vintlabs / fauxmoESP

Add voice control of your ESP32 and ESP8266 devices using Amazon Alexa
MIT License
391 stars 71 forks source link

My ESP8266-12F reboots with exception 3 after some hours of work. #163

Open jjsanma1 opened 3 years ago

jjsanma1 commented 3 years ago

The ESP8266 reboots after some hours . The ESP is acting as HTTP server (using ESP8266WebServer.h)

for one ESP HTTP client and for one movile APP as well. During the day , ESP client and Mobile APP are requesting every 3 seconds and everything works well . During night , only Mobile APP is requesting. Then , early morning when ESP client wakes up and starts requests again , for somereason I get the exception 3. I've monitored Heap max size and Heap fragmentation but it seems there is no issue there.

Exception (3): epc1=0x40100cc9 epc2=0x00000000 epc3=0x00000000 excvaddr=0x400339b8 depc=0x00000000

Exception decoder says : Exception 3: LoadStoreError: Processor internal physical address or data error during load or store PC: 0x40100cc9: umm_assimilate_up(uint16_t) at C:\Users\jj\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.4\cores\esp8266\umm_malloc\umm_malloc.cpp line 207 EXCVADDR: 0x400339b8

ino Code: //** variables para aislar el problema de exception 29 y 3 **

define HEAP_CHECK;

/*#define TIMER1_ENABLED;

define TIMER2_ENABLED;

define OTA_ENABLED;

define A6_ENABLED;

define ALEXA_ENABLED;

define NTP_ENABLED;*/

//*** //* LIBRERIAS * //***

include //TimeLib library is needed https://github.com/PaulStoffregen/Time

include // ojo usar la version 6.0.9 de la libreria de gestion de port serie actualizada a traves de este IDE arduino

include // https://github.com/arduino-libraries/NTPClient/blob/master/examples/Basic/Basic.ino , ejemplo https://randomnerdtutorials.com/esp8266-nodemcu-date-time-ntp-client-server-arduino/

include // https://github.com/JChristensen/Timezone

include // gestion del modulo ESP8266 . requiere installar todo el pack https://github.com/esp8266/Arduino

include

include // gestion del server HTTP en modulo ESP8266

include // https://github.com/esp8266/Arduino http library to manage http connections to DDNS portal

include // sustituida por la ESP_EEPROM

include // gestion de timer como interrupcion

include "IFTTTESP8266.h"

include // to send pings to test connection https://github.com/dancol90/ESP8266Ping/blob/master/examples/SimplePing/SimplePing.ino

//#include "fauxmoESP.h" // libary for Alexa voice control https://bitbucket.org/xoseperez/fauxmoesp/get/master.zip o https://github.com/simap/fauxmoesp also needs ESPAsyncTCP.h library https://github.com/me-no-dev/AsyncTCP/archive/master.zip // includes para programacion OTA

include // OJO USAR SIEMPRE LA LIBRERIA INCLUIDA EN ESP8266/ARDUINO NO LA QUE SE CARGA DESDE EL GESTOR DE LIBRERIAS

include "ESP8266_Utils_OTA.hpp" // fichero con las funciones para programacion OTA

// includes para ALexa

include

include "Switch.h" //Ojo este fichero debe estar en el mismo directorio que el programa //https://github.com/kakopappa/arduino-esp8266-alexa-multiple-wemo-switch/tree/master/wemos

include "UpnpBroadcastResponder.h" //Ojo este fichero debe estar en el mismo directorio que el programa //https://github.com/kakopappa/arduino-esp8266-alexa-multiple-wemo-switch/tree/master/wemos

include "CallbackFunction.h" //Ojo este fichero debe estar en el mismo directorio que el programa //https://github.com/kakopappa/arduino-esp8266-alexa-multiple-wemo-switch/tree/master/wemos

// Ticker tempo1;// crea objeto timer Ticker tempo2;// crea objeto timer // //***** VARIABLES A CONFIGURAR SEGUN NECESIDADES* //***

static const char ssid[]="xx"; //nombre de la red wifi a conectarse static const char* password="xx";//password de la red wifi a conectarse const int time_filtro_uWaves=10;// filtro en mseg para deteccion del sensor uWaves y minimizar falsos positivos

define MAX_REMOTE_DEVICES 10//define el numero maximo de equipos remotos

int wifi_time_out=25; // time out de conexion a la red WIFI int time_to_enable= 30;// Delay to enable the alarm after receive the command from the APP or Alexa . I've increased to 30 seconds because when you enable the alarm and you open and close the main door //it takes 15 seconds to send the door message and then the alarm is already enabled when this message arrives and then the alarm triggers. int time_to_disable= 10;// Delay in seconds to activate the alarm after any sensor is on. this is to let time to disable it int siren_time_ON = 15; // in seconds by siren time ON for PWM int siren_time_OFF = 5; // in seconds by siren time OFF for PWM int siren_times=5; // nb of siren cycles for PWM static const int comm_preset=15; // It is the time-out in seconds for communication with devices that send alive messages regularly //#define MAX_STRING_LENGHT 31//define el máximo de caracteres que puede tener las cadenas de los equipos remotos (nombre , tipo ect) //#define MAX_STRING_SERVER 2000 // estimation of max length of the response server frame

define EEPROM_ADDR_VIRGEN 10

define EEPROM_ADDR_ENABLE 0

define EEPROM_ADDR_LAST_TIME_ALARM 20

define EEPROM_ADDR_LAST_TIME_DETECTION 50

// ** ** ** ** ** ** static const String domain_ddns = "xxxxxxxxxxxx"; // URL de este servidor basado en el ddns server static const String token_ddns = "xxxxxxx"; // token del servicio en el ddns server

define IFTTTKEY "exxxxxxxxx" // !!! cuenta jjsanma1@gmail.com

define IFTTTKEY1 "xxxxxxxxxxxxxx" // !!! cuenta jjsanma2@gmail.com

String ALEXA_DEVICE_ALARM_ENABLE="xxxxx"; // defines the name of the device to be recognize by Alexa voice String ALEXA_DEVICE_ALARM_ON="xxxxxxxxxx"; // defines the name of the device to be recognize by Alexa voice int preset_update_DDNS = 1000; // periodo en segundos para chequeo de IP publica int preset_check_network = 20; //preset en segundos para check de red y envio de SMS por el modulo A6en caso de fallo de red static const int A6_call_time_setup = 20; // setup duration of the call in secs

static const int timer_check_A6_setup = 20; // setup frequency of checking A6 SMS module in secs static const int A6_timeout_setup = 3; // setup time out for response of A6 SMS module in secs . is long in order to avoid issues when testing the network through dns requests int ping_times = 3; // numero de pings antes de decidir que la red falla // put constant strings in flash static const char ATCREG[] PROGMEM="AT+CREG?"; // Checks A6 Module static const char ATCREG1[] PROGMEM="+CREG: 1,1"; // A6 registration static const char ATH[] PROGMEM="ATH"; static const char ATIPR[] PROGMEM=" AT+IPR=9600"; static const char ATE0[] PROGMEM="ATE0"; static const String myPhoneNumber="xxxxxxxxxxxx"; // phone number to call or send SMS through A6 GSM Module static const String alarm_message = "A6 says: ALARM ON PISO "; static const String alarm_track = "A6 says: ALARM SENSOR PISO : "; static const String powerdown_message = "A6 says: POWER DOWN PISO "; static const String powerup_message = "A6 says: POWER UP PISO "; static const String ESPup_message = "A6 says: ESPinit PISO "; static const String error_network_message = "A6:PING ERROR PISO "; const String error_wifi_message = "A6:WIFI ERROR PISO "; IPAddress remote_ip(8, 8, 8, 8); // google ip to send ping to test the internet connection

//*** //* VARIABLES de trabajo ** //*** ESP8266WebServer server(81);//Create an instance of the ESP8266 server HTTP and specify the port to listen. It will reply to the Androdid APP client

