Compare commits

...

24 commits

Author SHA1 Message Date
nicolas.schmauch 98b0130911 Actualiser src/main.cpp 2024-06-26 11:25:15 +02:00
nicolas.schmauch 2f6da4ea09 Actualiser mqtt-python.py 2024-06-25 14:16:39 +02:00
Nicolas Schmauch 37ef459625 LocalSave + clearOldData + SendLocalData 2024-06-25 13:54:06 +02:00
Nicolas Schmauch 97346c1b06 Add LocalSave and SendLocalData 2024-06-21 10:38:52 +02:00
Nicolas Schmauch e9d30f5f30 comm 2024-06-21 10:38:19 +02:00
Nicolas Schmauch f164212c74 Add LocalSave and SendLocalData 2024-06-21 10:24:50 +02:00
Nicolas Schmauch cce2fb3629 améliration du code 2024-06-14 17:07:29 +02:00
noah cazeaudumec 0b04918e65 ajustement valeur batterie + save des données en local 2024-06-14 14:46:44 +02:00
nicolas.schmauch 3215912edd Actualiser mqtt-python.py 2024-06-12 10:19:21 +02:00
nicolas.schmauch 8c9f015b08 Actualiser mqtt-python.py 2024-06-11 16:27:28 +02:00
noah cazeaudumec 42f7f3331d amelioration+debug+com 2024-06-07 14:27:50 +02:00
margot.dubuisson aa83fc58d6 Actualiser include/secret.h
change password
2024-06-06 15:39:34 +02:00
nicolas.schmauch f1b23c54a6 Actualiser platformio.ini 2024-05-31 18:24:06 +02:00
Nicolas Schmauch 2d622688e6 new mqtt-python 2024-05-30 17:19:25 +02:00
Aurélien Gauthier c463b39c56 fixxx with epoch time we pray to it work 2022-06-13 17:51:51 +02:00
Aurélien Gauthier 367baf5f9a try test ntp fix 2022-06-13 16:55:18 +02:00
Aurélien Gauthier 80dac772f5 try fix restart bad work, condition fonction removed 2022-06-07 14:04:09 +02:00
Aurélien Gauthier efa325b044 try fix restart wrong fonctionnement, old condition fonction nor rm 2022-06-07 14:02:42 +02:00
Aurélien Gauthier 44872fc71e add persistant solution for restart and comment 2022-06-02 15:49:34 +02:00
Aurélien Gauthier d886bce090 restart each day to try bug fix, add delay for lost connexion wifi and mqtt 2022-06-02 00:21:41 +02:00
Aurélien Gauthier f0a0ccc395 timestamp fix 2022-05-24 16:50:46 +02:00
Aurélien Gauthier a21f0104d8 vscode extension 2022-05-24 10:05:31 +02:00
Aurélien Gauthier e21137c10d test unix timestamp fix 2022-05-24 10:03:16 +02:00
auel 6105de9f97 Temp captor:fixed, Battery measurement:work, solder on esp32, not final version 2022-05-20 17:01:50 +02:00
31 changed files with 1695 additions and 389 deletions

10
.vscode/extensions.json vendored Normal file
View file

@ -0,0 +1,10 @@
{
// See http://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format
"recommendations": [
"platformio.platformio-ide"
],
"unwantedRecommendations": [
"ms-vscode.cpptools-extension-pack"
]
}

57
.vscode/settings.json vendored Normal file
View file

@ -0,0 +1,57 @@
{
"files.associations": {
"array": "cpp",
"atomic": "cpp",
"*.tcc": "cpp",
"bitset": "cpp",
"cctype": "cpp",
"chrono": "cpp",
"clocale": "cpp",
"cmath": "cpp",
"cstdarg": "cpp",
"cstddef": "cpp",
"cstdint": "cpp",
"cstdio": "cpp",
"cstdlib": "cpp",
"cstring": "cpp",
"ctime": "cpp",
"cwchar": "cpp",
"cwctype": "cpp",
"deque": "cpp",
"unordered_map": "cpp",
"unordered_set": "cpp",
"vector": "cpp",
"exception": "cpp",
"algorithm": "cpp",
"functional": "cpp",
"iterator": "cpp",
"map": "cpp",
"memory": "cpp",
"memory_resource": "cpp",
"numeric": "cpp",
"optional": "cpp",
"random": "cpp",
"ratio": "cpp",
"regex": "cpp",
"string": "cpp",
"string_view": "cpp",
"system_error": "cpp",
"tuple": "cpp",
"type_traits": "cpp",
"utility": "cpp",
"fstream": "cpp",
"initializer_list": "cpp",
"iomanip": "cpp",
"iosfwd": "cpp",
"iostream": "cpp",
"istream": "cpp",
"limits": "cpp",
"new": "cpp",
"ostream": "cpp",
"sstream": "cpp",
"stdexcept": "cpp",
"streambuf": "cpp",
"cinttypes": "cpp",
"typeinfo": "cpp"
}
}

View file

@ -15,37 +15,58 @@
#include <Pangodream_18650_CL.h> #include <Pangodream_18650_CL.h>
#include <secret.h> #include <secret.h>
#define TOPIC "test1" #define TOPIC "test"
#define MQTT_ADDRESS "192.168.0.242" #define MQTT_ADDRESS "185.233.103.24"
#define MQTT_PORT 1883 #define MQTT_PORT 1883
#define ESPNAME "esp32-bastien" #define ESPNAME "esp32-fablab"
#define CLUSTER "grappe1" #define CLUSTER "grappe3"
#define SENSORS_NUMBER 5 #define SENSORS_NUMBER 5
#define DHT22 22 #define DHT22 22
#define TIME_TO_SLEEP 598 // comment for the test part this is the good frequency
#define TIME_TO_SLEEP 596
// #define TIME_TO_SLEEP 28
#define US_TO_S_FACTOR 1000000 #define US_TO_S_FACTOR 1000000
#define R2 100 #define R2 100
#define R3 10 #define R3 10
#define VOLTAGE_OUT(Vin) (((Vin)*R3) / (R2 + R3)) #define VOLTAGE_OUT(Vin) (((Vin) * R3) / (R2 + R3))
#define VOLTAGE_MAX 4200 #define VOLTAGE_MAX 4200
#define VOLTAGE_MIN 3300 #define VOLTAGE_MIN 3300
#define ADC_REFERENCE 1100 #define ADC_REFERENCE 1100
#define VOLTAGE_TO_ADC(in) ((ADC_REFERENCE * (in)) / 4096) #define VOLTAGE_TO_ADC(in) ((ADC_REFERENCE * (in)) / 4096)
#define BATTERY_MAX_ADC VOLTAGE_TO_ADC(VOLTAGE_OUT(VOLTAGE_MAX)) #define BATTERY_MAX_ADC VOLTAGE_TO_ADC(VOLTAGE_OUT(VOLTAGE_MAX))
#define BATTERY_MIN_ADC VOLTAGE_TO_ADC(VOLTAGE_OUT(VOLTAGE_MIN)) #define BATTERY_MIN_ADC VOLTAGE_TO_ADC(VOLTAGE_OUT(VOLTAGE_MIN))
#define ADC_PIN 34 // Solder apply on all riders behind the ESP32 for the battery voltage captor
#define CONV_FACTOR 2.92 #define ADC_PIN 35
#define CONV_FACTOR 1.78
#define READS 20 #define READS 20
const long gmtOffset_sec = 3600;
int getAverageChargeLevel();
void setupMQTT(const char *address, int port); void setupMQTT(const char *address, int port);
void setupWIFI(const char *wifi_name, const char *password); void setupWIFI(const char *wifi_name, const char *password);
void reconnect(void); void reconnect(void);
void initSensors(DHT *sensors, int number); void initSensors(DHT *sensors, int number);
void readSensors(DHT sensors[], float temp[], float hum[], int number); void readSensors(DHT sensors[], float temp[], float hum[], int number);
void sleep(); void sleep();
void clearOldData(int index);
void LocalSave();
void SendLocalData();
std::tuple<int, int, int> getDate(); std::tuple<int, int, int> getDate();
/**
* @brief hgfhdjskl
*
* @param txt testetest
* @param temp dqsdzfs
* @param hum
* @param number vdsvsvsvs
*/
void writeMsg(char *txt, float *temp, float *hum, int number); void writeMsg(char *txt, float *temp, float *hum, int number);
//timeClient.getEpochTime().toCharArray(date, 50); = convertir un string en char // timeClient.getEpochTime().toCharArray(date, 50); = convertir un string en char
/*
For test the esp32 signal emission without server Working/fixed/updated :
mosquitto_sub -h cohabit-capteurs.aquilenet.fr -u capteurs -P Fablab -t test-alex
*/
#endif #endif

View file

@ -1,5 +1,4 @@
#define MQTT_USER "NomUtilisateurMQTT" #define MQTT_USER "capteurs"
#define MQTT_MDP "MotDePasseMQTT" #define MQTT_MDP "Fablab"
#define SSID "NomDuWifi" #define SSID "coh@bit"
#define PWD "MotDePasseWifi" #define PWD "lewifidecohabit"

View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2019 Pangodream
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View file

@ -0,0 +1,2 @@
# 18650CL
Library to calculate 18650 charge in Arduino environment

View file

