#include "main.h" #include "NTPClient.h" //#include "driver/" #include #include #include #include #include #define STORAGE_NAMESPACE "storage" #define _OPEN_SYS_ITOA_EXT #define RESTART 1 #define REFRESHMEMBOOT 0 #define RESTARTTIMES 2 #define REFRESHTIMES 4 using namespace std; DHT sensors[SENSORS_NUMBER] = {DHT(04, DHT22), DHT(18, DHT22), DHT(05, DHT22), DHT(17, DHT22), DHT(16, DHT22)}; float temp[SENSORS_NUMBER]; float hum[SENSORS_NUMBER]; Pangodream_18650_CL Battery(ADC_PIN, CONV_FACTOR, READS); WiFiClient WifiClient; PubSubClient MqttClient(WifiClient); WiFiUDP NtpUDP; /** * @brief create NTP profile for frenchs users * * @param NtpUDP: Protocole use * * @param "europe.pool.ntp.org": serve target * * @param 7200: jet lag europe time from France (2 * 3600 sec) */ NTPClient TimeClient(NtpUDP, "europe.pool.ntp.org" , 7200 , 60000); //NTPClient TimeClient(NtpUDP, "pool.ntp.org"); //-------------------- CONDITION --------------------// /** * @brief test if the time is good for restart or refresh memory * * @param hours * @param minutes * @param restart bool to choose which the restart time bool or the resfres time bool will be returned * @return true It's time to refresh or restart * @return false It's not the time to refresh or restart */ bool testTime (int hours, int minutes, bool restart){ // debug parts // Serial.println('\n'); // Serial.println((REFRESHTIMES * TIME_TO_SLEEP) / 3600,DEC); // Serial.println(((REFRESHTIMES * TIME_TO_SLEEP) % 3600) / 60,DEC); // Serial.println('\n'); if (restart){ // restart parts if(hours < (RESTARTTIMES * TIME_TO_SLEEP) / 3600) return true; else{ if((hours = (RESTARTTIMES * TIME_TO_SLEEP) / 3600) && (minutes <= ((RESTARTTIMES * TIME_TO_SLEEP) % 3600) / 60))return true; return false; } } else { // refresh parts if(hours >= (RESTARTTIMES * TIME_TO_SLEEP) / 3600){ if(hours < (REFRESHTIMES * TIME_TO_SLEEP) / 3600)return true; else{ if((hours = (REFRESHTIMES * TIME_TO_SLEEP) / 3600) && (minutes <= ((REFRESHTIMES * TIME_TO_SLEEP) % 3600) / 60))return true; else{ return false; } } } } // Not needed but carefully habits return false; } // bool testTime (int hours, int minutes, bool restart){ // // debug parts // // Serial.println('\n'); // // Serial.println((REFRESHTIMES * TIME_TO_SLEEP) / 3600,DEC); // // Serial.println(((REFRESHTIMES * TIME_TO_SLEEP) % 3600) / 60,DEC); // // Serial.println('\n'); // if (restart){ // restart parts // if( hours >= 12 && minutes >= 0 ) return true; // else{ // if((hours < 12) /*&& (minutes <= ((RESTARTTIMES * TIME_TO_SLEEP) % 3600) / 60) */)return true; // return false; // } // } else { // refresh parts // if(hours >= 12){ // if(hours <= 14 && minutes > 20 )return true; // else{ // if((hours = (REFRESHTIMES * TIME_TO_SLEEP) / 3600) && (minutes <= ((REFRESHTIMES * TIME_TO_SLEEP) % 3600) / 60))return true; // else{ // return false; // } // } // } // } // // Not needed but carefully habits // return false; // } //-------------------- FONCTIONS --------------------// //-------------- Connexion MQTT --------------// void setupMQTT(const char *address, int port) { MqttClient.setServer(address, port); } void setupWIFI(const char *wifi_name, const char *password) { Serial.println('\n'); WiFi.begin(wifi_name, password); Serial.print("Connecting to "); Serial.print(wifi_name); int cpttry = 10; while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print('.'); /* stop trying wifi connexion */ cpttry--; if(cpttry == 0){ Serial.print("wifi: 10 try go to sleep"); sleep(); } } Serial.println('\n'); Serial.println("Connection established!"); Serial.print("IP address:\t"); Serial.println(WiFi.localIP()); } void reconnect(void) { Serial.println("Connecting to MQTT Broker..."); int cpttry = 10; while (!MqttClient.connected()) { /* stop trying mqtt connexion */ cpttry--; if(cpttry == 0){ Serial.print("Mqtt: 10 try go to sleep"); sleep(); } Serial.print("."); if (MqttClient.connect(ESPNAME, MQTT_USER, MQTT_MDP)) // MQTT_MDP (mot de passe) { Serial.println("Connected."); } } } //-------------- Initialisation et lecture des capteurs --------------// void initSensors(DHT *sensors, int number) { int i; for (i = 0; i < number; i++) { sensors[i].begin(); } } void readSensors(DHT sensors[], float temp[], float hum[], int number) { int i; for (i = 0; i < number; i++) { *(temp + i) = sensors[i].readTemperature(); *(hum + i) = sensors[i].readHumidity(); } } //-------------------- Sleep de l'ESP --------------------// void sleep() { esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * US_TO_S_FACTOR); esp_deep_sleep_start(); } //exemple d'une triple utilisation de valeur pour une fonction utilise pour la date std::tuple getDate() { struct timeval synctime; TimeClient.forceUpdate(); time_t rawtime = TimeClient.getEpochTime(); synctime.tv_sec = rawtime; synctime.tv_usec = 0; if(settimeofday(&synctime,NULL) != 0) std::cout << "error\n" ; //setenv("TZ", "CEST+2", 1); //tzset(); // set timezone to France setenv("TZ", "CET-1CEST-2,M3.5.0/02:00:00,M10.5.0/03:00:00", 2); // set at 2 or 3 (Third parameter) tzset(); struct tm *ti; ti = localtime(&rawtime); int year = ti->tm_year + 1900; int month = (ti->tm_mon + 1) < 10 ? 0 + (ti->tm_mon + 1) : (ti->tm_mon + 1); int day = (ti->tm_mday) < 10 ? 0 + (ti->tm_mday) : (ti->tm_mday); return std::make_tuple(year, month, day); } // Function that gets current epoch time unsigned long getTime() { time_t now = TimeClient.getEpochTime();; struct timeval synctime; struct tm timeinfo; synctime.tv_sec = now; synctime.tv_usec = 0; if(settimeofday(&synctime,NULL) != 0) std::cout << "error\n" ; TimeClient.forceUpdate(); vTaskDelay(1000); if (!getLocalTime(&timeinfo)) { Serial.println("Failed to obtain time"); return(0); } time(&now); Serial.println(now); return now; } //-------------------- Création de trames --------------------// void writeMessage(char *txt, float *temp, float *hum, int number) { int chargelvl = Battery.getBatteryChargeLevel(); //time_t rawtime = TimeClient.getEpochTime(); switch (number) { case 1: sprintf(txt, "|%s|%0.2f|%0.2f", CLUSTER, temp[0], hum[0]); break; case 2: sprintf(txt, "|%s|%0.2f %0.2f|%0.2f %0.2f", CLUSTER, temp[0], temp[1], hum[0], hum[1]); break; case 3: sprintf(txt, "|%s|%0.2f %0.2f %0.2f|%0.2f %0.2f %0.2f", CLUSTER, temp[0], temp[1], temp[2], hum[0], hum[1], hum[2]); break; case 4: sprintf(txt, "|%s|%0.2f %0.2f %0.2f %0.2f|%0.2f %0.2f %0.2f %0.2f", CLUSTER, temp[0], temp[1], temp[2], temp[3], hum[0], hum[1], hum[2], hum[3]); break; case 5: sprintf(txt, "|%s|%0.2f %0.2f %0.2f %0.2f %0.2f|%0.2f %0.2f %0.2f %0.2f %0.2f|%d", CLUSTER, temp[0], temp[1], temp[2], temp[3], temp[4], hum[0], hum[1], hum[2], hum[3], hum[4], chargelvl); break; case 6: sprintf(txt, "|%s|%0.2f %0.2f %0.2f %0.2f %0.2f %0.2f|%0.2f %0.2f %0.2f %0.2f %0.2f %0.2f", CLUSTER, temp[0], temp[1], temp[2], temp[3], temp[4], temp[5], hum[0], hum[1], hum[2], hum[3], hum[4], hum[5]); break; default: Serial.println("Erreur, temp et hum sont trop longs : trop de capteurs"); break; } } /** * @brief read, refresh and return the day boot state * * @return bool at true if the esp was restarted or false if error or not restarted * @inspired of https://github.com/espressif/esp-idf/blob/master/examples/storage/nvs_rw_blob/main/nvs_blob_example_main.c */ bool TestBoot(bool resOrRfsh) { nvs_handle_t my_handle; esp_err_t err; bool booted = false; //Serial.println("Test"); // Open err = nvs_open(STORAGE_NAMESPACE, NVS_READWRITE, &my_handle); if (err != ESP_OK){ Serial.println("Erreur open nvs persistant storage"); return false; } /******** Refresh part ********/ if(resOrRfsh == REFRESHMEMBOOT){ int32_t restart = REFRESHMEMBOOT; err = nvs_set_i32(my_handle, "restart", restart); if (err != ESP_OK) { Serial.println("Erreur write nvs persistant storage"); return false; } // Commit written value. // After setting any values, nvs_commit() must be called to ensure changes are written // to flash storage. Implementations may write to storage at other times, // but this is not guaranteed. err = nvs_commit(my_handle); if (err != ESP_OK) return err; // Close nvs_close(my_handle); Serial.println("Refresh memory restart state "); return false; } /******** ********/ // Read int32_t restart = 0; // value will default to 0, if not set yet in NVS err = nvs_get_i32(my_handle, "restart", &restart); if (err != ESP_OK && err != ESP_ERR_NVS_NOT_FOUND){ Serial.println("Erreur read nvs persistant storage"); return false; } if(!restart){ // Write restart = 1; err = nvs_set_i32(my_handle, "restart", restart); if (err != ESP_OK) { Serial.println("Erreur write nvs persistant storage"); return false; } // Commit written value. // After setting any values, nvs_commit() must be called to ensure changes are written // to flash storage. Implementations may write to storage at other times, // but this is not guaranteed. err = nvs_commit(my_handle); if (err != ESP_OK) return err; // Close nvs_close(my_handle); Serial.println("Flag restart = 0 (not restarted)"); return true; } else { // Close nvs_close(my_handle); Serial.println("Flag restart = 1 (already restart)"); return false; } /* Not needed but finish properly the function */ // Close Serial.println("Maybe issue: last return"); nvs_close(my_handle); return false; } //-------------------- Initialisation --------------------// void setup() { Serial.begin(9600); Serial.println("-----------------Start---------------------"); setupWIFI(SSID, PWD); setupMQTT(MQTT_ADDRESS, MQTT_PORT); initSensors(sensors, SENSORS_NUMBER); TimeClient.begin(); //int rawtime = (TimeClient.getEpochTime()) % 86400; // 86400 = 60sec*60minutes*24heures unsigned long rawtime = getTime(); int hours = rawtime / 3600, minutes = (rawtime % 3600) / 60 , secondes = rawtime % 60; if (nvs_flash_init() != ESP_OK){ Serial.println("Erreur flash init"); } /** * @brief restart the ESP if there is the time restart * */ if(testTime(hours, minutes, RESTART) && TestBoot(RESTART)){ Serial.println("-----------------RESSSSTTTAAAART---------------------"); ESP.restart(); delay(1000); } else if(testTime(hours, minutes, REFRESHMEMBOOT)){ TestBoot(REFRESHMEMBOOT); } /* ######### test time part ######### Serial.println('\n'); Serial.println(hours,DEC); Serial.println(':'); Serial.println(minutes,DEC); Serial.println(':'); Serial.println(secondes,DEC); Serial.println('\n'); */ } //-------------------- Boucle principale --------------------// void loop() { int year, month, day; int lenght; unsigned long now; char time[30]; char date[30]; char msg[70]; bool horoIssue = false; MqttClient.loop(); if (!MqttClient.connected()) { reconnect(); } readSensors(sensors, temp, hum, SENSORS_NUMBER); writeMessage(msg, temp, hum, SENSORS_NUMBER); TimeClient.update(); TimeClient.getFormattedTime().toCharArray(time, 30); //tie(year, month, day) = getDate(); /* debug print*/ // Serial.println('\n'); // Serial.println(year,DEC); // Serial.println(':'); // Serial.println(month,DEC); // Serial.println(':'); // Serial.println(day,DEC); // Serial.println('\n'); now = getTime(); //TimeClient.update(); //Serial.println(TimeClient.getFormattedTime()); //Solution to the issue generated by the Ntpclient for the horodatage midnight at two o'clock // if (time[0] == '0' && (time[1] == '0' || time[1] == '1')){ // if (day == 31){ // if(month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12){ // day = 1; // month++; // if(month == 13){ // month == 1; // year++; // } // } // }else if (day == 30){ // if(month == 4 || month == 6 || month == 9 || month == 11){ // day = 1; // month++; // } // }else if(day == 29){ // if(month == 2){ // day = 1; // month++; // } // }else{ // day++; // } // } lenght = sprintf(date,"%s|", ultoa(now, date, 10) /* "|%d-%d-%d ", year, month, day */); sprintf(date + lenght, time); sprintf(date + strlen(date), msg); MqttClient.publish(TOPIC, date); Serial.println("-----------------DeepSleep---------------------"); delay(2000); sleep(); delay(1000); }