//Espalexa espalexa; bool Requestok = false; bool edge_alarm_on = false; unsigned long time_update_DDNS; int update_DDNS = 0; String new_ip; String old_ip; String time_date; String time_last_alarm = "00:00:00 00/00/00"; String time_last_powerdown = "00:00:00 00/00/00"; String time_last_powerup = "00:00:00 00/00/00"; String time_last_ESPup = "00:00:00 00/00/00"; String time_last_error_network = "00:00:00 00/00/00"; String time_last_detection = "00:00:00 00/00/00"; //guarda la fecha/hora de la ultima deteccion de los sensores int initEEPROM = 0; int current_time_siren_ON = 0; // PWM : timer para el tiempo en que sonara la sirena int current_time_siren_OFF = 0;// PWM timer para el tiempo en que no sonara la sirena int siren_status=0;// flag para el PWM de la sirena int current_siren_times=0; int alarm_on_app = 0; bool edge_powerdown = false; bool edge_powerup = false; bool edge_ESPup = false;

// *** configuracion de las I/O const int in_PIR = 4; //GPIO4 const int in_uWaves = 14; //GPIO14 //V0.0.5 const int in_power_on = 12; //GPIO12 const int out_sirena = 05; // GPIO5 const int analogInPin = A0; // ESP8266 Analog Pin ADC0 = A0 const int out_led = 16; // GPIO16 led output : blinking= Alarm enabled - off=alarm disabled

//*** variables para gestion del modulo A6 GSM static const int RX_ESP = 13; // GPIO13 RX2 para comunicacion con A6 static const int TX_ESP = 15; // GPIO15 TX2 para comunicacion con A6

define OK 1

define NOK 0

long timer_check_A6 = 0; int A6_sending_sms = 0; int A6_status = NOK;

define buffer_max 400

char receivedA6[buffer_max];// string to contain the string sent by PIC with all values int ndx = 0; int A6_wait_reply = 0; // flag para indicar que se espera respuesta del modulo A6 GSM int A6_timeout = 0; // timeout de respuesta del modulo A6 GSM int A6_calling = 0; // flag indicando "llamando" del modulo A6 GSM int A6_calling_time = 0; // temporizador de tiempo de llamada del modulo A6 GSM long time_check_battery = 0; int manual_sent = 0; int timer_check_network = 0; // timer para check del estado de la red bool error_network_flag = false; int check_network = 0; int error_network_count = 0; bool SMS_sent_recently = false; int timer_after_SMS = 0; //Create software serial object to communicate with A6 //SoftwareSerial a6Serial(RX_ESP,TX_ESP,buffer_max); //A6 URX Conectado al GPIO15 y A6 UTX conectado al GPI013 //SoftwareSerial a6Serial(RX_ESP,TX_ESP); //A6 URX Conectado al GPIO15 y A6 UTX conectado al GPI013 SoftwareSerial a6Serial; // variables to check central and other alarm devices --> device 0 is the central device arbitrating the network bool alarm_device=false; // Indicates that at least one remote device is in alarm .OR of all alarm_on[xx] in remote devices. String device_type[MAX_REMOTE_DEVICES]; // name of the remote device String device_name[MAX_REMOTE_DEVICES]; // name of the remote device bool comm_error_sent[MAX_REMOTE_DEVICES];// to send only once to IFTTT when communication device error bool alarm_active=false; bool alarm_on[MAX_REMOTE_DEVICES]; // status of the remote device alarm bool alarm_on_old[MAX_REMOTE_DEVICES];// to detect changes in the sensors bool alarm_enabled[MAX_REMOTE_DEVICES]; // enable/disable of the remote device alarm bool comm_status[MAX_REMOTE_DEVICES]; // status of the communication with remote device int comm_timer[MAX_REMOTE_DEVICES]; int comm_counter[MAX_REMOTE_DEVICES]; int comm_counter_old[MAX_REMOTE_DEVICES]; bool detector_1[MAX_REMOTE_DEVICES];// status of the remote device detector 1 bool detector_2[MAX_REMOTE_DEVICES];// status of the remote device detector 2 int battery_status[MAX_REMOTE_DEVICES];// status of the remote device battery float battery_voltage[MAX_REMOTE_DEVICES];// value of the remote device battery bool power_status[MAX_REMOTE_DEVICES];// status of the remote device power String SSID_device[MAX_REMOTE_DEVICES];// name of the wifi network where each device is connected to String last_date_time_device[MAX_REMOTE_DEVICES]; String ip_device[MAX_REMOTE_DEVICES];// int port_device[MAX_REMOTE_DEVICES];//

int timer_led=0; signed int Device_in_alarm=0; signed int Device_track_alarm=0; //fauxmoESP fauxmo; // Object to manage Alexa Voice int counter_wifi_error=0; int timer_to_enable=0; int timer_to_disable=0; bool alarm_enable_rcv=false; bool alarm_enabled_old=false; bool alarm_true=false; bool rising_edge_true_enabled=false; String WIFI_SSID;

// Define NTP Client to get time

ifdef NTP_ENABLED

WiFiUDP ntpUDP;
const long utcOffsetInSeconds = 3600; // Adjusts time zone UTC +0.00
NTPClient timeClient(ntpUDP, "pool.ntp.org", utcOffsetInSeconds,60000);
// Central European Time (Frankfurt, Paris)
TimeChangeRule CEST = {"CEST", Last, Sun, Mar, 2, 120};     // Central European Summer Time
TimeChangeRule CET = {"CET ", Last, Sun, Oct, 3, 60};       // Central European Standard Time
Timezone CE(CEST, CET);

endif

// variables to save and read in EEprom the values of the remote devices when sporadic reboots

define MAX_CHAR_STRING 31 //Max lenght of strings

define MAX_CHAR_BOOL 1 //Max lenght of bool types

define MAX_CHAR_FLOAT 4 //Max lenght of float types

define FIRST_ADDR_EEPROM 150 //Max lenght of float types

// declare new maker event with the name "ESP" IFTTT client(IFTTTKEY);// para envio a cuenta 1 de IFTTT con telefono de JJ IFTTT client1(IFTTTKEY1);// para envio a cuenta 2 de IFTTT con telefono de Gloria String reset_cause; int wifi_timer; int previousMillis=0; int intervalMillis=5000; //alexa UpnpBroadcastResponder upnpBroadcastResponder; Switch protection = NULL; Switch siren = NULL; int old_power_sts; bool in_uWaves_filtered=false; bool sensor0_old=false; long oldmilis=0;

struct { byte mac [ 6 ] ; byte mode ; byte chl ; IPAddress ip ; IPAddress gw ; IPAddress msk ; IPAddress dns ; uint16_t localPort; uint32_t chk ;

} cfgbuf;

//uint32_t StartTimeMs , SetupTime ;

// returns 0=got saved info, 1=data reset uint32_t readcfg(void) { uint32_t x = 0 ; uint32_t p = (uint32_t )cfgbuf.mac ; ESP.rtcUserMemoryRead(0 ,p ,sizeof(cfgbuf)); for (uint32_t i = 0; i < sizeof(cfgbuf)/4; i++) x += p[i]; if (x) { for (uint32_t i = 0; i < 6; i++) cfgbuf.mac[i] = 0xff; cfgbuf.mode = 0; // chk err, reconfig cfgbuf.chl = 0; cfgbuf.ip = IPAddress(0, 0, 0, 0); cfgbuf.gw = IPAddress(0, 0, 0, 0); cfgbuf.msk = IPAddress(255, 255, 255, 0); cfgbuf.dns = IPAddress(0, 0, 0, 0); cfgbuf.localPort = 10000; x = 1; } return x; }

void writecfg(void) { int x = 0; static struct station_config conf; wifi_station_get_config(&conf); // save new info for (uint32_t i = 0; i < sizeof(conf.bssid); i++) cfgbuf.mac[i] = conf.bssid[i]; cfgbuf.chl = wifi_get_channel(); cfgbuf.ip = WiFi.localIP(); cfgbuf.gw = WiFi.gatewayIP(); cfgbuf.msk = WiFi.subnetMask(); cfgbuf.dns = WiFi.dnsIP(); // recalculate checksum uint32_t p = (uint32_t )cfgbuf.mac; for (uint32_t i = 0; i < sizeof(cfgbuf)/4-1 ; i++) x += p[i]; cfgbuf.chk =- x ; ESP.rtcUserMemoryWrite(0, p, sizeof(cfgbuf)); } //***** // ** rutina de interrupcion por tiempo que se ejecuta cada x segundos* ** //***** void tempo2_sub() { // led blinking
if (digitalRead (in_power_on)==0) { // if mains down --> led every 0.5 sec digitalWrite (out_led, !digitalRead (out_led)); } else if (battery_status[0]==0){ // if battery down --> led every 1 sec if(++timer_led>2){ digitalWrite (out_led, !digitalRead (out_led)); timer_led=0;
} } //else if ((digitalRead (in_PIR) == HIGH && in_uWaves_filtered == HIGH)){ // if both detectors ON -> led continous else if (in_uWaves_filtered || digitalRead (in_PIR) == HIGH){ // if uWaves ON -> led continous digitalWrite (out_led, LOW); } else { digitalWrite (out_led, HIGH);// else led off } } // fin rutina timer 2