@ -0,0 +1,28 @@
#include <Pangodream_18650_CL.h>
//#define ADC_PIN 34
//#define CONV_FACTOR 1.7
//#define READS 20
Pangodream_18650_CL BL;
/**
* If you need to change default values you can use it as
* Pangodream_18650_CL BL(ADC_PIN, CONV_FACTOR, READS);
*/
void setup() {
Serial.begin(115200);
}
void loop() {
Serial.print("Value from pin: ");
Serial.println(analogRead(34));
Serial.print("Average value from pin: ");
Serial.println(BL.pinRead());
Serial.print("Volts: ");
Serial.println(BL.getBatteryVolts());
Serial.print("Charge level: ");
Serial.println(BL.getBatteryChargeLevel());
Serial.println("");
delay(1000);
}

View file

@ -0,0 +1,18 @@
#######################################
# Syntax Coloring Map BH1750FVI
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
Pangodream_18650_CL KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
getBatteryChargeLevel KEYWORD2
getBatteryVolts KEYWORD2
getAnalogPin KEYWORD2
pinRead KEYWORD2
getConvFactor KEYWORD2

View file

@ -0,0 +1,9 @@
name=Pangodream_18650_CL
version=1.0.1
author=Pangodream
maintainer=Pangodream
sentence=Pangodream Library to calculate 18650 charge
paragraph=Pangodream Library to calculate 18650 Ion-Li battery charge
category=Uncategorized
url=https://github.com/pangodream/18650CL
architectures=esp32

View file

@ -0,0 +1,177 @@
/*
MIT License
Copyright (c) 2019 Pangodream
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "Arduino.h"
#include "Pangodream_18650_CL.h"
Pangodream_18650_CL::Pangodream_18650_CL(int addressPin, double convFactor, int reads)
{
_reads = reads;
_convFactor = convFactor;
_addressPin = addressPin;
_initVoltsArray();
}
Pangodream_18650_CL::Pangodream_18650_CL(int addressPin, double convFactor)
{
_reads = DEF_READS;
_convFactor = convFactor;
_addressPin = addressPin;
_initVoltsArray();
}
Pangodream_18650_CL::Pangodream_18650_CL(int addressPin)
{
_reads = DEF_READS;
_convFactor = DEF_CONV_FACTOR;
_addressPin = addressPin;
_initVoltsArray();
}
Pangodream_18650_CL::Pangodream_18650_CL()
{
_reads = DEF_READS;
_convFactor = DEF_CONV_FACTOR;
_addressPin = DEF_PIN;
_initVoltsArray();
}
int Pangodream_18650_CL::getAnalogPin()
{
return _addressPin;
}
double Pangodream_18650_CL::getConvFactor()
{
return _convFactor;
}
/**
* Loads each voltage value in its matching charge element (index)
*/
// void Pangodream_18650_CL::_initVoltsArray(){
// _vs[0] = 3.200;
// _vs[1] = 3.250; _vs[2] = 3.300; _vs[3] = 3.350; _vs[4] = 3.400; _vs[5] = 3.450;
// _vs[6] = 3.500; _vs[7] = 3.550; _vs[8] = 3.600; _vs[9] = 3.650; _vs[10] = 3.700;
// _vs[11] = 3.703; _vs[12] = 3.706; _vs[13] = 3.710; _vs[14] = 3.713; _vs[15] = 3.716;
// _vs[16] = 3.719; _vs[17] = 3.723; _vs[18] = 3.726; _vs[19] = 3.729; _vs[20] = 3.732;
// _vs[21] = 3.735; _vs[22] = 3.739; _vs[23] = 3.742; _vs[24] = 3.745; _vs[25] = 3.748;
// _vs[26] = 3.752; _vs[27] = 3.755; _vs[28] = 3.758; _vs[29] = 3.761; _vs[30] = 3.765;
// _vs[31] = 3.768; _vs[32] = 3.771; _vs[33] = 3.774; _vs[34] = 3.777; _vs[35] = 3.781;
// _vs[36] = 3.784; _vs[37] = 3.787; _vs[38] = 3.790; _vs[39] = 3.794; _vs[40] = 3.797;
// _vs[41] = 3.800; _vs[42] = 3.805; _vs[43] = 3.811; _vs[44] = 3.816; _vs[45] = 3.821;
// _vs[46] = 3.826; _vs[47] = 3.832; _vs[48] = 3.837; _vs[49] = 3.842; _vs[50] = 3.847;
// _vs[51] = 3.853; _vs[52] = 3.858; _vs[53] = 3.863; _vs[54] = 3.868; _vs[55] = 3.874;
// _vs[56] = 3.879; _vs[57] = 3.884; _vs[58] = 3.889; _vs[59] = 3.895; _vs[60] = 3.900;
// _vs[61] = 3.906; _vs[62] = 3.911; _vs[63] = 3.917; _vs[64] = 3.922; _vs[65] = 3.928;
// _vs[66] = 3.933; _vs[67] = 3.939; _vs[68] = 3.944; _vs[69] = 3.950; _vs[70] = 3.956;
// _vs[71] = 3.961; _vs[72] = 3.967; _vs[73] = 3.972; _vs[74] = 3.978; _vs[75] = 3.983;
// _vs[76] = 3.989; _vs[77] = 3.994; _vs[78] = 4.000; _vs[79] = 4.008; _vs[80] = 4.015;
// _vs[81] = 4.023; _vs[82] = 4.031; _vs[83] = 4.038; _vs[84] = 4.046; _vs[85] = 4.054;
// _vs[86] = 4.062; _vs[87] = 4.069; _vs[88] = 4.077; _vs[89] = 4.085; _vs[90] = 4.092;
// _vs[91] = 4.100; _vs[92] = 4.111; _vs[93] = 4.122; _vs[94] = 4.133; _vs[95] = 4.144;
// _vs[96] = 4.156; _vs[97] = 4.167; _vs[98] = 4.178; _vs[99] = 4.189; _vs[100] = 4.200;
// }
void Pangodream_18650_CL::_initVoltsArray(){
_vs[0] = 3.300;
_vs[1] = 3.309; _vs[2] = 3.318; _vs[3] = 3.327; _vs[4] = 3.336; _vs[5] = 3.345;
_vs[6] = 3.354; _vs[7] = 3.363; _vs[8] = 3.372; _vs[9] = 3.381; _vs[10] = 3.390;
_vs[11] = 3.399; _vs[12] = 3.408; _vs[13] = 3.417; _vs[14] = 3.426; _vs[15] = 3.435;
_vs[16] = 3.444; _vs[17] = 3.453; _vs[18] = 3.462; _vs[19] = 3.471; _vs[20] = 3.480;
_vs[21] = 3.489; _vs[22] = 3.498; _vs[23] = 3.507; _vs[24] = 3.516; _vs[25] = 3.525;
_vs[26] = 3.534; _vs[27] = 3.543; _vs[28] = 3.552; _vs[29] = 3.561; _vs[30] = 3.570;
_vs[31] = 3.579; _vs[32] = 3.588; _vs[33] = 3.597; _vs[34] = 3.606; _vs[35] = 3.615;
_vs[36] = 3.624; _vs[37] = 3.633; _vs[38] = 3.642; _vs[39] = 3.651; _vs[40] = 3.660;
_vs[41] = 3.669; _vs[42] = 3.678; _vs[43] = 3.687; _vs[44] = 3.696; _vs[45] = 3.705;
_vs[46] = 3.714; _vs[47] = 3.723; _vs[48] = 3.732; _vs[49] = 3.741; _vs[50] = 3.750;
_vs[51] = 3.759; _vs[52] = 3.768; _vs[53] = 3.777; _vs[54] = 3.786; _vs[55] = 3.795;
_vs[56] = 3.804; _vs[57] = 3.813; _vs[58] = 3.822; _vs[59] = 3.831; _vs[60] = 3.840;
_vs[61] = 3.849; _vs[62] = 3.858; _vs[63] = 3.867; _vs[64] = 3.876; _vs[65] = 3.885;
_vs[66] = 3.894; _vs[67] = 3.903; _vs[68] = 3.912; _vs[69] = 3.921; _vs[70] = 3.930;
_vs[71] = 3.939; _vs[72] = 3.948; _vs[73] = 3.957; _vs[74] = 3.966; _vs[75] = 3.975;
_vs[76] = 3.984; _vs[77] = 3.993; _vs[78] = 4.002; _vs[79] = 4.011; _vs[80] = 4.020;
_vs[81] = 4.029; _vs[82] = 4.038; _vs[83] = 4.047; _vs[84] = 4.056; _vs[85] = 4.065;
_vs[86] = 4.074; _vs[87] = 4.083; _vs[88] = 4.092; _vs[89] = 4.101; _vs[90] = 4.110;
_vs[91] = 4.119; _vs[92] = 4.128; _vs[93] = 4.137; _vs[94] = 4.146; _vs[95] = 4.155;
_vs[96] = 4.164; _vs[97] = 4.173; _vs[98] = 4.182; _vs[99] = 4.191; _vs[100] = 4.200;
}
int Pangodream_18650_CL::getBatteryChargeLevel()
{
int readValue = _analogRead(_addressPin);
double volts = _analogReadToVolts(readValue);
int chargeLevel = _getChargeLevel(volts);
return chargeLevel;
}
int Pangodream_18650_CL::pinRead(){
return _analogRead(_addressPin);
}
int Pangodream_18650_CL::_analogRead(int pinNumber){
int totalValue = 0;
int averageValue = 0;
for(int i = 0; i < _reads; i++){
totalValue += analogRead(pinNumber);
}
averageValue = totalValue / _reads;
return averageValue;
}
/**
* Performs a binary search to find the index corresponding to a voltage.
* The index of the array is the charge %
*/
int Pangodream_18650_CL::_getChargeLevel(double volts){
int idx = 50;
int prev = 0;
int half = 0;
if (volts >= 4.2){
return 100;
}
if (volts <= 3.2){
return 0;
}
while(true){
half = abs(idx - prev) / 2;
prev = idx;
if(volts >= _vs[idx]){
idx = idx + half;
}else{
idx = idx - half;
}
if (prev == idx){
break;
}
}
return idx;
}
double Pangodream_18650_CL::_analogReadToVolts(int readValue){
double volts;
volts = readValue * _convFactor / 1000;
return volts;
}
double Pangodream_18650_CL::getBatteryVolts(){
int readValue = analogRead(_addressPin);
return _analogReadToVolts(readValue);
}

