From 1b5c4768d1c39dfd0637c835d2530503d27a2254 Mon Sep 17 00:00:00 2001 From: Charles Date: Sat, 25 Feb 2023 15:56:33 +0100 Subject: [PATCH] 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 --- lib/lib_div/LibTeleinfo/README.md | 46 ++++++---- lib/lib_div/LibTeleinfo/library.json | 2 +- lib/lib_div/LibTeleinfo/library.properties | 2 +- lib/lib_div/LibTeleinfo/src/LibTeleinfo.cpp | 98 +++++++++++++++------ lib/lib_div/LibTeleinfo/src/LibTeleinfo.h | 23 ++--- 5 files changed, 116 insertions(+), 55 deletions(-) diff --git a/lib/lib_div/LibTeleinfo/README.md b/lib/lib_div/LibTeleinfo/README.md index 11a90ac2b..a83d34569 100644 --- a/lib/lib_div/LibTeleinfo/README.md +++ b/lib/lib_div/LibTeleinfo/README.md @@ -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 ... -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`.
@@ -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.
-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]. 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_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. - [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_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 -License -======= +# License + Cette oeuvre est mise à disposition selon les termes de la Licence Creative Commons Attribution - Pas d’Utilisation 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 ;-) -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] -[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 +[3]: https://www.enedis.fr/sites/default/files/Enedis-NOI-CPT_54E.pdf [6]: https://hallard.me/category/tinfo/ [7]: https://hallard.me [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 [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 -[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/ [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 + diff --git a/lib/lib_div/LibTeleinfo/library.json b/lib/lib_div/LibTeleinfo/library.json index ea6932a9b..84593d3a6 100644 --- a/lib/lib_div/LibTeleinfo/library.json +++ b/lib/lib_div/LibTeleinfo/library.json @@ -1,6 +1,6 @@ { "name": "LibTeleinfo", - "version": "1.1.3", + "version": "1.1.5", "keywords": "teleinfo, french, meter, power, erdf, linky, tic", "description": "Decoder for Teleinfo (aka TIC) from French smart power meters", "repository": diff --git a/lib/lib_div/LibTeleinfo/library.properties b/lib/lib_div/LibTeleinfo/library.properties index ad488ca08..562d96c62 100644 --- a/lib/lib_div/LibTeleinfo/library.properties +++ b/lib/lib_div/LibTeleinfo/library.properties @@ -1,5 +1,5 @@ name=LibTeleinfo -version=1.1.3 +version=1.1.5 author=Charles-Henri Hallard maintainer=Charles-Henri Hallard sentence=Decoder for Teleinfo (aka TIC) from French smart power meters diff --git a/lib/lib_div/LibTeleinfo/src/LibTeleinfo.cpp b/lib/lib_div/LibTeleinfo/src/LibTeleinfo.cpp index cdaa8aa9e..de9d3ef21 100644 --- a/lib/lib_div/LibTeleinfo/src/LibTeleinfo.cpp +++ b/lib/lib_div/LibTeleinfo/src/LibTeleinfo.cpp @@ -50,6 +50,8 @@ TInfo::TInfo() _fn_data = NULL; _fn_new_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 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 ; uint32_t ts = 0; + // Time stamped field? if (horodate && *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 ) { // Copy it 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 return (me); } else { @@ -279,19 +298,12 @@ ValueList * TInfo::valueAdd(char * name, char * value, uint8_t checksum, uint8_t // Our linked list structure sizeof(ValueList) // + Name + '\0' // + Value + '\0' - size_t size ; - #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 + size_t size = sizeof(ValueList) + lgname + 1 + lgvalue + 1 ; // Create new node with size to store strings - if ((newNode = (ValueList *) malloc(size) ) == NULL) + if ((newNode = (ValueList *) malloc(size) ) == NULL) { return ( (ValueList *) NULL ); + } // get our buffer Safe memset(newNode, 0, size); @@ -456,10 +468,13 @@ char * TInfo::valueGet(char * name, char * value) if (lgname==strlen(me->name) && strcmp(me->name, name)==0) { // this one has a value ? if (me->value) { - // copy to dest buffer - uint8_t lgvalue = strlen(me->value); - strlcpy(value, me->value , lgvalue + 1 ); - return ( value ); + // Check back checksum + if (me->checksum == calcChecksum(me->name, me->value)) { + // copy to dest buffer + uint8_t lgvalue = strlen(me->value); + strlcpy(value, me->value , lgvalue + 1 ); + return ( value ); + } } } } @@ -494,10 +509,13 @@ char * TInfo::valueGet_P(const char * name, char * value) if (lgname==strlen(me->name) && strcmp_P(me->name, name)==0) { // this one has a value ? if (me->value) { - // copy to dest buffer - uint8_t lgvalue = strlen(me->value); - strlcpy(value, me->value , lgvalue + 1 ); - return ( value ); + // Check back checksum + if (me->checksum == calcChecksum(me->name, me->value)) { + // copy to dest buffer + uint8_t lgvalue = strlen(me->value); + strlcpy(value, me->value , lgvalue + 1 ); + return ( value ); + } } } } @@ -529,6 +547,7 @@ uint8_t TInfo::valuesDump(void) // Get our linked list ValueList * me = &_valueslist; uint8_t index = 0; + uint8_t checksum=0; // Got one ? if (me) { @@ -541,7 +560,7 @@ uint8_t TInfo::valuesDump(void) TI_Debug(index) ; TI_Debug(F(") ")) ; - if (me->name) { + if (me->name ) { TI_Debug(me->name) ; } else { TI_Debug(F("NULL")) ; @@ -555,9 +574,17 @@ uint8_t TInfo::valuesDump(void) TI_Debug(F("NULL")) ; } + if (me->name && me->value && *me->name && *me->value) { + checksum = calcChecksum(me->name, me->value); + } + TI_Debug(F(" '")) ; TI_Debug(me->checksum) ; - TI_Debug(F("' ")); + if (me->checksum != checksum ) { + TI_Debug(F("'!Err ")); + } else { + TI_Debug(F("' ")); + } // Flags management if ( me->flags) { @@ -798,6 +825,7 @@ ValueList * TInfo::checkLine(char * pline) // 2 Label + Space + 1 etiquette + space + checksum + \r if ( len < 7 || len >= TINFO_BUFSIZE) { //AddLog(3, PSTR("LibTeleinfo: Error len < 7 || len >= TINFO_BUFSIZE")); + _framesizeerror++; return NULL; } @@ -904,9 +932,15 @@ ValueList * TInfo::checkLine(char * pline) } 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 @@ -948,7 +982,17 @@ _State_e TInfo::process(char c) _state = TINFO_WAIT_ETX; } 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 ? 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 ? if (_state == TINFO_READY) { // Store data recceived (we'll need it) - if ( _recv_idx < TINFO_BUFSIZE) + if ( _recv_idx < TINFO_BUFSIZE) { _recv_buff[_recv_idx++]=c; + } else { + // group is too big (some ETX missing) + _framesizeerror++; + } // clear the end of buffer (paranoia inside) memset(&_recv_buff[_recv_idx], 0, TINFO_BUFSIZE-_recv_idx); diff --git a/lib/lib_div/LibTeleinfo/src/LibTeleinfo.h b/lib/lib_div/LibTeleinfo/src/LibTeleinfo.h index 3c947b5ca..8ac4ad034 100644 --- a/lib/lib_div/LibTeleinfo/src/LibTeleinfo.h +++ b/lib/lib_div/LibTeleinfo/src/LibTeleinfo.h @@ -74,14 +74,6 @@ void AddLog(uint32_t loglevel, PGM_P formatP, ...); #define TI_Debugflush {} #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 typedef struct _ValueList ValueList; struct _ValueList @@ -94,8 +86,6 @@ struct _ValueList char * value; // value }; -#pragma pack(pop) - // Library state machine enum _Mode_e { TINFO_MODE_HISTORIQUE, // Legacy mode (1200) @@ -125,6 +115,7 @@ enum _State_e { // Teleinfo start and end of frame characters #define TINFO_STX 0x02 #define TINFO_ETX 0x03 +#define TINFO_EOT 0x04 // frame interrupt (End Of Transmission) #define TINFO_HT 0x09 #define TINFO_SGR '\n' // start of group #define TINFO_EGR '\r' // End of group @@ -151,7 +142,12 @@ class TInfo char * valueGet_P(const char * name, char * value); int labelCount(); boolean listDelete(); + void clearStats(); 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: void clearBuffer(); @@ -169,6 +165,13 @@ class TInfo char _separator; uint8_t _recv_idx; // index in receive buffer 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_data)(ValueList * valueslist, uint8_t state); void (*_fn_new_frame)(ValueList * valueslist);