//***** // ** rutina de interrupcion por tiempo que se ejecuta cada x segundos* ** //*** void tempo1_sub() {
wifi_timer++; // time out for Wifi connection //if (boot_delay<5) boot_delay++;// delay to avoid powerup sms when esp reboots // delay after sent A6 SMS to avoid alarm activation if (SMS_sent_recently == true) { if (++timer_after_SMS > 20) { // delay in seconds after A6_send_SMS to avoid false alarms due to drop of 5Volts and false PIR & uWave signals SMS_sent_recently = false; timer_after_SMS = 0; } } //check si hay red IP if (++timer_check_network > preset_check_network) { timer_check_network = 0;
check_network = 1; } // update ddns IP if (++time_update_DDNS > preset_update_DDNS) { time_update_DDNS = 0; update_DDNS = 1;
} // Incrementa tiempo de alarma ON if (siren_status == 1) current_time_siren_ON++; if (siren_status == 2) current_time_siren_OFF++; // check battery every minute if (++time_check_battery > 60) { time_check_battery = 0; read_battery(); } // *
gestion de comunicaciones con el modulo A6 GSM/GPRS //envia AT cada x seg y reenvia al port serie para monitorizar if (++timer_check_A6 > timer_check_A6_setup) { timer_check_A6 = 0; if ( A6_sending_sms == 0 && A6_calling == 0) { A6_clear_buffer (); A6_wait_reply = 1; A6_timeout = 0; ndx = 0;

ifdef A6_ENABLED

    if( SMS_sent_recently == false) a6Serial.println(FPSTR(ATCREG)); //Once the hands test is successful, it will back to Oºººººººººººº
  #endif
}//fin envio de trama al A6 para check

} //fin tempo envio de trama al A6 para check

//comprobar la respuesta al AT , la recepcion se hace en el loop if (A6_wait_reply == 1) { if (++A6_timeout > A6_timeout_setup) { A6_wait_reply = 0; A6_timeout = 0; String receivedStr(receivedA6); if (receivedStr.indexOf(FPSTR(ATCREG1)) > 0) { A6_status = OK; } else { A6_status = NOK; timer_check_A6 = timer_check_A6_setup-5; // send inmediatelly another request to check A6 GSM //Serial.println("A6 comm error"); } }//fin timeout respuesta A6 }// *** fin gestion de respuesta del modulo A6 GSM/GPRS

// gestion del tiempo de llamada antes de colgar if (A6_calling == 1) { if (++A6_calling_time > A6_call_time_setup) { //colgar despues de x segundos A6_calling_time = 0; A6_calling = 0;

ifdef A6_ENABLED

    a6Serial.println(FPSTR(ATH));
  #endif //hang up     
}

}
// timer to delay enable
if(alarm_enable_rcv==true){ if(++timer_to_enable>time_to_enable){//wait for x seconds for true enable alarm_enable_rcv=false; alarm_enabled[0]=true; // alarm true enabled timer_to_enable=0;
} } // timer to delay disable
if(SMS_sent_recently == false && alarm_device==true){
if(++timer_to_disable>time_to_disable){//wait for x seconds before activate the alarm alarm_true=true;
} }
} // *** fin rutina timer1

// **** // ** rutina que se ejecuta 1 vez al inicio * // **** void setup() {
//ESP.wdtDisable(); // desbilita el WDT por soft de 1 seg . sigue habilitado el de hardware que es de 6 seg. para habilitarlo de nuevo ESP.wdtEnable(1000);

Serial.begin(74880);// para usar la misma que el debug del esp y poder debugar bien
delay(200); // time to stabilize
// gets info about last reset reason , this is to print and to send to IFTTT later rst_info* rinfo = ESP.getResetInfoPtr(); Serial.printf_P(PSTR(" rinfo->reason: %d, %s\n"), rinfo->reason, ESP.getResetReason().c_str()); reset_cause+= " rinfo->reason: " + String(ESP.getResetReason().c_str()); Serial.printf_P(PSTR(" rinfo->exccause: %d\n"), rinfo->exccause); reset_cause+= " rinfo->exccause: " + String(rinfo->exccause); Serial.printf_P(PSTR(" rinfo->epc1: %d\n"), rinfo->epc1); reset_cause+= " rinfo->epc1: " + String(rinfo->epc1); Serial.printf_P(PSTR(" rinfo->epc2: %d\n"), rinfo->epc2); reset_cause+= " rinfo->epc2: " + String(rinfo->epc2); Serial.printf_P(PSTR(" rinfo->epc3: %d\n"), rinfo->epc3); reset_cause+= " rinfo->epc3: " + String(rinfo->epc3); Serial.printf_P(PSTR(" rinfo->excvaddr: %d\n"), rinfo->excvaddr); reset_cause+= " rinfo->excvaddr: " + String(rinfo->excvaddr); Serial.printf_P(PSTR(" rinfo->depc: %d\n"), rinfo->depc); reset_cause+= " rinfo->depc: " + String(rinfo->depc);

//**** defines I/Os pinMode(in_PIR, INPUT); pinMode(in_uWaves, INPUT); pinMode(in_power_on, INPUT); pinMode(out_sirena, OUTPUT); pinMode(out_led, OUTPUT);

// reserve RAM for strings 
//s.reserve(MAX_STRING_SERVER);// reserve RAM for response server
// reserve ram for devices values
 for (int pp=1;pp<=MAX_REMOTE_DEVICES-1;pp++) {            
            device_type[pp].reserve(MAX_CHAR_STRING); 
            device_name[pp].reserve(MAX_CHAR_STRING); 
            SSID_device[pp].reserve(MAX_CHAR_STRING); 
            SSID_device[pp].reserve(MAX_CHAR_STRING); 
            last_date_time_device[pp].reserve(MAX_CHAR_STRING);        
  }

// sets name and type for this device
device_type[0]="central"; device_name[0]="central"; // Lectura escritura de valores en EEPROM EEPROM.begin(4096); // inicializa EEPROM con x bytes puede llegar hasta 4096 EEPROM.get(EEPROM_ADDR_VIRGEN, initEEPROM); if (initEEPROM == 69) { // si la eeprom ya habia sido escrita antes (de lo contrario da error al leer un string con todo a 0 time_last_alarm = EEprom_read_String(EEPROM_ADDR_LAST_TIME_ALARM);
time_last_detection = EEprom_read_String(EEPROM_ADDR_LAST_TIME_DETECTION);
EEPROM.get(EEPROM_ADDR_ENABLE, alarm_enabled[0]); if (alarm_enabled[0] > 1 || alarm_enabled[0] < 0 ) { alarm_enabled[0] = true; }
for (int pp=1;pp<=MAX_REMOTE_DEVICES-1;pp++) {
read_eeprom_devices(pp);// lee de la eeprom los valores de los esclavos . Es porque a veces el esp hace reset y se borran } } else { // la eeprom es virgen
EEprom_write_String(EEPROM_ADDR_LAST_TIME_ALARM, time_last_alarm); //guarda la fecha de la ultima alarma EEprom_write_String(EEPROM_ADDR_LAST_TIME_DETECTION, time_last_detection); //guarda la fecha de la ultima alarma alarm_enabled[0]=false; EEPROM.put(EEPROM_ADDR_VIRGEN, 69); EEPROM.put(EEPROM_ADDR_ENABLE, alarm_enabled[0]);
EEPROM.commit(); // rellena valores en la EEPROM los string de last_date_time_device para evitar espacios blancos en la trama a la APP for (int pp=1;pp<=MAX_REMOTE_DEVICES-1;pp++) { device_type[pp]="type"; device_name[pp]="name"; SSID_device[pp]="NOSSID"; last_date_time_device[pp]="00/00/00-00:00:00"; comm_error_sent[pp]=true; // to avoid send to IFTTT messages if device is not connected when reboot the central write_eeprom_devices(pp); }
}