View file

@ -0,0 +1,94 @@
/*
MIT License
Copyright (c) 2019 Pangodream
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/*
* 18650 Ion-Li battery charge
*/
#ifndef Pangodream_18650_CL_h
#define Pangodream_18650_CL_h
#include "Arduino.h"
#define DEF_PIN 34
#define DEF_CONV_FACTOR 1.7
#define DEF_READS 20
/*
* 18650 Ion-Li battery charge
* Calculates charge level of an 18650 Ion-Li battery
*/
class Pangodream_18650_CL {
public:
/*
* Constructor
* @param addressPin, ADC pin number where the voltage divider is connected to
*/
Pangodream_18650_CL(int addressPin);
/*
* Constructor
* @param addressPin, ADC pin number where the voltage divider is connected to
* @param convFactor, Convertion factor for analog read units to volts
*/
Pangodream_18650_CL(int addressPin, double convFactor);
/*
* Constructor
* @param addressPin, ADC pin number where the voltage divider is connected to
* @param convFactor, Convertion factor for analog read units to volts
* @param reads, Number of reads of analog pin to calculate an average value
*/
Pangodream_18650_CL(int addressPin, double convFactor, int reads);
/*
* Constructor
*/
Pangodream_18650_CL();
/*
* Get the battery charge level (0-100)
* @return The calculated battery charge level
*/
int getBatteryChargeLevel();
double getBatteryVolts();
int getAnalogPin();
int pinRead();
double getConvFactor();
private:
int _addressPin; //!< ADC pin used, default is GPIO34 - ADC1_6
int _reads; //Number of reads of ADC pin to calculate an average value
double _convFactor; //!< Convertion factor to translate analog units to volts
double _vs[101]; //Array with voltage - charge definitions
void _initVoltsArray();
int _getChargeLevel(double volts);
int _analogRead(int pinNumber);
double _analogReadToVolts(int readValue);
};
#endif

View file

@ -0,0 +1,7 @@
# See: https://github.com/codespell-project/codespell#using-a-config-file
[codespell]
# In the event of a false positive, add the problematic word, in all lowercase, to a comma-separated list here:
ignore-words-list = ,
check-filenames =
check-hidden =
skip = ./.git

View file

@ -0,0 +1,10 @@
# See: https://docs.github.com/en/github/administering-a-repository/configuration-options-for-dependency-updates#about-the-dependabotyml-file
version: 2
updates:
# Configure check for outdated GitHub Actions actions in workflows.
# See: https://docs.github.com/en/github/administering-a-repository/keeping-your-actions-up-to-date-with-dependabot
- package-ecosystem: github-actions
directory: / # Check the repository's workflows under /.github/workflows/
schedule:
interval: daily

View file

@ -0,0 +1,28 @@
name: Check Arduino
# See: https://docs.github.com/en/free-pro-team@latest/actions/reference/events-that-trigger-workflows
on:
push:
pull_request:
schedule:
# Run every Tuesday at 8 AM UTC to catch breakage caused by new rules added to Arduino Lint.
- cron: "0 8 * * TUE"
workflow_dispatch:
repository_dispatch:
jobs:
lint:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Arduino Lint
uses: arduino/arduino-lint-action@v1
with:
compliance: specification
library-manager: update
# Always use this setting for official repositories. Remove for 3rd party projects.
official: true
project-type: library

View file

@ -0,0 +1,70 @@
name: Compile Examples
# See: https://docs.github.com/en/free-pro-team@latest/actions/reference/events-that-trigger-workflows
on:
push:
paths:
- ".github/workflows/compile-examples.yml"
- "examples/**"
- "**.c"
- "**.cpp"
- "**.h"
- "*.S"
pull_request:
paths:
- ".github/workflows/compile-examples.yml"
- "examples/**"
- "**.c"
- "**.cpp"
- "**.h"
- "*.S"
schedule:
# Run every Tuesday at 8 AM UTC to catch breakage caused by changes to external resources (libraries, platforms).
- cron: "0 8 * * TUE"
workflow_dispatch:
repository_dispatch:
jobs:
build:
name: ${{ matrix.board.fqbn }}
runs-on: ubuntu-latest
env:
SKETCHES_REPORTS_PATH: sketches-reports
strategy:
fail-fast: false
matrix:
board:
- fqbn: esp8266:esp8266:huzzah
platforms: |
- name: esp8266:esp8266
source-url: https://arduino.esp8266.com/stable/package_esp8266com_index.json
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Compile examples
uses: arduino/compile-sketches@v1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
fqbn: ${{ matrix.board.fqbn }}
platforms: ${{ matrix.board.platforms }}
libraries: |
# Install the library from the local path.
- source-path: ./
# Additional library dependencies can be listed here.
# See: https://github.com/arduino/compile-sketches#libraries
sketch-paths: |
- examples
enable-deltas-report: true
sketches-report-path: ${{ env.SKETCHES_REPORTS_PATH }}
- name: Save sketches report as workflow artifact
uses: actions/upload-artifact@v3
with:
if-no-files-found: error
path: ${{ env.SKETCHES_REPORTS_PATH }}
name: ${{ env.SKETCHES_REPORTS_PATH }}

View file

@ -0,0 +1,24 @@
name: Report Size Deltas
# See: https://docs.github.com/en/free-pro-team@latest/actions/reference/events-that-trigger-workflows
on:
push:
paths:
- ".github/workflows/report-size-deltas.yml"
schedule:
# Run at the minimum interval allowed by GitHub Actions.
# Note: GitHub Actions periodically has outages which result in workflow failures.
# In this event, the workflows will start passing again once the service recovers.
- cron: "*/5 * * * *"
workflow_dispatch:
repository_dispatch:
jobs:
report:
runs-on: ubuntu-latest
steps:
- name: Comment size deltas reports to PRs
uses: arduino/report-size-deltas@v1
with:
# The name of the workflow artifact created by the sketch compilation workflow
sketches-reports-source: sketches-reports

View file

@ -0,0 +1,22 @@
name: Spell Check
# See: https://docs.github.com/en/free-pro-team@latest/actions/reference/events-that-trigger-workflows
on:
push:
pull_request:
schedule:
# Run every Tuesday at 8 AM UTC to catch new misspelling detections resulting from dictionary updates.
- cron: "0 8 * * TUE"
workflow_dispatch:
repository_dispatch:
jobs:
spellcheck:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Spell check
uses: codespell-project/actions-codespell@master

View file

