mirror of https://github.com/arendst/Tasmota.git
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:
parent
0aaa616881
commit
1b5c4768d1
|
@ -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/>
|
||||
|
@ -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.
|
||||
<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
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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":
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue