#include "main.h" #include "NTPClient.h" //#include "Effortless_SPIFFS.h" //#include "driver/" #include #include #include #include #include #define STORAGE_NAMESPACE "storage" #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); //-------------------- CONDITION --------------------// bool testTime (int hours, int minutes, bool restart){ 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; } } } } return false; } /** * @brief Time hour for restart or time for refresh restart persistant mem * * @param hours * @param restart bool at true for restart or at false for resfresh memory * @return true right hour for restart or refresh * @return false bad hour for restart or refresh */ bool ishour(int hours, bool restart){ if (restart){ Serial.println('\n'); Serial.println((RESTARTTIMES * TIME_TO_SLEEP) / 3600,DEC); Serial.println('\n'); return hours <= (RESTARTTIMES * TIME_TO_SLEEP) / 3600; } // Then refresh time return (hours >= (RESTARTTIMES * TIME_TO_SLEEP) / 3600) && (hours <= (REFRESHTIMES * TIME_TO_SLEEP) / 3600); } /** * @brief Time minute for restart or time for refresh restart persistant mem * * @param minutes * @param restart bool at true for restart or at false for resfresh memory * @return true right minute for restart or refresh * @return false bad minute for restart or refresh */ bool isminute(int minutes, bool restart){ if (restart){ Serial.println(((RESTARTTIMES * TIME_TO_SLEEP) % 3600) / 60,DEC); Serial.println('\n'); return minutes <= ((RESTARTTIMES * TIME_TO_SLEEP) % 3600) / 60; } // Then refresh time return (minutes >= ((RESTARTTIMES * TIME_TO_SLEEP) % 3600) / 60) && (minutes <= ((REFRESHTIMES * TIME_TO_SLEEP) % 3600) / 60); } /** * @brief Time seconde for restart or time for refresh restart persistant mem * * @param secondes * @param restart bool at true for restart or at false for resfresh memory * @return true right secondes for restart or refresh * @return false bad secondes for restart or refresh */ // bool issecond(int secondes, bool restart){ // if (restart){ // return secondes <= ((2 * TIME_TO_SLEEP) - 1 ) % 60; // } // // Then refresh time // return (secondes > ((2 * TIME_TO_SLEEP) - 1 ) % 60) && (secondes <= ((4 * TIME_TO_SLEEP) - 1 ) % 60); // } //-------------------- 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(); 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; struct tm timeinfo; 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("not restart"); return true; } else { // Close nvs_close(my_handle); Serial.println("already restart"); return false; } /* Not needed but finish properly the function */ // Close nvs_close(my_handle); return false; } //-------------------- Initialisation --------------------// void setup() { Serial.begin(9600); setupWIFI(SSID, PWD); setupMQTT(MQTT_ADDRESS, MQTT_PORT); initSensors(sensors, SENSORS_NUMBER); TimeClient.begin(); TimeClient.forceUpdate(); int rawtime = (TimeClient.getEpochTime()) % 86400; // 86400 = 60sec*60minutes*24heures 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(TestBoot(RESTART) && testTime(hours, minutes, RESTART)){ ESP.restart(); } 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; char time[30]; char date[30]; char msg[70]; 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(); lenght = sprintf(date, "%d-%d-%d ", year, month, day); sprintf(date + lenght, time); sprintf(date + strlen(date), msg); MqttClient.publish(TOPIC, date); delay(2000); sleep(); }