@ -0,0 +1,138 @@
# Source: https://github.com/arduino/tooling-project-assets/blob/main/workflow-templates/sync-labels.md
name: Sync Labels
# See: https://docs.github.com/en/actions/reference/events-that-trigger-workflows
on:
push:
paths:
- ".github/workflows/sync-labels.ya?ml"
- ".github/label-configuration-files/*.ya?ml"
pull_request:
paths:
- ".github/workflows/sync-labels.ya?ml"
- ".github/label-configuration-files/*.ya?ml"
schedule:
# Run daily at 8 AM UTC to sync with changes to shared label configurations.
- cron: "0 8 * * *"
workflow_dispatch:
repository_dispatch:
env:
CONFIGURATIONS_FOLDER: .github/label-configuration-files
CONFIGURATIONS_ARTIFACT: label-configuration-files
jobs:
check:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Download JSON schema for labels configuration file
id: download-schema
uses: carlosperate/download-file-action@v1
with:
file-url: https://raw.githubusercontent.com/arduino/tooling-project-assets/main/workflow-templates/assets/sync-labels/arduino-tooling-gh-label-configuration-schema.json
location: ${{ runner.temp }}/label-configuration-schema
- name: Install JSON schema validator
run: |
sudo npm install \
--global \
ajv-cli \
ajv-formats
- name: Validate local labels configuration
run: |
# See: https://github.com/ajv-validator/ajv-cli#readme
ajv validate \
--all-errors \
-c ajv-formats \
-s "${{ steps.download-schema.outputs.file-path }}" \
-d "${{ env.CONFIGURATIONS_FOLDER }}/*.{yml,yaml}"
download:
needs: check
runs-on: ubuntu-latest
strategy:
matrix:
filename:
# Filenames of the shared configurations to apply to the repository in addition to the local configuration.
# https://github.com/arduino/tooling-project-assets/blob/main/workflow-templates/assets/sync-labels
- universal.yml
steps:
- name: Download
uses: carlosperate/download-file-action@v1
with:
file-url: https://raw.githubusercontent.com/arduino/tooling-project-assets/main/workflow-templates/assets/sync-labels/${{ matrix.filename }}
- name: Pass configuration files to next job via workflow artifact
uses: actions/upload-artifact@v3
with:
path: |
*.yaml
*.yml
if-no-files-found: error
name: ${{ env.CONFIGURATIONS_ARTIFACT }}
sync:
needs: download
runs-on: ubuntu-latest
steps:
- name: Set environment variables
run: |
# See: https://docs.github.com/en/actions/reference/workflow-commands-for-github-actions#setting-an-environment-variable
echo "MERGED_CONFIGURATION_PATH=${{ runner.temp }}/labels.yml" >> "$GITHUB_ENV"
- name: Determine whether to dry run
id: dry-run
if: >
github.event_name == 'pull_request' ||
(
(
github.event_name == 'push' ||
github.event_name == 'workflow_dispatch'
) &&
github.ref != format('refs/heads/{0}', github.event.repository.default_branch)
)
run: |
# Use of this flag in the github-label-sync command will cause it to only check the validity of the
# configuration.
echo "::set-output name=flag::--dry-run"
- name: Checkout repository
uses: actions/checkout@v3
- name: Download configuration files artifact
uses: actions/download-artifact@v3
with:
name: ${{ env.CONFIGURATIONS_ARTIFACT }}
path: ${{ env.CONFIGURATIONS_FOLDER }}
- name: Remove unneeded artifact
uses: geekyeggo/delete-artifact@v1
with:
name: ${{ env.CONFIGURATIONS_ARTIFACT }}
- name: Merge label configuration files
run: |
# Merge all configuration files
shopt -s extglob
cat "${{ env.CONFIGURATIONS_FOLDER }}"/*.@(yml|yaml) > "${{ env.MERGED_CONFIGURATION_PATH }}"
- name: Install github-label-sync
run: sudo npm install --global github-label-sync
- name: Sync labels
env:
GITHUB_ACCESS_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
# See: https://github.com/Financial-Times/github-label-sync
github-label-sync \
--labels "${{ env.MERGED_CONFIGURATION_PATH }}" \
${{ steps.dry-run.outputs.flag }} \
${{ github.repository }}

View file

@ -1,10 +0,0 @@
language: c
sudo: false
before_install:
- source <(curl -SLs https://raw.githubusercontent.com/adafruit/travis-ci-arduino/master/install.sh)
script:
- build_platform esp8266
notifications:
email:
on_success: change
on_failure: change

140
lib/NTPClient-master/NTPClient.cpp Normal file → Executable file
View file

@ -25,7 +25,7 @@ NTPClient::NTPClient(UDP& udp) {
this->_udp = &udp; this->_udp = &udp;
} }
NTPClient::NTPClient(UDP& udp, int timeOffset) { NTPClient::NTPClient(UDP& udp, long timeOffset) {
this->_udp = &udp; this->_udp = &udp;
this->_timeOffset = timeOffset; this->_timeOffset = timeOffset;
} }
@ -35,24 +35,45 @@ NTPClient::NTPClient(UDP& udp, const char* poolServerName) {
this->_poolServerName = poolServerName; this->_poolServerName = poolServerName;
} }
NTPClient::NTPClient(UDP& udp, const char* poolServerName, int timeOffset) { NTPClient::NTPClient(UDP& udp, IPAddress poolServerIP) {
this->_udp = &udp;
this->_poolServerIP = poolServerIP;
this->_poolServerName = NULL;
}
NTPClient::NTPClient(UDP& udp, const char* poolServerName, long timeOffset) {
this->_udp = &udp; this->_udp = &udp;
this->_timeOffset = timeOffset; this->_timeOffset = timeOffset;
this->_poolServerName = poolServerName; this->_poolServerName = poolServerName;
} }
NTPClient::NTPClient(UDP& udp, const char* poolServerName, int timeOffset, unsigned long updateInterval) { NTPClient::NTPClient(UDP& udp, IPAddress poolServerIP, long timeOffset){
this->_udp = &udp;
this->_timeOffset = timeOffset;
this->_poolServerIP = poolServerIP;
this->_poolServerName = NULL;
}
NTPClient::NTPClient(UDP& udp, const char* poolServerName, long timeOffset, unsigned long updateInterval) {
this->_udp = &udp; this->_udp = &udp;
this->_timeOffset = timeOffset; this->_timeOffset = timeOffset;
this->_poolServerName = poolServerName; this->_poolServerName = poolServerName;
this->_updateInterval = updateInterval; this->_updateInterval = updateInterval;
} }
NTPClient::NTPClient(UDP& udp, IPAddress poolServerIP, long timeOffset, unsigned long updateInterval) {
this->_udp = &udp;
this->_timeOffset = timeOffset;
this->_poolServerIP = poolServerIP;
this->_poolServerName = NULL;
this->_updateInterval = updateInterval;
}
void NTPClient::begin() { void NTPClient::begin() {
this->begin(NTP_DEFAULT_LOCAL_PORT); this->begin(NTP_DEFAULT_LOCAL_PORT);
} }
void NTPClient::begin(int port) { void NTPClient::begin(unsigned int port) {
this->_port = port; this->_port = port;
this->_udp->begin(this->_port); this->_udp->begin(this->_port);
@ -60,37 +81,15 @@ void NTPClient::begin(int port) {
this->_udpSetup = true; this->_udpSetup = true;
} }
bool NTPClient::isValid(byte * ntpPacket)
{
//Perform a few validity checks on the packet
if((ntpPacket[0] & 0b11000000) == 0b11000000) //Check for LI=UNSYNC
return false;
if((ntpPacket[0] & 0b00111000) >> 3 < 0b100) //Check for Version >= 4
return false;
if((ntpPacket[0] & 0b00000111) != 0b100) //Check for Mode == Server
return false;
if((ntpPacket[1] < 1) || (ntpPacket[1] > 15)) //Check for valid Stratum
return false;
if( ntpPacket[16] == 0 && ntpPacket[17] == 0 &&
ntpPacket[18] == 0 && ntpPacket[19] == 0 &&
ntpPacket[20] == 0 && ntpPacket[21] == 0 &&
ntpPacket[22] == 0 && ntpPacket[22] == 0) //Check for ReferenceTimestamp != 0
return false;
return true;
}
bool NTPClient::forceUpdate() { bool NTPClient::forceUpdate() {
#ifdef DEBUG_NTPClient #ifdef DEBUG_NTPClient
Serial.println("Update from NTP Server"); Serial.println("Update from NTP Server");
#endif #endif
// flush any existing packets // flush any existing packets
while(this->_udp->parsePacket() != 0) while(this->_udp->parsePacket() != 0)
this->_udp->flush(); this->_udp->flush();
this->sendNTPPacket(); this->sendNTPPacket();
// Wait till data is there or timeout... // Wait till data is there or timeout...
@ -99,20 +98,14 @@ bool NTPClient::forceUpdate() {
do { do {
delay ( 10 ); delay ( 10 );
cb = this->_udp->parsePacket(); cb = this->_udp->parsePacket();
if(cb > 0)
{
this->_udp->read(this->_packetBuffer, NTP_PACKET_SIZE);
if(!this->isValid(this->_packetBuffer))
cb = 0;
}
if (timeout > 100) return false; // timeout after 1000 ms if (timeout > 100) return false; // timeout after 1000 ms
timeout++; timeout++;
} while (cb == 0); } while (cb == 0);
this->_lastUpdate = millis() - (10 * (timeout + 1)); // Account for delay in reading the time this->_lastUpdate = millis() - (10 * (timeout + 1)); // Account for delay in reading the time
this->_udp->read(this->_packetBuffer, NTP_PACKET_SIZE);
unsigned long highWord = word(this->_packetBuffer[40], this->_packetBuffer[41]); unsigned long highWord = word(this->_packetBuffer[40], this->_packetBuffer[41]);
unsigned long lowWord = word(this->_packetBuffer[42], this->_packetBuffer[43]); unsigned long lowWord = word(this->_packetBuffer[42], this->_packetBuffer[43]);
// combine the four bytes (two words) into a long integer // combine the four bytes (two words) into a long integer
@ -121,39 +114,43 @@ bool NTPClient::forceUpdate() {
this->_currentEpoc = secsSince1900 - SEVENZYYEARS; this->_currentEpoc = secsSince1900 - SEVENZYYEARS;
return true; return true; // return true after successful update
} }
bool NTPClient::update() { bool NTPClient::update() {
if ((millis() - this->_lastUpdate >= this->_updateInterval) // Update after _updateInterval if ((millis() - this->_lastUpdate >= this->_updateInterval) // Update after _updateInterval
|| this->_lastUpdate == 0) { // Update if there was no update yet. || this->_lastUpdate == 0) { // Update if there was no update yet.
if (!this->_udpSetup) this->begin(); // setup the UDP client if needed if (!this->_udpSetup || this->_port != NTP_DEFAULT_LOCAL_PORT) this->begin(this->_port); // setup the UDP client if needed
return this->forceUpdate(); return this->forceUpdate();
} }
return true; return false; // return false if update does not occur
} }
unsigned long NTPClient::getEpochTime() { bool NTPClient::isTimeSet() const {
return (this->_lastUpdate != 0); // returns true if the time has been set, else false
}
unsigned long NTPClient::getEpochTime() const {
return this->_timeOffset + // User offset return this->_timeOffset + // User offset
this->_currentEpoc + // Epoc returned by the NTP server this->_currentEpoc + // Epoch returned by the NTP server
((millis() - this->_lastUpdate) / 1000); // Time since last update ((millis() - this->_lastUpdate) / 1000); // Time since last update
} }
int NTPClient::getDay() { int NTPClient::getDay() const {
return (((this->getEpochTime() / 86400L) + 4 ) % 7); //0 is Sunday return (((this->getEpochTime() / 86400L) + 4 ) % 7); //0 is Sunday
} }
int NTPClient::getHours() { int NTPClient::getHours() const {
return ((this->getEpochTime() % 86400L) / 3600); return ((this->getEpochTime() % 86400L) / 3600);
} }
int NTPClient::getMinutes() { int NTPClient::getMinutes() const {
return ((this->getEpochTime() % 3600) / 60); return ((this->getEpochTime() % 3600) / 60);
} }
int NTPClient::getSeconds() { int NTPClient::getSeconds() const {
return (this->getEpochTime() % 60); return (this->getEpochTime() % 60);
} }
String NTPClient::getFormattedTime(unsigned long secs) { String NTPClient::getFormattedTime() const {
unsigned long rawTime = secs ? secs : this->getEpochTime(); unsigned long rawTime = this->getEpochTime();
unsigned long hours = (rawTime % 86400L) / 3600; unsigned long hours = (rawTime % 86400L) / 3600;
String hoursStr = hours < 10 ? "0" + String(hours) : String(hours); String hoursStr = hours < 10 ? "0" + String(hours) : String(hours);
@ -166,33 +163,6 @@ String NTPClient::getFormattedTime(unsigned long secs) {
return hoursStr + ":" + minuteStr + ":" + secondStr; return hoursStr + ":" + minuteStr + ":" + secondStr;
} }
// Based on https://github.com/PaulStoffregen/Time/blob/master/Time.cpp
// currently assumes UTC timezone, instead of using this->_timeOffset
String NTPClient::getFormattedDate(unsigned long secs) {
unsigned long rawTime = (secs ? secs : this->getEpochTime()) / 86400L; // in days
unsigned long days = 0, year = 1970;
uint8_t month;
static const uint8_t monthDays[]={31,28,31,30,31,30,31,31,30,31,30,31};
while((days += (LEAP_YEAR(year) ? 366 : 365)) <= rawTime)
year++;
rawTime -= days - (LEAP_YEAR(year) ? 366 : 365); // now it is days in this year, starting at 0
days=0;
for (month=0; month<12; month++) {
uint8_t monthLength;
if (month==1) { // february
monthLength = LEAP_YEAR(year) ? 29 : 28;
} else {
monthLength = monthDays[month];
}
if (rawTime < monthLength) break;
rawTime -= monthLength;
}
String monthStr = ++month < 10 ? "0" + String(month) : String(month); // jan is month 1
String dayStr = ++rawTime < 10 ? "0" + String(rawTime) : String(rawTime); // day of month
return String(year) + "-" + monthStr + "-" + dayStr + "T" + this->getFormattedTime(secs ? secs : 0) + "Z";
}
void NTPClient::end() { void NTPClient::end() {
this->_udp->stop(); this->_udp->stop();
@ -207,28 +177,36 @@ void NTPClient::setUpdateInterval(unsigned long updateInterval) {
this->_updateInterval = updateInterval; this->_updateInterval = updateInterval;
} }
void NTPClient::setPoolServerName(const char* poolServerName) {
this->_poolServerName = poolServerName;
}
void NTPClient::sendNTPPacket() { void NTPClient::sendNTPPacket() {
// set all bytes in the buffer to 0 // set all bytes in the buffer to 0
memset(this->_packetBuffer, 0, NTP_PACKET_SIZE); memset(this->_packetBuffer, 0, NTP_PACKET_SIZE);
// Initialize values needed to form NTP request // Initialize values needed to form NTP request
// (see URL above for details on the packets)
this->_packetBuffer[0] = 0b11100011; // LI, Version, Mode this->_packetBuffer[0] = 0b11100011; // LI, Version, Mode
this->_packetBuffer[1] = 0; // Stratum, or type of clock this->_packetBuffer[1] = 0; // Stratum, or type of clock
this->_packetBuffer[2] = 6; // Polling Interval this->_packetBuffer[2] = 6; // Polling Interval
this->_packetBuffer[3] = 0xEC; // Peer Clock Precision this->_packetBuffer[3] = 0xEC; // Peer Clock Precision
// 8 bytes of zero for Root Delay & Root Dispersion // 8 bytes of zero for Root Delay & Root Dispersion
this->_packetBuffer[12] = 0x49; this->_packetBuffer[12] = 49;
this->_packetBuffer[13] = 0x4E; this->_packetBuffer[13] = 0x4E;
this->_packetBuffer[14] = 0x49; this->_packetBuffer[14] = 49;
this->_packetBuffer[15] = 0x52; this->_packetBuffer[15] = 52;
// all NTP fields have been given values, now // all NTP fields have been given values, now
// you can send a packet requesting a timestamp: // you can send a packet requesting a timestamp:
this->_udp->beginPacket(this->_poolServerName, 123); //NTP requests are to port 123 if (this->_poolServerName) {
this->_udp->beginPacket(this->_poolServerName, 123);
} else {
this->_udp->beginPacket(this->_poolServerIP, 123);
}
this->_udp->write(this->_packetBuffer, NTP_PACKET_SIZE); this->_udp->write(this->_packetBuffer, NTP_PACKET_SIZE);
this->_udp->endPacket(); this->_udp->endPacket();
} }
void NTPClient::setEpochTime(unsigned long secs) { void NTPClient::setRandomPort(unsigned int minValue, unsigned int maxValue) {
this->_currentEpoc = secs; randomSeed(analogRead(0));
this->_port = random(minValue, maxValue);
} }

65
lib/NTPClient-master/NTPClient.h Normal file → Executable file
View file

@ -7,8 +7,6 @@
#define SEVENZYYEARS 2208988800UL #define SEVENZYYEARS 2208988800UL
#define NTP_PACKET_SIZE 48 #define NTP_PACKET_SIZE 48
#define NTP_DEFAULT_LOCAL_PORT 1337 #define NTP_DEFAULT_LOCAL_PORT 1337
#define LEAP_YEAR(Y) ( (Y>0) && !(Y%4) && ( (Y%100) || !(Y%400) ) )
class NTPClient { class NTPClient {
private: private:
@ -16,8 +14,9 @@ class NTPClient {
bool _udpSetup = false; bool _udpSetup = false;
const char* _poolServerName = "pool.ntp.org"; // Default time server const char* _poolServerName = "pool.ntp.org"; // Default time server
int _port = NTP_DEFAULT_LOCAL_PORT; IPAddress _poolServerIP;
int _timeOffset = 0; unsigned int _port = NTP_DEFAULT_LOCAL_PORT;
long _timeOffset = 0;
unsigned long _updateInterval = 60000; // In ms unsigned long _updateInterval = 60000; // In ms
@ -27,14 +26,28 @@ class NTPClient {
byte _packetBuffer[NTP_PACKET_SIZE]; byte _packetBuffer[NTP_PACKET_SIZE];
void sendNTPPacket(); void sendNTPPacket();
bool isValid(byte * ntpPacket);
public: public:
NTPClient(UDP& udp); NTPClient(UDP& udp);
NTPClient(UDP& udp, int timeOffset); NTPClient(UDP& udp, long timeOffset);
NTPClient(UDP& udp, const char* poolServerName); NTPClient(UDP& udp, const char* poolServerName);
NTPClient(UDP& udp, const char* poolServerName, int timeOffset); NTPClient(UDP& udp, const char* poolServerName, long timeOffset);
NTPClient(UDP& udp, const char* poolServerName, int timeOffset, unsigned long updateInterval); NTPClient(UDP& udp, const char* poolServerName, long timeOffset, unsigned long updateInterval);
NTPClient(UDP& udp, IPAddress poolServerIP);
NTPClient(UDP& udp, IPAddress poolServerIP, long timeOffset);
NTPClient(UDP& udp, IPAddress poolServerIP, long timeOffset, unsigned long updateInterval);
/**
* Set time server name
*
* @param poolServerName
*/
void setPoolServerName(const char* poolServerName);
/**
* Set random local port
*/
void setRandomPort(unsigned int minValue = 49152, unsigned int maxValue = 65535);
/** /**
* Starts the underlying UDP client with the default local port * Starts the underlying UDP client with the default local port
@ -44,7 +57,7 @@ class NTPClient {
/** /**
* Starts the underlying UDP client with the specified local port * Starts the underlying UDP client with the specified local port
*/ */
void begin(int port); void begin(unsigned int port);
/** /**
* This should be called in the main loop of your application. By default an update from the NTP Server is only * This should be called in the main loop of your application. By default an update from the NTP Server is only
@ -61,10 +74,17 @@ class NTPClient {
*/ */
bool forceUpdate(); bool forceUpdate();
int getDay(); /**
int getHours(); * This allows to check if the NTPClient successfully received a NTP packet and set the time.
int getMinutes(); *
int getSeconds(); * @return true if time has been set, else false
*/
bool isTimeSet() const;
int getDay() const;
int getHours() const;
int getMinutes() const;
int getSeconds() const;
/** /**
* Changes the time offset. Useful for changing timezones dynamically * Changes the time offset. Useful for changing timezones dynamically
@ -78,28 +98,17 @@ class NTPClient {
void setUpdateInterval(unsigned long updateInterval); void setUpdateInterval(unsigned long updateInterval);
/** /**
* @return secs argument (or 0 for current time) formatted like `hh:mm:ss` * @return time formatted like `hh:mm:ss`
*/ */
String getFormattedTime(unsigned long secs = 0); String getFormattedTime() const;
/** /**
* @return time in seconds since Jan. 1, 1970 * @return time in seconds since Jan. 1, 1970
*/ */
unsigned long getEpochTime(); unsigned long getEpochTime() const;
/**
* @return secs argument (or 0 for current date) formatted to ISO 8601
* like `2004-02-12T15:19:21+00:00`
*/
String getFormattedDate(unsigned long secs = 0);
/** /**
* Stops the underlying UDP client * Stops the underlying UDP client
*/ */
void end(); void end();
/**
* Replace the NTP-fetched time with seconds since Jan. 1, 1970
*/
void setEpochTime(unsigned long secs);
}; };

