Libteleinfo update to V1.1.5 (#18050)

* Updated to V1.1.5

* Updated to V.1.1.5

Added new End Of Transmission code from Standard Mode
Check back checksum before returning stored values (corruption checks)
Added error counters stats
Removed dirty linked list align #pragma for ESP target
This commit is contained in:
Charles 2023-02-25 15:56:33 +01:00 committed by GitHub
parent 0aaa616881
commit 1b5c4768d1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 116 additions and 55 deletions

View File

@ -1,14 +1,12 @@
Teleinfo (Aka TIC) Universal Library # Teleinfo (Aka TIC) Universal Library
====================================
This is a generic Teleinfo French Meter Measure Library, it can be used on Arduino like device and also such as Spark Core, Particle, ESP8266, Raspberry PI or anywhere you can do Cpp code ... This is a generic Teleinfo French Meter Measure Library, it can be used on Arduino like device and also such as Spark Core, Particle, ESP8266, Raspberry PI or anywhere you can do Cpp code ...
You can see Teleinformation official french datasheet [there][1] You can see Teleinformation official french datasheet [there][1] and this one is for [Linky][3].
Since this is really dedicated to French energy measuring system, I will continue in French Since this is really dedicated to French energy measuring system, I will continue in French.
Installation # Installation
============
Copier le contenu de ce dossier (download zip) dans le dossier libraries de votre environnement Arduino Vous devriez avoir maintenant quelque chose comme `your_sketchbook_folder/libraries/LibTeleinfo` et ce dossier doit contentir les fichiers .cpp et .h ainsi que le sous dossier `examples`. Copier le contenu de ce dossier (download zip) dans le dossier libraries de votre environnement Arduino Vous devriez avoir maintenant quelque chose comme `your_sketchbook_folder/libraries/LibTeleinfo` et ce dossier doit contentir les fichiers .cpp et .h ainsi que le sous dossier `examples`.
<br/> <br/>
@ -17,14 +15,12 @@ Pour trouver votre dossier de sketchbook, dans l'environnement IDE, allez dans F
allez voir ce [tutorial][2] sur les librairies Arduino si beoin. allez voir ce [tutorial][2] sur les librairies Arduino si beoin.
<br/> <br/>
Documentation # Documentation
=============
J'ai écrit un article [dédié][10] sur cette librairie, vous pouvez aussi voir les [catégories][6] associées à la téléinfo sur mon [blog][7]. J'ai écrit un article [dédié][10] sur cette librairie, vous pouvez aussi voir les [catégories][6] associées à la téléinfo sur mon [blog][7].
Pour les commentaires et le support vous pouvez allez sur le [forum][8] dédié ou dans la [communauté][9] Pour les commentaires et le support vous pouvez allez sur le [forum][8] dédié ou dans la [communauté][9]
Sketch d'exemples # Sketch d'exemples
=================
- [Arduino_Softserial_Etiquette][3] Affiche des informations de téléinformation reçue étiquette par étiquette - [Arduino_Softserial_Etiquette][3] Affiche des informations de téléinformation reçue étiquette par étiquette
- [Arduino_Softserial_Blink][11] Affiche des informations de téléinformation reçue trame par trame avec clignotement LED court/long si les données ont été modifiés - [Arduino_Softserial_Blink][11] Affiche des informations de téléinformation reçue trame par trame avec clignotement LED court/long si les données ont été modifiés
@ -32,23 +28,32 @@ Sketch d'exemples
- [Raspberry_JSON][12] Retourne les informations de téléinformation au format JSON sur stdout. - [Raspberry_JSON][12] Retourne les informations de téléinformation au format JSON sur stdout.
- [Wifinfo][5] ESP8266, ESP32 Wifi Teleinformation, Web + Rest + bonus, version en cours de développement, à venir mais un article [dédié][13] est déjà présent sur mon blog - [Wifinfo][5] ESP8266, ESP32 Wifi Teleinformation, Web + Rest + bonus, version en cours de développement, à venir mais un article [dédié][13] est déjà présent sur mon blog
- [ESP32][14] ESP32 Basic test pour WifInfo32 nouveau nom Denky :-) - [ESP32][14] ESP32 Basic test pour WifInfo32 nouveau nom Denky :-)
- [ESP32_Passthru][14] ESP32 PassThru Basic test pour Denky D4, affiche les données et les stats de la téléinfo dans la console série
- [ESP8266_DataChanged][15] ESP8266 Surveille et affiche les données changées entre 2 trames, clignote la LED RGB en fonction
- [Teleinfo_DenkyD4][16] ESP32 Denky D4 Basic test et stats pour le nouveau Denky D4 basé sur l'ESP32-Pico-V3-02
- [Teleinfo_Stats][18] ESP32 Programme de test et statistiques pour la qualité de réception
# Pourquoi
Pourquoi
========
- J'utilise la téléinfo dans plusieurs de mes programmes et j'en avais marre de devoir faire des copier/coller de code constament, j'ai donc décidé de faire une librairie commune que j'utilise sans me poser de question - J'utilise la téléinfo dans plusieurs de mes programmes et j'en avais marre de devoir faire des copier/coller de code constament, j'ai donc décidé de faire une librairie commune que j'utilise sans me poser de question
License # License
=======
Cette oeuvre est mise à disposition selon les termes de la Licence Creative Commons Attribution - Pas dUtilisation Commerciale - Partage dans les Mêmes Conditions 4.0 International. Cette oeuvre est mise à disposition selon les termes de la Licence Creative Commons Attribution - Pas dUtilisation Commerciale - Partage dans les Mêmes Conditions 4.0 International.
Si vous êtes une entreprise et que vous souhaitez participer car vous utilisez cette librairie dans du hardware (box, automate, ...), vous pouvez toujours m'envoyer un exemplaire de votre fabrication, c'est toujours sympa de voir ce qui est fait avec ce code ;-) Si vous êtes une entreprise et que vous souhaitez participer car vous utilisez cette librairie dans du hardware (box, automate, ...), vous pouvez toujours m'envoyer un exemplaire de votre fabrication, c'est toujours sympa de voir ce qui est fait avec ce code ;-)
Divers # Addon
======
Ajout des compteurs d'erreurs, et du traitement du caracteres EOT d'interruption de trames
# Divers
Vous pouvez aller voir les nouveautés et autres projets sur [blog][7] Vous pouvez aller voir les nouveautés et autres projets sur [blog][7]
[1]: http://www.erdf.fr/sites/default/files/ERDF-NOI-CPT_02E.pdf [1]: https://www.enedis.fr/sites/default/files/Enedis-NOI-CPT_02E.pdf
[2]: http://learn.adafruit.com/arduino-tips-tricks-and-techniques/arduino-libraries [2]: http://learn.adafruit.com/arduino-tips-tricks-and-techniques/arduino-libraries
[3]: https://www.enedis.fr/sites/default/files/Enedis-NOI-CPT_54E.pdf
[6]: https://hallard.me/category/tinfo/ [6]: https://hallard.me/category/tinfo/
[7]: https://hallard.me [7]: https://hallard.me
[8]: https://community.hallard.me/category/7 [8]: https://community.hallard.me/category/7
@ -59,7 +64,12 @@ Vous pouvez aller voir les nouveautés et autres projets sur [blog][7]
[4]: https://github.com/hallard/LibTeleinfo/blob/master/examples/Arduino_Softserial_JSON/Arduino_Softserial_JSON.ino [4]: https://github.com/hallard/LibTeleinfo/blob/master/examples/Arduino_Softserial_JSON/Arduino_Softserial_JSON.ino
[5]: https://github.com/hallard/LibTeleinfo/tree/master/examples/Wifinfo/Wifinfo.ino [5]: https://github.com/hallard/LibTeleinfo/tree/master/examples/Wifinfo/Wifinfo.ino
[11]: https://github.com/hallard/LibTeleinfo/blob/master/examples/Arduino_Softserial/Arduino_Softserial_Blink.ino [11]: https://github.com/hallard/LibTeleinfo/blob/master/examples/Arduino_Softserial/Arduino_Softserial_Blink.ino
[12]: https://github.com/hallard/LibTeleinfo/blob/master/examples/Raspberry_JSON/Raspberry_JSON.ino [12]: https://github.com/hallard/LibTeleinfo/blob/master/examples/Raspberry_JSON/raspjson.cpp
[13]: https://hallard.me/wifiinfo/ [13]: https://hallard.me/wifiinfo/
[14]: https://github.com/hallard/LibTeleinfo/blob/master/examples/ESP32/ESP32.ino [14]: https://github.com/hallard/LibTeleinfo/blob/master/examples/ESP32/ESP32.ino
[15]: https://github.com/hallard/LibTeleinfo/blob/master/examples/ESP8266_DataChanged/ESP8266_DataChanged.ino
[16]: https://github.com/hallard/LibTeleinfo/blob/master/examples/Teleinfo_DenkyD4/Teleinfo_DenkyD4.ino
[17]: https://github.com/hallard/LibTeleinfo/blob/master/examples/ESP32_Passthru/ESP32_Passthru.ino
[18]: https://github.com/hallard/LibTeleinfo/blob/master/examples/Teleinfo_Stats/Teleinfo_Stats.ino