//Begin serial communication with Arduino and A6 by default = 115200 . no tiene autodected.

ifdef A6_ENABLED

 a6Serial.begin(9600, SWSERIAL_8N1, RX_ESP, TX_ESP , false, 256);

endif

/if (A6_ENABLED==true) a6Serial.begin(115200); delay(200);
if (A6_ENABLED==true) a6Serial.println(FPSTR(ATIPR)); //change baud in A6 to 9600 porque a 115200 no va muy bien
delay(200);
if (A6_ENABLED==true) a6Serial.begin(9600);//change baud in ESP delay(200);
/

ifdef A6_ENABLED

 a6Serial.println(FPSTR(ATE0)); 

endif//change baud in A6 to 9600 porque a 115200 no va muy bien

read_battery();// read battery at init // pone en marcha el timer

ifdef TIMER1_ENABLED

tempo1.attach(1, tempo1_sub); // inicia el timer cada segundo

endif

ifdef TIMER2_ENABLED

 tempo2.attach(0.5, tempo2_sub); // inicia el timer cada segundo

endif

old_power_sts=digitalRead (in_power_on); //V2.12.9 to avoid sms powerup when reboot // ** conecta a red wifi si esta desconectado. si no se conecta en x segundos vuelve a intentarlo
// ** conecta a red wifi.
//V2.12.93 connect_wifi(0); // connect to wifi in slow mode (not uses saved parameters) to avoid problems if we change the router , network name etc

server.on("/", handleRootPath); //Associate the handler function to the path . In this case "\" means the root directory. handleRootPath is the name of the function to call server.begin(); //Start the server

ifdef NTP_ENABLED

 timeClient.begin();

endif

ifdef OTA_ENABLED

 InitOTA();

endif// enable programacion OTA

// Define alexa devices here.

ifdef ALEXA_ENABLED

upnpBroadcastResponder.beginUdpMulticast();    
// Define your switches here. Max 10
// Format: Alexa invocation name, local port no, on callback, off callback
protection = new Switch(ALEXA_DEVICE_ALARM_ENABLE, 80, alexa_protection_on, alexa_protection_off);
siren = new Switch(ALEXA_DEVICE_ALARM_ON,82, alexa_siren_on, alexa_siren_off);
Serial.println("Adding switches upnp broadcast responder");
upnpBroadcastResponder.addDevice(*protection);
upnpBroadcastResponder.addDevice(*siren);
Serial.println(FPSTR("ALEXA READY"));  

endif

}//****fin del setup

// ***** // ** rutina que se ejecuta en continuo * // ***** void loop() {

// V2.12.93 - reconnection to wifi if disconected if (WiFi.status() != WL_CONNECTED) connect_wifi(3); // check wifi and reconnect if needed

// checks heap fragmentation

ifdef HEAP_CHECK

 unsigned long currentMillis = millis();
 if (currentMillis - previousMillis >= intervalMillis) {
    // save the last time you blinked the LED
    previousMillis = currentMillis;
    print_heap();
 }    

endif

// alexa loop

ifdef ALEXA_ENABLED

 if(WiFi.status() == WL_CONNECTED){
    upnpBroadcastResponder.serverLoop();      
    protection->serverLoop();
    siren->serverLoop();
}

endif

// programacion OTA

ifdef OTA_ENABLED

ArduinoOTA.handle();

endif

// gestion del buffer de comunicacion con A6 GSM para recibir los mensajes

ifdef A6_ENABLED

checkSwSerial(&a6Serial);

endif

// V2.12.91 - //if(digitalRead (in_uWaves)) delay(1000); //if(digitalRead (in_uWaves))in_uWaves_filtered=true; //else in_uWaves_filtered=false; // V2.12.92 - //filtro para falsos positivos del sensor uwaves bool sensor0=digitalRead (in_uWaves);
if (sensor0!=sensor0_old){ sensor0_old=sensor0; if (sensor0==HIGH) oldmilis=millis();
} if((millis()-oldmilis)>time_filtro_uWaves) {
if (sensor0==HIGH)in_uWaves_filtered=HIGH;
oldmilis=0;
} if (sensor0==LOW)in_uWaves_filtered=LOW;

// saves the date/time of the last detection if(in_uWaves_filtered|| digitalRead(in_PIR)){ //if(digitalRead (in_PIR) == HIGH && in_uWaves_filtered == HIGH){ time_last_detection = NTPgetdatetime();// EEprom_write_String(EEPROM_ADDR_LAST_TIME_DETECTION, time_last_detection); }

// ** CHECKS ALARM *****
if (alarm_enabled[0]==true){ // si alarma habilitada
//if(digitalRead (in_PIR) == HIGH && in_uWaves_filtered == HIGH) alarm_on[0]=true; //detects PIR + uWaves to put alarm on
//else alarm_on[0]=false; if (rising_edge_true_enabled==false){
copy_sensors(&alarm_on[0],&alarm_on_old[0],MAX_REMOTE_DEVICES); // copy the current value of the sensors
} rising_edge_true_enabled=true;

       //checks if sensors changed then alarm          
       if(alarm_device==false){ // to avoid check sensor when the alarm has been triggered by a door and then no need to check here but in the frame reception routine
             Device_in_alarm=check_sensors(&alarm_on[0],&alarm_on_old[0],MAX_REMOTE_DEVICES);
             if (Device_in_alarm!=-1){                     
                alarm_device=true;  //alarm  because at least a sensor changed 
                //V1.12.92 commented if (device_type[Device_in_alarm]== "door") timer_to_disable=time_to_disable-1;//eliminar el delay para la desactivacion de la alarma  si es puerta para compensar el delay propio del detector de puerta (aprox 10 seg)
                copy_sensors(&alarm_on[0],&alarm_on_old[0],MAX_REMOTE_DEVICES); // copy the current value of the sensors to detect new changes and send to IFTTT each time a sensor changes                      
             }     
       }
       //if(digitalRead (in_PIR) == HIGH && in_uWaves_filtered == HIGH) alarm_on[0]=true; //detects PIR + uWaves to put alarm on             
       //else alarm_on[0]=false;          
       //new approach . now PIR is not used . PIR or uWaves is used but only when wifi is neutralized by robbers      
       if(error_network_flag==true && (in_uWaves_filtered || digitalRead(in_PIR))){
              alarm_on[0]=true; 
              timer_to_disable=time_to_disable-1;//V2.12.8 eliminar el delay para la desactivacion de la alarma para evitar nueva espera despues de espera en la deteccion de error de red
       }

