Compare commits

..

No commits in common. "ba96f0971702e8a43bc43e2af93955d5ecac8b1e" and "68db78cd5e95e8c997ea2b7fac941ce5957c256c" have entirely different histories.

9 changed files with 173 additions and 327 deletions

1
.gitignore vendored
View File

@ -1,6 +1,5 @@
#specific files
secret.h
build/
# ---> C++
# Prerequisites

View File

@ -1,8 +0,0 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
"version": "0.2.0",
"configurations": [
]
}

Binary file not shown.

View File

@ -1,43 +1,22 @@
#include "serial.h"
#include "secret.h"
#include "tic.h"
#include "ota.h"
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <ElegantOTA.h>
#include <PubSubClient.h>
// Activer le Wi-Fi
#define WIFI_ENABLE
// Initialiser le serveur web si le Wi-Fi est activé
#ifdef WIFI_ENABLE
ESP8266WebServer server(HTTP_PORT);
WiFiClient espClient;
PubSubClient mqttclient(espClient);
#endif
unsigned long previousMillis = 0;
unsigned long previousForceMillis = 0;
const long interval = 1000;
void mqttConnect() {
// Loop until we're reconnected
while (!mqttclient.connected()) {
// Create a random client ID
String clientId = MQTT_CLIENTID;
clientId += String(random(0xffff), HEX);
// Attempt to connect
if (mqttclient.connect(clientId.c_str(), MQTT_USERNAME, MQTT_PASSWORD)) {
// Once connected, publish an announcement...
mqttclient.publish(MQTT_TOPIC, "MQTT TIC interface online");
} else {
delay(1000);
}
}
}
// Durée de sommeil en microsecondes (par exemple, 5 secondes)
const int sleepDuration = 5 * 1000000;
// Fonction pour configurer et connecter au réseau Wi-Fi
void setup_wifi() {
@ -45,10 +24,10 @@ void setup_wifi() {
// Connexion au réseau Wi-Fi
DebugPort.println();
DebugPort.print("Connecting to ");
DebugPort.println(STASSID);
DebugPort.println(ssid);
WiFi.mode(WIFI_STA);
WiFi.begin(STASSID, STAPSK);
WiFi.begin(ssid, passPhrase);
int c = 0;
// Attendre la connexion Wi-Fi
@ -135,6 +114,12 @@ void setup_serial() {
#endif
}
// Fonction pour mettre l'ESP8266 en mode deep sleep
void goToDeepSleep() {
DebugPort.println("Going to deep sleep...");
ESP.deepSleep(sleepDuration);
}
// Fonction d'initialisation principale
void setup() {
@ -145,60 +130,20 @@ void setup() {
// Configurer les routes du serveur
restServerRouting();
ElegantOTA.begin(&server);
// ElegantOTA callbacks
ElegantOTA.onStart(onOTAStart);
ElegantOTA.onProgress(onOTAProgress);
ElegantOTA.onEnd(onOTAEnd);
// Démarrer le serveur HTTP
DebugPort.println("Start HTTP server");
server.begin();
DebugPort.println("HTTP server started");
//Démarrer le serveur MQTT
mqttclient.setServer(MQTT_SERVER, MQTT_PORT);
#endif
}
// Boucle principale
void loop() {
ElegantOTA.loop();
server.handleClient();
readTicPort();
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
// save the last time you blinked the LED
previousMillis = currentMillis;
//Interface MQTT
if (!mqttclient.connected()) {
mqttConnect();
}
mqttPublish(&mqttclient);
}
if (currentMillis - previousForceMillis >= (30*interval)) {
// save the last time you blinked the LED
previousForceMillis = currentMillis;
//Interface MQTT
if (!mqttclient.connected()) {
mqttConnect();
}
mqttForcePublish(&mqttclient);
}
mqttclient.loop();
/*
// Si aucune requête n'est en cours, mettre l'ESP8266 en mode deep sleep
if (server.client().available() == 0) {
goToDeepSleep();
}*/
}
}

32
ota.cpp
View File

@ -1,32 +0,0 @@
#include "ota.h"
#include "serial.h"
#include <Arduino.h>
#include <stddef.h>
unsigned long ota_progress_millis = 0;
void onOTAStart() {
// Log when OTA has started
DebugPort.println("OTA update started!");
// <Add your own code here>
}
void onOTAProgress(size_t current, size_t final) {
// Log every 1 second
if (millis() - ota_progress_millis > 1000) {
ota_progress_millis = millis();
DebugPort.printf("OTA Progress Current: %u bytes, Final: %u bytes\n", current, final);
}
}
void onOTAEnd(bool success) {
// Log when OTA has finished
if (success) {
DebugPort.println("OTA update finished successfully!");
} else {
DebugPort.println("There was an error during OTA update!");
}
// <Add your own code here>
}

12
ota.h
View File

@ -1,12 +0,0 @@
#ifndef OTA
#define OTA
#include <stddef.h>
void onOTAStart();
void onOTAProgress(size_t current, size_t final);
void onOTAEnd(bool success);
#endif

View File

@ -16,11 +16,3 @@
const char *ssid = STASSID;
const char *passPhrase = STAPSK;
// MQTT Broker settings
const char *mqtt_broker = "broker.emqx.io"; // EMQX broker endpoint
const char *mqtt_topic = "emqx/esp8266/led"; // MQTT topic
const char *mqtt_username = "emqx"; // MQTT username for authentication
const char *mqtt_password = "public"; // MQTT password for authentication
const int mqtt_port = 1883; // MQTT port (TCP)
const char *mqtt_clientId = "tic_client-"

264
tic.cpp
View File

@ -1,9 +1,7 @@
#include "lwip/ip.h"
#include "tic.h"
#include "serial.h"
#include "secret.h"
#include <Arduino.h>
#include <PubSubClient.h>
// #define DEBUG 1
@ -21,11 +19,9 @@ RelaisStatus relaisStatus; // definition du relais status
Action actionJp1[11]; // actions définie pour jour +1
int nbActions;
static struct GroupDetail processGroup(String group) {
static struct GroupDetail processGroup(String group)
{
struct GroupDetail gd;
gd.globale = group;
unsigned char computedChecksum = calcCheckSum(group);
int indexgrp = group.indexOf(HT);
gd.name = group.substring(0, indexgrp);
@ -35,24 +31,20 @@ static struct GroupDetail processGroup(String group) {
group = group.substring(indexgrp + 1);
indexgrp = group.indexOf(HT);
String key = "";
String key = group.substring(0, indexgrp);
group = group.substring(indexgrp + 1);
indexgrp = group.indexOf(HT);
if (indexgrp != -1) // some parameters may have hour recording.
{
gd.horodate = gd.value;
gd.value = group.substring(0, indexgrp);
group = group.substring(indexgrp + 1);
gd.value = key;
}
//gd.checksum = group;
if (group[0]==computedChecksum) {
gd.checkok = true;
} else {
gd.checkok = false;
}
return gd;
}
static void processStge(RegistreStatus *rs, String value) {
static void processStge(RegistreStatus *rs, String value)
{
char stge[9] = "";
// copy in the char array
strncpy(stge, value.c_str(), 8);
@ -61,7 +53,8 @@ static void processStge(RegistreStatus *rs, String value) {
rs->uli = l;
}
static void processRelais(RelaisStatus *rs, String value) {
static void processRelais(RelaisStatus *rs, String value)
{
char stge[4] = "";
// copy in the char array
strncpy(stge, value.c_str(), 3);
@ -69,19 +62,24 @@ static void processRelais(RelaisStatus *rs, String value) {
rs->ui = strtoul(stge, NULL, 16);
}
static void processActionsCalendrier(String value) {
static void processActionsCalendrier(String value)
{
nbActions = 0;
String s = value;
while (s.length() > 0) {
while (s.length() > 0)
{
int index = s.indexOf(SP);
if (index == -1) // No space found
{
break;
} else {
}
else
{
char data[9] = "";
data[8] = '\0';
strncpy(data, s.substring(0, index).c_str(), 8);
if (strncmp(data, NONUTILE, 8) != 0) {
if (strncmp(data, NONUTILE, 8) != 0)
{
char stge[5] = "";
// copy ssss field
memcpy(stge, &data[4], 4);
@ -104,14 +102,19 @@ static void processActionsCalendrier(String value) {
*
* @param data A reference to a String containing the data frame to be processed.
*/
static void processTrame(String &data) {
while (data.length() > 0) {
static void processTrame(String &data)
{
while (data.length() > 0)
{
// Find the position of the next carriage return (CR) character
int index = data.indexOf(CR);
// If no CR is found, exit the loop
if (index == -1) {
if (index == -1)
{
break;
} else {
}
else
{
// Extract the group string between the start and the CR character
String group = data.substring(1, index);
// Process the group to extract detailed information
@ -119,54 +122,46 @@ static void processTrame(String &data) {
// Check if the extracted group name matches any user-selected etiquette
int t = 0;
while ((SelectedEtiquette[t] != gd.name) && (t < NB_ETIQUETTE)) {
while ((SelectedEtiquette[t] != gd.name) && (t < NB_ETIQUETTE))
{
++t;
}
// If a match is found, update the corresponding TicValues entry if the group confirms the checksum
if (t < NB_ETIQUETTE) {
//If there is a value update
if (TicValues[t].value.compareTo(gd.value) != 0 && gd.checkok){
//There is some noise on instantaneous value, filter
if (SelectedEtiquette[t] == "SINSTS" || SelectedEtiquette[t] == "SINSTS1" || SelectedEtiquette[t] == "SINSTS2" || SelectedEtiquette[t] == "SINSTS3") {
int oldval = TicValues[t].value.toInt();
int newcal = (gd.value.toInt() + oldval) / 2;
if (newcal < oldval * 0.92 || newcal > oldval * 1.02) {
gd.updated = true;
TicValues[t] = gd;
} else {
TicValues[t].value = String(newcal);
}
} else {
gd.updated = true;
// If a match is found, update the corresponding TicValues entry
if (t < NB_ETIQUETTE)
{
TicValues[t] = gd;
// Depending on the group name, call the appropriate processing function
if (gd.name == "STGE") {
if (gd.name == "STGE")
{
processStge(&regStatus, gd.value);
} else if (gd.name == "RELAIS") {
}
else if (gd.name == "RELAIS")
{
processRelais(&relaisStatus, gd.value);
} else if (gd.name == "PJOURF+1") {
}
else if (gd.name == "PJOURF+1")
{
processActionsCalendrier(gd.value);
}
}
} else {
TicValues[t].updated = false;
}
}
data = data.substring(index + 1);
}
}
}
static char *actionJp1AsJson() {
static char *actionJp1AsJson()
{
const int bufferSize = 1000;
static char jsonBuffer[bufferSize]; // Adjust size as needed
snprintf(jsonBuffer, bufferSize, "\"PJOURF+1\": [");
for (int i = 0; i < nbActions; i++) {
for (int i = 0; i < nbActions; i++)
{
// Format each action
char actionJson[256]; // To store individual action JSON string
String relaisSec = "";
switch ((unsigned int)actionJp1[i].action.bits.relaisSec) {
switch ((unsigned int)actionJp1[i].action.bits.relaisSec)
{
case 0:
relaisSec = "no change";
break;
@ -194,9 +189,12 @@ static char *actionJp1AsJson() {
actionJp1[i].action.bits.relais1, actionJp1[i].action.bits.index);
// Append the current action's JSON to the overall JSON buffer
if (i == (nbActions - 1)) { // Last item, no comma at the end
if (i == (nbActions - 1))
{ // Last item, no comma at the end
strncat(jsonBuffer, actionJson, bufferSize - strlen(jsonBuffer) - 1);
} else {
}
else
{
strncat(jsonBuffer, actionJson, bufferSize - strlen(jsonBuffer) - 1);
strncat(jsonBuffer, ",", bufferSize - strlen(jsonBuffer) - 1);
}
@ -207,7 +205,8 @@ static char *actionJp1AsJson() {
return jsonBuffer;
}
static char *relaisStatusAsJson(RelaisStatusBits *status, String rawValue) {
static char *relaisStatusAsJson(RelaisStatusBits *status, String rawValue)
{
// Pre-allocate buffer large enough to hold the JSON string
static char response[150]; // Adjust size as needed
// Use snprintf to construct the JSON string efficiently
@ -236,7 +235,8 @@ static char *relaisStatusAsJson(RelaisStatusBits *status, String rawValue) {
return response;
}
static char *registreStatusAsJson(RegistreStatusBits *status, String rawValue) {
static char *registreStatusAsJson(RegistreStatusBits *status, String rawValue)
{
// Pre-allocate buffer large enough to hold the JSON string
static char response[1000]; // Adjust size as needed
@ -286,18 +286,27 @@ static char *registreStatusAsJson(RegistreStatusBits *status, String rawValue) {
return response;
}
String ticValuesAsJson() {
String ticValuesAsJson()
{
String response = "{";
for (int i = 0; i < NB_ETIQUETTE; ++i) {
for (int i = 0; i < NB_ETIQUETTE; ++i)
{
if (SelectedEtiquette[i] == "STGE") {
if (SelectedEtiquette[i] == "STGE")
{
response += registreStatusAsJson(&regStatus.bits, TicValues[i].value);
} else if (SelectedEtiquette[i] == "RELAIS") {
}
else if (SelectedEtiquette[i] == "RELAIS")
{
response += relaisStatusAsJson(&relaisStatus.bits, TicValues[i].value);
} else if (SelectedEtiquette[i] == "PJOURF+1") {
}
else if (SelectedEtiquette[i] == "PJOURF+1")
{
response += actionJp1AsJson();
} else {
}
else
{
static char jres[150]; // Adjust size as needed
// Use snprintf to construct the JSON string efficiently
@ -308,7 +317,8 @@ String ticValuesAsJson() {
response += jres;
}
if (i < (NB_ETIQUETTE - 1)) {
if (i < (NB_ETIQUETTE - 1))
{
response += ',';
}
}
@ -316,16 +326,20 @@ String ticValuesAsJson() {
return response;
}
String ticBasicValuesAsJson() {
String ticBasicValuesAsJson()
{
String response = "{";
for (int i = 0; i < NB_ETIQUETTE; ++i) {
for (int i = 0; i < NB_ETIQUETTE; ++i)
{
if (SelectedEtiquette[i] == "LTARF" || SelectedEtiquette[i] == "EAST" || SelectedEtiquette[i] == "EASF01" || SelectedEtiquette[i] == "EASF02" || SelectedEtiquette[i] == "EASF03" || SelectedEtiquette[i] == "EASF04" || SelectedEtiquette[i] == "EASD01" || SelectedEtiquette[i] == "EASD02" || SelectedEtiquette[i] == "EASD03" || SelectedEtiquette[i] == "EASD04" || SelectedEtiquette[i] == "EAIT" || SelectedEtiquette[i] == "ERQ1" || SelectedEtiquette[i] == "ERQ2" || SelectedEtiquette[i] == "ERQ3" || SelectedEtiquette[i] == "ERQ4" || SelectedEtiquette[i] == "IRMS1" || SelectedEtiquette[i] == "IRMS2" || SelectedEtiquette[i] == "IRMS3" || SelectedEtiquette[i] == "URMS1" || SelectedEtiquette[i] == "URMS2" || SelectedEtiquette[i] == "URMS3" || SelectedEtiquette[i] == "SINSTS" || SelectedEtiquette[i] == "SINSTSI" || SelectedEtiquette[i] == "SINSTS1" || SelectedEtiquette[i] == "SINSTS2" || SelectedEtiquette[i] == "SINSTS3" || SelectedEtiquette[i] == "SINSTSI") {
if (SelectedEtiquette[i] == "LTARF" || SelectedEtiquette[i] == "EAST" || SelectedEtiquette[i] == "EASF01" || SelectedEtiquette[i] == "EASF02" || SelectedEtiquette[i] == "EASF03" || SelectedEtiquette[i] == "EASF04" || SelectedEtiquette[i] == "EASD01" || SelectedEtiquette[i] == "EASD02" || SelectedEtiquette[i] == "EASD03" || SelectedEtiquette[i] == "EASD04" || SelectedEtiquette[i] == "EAIT" || SelectedEtiquette[i] == "ERQ1" || SelectedEtiquette[i] == "ERQ2" || SelectedEtiquette[i] == "ERQ3" || SelectedEtiquette[i] == "ERQ4" || SelectedEtiquette[i] == "IRMS1" || SelectedEtiquette[i] == "IRMS2" || SelectedEtiquette[i] == "IRMS3" || SelectedEtiquette[i] == "URMS1" || SelectedEtiquette[i] == "URMS2" || SelectedEtiquette[i] == "URMS3" || SelectedEtiquette[i] == "SINSTS" || SelectedEtiquette[i] == "SINSTSI" || SelectedEtiquette[i] == "SINSTS1" || SelectedEtiquette[i] == "SINSTS2" || SelectedEtiquette[i] == "SINSTS3" || SelectedEtiquette[i] == "SINSTSI")
{
static char jres[150]; // Adjust size as needed
if (response != "{") {
if (response != "{")
{
response += ",";
}
@ -341,27 +355,6 @@ String ticBasicValuesAsJson() {
return response;
}
void mqttPublish(PubSubClient *mqttclient) {
for (int i = 0; i < NB_ETIQUETTE; ++i) {
if (TicValues[i].updated) {
String topic = MQTT_TOPIC;
topic += "/",
topic += SelectedEtiquette[i];
mqttclient->publish(topic.c_str(), TicValues[i].value.c_str());
TicValues[i].updated = false;
}
}
}
void mqttForcePublish(PubSubClient *mqttclient) {
for (int i = 0; i < NB_ETIQUETTE; ++i) {
String topic = MQTT_TOPIC;
topic += "/",
topic += SelectedEtiquette[i];
mqttclient->publish(topic.c_str(), TicValues[i].value.c_str());
}
}
/**
* Reads data from the TicPort and processes it according to specific control characters.
*
@ -376,12 +369,15 @@ void mqttForcePublish(PubSubClient *mqttclient) {
*
* The built-in LED is used to indicate the state of data reception.
*/
void readTicPort() {
void readTicPort()
{
// Check TicPort availability
if (TicPort.available()) {
if (TicPort.available())
{
byte incomingByte = TicPort.read(); // Read a byte from the TicPort
// Check if the incoming byte is the End Of Transmission (EOT) character
if (incomingByte == EOT) {
if (incomingByte == EOT)
{
// Force the end of transmission
// Reject everything
isReceiving = false;
@ -389,13 +385,18 @@ void readTicPort() {
}
// Check if the system is currently receiving data
if (isReceiving) {
if (isReceiving)
{
// Check if the end of the frame is reached (ETX character)
if (incomingByte == ETX) {
if (incomingByte == ETX)
{
// Extract the useful part of the frame
if (nActiveData == 1) {
if (nActiveData == 1)
{
processTrame(data1); // Process the data in data1
} else {
}
else
{
processTrame(data2); // Process the data in data2
}
// Indicate that the data reception is complete
@ -403,29 +404,41 @@ void readTicPort() {
digitalWrite(LED_BUILTIN, HIGH);
// Debugging information: Print the extracted data
#ifdef DEBUG
for (int i = 0; i < NB_ETIQUETTE; ++i) {
for (int i = 0; i < NB_ETIQUETTE; ++i)
{
DebugPort.print(TicValues[i].name);
DebugPort.print(":");
DebugPort.println(TicValues[i].value);
}
#endif
} else {
}
else
{
// Add the incoming byte to the current frame
if (nActiveData == 1) {
if (nActiveData == 1)
{
data1 += (char)incomingByte; // Append the byte to data1
} else {
}
else
{
data2 += (char)incomingByte; // Append the byte to data2
}
}
} else {
}
else
{
// Look for the start of the frame (STX character)
if (incomingByte == STX) {
if (incomingByte == STX)
{
isReceiving = true;
digitalWrite(LED_BUILTIN, LOW);
if (nActiveData == 1) {
if (nActiveData == 1)
{
data2 = "";
nActiveData = 2;
} else {
}
else
{
data1 = "";
nActiveData = 1;
}
@ -433,46 +446,3 @@ void readTicPort() {
}
}
}
// Function to calculate the checksum
unsigned char calcCheckSum(const String &data) {
unsigned int sum = 0;
// Calculate the sum of ASCII values
for (size_t i = 0; i < data.length() - 1; ++i) {
sum += data[i];
}
// Truncate the sum to 6 bits
sum &= 0x3F;
// Add 0x20 to get the final checksum
unsigned char checksum = sum + 0x20;
return checksum;
}
unsigned char calcCheckSum2(GroupDetail *data) {
char c;
uint sum = 2 * HT;
if (data->name.length() && data->value.length()) {
for (char &c : data->name) {
if (c >= 0x20 && c <= 0x7E) {
sum += c;
} else {
return 0;
}
}
for (char &c : data->value) {
if (c >= 0x20 && c <= 0x7E) {
sum += c;
} else {
return 0;
}
}
return (sum & 0x3f) + 0x20;
}
return 0;
}

8
tic.h
View File

@ -4,7 +4,6 @@
#define TIC_DEF
#include <Arduino.h>
#include <PubSubClient.h>
#define TIC
@ -13,7 +12,6 @@
#define HTTP_PORT 80 //port
// Définition des constantes pour les délimiteurs de trame TIC
//Uniquement le mode standard est supporté
//CF document ENEDIS
#define STX 0x02 // Début de la trame : 0x02 (<STX>)
#define ETX 0x03 // Fin de la trame : 0x03 (<ETX>) End Of Text
@ -30,12 +28,9 @@
// Structure pour stocker les détails d'un groupe TIC
struct GroupDetail {
String globale;
String name; // Nom de l'étiquette
String value; // Valeur associée à l'étiquette
String horodate; // Horodatage de la valeur
bool updated;
bool checkok; //status of checksum
};
// Structure pour les bits de statut du registre
@ -164,7 +159,4 @@ const static String kPointeMobile[4] = { "no", "PM1", "PM2", "PM3" };
void readTicPort();
String ticValuesAsJson();
String ticBasicValuesAsJson();
void mqttPublish(PubSubClient *mqttclient);
void mqttForcePublish(PubSubClient *mqttclient);
unsigned char calcCheckSum(const String &data);//(GroupDetail *data);
#endif