#include //this needs to be first, e folosit de salvarea credentialelor pe FS #include #include #include //https://github.com/tzapu/WiFiManager #include //https://github.com/bblanchon/ArduinoJson pentru salvarea credentialelor in eprom #include #include #include #include #define DEBUG 0 //0=off 1=on #define PIR D1 // pinul de date D1 la care se conecteaza PIRul bool ARM,lastPIR; unsigned int interval_alarma = 60000; // la ce interval sa trimita notificarile 60 sec = 60000 in cazul in care a re doua alarme consecutive unsigned long t_alarma=0; const unsigned long interval_update=1000*60*5; // face update la 5 min unsigned long t_update=0; char mqtt_user[9]; //le va lua din FS char mqtt_devid[5]; //le va lua din FS char mqttPassword[15]; //urmatoarele le va genera cu functia gen char mqttSUB[23]; char espName[14]; char mqttESP[23]; char mqttALM[25]; char mqttPIR[23]; char mqttLWT[23]; char mqttSTA[25]; char wifiID[15]; const String model = "NodeMCU PIR"; const String ver = "v2.1.2"; const char* mqttServer = "mqtt.clickhome.ro"; const int mqttPort = 1883; String mqttMessage; WiFiClient espClient; PubSubClient client(espClient); bool readConfigFile(); void generate_vars(){ strcpy (mqttPassword, "8219CH"); strcat (mqttPassword, mqtt_user); strcpy (espName, mqtt_user); strcat (espName, "-"); strcat (espName, mqtt_devid); strcpy (mqttSUB, "cmnd/"); strcat (mqttSUB, espName); strcat (mqttSUB, "/ESP"); strcpy (mqttESP, "stat/"); strcat (mqttESP, espName); strcat (mqttESP, "/ESP"); strcpy (mqttPIR, "stat/"); strcat (mqttPIR, espName); strcat (mqttPIR, "/PIR"); strcpy (mqttALM, "stat/"); strcat (mqttALM, espName); strcat (mqttALM, "/ALARM"); strcpy (mqttLWT, "tele/"); strcat (mqttLWT, espName); strcat (mqttLWT, "/LWT"); strcpy (mqttSTA, "tele/"); strcat (mqttSTA, espName); strcat (mqttSTA, "/STATE"); strcpy (wifiID, "ClickHome-"); strcat (wifiID, mqtt_devid); } String ipToString(IPAddress ip){ String s=""; for (int i=0; i<4; i++) s += i ? "." + String(ip[i]) : String(ip[i]); return s; } String getMacAddress() { byte mac[6]; WiFi.macAddress(mac); String cMac = ""; for (int i = 0; i < 6; ++i) { cMac += String(mac[i],HEX); if(i<5) cMac += "-"; } cMac.toUpperCase(); return cMac; } void reconectez() { while (String(mqtt_user)==""){ #if DEBUG Serial.println("Invalid user!"); #endif delay(99999999); } // ma conectez la mqtt server while (!client.connected()) { client.setServer(mqttServer, mqttPort); #if DEBUG Serial.print("AtloopTempting MQTT connection..."); #endif // Incerc sa ma reconectez cu LWT din 5 in 5 secunde if (client.connect(espName, mqtt_user, mqttPassword, mqttLWT, 1, 1, "Offline")) { #if DEBUG Serial.println("connected"); #endif client.publish(mqttLWT,"Online",TRUE); // trimit informatii utile cand ma conectez String esp_info = "{\"ESPMac\":\""; esp_info += getMacAddress(); esp_info += "\",\"IPAddress\":\""; esp_info += ipToString(WiFi.localIP()); esp_info += "\"}"; String netinfo = "{\"Module\":\""; netinfo += String (model); netinfo += "\",\"Version\":\""; netinfo += String (ver); netinfo += "\"}"; client.publish(mqttESP, netinfo.c_str(),TRUE); #if DEBUG Serial.println(netinfo); #endif client.publish(mqttESP, esp_info.c_str(),TRUE); #if DEBUG Serial.println(esp_info); #endif client.subscribe(mqttSUB); } else { #if DEBUG Serial.print("failed, rc="); Serial.print(client.state()); Serial.println(" try again in 60 seconds"); #endif // Wait 60 seconds before retrying delay(60000); } } } void setup() { pinMode(PIR,INPUT_PULLUP); #if DEBUG Serial.begin(115200); #endif // Mount the filesystem bool result = SPIFFS.begin(); #if DEBUG //Serial.println("SPIFFS opened: " + result); #endif readConfigFile(); //citesc user si devid din memorie generate_vars(); //genereaza topicurile de mqtt in baza mqtt_user si mqtt_devid // ma conectez la AP via wifi WiFiManager wifi; wifi.setConfigPortalTimeout(120); // a timeout so the ESP doesn't hang waiting to be configured, for instance after a power failure wifi.setTimeout(180); // sta AP 3 minute apoi se reseteaza din nou if (!wifi.autoConnect(wifiID)) { #if DEBUG Serial.println("timeout - going to sleep"); #endif } delay(200); reconectez(); client.setCallback(getMessage); //setez functia care parseaza mesajele venite prin mqtt String json = "{\"ARM\":\""; json += String (ARM); json += "\"}"; client.publish(mqttPIR, json.c_str(),TRUE); update_state(); //facem update la mqtt cu Uptime } void getMessage(char* topic, byte* payload, unsigned int length) { float t = 0; mqttMessage=""; #if DEBUG Serial.print("Message arrived in topic: "); Serial.println(topic); Serial.print("Message:"); #endif for (int i = 0; i < length; i++) { mqttMessage += (char)payload[i]; } #if DEBUG Serial.println(mqttMessage); #endif // procedura de software update via WEB if (mqttMessage == "update") { String msg="Software update: "; t_httpUpdate_return ret; //ESPhttpUpdate.rebootOnUpdate(false); ret = ESPhttpUpdate.update("http://update.clickhome.ro/pir/arduino.bin"); switch(ret) { case HTTP_UPDATE_FAILED: msg.concat(" eroare:"); msg.concat(ESPhttpUpdate.getLastError()); msg.concat(" motiv:"); msg.concat(ESPhttpUpdate.getLastErrorString().c_str()); break; case HTTP_UPDATE_NO_UPDATES: msg.concat(" no update."); break; case HTTP_UPDATE_OK: msg.concat(" success."); break; } #if DEBUG Serial.println(msg); #endif } if (mqttMessage == "stare") { // citesc starea si o trimit String json = "{\"ARM\":\""; json += String (ARM); json += "\"}"; #if DEBUG Serial.println(json); #endif client.publish(mqttPIR, json.c_str(),TRUE); } if (mqttMessage == "ARM" || mqttMessage == "DISARM") { ARM = (mqttMessage=="ARM") ? true : false; String json = "{\"ARM\":\""; json += String (ARM); json += "\"}"; client.publish(mqttPIR, json.c_str(),TRUE); } // reset la ESP if (mqttMessage == "reset") { String lastwords="Am fost resetat ..."; client.publish(mqttPIR, lastwords.c_str(), TRUE); delay (3000); ESP.reset(); delay (5000); } } bool readConfigFile() { // this opens the config file in read-mode File f = SPIFFS.open("/config.json", "r"); if (!f) { #if DEBUG Serial.println("Configuration file not found"); #endif return false; } else { // we could open the file size_t size = f.size(); // Allocate a buffer to store contents of the file. std::unique_ptr buf(new char[size]); // Read and store file contents in buf f.readBytes(buf.get(), size); // Closing file f.close(); // Using dynamic JSON buffer which is not the recommended memory model, but anyway // See https://github.com/bblanchon/ArduinoJson/wiki/Memory%20model DynamicJsonBuffer jsonBuffer; // Parse JSON string JsonObject& json = jsonBuffer.parseObject(buf.get()); // Test if parsing succeeds. if (!json.success()) { #if DEBUG Serial.println("JSON parseObject() failed"); #endif return false; } #if DEBUG json.printTo(Serial); #endif strcpy(mqtt_user, json["mqtt_user"]); strcpy(mqtt_devid, json["mqtt_devid"]); } return true; } void update_state(){ //facem update la mqtt cu Uptime String json = "{\"Uptime\":"; json += (int)millis()/3600000; //exprimat in ore json += "}"; client.publish(mqttSTA, json.c_str(),FALSE); } void loop() { if (!client.connected()) { reconectez(); } client.loop(); //facem update la $interval_update cu uptime if (millis() - t_update > interval_update){ update_state(); t_update=millis(); } //end update if (ARM==1){ //daca e armat if (digitalRead(PIR)!=lastPIR){ //daca s-a schimbat valoarea if (digitalRead(PIR)==1){ //daca am alarma if (millis() - t_alarma > interval_alarma){ //daca a trecut timpul de la alarma anterioara String json = "{\"PIR\":1}"; client.publish(mqttALM, json.c_str(),FALSE); t_alarma=millis(); #if DEBUG Serial.print("Trimis mqtt alarm:"); #endif } } #if DEBUG Serial.print("Direct PIN:"); Serial.println (digitalRead(PIR)); #endif lastPIR=digitalRead(PIR); } } }