// triggers alarm if all conditions are ok and time delay elapsed if (alarm_true==true || alarm_on_app == 1) { alarm_active = true; // alarma on if (!edge_alarm_on) { edge_alarm_on = true; // si no hay conexion internet envia sms via A6gsm String mensaka= "ALARM ON.Device: "+device_name[Device_in_alarm]+" Status: "+alarm_on[Device_in_alarm];
if (WiFi.status() == WL_CONNECTED){ if (Ping.ping(remote_ip)) { //guarda el time/date de la alarma. ojo no poner fuera del check de red porque si no hay red el NTP.get... genera un boot the esp
time_last_alarm = NTPgetdatetime();//timeClient.getFormattedTime (); EEprom_write_String(EEPROM_ADDR_LAST_TIME_ALARM, time_last_alarm);
if (Device_in_alarm<0) Device_in_alarm=0; //avoid error when Device_in_alarm=-1
send_IFTTT("call",mensaka);//enviar call a JJ send_IFTTT("sms",mensaka);// enviar call a JJ send_IFTTT("mail",mensaka);// enviar mail a JJ send_IFTTT1("call",mensaka);// enviar call a gloria send_IFTTT1("sms",mensaka);// enviar sms a gloria send_IFTTT1("mail",mensaka);// enviar mail a gloria
}
else { // no hay ping //Serial.println("ping error!! send alarm SMS message , alarm_on_app=" + String(alarm_on_app) + "PIR= " + digitalRead (in_PIR) + " mW= " + in_uWaves_filtered + "alarm_0n:" + String(alarm_active)); if (Device_in_alarm<0) Device_in_alarm=0; //avoid error when Device_in_alarm=-1 A6_send_sms (myPhoneNumber, alarm_message + mensaka); delay(500); A6_call (myPhoneNumber); manual_sent = 1; } }
else { // no hay red wifi //Serial.println("WIFI error!! send alarm SMS message , alarm_on_app=" + String(alarm_on_app) + "PIR= " + digitalRead (in_PIR) + " mW= " + in_uWaves_filtered + "alarm_0n:" + String(alarm_active)); if (Device_in_alarm<0) Device_in_alarm=0; //avoid error when Device_in_alarm=-1 A6_send_sms (myPhoneNumber, alarm_message + mensaka); delay(500); A6_call(myPhoneNumber); manual_sent = 1;
}
if (manual_sent == 0 && alarm_on_app == 1) { // en caso de alarma remota manual pero no se ha enviado SMS //Serial.println("manual_sent==0 && alarm_on_app==1 A6_Status= " + String(A6_status)); if (Device_in_alarm<0) Device_in_alarm=0; //avoid error when Device_in_alarm=-1 A6_send_sms (myPhoneNumber, alarm_message + mensaka); delay(500); A6_call (myPhoneNumber);
} //ACTIVA PWM para SIRENA siren_status=1; }// end edge alarm on // detects each time a sensor changes and sends event to IFTTT to track the journey of the robber
Device_track_alarm=check_sensors(&alarm_on[0],&alarm_on_old[0],MAX_REMOTE_DEVICES);// busca cambio en sensor
if (Device_track_alarm!=-1){ copy_sensors(&alarm_on[0],&alarm_on_old[0],MAX_REMOTE_DEVICES); // copy the current value of the sensors to detect new changes and send to IFTTT each time a sensor changes String mensaka= "Track Sensor: "+device_name[Device_track_alarm]+" Status: "+alarm_on[Device_track_alarm];
// si no hay conexion internet envia sms via A6gsm if (WiFi.status() == WL_CONNECTED){ if (Ping.ping(remote_ip)) { if (Device_track_alarm<0) Device_track_alarm=0; //avoid error when Device_in_alarm=-1
send_IFTTT("sms",mensaka); send_IFTTT("mail",mensaka); }
else { // no hay ping if (Device_track_alarm<0) Device_track_alarm=0; //avoid error when Device_in_alarm=-1
A6_send_sms (myPhoneNumber, alarm_track + mensaka); delay(500); manual_sent = 1; } }
else { // no hay red wifi //Serial.println("WIFI error!! send alarm SMS message , alarm_on_app=" + String(alarm_on_app) + "PIR= " + digitalRead (in_PIR) + " mW= " + in_uWaves_filtered + "alarm_0n:" + String(alarm_active)); if (Device_track_alarm<0) Device_track_alarm=0; //avoid error when Device_in_alarm=-1 A6_send_sms (myPhoneNumber, alarm_track + mensaka); delay(500); manual_sent = 1;
}

             }              

}// end alarm ON

}// end alarma habilitada
else {//si alarma no habilitada alarm_enabled[0]=false; alarm_active = false; alarm_true=false; timer_to_disable=0; alarm_device=false; alarm_on[0]=false;
//Device_in_alarm=0; alarm_on_app = 0; edge_alarm_on = false; manual_sent = 0; siren_status=0;
rising_edge_true_enabled=false; }

// * END CHECKS ALARM ***** //* PWM sirena *** if (siren_status==0){ digitalWrite (out_sirena, LOW);
current_time_siren_ON = 0; current_time_siren_OFF = 0; current_siren_times=0; } if (siren_status==1) { // PWM ON digitalWrite (out_sirena, HIGH);
if (current_time_siren_ON >= siren_time_ON) { current_time_siren_OFF = 0; siren_status=2; }
} if (siren_status==2) { // PWM OFF digitalWrite (out_sirena, LOW); if (current_time_siren_OFF >= siren_time_OFF) {
if (++current_siren_times>=siren_times){ siren_status=0; } else { current_time_siren_ON = 0; siren_status=1; } }
}

// saves changes of enabled alarm in eeprom and sends to if (alarm_enabled[0]!=alarm_enabled_old){
alarm_enabled_old=alarm_enabled[0]; EEPROM.put(EEPROM_ADDR_ENABLE, alarm_enabled_old); EEPROM.commit();
//deteccion de cambio en el enabled para avisar a todos los PIR // sends alarm enabled status to all PIRs , then they will take picture before send their status to the central /
for (int pp=1;pp<=MAX_REMOTE_DEVICES-1;pp++){ // eliminado en V2.12.5 //yield(); if (device_type[pp]=="pir"){
send_msg_device(alarm_enabled[0],ip_device[pp],port_device[pp]); }
} /
} //
V2.12.9 - detection of power up and down if(digitalRead (in_power_on)!=old_power_sts){ old_power_sts=digitalRead (in_power_on); String mensaka; if(digitalRead (in_power_on)) mensaka="POWER UP: ";
else mensaka="POWER DOWN: "; mensaka+=digitalRead (in_power_on);
if (WiFi.status()== WL_CONNECTED){ if (Ping.ping(remote_ip)) send_IFTTT("sms",mensaka);
else A6_send_sms (myPhoneNumber, powerdown_message); // no ping
} // end if WIFI connected else { if(digitalRead (in_power_on)) A6_send_sms (myPhoneNumber, powerup_message); // else A6_send_sms (myPhoneNumber, powerdown_message); //
}
}

// * deteccion de ESPUp **** if (edge_ESPup == false) {
edge_ESPup = true;
if (WiFi.status() == WL_CONNECTED){
if (Ping.ping(remote_ip)){
send_IFTTT("mail","ESP_INIT: "+ reset_cause);
} else A6_send_sms (myPhoneNumber,ESPup_message); // no ping
}// end wifi connected else A6_send_sms (myPhoneNumber, ESPup_message);// no WIFI
}

//*** //**** Server starts handling queries **** //** server.handleClient();// server handle info

//** //**** ddns update regularly**** //** // ######## GET PUBLIC IP ######## // if (update_DDNS == 1) {
//print_heap(); update_DDNS = 0;
HTTPClient http; http.begin("http://ipv4bot.whatismyipaddress.com/"); delay(10); int httpCode = http.GET(); delay(10); if (httpCode > 0) { if (httpCode == HTTP_CODE_OK) { new_ip = http.getString(); } } http.end(); // Open a connection to Ipify to get the public IP address

// ######## CHECK & UPDATE ######### //
if (old_ip != new_ip) {
  HTTPClient http1;
  String cmd1 = "http://www.duckdns.org/update?domains=" + domain_ddns + "&token=" + token_ddns + "&ip="; // no es necesario enviar la nueva IP , ya lo calcula ducksdns
  http1.begin(cmd1);
  delay(10);
  int httpCode1 = http1.GET();
  delay(10);
  if (httpCode1 > 0) {
    old_ip = new_ip;
  }
  http1.end();
}

}// fin ddns update // checks WIFI and internet network connection if (check_network == 1) { // flag para indicar que hay que chequear WIFI y enviar ping para chequeo de la red (si se hace el ping en la rutina del timer no funciona bien //print_heap();// pru check_network = 0; //to do only once // detects WIFI failure if (WiFi.status() != WL_CONNECTED){ // Not necessary to check ping since there is no network
error_network_count = 0; // reset de contador de errores counter_wifi_error++;
if(alarm_enabled[0]) counter_wifi_error++; //V2.12.8 - to reduce delay when alarm is enabled and network fails
if (counter_wifi_error>2 && error_network_flag == false) {// wifi error after 2 attempts error_network_flag = true; counter_wifi_error=0; Serial.println(FPSTR("Network ERROR: WIFI DISCONNECTED")); //When alarm enabled --> sends SMS if network fails if (alarm_enabled[0]== true) { // si alarma habilitada
A6_send_sms (myPhoneNumber, error_wifi_message); }
}
} else { // if WIFI well connected counter_wifi_error=0;
if (Ping.ping(remote_ip)) { // enviar ping error_network_flag = false; // reset de bit indicando error de red error_network_count = 0; // reset de contador de errores check_network = 0;
Serial.println(FPSTR("PING OK"));
} else { error_network_count++; //incremento de contador de errores if(alarm_enabled[0]) counter_wifi_error++; //V2.12.8 - to reduce delay when alarm is enabled and network fails
} if (error_network_count >= ping_times && error_network_flag == false) { // si error varias veces y no hay error de red --> error de red y envio de SMS error_network_flag = true; Serial.println(FPSTR("Network ERROR: ping not responding")); if (alarm_enabled[0]== true) { // si alarma habilitada
A6_send_sms (myPhoneNumber, error_network_message); } check_network = 0; }
} /BORRAR/ sends alarm enabled status to all PIRs , then they will take picture before send their status to the central for (int pp=1;pp<=MAX_REMOTE_DEVICES-1;pp++){ yield(); if (device_type[pp]=="pir"){
send_msg_device(alarm_enabled[0] , ip_device[pp],port_device[pp]); } }
/ }// end check network

