Open jjsanma1 opened 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... 😉
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 .
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
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
} //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
}
// 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);
// 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
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
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
endif
ifdef TIMER2_ENABLED
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
endif
ifdef OTA_ENABLED
endif// enable programacion OTA
// Define alexa devices here.
ifdef ALEXA_ENABLED
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
endif
// alexa loop
ifdef ALEXA_ENABLED
endif
// programacion OTA
ifdef OTA_ENABLED
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;
// 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 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
}// 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);
}// 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
}
// * 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
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
} //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]); }