View File

@ -1,6 +1,6 @@
{ {
"name": "LibTeleinfo", "name": "LibTeleinfo",
"version": "1.1.3", "version": "1.1.5",
"keywords": "teleinfo, french, meter, power, erdf, linky, tic", "keywords": "teleinfo, french, meter, power, erdf, linky, tic",
"description": "Decoder for Teleinfo (aka TIC) from French smart power meters", "description": "Decoder for Teleinfo (aka TIC) from French smart power meters",
"repository": "repository":

View File

@ -1,5 +1,5 @@
name=LibTeleinfo name=LibTeleinfo
version=1.1.3 version=1.1.5
author=Charles-Henri Hallard <hallard.me> author=Charles-Henri Hallard <hallard.me>
maintainer=Charles-Henri Hallard <community.hallard.me> maintainer=Charles-Henri Hallard <community.hallard.me>
sentence=Decoder for Teleinfo (aka TIC) from French smart power meters sentence=Decoder for Teleinfo (aka TIC) from French smart power meters

View File

@ -50,6 +50,8 @@ TInfo::TInfo()
_fn_data = NULL; _fn_data = NULL;
_fn_new_frame = NULL; _fn_new_frame = NULL;
_fn_updated_frame = NULL; _fn_updated_frame = NULL;
clearStats();
} }
/* ====================================================================== /* ======================================================================
@ -78,6 +80,22 @@ void TInfo::init(_Mode_e mode)
} }
} }
/* ======================================================================
Function: clearStats
Purpose : clear stats counters
Input : -
Output : -
Comments: -
====================================================================== */
void TInfo::clearStats()
{
// reset Frame counters stats
_checksumerror =0;
_framesizeerror=0;
_frameformaterror=0;
_frameinterrupted=0;
}
/* ====================================================================== /* ======================================================================
Function: attachADPS Function: attachADPS
Purpose : attach a callback when we detected a ADPS on any phase Purpose : attach a callback when we detected a ADPS on any phase
@ -226,6 +244,7 @@ ValueList * TInfo::valueAdd(char * name, char * value, uint8_t checksum, uint8_t
ValueList *parNode = NULL ; ValueList *parNode = NULL ;
uint32_t ts = 0; uint32_t ts = 0;
// Time stamped field?
if (horodate && *horodate) { if (horodate && *horodate) {
ts = horodate2Timestamp(horodate); ts = horodate2Timestamp(horodate);
} }
@ -256,8 +275,8 @@ ValueList * TInfo::valueAdd(char * name, char * value, uint8_t checksum, uint8_t
if (strlen(me->value) >= lgvalue ) { if (strlen(me->value) >= lgvalue ) {
// Copy it // Copy it
strlcpy(me->value, value , lgvalue + 1 ); strlcpy(me->value, value , lgvalue + 1 );
me->checksum = checksum ; // store checksum for future check without horodate
me->checksum = ts ? calcChecksum(name,value) : checksum ;
// That's all // That's all
return (me); return (me);
} else { } else {
@ -279,19 +298,12 @@ ValueList * TInfo::valueAdd(char * name, char * value, uint8_t checksum, uint8_t
// Our linked list structure sizeof(ValueList) // Our linked list structure sizeof(ValueList)
// + Name + '\0' // + Name + '\0'
// + Value + '\0' // + Value + '\0'
size_t size ; size_t size = sizeof(ValueList) + lgname + 1 + lgvalue + 1 ;
#if defined (ESP8266) || defined (ESP32)
lgname = ESP_allocAlign(lgname+1); // Align name buffer
lgvalue = ESP_allocAlign(lgvalue+1); // Align value buffer
// Align the whole structure
size = ESP_allocAlign( sizeof(ValueList) + lgname + lgvalue ) ;
#else
size = sizeof(ValueList) + lgname + 1 + lgvalue + 1 ;
#endif
// Create new node with size to store strings // Create new node with size to store strings
if ((newNode = (ValueList *) malloc(size) ) == NULL) if ((newNode = (ValueList *) malloc(size) ) == NULL) {
return ( (ValueList *) NULL ); return ( (ValueList *) NULL );
}
// get our buffer Safe // get our buffer Safe
memset(newNode, 0, size); memset(newNode, 0, size);
@ -456,6 +468,8 @@ char * TInfo::valueGet(char * name, char * value)
if (lgname==strlen(me->name) && strcmp(me->name, name)==0) { if (lgname==strlen(me->name) && strcmp(me->name, name)==0) {
// this one has a value ? // this one has a value ?
if (me->value) { if (me->value) {
// Check back checksum
if (me->checksum == calcChecksum(me->name, me->value)) {
// copy to dest buffer // copy to dest buffer
uint8_t lgvalue = strlen(me->value); uint8_t lgvalue = strlen(me->value);
strlcpy(value, me->value , lgvalue + 1 ); strlcpy(value, me->value , lgvalue + 1 );
@ -464,6 +478,7 @@ char * TInfo::valueGet(char * name, char * value)
} }
} }
} }
}
// not found // not found
return ( NULL); return ( NULL);
} }
@ -494,6 +509,8 @@ char * TInfo::valueGet_P(const char * name, char * value)
if (lgname==strlen(me->name) && strcmp_P(me->name, name)==0) { if (lgname==strlen(me->name) && strcmp_P(me->name, name)==0) {
// this one has a value ? // this one has a value ?
if (me->value) { if (me->value) {
// Check back checksum
if (me->checksum == calcChecksum(me->name, me->value)) {
// copy to dest buffer // copy to dest buffer
uint8_t lgvalue = strlen(me->value); uint8_t lgvalue = strlen(me->value);
strlcpy(value, me->value , lgvalue + 1 ); strlcpy(value, me->value , lgvalue + 1 );
@ -502,6 +519,7 @@ char * TInfo::valueGet_P(const char * name, char * value)
} }
} }
} }
}
// not found // not found
return ( NULL); return ( NULL);
} }
@ -529,6 +547,7 @@ uint8_t TInfo::valuesDump(void)
// Get our linked list // Get our linked list
ValueList * me = &_valueslist; ValueList * me = &_valueslist;
uint8_t index = 0; uint8_t index = 0;
uint8_t checksum=0;
// Got one ? // Got one ?
if (me) { if (me) {
@ -555,9 +574,17 @@ uint8_t TInfo::valuesDump(void)
TI_Debug(F("NULL")) ; TI_Debug(F("NULL")) ;
} }
if (me->name && me->value && *me->name && *me->value) {
checksum = calcChecksum(me->name, me->value);
}
TI_Debug(F(" '")) ; TI_Debug(F(" '")) ;
TI_Debug(me->checksum) ; TI_Debug(me->checksum) ;
if (me->checksum != checksum ) {
TI_Debug(F("'!Err "));
} else {
TI_Debug(F("' ")); TI_Debug(F("' "));
}
// Flags management // Flags management
if ( me->flags) { if ( me->flags) {
@ -798,6 +825,7 @@ ValueList * TInfo::checkLine(char * pline)
// 2 Label + Space + 1 etiquette + space + checksum + \r // 2 Label + Space + 1 etiquette + space + checksum + \r
if ( len < 7 || len >= TINFO_BUFSIZE) { if ( len < 7 || len >= TINFO_BUFSIZE) {
//AddLog(3, PSTR("LibTeleinfo: Error len < 7 || len >= TINFO_BUFSIZE")); //AddLog(3, PSTR("LibTeleinfo: Error len < 7 || len >= TINFO_BUFSIZE"));
_framesizeerror++;
return NULL; return NULL;
} }
@ -904,10 +932,16 @@ ValueList * TInfo::checkLine(char * pline)
} }
else else
{ {
AddLog(1, PSTR("LibTeleinfo::checkLine Err checksum 0x%02X != 0x%02X"), calc_checksum, checksum); _checksumerror++;
AddLog(1, PSTR("LibTeleinfo::checkLine Err checksum 0x%02X != 0x%02X (total errors=%d)"), calc_checksum, checksum, _checksumerror);
} }
} }
} }
else
{
_frameformaterror++;
AddLog(1, PSTR("LibTeleinfo::checkLine frame format error, total=%d"), _frameformaterror);
}
} }
// Next char // Next char
p++; p++;
@ -949,6 +983,16 @@ _State_e TInfo::process(char c)
} }
break; break;
// frame interruption
case TINFO_EOT:
//AddLog(3, PSTR("LibTeleinfo: case TINFO_EOT >>>>>>>>>>>>>>>>>>"));
// discard incomplete frame
// Clear buffer, begin to store in it
clearBuffer();
_frameinterrupted++;
_state = TINFO_WAIT_STX;
break;
// End of transmission ? // End of transmission ?
case TINFO_ETX: case TINFO_ETX:
//AddLog(3, PSTR("LibTeleinfo: case TINFO_ETX >>>>>>>>>>>>>>>>>>")); //AddLog(3, PSTR("LibTeleinfo: case TINFO_ETX >>>>>>>>>>>>>>>>>>"));
@ -1002,8 +1046,12 @@ _State_e TInfo::process(char c)
// Are we ready to process ? // Are we ready to process ?
if (_state == TINFO_READY) { if (_state == TINFO_READY) {
// Store data recceived (we'll need it) // Store data recceived (we'll need it)
if ( _recv_idx < TINFO_BUFSIZE) if ( _recv_idx < TINFO_BUFSIZE) {
_recv_buff[_recv_idx++]=c; _recv_buff[_recv_idx++]=c;
} else {
// group is too big (some ETX missing)
_framesizeerror++;
}
// clear the end of buffer (paranoia inside) // clear the end of buffer (paranoia inside)
memset(&_recv_buff[_recv_idx], 0, TINFO_BUFSIZE-_recv_idx); memset(&_recv_buff[_recv_idx], 0, TINFO_BUFSIZE-_recv_idx);

View File

@ -74,14 +74,6 @@ void AddLog(uint32_t loglevel, PGM_P formatP, ...);
#define TI_Debugflush {} #define TI_Debugflush {}
#endif #endif
// For 4 bytes Aligment boundaries
#if defined (ESP8266) || defined (ESP32)
#define ESP_allocAlign(size) ((size + 3) & ~((size_t) 3))
#endif
#pragma pack(push) // push current alignment to stack
#pragma pack(1) // set alignment to 1 byte boundary
// Linked list structure containing all values received // Linked list structure containing all values received
typedef struct _ValueList ValueList; typedef struct _ValueList ValueList;
struct _ValueList struct _ValueList
@ -94,8 +86,6 @@ struct _ValueList
char * value; // value char * value; // value
}; };
#pragma pack(pop)
// Library state machine // Library state machine
enum _Mode_e { enum _Mode_e {
TINFO_MODE_HISTORIQUE, // Legacy mode (1200) TINFO_MODE_HISTORIQUE, // Legacy mode (1200)
@ -125,6 +115,7 @@ enum _State_e {
// Teleinfo start and end of frame characters // Teleinfo start and end of frame characters
#define TINFO_STX 0x02 #define TINFO_STX 0x02
#define TINFO_ETX 0x03 #define TINFO_ETX 0x03
#define TINFO_EOT 0x04 // frame interrupt (End Of Transmission)
#define TINFO_HT 0x09 #define TINFO_HT 0x09
#define TINFO_SGR '\n' // start of group #define TINFO_SGR '\n' // start of group
#define TINFO_EGR '\r' // End of group #define TINFO_EGR '\r' // End of group
@ -151,7 +142,12 @@ class TInfo
char * valueGet_P(const char * name, char * value); char * valueGet_P(const char * name, char * value);
int labelCount(); int labelCount();
boolean listDelete(); boolean listDelete();
void clearStats();
unsigned char calcChecksum(char *etiquette, char *valeur, char *horodate=NULL) ; unsigned char calcChecksum(char *etiquette, char *valeur, char *horodate=NULL) ;
uint32_t getChecksumErrorCount() { return _checksumerror; };
uint32_t getFrameSizeErrorCount() { return _framesizeerror; };
uint32_t getFrameFormatErrorCount() { return _frameformaterror; };
uint32_t getFrameInterruptedCount() { return _frameinterrupted; };
private: private:
void clearBuffer(); void clearBuffer();
@ -169,6 +165,13 @@ class TInfo
char _separator; char _separator;
uint8_t _recv_idx; // index in receive buffer uint8_t _recv_idx; // index in receive buffer
boolean _frame_updated; // Data on the frame has been updated boolean _frame_updated; // Data on the frame has been updated
// Frame counters stats
uint32_t _checksumerror;
uint32_t _framesizeerror;
uint32_t _frameformaterror;
uint32_t _frameinterrupted;
void (*_fn_ADPS)(uint8_t phase, char * label); void (*_fn_ADPS)(uint8_t phase, char * label);
void (*_fn_data)(ValueList * valueslist, uint8_t state); void (*_fn_data)(ValueList * valueslist, uint8_t state);
void (*_fn_new_frame)(ValueList * valueslist); void (*_fn_new_frame)(ValueList * valueslist);