//***** }//****fin del loop del programa* //***

// *** // **** FUNCIONES * // ****

// ***** // **Server management - replies to the client requests ** // **** void handleRootPath() { //Handler for the rooth path // ** //* OJO esto es necesario para que no haga reboot cada ciertas horas * // ** //Serial.println(FPSTR("received client request")); //delay(10); String req = server.argName(0); Requestok = false; //send_response_to_device=false; // Match the request int slave_nb; //* request from other device to this central device - frame contains data separated by spaces****
if (req == "status_frame") { // indicates frame from device
//Serial.println(FPSTR("received status_frame"));
slave_nb=server.arg(0).toInt(); // if (slave_nb>=0 && slave_nb<=MAX_REMOTE_DEVICES-1) { // checks to avoid resets because nb slave > maximum comm_status[slave_nb]=true; //communication is working comm_error_sent[slave_nb]=false; comm_counter[slave_nb]++; // communication timer for timeout
device_type[slave_nb]=server.arg(1); device_name[slave_nb]=server.arg(2);
alarm_on[slave_nb]=server.arg(3).toInt();
alarm_enabled[slave_nb]=server.arg(4).toInt();
detector_1[slave_nb]=server.arg(5).toInt();
detector_2[slave_nb]=server.arg(6).toInt();
battery_status[slave_nb]=server.arg(7).toInt(); battery_voltage[slave_nb]=server.arg(8).toFloat(); SSID_device[slave_nb]=server.arg(9);//SSID_device[slave_nb]=getValue(server.arg(9),0,0); last_date_time_device[slave_nb] = NTPgetdatetime();//timeClient.getFormattedTime ();
last_date_time_device[slave_nb].replace(" ","-"); // JJPRU quita el espacio al sting de fecha y hora ip_device[slave_nb]=server.arg(10); port_device[slave_nb]=server.arg(11).toInt(); // save in eeprom the values .
write_eeprom_devices(slave_nb);

          // if keypad then enable or disable the alarm
          if (device_type[slave_nb]=="keypad") {         
            if(alarm_enabled[slave_nb]==true)  alarm_enable_rcv=true;      
            else {
                 alarm_enabled[0]=false;   
                 //alarm_true_enabled=false;        
                 alarm_enable_rcv=false;
                 timer_to_enable=0;
            }
          }// end keypad

         // V2.1 if door sensor then activate the alarm if alarm is enabled  
        if ((alarm_enabled[0]==true) && (device_type[slave_nb]=="door")){  // si alarma habilitada  --> active alarm regardless of sensor status
               //checks if sensors changed then alarm          
                Device_in_alarm=slave_nb;    
                alarm_device=true;  //alarm  because message received from the device              
        }      // end door sensor

         // send_response_to_device=true; // will send response to the device to indicate the status of the alarm (enable - disable) , this will indicate the device if it has to send to IFTTT  

    //sends response to the device after reception of device status frame
         //if(send_response_to_device==true){
              String s = "response=";
              if (device_type[slave_nb]=="keypad") {
                s += String(alarm_enable_rcv)  ;//sends the enable status of the alarm to the keypad
              }
              else{
                s += String(alarm_enabled[0])  ;//// V2.1 sends the enable status of the alarm to the devices (except keypad)
              }                  
              s += "%";// to detect end of frame at the server side
              server.send(200, "text/plain", s);
         //}//end send response to device
   }// end nb slave is correct

}// end reception of status frame
//* request from APP to this central device **** if (req == "alarm_disabled") { //app client request to dissable alarm alarm_enabled[0]= false; //resets the timer for alarm_enabled alarm_enable_rcv=false; timer_to_enable=0; Requestok = true; } else if (req == "alarm_enabled") { //client request to alarm alarm timer_to_enable=0; alarm_enable_rcv=true; Requestok = true; } else if (req == "alarm_on") { //client request to set alarm ON manually and also send SMS + call through A6 //A6_send_sms (myPhoneNumber, alarm_message + device_name[Device_in_alarm]); alarm_enabled[0]= true; alarm_on_app = 1; Requestok = true; } else if (req == "alarm_off") { //client request to set alarm OFF alarm_on_app = 0; //resets the timer for alarm_enabled alarm_enable_rcv=false; timer_to_enable=0; Requestok = true; } else if (req == "A6_sms_call") { //client request to send SMS
A6_send_sms (myPhoneNumber, alarm_message + time_last_alarm); delay(500); A6_call (myPhoneNumber); Requestok = true; } //*
client request to read values else if (req.indexOf("getvalues") != -1) { Requestok = true; //Serial.println(FPSTR("received getvalues")); } // * client request writing parameters*** else if (req.indexOf("setconfig") != -1) { if (server.arg(0).toInt()>10 && server.arg(0).toInt()<50) wifi_time_out=server.arg(0).toInt(); //15 if (server.arg(1).toInt()>5 && server.arg(1).toInt()<100) time_to_enable=server.arg(1).toInt();//30 if (server.arg(2).toInt()>5 && server.arg(2).toInt()<100) time_to_disable=server.arg(2).toInt();//10 if (server.arg(3).toInt()>5 && server.arg(3).toInt()<100) siren_time_ON=server.arg(3).toInt();//15 if (server.arg(4).toInt()>1 && server.arg(4).toInt()<50) siren_time_OFF=server.arg(4).toInt();//5 if (server.arg(5).toInt()>=0 && server.arg(5).toInt()<50) siren_times=server.arg(5).toInt();//5

String s = "setconfig";
server.send(200, "text/plain", s);   

}
// * client request reading parameters*** else if (req.indexOf("getconfig") != -1) { String s = "getconfig"; s += " " + String(wifi_time_out) ;//posicion 1 s += " " + String(time_to_enable) ;//posicion 2 s += " " + String(time_to_disable) ;//posicion 3 s += " " + String(siren_time_ON) ;//posicion 4 s += " " + String(siren_time_OFF) ;//posicion 5 s += " " + String(siren_times) ;//posicion 6 s += " " + String(ALEXA_DEVICE_ALARM_ENABLE) ;//posicion 7 s += " " + String(ALEXA_DEVICE_ALARM_ON) ;//posicion 8 server.send(200, "text/plain", s);
}

// sends response to the app after reception of the getvalues query if (Requestok == true) { String s = "getvalues"; s += " " + String(alarm_enabled[0]) ;//posicion 1 s += " " + String(alarm_active) ;//posicion 2 s += " " + String(digitalRead (in_PIR)) ;//posicion3 s += " " + String(in_uWaves_filtered) ;//posicion 4 s += " " + String(digitalRead (out_sirena)) ;//posicion 5 s += " " + time_last_alarm;//posicion 6 y 7 if (Device_in_alarm<0) Device_in_alarm=0; //avoid error when Device_in_alarm=-1 s += " " + device_name[Device_in_alarm];//posicion 8 s += " " +String(digitalRead (in_power_on)) ;//posicion 9 s += " " +String(A6_status) ; // status del modulo A6 //posicion 10 s += " " + String(battery_voltage[0]) ; // voltaje de bateria //posicion 11 s += " " + String(battery_status[0]) ; // estado de carga de bateria //posicion 12 s += " " + WIFI_SSID ; // red wifi a la que esta conectada la central //posicion 13 s += " " + String(time_to_enable-timer_to_enable);// posicion 14 this will indicate the APP that alarm is waiting for enable s += " " + time_last_detection;// posicion 15 y 16 this will send the last time that sensor has detected presence s += " " + String(ESP.getHeapFragmentation());// posicion 17 this will indicate the APP heap fragmentation percentage

