first commit
This commit is contained in:
430
ESP32_Teleinfo_Stats/ESP32_Teleinfo_Stats.ino
Normal file
430
ESP32_Teleinfo_Stats/ESP32_Teleinfo_Stats.ino
Normal file
@@ -0,0 +1,430 @@
|
||||
// **********************************************************************************
|
||||
// Arduino Teleinfo sample, Check and return Teleinfo Stats
|
||||
// This sketch works as is only for Denky D4 board, need to be adapted for other
|
||||
// **********************************************************************************
|
||||
// Creative Commons Attrib Share-Alike License
|
||||
// You are free to use/extend this library but please abide with the CC-BY-SA license:
|
||||
// http://creativecommons.org/licenses/by-sa/4.0/
|
||||
//
|
||||
// for detailled explanation of this library see dedicated article
|
||||
// https://hallard.me/libteleinfo/
|
||||
//
|
||||
// For any explanation about teleinfo or use, see my blog
|
||||
// https://hallard.me/category/tinfo
|
||||
//
|
||||
// see dedicated article here https://hallard.me/demystifier-la-teleinfo/
|
||||
//
|
||||
// Written by Charles-Henri Hallard (https://hallard.me)
|
||||
//
|
||||
// History : V1.00 2023-01-21 - First release
|
||||
//
|
||||
// All text above must be included in any redistribution.
|
||||
//
|
||||
// **********************************************************************************
|
||||
#include <LibTeleinfo.h>
|
||||
#include <WiFi.h>
|
||||
#include <WiFiClient.h>
|
||||
#include <WebServer.h>
|
||||
#include <ESPmDNS.h>
|
||||
#include <Update.h>
|
||||
#include <ArduinoOTA.h>
|
||||
|
||||
|
||||
const char* ssid = "Livebox-37cc";
|
||||
const char* pass = "8A6060920A8A86896F770F2C47";
|
||||
WebServer server(80);
|
||||
|
||||
|
||||
#define SERIAL_DEBUG Serial
|
||||
#define SERIAL_TIC Serial1
|
||||
|
||||
#define PUSH_BUTTON 15 //0
|
||||
|
||||
// Teleinfo RXD pin is connected to ESP32-PICO-V3-02 GPIO8
|
||||
#define TIC_RX_PIN 16 //8
|
||||
|
||||
// Default mode, can be switched back and forth
|
||||
// with Denky D4 push button
|
||||
_Mode_e tinfo_mode = TINFO_MODE_HISTORIQUE;
|
||||
|
||||
TInfo tinfo; // Teleinfo object
|
||||
|
||||
// Uptime timer
|
||||
boolean tick1sec=0;// one for interrupt, don't mess with
|
||||
unsigned long uptime=0; // save value we can use in sketch even if we're interrupted
|
||||
|
||||
// Count total frames
|
||||
uint32_t total_frames = 0;
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Login page
|
||||
*/
|
||||
|
||||
const char* loginIndex =
|
||||
"<form name='loginForm'>"
|
||||
"<table width='20%' bgcolor='A09F9F' align='center'>"
|
||||
"<tr>"
|
||||
"<td colspan=2>"
|
||||
"<center><font size=4><b>ESP32 Login Page</b></font></center>"
|
||||
"<br>"
|
||||
"</td>"
|
||||
"<br>"
|
||||
"<br>"
|
||||
"</tr>"
|
||||
"<tr>"
|
||||
"<td>Username:</td>"
|
||||
"<td><input type='text' size=25 name='userid'><br></td>"
|
||||
"</tr>"
|
||||
"<br>"
|
||||
"<br>"
|
||||
"<tr>"
|
||||
"<td>Password:</td>"
|
||||
"<td><input type='Password' size=25 name='pwd'><br></td>"
|
||||
"<br>"
|
||||
"<br>"
|
||||
"</tr>"
|
||||
"<tr>"
|
||||
"<td><input type='submit' onclick='check(this.form)' value='Login'></td>"
|
||||
"</tr>"
|
||||
"</table>"
|
||||
"</form>"
|
||||
"<script>"
|
||||
"function check(form)"
|
||||
"{"
|
||||
"if(form.userid.value=='admin' && form.pwd.value=='admin')"
|
||||
"{"
|
||||
"window.open('/serverIndex')"
|
||||
"}"
|
||||
"else"
|
||||
"{"
|
||||
" alert('Error Password or Username')/*displays error message*/"
|
||||
"}"
|
||||
"}"
|
||||
"</script>";
|
||||
|
||||
|
||||
|
||||
/* ======================================================================
|
||||
Function: ShowStats
|
||||
Purpose : display teleinfo stats
|
||||
Input : -
|
||||
Output : -
|
||||
Comments: -
|
||||
====================================================================== */
|
||||
void ShowStats()
|
||||
{
|
||||
SERIAL_DEBUG.println(F("\r\n======= Stats ======="));
|
||||
SERIAL_DEBUG.printf_P(PSTR("Total Frames : %d\r\n"), total_frames);
|
||||
SERIAL_DEBUG.printf_P(PSTR("Interrupts : %d\r\n"), tinfo.getFrameInterruptedCount());
|
||||
SERIAL_DEBUG.printf_P(PSTR("Checksum Err : %d\r\n"), tinfo.getChecksumErrorCount());
|
||||
SERIAL_DEBUG.printf_P(PSTR("Size Err : %d\r\n"), tinfo.getFrameSizeErrorCount());
|
||||
SERIAL_DEBUG.printf_P(PSTR("Format Err : %d\r\n"), tinfo.getFrameFormatErrorCount());
|
||||
SERIAL_DEBUG.println( F("====================="));
|
||||
}
|
||||
|
||||
|
||||
/* ======================================================================
|
||||
Function: NewFrame
|
||||
Purpose : callback when we received a complete teleinfo frame
|
||||
Input : linked list pointer on the concerned data
|
||||
Output : -
|
||||
Comments: -
|
||||
====================================================================== */
|
||||
void NewFrame(ValueList * me)
|
||||
{
|
||||
total_frames++;
|
||||
// Display stat info on each 10 frames
|
||||
if (total_frames % 10 == 0) {
|
||||
ShowStats();
|
||||
}
|
||||
}
|
||||
|
||||
/* ======================================================================
|
||||
Function: initSerial
|
||||
Purpose : Configure (or reconfigure Serial Port)
|
||||
Input : -
|
||||
Output : -
|
||||
Comments: -
|
||||
====================================================================== */
|
||||
void initSerial()
|
||||
{
|
||||
// Cleanup
|
||||
SERIAL_TIC.flush();
|
||||
SERIAL_TIC.end();
|
||||
|
||||
// Configure Teleinfo
|
||||
SERIAL_DEBUG.printf_P(PSTR("TIC RX=GPIO%d Mode:"), TIC_RX_PIN);
|
||||
SERIAL_TIC.begin(tinfo_mode == TINFO_MODE_HISTORIQUE ? 1200 : 9600, SERIAL_7E1, TIC_RX_PIN);
|
||||
|
||||
if ( tinfo_mode == TINFO_MODE_HISTORIQUE ) {
|
||||
SERIAL_DEBUG.println(F("Historique"));
|
||||
} else {
|
||||
SERIAL_DEBUG.println(F("Standard"));
|
||||
}
|
||||
}
|
||||
|
||||
/* ======================================================================
|
||||
Function: setup
|
||||
Purpose : Setup I/O and other one time startup stuff
|
||||
Input : -
|
||||
Output : -
|
||||
Comments: -
|
||||
====================================================================== */
|
||||
void setup()
|
||||
{
|
||||
// Serial, pour le debug
|
||||
SERIAL_DEBUG.begin(115200);
|
||||
SERIAL_DEBUG.println(F("\r\n\r\n"));
|
||||
SERIAL_DEBUG.println(F("====================================="));
|
||||
SERIAL_DEBUG.println(F(" Teleinfo stats "));
|
||||
SERIAL_DEBUG.println(F("====================================="));
|
||||
SERIAL_DEBUG.println(F(" You can change teleinfo mode from"));
|
||||
SERIAL_DEBUG.println(F("Historique to Standard with B0 button"));
|
||||
|
||||
// Button
|
||||
pinMode(PUSH_BUTTON, INPUT_PULLUP);
|
||||
|
||||
// Init Serial Port
|
||||
initSerial();
|
||||
// Init teleinfo
|
||||
tinfo.init(tinfo_mode);
|
||||
// Attacher les callback dont nous avons besoin
|
||||
tinfo.attachNewFrame(NewFrame);
|
||||
|
||||
WiFi.mode(WIFI_STA);
|
||||
WiFi.begin(ssid, pass);
|
||||
while (WiFi.waitForConnectResult() != WL_CONNECTED) {
|
||||
Serial.println("Connection Failed! Rebooting...");
|
||||
delay(5000);
|
||||
ESP.restart();
|
||||
}
|
||||
|
||||
// Définissez les gestionnaires pour les différentes URL
|
||||
// server.on("/", HTTP_GET, handleRoot);
|
||||
// server.on("/getData", HTTP_GET, handleData);
|
||||
server.on("/", HTTP_GET, []() {
|
||||
server.sendHeader("Connection", "close");
|
||||
server.send(200, "text/html", loginIndex);
|
||||
});
|
||||
|
||||
// Démarrer le serveur
|
||||
server.begin();
|
||||
Serial.println("Serveur Web démarré");
|
||||
|
||||
// Port defaults to 8266
|
||||
ArduinoOTA.setPort(8266);
|
||||
|
||||
// Hostname defaults to esp8266-[ChipID]
|
||||
// ArduinoOTA.setHostname("myesp8266");
|
||||
|
||||
// No authentication by default
|
||||
// ArduinoOTA.setPassword("admin");
|
||||
|
||||
// Password can be set with it's md5 value as well
|
||||
// MD5(admin) = 21232f297a57a5a743894a0e4a801fc3
|
||||
// ArduinoOTA.setPasswordHash("21232f297a57a5a743894a0e4a801fc3");
|
||||
|
||||
ArduinoOTA.onStart([]() {
|
||||
String type;
|
||||
if (ArduinoOTA.getCommand() == U_FLASH) {
|
||||
type = "sketch";
|
||||
} else { // U_FS
|
||||
type = "filesystem";
|
||||
}
|
||||
|
||||
// NOTE: if updating FS this would be the place to unmount FS using FS.end()
|
||||
Serial.println("Start updating " + type);
|
||||
});
|
||||
ArduinoOTA.onEnd([]() {
|
||||
Serial.println("\nEnd");
|
||||
});
|
||||
ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
|
||||
Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
|
||||
});
|
||||
ArduinoOTA.onError([](ota_error_t error) {
|
||||
Serial.printf("Error[%u]: ", error);
|
||||
if (error == OTA_AUTH_ERROR) {
|
||||
Serial.println("Auth Failed");
|
||||
} else if (error == OTA_BEGIN_ERROR) {
|
||||
Serial.println("Begin Failed");
|
||||
} else if (error == OTA_CONNECT_ERROR) {
|
||||
Serial.println("Connect Failed");
|
||||
} else if (error == OTA_RECEIVE_ERROR) {
|
||||
Serial.println("Receive Failed");
|
||||
} else if (error == OTA_END_ERROR) {
|
||||
Serial.println("End Failed");
|
||||
}
|
||||
});
|
||||
ArduinoOTA.begin();
|
||||
Serial.println("Ready");
|
||||
Serial.print("IP address: ");
|
||||
Serial.println(WiFi.localIP());
|
||||
}
|
||||
|
||||
/* ======================================================================
|
||||
Function: loop
|
||||
Purpose : infinite loop main code
|
||||
Input : -
|
||||
Output : -
|
||||
Comments: -
|
||||
====================================================================== */
|
||||
void loop()
|
||||
{
|
||||
ArduinoOTA.handle();
|
||||
server.handleClient();
|
||||
|
||||
//SERIAL_DEBUG.println("In loop");
|
||||
static char c;
|
||||
static unsigned long previousMillis = 0;
|
||||
static uint8_t buttonState = 0;
|
||||
static unsigned long lastDebounceTime = 0;
|
||||
_State_e state;
|
||||
|
||||
unsigned long currentMillis = millis();
|
||||
|
||||
// Button to switch mode
|
||||
uint8_t button = digitalRead(PUSH_BUTTON);
|
||||
|
||||
// New Press
|
||||
if ( button==LOW && buttonState==0) {
|
||||
buttonState = 1;
|
||||
lastDebounceTime = millis();
|
||||
|
||||
// Pressed enought (debounced)
|
||||
} else if ( buttonState==1 && button==LOW && (millis()-lastDebounceTime)>50 ) {
|
||||
buttonState = 2;
|
||||
|
||||
// Release (no need debouce here)
|
||||
} else if ( buttonState==2 && button==HIGH ) {
|
||||
|
||||
// Invert mode
|
||||
if ( tinfo_mode == TINFO_MODE_HISTORIQUE ) {
|
||||
tinfo_mode = TINFO_MODE_STANDARD;
|
||||
} else {
|
||||
tinfo_mode = TINFO_MODE_HISTORIQUE;
|
||||
}
|
||||
|
||||
// Init Serial Port
|
||||
initSerial();
|
||||
|
||||
// Init teleinfo
|
||||
tinfo.init(tinfo_mode);
|
||||
|
||||
lastDebounceTime = millis();
|
||||
buttonState = 0;
|
||||
}
|
||||
|
||||
|
||||
// Avons nous recu un ticker de seconde?
|
||||
if (tick1sec) {
|
||||
tick1sec = false;
|
||||
uptime++;
|
||||
}
|
||||
|
||||
// On a reçu un caractère ?
|
||||
if ( SERIAL_TIC.available() ) {
|
||||
// Le lire
|
||||
c = SERIAL_TIC.read();
|
||||
|
||||
// Gérer
|
||||
state = tinfo.process(c);
|
||||
|
||||
// L'affcher dans la console
|
||||
if (c==TINFO_STX) {
|
||||
SERIAL_DEBUG.print("<STX>");
|
||||
} else if (c==TINFO_ETX) {
|
||||
SERIAL_DEBUG.print("<ETX>");
|
||||
} else if (c==TINFO_HT) {
|
||||
SERIAL_DEBUG.print("<TAB>");
|
||||
} else if (c==TINFO_EOT) {
|
||||
SERIAL_DEBUG.print("<INTERRUPT>");
|
||||
} else {
|
||||
// Display only when receiving state OK
|
||||
if (state == TINFO_READY) {
|
||||
SERIAL_DEBUG.print(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (currentMillis - previousMillis > 1000 ) {
|
||||
// save the last time
|
||||
previousMillis = currentMillis;
|
||||
tick1sec = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ======================================================================
|
||||
Function: sendJSON
|
||||
Purpose : dump teleinfo values on serial
|
||||
Input : linked list pointer on the concerned data
|
||||
true to dump all values, false for only modified ones
|
||||
Output : -
|
||||
Comments: -
|
||||
====================================================================== */
|
||||
void sendJSON(ValueList * me, boolean all)
|
||||
{
|
||||
bool firstdata = true;
|
||||
|
||||
// Got at least one ?
|
||||
if (me) {
|
||||
// Json start
|
||||
Serial.print(F("{"));
|
||||
|
||||
if (all) {
|
||||
Serial.print(F("\"_UPTIME\":"));
|
||||
Serial.print(uptime, DEC);
|
||||
firstdata = false;
|
||||
}
|
||||
|
||||
// Loop thru the node
|
||||
while (me->next) {
|
||||
// go to next node
|
||||
me = me->next;
|
||||
|
||||
// uniquement sur les nouvelles valeurs ou celles modifiées
|
||||
// sauf si explicitement demandé toutes
|
||||
if ( all || ( me->flags & (TINFO_FLAGS_UPDATED | TINFO_FLAGS_ADDED) ) )
|
||||
{
|
||||
// First elemement, no comma
|
||||
if (firstdata)
|
||||
firstdata = false;
|
||||
else
|
||||
Serial.print(F(", ")) ;
|
||||
|
||||
Serial.print(F("\"")) ;
|
||||
Serial.print(me->name) ;
|
||||
Serial.print(F("\":")) ;
|
||||
|
||||
// we have at least something ?
|
||||
if (me->value && strlen(me->value))
|
||||
{
|
||||
boolean isNumber = true;
|
||||
uint8_t c;
|
||||
char * p = me->value;
|
||||
|
||||
// check if value is number
|
||||
while (*p && isNumber) {
|
||||
if ( *p < '0' || *p > '9' )
|
||||
isNumber = false;
|
||||
p++;
|
||||
}
|
||||
|
||||
// this will add "" on not number values
|
||||
if (!isNumber) {
|
||||
Serial.print(F("\"")) ;
|
||||
Serial.print(me->value) ;
|
||||
Serial.print(F("\"")) ;
|
||||
}
|
||||
// this will remove leading zero on numbers
|
||||
else
|
||||
Serial.print(atol(me->value));
|
||||
}
|
||||
}
|
||||
}
|
||||
// Json end
|
||||
Serial.println(F("}")) ;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user