code-grappe/src/main.cpp
2022-06-13 17:51:51 +02:00

454 lines
13 KiB
C++

#include "main.h"
#include "NTPClient.h"
//#include "driver/"
#include <sys/time.h>
#include <nvs_flash.h>
#include <ctime>
#include <iostream>
#include <chrono>
#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); // ancienne configuration
NTPClient TimeClient(NtpUDP, "europe.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<int, int, int> 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();
TimeClient.update();
//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();
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);
}