Skip to content

Commit

Permalink
Libteleinfo update to V1.1.5 (#18050)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
hallard authored Feb 25, 2023
1 parent 0aaa616 commit 1b5c476
Show file tree
Hide file tree
Showing 5 changed files with 116 additions and 55 deletions.
46 changes: 28 additions & 18 deletions lib/lib_div/LibTeleinfo/README.md
Original file line number Diff line number Diff line change
@@ -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`.
<br/>
Expand All @@ -17,38 +15,45 @@ Pour trouver votre dossier de sketchbook, dans l'environnement IDE, allez dans F
allez voir ce [tutorial][2] sur les librairies Arduino si beoin.
<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].
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
- [Arduino_Softserial_JSON][4] Retourne les informations de téléinformation au format JSON sur la liaison série.
- [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
Expand All @@ -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


2 changes: 1 addition & 1 deletion lib/lib_div/LibTeleinfo/library.json
Original file line number Diff line number Diff line change
@@ -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":
Expand Down
2 changes: 1 addition & 1 deletion lib/lib_div/LibTeleinfo/library.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name=LibTeleinfo
version=1.1.3
version=1.1.5
author=Charles-Henri Hallard <hallard.me>
maintainer=Charles-Henri Hallard <community.hallard.me>
sentence=Decoder for Teleinfo (aka TIC) from French smart power meters
Expand Down
98 changes: 73 additions & 25 deletions lib/lib_div/LibTeleinfo/src/LibTeleinfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ TInfo::TInfo()
_fn_data = NULL;
_fn_new_frame = NULL;
_fn_updated_frame = NULL;

clearStats();
}

/* ======================================================================
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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 {
Expand All @@ -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);
Expand Down Expand Up @@ -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 );
}
}
}
}
Expand Down Expand Up @@ -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 );
}
}
}
}
Expand Down Expand Up @@ -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) {
Expand All @@ -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")) ;
Expand All @@ -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) {
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 >>>>>>>>>>>>>>>>>>"));
Expand Down Expand Up @@ -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);
Expand Down
23 changes: 13 additions & 10 deletions lib/lib_div/LibTeleinfo/src/LibTeleinfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -94,8 +86,6 @@ struct _ValueList
char * value; // value
};

#pragma pack(pop)

// Library state machine
enum _Mode_e {
TINFO_MODE_HISTORIQUE, // Legacy mode (1200)
Expand Down Expand Up @@ -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
Expand All @@ -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();
Expand All @@ -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);
Expand Down

0 comments on commit 1b5c476

Please sign in to comment.