// ---------------------------------------------------------------------------------------------------- // Watchdog v3 - Leonardo // EoF 2017 // ---------------------------------------------------------------------------------------------------- #include "watchdog_3.h" GPRS modem(Serial1, MOD_PWR); bool modemOK = false; byte modemErrCount = 0; DHT dht(T_PIN, DHT11); char command[CMD_SIZE]; char message[SMS_SIZE]; char phone[PHONE_SIZE]; char datetime[DATE_SIZE]; char s_buffer[BUFFER_SIZE]; char l_buffer[LONG_BUFFER_SIZE]; bool cmdFromModem = false; unsigned long t = 0; int addr = 0; byte temp = 0, hum = 0, loud = 0, power = 0, battery = 0; byte btnCount = 0; bool btnTrigger = false; byte event; const float r12_1 = 20000; // 20K const float r12_2 = 10000; // 10K const float r5_1 = 10000; // 20K const float r5_2 = 10000; // 10K const float rbat_1 = 10000; // 10K const float rbat_2 = 10000; // 10K const float rout_1 = 10000; // 10K const float rout_2 = 10000; // 10K float vcc = 0.0; float k12, k5, kbat, kout; float v12, v5, vbat, vout; // эту константу (typVbg) необходимо откалибровать индивидуально const float typVbg = 1.08; // 1.0 -- 1.2 void setup() { Serial.begin(COM_BR); Serial1.begin(MOD_BR); modem.powerOn(); modemOK = modem.init(); // Конфигурируем пины pinMode(A_PIN, INPUT); pinMode(V5_PIN, INPUT); pinMode(V12_PIN, INPUT); pinMode(VBAT_PIN, INPUT); pinMode(VOUT_PIN, INPUT); pinMode(LED_PIN, OUTPUT); pinMode(BTN_PIN, INPUT); pinMode(FAN_PIN, OUTPUT); // Инициализируем климатический сенсор dht.begin(); // Коэффициенты делителей напряжений k12 = r12_2 / (r12_1 + r12_2); k5 = r5_2 / (r5_1 + r5_2); kbat = rbat_2 / (rbat_1 + rbat_2); kout = rout_2 / (rout_1 + rout_2); modem.controlGPIO(1, 0); modem.controlGPIO(2, 0); modem.controlGPIO(3, 0); modem.controlGPIO(4, 0); sprint("Init"); printParams(); sprint_P(str_help); initEEPROM(); } void loop() { if (millis() - t > PERIOD) { getStatus(); t = millis(); //sprint("Status!"); } checkModem(); if (!cmdFromModem) { readSerial(command, CMD_SIZE); } if (command[0] != '\0') { sprint(">", false); sprint(command); if (!strcmp_P(command, cmd_status)) { getStatusMessage(message); returnAnswer(message); } else if (!strcmp_P(command, cmd_help)) { sprint_P(str_help); sendHelp(); } else if (!strcmp_P(command, cmd_sms_on)) { smsOn(true); returnAnswer(); } else if (!strcmp_P(command, cmd_sms_off)) { smsOn(false); returnAnswer(); } else if (!strcmp_P(command, cmd_auth_on)) { authOn(true); returnAnswer(); } else if (!strcmp_P(command, cmd_auth_off)) { authOn(false); returnAnswer(); } else if (!strcmp_P(command, cmd_fwd_on)) { fwdOn(true); returnAnswer(); } else if (!strcmp_P(command, cmd_fwd_off)) { fwdOn(false); returnAnswer(); } else if (!strcmp_P(command, cmd_on)) { mainPowerOn(); returnAnswer(); } else if (!strcmp_P(command, cmd_off)) { mainPowerOff(); returnAnswer(); } else if (!strcmp_P(command, cmd_reset)) { mainReset(); returnAnswer(); } else if (!strcmp_P(command, cmd_a)) { a_PowerBreak(); returnAnswer(); } else if (!strcmp_P(command, cmd_b)) { b_PowerBreak(); returnAnswer(); } else if (!strcmp_P(command, cmd_forward)) { forwardLastSMS(); } else if (!strcmp_P(command, cmd_modem_reset) && !cmdFromModem) { modem.reset(); modem.init(); returnAnswer(); } else if (!strcmp_P(command, cmd_modem_console) && !cmdFromModem) { modemConsole(); } else if (!strcmp_P(command, cmd_edit_ab) && !cmdFromModem) { editAddressBook(); } else if (!strcmp_P(command, cmd_show_ab) && !cmdFromModem) { printAddressBook(); } else { sprint_P(str_help); sendHelp(); } } ledOn(); delay(5); ledOff(); if (buttonPressed()) { ledOn(); if (btnCount < BTN_COUNT) btnCount++; } else { ledOff(); btnCount = 0; btnTrigger = false; } if (btnCount >= BTN_COUNT && !btnTrigger) { btnTrigger = true; if (entryNotEmpty(0)) { loadPhoneNumber(0, phone); modem.callUp(phone); sprint("Out call: ", phone); while (true) { ledOn(); event = modem.getEvent(message, phone, datetime, l_buffer, LONG_BUFFER_SIZE, NO_CHECK); ledOff(); delay(150); if (event == BUSY || event == NO_CARRIER || event == NO_ANSWER) break; if (event == ANSWER) t = millis(); if (!buttonPressed()) btnTrigger = false; if (millis() - t > CALL_TIMEOUT || (buttonPressed() && !btnTrigger)) { btnTrigger = true; break; } } modem.hangup(); sprint("Call over"); } else { flash(5); } } } // Запрос статуса word getStatus() { unsigned int stat = 0; // Get sensors getTH(); if (temp > 28) stat |= TEMP_WARN; if (hum > 85) stat |= HUM_WARN; loud = analogRead(A_PIN); if (loud > 250) stat |= LOUD_WARN; getVs(); if (v12 < 10) stat |= POWER_WARN; if (vbat < 6.4) stat |= BAT_WARN; return stat; } // void printAll() { sprint("phone: ", phone); sprint("date: ", datetime); sprint("msg: ", message); sprint("msg len: ", strlen(message)); sprint("cmd: ", command); sprint("t: ", temp); sprint("h: ", hum); sprint("l: ", loud); sprint("mdm: ", modemOK, true); sprint("sms: ", smsOn(), true); sprint("auth: ", authOn(), true); sprint("fwd: ", fwdOn(), true); sprint("Vcc: ", vcc); sprint("V12: ", v12); sprint("V5: ", v5); sprint("Vbat: ", vbat); sprint("Vout: ", vout); } // Формируем читабельную строку со статусом void getStatusMessage(char *message) { word stat = getStatus(); char s[10]; message[0] = '\0'; if (stat != 0) { strcat(message, "WARNING"); } else { strcat(message, "OK"); } strcat(message, "\nT: "); itoa(temp, s, 10); strcat(message, s); strcat(message, "C"); if (stat & TEMP_WARN) strcat(message, " !"); strcat(message, " H: "); itoa(hum, s, 10); strcat(message, s); strcat(message, "%"); if (stat & HUM_WARN) strcat(message, " !"); strcat(message, " L: "); itoa(loud, s, 10); strcat(message, s); strcat(message, "UE"); if (stat & LOUD_WARN) strcat(message, " !"); strcat(message, "\nVcc: "); ftoa(vcc, s); strcat(message, s); strcat(message, "V"); strcat(message, "\nV12: "); ftoa(v12, s); strcat(message, s); strcat(message, "V"); strcat(message, " V5: "); ftoa(v5, s); strcat(message, s); strcat(message, "V"); strcat(message, "\nVbat: "); ftoa(vbat, s); strcat(message, s); strcat(message, "V"); strcat(message, " Vout: "); ftoa(vout, s); strcat(message, s); strcat(message, "V"); strcat(message, "\n\nPower: "); if (stat & POWER_WARN) strcat(message, "Off"); else strcat(message, "On"); strcat(message, " Battery: "); if (stat & BAT_WARN) strcat(message, "Low"); else strcat(message, "Ok"); strcat(message, "\nSMS: "); if (smsOn()) strcat(message, "On"); else strcat(message, "Off"); strcat(message, " Auth: "); if (authOn()) strcat(message, "On"); else strcat(message, "Off"); strcat(message, " Fwd: "); if (fwdOn()) strcat(message, "On"); else strcat(message, "Off"); } // Обработка событий модема void checkModem() { cmdFromModem = false; command[0] = '\0'; switch (modem.getEvent(message, phone, datetime, l_buffer, LONG_BUFFER_SIZE)) { case ERR: sprint("Mdm err!"); modemOK = false; if (modemErrCount < MAX_ERROR) modemErrCount++; if (modemErrCount >= MAX_ERROR) { sprint("Rst mdm..."); modem.reset(); if (modem.init()) { sprint("Mdm OK"); modemOK = true; } } return; case SMS: sprint("SMS: ", phone); flash(3); if (authOn() && !authOK(phone)) { strcpy_P(command, cmd_forward); } else { strncpy(command, message, CMD_SIZE); } cmdFromModem = true; break; case CALL: sprint("Call: ", phone); if (authOn() && !authOK(phone)) { modem.hangup(); sprint("Unauth call"); } else { modem.answer(); t = millis(); while (!modem.ifcallEnd()) { ledOn(); delay(1000); ledOff(); if (millis() - t > CALL_TIMEOUT || buttonPressed()) { modem.hangup(); break; } } sprint("Call over"); } cmdFromModem = true; break; case NONE: cmdFromModem = false; break; } modemErrCount = 0; modemOK = true; } // Консоль модема void modemConsole() { sprint_P(str_modem_cons_on); sprint("Timeout is ", TIMEOUT, false); sprint(" ms after last command"); t = millis(); byte i = 0; while (millis() - t < TIMEOUT) { if (Serial1.available()) { while(Serial1.available()) { s_buffer[i++] = Serial1.read(); if(i == BUFFER_SIZE) break; } Serial.write(s_buffer, i); i = 0; } if (Serial.available()) { Serial1.write(Serial.read()); t = millis(); } } sprint_P(str_modem_cons_off); } // Читаем команды с COM-порта void readSerial(char *com, byte com_size) { com[0] = '\0'; com[com_size - 1] = '\0'; byte i = 0; while (Serial.available() > 0 && i < com_size - 1) { com[i] = Serial.read(); if (com[i] == '\r') { com[i] = '\0'; } else if (com[i] == '\n') { com[i] = '\0'; break; } i++; } } // Отправляем ответ void returnAnswer(const char * answer) { sprint(answer); if (modemOK && smsOn() && cmdFromModem) { modem.sendSMS(phone, answer); } } void sendHelp() { if (modemOK && smsOn() && cmdFromModem) { if (authOn() && !authOK(phone)) return; modem.sendSMS(phone, str_help); } } void forwardLastSMS() { char main_phone[PHONE_SIZE]; sprint("Get SMS from: ", false); sprint(phone); sprint("at: ", false); sprint(datetime); sprint(message); if (fwdOn() && entryNotEmpty(0)) { loadPhoneNumber(0, main_phone); s_buffer[0] = '\0'; strcat(s_buffer, "SMS from "); strcat(s_buffer, phone); strcat(s_buffer, " at "); strcat(s_buffer, datetime); modem.sendSMS(main_phone, s_buffer); modem.sendSMS(main_phone, message); } } // Управление подключенным оборудованием void mainPowerOn() { if (!isPowerOn()) { modem.controlGPIO(1, 1); delay(500); modem.controlGPIO(1, 0); } } void mainPowerOff() { modem.controlGPIO(1, 1); delay(6000); modem.controlGPIO(1, 0); } void mainReset() { modem.controlGPIO(2, 1); delay(500); modem.controlGPIO(2, 0); } void a_PowerBreak() { modem.controlGPIO(3, 1); delay(5000); modem.controlGPIO(3, 0); } void b_PowerBreak() { modem.controlGPIO(4, 1); delay(5000); modem.controlGPIO(4, 0); } bool isPowerOn() { getVs(); if (v12 > 10) return true; else return false; } // Адресная книга bool savePhoneNumber(byte index, char * phone) { if (index > AB_MAX_INDEX) return false; addr = AB_ADDR + index * PHONE_SIZE; for (byte i = 0; i < PHONE_SIZE; i++) EEPROM.update(addr + i, phone[i]); return true; } bool delPhoneNumber(byte index) { if (index > AB_MAX_INDEX) return false; clearBuffer(phone, PHONE_SIZE); strcpy(phone, ""); return savePhoneNumber(index, phone); } bool loadPhoneNumber(byte index, char * phone) { if (index > AB_MAX_INDEX) return false; addr = AB_ADDR + index * PHONE_SIZE; for (byte i = 0; i < PHONE_SIZE - 1; i++) phone[i] = EEPROM.read(addr + i); phone[PHONE_SIZE - 1] = '\0'; return true; } bool entryNotEmpty(byte index) { char phone[PHONE_SIZE]; loadPhoneNumber(index, phone); return strcmp(phone, ""); } void printPhoneNumber(byte index) { if (index > AB_MAX_INDEX) { sprint("Max index is: ", AB_MAX_INDEX); return; } loadPhoneNumber(index, phone); sprint("", index, false); sprint(": ", false); sprint(phone); } void printAddressBook() { sprint("i Phone"); for (byte i = 0; i <= AB_MAX_INDEX; i++) printPhoneNumber(i); } void clearAddressBook() { for (byte i = 0; i <= AB_MAX_INDEX; i++) delPhoneNumber(i); } void editAddressBook() { char *p; char indexString[4]; byte index, i = 0; sprint_P(str_eab); sprint_P(str_help_ab); sprint_P(str_format_ab); t = millis(); while (millis() - t < TIMEOUT) { readSerial(s_buffer, BUFFER_SIZE); if (s_buffer[0] != '\0') { t = millis(); if (!strcmp_P(s_buffer, cmd_exit)) { break; } else if (!strcmp_P(s_buffer, cmd_show)) { printAddressBook(); } else if (!strcmp_P(s_buffer, cmd_clear)) { clearAddressBook(); } else { p = strstr(s_buffer, ":"); i = 0; while(s_buffer[i] != ':' && i < BUFFER_SIZE) i++; if (p == NULL || i == 0 || i > 1) { sprint_P(str_format_ab); } else { // Get index clearBuffer(indexString, 4); strncpy(indexString, s_buffer, i); index = atoi(indexString); // Get phone i = 0; p = strstr(s_buffer, ":") + 1; strcpy(phone, p); if (strcmp(phone, "delete")) { // Save savePhoneNumber(index, phone); sprint("OK"); } else { // Delete delPhoneNumber(index); sprint("OK"); } } } } } sprint_P(str_help); } // Утилиты void clearBuffer(char *in_buffer, byte in_size) { for(byte i = 0; i < in_size - 1; i++) in_buffer[i] = '\0'; } void printParams() { if(smsOn()) sprint("SMS on | ", false); else sprint("SMS off | ", false); if(authOn()) sprint("Auth on | ", false); else sprint("Auth off | ", false); if(smsOn()) sprint("Fwd on"); else sprint("Fwd off"); } bool authOK(char *phone) { char t_phone[PHONE_SIZE]; for(byte i = 0; i <= AB_MAX_INDEX; i++) { loadPhoneNumber(i, t_phone); if (!strcmp(phone, t_phone)) return true; } return false; } void sprint(const char *description, const byte data, const bool ln) { Serial.print(description); Serial.print(data); if (ln) Serial.println(); } void sprint(const char *description, const char *data, const bool ln) { Serial.print(description); Serial.print(data); if (ln) Serial.println(); } void sprint(const char *description, const int data, const bool ln) { Serial.print(description); Serial.print(data); if (ln) Serial.println(); } void sprint(const char *description, const unsigned int data, const bool ln) { Serial.print(description); Serial.print(data); if (ln) Serial.println(); } void sprint(const char *description, const long int data, const bool ln) { Serial.print(description); Serial.print(data); if (ln) Serial.println(); } void sprint(const char *description, const long unsigned int data, const bool ln) { Serial.print(description); Serial.print(data); if (ln) Serial.println(); } void sprint(const char *description, const float data, const bool ln) { Serial.print(description); Serial.print(data); if (ln) Serial.println(); } void sprint(const char *description, const bool ln) { Serial.print(description); if (ln) Serial.println(); } void sprint_P(const char *description, const bool ln) { int len = strlen_P(description); char c; for (byte i = 0; i < len; i++) { c = pgm_read_byte_near(description + i); Serial.print(c); } if (ln) Serial.println(); } bool smsOn() { addr = PARAM_ADDR + SMS_ON_INDEX; return (bool)EEPROM.read(addr); } void smsOn(bool temp) { addr = PARAM_ADDR + SMS_ON_INDEX; EEPROM.update(addr, (byte)temp); } bool authOn() { addr = PARAM_ADDR + AUTH_ON_INDEX; return (bool)EEPROM.read(addr); } void authOn(bool temp) { addr = PARAM_ADDR + AUTH_ON_INDEX; EEPROM.update(addr, (byte)temp); } bool fwdOn() { addr = PARAM_ADDR + FWD_ON_INDEX; return (bool)EEPROM.read(addr); } void fwdOn(bool temp) { addr = PARAM_ADDR + FWD_ON_INDEX; EEPROM.update(addr, (byte)temp); } void fanPWM(byte power) { analogWrite(FAN_PIN, power); } void fanOn() { digitalWrite(FAN_PIN, HIGH); } void fanOff() { digitalWrite(FAN_PIN, LOW); } void ledPWM(byte power) { analogWrite(LED_PIN, power); } void ledOn() { digitalWrite(LED_PIN, HIGH); } void ledOff() { digitalWrite(LED_PIN, LOW); } void flash(byte count) { for (byte i = 0; i < count; i++) { ledOn(); delay(5); ledOff(); delay(150); } } bool buttonPressed() { if (digitalRead(BTN_PIN) == LOW) return true; return false; } float readvcc() { byte i; float tmp = 0.0; // Read 1.1V reference against Avcc // set the reference to vcc and the measurement to the internal 1.1V reference #if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); #elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) ADMUX = _BV(MUX5) | _BV(MUX0); #elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) ADMUX = _BV(MUX3) | _BV(MUX2); #else // works on an Arduino 168 or 328 ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); #endif delay(3); // Wait for Vref to settle ADCSRA |= _BV(ADSC); // Start conversion while (bit_is_set(ADCSRA,ADSC)); // measuring uint8_t low = ADCL; // must read ADCL first - it then locks ADCH uint8_t high = ADCH; // unlocks both tmp = (high<<8) | low; tmp = (typVbg * 1023.0) / tmp; return tmp; } void getVs() { v12 = 0.0; v5 = 0.0; vbat = 0.0; vout = 0.0; v12 += readvcc() * analogRead(V12_PIN); v5 += readvcc() * analogRead(V5_PIN); vbat += readvcc() * analogRead(VBAT_PIN); vout += readvcc() * analogRead(VOUT_PIN); vcc = readvcc(); v12 = v12 / 1024.0 / k12; v5 = v5 / 1024.0 / k5; vbat = vbat / 1024.0 / kbat; vout = vout / 1024.0 / kout; } void printVs() { sprint("Vcc: ", vcc); sprint("V12: ", v12); sprint("V5: ", v5); sprint("Vbat: ", vbat); sprint("Vout: ", vout); } void getTH() { int check; check = dht.read(); switch (check) { case DHT_OK: temp = dht.getTemperatureC(); hum = dht.getHumidity(); break; case DHT_ERROR_TIMEOUT: temp = 253; break; case DHT_ERROR_CHECKSUM: temp = 254; break; } } void ftoa(float f, char *s) { int d1, d2; char t[10]; s[0] = '\0'; d1 = (int)f; f = f - d1; f = f * 100; d2 = (int)f; itoa(d1, t, 10); strcat(s, t); strcat(s, "."); itoa(d2, t, 10); strcat(s, t); } void initEEPROM() { int flag_addr = PARAM_ADDR + EEPROM_INIT_INDEX; if (EEPROM.read(flag_addr) != INIT_FLAG) { clearAddressBook(); smsOn(false); authOn(true); fwdOn(true); EEPROM.write(flag_addr, INIT_FLAG); } }