// sends the status of all remote devices
for (int pp=1;pp<=MAX_REMOTE_DEVICES-1;pp++){ yield(); s += " " + device_type[pp]; // posicion 18
s += " " + device_name[pp]; // posicion 19 s += " " + String(alarm_enabled[pp]); // posicion 20 s += " " + String(alarm_on[pp]); // posicion 21
s += " " + String(detector_1[pp]); // posicion 22 s += " " + String(detector_2[pp]); // posicion 23 s += " " + String(comm_status[pp]); // posicion 24 //s += " wifi_status " + String(pp) + "=" + String(wifi_status[pp]); // s += " " + String(power_status[pp]); // posicion 25 s += " " + String(battery_status[pp]); // posicion 26 s += " " + String(battery_voltage[pp]); // posicion 27
s += " " + SSID_device[pp];// posicion 28
s += " " + last_date_time_device[pp];// posicion 29 y 30
} server.send(200, "text/plain", s);
}//end request is true

}// end Server management

// ***** // **ENVIO SMS MEDIANTE MODULO A6 GSM/GPRS ** // ** void A6_send_sms (String number, String message) { SMS_sent_recently = true; //flag para retardar alarma en caso de que este habilitada timer_after_SMS = 0; // timer a 0 para retardo antes de comprobar alarma
A6_clear_buffer (); A6_wait_reply = 1; A6_timeout = 0; ndx = 0;

ifdef A6_ENABLED

a6Serial.println("AT+CMGS=\"" + number + "\"\r\n"); // envia SMS delay(200); a6Serial.print(message); //text content a6Serial.write(26); a6Serial.println(FPSTR(ATH)); //hang up

endif

} // ***** // **ENVIO SMS MEDIANTE MODULO A6 GSM/GPRS ** // ** void A6_call (String number) { SMS_sent_recently = true; //flag para retardar alarma en caso de que este habilitada timer_after_SMS = 0; // timer a 0 para retardo antes de comprobar alarma
A6_clear_buffer (); A6_wait_reply = 1; A6_timeout = 0; ndx = 0;

ifdef A6_ENABLED

a6Serial.println(FPSTR(ATH)); //hang up delay(500); A6_calling = 0; a6Serial.println("ATD" + number); // hace llamada
A6_calling = 1; A6_calling_time = 0;

endif

} // *** // **//borrar buffer de recepcion A6 GSM ** // ** void A6_clear_buffer () { receivedA6[0] = 0; //borrando el primer caracter es suficiente } // * // **//escribe string en EEPROM * // ** void EEprom_write_String(int add, String data){
int _size = data.length(); int i; for (i = 0; i < _size; i++) { EEPROM.write(add + i, data[i]); } EEPROM.write(add + _size, '\0'); //Add termination null character for String Data EEPROM.commit(); }

// ***** // **//lee string de EEPROM * // **** String EEprom_read_String(int add){ int i; char data[MAX_CHAR_STRING]; //Max 100 Bytes int len = 0; unsigned char k; k = EEPROM.read(add); //Serial.println("addr: " + String(add)); while (k != '\0' && len < MAX_CHAR_STRING) //Read until null character { k = EEPROM.read(add + len); data[len] = k; len++; } data[len] = '\0'; return String(data); } // reads voltage of the battery void read_battery() { // read the analog in value and calculation of battery voltage . uses 1000 as R1 and 220 as R2 . uses a correction factor measured empirically battery_voltage[0] = (analogRead(analogInPin) / 1024.0) ((1000.0 + 220.0) / 220.0) 1, 230435385; if (battery_voltage[0] >= 3.7) battery_status[0] = 2 ; if (battery_voltage[0] < 3.7 && battery_voltage[0] >= 3.5) battery_status[0] = 1; if (battery_voltage[0] < 3.5) battery_status[0] = 0 ; }

//*** //*checks if any sensor has changed and returns the sensor number that caused the alarm ** //*** signed int check_sensors(bool bit_array1 , bool bit_array2, int nbits){ for(int pp=0;pp<nbits;pp++){ yield(); if (bit_array1[pp]!=bit_array2[pp]){
return pp; //al menos un sensor ha cambiado de estado devuelve el valor del sensor que ha cambiado--> alarma } } return (-1);//ningun sensor ha cambiado de estado --> alarma

} //*** //*copy status of sensors from array1 to array2 to detect any change when alarm is enabled ** //*** void copy_sensors(bool bit_array1 , bool bit_array2, int nbits) { for(int pp=0;pp<nbits;pp++) { yield(); bit_array2[pp]=bit_array1[pp];
} return ; } // gets date and time from NTP server String NTPgetdatetime(){

ifdef NTP_ENABLED

   timeClient.update();
   unsigned long epochTime = timeClient.getEpochTime();     
   //Get a time structure
struct tm *ptm = gmtime ((time_t *)&epochTime);   
int monthDay = ptm->tm_mday;  
int currentMonth = ptm->tm_mon+1; 
int currentYear = ptm->tm_year+1900;   
return timeClient.getFormattedTime()+ " " + monthDay + "/" + currentMonth + "/" +currentYear;

else

return ("00:00:00 00/00/0000");

endif

}

// ***** // **WRITE EN EEPROM VALORES DE REMOTE DEVICES** // **

void write_eeprom_devices(int slave){ int ad=slave*FIRST_ADDR_EEPROM;// first address to write
EEprom_write_String(ad, device_type[slave]); ad=ad+MAX_CHAR_STRING; EEprom_write_String(ad , device_name[slave]); ad=ad+MAX_CHAR_STRING; EEPROM.write(ad,alarm_on[slave]); ad=ad+MAX_CHAR_BOOL;
EEPROM.write(ad , alarm_enabled[slave]); ad=ad+MAX_CHAR_BOOL;
EEPROM.write(ad , detector_1[slave]); ad=ad+MAX_CHAR_BOOL;
EEPROM.write(ad , detector_2[slave]); ad=ad+MAX_CHAR_BOOL; EEPROM.write(ad , battery_status[slave]); ad=ad+MAX_CHAR_BOOL;
EEPROM.put(ad , battery_voltage[slave]); ad=ad+MAX_CHAR_FLOAT;
EEprom_write_String(ad , SSID_device[slave]); ad=ad+MAX_CHAR_STRING; EEprom_write_String(ad , last_date_time_device[slave]);
ad=ad+MAX_CHAR_STRING; EEprom_write_String(ad , ip_device[slave]);
ad=ad+MAX_CHAR_BOOL;
EEPROM.put(ad , port_device[slave]);
EEPROM.commit();
} // ***** // **READ DE EEPROM VALORES DE REMOTE DEVICES** // **

