#include <WiFi.h>
#include <HTTPClient.h>
#include <WiFiClient.h>
#include <WiFiClientSecure.h>
#define MAX_SIZE_T 80
int LastHeureRTE = -1;
String STGEt = ""; //Status Tempo uniquement RTE
String LTARF = ""; //Option tarifaire RTE
byte TempoRTEon = 1; // considere ontention couleurs tempo depuis RTE
byte ModeReseau = 0; //0 = Internet, 1= LAN only, 2 =AP pas de réseau
#define StockMessage Serial.println
String RTE_Jour="NON_DEFINI";
String RTE_Demain="NON_DEFINI";
bool HeureValide = true; // considere heure ajusté a la main
int16_t Int_Heure = 8; //Heure interne
int16_t Int_Minute = 30;
int16_t Int_Seconde = 0;
int16_t HeureCouranteDeci = 0;
WiFiClientSecure clientSecuRTE;
#define TelnetPrint Serial.print
#define TelnetPrintln Serial.println
String Source = "NotDef";
String StringJson(String nom, String Json) {
int p = Json.indexOf(nom + "\":");
Json = Json.substring(p);
p = Json.indexOf(":");
Json = Json.substring(p + 1);
p = Json.indexOf("\"");
Json = Json.substring(p + 1);
p = Json.indexOf("\"");
Json = Json.substring(0, p);
return Json;
}
void Call_RTE_data() {
char buffer[MAX_SIZE_T];
const char* adr_RTE_Host = "www.services-rte.com";
String Host = String(adr_RTE_Host);
String urlJSON = "/cms/open_data/v1/tempoLight";
String RTEdata = "";
String line = "";
String DateRTE = ""; //an-mois-jour
String DateRTE2 = ""; //an-mois-jour lendemain
int Hcour = HeureCouranteDeci / 2; //Par pas de 72secondes pour faire 2 appels si un bug
int LastH = LastHeureRTE / 2;
// il faut éviter de questionner l'URL tempo light si on a déjà les infos qui nous intéressent...
bool couleur_lendemain = (STGEt == "4" || STGEt == "8" || STGEt == "C" ); // true si couleur du lendemain connue
bool couleur_jour = (LTARF == "TEMPO_BLEU" || LTARF == "TEMPO_BLANC" || LTARF == "TEMPO_ROUGE"); // true si couleur du jour connu
// traitement du changement de couleur tempo à 6h00, avec ré-initialisation de la couleur du lendemain
if ( (Hcour==300) && (LTARF!="") && (STGEt!="") ) // à 6h00 précises, la couleur tempo du lendemain devient la couleur du jour. Celle du lendemain n'est à priori pas encore connue
// Cela permet de continuer à fonctionner de manière nominale même si le site RTE n'est pas encore renseigné
// && (LTARF!="") pour ne pas passer dans cette boucle au reset si fait à 6h00 du matin...
// && (STGEt<>"") pour éviter de passer plusieurs fois( 3 à 4 ) dans cette boucle à cause du Hcour/2
{
if (STGEt == "4") LTARF = "TEMPO_BLEU";
else if (STGEt == "8") LTARF = "TEMPO_BLANC";
else if (STGEt == "C") LTARF = "TEMPO_ROUGE";
STGEt="";
couleur_lendemain=false; // on ne connait plus la couleur du lendemain. Cela forcera la lecture sur le site RTE
if (LTARF!="" && TempoRTEon == 1 && ModeReseau==0) {
StockMessage("Tempo depuis 6h00: " + LTARF + ",demain ? ");
RTE_Jour="NON_DEFINI";
RTE_Demain="NON_DEFINI";
}
}
if ((HeureValide) && (!(couleur_lendemain && couleur_jour ) ) && ((LastH != Hcour) && (Hcour == 302 || Hcour == 310 || Hcour == 530 || Hcour == 560 || Hcour == 600 || Hcour == 900 || Hcour == 1150) || LastHeureRTE < 0)) {
if (TempoRTEon == 1 && ModeReseau==0) {
// Use clientSecu class to create TCP connections
clientSecuRTE.setInsecure(); //skip verification
if (!clientSecuRTE.connect(adr_RTE_Host, 443,3000)) {
StockMessage("Connection failed to RTE server :" + Host);
} else {
time_t timestamp = time(NULL) - 21600; //Decallage début période couleur RTE de 6h.
struct tm* pTime = localtime(×tamp);
strftime(buffer, MAX_SIZE_T, "%Y-%m-%d", pTime);
DateRTE = String(buffer);
time_t timestamp2 = time(NULL) + 64800; //Decallage début période couleur RTE de 18h pour le lendemainh.
struct tm* pTime2 = localtime(×tamp2);
strftime(buffer, MAX_SIZE_T, "%Y-%m-%d", pTime2);
DateRTE2 = String(buffer);
TelnetPrint("DateRTE:");
TelnetPrintln(DateRTE);
TelnetPrint("DateRTE lendemain:");
TelnetPrintln(DateRTE2);
TelnetPrintln(urlJSON);
clientSecuRTE.print(String("GET ") + urlJSON + " HTTP/1.1\r\n" + "Host: " + Host + "\r\n" + "Connection: close\r\n\r\n");
TelnetPrintln("Request vers RTE Envoyé");
unsigned long timeout = millis();
while (clientSecuRTE.available() == 0) {
if (millis() - timeout > 5000) {
StockMessage(">>> clientSecuRTE RTE Timeout !");
clientSecuRTE.stop();
return;
}
}
timeout = millis();
// Lecture des données brutes distantes
int fin = 0;
while (clientSecuRTE.connected() && (millis() - timeout < 5000) && fin < 2) {
line = clientSecuRTE.readStringUntil('\n');
RTEdata += line;
if (line.indexOf("}}") >= 0) fin = 2;
}
clientSecuRTE.stop();
if(RTEdata.indexOf("Date: ") >= 0 && RTEdata.indexOf(" GMT") >= 0) { // Date selon RFC1123 RFC822 dans l'entete depuis site RTE
String TodayGMT = RTEdata.substring(RTEdata.indexOf("Date: ") + 6, RTEdata.indexOf("Date: ") + 35);
// recup quelques chose comme : Sat, 20 Dec 2025 14:39:38 GMT
const char* months = "JanFebMarAprMayJunJulAugSepOctNovDec";
char monthStr[4] = {0};
strncpy(monthStr, TodayGMT.substring(8).c_str(),3);
monthStr[3] = 0;
char* p = strstr(months, monthStr);
int JJ = TodayGMT.substring(5).toInt();
int MM = (p - months) / 3;
int YYYY = TodayGMT.substring(12).toInt();
int hh = TodayGMT.substring(17).toInt();
int mm = TodayGMT.substring(20).toInt();
int ss = TodayGMT.substring(23).toInt();
//Serial.printf("Numerique obtenu : %d/%d/%d %d:%d:%d\n", JJ, MM, YYYY, hh, mm, ss);
struct tm tm; // charge une structure tm avec la date et l'heure du fuseau GMT
// a quelques secondes près c'est une datage temporelle de l'instant
tm.tm_year = YYYY - 1900;
tm.tm_mon = MM;
tm.tm_mday = JJ;
tm.tm_hour = hh;
tm.tm_min = mm;
tm.tm_sec = ss;
char* oldTZ = getenv("TZ"); // IMPORTANT : on a un timestamp UTC → utiliser mktime en mode UTC
//if (oldTZ) Serial.println(oldTZ); else Serial.println("Aucun fuseau horaire de defini");
char backupTZ[64] = {0};
if (oldTZ) strncpy(backupTZ, oldTZ, sizeof(backupTZ)-1);
setenv("TZ", "UTC", 1);// On force temporairement TZ=UTC
tzset();
time_t t = mktime(&tm);
if (oldTZ) // Restaurer TZ précédent
setenv("TZ", backupTZ, 1);
else
unsetenv("TZ");
tzset();
// a quelques secondes près, la structure t c'est une datage temporelle de l'instant : nombre de seconde depuis 1970
// corrige DateRTE et DateRTE2
time_t timestamp = t - 21600; // retarde de 6h.
struct tm* pTime = localtime(×tamp);
strftime(buffer, MAX_SIZE_T, "%Y-%m-%d", pTime);
DateRTE = String(buffer);
time_t timestamp2 = t + 64800; // avance de 18h.
struct tm* pTime2 = localtime(×tamp2);
strftime(buffer, MAX_SIZE_T, "%Y-%m-%d", pTime2);
DateRTE2 = String(buffer);
//TelnetPrint("Corrected DateRTE:"); // ne tient pas compte de la date dans l'ESP
//TelnetPrintln(DateRTE);
//TelnetPrint("Corrected DateRTE lendemain:"); // ne tient pas compte de la date dans l'ESP
//TelnetPrintln(DateRTE2);
}
TelnetPrint("\n\nRTEdata:");
TelnetPrintln(RTEdata);
// C'est RTE qui donne la couleur
int p = RTEdata.indexOf("\"" + DateRTE + "\"");
int q = RTEdata.indexOf("\"" + DateRTE2 + "\"");
if (p > 0 || q > 0) {
String LTARFrecu = StringJson(DateRTE, RTEdata); //Remplace code du Linky
if (LTARFrecu == "BLUE") LTARF = "TEMPO_BLEU";
if (LTARFrecu == "WHITE") LTARF = "TEMPO_BLANC";
if (LTARFrecu == "RED") LTARF = "TEMPO_ROUGE";
line = "0";
String lendemain = "NON_DEFINI";
LTARFrecu = StringJson(DateRTE2, RTEdata);
if (LTARFrecu.indexOf("BLUE") >= 0) {
line = "4";
lendemain = "TEMPO_BLEU";
}
if (LTARFrecu.indexOf("WHITE") >= 0) {
line = "8";
lendemain = "TEMPO_BLANC";
}
if (LTARFrecu.indexOf("RED") >= 0) {
line = "C";
lendemain = "TEMPO_ROUGE";
}
RTE_Jour=LTARF;
RTE_Demain=lendemain;
STGEt = line; //Valeur Hexa code du Linky
StockMessage("Periode du " + DateRTE + " 6h au " + DateRTE2 + " 6h : " + LTARF + " | 'Demain' : " + lendemain);
//StockMessage(DateRTE + " : " + LTARF + " | " + DateRTE2 + " : " + lendemain);
RTEdata = "";
LastHeureRTE = HeureCouranteDeci; //Heure lecture Tempo RTE
} else {
StockMessage(DateRTE + " : Pas de données RTE valides");
}
}
} else {
if (Source != "Linky" && Source != "Ext") {
LTARF = "";
STGEt = "0";
}
}
}
}
void setup() {
setenv("TZ", "CET-1CEST,M3.5.0/2,M10.5.0/3", 1); // équivalent, en plus court de : CET-1CEST-2,M3.5.0/02:00:00,M10.5.0/03:00:00
tzset();
Serial.begin(115200);
Serial.print("Connecting to WiFi");
WiFi.begin("Wokwi-GUEST", "", 6);
while (WiFi.status() != WL_CONNECTED) {
delay(250);
Serial.print(".");
}
Serial.println(" Connected!");
HeureCouranteDeci = Int_Heure * 100 + Int_Minute * 10 / 6;
Call_RTE_data();
}
void loop() {
// put your main code here, to run repeatedly:
delay(10); // this speeds up the simulation
}