View file

@ -1,6 +1,8 @@
# NTPClient # NTPClient
[![Build Status](https://travis-ci.org/arduino-libraries/NTPClient.svg?branch=master)](https://travis-ci.org/arduino-libraries/NTPClient) [![Check Arduino status](https://github.com/arduino-libraries/NTPClient/actions/workflows/check-arduino.yml/badge.svg)](https://github.com/arduino-libraries/NTPClient/actions/workflows/check-arduino.yml)
[![Compile Examples status](https://github.com/arduino-libraries/NTPClient/actions/workflows/compile-examples.yml/badge.svg)](https://github.com/arduino-libraries/NTPClient/actions/workflows/compile-examples.yml)
[![Spell Check status](https://github.com/arduino-libraries/NTPClient/actions/workflows/spell-check.yml/badge.svg)](https://github.com/arduino-libraries/NTPClient/actions/workflows/spell-check.yml)
Connect to a NTP server, here is how: Connect to a NTP server, here is how:
@ -22,7 +24,7 @@ WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP); NTPClient timeClient(ntpUDP);
// You can specify the time server pool and the offset, (in seconds) // You can specify the time server pool and the offset, (in seconds)
// additionaly you can specify the update interval (in milliseconds). // additionally you can specify the update interval (in milliseconds).
// NTPClient timeClient(ntpUDP, "europe.pool.ntp.org", 3600, 60000); // NTPClient timeClient(ntpUDP, "europe.pool.ntp.org", 3600, 60000);
void setup(){ void setup(){
@ -45,3 +47,6 @@ void loop() {
delay(1000); delay(1000);
} }
``` ```
## Function documentation
`getEpochTime` returns the Unix epoch, which are the seconds elapsed since 00:00:00 UTC on 1 January 1970 (leap seconds are ignored, every day is treated as having 86400 seconds). **Attention**: If you have set a time offset this time offset will be added to your epoch timestamp.

View file

@ -11,7 +11,7 @@ const char *password = "<PASSWORD>";
WiFiUDP ntpUDP; WiFiUDP ntpUDP;
// You can specify the time server pool and the offset (in seconds, can be // You can specify the time server pool and the offset (in seconds, can be
// changed later with setTimeOffset() ). Additionaly you can specify the // changed later with setTimeOffset() ). Additionally you can specify the
// update interval (in milliseconds, can be changed using setUpdateInterval() ). // update interval (in milliseconds, can be changed using setUpdateInterval() ).
NTPClient timeClient(ntpUDP, "europe.pool.ntp.org", 3600, 60000); NTPClient timeClient(ntpUDP, "europe.pool.ntp.org", 3600, 60000);

View file

@ -0,0 +1,53 @@
#include <NTPClient.h>
// change next line to use with another board/shield
#include <ESP8266WiFi.h>
//#include <WiFi.h> // for WiFi shield
//#include <WiFi101.h> // for WiFi 101 shield or MKR1000
#include <WiFiUdp.h>
const char *ssid = "<SSID>";
const char *password = "<PASSWORD>";
WiFiUDP ntpUDP;
// initialized to a time offset of 10 hours
NTPClient timeClient(ntpUDP,"pool.ntp.org", 36000, 60000);
// HH:MM:SS
// timeClient initializes to 10:00:00 if it does not receive an NTP packet
// before the 100ms timeout.
// without isTimeSet() the LED would be switched on, although the time
// was not yet set correctly.
// blue LED on ESP-12F
const int led = 2;
const int hour = 10;
const int minute = 0;
void setup(){
Serial.begin(115200);
pinMode(led, OUTPUT);
// led is off when pin is high
digitalWrite(led, 1);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay (500);
Serial.print (".");
}
timeClient.begin();
}
void loop() {
timeClient.update();
Serial.println(timeClient.getFormattedTime());
if(timeClient.isTimeSet()) {
if (hour == timeClient.getHours() && minute == timeClient.getMinutes()) {
digitalWrite(led, 0);
}
}
delay(1000);
}

View file

@ -12,9 +12,13 @@ begin KEYWORD2
end KEYWORD2 end KEYWORD2
update KEYWORD2 update KEYWORD2
forceUpdate KEYWORD2 forceUpdate KEYWORD2
isTimeSet KEYWORD2
getDay KEYWORD2 getDay KEYWORD2
getHours KEYWORD2 getHours KEYWORD2
getMinutes KEYWORD2 getMinutes KEYWORD2
getSeconds KEYWORD2 getSeconds KEYWORD2
getFormattedTime KEYWORD2 getFormattedTime KEYWORD2
getEpochTime KEYWORD2 getEpochTime KEYWORD2
setTimeOffset KEYWORD2
setUpdateInterval KEYWORD2
setPoolServerName KEYWORD2

View file

@ -1,24 +0,0 @@
{
"name": "NTPClient",
"keywords": "ntp, client, time",
"description": "A NTPClient to connect to a time server",
"authors":
[
{
"name": "Fabrice Weinberg",
"email": "fabrice@weinberg.me"
},
{
"name": "Sandeep Mistry",
"email": "s.mistry@arduino.cc"
}
],
"repository":
{
"type": "git",
"url": "https://github.com/arduino-libraries/NTPClient.git"
},
"version": "3.1.0",
"frameworks": "arduino",
"platforms": "espressif"
}

View file

@ -1,5 +1,5 @@
name=NTPClient name=NTPClient
version=3.1.0 version=3.2.1
author=Fabrice Weinberg author=Fabrice Weinberg
maintainer=Fabrice Weinberg <fabrice@weinberg.me> maintainer=Fabrice Weinberg <fabrice@weinberg.me>
sentence=An NTPClient to connect to a time server sentence=An NTPClient to connect to a time server

View file

@ -1,55 +0,0 @@
import paho.mqtt.client as mqttClient
from influxdb import InfluxDBClient
import time
TOPIC = "test1"
broker_address= "localhost"
port = 1883
database = "thermo-bibli"
nom_client = "capteurs1"
def on_connect(client, userdata, flags, rc):
print("Connected with result code "+str(rc))
client.subscribe(TOPIC, 2)
def addData(database, time, numero_grappe, numero_capteur, temp, hum, batterie): # ajoute donnée à base de donnée influxDB
client = InfluxDBClient(host='localhost', port=8086)
client.create_database(database)
client.switch_database(database)
data = [
{
"measurement": numero_grappe,
"tags": {"numero_capteur": numero_capteur},
"time": time,
"fields": {"temperature": temp, "humidite": hum, "batterie": batterie}
}
]
client.write_points(data)
def on_message(client, userdata, message):
message = (message.payload).decode("utf-8") # convertit type bytes en string
print("Message reçu")
tab = message.split("|")
temp = tab[2].split()
hum = tab[3].split()
batterie = tab[4]
L = len(temp)
for i in range(L):
addData(database, tab[0], tab[1], "capteur" + str(i+1), temp[i], hum[i], batterie)
client = mqttClient.Client(nom_client, False)
client.username_pw_set(username="capteurs",password="Fablab")
client.on_connect= on_connect #callback
client.on_message= on_message #callback
client.connect(broker_address, port, 65535)
client.loop_start()
try:
while True:
time.sleep(0.1)
except KeyboardInterrupt:
print ("exiting")
client.disconnect()
client.loop_stop()

100
mqtt-python.py Normal file
View file

@ -0,0 +1,100 @@
#!/usr/bin/python3
#lib pour faire le timestamp
#from datetime import datetime
#lib pour ecoute mqtt
import paho.mqtt.client as mqttClient
import time
import sys
#http request lib
import requests
from aiohttp import ClientSession
##################################################################################################
#var mqtt
TOPIC = "test"
broker_address= "localhost"
port = 1883
nom_client = "serveur-test"
#var influx
influx_bucket = "Fablab" #database
influx_token = "QRzx929_X67sunqmY6xpS65fM7ff7Gy_Fz4ZD2qAT7eaR8Jps-9CZtEkot5Z01CQ-q1tq87IRyahXGebsSEzxV==" #token
influx_org="Fablab"
influx_url=f"http://localhost:8086/api/v2/write?org={influx_org}&bucket={influx_bucket}&precision=s"
#########################################################################################################
#http
async def get(session: object, url: object) -> object:
async with session.get(url) as response:
return await response.text()
#enregistre dans un fichier pour debug
def log(time):
f = open("/var/log/mqtt-influxdb/date.txt", "a")
f.write(time + "\n")
f.close()
def dump_log(text):
f = open("/var/log/mqtt-influxdb/dumped_message_thermo-fablab", "a")
f.write(text + "\n")
f.close()
#envois les donnees a influx via l'apiv2
def addData(time, numero_grappe, numero_capteur, temp, hum, batterie): # ajoute donnée à base de donnée influxDB
Headers = {"Authorization": f"Token {influx_token}"}
#data envoye a l'api
int_time = int(time)
#if (int_time > 1817589156):
# time = str(int_time - 368384901)
Data=f"{numero_grappe},numero_capteur={numero_capteur} temperature={temp},humidite={hum},batterie={batterie} {time}"
print(Data)
response = requests.post(influx_url, headers=Headers, data=Data)
print(response.status_code)
#debug api, fonctionne correctement malgres le code retour 204, quand il y a un code 204 le json response fait une erreur
#print("Status Code", response.status_code)
#print("JSON Response ", response.json())
def on_connect(client, userdata, flags, rc):
print("Connected with result code "+str(rc))
client.subscribe(TOPIC, 2)
def on_message(client, userdata, message):
message = (message.payload).decode("utf-8") # convertit type bytes en string
print("\nMessage reçu")
tab = message.split("|")
temp = tab[2].split()
hum = tab[3].split()
batterie = tab[4]
L = len(temp)
time=tab[0]
#envois la valeur temps reçu pour le debug
#log(time + " reçu")
for i in range(L):
addData(time, tab[1], "capteur" + str(i+1), temp[i], hum[i], batterie)
#log("---------")
#envois la valeur message pour le debug
#dump_log(message)
client = mqttClient.Client(nom_client, False)
client.username_pw_set(username="capteurs",password="Fablab")
client.on_connect= on_connect #callback
client.on_message= on_message #callback
client.connect(broker_address, port, 65535)
client.loop_start()
try:
while True:
time.sleep(0.1)
except KeyboardInterrupt:
print ("exiting")
client.disconnect()
client.loop_stop()

View file

@ -4,13 +4,14 @@
; Upload options: custom upload port, speed and extra flags ; Upload options: custom upload port, speed and extra flags
; Library options: dependencies, extra library storages ; Library options: dependencies, extra library storages
; Advanced options: extra scripting ; Advanced options: extra scripting
; ;
; Please visit documentation for the other options and examples ; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html ; https://docs.platformio.org/page/projectconf.html
[env:esp32dev] [env:esp32_olimex_devKit_Lipo]
platform = espressif32 platform = espressif32
board = esp32dev board = esp32-devkitlipo
framework = arduino framework = arduino
lib_deps = lib_deps =
adafruit/DHT sensor library@^1.4.2 adafruit/DHT sensor library@^1.4.2
@ -18,4 +19,4 @@ lib_deps =
knolleary/PubSubClient@^2.8 knolleary/PubSubClient@^2.8
ottowinter/ESPAsyncWebServer-esphome@^1.2.7 ottowinter/ESPAsyncWebServer-esphome@^1.2.7
ottowinter/AsyncTCP-esphome@^1.2.1 ottowinter/AsyncTCP-esphome@^1.2.1
arduino-libraries/NTPClient@^3.1.0 arduino-libraries/NTPClient@^3.1.0

View file

@ -1,171 +1,681 @@
#include "main.h" #include "main.h"
#include "NTPClient.h"
using namespace std;
#include <sys/time.h>
DHT sensors[SENSORS_NUMBER] = {DHT(23, DHT22), DHT(22, DHT22), DHT(21, DHT22), DHT(17, DHT22), DHT(2, DHT22)}; #include <nvs_flash.h>
float temp[SENSORS_NUMBER]; #include <ctime>
float hum[SENSORS_NUMBER]; #include <iostream>
#include <chrono>
WiFiClient WifiClient; #include "Preferences.h"
PubSubClient MqttClient(WifiClient);
WiFiUDP NtpUDP; #define STORAGE_NAMESPACE "storage"
NTPClient TimeClient(NtpUDP, "europe.pool.ntp.org", 0, 60000); #define _OPEN_SYS_ITOA_EXT
Pangodream_18650_CL Battery(ADC_PIN, CONV_FACTOR, READS); #define RESTART 1
#define REFRESHMEMBOOT 0
//-------------------- FONCTIONS --------------------// #define RESTARTTIMES 2
#define REFRESHTIMES 4
//-------------- Connexion MQTT --------------//
using namespace std;
void setupMQTT(const char *address, int port)
{ Preferences preferences;
MqttClient.setServer(address, port);
} // Array of DHT sensors with their respective pins and types
DHT sensors[SENSORS_NUMBER] = {DHT(04, DHT22), DHT(18, DHT22), DHT(05, DHT22), DHT(17, DHT22), DHT(16, DHT22)};
void setupWIFI(const char *wifi_name, const char *password)
{ // Arrays to store temperature and humidity readings
Serial.println('\n'); float temp[SENSORS_NUMBER];
float hum[SENSORS_NUMBER];
WiFi.begin(wifi_name, password);
Serial.print("Connecting to "); // Pangodream_18650_CL battery object with ADC pin, conversion factor, and number of reads
Serial.print(wifi_name); Pangodream_18650_CL Battery(ADC_PIN, CONV_FACTOR, READS);
while (WiFi.status() != WL_CONNECTED) // WiFi client object
{ WiFiClient WifiClient;
delay(500);
Serial.print('.'); // PubSubClient object for MQTT communication
} PubSubClient MqttClient(WifiClient);
Serial.println('\n');
Serial.println("Connection established!"); // UDP object for NTP communication
Serial.print("IP address:\t"); WiFiUDP NtpUDP;
Serial.println(WiFi.localIP());
} // NTP client object with UDP and NTP server address
NTPClient TimeClient(NtpUDP, "192.168.23.254"); /*si vous utilisez le Wifi du fablab*/
void reconnect(void) // NTPClient TimeClient(NtpUDP, "europe.pool.ntp.org"); /*si vous utilisez un réseau 4g ou autre */
{
Serial.println("Connecting to MQTT Broker..."); //-------------------- CONDITION --------------------//
while (!MqttClient.connected())
{ /**
Serial.print("."); * @brief Test if the time is good for restart or refresh memory
if (MqttClient.connect(ESPNAME, MQTT_USER, MQTT_PWD)) *
{ * @param hours
Serial.println("Connected."); * @param minutes
} * @param restart bool to choose which the restart time bool or the refresh 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
*/
//-------------- Initialisation et lecture des capteurs --------------// bool testTime(int hours, int minutes, bool restart)
{
void initSensors(DHT *sensors, int number) // debug parts
{ // Serial.println('\n');
int i; // Serial.println((REFRESHTIMES * TIME_TO_SLEEP) / 3600,DEC);
for (i = 0; i < number; i++) // Serial.println(((REFRESHTIMES * TIME_TO_SLEEP) % 3600) / 60,DEC);
{ // Serial.println('\n');
sensors[i].begin();
} if (restart)
} { // restart parts
if (hours < (RESTARTTIMES * TIME_TO_SLEEP) / 3600)
void readSensors(DHT sensors[], float temp[], float hum[], int number) return true;
{ else
int i; {
for (i = 0; i < number; i++) if ((hours = (RESTARTTIMES * TIME_TO_SLEEP) / 3600) && (minutes <= ((RESTARTTIMES * TIME_TO_SLEEP) % 3600) / 60))
{ return true;
*(temp + i) = sensors[i].readTemperature(); return false;
*(hum + i) = sensors[i].readHumidity(); }
} }
} else
{ // refresh parts
//-------------------- Sleep de l'ESP --------------------// if (hours >= (RESTARTTIMES * TIME_TO_SLEEP) / 3600)
{
void sleep() if (hours < (REFRESHTIMES * TIME_TO_SLEEP) / 3600)
{ return true;
esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * US_TO_S_FACTOR); else
esp_deep_sleep_start(); {
} if ((hours = (REFRESHTIMES * TIME_TO_SLEEP) / 3600) && (minutes <= ((REFRESHTIMES * TIME_TO_SLEEP) % 3600) / 60))
return true;
//exemple d'une triple utilisation de valeur pour une fonction utilise pour la date else
std::tuple<int, int, int> getDate() {
{ return false;
time_t rawtime = TimeClient.getEpochTime(); }
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); // Not needed but carefully habits
int day = (ti->tm_mday) < 10 ? 0 + (ti->tm_mday) : (ti->tm_mday); return false;
}
return std::make_tuple(year, month, day);
} //-------------------- FONCTIONS --------------------//
//-------------------- Création de trames --------------------// //-------------- Connexion MQTT --------------//
void writeMessage(char *txt, float *temp, float *hum, int number) /**
{ * @brief Set up MQTT server with address and port
int chargelvl = Battery.getBatteryChargeLevel(); *
switch (number) * @param address MQTT server address
{ * @param port MQTT server port
case 1: */
sprintf(txt, "|%s|%0.2f|%0.2f", CLUSTER, temp[0], hum[0]); void setupMQTT(const char *address, int port)
break; {
case 2: MqttClient.setServer(address, port);
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]); * @brief Set up WiFi connection with SSID and password
break; *
case 4: * @param wifi_name WiFi SSID
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]); * @param password WiFi password
break; */
case 5: void setupWIFI(const char *wifi_name, const char *password)
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; Serial.println('\n');
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]); WiFi.begin(wifi_name, password);
break; Serial.print("Connecting to ");
default: Serial.print(wifi_name);
Serial.println("Erreur, temp et hum sont trop longs : trop de capteurs");
break; int cpttry = 10;
} while (WiFi.status() != WL_CONNECTED)
} {
delay(500);
//-------------------- Initialisation --------------------// Serial.print('.');
void setup() /* stop trying wifi connexion */
{ cpttry--;
Serial.begin(9600); if (cpttry == 0)
setupWIFI(SSID, PWD); {
setupMQTT(MQTT_ADDRESS, MQTT_PORT); Serial.print("wifi: 10 try go to sleep");
initSensors(sensors, SENSORS_NUMBER); sleep();
TimeClient.begin(); }
} }
Serial.println('\n');
//-------------------- Boucle pricipale --------------------// Serial.println("Connection established!");
Serial.print("IP address:\t");
void loop() Serial.println(WiFi.localIP());
{ }
int year, month, day;
int lenght; void reconnect(void)
char time[30]; {
char date[30]; Serial.println("\n Connecting to MQTT Broker...");
char msg[70]; int cpttry = 10;
while (!MqttClient.connected())
MqttClient.loop(); {
if (!MqttClient.connected()) /* stop trying mqtt connexion */
{ cpttry--;
reconnect(); if (cpttry == 0)
} {
Serial.print("Mqtt: 10 try go to sleep");
readSensors(sensors, temp, hum, SENSORS_NUMBER); LocalSave();
writeMessage(msg, temp, hum, SENSORS_NUMBER); sleep();
}
TimeClient.update();
TimeClient.getFormattedTime().toCharArray(time, 30); Serial.print(".");
tie(year, month, day) = getDate(); if (MqttClient.connect(ESPNAME, MQTT_USER, MQTT_MDP)) // MQTT_MDP (mot de passe)
lenght = sprintf(date, "%d-%d-%d ", year, month, day); {
sprintf(date + lenght, time); Serial.println("Connected.");
sprintf(date + strlen(date), msg); }
MqttClient.publish(TOPIC, date); }
}
delay(2000);
//-------------- Initialisation et lecture des capteurs --------------//
sleep();
/**
* @brief Initialize DHT sensors
*
* @param sensors array of DHT sensors
* @param number number of sensors
*/
void initSensors(DHT *sensors, int number)
{
int i;
for (i = 0; i < number; i++)
{
sensors[i].begin();
}
}
/**
* @brief Read temperature and humidity from DHT sensors
*
* @param sensors array of DHT sensors
* @param temp array to store temperature readings
* @param hum array to store humidity readings
* @param number number of sensors
*/
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 --------------------//
/**
* @brief Put ESP into deep sleep mode
*/
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";
// 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(); //cette ligne crée un bug avec l'heure quand on est connecté au réseau du fablab
vTaskDelay(1000);
if (!getLocalTime(&timeinfo))
{
Serial.println("Failed to obtain time");
return (0);
}
time(&now);
Serial.println(now);
return now;
}
int getAverageChargeLevel()
{
const int moyenne = 10;
int charge[moyenne];
int total = 0;
for (int i = 0; i < moyenne; i++)
{
charge[i] = Battery.getBatteryChargeLevel(); // Assurez-vous que Battery.getBatteryChargeLevel() est défini
total += charge[i];
}
int chargelvl = total / moyenne;
return chargelvl;
}
//-------------------- Création de trames --------------------//
/**
* @brief Create message frame with temperature and humidity readings
*
* @param txt message buffer
* @param temp array of temperature readings
* @param hum array of humidity readings
* @param number number of sensors
*/
void writeMessage(char *txt, float *temp, float *hum, int number)
{
int chargelvl = getAverageChargeLevel();
delay(2000);
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;
}
}
//-------------------- read, refresh and return the day boot state --------------------//
/**
* @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 --------------------//
/**
* @brief Setup function for the ESP
*/
void setup()
{
Serial.begin(9600);
Serial.println("\n-----------------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');
}
// Définir la capacité maximale de stockage
const int maxDataSets = 11;
// Fonction pour sauvegarder les données localement
void LocalSave()
{
// Ouvre les préférences sous le nom "capteurs" en mode lecture/écriture
preferences.begin("capteurs", false);
// Lit l'indice de la prochaine sauvegarde, ou initialise à 0 s'il n'existe pas
int saveCounter = preferences.getInt("saveCounter", 0);
// Efface les anciennes données si nécessaire
if (saveCounter >= maxDataSets)
{
saveCounter = 0; // Réinitialise le compteur si la limite est atteinte
}
// Appelle la fonction pour effacer les données anciennes à l'index actuel
clearOldData(saveCounter);
// Calcule l'heure actuelle en secondes depuis l'époque Unix
int chargelvl = getAverageChargeLevel(); // Obtient le niveau moyen de la batterie
time_t rawtime = TimeClient.getEpochTime(); // Obtient l'heure actuelle
Serial.print("\n-----------------Save---------------------\n");
// Boucle pour sauvegarder les données de température et d'humidité
for (int i = 0; i < 5; i++)
{
char tempKey[16];
char humiKey[16];
// Génère des clés uniques pour chaque valeur de température et d'humidité
snprintf(tempKey, sizeof(tempKey), "temp%d_%d", saveCounter, i);
snprintf(humiKey, sizeof(humiKey), "hum%d_%d", saveCounter, i);
// Sauvegarde les valeurs de température et d'humidité dans les préférences
preferences.putFloat(tempKey, temp[i]);
preferences.putFloat(humiKey, hum[i]);
// Affiche les valeurs de température et d'humidité pour vérification
Serial.printf("temp[%d]: %0.2f\n", i, temp[i]);
Serial.printf("hum[%d]: %0.2f\n", i, hum[i]);
}
// Sauvegarde le temps et le niveau de charge
char timeKey[16];
char chargeKey[16];
snprintf(timeKey, sizeof(timeKey), "time%d", saveCounter);
snprintf(chargeKey, sizeof(chargeKey), "chargelvl%d", saveCounter);
// Sauvegarde les valeurs de temps et de niveau de charge dans les préférences
preferences.putInt(timeKey, rawtime);
preferences.putInt(chargeKey, chargelvl);
// Affiche les valeurs de temps et de niveau de charge pour vérification
Serial.printf("time: %d \n", rawtime);
Serial.printf("chargelvl: %d\n", chargelvl);
// Incrémente le compteur de sauvegardes et le sauvegarde
saveCounter++;
preferences.putInt("saveCounter", saveCounter);
// Termine l'accès aux préférences
preferences.end();
}
// Fonction pour effacer les anciennes données si l'espace est insuffisant
void clearOldData(int index)
{
// Variables pour stocker les noms de clé formatés
char timeKey[16];
char chargeKey[16];
// Formate les noms de clé pour le temps et le niveau de charge en fonction de l'index donné
snprintf(timeKey, sizeof(timeKey), "time%d", index);
snprintf(chargeKey, sizeof(chargeKey), "chargelvl%d", index);
// Supprime les entrées correspondantes au temps et au niveau de charge
preferences.remove(timeKey);
preferences.remove(chargeKey);
// Boucle pour supprimer les entrées de température et d'humidité associées
for (int i = 0; i < 5; i++)
{
// Variables pour stocker les noms de clé formatés pour la température et l'humidité
char tempKey[16];
char humiKey[16];
// Formate les noms de clé pour la température et l'humidité en fonction de l'index et du sous-index
snprintf(tempKey, sizeof(tempKey), "temp%d_%d", index, i);
snprintf(humiKey, sizeof(humiKey), "hum%d_%d", index, i);
// Supprime les entrées correspondantes à la température et à l'humidité
preferences.remove(tempKey);
preferences.remove(humiKey);
}
}
// Fonction pour envoyer les données locales
void SendLocalData()
{
// Ouvre les préférences sous le nom "capteurs" en mode lecture seule
preferences.begin("capteurs", true);
// Lit le compteur de sauvegardes, ou initialise à 0 s'il n'existe pas
int saveCounter = preferences.getInt("saveCounter", 0);
// Boucle pour envoyer les données sauvegardées
for (int counter = 0; counter < saveCounter; counter++)
{
char timeKey[16];
char chargeKey[16];
// Génère des clés uniques pour le temps et le niveau de charge
snprintf(timeKey, sizeof(timeKey), "time%d", counter);
snprintf(chargeKey, sizeof(chargeKey), "chargelvl%d", counter);
// Lit les valeurs de temps et de niveau de charge depuis les préférences
time_t rawtime = preferences.getInt(timeKey, 0);
int chargelvl = preferences.getInt(chargeKey, 0);
// Boucle pour lire les données de température et d'humidité
for (int i = 0; i < 5; i++)
{
char tempKey[16];
char humiKey[16];
// Génère des clés uniques pour chaque valeur de température et d'humidité
snprintf(tempKey, sizeof(tempKey), "temp%d_%d", counter, i);
snprintf(humiKey, sizeof(humiKey), "hum%d_%d", counter, i);
// Lit les valeurs de température et d'humidité depuis les préférences
temp[i] = preferences.getFloat(tempKey, 0);
hum[i] = preferences.getFloat(humiKey, 0);
}
// Prépare le message à envoyer
char msgsld[200];
sprintf(msgsld, "%lu|%s|%0.2f %0.2f %0.2f %0.2f %0.2f|%0.2f %0.2f %0.2f %0.2f %0.2f|%d", rawtime, CLUSTER, temp[0], temp[1], temp[2], temp[3], temp[4], hum[0], hum[1], hum[2], hum[3], hum[4], chargelvl);
// Envoie le message via MQTT
MqttClient.publish(TOPIC, msgsld);
Serial.println(msgsld);
// Supprime les clés après envoi
clearOldData(counter);
}
// Réinitialise le compteur de sauvegardes
preferences.putInt("saveCounter", 0);
// Termine l'accès aux préférences
preferences.end();
}
//-------------------- Boucle principale --------------------//
/**
* @brief Main loop function for the ESP
*/
void loop()
{
int year, month, day;
int lenght;
unsigned long now;
char time[30];
char date[30];
char msg[70];
bool horoIssue = false;
readSensors(sensors, temp, hum, SENSORS_NUMBER);
writeMessage(msg, temp, hum, SENSORS_NUMBER);
MqttClient.loop();
if (!MqttClient.connected())
{
reconnect();
}
// MqttClient.publish(TOPIC, msg, date);
// 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);
// Serial.println("msg1 : "); //debug print
// Serial.println(msg); //debug print
sprintf(date + strlen(date), msg);
// Serial.println("msg2 : "); //debug print
// Serial.println(msg); //debug print
// Serial.println("date : "); //debug print
// Serial.println(date); //debug print
Serial.println("\n");
Serial.println("-----------------Local---------------------");
SendLocalData();
nvs_flash_erase(); // Supprime les données en local.
MqttClient.publish(TOPIC, date);
Serial.println("-----------------Brut---------------------");
Serial.println(date);
Serial.println("-----------------DeepSleep---------------------");
delay(2000);
sleep();
delay(1000);
} }