void read_eeprom_devices(int slave){ int ad=slave*FIRST_ADDR_EEPROM;// first address to write String typo=EEprom_read_String(ad);
comm_status[slave]=1;
device_type[slave]= EEprom_read_String(ad);
ad=ad+MAX_CHAR_STRING; device_name[slave]=EEprom_read_String(ad); ad=ad+MAX_CHAR_STRING; alarm_on[slave]= EEPROM.read(ad); ad=ad+MAX_CHAR_BOOL;
alarm_enabled[slave]=EEPROM.read(ad); ad=ad+MAX_CHAR_BOOL;
detector_1[slave]=EEPROM.read(ad); ad=ad+MAX_CHAR_BOOL;
detector_2[slave]=EEPROM.read(ad); ad=ad+MAX_CHAR_BOOL; battery_status[slave]= EEPROM.read(ad); ad=ad+MAX_CHAR_BOOL;
EEPROM.get(ad,battery_voltage[slave]);
ad=ad+MAX_CHAR_FLOAT;
SSID_device[slave]=EEprom_read_String(ad); ad=ad+MAX_CHAR_STRING; last_date_time_device[slave]=EEprom_read_String(ad);
} //Alexa callback functions bool alexa_protection_on() { // this just sets a variable that the main loop() does something about Serial.println(FPSTR("ALARM ENABLED switched by Alexa")); timer_to_enable=0; alarm_enable_rcv=true;
return(true); } bool alexa_protection_off() { // this just sets a variable that the main loop() does something about Serial.println(FPSTR("ALARM DISABLED switched by Alexa")); alarm_enabled[0]=false; alarm_enable_rcv=false; timer_to_enable=0;
return(false); } bool alexa_siren_on() { Serial.println(FPSTR("ALARM ON switched by Alexa"));
alarm_enabled[0]= true; alarm_on_app = 1; return(true);} bool alexa_siren_off() { Serial.println(FPSTR("ALARM OFF switched by Alexa")); alarm_enabled[0]= false;
alarm_on_app = 0; //resets the timer for alarm_enabled alarm_enable_rcv=false; timer_to_enable=0; return(false); } // send to IFTTT //*****envio de evento a IFTTT a JJ . type=sms,mail,call . dispositivo= texto libre (alarma,caldera,persiana etc), mensaje=mensaje a enviar (alarma ON , init , network fail, power down,etc) void send_IFTTT(String type,String mensaje){
String time_date = NTPgetdatetime();//timeClient.getFormattedTime ();
time_date.replace(' ', '-'); // reemplaza espacio por caracter "-" si no el IFTTT no funciona porque detecta un espacio
client.add("ALARMA PISO " + mensaje + time_date); // specifies the args of type "String"
//Send value can specify up to three
//client.add(mensaje); // optional
//client.add(time_date); // option
int str_len = type.length() + 1; // Length (with one extra character for the null terminator) char char_array[str_len]; // Prepare the character array (the buffer) type.toCharArray(char_array, str_len);// Copy it over
client.sendAll(char_array);

}// end send msg to IFTTT a JJ //**** envio de evento a IFTTT a gloria . type=sms,mail,call . dispositivo= texto libre (alarma,caldera,persiana etc), mensaje=mensaje a enviar (alarma ON , init , network fail, power down,etc) void send_IFTTT1(String type,String mensaje){
String time_date = NTPgetdatetime();//timeClient.getFormattedTime (); time_date.replace(' ', '-'); // reemplaza espacio por caracter "-" si no el IFTTT no funciona porque detecta un espacio
client1.add("ALARMA PISO " + mensaje + time_date); // specifies the args of type "String"
//Send value can specify up to three //client1.add(mensaje); // optional //client1.add(time_date); // option
int str_len = type.length() + 1; // Length (with one extra character for the null terminator) char char_array[str_len]; // Prepare the character array (the buffer) type.toCharArray(char_array, str_len);// Copy it over client1.sendAll(char_array);
}// end send msg to IFTTT a Gloria

void print_heap(){ //* check memory leaks *** //returns the free heap size.returns the fragmentation metric (0% is clean, more than ~50% is not harmless).returns the largest contiguous free RAM block in the heap, useful for checking heap fragmentation. NOTE: Maximum malloc()able block will be smaller due to memory manager overheads. //Serial.print(ESP.getFreeHeap()); Serial.print("fragm: "); Serial.print(ESP.getHeapFragmentation()); Serial.print("% Max block: "); Serial.print(ESP.getMaxFreeBlockSize());
Serial.println(" bytes ");
} //recepcion de trama del A6 void checkSwSerial(SoftwareSerial* ss) { // gestion del buffer de comunicacion con A6 GSM para recibir los mensajes

ifdef A6_ENABLED

      while (ss->available() > 0 ) {// recoge los caracteres del buffer 
        char rc = ss->read();
        receivedA6[ndx] = rc;
        ndx++;
        if (ndx > buffer_max - 2) ndx = 0;
        //yield();
      }
#endif   

} //convert ip from string to 4 bytes array void parseBytes(const char str, char sep, byte bytes, int maxBytes, int base) { for (int i = 0; i < maxBytes; i++) { bytes[i] = strtoul(str, NULL, base); // Convert byte str = strchr(str, sep); // Find next separator if (str == NULL || *str == '\0') { break; // No more separators, exit } str++; // Point to next character after separator } } // sends PIR devices status of the alarm void send_msg_device(bool status_alarm , String iphost,byte ipport){ Serial.println("SEND MSG TO DEVICE"); Serial.println(iphost+" "+String(ipport)); const int API_TIMEOUT = 5000; //keep it long if you want to receive headers from client WiFiClient cliente;// to communicate with the central
cliente.setTimeout(API_TIMEOUT); // Hacemos la petición mediante SSL
byte ip[4]; parseBytes(iphost.c_str(), '.', ip, 4, 10);
int pp=cliente.connect(ip, ipport); if (pp==1) {
//Serial.println("Connection ok: " + String(pp)); // Construimos la petición HTTP
String toSend = "GET /?alarm_status=";
toSend += "&alarm_on=" + String(ipport);
toSend += "&alarm_enabled=";
toSend += String(status_alarm); //toSend +=" HTTP/1.1"; //toSend += "\r\n"; //toSend += "Connection: close\r\n\r\n";
cliente.print(toSend); Serial.println(toSend); } // Desconectamos del cliente cliente.flush();//espera a que todos los datos del buffer de recepcion esten leidos delay(200); cliente.stop();//cierra el socket delay(200); //espera a que el socket se cierre en el server de lo contrario , al pasar a sleep muy rapido , en el server se queda abierto y se fragmenta la memoria

} //V2.12.93 Funcion conecta wifi Basada en https://github.com/tve/low-power-wifi/blob/master/esp8266-deep-sleep/src/main.ino // Se puede escoger el modo de conexion por si se necesita rapidez de conexion como por ejemplo en los detectores PIR con uWaves que se dejan en sleep y se //despiertan con el uwaves. Tambien para las puertas .el parametro modo : 0=5seg 1=2seg 2=3seg 3=1,2seg. Para la conexion en el setup se usa modo 0 bool connect_wifi(int modo){
readcfg(); //recupera los ultimos parametros if (readcfg() == 0) cfgbuf.mode = modo; // can only force if we got saved info else readcfg();
//printf("\n===== Deep sleep test starting mode=%d =====\n", cfgbuf.mode); if (WiFi.getMode() != WIFI_OFF) { WiFi.persistent(true); WiFi.mode(WIFI_OFF); } WiFi.persistent(false); WiFi.mode(WIFI_STA);
WiFi.setSleepMode(WIFI_NONE_SLEEP); int m = cfgbuf.mode;
switch (cfgbuf.mode) { case 0:
WiFi.begin(ssid, password);
break; case 1: WiFi.begin(ssid, password, cfgbuf.chl, cfgbuf.mac); break; case 2: { bool ok = WiFi.config(cfgbuf.ip, cfgbuf.gw, cfgbuf.msk, cfgbuf.dns); if (!ok) printf("* Wifi.config failed, mode=%d\n", m); WiFi.begin(ssid, password); break; } default:
WiFi.config(cfgbuf.ip, cfgbuf.gw, cfgbuf.msk, cfgbuf.dns); WiFi.begin(ssid, password, cfgbuf.chl, cfgbuf.mac); cfgbuf.mode = -1; break; } Serial.println(FPSTR("Connecting Wifi")); wifi_timer=0; // reset timer
while (wifi_timer< wifi_time_out){// x segundos de timeout yield();
if(WiFi.status() == WL_CONNECTED) {
writecfg(); WIFI_SSID=WiFi.SSID(); //Gets the SSID of wifi connected to communicate to the mobile APP
IPAddress ip=WiFi.localIP();//Ethernet.localIP();
Serial.println("Wifi Connected. "+ IpAddress2String(ip)+" " + WIFI_SSID);
return(true);
}
} return(false);
} //*****
//converts IP address to String //*** String IpAddress2String(const IPAddress& ipAddress) { return String(ipAddress[0]) + String(".") +\ String(ipAddress[1]) + String(".") +\ String(ipAddress[2]) + String(".") +\ String(ipAddress[3]); }

Miq1 commented 3 years ago

You are mixing AsyncTCP (FauxmoESP is using that) and synchronous TCP (ESP8266WebServer) here. I made the experience that this may be a problematic combination and moved my own servers (HTTP, Telnet and Modbus) to AsyncTCP as well. I had no reboot issues since.

By the way: it would be helpful if you would enclose your code in triple backtick lines (see the Markdown docs for that) to keep it nicely indented etc. As plain text, it is awkward to read... 😉

jjsanma1 commented 3 years ago

thanks Miq1 . Sorry for the confusion in the code. I don't use FauxmoESP , there is a // in this line. But I'll try to move to AsyncTCP .