From e05e9ea7139d753e0d7bfb884cb7ddbe17b30fe7 Mon Sep 17 00:00:00 2001 From: Charles Date: Thu, 11 Jun 2020 14:52:31 +0200 Subject: [PATCH 01/24] Creation --- lib/LibTeleinfo/README.md | 65 +++ lib/LibTeleinfo/library.json | 19 + lib/LibTeleinfo/library.properties | 9 + lib/LibTeleinfo/src/LibTeleinfo.cpp | 842 ++++++++++++++++++++++++++++ lib/LibTeleinfo/src/LibTeleinfo.h | 138 +++++ 5 files changed, 1073 insertions(+) create mode 100755 lib/LibTeleinfo/README.md create mode 100755 lib/LibTeleinfo/library.json create mode 100755 lib/LibTeleinfo/library.properties create mode 100644 lib/LibTeleinfo/src/LibTeleinfo.cpp create mode 100755 lib/LibTeleinfo/src/LibTeleinfo.h diff --git a/lib/LibTeleinfo/README.md b/lib/LibTeleinfo/README.md new file mode 100755 index 000000000..11a90ac2b --- /dev/null +++ b/lib/LibTeleinfo/README.md @@ -0,0 +1,65 @@ +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] + +Since this is really dedicated to French energy measuring system, I will continue in French + +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`. +
+Pour trouver votre dossier de sketchbook, dans l'environnement IDE, allez dans File>Preferences. +
+allez voir ce [tutorial][2] sur les librairies Arduino si beoin. +
+ +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 +================= + +- [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 :-) + +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 +======= +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 +====== +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 +[2]: http://learn.adafruit.com/arduino-tips-tricks-and-techniques/arduino-libraries +[6]: https://hallard.me/category/tinfo/ +[7]: https://hallard.me +[8]: https://community.hallard.me/category/7 +[9]: https://community.hallard.me +[10]: https://hallard.me/libteleinfo + +[3]: https://github.com/hallard/LibTeleinfo/blob/master/examples/Arduino_Softserial/Arduino_Softserial_Etiquette.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 +[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 +[13]: https://hallard.me/wifiinfo/ +[14]: https://github.com/hallard/LibTeleinfo/blob/master/examples/ESP32/ESP32.ino + diff --git a/lib/LibTeleinfo/library.json b/lib/LibTeleinfo/library.json new file mode 100755 index 000000000..068618ce0 --- /dev/null +++ b/lib/LibTeleinfo/library.json @@ -0,0 +1,19 @@ +{ + "name": "LibTeleinfo", + "version": "1.1.0", + "keywords": "teleinfo, french, meter, power, erdf, linky, tic", + "description": "Decoder for Teleinfo (aka TIC) from French smart power meters", + "repository": + { + "type": "git", + "url": "https://github.com/hallard/LibTeleinfo.git" + }, + "authors": + { + "name": "Charles-Henri Hallard", + "url": "http://hallard.me" + }, + "frameworks": "arduino", + "platforms": "*" +} + diff --git a/lib/LibTeleinfo/library.properties b/lib/LibTeleinfo/library.properties new file mode 100755 index 000000000..2420c5fc2 --- /dev/null +++ b/lib/LibTeleinfo/library.properties @@ -0,0 +1,9 @@ +name=LibTeleinfo +version=1.1.0 +author=Charles-Henri Hallard +maintainer=Charles-Henri Hallard +sentence=Decoder for Teleinfo (aka TIC) from French smart power meters +paragraph=This is a generic Teleinfo (aka TIC) French Meter Measure Library, it can be used on Arduino, Particle, ESP8266, Raspberry PI or anywhere you can do Cpp coding. +category=Communication +url=https://github.com/hallard/LibTeleinfo +architectures=* \ No newline at end of file diff --git a/lib/LibTeleinfo/src/LibTeleinfo.cpp b/lib/LibTeleinfo/src/LibTeleinfo.cpp new file mode 100644 index 000000000..b2d597f28 --- /dev/null +++ b/lib/LibTeleinfo/src/LibTeleinfo.cpp @@ -0,0 +1,842 @@ +// ********************************************************************************** +// Driver definition for French Teleinfo +// ********************************************************************************** +// 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 any explanation about teleinfo ou use , see my blog +// http://hallard.me/category/tinfo +// +// Code based on following datasheet +// http://www.erdf.fr/sites/default/files/ERDF-NOI-CPT_02E.pdf +// +// Written by Charles-Henri Hallard (http://hallard.me) +// +// History : V1.00 2015-06-14 - First release +// V2.00 2020-06-11 - Integration into Tasmota +// +// All text above must be included in any redistribution. +// +// Edit : Tab size set to 2 but I converted tab to sapces +// +// ********************************************************************************** + +#include "LibTeleinfo.h" + +/* ====================================================================== +Class : TInfo +Purpose : Constructor +Input : - +Output : - +Comments: - +====================================================================== */ +TInfo::TInfo() +{ + // Init of our linked list + _valueslist.name = NULL; + _valueslist.value = NULL; + _valueslist.checksum = '\0'; + _valueslist.flags = TINFO_FLAGS_NONE; + + // callback + _fn_ADPS = NULL; + _fn_data = NULL; + _fn_new_frame = NULL; + _fn_updated_frame = NULL; +} + +/* ====================================================================== +Function: init +Purpose : try to guess +Input : - +Output : - +Comments: - +====================================================================== */ +void TInfo::init() +{ + // free up linked list (in case on recall init()) + listDelete(); + + // clear our receive buffer + clearBuffer(); + + // We're in INIT in term of receive data + _state = TINFO_INIT; +} + +/* ====================================================================== +Function: attachADPS +Purpose : attach a callback when we detected a ADPS on any phase +Input : callback function +Output : - +Comments: - +====================================================================== */ +void TInfo::attachADPS(void (*fn_ADPS)(uint8_t phase)) +{ + // indicate the user callback + _fn_ADPS = fn_ADPS; +} + +/* ====================================================================== +Function: attachNewData +Purpose : attach a callback when we detected a new/changed value +Input : callback function +Output : - +Comments: - +====================================================================== */ +void TInfo::attachData(void (*fn_data)(ValueList * valueslist, uint8_t state)) +{ + // indicate the user callback + _fn_data = fn_data; +} + +/* ====================================================================== +Function: attachNewFrame +Purpose : attach a callback when we received a full frame +Input : callback function +Output : - +Comments: - +====================================================================== */ +void TInfo::attachNewFrame(void (*fn_new_frame)(ValueList * valueslist)) +{ + // indicate the user callback + _fn_new_frame = fn_new_frame; +} + +/* ====================================================================== +Function: attachChangedFrame +Purpose : attach a callback when we received a full frame where data + has changed since the last frame (cool to update data) +Input : callback function +Output : - +Comments: - +====================================================================== */ +void TInfo::attachUpdatedFrame(void (*fn_updated_frame)(ValueList * valueslist)) +{ + // indicate the user callback + _fn_updated_frame = fn_updated_frame; +} + +/* ====================================================================== +Function: clearBuffer +Purpose : clear and init the buffer +Input : - +Output : - +Comments: - +====================================================================== */ +void TInfo::clearBuffer() +{ + // Clear our buffer, set index to 0 + memset(_recv_buff, 0, TINFO_BUFSIZE); + _recv_idx = 0; +} + + +/* ====================================================================== +Function: addCustomValue +Purpose : let user add custom values (mainly for testing) +Input : Pointer to the label name + pointer to the value + pointer on flag state of the label +Output : pointer to the new node (or founded one) +Comments: checksum is calculated before adding, no need to bother with +====================================================================== */ +ValueList * TInfo::addCustomValue(char * name, char * value, uint8_t * flags) +{ + // Little check + if (name && *name && value && *value) { + ValueList * me; + + // Same as if we really received this line + customLabel(name, value, flags); + me = valueAdd(name, value, calcChecksum(name,value), flags); + + if ( me ) { + // something to do with new datas + if (*flags & (TINFO_FLAGS_UPDATED | TINFO_FLAGS_ADDED | TINFO_FLAGS_ALERT) ) { + // this frame will for sure be updated + _frame_updated = true; + } + return (me); + } + } + + // Error or Already Exists + return ( (ValueList *) NULL); +} + +/* ====================================================================== +Function: valueAdd +Purpose : Add element to the Linked List of values +Input : Pointer to the label name + pointer to the value + checksum value + flag state of the label (modified by function) +Output : pointer to the new node (or founded one) +Comments: - state of the label changed by the function +====================================================================== */ +ValueList * TInfo::valueAdd(char * name, char * value, uint8_t checksum, uint8_t * flags) +{ + // Get our linked list + ValueList * me = &_valueslist; + + uint8_t lgname = strlen(name); + uint8_t lgvalue = strlen(value); + uint8_t thischeck = calcChecksum(name,value); + + // just some paranoia + if (thischeck != checksum ) { + TI_Debug(name); + TI_Debug('='); + TI_Debug(value); + TI_Debug(F(" '")); + TI_Debug((char) checksum); + TI_Debug(F("' Not added bad checksum calculated '")); + TI_Debug((char) thischeck); + TI_Debugln(F("'")); + } else { + // Got one and all seems good ? + if (me && lgname && lgvalue && checksum) { + // Create pointer on the new node + ValueList *newNode = NULL; + ValueList *parNode = NULL ; + + // Loop thru the node + while (me->next) { + // save parent node + parNode = me ; + + // go to next node + me = me->next; + + // Check if we already have this LABEL (same name AND same size) + if (lgname==strlen(me->name) && strncmp(me->name, name, lgname)==0) { + // Already got also this value return US + if (lgvalue==strlen(me->value) && strncmp(me->value, value, lgvalue) == 0) { + *flags |= TINFO_FLAGS_EXIST; + me->flags = *flags; + return ( me ); + } else { + // We changed the value + *flags |= TINFO_FLAGS_UPDATED; + me->flags = *flags ; + // Do we have enought space to hold new value ? + if (strlen(me->value) >= lgvalue ) { + // Copy it + strlcpy(me->value, value , lgvalue ); + me->checksum = checksum ; + + // That's all + return (me); + } else { + // indicate our parent node that the next node + // is not us anymore but the next we have + parNode->next = me->next; + + // free up this node + free (me); + + // Return to parent (that will now point on next node and not us) + // and continue loop just in case we have sevral with same name + me = parNode; + } + } + } + } + + // 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 + + // Create new node with size to store strings + if ((newNode = (ValueList *) malloc(size) ) == NULL) + return ( (ValueList *) NULL ); + + // get our buffer Safe + memset(newNode, 0, size); + + // Put the new node on the list + me->next = newNode; + + // First String located after last struct element + // Second String located after the First + \0 + newNode->checksum = checksum; + newNode->name = (char *) newNode + sizeof(ValueList); + newNode->value = (char *) newNode->name + lgname + 1; + + // Copy the string data + memcpy(newNode->name , name , lgname ); + memcpy(newNode->value, value , lgvalue ); + + // So we just created this node but was it new + // or was matter of text size ? + if ( (*flags & TINFO_FLAGS_UPDATED) == 0) { + // so we added this node ! + *flags |= TINFO_FLAGS_ADDED ; + newNode->flags = *flags; + } + + TI_Debug(F("Added '")); + TI_Debug(name); + TI_Debug('='); + TI_Debug(value); + TI_Debug(F("' '")); + TI_Debug((char) checksum); + TI_Debugln(F("'")); + + // return pointer on the new node + return (newNode); + } + + } // Checksum OK + + + // Error or Already Exists + return ( (ValueList *) NULL); +} + +/* ====================================================================== +Function: valueRemoveFlagged +Purpose : remove element to the Linked List of values where +Input : paramter flags +Output : true if found and removed +Comments: - +====================================================================== */ +boolean TInfo::valueRemoveFlagged(uint8_t flags) +{ + boolean deleted = false; + + // Get our linked list + ValueList * me = &_valueslist; + ValueList *parNode = NULL ; + + // Got one and all seems good ? + if (me) { + // Loop thru the node + while (me->next) { + // save parent node + parNode = me ; + + // go to next node + me = me->next; + + // found the flags? + if (me->flags & flags ) { + // indicate our parent node that the next node + // is not us anymore but the next we have + parNode->next = me->next; + + // free up this node + free (me); + + // Return to parent (that will now point on next node and not us) + // and continue loop just in case we have sevral with same name + me = parNode; + deleted = true; + } + } + } + + return (deleted); +} + +/* ====================================================================== +Function: valueRemove +Purpose : remove element to the Linked List of values +Input : Pointer to the label name +Output : true if found and removed +Comments: - +====================================================================== */ +boolean TInfo::valueRemove(char * name) +{ + boolean deleted = false; + + // Get our linked list + ValueList * me = &_valueslist; + ValueList *parNode = NULL ; + + uint8_t lgname = strlen(name); + + // Got one and all seems good ? + if (me && lgname) { + // Loop thru the node + while (me->next) { + // save parent node + parNode = me ; + + // go to next node + me = me->next; + + // found ? + if (strncmp(me->name, name, lgname) == 0) { + // indicate our parent node that the next node + // is not us anymore but the next we have + parNode->next = me->next; + + // free up this node + free (me); + + // Return to parent (that will now point on next node and not us) + // and continue loop just in case we have sevral with same name + me = parNode; + deleted = true; + } + } + } + + return (deleted); +} + +/* ====================================================================== +Function: valueGet +Purpose : get value of one element +Input : Pointer to the label name + pointer to the value where we fill data +Output : pointer to the value where we filled data NULL is not found +====================================================================== */ +char * TInfo::valueGet(char * name, char * value) +{ + // Get our linked list + ValueList * me = &_valueslist; + uint8_t lgname = strlen(name); + + // Got one and all seems good ? + if (me && lgname) { + + // Loop thru the node + while (me->next) { + + // go to next node + me = me->next; + + // Check if we match this LABEL + if (lgname==strlen(me->name) && strncmp(me->name, name, lgname)==0) { + // this one has a value ? + if (me->value) { + // copy to dest buffer + uint8_t lgvalue = strlen(me->value); + strlcpy(value, me->value , lgvalue ); + return ( value ); + } + } + } + } + // not found + return ( NULL); +} + +/* ====================================================================== +Function: getTopList +Purpose : return a pointer on the top of the linked list +Input : - +Output : Pointer +====================================================================== */ +ValueList * TInfo::getList(void) +{ + // Get our linked list + return &_valueslist; +} + +/* ====================================================================== +Function: valuesDump +Purpose : dump linked list content +Input : - +Output : total number of values +====================================================================== */ +uint8_t TInfo::valuesDump(void) +{ + // Get our linked list + ValueList * me = &_valueslist; + uint8_t index = 0; + + // Got one ? + if (me) { + // Loop thru the node + while (me->next) { + // go to next node + me = me->next; + + index++; + TI_Debug(index) ; + TI_Debug(F(") ")) ; + + if (me->name) { + TI_Debug(me->name) ; + } else { + TI_Debug(F("NULL")) ; + } + + TI_Debug(F("=")) ; + + if (me->value) { + TI_Debug(me->value) ; + } else { + TI_Debug(F("NULL")) ; + } + + TI_Debug(F(" '")) ; + TI_Debug(me->checksum) ; + TI_Debug(F("' ")); + + // Flags management + if ( me->flags) { + TI_Debug(F("Flags:0x")); + TI_Debugf("%02X =>", me->flags); + if ( me->flags & TINFO_FLAGS_EXIST) { + TI_Debug(F("Exist ")) ; + } + if ( me->flags & TINFO_FLAGS_UPDATED) { + TI_Debug(F("Updated ")) ; + } + if ( me->flags & TINFO_FLAGS_ADDED) { + TI_Debug(F("New ")) ; + } + } + + TI_Debugln() ; + } + } + + return index; +} + +/* ====================================================================== +Function: labelCount +Purpose : Count the number of label in the list +Input : - +Output : element numbers +====================================================================== */ +int TInfo::labelCount() +{ + int count = 0; + + // Get our linked list + ValueList * me = &_valueslist; + + if (me) + while ((me = me->next)) + count++; + + return (count); +} + +/* ====================================================================== +Function: listDelete +Purpose : Delete the ENTIRE Linked List, not a value +Input : - +Output : True if Ok False Otherwise +====================================================================== */ +boolean TInfo::listDelete() +{ + // Get our linked list + ValueList * me = &_valueslist; + + // Got a pointer + if (me) { + ValueList *current; + + // For each linked list + while ((current = me->next)) { + // Get the next + me->next = current->next; + + // Free the current + free(current); + } + + // Free the top element + me->next = NULL ; + + // Ok + return (true); + } + + return (false); +} + +/* ====================================================================== +Function: checksum +Purpose : calculate the checksum based on data/value fields +Input : label name + label value +Output : checksum +Comments: return '\0' in case of error +====================================================================== */ +unsigned char TInfo::calcChecksum(char *etiquette, char *valeur) +{ + uint8_t sum = ' '; // Somme des codes ASCII du message + un espace + + // avoid dead loop, always check all is fine + if (etiquette && valeur) { + // this will not hurt and may save our life ;-) + if (strlen(etiquette) && strlen(valeur)) { + while (*etiquette) + sum += *etiquette++ ; + + while(*valeur) + sum += *valeur++ ; + + return ( (sum & 63) + ' ' ) ; + } + } + return 0; +} + +/* ====================================================================== +Function: customLabel +Purpose : do action when received a correct label / value + checksum line +Input : plabel : pointer to string containing the label + pvalue : pointer to string containing the associated value + pflags pointer in flags value if we need to cchange it +Output : +Comments: +====================================================================== */ +void TInfo::customLabel( char * plabel, char * pvalue, uint8_t * pflags) +{ + int8_t phase = -1; + + // Monophasé + if (strcmp(plabel, "ADPS")==0 ) + phase=0; + + // For testing + //if (strcmp(plabel, "IINST")==0 ) { + // *pflags |= TINFO_FLAGS_ALERT; + //} + + // triphasé c'est ADIR + Num Phase + if (plabel[0]=='A' && plabel[1]=='D' && plabel[2]=='I' && plabel[3]=='R' && plabel[4]>='1' && plabel[4]<='3') { + phase = plabel[4]-'0'; + } + + // Nous avons un ADPS ? + if (phase>=0 && phase <=3) { + // ne doit pas être sauvé définitivement + *pflags |= TINFO_FLAGS_ALERT; + + // Traitement de l'ADPS demandé par le sketch + if (_fn_ADPS) + _fn_ADPS(phase); + } +} + +/* ====================================================================== +Function: checkLine +Purpose : check one line of teleinfo received +Input : - +Output : pointer to the data object in the linked list if OK else NULL +Comments: +====================================================================== */ +ValueList * TInfo::checkLine(char * pline) +{ + char * p; + char * ptok; + char * pend; + char * pvalue; + char checksum; + char buff[TINFO_BUFSIZE]; + uint8_t flags = TINFO_FLAGS_NONE; + //boolean err = true ; // Assume error + int len ; // Group len + + if (pline==NULL) + return NULL; + + len = strlen(pline); + + // a line should be at least 7 Char + // 2 Label + Space + 1 etiquette + space + checksum + \r + if ( len < 7 ) + return NULL; + + // Get our own working copy + strlcpy( buff, _recv_buff, len+1); + + p = &buff[0]; + ptok = p; // for sure we start with token name + pend = p + len; // max size + + // Init values + pvalue = NULL; + checksum = 0; + + //TI_Debug("Got ["); + //TI_Debug(len); + //TI_Debug("] "); + + + // Loop in buffer + while ( p < pend ) { + // start of token value + if ( *p==' ' && ptok) { + // Isolate token name + *p++ = '\0'; + + // 1st space, it's the label value + if (!pvalue) + pvalue = p; + else + // 2nd space, so it's the checksum + checksum = *p; + } + // new line ? ok we got all we need ? + + if ( *p=='\r' ) { + *p='\0'; + + // Good format ? + if ( ptok && pvalue && checksum ) { + // Always check to avoid bad behavior + if(strlen(ptok) && strlen(pvalue)) { + // Is checksum is OK + if ( calcChecksum(ptok,pvalue) == checksum) { + // In case we need to do things on specific labels + customLabel(ptok, pvalue, &flags); + + // Add value to linked lists of values + ValueList * me = valueAdd(ptok, pvalue, checksum, &flags); + + // value correctly added/changed + if ( me ) { + // something to do with new datas + if (flags & (TINFO_FLAGS_UPDATED | TINFO_FLAGS_ADDED | TINFO_FLAGS_ALERT) ) { + // this frame will for sure be updated + _frame_updated = true; + + // Do we need to advertise user callback + if (_fn_data) + _fn_data(me, flags); + } + } + } + } + } + } + // Next char + p++; + + } // While + + return NULL; +} + +/* ====================================================================== +Function: process +Purpose : teleinfo serial char received processing, should be called + my main loop, this will take care of managing all the other +Input : pointer to the serial used +Output : teleinfo global state +====================================================================== */ +_State_e TInfo::process(char c) +{ + // be sure 7 bits only + c &= 0x7F; + + // What we received ? + switch (c) { + // start of transmission ??? + case TINFO_STX: + // Clear buffer, begin to store in it + clearBuffer(); + + // by default frame is not "updated" + // if data change we'll set this flag + _frame_updated = false; + + // We were waiting fo this one ? + if (_state == TINFO_INIT || _state == TINFO_WAIT_STX ) { + TI_Debugln(F("TINFO_WAIT_ETX")); + _state = TINFO_WAIT_ETX; + } + break; + + // End of transmission ? + case TINFO_ETX: + + // Normal working mode ? + if (_state == TINFO_READY) { + // Get on top of our linked list + ValueList * me = &_valueslist; + + // Call user callback if any + if (_frame_updated && _fn_updated_frame) + _fn_updated_frame(me); + else if (_fn_new_frame) + _fn_new_frame(me); + + #ifdef TI_Debug + valuesDump(); + #endif + + // It's important there since all user job is done + // to remove the alert flags from table (ADPS for example) + // it will be put back again next time if any + valueRemoveFlagged(TINFO_FLAGS_ALERT); + } + + // We were waiting fo this one ? + if (_state == TINFO_WAIT_ETX) { + TI_Debugln(F("TINFO_READY")); + _state = TINFO_READY; + } + else if ( _state == TINFO_INIT) { + TI_Debugln(F("TINFO_WAIT_STX")); + _state = TINFO_WAIT_STX ; + } + + break; + + // Start of group \n ? + case TINFO_SGR: + // Do nothing we'll work at end of group + // we can safely ignore this char + break; + + // End of group \r ? + case TINFO_EGR: + // Are we ready to process ? + if (_state == TINFO_READY) { + // Store data recceived (we'll need it) + if ( _recv_idx < TINFO_BUFSIZE) + _recv_buff[_recv_idx++]=c; + + // clear the end of buffer (paranoia inside) + memset(&_recv_buff[_recv_idx], 0, TINFO_BUFSIZE-_recv_idx); + + // check the group we've just received + checkLine(_recv_buff) ; + + // Whatever error or not, we done + clearBuffer(); + } + break; + + // other char ? + default: + { + // Only in a ready state of course + if (_state == TINFO_READY) { + // If buffer is not full, Store data + if ( _recv_idx < TINFO_BUFSIZE) + _recv_buff[_recv_idx++]=c; + else + clearBuffer(); + } + } + break; + } + + return _state; +} + + diff --git a/lib/LibTeleinfo/src/LibTeleinfo.h b/lib/LibTeleinfo/src/LibTeleinfo.h new file mode 100755 index 000000000..00b5495c4 --- /dev/null +++ b/lib/LibTeleinfo/src/LibTeleinfo.h @@ -0,0 +1,138 @@ +// ********************************************************************************** +// Driver definition for French Teleinfo +// ********************************************************************************** +// 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 any explanation about teleinfo ou use , see my blog +// http://hallard.me/category/tinfo +// +// Code based on following datasheet +// http://www.erdf.fr/sites/default/files/ERDF-NOI-CPT_02E.pdf +// +// Written by Charles-Henri Hallard (http://hallard.me) +// +// History : V1.00 2015-06-14 - First release +// V2.00 2020-06-11 - Integration into Tasmota +// +// All text above must be included in any redistribution. +// +// Edit : Tab size set to 2 but I converted tab to sapces +// +// ********************************************************************************** + +#ifndef LibTeleinfo_h +#define LibTeleinfo_h + +// Define this if you want library to be verbose +//#define TI_DEBUG + +// I prefix debug macro to be sure to use specific for THIS library +// debugging, this should not interfere with main sketch or other +// libraries +#ifdef TI_DEBUG + #ifdef ESP8266 + #define TI_Debug(x) Serial1.print(x) + #define TI_Debugln(x) Serial1.println(x) + #define TI_Debugf(...) Serial1.printf(__VA_ARGS__) + #define TI_Debugflush Serial1.flush + #else + #define TI_Debug(x) Serial.print(x) + #define TI_Debugln(x) Serial.println(x) + #define TI_Debugf(...) Serial.printf(__VA_ARGS__) + #define TI_Debugflush Serial.flush + #endif +#else + #define TI_Debug(x) + #define TI_Debugln(x) + #define TI_Debugf(...) + #define TI_Debugflush +#endif + +// For 4 bytes Aligment boundaries +#define ESP_allocAlign(size) ((size + 3) & ~((size_t) 3)) + +#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 +{ + ValueList *next; // next element + char * name; // LABEL of value name + char * value; // value + uint8_t checksum;// checksum + uint8_t flags; // specific flags +}; + +#pragma pack(pop) + +// Library state machine +enum _State_e { + TINFO_INIT, // We're in init + TINFO_WAIT_STX, // We're waiting for STX + TINFO_WAIT_ETX, // We had STX, We're waiting for ETX + TINFO_READY // We had STX AND ETX, So we're OK +}; + +// what we done with received value (also for callback flags) +#define TINFO_FLAGS_NONE 0x00 +#define TINFO_FLAGS_NOTHING 0x01 +#define TINFO_FLAGS_ADDED 0x02 +#define TINFO_FLAGS_EXIST 0x04 +#define TINFO_FLAGS_UPDATED 0x08 +#define TINFO_FLAGS_ALERT 0x80 /* This will generate an alert */ + +// Local buffer for one line of teleinfo +// maximum size, I think it should be enought +#define TINFO_BUFSIZE 64 + +// Teleinfo start and end of frame characters +#define TINFO_STX 0x02 +#define TINFO_ETX 0x03 +#define TINFO_SGR '\n' // start of group +#define TINFO_EGR '\r' // End of group + +class TInfo +{ + public: + TInfo(); + void init(); + _State_e process (char c); + void attachADPS(void (*_fn_ADPS)(uint8_t phase)); + void attachData(void (*_fn_data)(ValueList * valueslist, uint8_t state)); + void attachNewFrame(void (*_fn_new_frame)(ValueList * valueslist)); + void attachUpdatedFrame(void (*_fn_updated_frame)(ValueList * valueslist)); + ValueList * addCustomValue(char * name, char * value, uint8_t * flags); + ValueList * getList(void); + uint8_t valuesDump(void); + char * valueGet(char * name, char * value); + boolean listDelete(); + unsigned char calcChecksum(char *etiquette, char *valeur) ; + + private: + void clearBuffer(); + ValueList * valueAdd (char * name, char * value, uint8_t checksum, uint8_t * flags); + boolean valueRemove (char * name); + boolean valueRemoveFlagged(uint8_t flags); + int labelCount(); + void customLabel( char * plabel, char * pvalue, uint8_t * pflags) ; + ValueList * checkLine(char * pline) ; + + _State_e _state; // Teleinfo machine state + ValueList _valueslist; // Linked list of teleinfo values + char _recv_buff[TINFO_BUFSIZE]; // line receive buffer + uint8_t _recv_idx; // index in receive buffer + boolean _frame_updated; // Data on the frame has been updated + void (*_fn_ADPS)(uint8_t phase); + void (*_fn_data)(ValueList * valueslist, uint8_t state); + void (*_fn_new_frame)(ValueList * valueslist); + void (*_fn_updated_frame)(ValueList * valueslist); + + //volatile uint8_t *dcport; + //uint8_t dcpinmask; +}; + +#endif From ac65758cc385b42cca84abf6cf42f7528a43e00c Mon Sep 17 00:00:00 2001 From: Charles Date: Thu, 11 Jun 2020 14:53:10 +0200 Subject: [PATCH 02/24] Added support of TELEINFO --- tasmota/tasmota_configurations.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tasmota/tasmota_configurations.h b/tasmota/tasmota_configurations.h index 811076d8f..2af371976 100644 --- a/tasmota/tasmota_configurations.h +++ b/tasmota/tasmota_configurations.h @@ -167,6 +167,7 @@ #define USE_DDSU666 // Add support for Chint DDSU666 Modbus energy monitor (+0k6 code) //#define USE_SOLAX_X1 // Add support for Solax X1 series Modbus log info (+3k1 code) //#define USE_LE01MR // Add support for F&F LE-01MR modbus energy meter (+2k code) +//#define USE_TELEINFO // Add support for French Energy Provider metering telemetry #define USE_DHT // Add support for DHT11, AM2301 (DHT21, DHT22, AM2302, AM2321) and SI7021 Temperature and Humidity sensor #define USE_MAX31855 // Add support for MAX31855 K-Type thermocouple sensor using softSPI @@ -263,6 +264,8 @@ #undef USE_DDSU666 // Disable support for Chint DDSU666 Modbus energy monitor (+0k6 code) #undef USE_SOLAX_X1 // Disable support for Solax X1 series Modbus log info (+3k1 code) #undef USE_LE01MR // Disable support for F&F LE-01MR Modbus energy meter (+2k code) + #undef USE_TELEINFO // Disable support for French Energy Provider metering telemetry + #define USE_I2C // I2C using library wire (+10k code, 0k2 mem, 124 iram) #define USE_DISPLAY // Add I2C Display Support (+2k code) @@ -353,6 +356,7 @@ #undef USE_DDSU666 // Disable support for Chint DDSU666 Modbus energy monitor (+0k6 code) #undef USE_SOLAX_X1 // Disable support for Solax X1 series Modbus log info (+3k1 code) #undef USE_LE01MR // Disable support for F&F LE-01MR Modbus energy meter (+2k code) + #undef USE_TELEINFO // Disable support for French Energy Provider metering telemetry //#undef USE_DS18x20 // Disable support for DS18x20 sensors with id sort, single scan and read retry (+1k3 code) @@ -496,6 +500,8 @@ #undef USE_DDSU666 // Disable support for Chint DDSU666 Modbus energy monitor (+0k6 code) #undef USE_SOLAX_X1 // Disable support for Solax X1 series Modbus log info (+3k1 code) #undef USE_LE01MR // Disable support for F&F LE-01MR Modbus energy meter (+2k code) +#undef USE_TELEINFO // Disable support for French Energy Provider metering telemetry + #undef USE_DHT // Disable support for DHT11, AM2301 (DHT21, DHT22, AM2302, AM2321) and SI7021 Temperature and Humidity sensor #undef USE_MAX31855 // Disable MAX31855 K-Type thermocouple sensor using softSPI @@ -621,6 +627,7 @@ #undef USE_DDSU666 // Disable support for Chint DDSU666 Modbus energy monitor (+0k6 code) #undef USE_SOLAX_X1 // Disable support for Solax X1 series Modbus log info (+3k1 code) #undef USE_LE01MR // Disable support for F&F LE-01MR Modbus energy meter (+2k code) +#undef USE_TELEINFO // Disable support for French Energy Provider metering telemetry #undef USE_DHT // Disable support for DHT11, AM2301 (DHT21, DHT22, AM2302, AM2321) and SI7021 Temperature and Humidity sensor #undef USE_MAX31855 // Disable MAX31855 K-Type thermocouple sensor using softSPI From 4afbbca7732b0a6d627cb9e3de3c00391798186e Mon Sep 17 00:00:00 2001 From: Charles Date: Fri, 12 Jun 2020 16:28:57 +0200 Subject: [PATCH 03/24] Added French Smart Meter Teleinformation --- tasmota/language/bg_BG.h | 2 ++ tasmota/language/cs_CZ.h | 2 ++ tasmota/language/de_DE.h | 2 ++ tasmota/language/el_GR.h | 2 ++ tasmota/language/en_GB.h | 2 ++ tasmota/language/es_ES.h | 2 ++ tasmota/language/fr_FR.h | 2 ++ tasmota/language/he_HE.h | 2 ++ tasmota/language/hu_HU.h | 2 ++ tasmota/language/it_IT.h | 2 ++ tasmota/language/ko_KO.h | 2 ++ tasmota/language/nl_NL.h | 2 ++ tasmota/language/pl_PL.h | 2 ++ tasmota/language/pt_BR.h | 2 ++ tasmota/language/pt_PT.h | 2 ++ tasmota/language/ro_RO.h | 2 ++ tasmota/language/ru_RU.h | 2 ++ tasmota/language/sk_SK.h | 2 ++ tasmota/language/sv_SE.h | 2 ++ tasmota/language/tr_TR.h | 2 ++ tasmota/language/uk_UA.h | 2 ++ tasmota/language/zh_CN.h | 2 ++ tasmota/language/zh_TW.h | 2 ++ 23 files changed, 46 insertions(+) diff --git a/tasmota/language/bg_BG.h b/tasmota/language/bg_BG.h index 935704e74..769b9f66a 100644 --- a/tasmota/language/bg_BG.h +++ b/tasmota/language/bg_BG.h @@ -679,6 +679,8 @@ #define D_SENSOR_ELECTRIQ_MOODL "MOODL Tx" #define D_SENSOR_AS3935 "AS3935" #define D_SENSOR_WINDMETER_SPEED "WindMeter Spd" +#define D_SENSOR_TELEINFO_RX "TInfo Rx" +#define D_SENSOR_TELEINFO_ENABLE "TInfo EN" #define D_GPIO_WEBCAM_PWDN "CAM_PWDN" #define D_GPIO_WEBCAM_RESET "CAM_RESET" #define D_GPIO_WEBCAM_XCLK "CAM_XCLK" diff --git a/tasmota/language/cs_CZ.h b/tasmota/language/cs_CZ.h index a04a6b16b..64d8e32b0 100644 --- a/tasmota/language/cs_CZ.h +++ b/tasmota/language/cs_CZ.h @@ -679,6 +679,8 @@ #define D_SENSOR_ELECTRIQ_MOODL "MOODL Tx" #define D_SENSOR_AS3935 "AS3935" #define D_SENSOR_WINDMETER_SPEED "WindMeter Spd" +#define D_SENSOR_TELEINFO_RX "TInfo Rx" +#define D_SENSOR_TELEINFO_ENABLE "TInfo EN" #define D_GPIO_WEBCAM_PWDN "CAM_PWDN" #define D_GPIO_WEBCAM_RESET "CAM_RESET" #define D_GPIO_WEBCAM_XCLK "CAM_XCLK" diff --git a/tasmota/language/de_DE.h b/tasmota/language/de_DE.h index 02464daa6..7cc9d6579 100644 --- a/tasmota/language/de_DE.h +++ b/tasmota/language/de_DE.h @@ -679,6 +679,8 @@ #define D_SENSOR_ELECTRIQ_MOODL "MOODL Tx" #define D_SENSOR_AS3935 "AS3935" #define D_SENSOR_WINDMETER_SPEED "WindMeter Spd" +#define D_SENSOR_TELEINFO_RX "TInfo Rx" +#define D_SENSOR_TELEINFO_ENABLE "TInfo EN" #define D_GPIO_WEBCAM_PWDN "CAM_PWDN" #define D_GPIO_WEBCAM_RESET "CAM_RESET" #define D_GPIO_WEBCAM_XCLK "CAM_XCLK" diff --git a/tasmota/language/el_GR.h b/tasmota/language/el_GR.h index 333458c72..92769256f 100644 --- a/tasmota/language/el_GR.h +++ b/tasmota/language/el_GR.h @@ -679,6 +679,8 @@ #define D_SENSOR_ELECTRIQ_MOODL "MOODL Tx" #define D_SENSOR_AS3935 "AS3935" #define D_SENSOR_WINDMETER_SPEED "WindMeter Spd" +#define D_SENSOR_TELEINFO_RX "TInfo Rx" +#define D_SENSOR_TELEINFO_ENABLE "TInfo EN" #define D_GPIO_WEBCAM_PWDN "CAM_PWDN" #define D_GPIO_WEBCAM_RESET "CAM_RESET" #define D_GPIO_WEBCAM_XCLK "CAM_XCLK" diff --git a/tasmota/language/en_GB.h b/tasmota/language/en_GB.h index 92637b350..e5fc07fa5 100644 --- a/tasmota/language/en_GB.h +++ b/tasmota/language/en_GB.h @@ -679,6 +679,8 @@ #define D_SENSOR_ELECTRIQ_MOODL "MOODL Tx" #define D_SENSOR_AS3935 "AS3935" #define D_SENSOR_WINDMETER_SPEED "WindMeter Spd" +#define D_SENSOR_TELEINFO_RX "TInfo Rx" +#define D_SENSOR_TELEINFO_ENABLE "TInfo EN" #define D_GPIO_WEBCAM_PWDN "CAM_PWDN" #define D_GPIO_WEBCAM_RESET "CAM_RESET" #define D_GPIO_WEBCAM_XCLK "CAM_XCLK" diff --git a/tasmota/language/es_ES.h b/tasmota/language/es_ES.h index 701f3e107..ff2eda915 100644 --- a/tasmota/language/es_ES.h +++ b/tasmota/language/es_ES.h @@ -679,6 +679,8 @@ #define D_SENSOR_ELECTRIQ_MOODL "MOODL Tx" #define D_SENSOR_AS3935 "AS3935" #define D_SENSOR_WINDMETER_SPEED "WindMeter Spd" +#define D_SENSOR_TELEINFO_RX "TInfo Rx" +#define D_SENSOR_TELEINFO_ENABLE "TInfo EN" #define D_GPIO_WEBCAM_PWDN "CAM_PWDN" #define D_GPIO_WEBCAM_RESET "CAM_RESET" #define D_GPIO_WEBCAM_XCLK "CAM_XCLK" diff --git a/tasmota/language/fr_FR.h b/tasmota/language/fr_FR.h index f91bd7fbd..38c160831 100644 --- a/tasmota/language/fr_FR.h +++ b/tasmota/language/fr_FR.h @@ -679,6 +679,8 @@ #define D_SENSOR_ELECTRIQ_MOODL "MOODL Tx" #define D_SENSOR_AS3935 "AS3935" #define D_SENSOR_WINDMETER_SPEED "WindMeter Spd" +#define D_SENSOR_TELEINFO_RX "TInfo Rx" +#define D_SENSOR_TELEINFO_ENABLE "TInfo EN" #define D_GPIO_WEBCAM_PWDN "CAM_PWDN" #define D_GPIO_WEBCAM_RESET "CAM_RESET" #define D_GPIO_WEBCAM_XCLK "CAM_XCLK" diff --git a/tasmota/language/he_HE.h b/tasmota/language/he_HE.h index 3550a1abd..59f2db4cb 100644 --- a/tasmota/language/he_HE.h +++ b/tasmota/language/he_HE.h @@ -679,6 +679,8 @@ #define D_SENSOR_ELECTRIQ_MOODL "MOODL Tx" #define D_SENSOR_AS3935 "AS3935" #define D_SENSOR_WINDMETER_SPEED "WindMeter Spd" +#define D_SENSOR_TELEINFO_RX "TInfo Rx" +#define D_SENSOR_TELEINFO_ENABLE "TInfo EN" #define D_GPIO_WEBCAM_PWDN "CAM_PWDN" #define D_GPIO_WEBCAM_RESET "CAM_RESET" #define D_GPIO_WEBCAM_XCLK "CAM_XCLK" diff --git a/tasmota/language/hu_HU.h b/tasmota/language/hu_HU.h index 1a58472e4..d976eecb4 100644 --- a/tasmota/language/hu_HU.h +++ b/tasmota/language/hu_HU.h @@ -679,6 +679,8 @@ #define D_SENSOR_ELECTRIQ_MOODL "MOODL Tx" #define D_SENSOR_AS3935 "AS3935" #define D_SENSOR_WINDMETER_SPEED "WindMeter Spd" +#define D_SENSOR_TELEINFO_RX "TInfo Rx" +#define D_SENSOR_TELEINFO_ENABLE "TInfo EN" #define D_GPIO_WEBCAM_PWDN "CAM_PWDN" #define D_GPIO_WEBCAM_RESET "CAM_RESET" #define D_GPIO_WEBCAM_XCLK "CAM_XCLK" diff --git a/tasmota/language/it_IT.h b/tasmota/language/it_IT.h index f1af3765f..6fa190eed 100644 --- a/tasmota/language/it_IT.h +++ b/tasmota/language/it_IT.h @@ -679,6 +679,8 @@ #define D_SENSOR_ELECTRIQ_MOODL "MOODL - TX" #define D_SENSOR_AS3935 "AS3935" #define D_SENSOR_WINDMETER_SPEED "Velocità vento" +#define D_SENSOR_TELEINFO_RX "TInfo Rx" +#define D_SENSOR_TELEINFO_ENABLE "TInfo EN" #define D_GPIO_WEBCAM_PWDN "CAM_PWDN" #define D_GPIO_WEBCAM_RESET "CAM_RESET" #define D_GPIO_WEBCAM_XCLK "CAM_XCLK" diff --git a/tasmota/language/ko_KO.h b/tasmota/language/ko_KO.h index a004ecec7..a3a032086 100644 --- a/tasmota/language/ko_KO.h +++ b/tasmota/language/ko_KO.h @@ -679,6 +679,8 @@ #define D_SENSOR_ELECTRIQ_MOODL "MOODL Tx" #define D_SENSOR_AS3935 "AS3935" #define D_SENSOR_WINDMETER_SPEED "WindMeter Spd" +#define D_SENSOR_TELEINFO_RX "TInfo Rx" +#define D_SENSOR_TELEINFO_ENABLE "TInfo EN" #define D_GPIO_WEBCAM_PWDN "CAM_PWDN" #define D_GPIO_WEBCAM_RESET "CAM_RESET" #define D_GPIO_WEBCAM_XCLK "CAM_XCLK" diff --git a/tasmota/language/nl_NL.h b/tasmota/language/nl_NL.h index ab6a28485..8ce2fc338 100644 --- a/tasmota/language/nl_NL.h +++ b/tasmota/language/nl_NL.h @@ -679,6 +679,8 @@ #define D_SENSOR_ELECTRIQ_MOODL "MOODL Tx" #define D_SENSOR_AS3935 "AS3935" #define D_SENSOR_WINDMETER_SPEED "WindMeter Spd" +#define D_SENSOR_TELEINFO_RX "TInfo Rx" +#define D_SENSOR_TELEINFO_ENABLE "TInfo EN" #define D_GPIO_WEBCAM_PWDN "CAM_PWDN" #define D_GPIO_WEBCAM_RESET "CAM_RESET" #define D_GPIO_WEBCAM_XCLK "CAM_XCLK" diff --git a/tasmota/language/pl_PL.h b/tasmota/language/pl_PL.h index aea969baf..676297b48 100644 --- a/tasmota/language/pl_PL.h +++ b/tasmota/language/pl_PL.h @@ -679,6 +679,8 @@ #define D_SENSOR_ELECTRIQ_MOODL "MOODL Tx" #define D_SENSOR_AS3935 "AS3935" #define D_SENSOR_WINDMETER_SPEED "WindMeter Spd" +#define D_SENSOR_TELEINFO_RX "TInfo Rx" +#define D_SENSOR_TELEINFO_ENABLE "TInfo EN" #define D_GPIO_WEBCAM_PWDN "CAM_PWDN" #define D_GPIO_WEBCAM_RESET "CAM_RESET" #define D_GPIO_WEBCAM_XCLK "CAM_XCLK" diff --git a/tasmota/language/pt_BR.h b/tasmota/language/pt_BR.h index 02c4b4ecc..3babc17ec 100644 --- a/tasmota/language/pt_BR.h +++ b/tasmota/language/pt_BR.h @@ -679,6 +679,8 @@ #define D_SENSOR_ELECTRIQ_MOODL "MOODL Tx" #define D_SENSOR_AS3935 "AS3935" #define D_SENSOR_WINDMETER_SPEED "WindMeter Spd" +#define D_SENSOR_TELEINFO_RX "TInfo Rx" +#define D_SENSOR_TELEINFO_ENABLE "TInfo EN" #define D_GPIO_WEBCAM_PWDN "CAM_PWDN" #define D_GPIO_WEBCAM_RESET "CAM_RESET" #define D_GPIO_WEBCAM_XCLK "CAM_XCLK" diff --git a/tasmota/language/pt_PT.h b/tasmota/language/pt_PT.h index 4507cecba..2a0ad139f 100644 --- a/tasmota/language/pt_PT.h +++ b/tasmota/language/pt_PT.h @@ -679,6 +679,8 @@ #define D_SENSOR_ELECTRIQ_MOODL "MOODL Tx" #define D_SENSOR_AS3935 "AS3935" #define D_SENSOR_WINDMETER_SPEED "WindMeter Spd" +#define D_SENSOR_TELEINFO_RX "TInfo Rx" +#define D_SENSOR_TELEINFO_ENABLE "TInfo EN" #define D_GPIO_WEBCAM_PWDN "CAM_PWDN" #define D_GPIO_WEBCAM_RESET "CAM_RESET" #define D_GPIO_WEBCAM_XCLK "CAM_XCLK" diff --git a/tasmota/language/ro_RO.h b/tasmota/language/ro_RO.h index 66e82ad55..e80dc8bc4 100644 --- a/tasmota/language/ro_RO.h +++ b/tasmota/language/ro_RO.h @@ -679,6 +679,8 @@ #define D_SENSOR_ELECTRIQ_MOODL "MOODL Tx" #define D_SENSOR_AS3935 "AS3935" #define D_SENSOR_WINDMETER_SPEED "WindMeter Spd" +#define D_SENSOR_TELEINFO_RX "TInfo Rx" +#define D_SENSOR_TELEINFO_ENABLE "TInfo EN" #define D_GPIO_WEBCAM_PWDN "CAM_PWDN" #define D_GPIO_WEBCAM_RESET "CAM_RESET" #define D_GPIO_WEBCAM_XCLK "CAM_XCLK" diff --git a/tasmota/language/ru_RU.h b/tasmota/language/ru_RU.h index 7c7fc770b..a037ff08f 100644 --- a/tasmota/language/ru_RU.h +++ b/tasmota/language/ru_RU.h @@ -679,6 +679,8 @@ #define D_SENSOR_ELECTRIQ_MOODL "MOODL Tx" #define D_SENSOR_AS3935 "AS3935" #define D_SENSOR_WINDMETER_SPEED "WindMeter Spd" +#define D_SENSOR_TELEINFO_RX "TInfo Rx" +#define D_SENSOR_TELEINFO_ENABLE "TInfo EN" #define D_GPIO_WEBCAM_PWDN "CAM_PWDN" #define D_GPIO_WEBCAM_RESET "CAM_RESET" #define D_GPIO_WEBCAM_XCLK "CAM_XCLK" diff --git a/tasmota/language/sk_SK.h b/tasmota/language/sk_SK.h index e242f9bc1..c016a0c8e 100644 --- a/tasmota/language/sk_SK.h +++ b/tasmota/language/sk_SK.h @@ -679,6 +679,8 @@ #define D_SENSOR_ELECTRIQ_MOODL "MOODL Tx" #define D_SENSOR_AS3935 "AS3935" #define D_SENSOR_WINDMETER_SPEED "WindMeter Spd" +#define D_SENSOR_TELEINFO_RX "TInfo Rx" +#define D_SENSOR_TELEINFO_ENABLE "TInfo EN" #define D_GPIO_WEBCAM_PWDN "CAM_PWDN" #define D_GPIO_WEBCAM_RESET "CAM_RESET" #define D_GPIO_WEBCAM_XCLK "CAM_XCLK" diff --git a/tasmota/language/sv_SE.h b/tasmota/language/sv_SE.h index 1649b7f5f..ff119f953 100644 --- a/tasmota/language/sv_SE.h +++ b/tasmota/language/sv_SE.h @@ -679,6 +679,8 @@ #define D_SENSOR_ELECTRIQ_MOODL "MOODL Tx" #define D_SENSOR_AS3935 "AS3935" #define D_SENSOR_WINDMETER_SPEED "WindMeter Spd" +#define D_SENSOR_TELEINFO_RX "TInfo Rx" +#define D_SENSOR_TELEINFO_ENABLE "TInfo EN" #define D_GPIO_WEBCAM_PWDN "CAM_PWDN" #define D_GPIO_WEBCAM_RESET "CAM_RESET" #define D_GPIO_WEBCAM_XCLK "CAM_XCLK" diff --git a/tasmota/language/tr_TR.h b/tasmota/language/tr_TR.h index 8a1063d7a..e744e97e8 100644 --- a/tasmota/language/tr_TR.h +++ b/tasmota/language/tr_TR.h @@ -679,6 +679,8 @@ #define D_SENSOR_ELECTRIQ_MOODL "MOODL Tx" #define D_SENSOR_AS3935 "AS3935" #define D_SENSOR_WINDMETER_SPEED "WindMeter Spd" +#define D_SENSOR_TELEINFO_RX "TInfo Rx" +#define D_SENSOR_TELEINFO_ENABLE "TInfo EN" #define D_GPIO_WEBCAM_PWDN "CAM_PWDN" #define D_GPIO_WEBCAM_RESET "CAM_RESET" #define D_GPIO_WEBCAM_XCLK "CAM_XCLK" diff --git a/tasmota/language/uk_UA.h b/tasmota/language/uk_UA.h index a16675ae4..4d4e25f44 100644 --- a/tasmota/language/uk_UA.h +++ b/tasmota/language/uk_UA.h @@ -679,6 +679,8 @@ #define D_SENSOR_ELECTRIQ_MOODL "MOODL Tx" #define D_SENSOR_AS3935 "AS3935" #define D_SENSOR_WINDMETER_SPEED "WindMeter Spd" +#define D_SENSOR_TELEINFO_RX "TInfo Rx" +#define D_SENSOR_TELEINFO_ENABLE "TInfo EN" #define D_GPIO_WEBCAM_PWDN "CAM_PWDN" #define D_GPIO_WEBCAM_RESET "CAM_RESET" #define D_GPIO_WEBCAM_XCLK "CAM_XCLK" diff --git a/tasmota/language/zh_CN.h b/tasmota/language/zh_CN.h index 0da3126fd..b5f54991a 100644 --- a/tasmota/language/zh_CN.h +++ b/tasmota/language/zh_CN.h @@ -679,6 +679,8 @@ #define D_SENSOR_ELECTRIQ_MOODL "MOODL Tx" #define D_SENSOR_AS3935 "AS3935" #define D_SENSOR_WINDMETER_SPEED "WindMeter Spd" +#define D_SENSOR_TELEINFO_RX "TInfo Rx" +#define D_SENSOR_TELEINFO_ENABLE "TInfo EN" #define D_GPIO_WEBCAM_PWDN "CAM_PWDN" #define D_GPIO_WEBCAM_RESET "CAM_RESET" #define D_GPIO_WEBCAM_XCLK "CAM_XCLK" diff --git a/tasmota/language/zh_TW.h b/tasmota/language/zh_TW.h index 1fb664d08..1d5ed6801 100644 --- a/tasmota/language/zh_TW.h +++ b/tasmota/language/zh_TW.h @@ -679,6 +679,8 @@ #define D_SENSOR_ELECTRIQ_MOODL "MOODL Tx" #define D_SENSOR_AS3935 "AS3935" #define D_SENSOR_WINDMETER_SPEED "WindMeter Spd" +#define D_SENSOR_TELEINFO_RX "TInfo Rx" +#define D_SENSOR_TELEINFO_ENABLE "TInfo EN" #define D_GPIO_WEBCAM_PWDN "CAM_PWDN" #define D_GPIO_WEBCAM_RESET "CAM_RESET" #define D_GPIO_WEBCAM_XCLK "CAM_XCLK" From 9a5f410c463e50259f272ae3200bde9626ed5fdd Mon Sep 17 00:00:00 2001 From: Charles Date: Fri, 12 Jun 2020 16:30:59 +0200 Subject: [PATCH 04/24] Added French Smart Meter Teleinformation --- tasmota/tasmota_template.h | 10 +++++++++- tasmota/tasmota_template_ESP32.h | 9 ++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/tasmota/tasmota_template.h b/tasmota/tasmota_template.h index 8b44a547b..552696577 100644 --- a/tasmota/tasmota_template.h +++ b/tasmota/tasmota_template.h @@ -234,6 +234,8 @@ enum UserSelectablePins { GPIO_BOILER_OT_TX, // OpenTherm Boiler TX pin GPIO_WINDMETER_SPEED, // WindMeter speed counter pin GPIO_BL0940_RX, // BL0940 serial interface + GPIO_TELEINFO_RX, // BL0940 serial interface + GPIO_TELEINFO_ENABLE, // BL0940 serial interface GPIO_SENSOR_END }; // Programmer selectable GPIO functionality @@ -324,7 +326,8 @@ const char kSensorNames[] PROGMEM = D_SENSOR_AS3935 "|" D_SENSOR_PMS5003_TX "|" D_SENSOR_BOILER_OT_RX "|" D_SENSOR_BOILER_OT_TX "|" D_SENSOR_WINDMETER_SPEED "|" - D_SENSOR_BL0940_RX + D_SENSOR_BL0940_RX "|" + D_SENSOR_TELEINFO_RX "|" D_SENSOR_TELEINFO_ENABLE ; const char kSensorNamesFixed[] PROGMEM = @@ -682,6 +685,11 @@ const uint8_t kGpioNiceList[] PROGMEM = { #ifdef USE_AS3935 GPIO_AS3935, #endif +#ifdef USE_TELEINFO + GPIO_TELEINFO_RX, + GPIO_TELEINFO_ENABLE, +#endif + }; /********************************************************************************************/ diff --git a/tasmota/tasmota_template_ESP32.h b/tasmota/tasmota_template_ESP32.h index aea45ea6a..bcb2d0f3e 100644 --- a/tasmota/tasmota_template_ESP32.h +++ b/tasmota/tasmota_template_ESP32.h @@ -129,6 +129,8 @@ enum UserSelectablePins { GPIO_WINDMETER_SPEED, // WindMeter speed counter pin GPIO_KEY1_TC, // Touch pin as button GPIO_BL0940_RX, // BL0940 serial interface + GPIO_TELEINFO_RX, // Teleinfo telemetry data receive pin + GPIO_TELEINFO_ENABLE, // Teleinfo Enable Receive Pin GPIO_SENSOR_END }; enum ProgramSelectablePins { @@ -218,7 +220,8 @@ const char kSensorNames[] PROGMEM = D_GPIO_WEBCAM_PSRCS "|" D_SENSOR_BOILER_OT_RX "|" D_SENSOR_BOILER_OT_TX "|" D_SENSOR_WINDMETER_SPEED "|" D_SENSOR_BUTTON "_tc|" - D_SENSOR_BL0940_RX + D_SENSOR_BL0940_RX "|" + D_SENSOR_TELEINFO_RX "|" D_SENSOR_TELEINFO_ENABLE ; const char kSensorNamesFixed[] PROGMEM = @@ -523,6 +526,10 @@ const uint16_t kGpioNiceList[] PROGMEM = { #ifdef USE_AS3935 AGPIO(GPIO_AS3935), #endif +#ifdef USE_TELEINFO + AGPIO(GPIO_TELEINFO_RX), + AGPIO(GPIO_TELEINFO_ENABLE), +#endif /* #ifndef USE_ADC_VCC AGPIO(ADC0_INPUT), // Analog input From e7dd3e17565ad2cf0f281f6cd1faa50593d464cc Mon Sep 17 00:00:00 2001 From: Charles Date: Fri, 12 Jun 2020 16:31:23 +0200 Subject: [PATCH 05/24] Created French Smart Meter Teleinformation --- tasmota/xnrg_15_teleinfo.ino | 197 +++++++++++++++++++++++++++++++++++ 1 file changed, 197 insertions(+) create mode 100644 tasmota/xnrg_15_teleinfo.ino diff --git a/tasmota/xnrg_15_teleinfo.ino b/tasmota/xnrg_15_teleinfo.ino new file mode 100644 index 000000000..4ea6c06b8 --- /dev/null +++ b/tasmota/xnrg_15_teleinfo.ino @@ -0,0 +1,197 @@ +/* + xnrg_15_Teleinfo.ino - Teleinfo support for Tasmota + + Copyright (C) 2020 Charles-Henri Hallard + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifdef USE_ENERGY_SENSOR +#ifdef USE_TELEINFO +/*********************************************************************************************\ + * Teleinfo : French energy provider metering telemety data + * Source: http://hallard.me/category/tinfo/ + * + * Hardware Serial will be selected if GPIO1 = [TELEINFO_RX] +\*********************************************************************************************/ + +#define XNRG_15 15 + +#include "LibTeleinfo.h" +#include + +#define TINFO_READ_TIMEOUT 400 // us; enough for 6 bytes@9600bps + +TInfo tinfo; // Teleinfo object +TasmotaSerial *TInfoSerial = nullptr; +bool tinfo_found = false; + +/*********************************************************************************************/ + +/* ====================================================================== +Function: ADPSCallback +Purpose : called by library when we detected a ADPS on any phased +Input : phase number + 0 for ADPS (monophase) + 1 for ADIR1 triphase + 2 for ADIR2 triphase + 3 for ADIR3 triphase +Output : - +Comments: should have been initialised in the main sketch with a + tinfo.attachADPSCallback(ADPSCallback()) +====================================================================== */ +void ADPSCallback(uint8_t phase) +{ + // n = phase number 1 to 3 + if (phase == 0) + phase = 1; + + AddLog_P2(LOG_LEVEL_INFO, PSTR("ADPS on phase %d"), phase); +} + +/* ====================================================================== +Function: DataCallback +Purpose : callback when we detected new or modified data received +Input : linked list pointer on the concerned data + current flags value +Output : - +Comments: - +====================================================================== */ +void DataCallback(struct _ValueList * me, uint8_t flags) +{ + char c = ' '; + + if (flags & TINFO_FLAGS_ADDED) { c = '#'; } + if (flags & TINFO_FLAGS_UPDATED) { c = '*'; } + + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TIC: %c %s=%s"),c , me->name, me->value); +} + +void TInfoDrvInit(void) { + if (PinUsed(GPIO_TELEINFO_RX)) { + energy_flg = XNRG_15; + } +} + +void TInfoInit(void) +{ + #ifdef USE_TELEINFO_STANDARD + #define TINFO_SPEED 9600 + #else + #define TINFO_SPEED 1200 + #endif + + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TIC: inferface speed %d bps"),TINFO_SPEED); + + tinfo_found = false; + if (PinUsed(GPIO_TELEINFO_RX)) + { + AddLog_P2(LOG_LEVEL_INFO, PSTR("TIC: enable receive on GPIO%d"), GPIO_TELEINFO_RX); + // Enable Teleinfo + if (PinUsed(GPIO_TELEINFO_ENABLE)) + { + pinMode(GPIO_TELEINFO_ENABLE, OUTPUT); + digitalWrite(GPIO_TELEINFO_ENABLE, HIGH); + AddLog_P2(LOG_LEVEL_INFO, PSTR("TIC: enable on GPIO%d"), GPIO_TELEINFO_ENABLE); + } + else + { + AddLog_P2(LOG_LEVEL_INFO, PSTR("TIC: always enabled")); + } + + TInfoSerial = new TasmotaSerial(Pin(GPIO_TELEINFO_RX), -1, 1); + // pinMode(GPIO_TELEINFO_RX, INPUT_PULLUP); + + if (TInfoSerial->begin(TINFO_SPEED, SERIAL_7E1)) + { + if (TInfoSerial->hardwareSerial()) + ClaimSerial(); + TInfoSerial->setTimeout(TINFO_READ_TIMEOUT); + + // Init teleinfo + tinfo.init(); + + // Attach needed callbacks + tinfo.attachADPS(ADPSCallback); + tinfo.attachData(DataCallback); + + tinfo_found = true; + AddLog_P2(LOG_LEVEL_INFO, PSTR("TIC: Ready")); + } + } +} + +void TInfoEvery250ms(void) +{ + char c; + if (!tinfo_found) + return; + + AddLog_P2(LOG_LEVEL_INFO, PSTR("TIC: received %d chars"), TInfoSerial->available()); + + // We received some data? + while (TInfoSerial->available()>8) + { + // get char + c = TInfoSerial->read(); + // data processing + tinfo.process(c); + } +} + +void TInfoShow(bool json) +{ + // TBD + if (json) + { +#ifdef USE_WEBSERVER + } + else + { +#endif // USE_WEBSERVER + } +} + +/*********************************************************************************************\ + * Interface +\*********************************************************************************************/ + +bool Xnrg15(uint8_t function) +{ + + switch (function) + { + case FUNC_EVERY_250_MSECOND: + if (uptime > 4) { TInfoEvery250ms(); } + break; + case FUNC_JSON_APPEND: + TInfoShow(1); + break; +#ifdef USE_WEBSERVER + case FUNC_WEB_SENSOR: + TInfoShow(0); + break; +#endif // USE_WEBSERVER + case FUNC_INIT: + TInfoInit(); + break; + case FUNC_PRE_INIT: + TInfoDrvInit(); + break; + } + return false; +} + +#endif // USE_TELEINFO +#endif // USE_ENERGY_SENSOR From acc67b9e9f7cf8d03b26286425ebdc88ce755b0d Mon Sep 17 00:00:00 2001 From: Charles Date: Fri, 12 Jun 2020 16:31:36 +0200 Subject: [PATCH 06/24] Fix Debug --- lib/LibTeleinfo/src/LibTeleinfo.h | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/lib/LibTeleinfo/src/LibTeleinfo.h b/lib/LibTeleinfo/src/LibTeleinfo.h index 00b5495c4..a9725b26a 100755 --- a/lib/LibTeleinfo/src/LibTeleinfo.h +++ b/lib/LibTeleinfo/src/LibTeleinfo.h @@ -25,6 +25,8 @@ #ifndef LibTeleinfo_h #define LibTeleinfo_h +#include "Arduino.h" + // Define this if you want library to be verbose //#define TI_DEBUG @@ -44,10 +46,10 @@ #define TI_Debugflush Serial.flush #endif #else - #define TI_Debug(x) - #define TI_Debugln(x) - #define TI_Debugf(...) - #define TI_Debugflush + #define TI_Debug(x) {} + #define TI_Debugln(x) {} + #define TI_Debugf(...) {} + #define TI_Debugflush {} #endif // For 4 bytes Aligment boundaries @@ -61,14 +63,15 @@ typedef struct _ValueList ValueList; struct _ValueList { ValueList *next; // next element - char * name; // LABEL of value name - char * value; // value uint8_t checksum;// checksum uint8_t flags; // specific flags + char * name; // LABEL of value name + char * value; // value }; #pragma pack(pop) + // Library state machine enum _State_e { TINFO_INIT, // We're in init @@ -95,6 +98,11 @@ enum _State_e { #define TINFO_SGR '\n' // start of group #define TINFO_EGR '\r' // End of group +typedef void (*_fn_ADPS) (uint8_t); +typedef void (*_fn_data) (ValueList *, uint8_t); +typedef void (*_fn_new_frame) (ValueList *); +typedef void (*_fn_updated_frame) (ValueList *); + class TInfo { public: From dbf4a3a205cea0782eac8078ae9a6f8ae67fedee Mon Sep 17 00:00:00 2001 From: Charles Date: Fri, 12 Jun 2020 16:32:32 +0200 Subject: [PATCH 07/24] Added French Smart Meter Teleinformation --- tasmota/my_user_config.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tasmota/my_user_config.h b/tasmota/my_user_config.h index 6e20a598e..ae9a66c66 100644 --- a/tasmota/my_user_config.h +++ b/tasmota/my_user_config.h @@ -589,6 +589,8 @@ #define USE_TASMOTA_SLAVE_FLASH_SPEED 57600 // Usually 57600 for 3.3V variants and 115200 for 5V variants #define USE_TASMOTA_SLAVE_SERIAL_SPEED 57600 // Depends on the sketch that is running on the Uno/Pro Mini //#define USE_OPENTHERM // Add support for OpenTherm (+15k code) +#define USE_TELEINFO // Add support for Teleinfo via serial RX interface + //#define USE_TELEINFO_STANDARD // Use standard mode (9600 bps) else it's historical mode (1200 bps) // -- Power monitoring sensors -------------------- #define USE_ENERGY_MARGIN_DETECTION // Add support for Energy Margin detection (+1k6 code) From 941e45ef4c72606b7ae350463f7b9ed95c301902 Mon Sep 17 00:00:00 2001 From: Charles Date: Fri, 12 Jun 2020 16:33:16 +0200 Subject: [PATCH 08/24] Added French Smart Meter Teleinformation --- tasmota/support_features.ino | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tasmota/support_features.ino b/tasmota/support_features.ino index 20bb9acf3..3fcd029bf 100644 --- a/tasmota/support_features.ino +++ b/tasmota/support_features.ino @@ -575,7 +575,9 @@ void GetFeatures(void) #ifdef USE_BL0940 feature6 |= 0x00004000; // xnrg_14_bl0940.ino #endif -// feature6 |= 0x00008000; +#ifdef USE_TELEINFO + feature6 |= 0x00008000; // xnrg_15_teleinfo.ino +#endif // feature6 |= 0x00010000; // feature6 |= 0x00020000; From 481576c35380c8b39e9299dcc807165a74bf680f Mon Sep 17 00:00:00 2001 From: Charles Date: Fri, 12 Jun 2020 16:34:19 +0200 Subject: [PATCH 09/24] Added Include --- lib/LibTeleinfo/src/LibTeleinfo.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/LibTeleinfo/src/LibTeleinfo.cpp b/lib/LibTeleinfo/src/LibTeleinfo.cpp index b2d597f28..77db56e54 100644 --- a/lib/LibTeleinfo/src/LibTeleinfo.cpp +++ b/lib/LibTeleinfo/src/LibTeleinfo.cpp @@ -22,6 +22,7 @@ // // ********************************************************************************** +#include "Arduino.h" #include "LibTeleinfo.h" /* ====================================================================== From 6cbae1fafe71049ecc331cb51e4343c657485d9e Mon Sep 17 00:00:00 2001 From: Charles Date: Fri, 12 Jun 2020 21:53:12 +0200 Subject: [PATCH 10/24] Added French Metering Teleinfo --- BUILDS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/BUILDS.md b/BUILDS.md index 7e642de4e..91bbd287e 100644 --- a/BUILDS.md +++ b/BUILDS.md @@ -68,6 +68,7 @@ | USE_DDSU666 | - | - | - | - | x | - | - | | USE_SOLAX_X1 | - | - | - | - | - | - | - | | USE_LE01MR | - | - | - | - | - | - | - | +| USE_TELEINFO | - | - | - | - | - | - | - | | | | | | | | | | | USE_ADC_VCC | x | x | - | - | - | - | - | | USE_COUNTER | - | - | x | x | x | x | x | From 4929d3c8e5b16347776bb338b6a99f824e554c39 Mon Sep 17 00:00:00 2001 From: Charles Date: Fri, 12 Jun 2020 21:53:26 +0200 Subject: [PATCH 11/24] Added French Metering Teleinfo --- RELEASENOTES.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index fdac7edde..fa35311dd 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -54,6 +54,8 @@ The following binary downloads have been compiled with ESP8266/Arduino library c ### Version 8.3.1.2 +- Created Energy sensor (Denky) for French Smart Metering meter provided by global Energy Providers, need a adaptater. See dedicated full [blog](http://hallard.me/category/tinfo/) about French teleinformation stuff +- Added Library to be used for decoding Teleinfo (French Metering Smart Meter) - Change IRremoteESP8266 library updated to v2.7.7 - Change Adafruit_SGP30 library from v1.0.3 to v1.2.0 (#8519) - Change Energy JSON Total field from ``"Total":[33.736,11.717,16.978]`` to ``"Total":33.736,"TotalTariff":[11.717,16.978]`` From 6d38a67cdad5eb72eb94b4033e06a2b65fb5ad61 Mon Sep 17 00:00:00 2001 From: Charles Date: Fri, 12 Jun 2020 21:53:54 +0200 Subject: [PATCH 12/24] Added deviice Denky for French Metering Teleinfo --- tasmota/tasmota_template.h | 28 +++++++++++++++++++++++++--- tasmota/tasmota_template_ESP32.h | 7 ++++--- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/tasmota/tasmota_template.h b/tasmota/tasmota_template.h index 552696577..a0146aece 100644 --- a/tasmota/tasmota_template.h +++ b/tasmota/tasmota_template.h @@ -777,8 +777,8 @@ enum SupportedModules { SUPLA1, WITTY, YUNSHAN, MAGICHOME, LUANIHVIO, KMC_70011, ARILUX_LC01, ARILUX_LC11, SONOFF_DUAL_R2, ARILUX_LC06, SONOFF_S31, ZENGGE_ZF_WF017, SONOFF_POW_R2, SONOFF_IFAN02, BLITZWOLF_BWSHP, SHELLY1, SHELLY2, PHILIPS, NEO_COOLCAM, ESP_SWITCH, OBI, TECKIN, APLIC_WDP303075, TUYA_DIMMER, GOSUND, ARMTRONIX_DIMMERS, SK03_TUYA, PS_16_DZ, TECKIN_US, MANZOKU_EU_4, - OBI2, YTF_IR_BRIDGE, DIGOO, KA10, ZX2820, MI_DESK_LAMP, SP10, WAGA, SYF05, SONOFF_L1, - SONOFF_IFAN03, EXS_DIMMER, PWM_DIMMER, SONOFF_D1, + OBI2, YTF_IR_BRIDGE, DIGOO, KA10, ZX2820, MI_DESK_LAMP, SP10, WAGA, SYF05, SONOFF_L1, + SONOFF_IFAN03, EXS_DIMMER, PWM_DIMMER, SONOFF_D1, DENKY, MAXMODULE}; #define USER_MODULE 255 @@ -791,7 +791,7 @@ const char kModuleNames[] PROGMEM = "Sonoff S31|Zengge WF017|Sonoff Pow R2|Sonoff iFan02|BlitzWolf SHP|Shelly 1|Shelly 2|Xiaomi Philips|Neo Coolcam|ESP Switch|" "OBI Socket|Teckin|AplicWDP303075|Tuya MCU|Gosund SP1 v23|ARMTR Dimmer|SK03 Outdoor|PS-16-DZ|Teckin US|Manzoku strip|" "OBI Socket 2|YTF IR Bridge|Digoo DG-SP202|KA10|Luminea ZX2820|Mi Desk Lamp|SP10|WAGA CHCZ02MB|SYF05|Sonoff L1|" - "Sonoff iFan03|EXS Dimmer|PWM Dimmer|Sonoff D1" + "Sonoff iFan03|EXS Dimmer|PWM Dimmer|Sonoff D1|Denky (Teleinfo)" ; const uint8_t kModuleNiceList[] PROGMEM = { @@ -2174,6 +2174,26 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { GPIO_LED1_INV, // GPIO13 WiFi Blue Led - Link and Power status 0, 0, 0, 0 }, + { // Denky (Teleinfo) Any ESP8266 device + GPIO_WS2812, // GPIO00 WS2812 RGB LED + GPIO_USER, // GPIO01 TX Serial RXD + GPIO_USER, // GPIO02 D4 Wemos DHT Shield + GPIO_TELEINFO_RX, // GPIO03 Smart Meter RX Serial + GPIO_I2C_SDA, // GPIO04 D2 Wemos I2C SDA + GPIO_I2C_SCL, // GPIO05 D1 Wemos I2C SCL + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + GPIO_USER, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) + GPIO_USER, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) + // GPIO11 (SD_CMD Flash) + GPIO_USER, // GPIO12 D6 + GPIO_USER, // GPIO13 D7 + GPIO_USER, // GPIO14 D5 + GPIO_USER, // GPIO15 D8 + GPIO_USER, // GPIO16 D0 Wemos Wake + ADC0_USER // ADC0 A0 Analog input + }, { // SONOFF_IFAN03 - Sonoff iFan03 (ESP8285) GPIO_KEY1, // GPIO00 WIFI_KEY0 Button 1 GPIO_TXD, // GPIO01 ESP_TXD Serial RXD connection to P0.5 of RF microcontroller @@ -2258,8 +2278,10 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { GPIO_LED1_INV, // GPIO13 WiFi Blue Led - Link and Power status 0, 0, 0, 0 } + }; + #endif // ESP8266 #ifdef ESP32 diff --git a/tasmota/tasmota_template_ESP32.h b/tasmota/tasmota_template_ESP32.h index bcb2d0f3e..f6424bfbf 100644 --- a/tasmota/tasmota_template_ESP32.h +++ b/tasmota/tasmota_template_ESP32.h @@ -610,18 +610,19 @@ typedef struct MYTMPLT { /********************************************************************************************/ // Supported hardware modules enum SupportedModules { - WEMOS, ESP32_CAM_AITHINKER, + WEMOS, ESP32_CAM_AITHINKER, ESP32_DENKY, MAXMODULE}; #define USER_MODULE 255 const char kModuleNames[] PROGMEM = - "ESP32-DevKit|ESP32 Cam AiThinker"; + "ESP32-DevKit|ESP32 Cam AiThinker|Denky (Teleinfo)"; // Default module settings const uint8_t kModuleNiceList[MAXMODULE] PROGMEM = { WEMOS, - ESP32_CAM_AITHINKER + ESP32_CAM_AITHINKER, + ESP32_DENKY }; const mytmplt kModules PROGMEM = From 6fd972d7a80dd5a3f23836e98987265b8b11fe2c Mon Sep 17 00:00:00 2001 From: Charles Date: Sat, 13 Jun 2020 02:18:01 +0200 Subject: [PATCH 13/24] Bumped to version 1.1.1 --- lib/LibTeleinfo/library.json | 2 +- lib/LibTeleinfo/library.properties | 2 +- lib/LibTeleinfo/src/LibTeleinfo.cpp | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/LibTeleinfo/library.json b/lib/LibTeleinfo/library.json index 068618ce0..70f368653 100755 --- a/lib/LibTeleinfo/library.json +++ b/lib/LibTeleinfo/library.json @@ -1,6 +1,6 @@ { "name": "LibTeleinfo", - "version": "1.1.0", + "version": "1.1.1", "keywords": "teleinfo, french, meter, power, erdf, linky, tic", "description": "Decoder for Teleinfo (aka TIC) from French smart power meters", "repository": diff --git a/lib/LibTeleinfo/library.properties b/lib/LibTeleinfo/library.properties index 2420c5fc2..fdcee4a25 100755 --- a/lib/LibTeleinfo/library.properties +++ b/lib/LibTeleinfo/library.properties @@ -1,5 +1,5 @@ name=LibTeleinfo -version=1.1.0 +version=1.1.1 author=Charles-Henri Hallard maintainer=Charles-Henri Hallard sentence=Decoder for Teleinfo (aka TIC) from French smart power meters diff --git a/lib/LibTeleinfo/src/LibTeleinfo.cpp b/lib/LibTeleinfo/src/LibTeleinfo.cpp index 77db56e54..8d34e89d1 100644 --- a/lib/LibTeleinfo/src/LibTeleinfo.cpp +++ b/lib/LibTeleinfo/src/LibTeleinfo.cpp @@ -212,9 +212,9 @@ ValueList * TInfo::valueAdd(char * name, char * value, uint8_t checksum, uint8_t me = me->next; // Check if we already have this LABEL (same name AND same size) - if (lgname==strlen(me->name) && strncmp(me->name, name, lgname)==0) { + if (lgname==strlen(me->name) && strcmp(me->name, name)==0) { // Already got also this value return US - if (lgvalue==strlen(me->value) && strncmp(me->value, value, lgvalue) == 0) { + if (lgvalue==strlen(me->value) && strcmp(me->value, value) == 0) { *flags |= TINFO_FLAGS_EXIST; me->flags = *flags; return ( me ); @@ -225,7 +225,7 @@ ValueList * TInfo::valueAdd(char * name, char * value, uint8_t checksum, uint8_t // Do we have enought space to hold new value ? if (strlen(me->value) >= lgvalue ) { // Copy it - strlcpy(me->value, value , lgvalue ); + strlcpy(me->value, value , lgvalue + 1 ); me->checksum = checksum ; // That's all From cf518463c1da8c601a139922af0c2ca883bbfcfa Mon Sep 17 00:00:00 2001 From: Charles Date: Sun, 14 Jun 2020 22:04:19 +0200 Subject: [PATCH 14/24] Implemented serial into loop --- tasmota/xnrg_15_teleinfo.ino | 127 +++++++++++++++++++++++++++++------ 1 file changed, 107 insertions(+), 20 deletions(-) diff --git a/tasmota/xnrg_15_teleinfo.ino b/tasmota/xnrg_15_teleinfo.ino index 4ea6c06b8..094f07bc8 100644 --- a/tasmota/xnrg_15_teleinfo.ino +++ b/tasmota/xnrg_15_teleinfo.ino @@ -31,14 +31,59 @@ #include "LibTeleinfo.h" #include -#define TINFO_READ_TIMEOUT 400 // us; enough for 6 bytes@9600bps +#define TINFO_READ_TIMEOUT 400 + +enum TInfoContrat{ + CONTRAT_BAS = 1, // BASE => Option Base. + CONTRAT_HC, // HC.. => Option Heures Creuses. + CONTRAT_EJP, // EJP. => Option EJP. + CONTRAT_BBR // BBRx => Option Tempo +}; + +enum TInfoTarif{ + TARIF_TH = 1, // Toutes les Heures. + TARIF_HC, // Heures Creuses. + TARIF_HP, // Heures Pleines. + TARIF_HN // BBRx => Option Tempo +}; + +//const char kTARIF_TH[] PROGMEM = ""; +//const char kTARIF_HC[] PROGMEM = "Heures Creuses"; +//const char kTARIF_HP[] PROGMEM = "Heures Pleines"; +//const char kTARIF_HN[] PROGMEM = "Heures Normales"; + +//const char kTtarifNames[] PROGMEM = { kTARIF_TH, kTARIF_HC, kTARIF_HP, kTARIF_HN }; + +/* + strcpy_P(buffer, (char*)pgm_read_dword(&(kTtarifNames[i]))); + + if ( label == "PTEC") { + // La période tarifaire en cours (Groupe "PTEC"), est codée sur 4 caractères + // J'ai pris un nombre arbitraire codé dans l'ordre ci-dessous + if (value=="TH..") value= 1; + else if (value=="HC..") value= 2; + else if (value=="HP..") value= 3; / + else if (value=="HN..") value= 4; + else if (value=="PM..") value= 5; // Heures de Pointe Mobile. + else if (value=="HCJB") value= 6; // Heures Creuses Jours Bleus. + else if (value=="HCJW") value= 7; // Heures Creuses Jours Blancs (White). + else if (value=="HCJR") value= 8; // Heures Creuses Jours Rouges. + else if (value=="HPJB") value= 9; // Heures Pleines Jours Bleus. + else if (value=="HPJW") value= 10;// Heures Pleines Jours Blancs (White). + else if (value=="HPJR") value= 11;// Heures Pleines Jours Rouges. + else value = 0; + +*/ + TInfo tinfo; // Teleinfo object TasmotaSerial *TInfoSerial = nullptr; bool tinfo_found = false; +uint8_t contrat; +uint8_t tarif; /*********************************************************************************************/ - + /* ====================================================================== Function: ADPSCallback Purpose : called by library when we detected a ADPS on any phased @@ -70,12 +115,39 @@ Comments: - ====================================================================== */ void DataCallback(struct _ValueList * me, uint8_t flags) { - char c = ' '; - - if (flags & TINFO_FLAGS_ADDED) { c = '#'; } - if (flags & TINFO_FLAGS_UPDATED) { c = '*'; } + char c = ' '; - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TIC: %c %s=%s"),c , me->name, me->value); + // Does this value is new or changed? + if (flags & (TINFO_FLAGS_ADDED | TINFO_FLAGS_UPDATED) ) + { + if (flags & TINFO_FLAGS_ADDED) { c = '#'; } + if (flags & TINFO_FLAGS_UPDATED) { c = '*'; } + + // Current tarif + if (!strcmp("PTEC", me->name)) + { + if (!strcmp("TH..", me->name)) { tarif = TARIF_TH; } + if (!strcmp("HC..", me->name)) { tarif = TARIF_HC; } + if (!strcmp("HP..", me->name)) { tarif = TARIF_HP; } + if (!strcmp("HN..", me->name)) { tarif = TARIF_HN; } + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TIC: Tarif changed, now '%s' (%d)"), me->value, tarif); + } + // Current I + else if (!strcmp("IINST", me->name)) + { + int i = atoi(me->value); + Energy.current[0] = (float) i; + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TIC: Current changed %s, now %d"), me->value, i); + } + // Current P + else if (!strcmp("PAPP", me->name)) + { + int papp = atoi(me->value); + Energy.active_power[0] = (float) papp; + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TIC: Power changed %s, now %d"), me->value, papp); + } + } + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TIC: %c %s=%s"),c , me->name, me->value); } void TInfoDrvInit(void) { @@ -94,7 +166,6 @@ void TInfoInit(void) AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TIC: inferface speed %d bps"),TINFO_SPEED); - tinfo_found = false; if (PinUsed(GPIO_TELEINFO_RX)) { AddLog_P2(LOG_LEVEL_INFO, PSTR("TIC: enable receive on GPIO%d"), GPIO_TELEINFO_RX); @@ -111,12 +182,16 @@ void TInfoInit(void) } TInfoSerial = new TasmotaSerial(Pin(GPIO_TELEINFO_RX), -1, 1); + // pinMode(GPIO_TELEINFO_RX, INPUT_PULLUP); if (TInfoSerial->begin(TINFO_SPEED, SERIAL_7E1)) { - if (TInfoSerial->hardwareSerial()) + if (TInfoSerial->hardwareSerial()) { + Serial.end(); + Serial.begin(TINFO_SPEED, SERIAL_7E1); ClaimSerial(); + } TInfoSerial->setTimeout(TINFO_READ_TIMEOUT); // Init teleinfo @@ -125,29 +200,36 @@ void TInfoInit(void) // Attach needed callbacks tinfo.attachADPS(ADPSCallback); tinfo.attachData(DataCallback); - + tinfo_found = true; AddLog_P2(LOG_LEVEL_INFO, PSTR("TIC: Ready")); } } } -void TInfoEvery250ms(void) +void TInfoLoop(void) { char c; if (!tinfo_found) return; - AddLog_P2(LOG_LEVEL_INFO, PSTR("TIC: received %d chars"), TInfoSerial->available()); + if (TInfoSerial->available()) { + //AddLog_P2(LOG_LEVEL_INFO, PSTR("TIC: received %d chars"), TInfoSerial->available()); - // We received some data? - while (TInfoSerial->available()>8) - { - // get char - c = TInfoSerial->read(); - // data processing - tinfo.process(c); - } + // We received some data? + while (TInfoSerial->available()>8) + { + // get char + c = TInfoSerial->read(); + + // data processing + tinfo.process(c); + } + } +} + +void TInfoEvery250ms(void) +{ } void TInfoShow(bool json) @@ -155,6 +237,8 @@ void TInfoShow(bool json) // TBD if (json) { + ResponseAppend_P(PSTR(",\"Contrat\":%d,\"Tarif\":%d"),contrat, tarif); + #ifdef USE_WEBSERVER } else @@ -172,6 +256,9 @@ bool Xnrg15(uint8_t function) switch (function) { + case FUNC_LOOP: + if (TInfoSerial) { TInfoLoop(); } + break; case FUNC_EVERY_250_MSECOND: if (uptime > 4) { TInfoEvery250ms(); } break; From 5e5ebb002541fc2aa7530df3c6174774dd5e476f Mon Sep 17 00:00:00 2001 From: Charles Date: Mon, 15 Jun 2020 00:52:49 +0200 Subject: [PATCH 15/24] Added new tarif contract --- tasmota/xnrg_15_teleinfo.ino | 203 +++++++++++++++++++++++++++-------- 1 file changed, 158 insertions(+), 45 deletions(-) diff --git a/tasmota/xnrg_15_teleinfo.ino b/tasmota/xnrg_15_teleinfo.ino index 094f07bc8..83a20648f 100644 --- a/tasmota/xnrg_15_teleinfo.ino +++ b/tasmota/xnrg_15_teleinfo.ino @@ -34,47 +34,44 @@ #define TINFO_READ_TIMEOUT 400 enum TInfoContrat{ - CONTRAT_BAS = 1, // BASE => Option Base. - CONTRAT_HC, // HC.. => Option Heures Creuses. - CONTRAT_EJP, // EJP. => Option EJP. - CONTRAT_BBR // BBRx => Option Tempo + CONTRAT_BAS = 1, // BASE => Option Base. + CONTRAT_HC, // HC.. => Option Heures Creuses. + CONTRAT_EJP, // EJP. => Option EJP. + CONTRAT_BBR // BBRx => Option Tempo }; enum TInfoTarif{ - TARIF_TH = 1, // Toutes les Heures. - TARIF_HC, // Heures Creuses. - TARIF_HP, // Heures Pleines. - TARIF_HN // BBRx => Option Tempo + TARIF_TH = 1, // Toutes les Heures. + TARIF_HC, // Heures Creuses. + TARIF_HP, // Heures Pleines. + TARIF_HN, // BBRx => Option Tempo + TARIF_PM, // Heures de Pointe Mobile. + TARIF_CB, // Heures Creuses Jours Bleus. + TARIF_CW, // Heures Creuses Jours Blancs (White). + TARIF_CR, // Heures Creuses Jours Rouges. + TARIF_PB, // Heures Pleines Jours Bleus. + TARIF_PW, // Heures Pleines Jours Blancs (White). + TARIF_PR // Heures Pleines Jours Rouges. }; -//const char kTARIF_TH[] PROGMEM = ""; -//const char kTARIF_HC[] PROGMEM = "Heures Creuses"; -//const char kTARIF_HP[] PROGMEM = "Heures Pleines"; -//const char kTARIF_HN[] PROGMEM = "Heures Normales"; - -//const char kTtarifNames[] PROGMEM = { kTARIF_TH, kTARIF_HC, kTARIF_HP, kTARIF_HN }; - -/* - strcpy_P(buffer, (char*)pgm_read_dword(&(kTtarifNames[i]))); - - if ( label == "PTEC") { - // La période tarifaire en cours (Groupe "PTEC"), est codée sur 4 caractères - // J'ai pris un nombre arbitraire codé dans l'ordre ci-dessous - if (value=="TH..") value= 1; - else if (value=="HC..") value= 2; - else if (value=="HP..") value= 3; / - else if (value=="HN..") value= 4; - else if (value=="PM..") value= 5; // Heures de Pointe Mobile. - else if (value=="HCJB") value= 6; // Heures Creuses Jours Bleus. - else if (value=="HCJW") value= 7; // Heures Creuses Jours Blancs (White). - else if (value=="HCJR") value= 8; // Heures Creuses Jours Rouges. - else if (value=="HPJB") value= 9; // Heures Pleines Jours Bleus. - else if (value=="HPJW") value= 10;// Heures Pleines Jours Blancs (White). - else if (value=="HPJR") value= 11;// Heures Pleines Jours Rouges. - else value = 0; - -*/ +const char kTARIF_TH[] PROGMEM = "Toutes"; +const char kTARIF_HC[] PROGMEM = "Creuses"; +const char kTARIF_HP[] PROGMEM = "Pleines"; +const char kTARIF_HN[] PROGMEM = "Normales"; +const char kTARIF_PM[] PROGMEM = "Pointe Mobile"; +const char kTARIF_CB[] PROGMEM = "Creuses Bleu"; +const char kTARIF_CW[] PROGMEM = "Creuses Blanc"; +const char kTARIF_CR[] PROGMEM = "Creuses Rouge"; +const char kTARIF_PB[] PROGMEM = "Pleines Bleu"; +const char kTARIF_PW[] PROGMEM = "Pleines Blanc"; +const char kTARIF_PR[] PROGMEM = "Pleines Rouge"; +const char * kTtarifNames[] PROGMEM = { + kTARIF_TH, + kTARIF_HC, kTARIF_HP, + kTARIF_HN, kTARIF_PM, + kTARIF_CB, kTARIF_CW, kTARIF_CR, kTARIF_PB, kTARIF_PW, kTARIF_PR +}; TInfo tinfo; // Teleinfo object TasmotaSerial *TInfoSerial = nullptr; @@ -127,32 +124,112 @@ void DataCallback(struct _ValueList * me, uint8_t flags) if (!strcmp("PTEC", me->name)) { if (!strcmp("TH..", me->name)) { tarif = TARIF_TH; } - if (!strcmp("HC..", me->name)) { tarif = TARIF_HC; } - if (!strcmp("HP..", me->name)) { tarif = TARIF_HP; } - if (!strcmp("HN..", me->name)) { tarif = TARIF_HN; } + else if (!strcmp("HC..", me->name)) { tarif = TARIF_HC; } + else if (!strcmp("HP..", me->name)) { tarif = TARIF_HP; } + else if (!strcmp("HN..", me->name)) { tarif = TARIF_HN; } + else if (!strcmp("PM..", me->name)) { tarif = TARIF_PM; } + else if (!strcmp("HCJB", me->name)) { tarif = TARIF_CB; } + else if (!strcmp("HCJW", me->name)) { tarif = TARIF_CW; } + else if (!strcmp("HCJR", me->name)) { tarif = TARIF_CR; } + else if (!strcmp("HPJB", me->name)) { tarif = TARIF_PB; } + else if (!strcmp("HPJW", me->name)) { tarif = TARIF_PW; } + else if (!strcmp("HPJR", me->name)) { tarif = TARIF_PR; } + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TIC: Tarif changed, now '%s' (%d)"), me->value, tarif); } + // Voltage V (not present on all Smart Meter) + else if (!strcmp("TENSION", me->name)) + { + Energy.voltage_available = true; + int i = atoi(me->value); + Energy.voltage[0] = (float) atoi(me->value); + + // Update current + if (Energy.voltage_available && Energy.voltage[0]) { + Energy.current[0] = Energy.active_power[0] / Energy.voltage[0] ; + } + + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TIC: Voltage %s, now %d"), me->value, i); + } // Current I else if (!strcmp("IINST", me->name)) { - int i = atoi(me->value); - Energy.current[0] = (float) i; - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TIC: Current changed %s, now %d"), me->value, i); + if (!Energy.voltage_available) { + int i = atoi(me->value); + Energy.current[0] = (float) atoi(me->value); + } else if (Energy.voltage[0]) { + Energy.current[0] = Energy.active_power[0] / Energy.voltage[0] ; + } + + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TIC: Current %s, now %d"), me->value, (int) Energy.current[0]); } // Current P else if (!strcmp("PAPP", me->name)) { int papp = atoi(me->value); - Energy.active_power[0] = (float) papp; - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TIC: Power changed %s, now %d"), me->value, papp); + Energy.active_power[0] = (float) atoi(me->value); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TIC: Power %s, now %d"), me->value, papp); + + // Update current + if (Energy.voltage_available && Energy.voltage[0]) { + Energy.current[0] = Energy.active_power[0] / Energy.voltage[0] ; + } + } + // kWh indexes + else if (!strcmp("HCHC", me->name) || !strcmp("HCHP", me->name)) + { + char value[32]; + unsigned long hc = 0; + unsigned long hp = 0; + unsigned long total = 0; + + if ( tinfo.valueGet((char *)"HCHC", value) ) { hc = atol(value);} + if ( tinfo.valueGet((char *)"HCHP", value) ) { hp = atol(value);} + total = hc+hp; + + EnergyUpdateTotal(total/1000.0f, true); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TIC: HC:%ld HP:%ld Total:%ld"), hc, hp, total); } } AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TIC: %c %s=%s"),c , me->name, me->value); } +/* ====================================================================== +Function: NewFrameCallback +Purpose : callback when we received a complete Teleinfo frama +Input : linked list pointer on the concerned data +Output : - +Comments: - +====================================================================== */ +void NewFrameCallback(struct _ValueList * me) +{ + // Reset Energy Watchdog + Energy.data_valid[0] = 0; +} + +/* ====================================================================== +Function: NewFrameCallback +Purpose : callback when we received a complete Teleinfo frama +Input : label to search for +Output : value filled +Comments: - +====================================================================== */ +char * getDataValue(char * label, char * value) +{ + if (!tinfo.valueGet(label, value) ) { + *value = '\0'; + } + return value; +} + + + void TInfoDrvInit(void) { if (PinUsed(GPIO_TELEINFO_RX)) { energy_flg = XNRG_15; + Energy.voltage_available = false; + //Energy.current_available = false; + Energy.type_dc = true; } } @@ -188,6 +265,9 @@ void TInfoInit(void) if (TInfoSerial->begin(TINFO_SPEED, SERIAL_7E1)) { if (TInfoSerial->hardwareSerial()) { + // This is a dirty hack to bypass HW serial init when for Teleinfo + // This protocol needs 7E1 configuration so on ESP8266 this is + // working only on Serial RX pin (Hardware Serial) for now Serial.end(); Serial.begin(TINFO_SPEED, SERIAL_7E1); ClaimSerial(); @@ -200,6 +280,7 @@ void TInfoInit(void) // Attach needed callbacks tinfo.attachADPS(ADPSCallback); tinfo.attachData(DataCallback); + tinfo.attachNewFrame(NewFrameCallback); tinfo_found = true; AddLog_P2(LOG_LEVEL_INFO, PSTR("TIC: Ready")); @@ -228,21 +309,52 @@ void TInfoLoop(void) } } + void TInfoEvery250ms(void) { } +#ifdef USE_WEBSERVER +const char HTTP_ENERGY_INDEX_TELEINFO[] PROGMEM = "{s}%s{m}%s " D_UNIT_KILOWATTHOUR "{e}" ; +const char HTTP_ENERGY_PAPP_TELEINFO[] PROGMEM = "{s}" D_POWERUSAGE "{m}%d " D_UNIT_WATT "{e}" ; +const char HTTP_ENERGY_IINST_TELEINFO[] PROGMEM = "{s}" D_CURRENT "{m}%d " D_UNIT_AMPERE "{e}" ; +const char HTTP_ENERGY_TARIF_TELEINFO[] PROGMEM = "{s}Tarif{m}%s{e}" ; +#endif // USE_WEBSERVER + void TInfoShow(bool json) { + char value[32]; // TBD if (json) { - ResponseAppend_P(PSTR(",\"Contrat\":%d,\"Tarif\":%d"),contrat, tarif); - + if ( tinfo.valueGet((char *)"PTEC", value) ) { + ResponseAppend_P(PSTR(",\"" "TARIF" "\":%s"), value); + } + if ( tinfo.valueGet((char *)"IINST", value) ) { + ResponseAppend_P(PSTR(",\"" D_CURRENT "\":%s"), value); + } + if ( tinfo.valueGet((char *)"PAPP", value) ) { + ResponseAppend_P(PSTR(",\"" D_POWERUSAGE "\":%s"), value); + } + if ( tinfo.valueGet((char *)"HCHC", value) ) { + ResponseAppend_P(PSTR(",\"" "HC" "\":%s"), value); + } + if ( tinfo.valueGet((char *)"HCHP", value) ) { + ResponseAppend_P(PSTR(",\"" "HP" "\":%s"), value); + } #ifdef USE_WEBSERVER } else { + getDataValue("HCHC", value); + WSContentSend_PD(HTTP_ENERGY_INDEX_TELEINFO, kTARIF_HC, value); + getDataValue("HCHP", value); + WSContentSend_PD(HTTP_ENERGY_INDEX_TELEINFO, kTARIF_HP, value); + if (tarif) { + WSContentSend_PD(HTTP_ENERGY_TARIF_TELEINFO, kTtarifNames[tarif-1]); + } + + #endif // USE_WEBSERVER } } @@ -263,6 +375,7 @@ bool Xnrg15(uint8_t function) if (uptime > 4) { TInfoEvery250ms(); } break; case FUNC_JSON_APPEND: + TInfoShow(1); break; #ifdef USE_WEBSERVER From 32d82b3568dca410a4fa986292951b3ce083fb06 Mon Sep 17 00:00:00 2001 From: Charles Date: Mon, 15 Jun 2020 01:20:49 +0200 Subject: [PATCH 16/24] Bump to v1.1.2 --- lib/LibTeleinfo/library.json | 2 +- lib/LibTeleinfo/library.properties | 2 +- lib/LibTeleinfo/src/LibTeleinfo.cpp | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/LibTeleinfo/library.json b/lib/LibTeleinfo/library.json index 70f368653..a93105e61 100755 --- a/lib/LibTeleinfo/library.json +++ b/lib/LibTeleinfo/library.json @@ -1,6 +1,6 @@ { "name": "LibTeleinfo", - "version": "1.1.1", + "version": "1.1.2", "keywords": "teleinfo, french, meter, power, erdf, linky, tic", "description": "Decoder for Teleinfo (aka TIC) from French smart power meters", "repository": diff --git a/lib/LibTeleinfo/library.properties b/lib/LibTeleinfo/library.properties index fdcee4a25..7cfc9a635 100755 --- a/lib/LibTeleinfo/library.properties +++ b/lib/LibTeleinfo/library.properties @@ -1,5 +1,5 @@ name=LibTeleinfo -version=1.1.1 +version=1.1.2 author=Charles-Henri Hallard maintainer=Charles-Henri Hallard sentence=Decoder for Teleinfo (aka TIC) from French smart power meters diff --git a/lib/LibTeleinfo/src/LibTeleinfo.cpp b/lib/LibTeleinfo/src/LibTeleinfo.cpp index 8d34e89d1..bb7b7119f 100644 --- a/lib/LibTeleinfo/src/LibTeleinfo.cpp +++ b/lib/LibTeleinfo/src/LibTeleinfo.cpp @@ -426,7 +426,7 @@ char * TInfo::valueGet(char * name, char * value) if (me->value) { // copy to dest buffer uint8_t lgvalue = strlen(me->value); - strlcpy(value, me->value , lgvalue ); + strlcpy(value, me->value , lgvalue + 1 ); return ( value ); } } @@ -661,7 +661,7 @@ ValueList * TInfo::checkLine(char * pline) return NULL; // Get our own working copy - strlcpy( buff, _recv_buff, len+1); + strlcpy( buff, pline, len+1); p = &buff[0]; ptok = p; // for sure we start with token name From 71b7b1632d96d047e44550110ea37a6281921c51 Mon Sep 17 00:00:00 2001 From: Charles Date: Mon, 15 Jun 2020 11:52:51 +0200 Subject: [PATCH 17/24] cleaned Serial init (not perfect but better) --- tasmota/xnrg_15_teleinfo.ino | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/tasmota/xnrg_15_teleinfo.ino b/tasmota/xnrg_15_teleinfo.ino index 83a20648f..97dfca314 100644 --- a/tasmota/xnrg_15_teleinfo.ino +++ b/tasmota/xnrg_15_teleinfo.ino @@ -262,14 +262,16 @@ void TInfoInit(void) // pinMode(GPIO_TELEINFO_RX, INPUT_PULLUP); - if (TInfoSerial->begin(TINFO_SPEED, SERIAL_7E1)) + // Trick here even using SERIAL_7E1 or TS_SERIAL_7E1 + // this is not working, need to call SetSerialConfig after + if (TInfoSerial->begin(TINFO_SPEED, TS_SERIAL_7E1)) { + // This is a dirty hack, looks like begin does not take into account + // the TS_SERIAL_7E1 configuration so on ESP8266 this is + // working only on Serial RX pin (Hardware Serial) for now + SetSerialConfig(TS_SERIAL_7E1); + if (TInfoSerial->hardwareSerial()) { - // This is a dirty hack to bypass HW serial init when for Teleinfo - // This protocol needs 7E1 configuration so on ESP8266 this is - // working only on Serial RX pin (Hardware Serial) for now - Serial.end(); - Serial.begin(TINFO_SPEED, SERIAL_7E1); ClaimSerial(); } TInfoSerial->setTimeout(TINFO_READ_TIMEOUT); From b98fa03dd0a7902dd9131b03f17dcfbded1431f0 Mon Sep 17 00:00:00 2001 From: Charles Date: Mon, 15 Jun 2020 14:44:32 +0200 Subject: [PATCH 18/24] Added valueGet_P option --- lib/LibTeleinfo/src/LibTeleinfo.cpp | 38 +++++++++++++++++++++++++++++ lib/LibTeleinfo/src/LibTeleinfo.h | 1 + 2 files changed, 39 insertions(+) diff --git a/lib/LibTeleinfo/src/LibTeleinfo.cpp b/lib/LibTeleinfo/src/LibTeleinfo.cpp index bb7b7119f..588555831 100644 --- a/lib/LibTeleinfo/src/LibTeleinfo.cpp +++ b/lib/LibTeleinfo/src/LibTeleinfo.cpp @@ -436,6 +436,44 @@ char * TInfo::valueGet(char * name, char * value) return ( NULL); } +/* ====================================================================== +Function: valueGet_P +Purpose : get value of one element +Input : Pointer to the label name + pointer to the value where we fill data +Output : pointer to the value where we filled data NULL is not found +====================================================================== */ +char * TInfo::valueGet_P(const char * name, char * value) +{ + // Get our linked list + ValueList * me = &_valueslist; + uint8_t lgname = strlen_P(name); + + // Got one and all seems good ? + if (me && lgname) { + + // Loop thru the node + while (me->next) { + + // go to next node + me = me->next; + + // Check if we match this LABEL + if (lgname==strlen(me->name) && strncmp_P(me->name, name, lgname)==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 ); + } + } + } + } + // not found + return ( NULL); +} + /* ====================================================================== Function: getTopList Purpose : return a pointer on the top of the linked list diff --git a/lib/LibTeleinfo/src/LibTeleinfo.h b/lib/LibTeleinfo/src/LibTeleinfo.h index a9725b26a..5b43523c7 100755 --- a/lib/LibTeleinfo/src/LibTeleinfo.h +++ b/lib/LibTeleinfo/src/LibTeleinfo.h @@ -117,6 +117,7 @@ class TInfo ValueList * getList(void); uint8_t valuesDump(void); char * valueGet(char * name, char * value); + char * valueGet_P(const char * name, char * value); boolean listDelete(); unsigned char calcChecksum(char *etiquette, char *valeur) ; From b889a97bc1ccb8a128b809bbc19a6c7d93de2e2f Mon Sep 17 00:00:00 2001 From: Charles Date: Mon, 15 Jun 2020 14:47:39 +0200 Subject: [PATCH 19/24] Use PSTR for labels values --- tasmota/xnrg_15_teleinfo.ino | 97 ++++++++++++++++++++++-------------- 1 file changed, 60 insertions(+), 37 deletions(-) diff --git a/tasmota/xnrg_15_teleinfo.ino b/tasmota/xnrg_15_teleinfo.ino index 97dfca314..aefced128 100644 --- a/tasmota/xnrg_15_teleinfo.ino +++ b/tasmota/xnrg_15_teleinfo.ino @@ -54,6 +54,17 @@ enum TInfoTarif{ TARIF_PR // Heures Pleines Jours Rouges. }; +// Label received +const char LABEL_HCHC[] PROGMEM = "HCHC"; +const char LABEL_HCHP[] PROGMEM = "HCHP"; +const char LABEL_PTEC[] PROGMEM = "PTEC"; +const char LABEL_PAPP[] PROGMEM = "PAPP"; +const char LABEL_IINST[] PROGMEM = "IINST"; +const char LABEL_TENSION[] PROGMEM = "TENSION"; + +// Some Values with string to compare to +const char VALUE_HCDD[] PROGMEM = "HC.."; + const char kTARIF_TH[] PROGMEM = "Toutes"; const char kTARIF_HC[] PROGMEM = "Creuses"; const char kTARIF_HP[] PROGMEM = "Pleines"; @@ -121,24 +132,24 @@ void DataCallback(struct _ValueList * me, uint8_t flags) if (flags & TINFO_FLAGS_UPDATED) { c = '*'; } // Current tarif - if (!strcmp("PTEC", me->name)) + if (!strcmp_P(LABEL_PTEC, me->name)) { - if (!strcmp("TH..", me->name)) { tarif = TARIF_TH; } - else if (!strcmp("HC..", me->name)) { tarif = TARIF_HC; } - else if (!strcmp("HP..", me->name)) { tarif = TARIF_HP; } - else if (!strcmp("HN..", me->name)) { tarif = TARIF_HN; } - else if (!strcmp("PM..", me->name)) { tarif = TARIF_PM; } - else if (!strcmp("HCJB", me->name)) { tarif = TARIF_CB; } - else if (!strcmp("HCJW", me->name)) { tarif = TARIF_CW; } - else if (!strcmp("HCJR", me->name)) { tarif = TARIF_CR; } - else if (!strcmp("HPJB", me->name)) { tarif = TARIF_PB; } - else if (!strcmp("HPJW", me->name)) { tarif = TARIF_PW; } - else if (!strcmp("HPJR", me->name)) { tarif = TARIF_PR; } + if (!strcmp_P("TH..", me->name)) { tarif = TARIF_TH; } + else if (!strcmp_P("HC..", me->name)) { tarif = TARIF_HC; } + else if (!strcmp_P("HP..", me->name)) { tarif = TARIF_HP; } + else if (!strcmp_P("HN..", me->name)) { tarif = TARIF_HN; } + else if (!strcmp_P("PM..", me->name)) { tarif = TARIF_PM; } + else if (!strcmp_P("HCJB", me->name)) { tarif = TARIF_CB; } + else if (!strcmp_P("HCJW", me->name)) { tarif = TARIF_CW; } + else if (!strcmp_P("HCJR", me->name)) { tarif = TARIF_CR; } + else if (!strcmp_P("HPJB", me->name)) { tarif = TARIF_PB; } + else if (!strcmp_P("HPJW", me->name)) { tarif = TARIF_PW; } + else if (!strcmp_P("HPJR", me->name)) { tarif = TARIF_PR; } AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TIC: Tarif changed, now '%s' (%d)"), me->value, tarif); } // Voltage V (not present on all Smart Meter) - else if (!strcmp("TENSION", me->name)) + else if (!strcmp_P(LABEL_TENSION, me->name)) { Energy.voltage_available = true; int i = atoi(me->value); @@ -152,7 +163,7 @@ void DataCallback(struct _ValueList * me, uint8_t flags) AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TIC: Voltage %s, now %d"), me->value, i); } // Current I - else if (!strcmp("IINST", me->name)) + else if (!strcmp_P(LABEL_IINST, me->name)) { if (!Energy.voltage_available) { int i = atoi(me->value); @@ -164,7 +175,7 @@ void DataCallback(struct _ValueList * me, uint8_t flags) AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TIC: Current %s, now %d"), me->value, (int) Energy.current[0]); } // Current P - else if (!strcmp("PAPP", me->name)) + else if (!strcmp_P(LABEL_PAPP, me->name)) { int papp = atoi(me->value); Energy.active_power[0] = (float) atoi(me->value); @@ -176,15 +187,15 @@ void DataCallback(struct _ValueList * me, uint8_t flags) } } // kWh indexes - else if (!strcmp("HCHC", me->name) || !strcmp("HCHP", me->name)) + else if (!strcmp_P(LABEL_HCHC, me->name) || !strcmp(LABEL_HCHP, me->name)) { char value[32]; unsigned long hc = 0; unsigned long hp = 0; unsigned long total = 0; - if ( tinfo.valueGet((char *)"HCHC", value) ) { hc = atol(value);} - if ( tinfo.valueGet((char *)"HCHP", value) ) { hp = atol(value);} + if ( tinfo.valueGet_P(LABEL_HCHC, value) ) { hc = atol(value);} + if ( tinfo.valueGet_P(LABEL_HCHP, value) ) { hp = atol(value);} total = hc+hp; EnergyUpdateTotal(total/1000.0f, true); @@ -214,9 +225,9 @@ Input : label to search for Output : value filled Comments: - ====================================================================== */ -char * getDataValue(char * label, char * value) +char * getDataValue_P(const char * label, char * value) { - if (!tinfo.valueGet(label, value) ) { + if (!tinfo.valueGet_P(label, value) ) { *value = '\0'; } return value; @@ -245,37 +256,49 @@ void TInfoInit(void) if (PinUsed(GPIO_TELEINFO_RX)) { - AddLog_P2(LOG_LEVEL_INFO, PSTR("TIC: enable receive on GPIO%d"), GPIO_TELEINFO_RX); + uint8_t rx_pin = Pin(GPIO_TELEINFO_RX); + AddLog_P2(LOG_LEVEL_INFO, PSTR("TIC: RX on GPIO%d"), rx_pin); // Enable Teleinfo if (PinUsed(GPIO_TELEINFO_ENABLE)) { - pinMode(GPIO_TELEINFO_ENABLE, OUTPUT); - digitalWrite(GPIO_TELEINFO_ENABLE, HIGH); - AddLog_P2(LOG_LEVEL_INFO, PSTR("TIC: enable on GPIO%d"), GPIO_TELEINFO_ENABLE); + uint8_t en_pin = Pin(GPIO_TELEINFO_ENABLE); + pinMode(en_pin, OUTPUT); + digitalWrite(en_pin, HIGH); + AddLog_P2(LOG_LEVEL_INFO, PSTR("TIC: Enable with GPIO%d"), en_pin); } else { AddLog_P2(LOG_LEVEL_INFO, PSTR("TIC: always enabled")); } - TInfoSerial = new TasmotaSerial(Pin(GPIO_TELEINFO_RX), -1, 1); + TInfoSerial = new TasmotaSerial(rx_pin, -1, 1); // pinMode(GPIO_TELEINFO_RX, INPUT_PULLUP); // Trick here even using SERIAL_7E1 or TS_SERIAL_7E1 // this is not working, need to call SetSerialConfig after - if (TInfoSerial->begin(TINFO_SPEED, TS_SERIAL_7E1)) + if (TInfoSerial->begin(TINFO_SPEED)) { + #if defined (ESP8266) + if (TInfoSerial->hardwareSerial() ) { + ClaimSerial(); + AddLog_P2(LOG_LEVEL_INFO, PSTR("TIC: using hardware serial")); + } else { + AddLog_P2(LOG_LEVEL_INFO, PSTR("TIC: using software serial")); + } + // This is a dirty hack, looks like begin does not take into account // the TS_SERIAL_7E1 configuration so on ESP8266 this is // working only on Serial RX pin (Hardware Serial) for now SetSerialConfig(TS_SERIAL_7E1); - - if (TInfoSerial->hardwareSerial()) { - ClaimSerial(); - } + TInfoSerial->setTimeout(TINFO_READ_TIMEOUT); + #elif defined (ESP32) + AddLog_P2(LOG_LEVEL_INFO, PSTR("TIC: using ESP32 hardware serial")); + #endif + + // Init teleinfo tinfo.init(); @@ -329,28 +352,28 @@ void TInfoShow(bool json) // TBD if (json) { - if ( tinfo.valueGet((char *)"PTEC", value) ) { + if ( tinfo.valueGet_P(LABEL_PTEC, value) ) { ResponseAppend_P(PSTR(",\"" "TARIF" "\":%s"), value); } - if ( tinfo.valueGet((char *)"IINST", value) ) { + if ( tinfo.valueGet_P(LABEL_IINST, value) ) { ResponseAppend_P(PSTR(",\"" D_CURRENT "\":%s"), value); } - if ( tinfo.valueGet((char *)"PAPP", value) ) { + if ( tinfo.valueGet_P(LABEL_PAPP, value) ) { ResponseAppend_P(PSTR(",\"" D_POWERUSAGE "\":%s"), value); } - if ( tinfo.valueGet((char *)"HCHC", value) ) { + if ( tinfo.valueGet_P(LABEL_HCHC, value) ) { ResponseAppend_P(PSTR(",\"" "HC" "\":%s"), value); } - if ( tinfo.valueGet((char *)"HCHP", value) ) { + if ( tinfo.valueGet_P(LABEL_HCHP, value) ) { ResponseAppend_P(PSTR(",\"" "HP" "\":%s"), value); } #ifdef USE_WEBSERVER } else { - getDataValue("HCHC", value); + getDataValue_P(LABEL_HCHC, value); WSContentSend_PD(HTTP_ENERGY_INDEX_TELEINFO, kTARIF_HC, value); - getDataValue("HCHP", value); + getDataValue_P(LABEL_HCHP, value); WSContentSend_PD(HTTP_ENERGY_INDEX_TELEINFO, kTARIF_HP, value); if (tarif) { WSContentSend_PD(HTTP_ENERGY_TARIF_TELEINFO, kTtarifNames[tarif-1]); From 93a38e892c1b4f0096841ccc078deb12c4c195fe Mon Sep 17 00:00:00 2001 From: Charles Date: Mon, 15 Jun 2020 21:52:47 +0200 Subject: [PATCH 20/24] @s-hadinger requests before merging PR --- RELEASENOTES.md | 4 ++-- tasmota/tasmota_template.h | 24 ++---------------------- 2 files changed, 4 insertions(+), 24 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 608cb67c9..af9be6756 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -54,8 +54,6 @@ The following binary downloads have been compiled with ESP8266/Arduino library c ### Version 8.3.1.3 -- Created Energy sensor (Denky) for French Smart Metering meter provided by global Energy Providers, need a adaptater. See dedicated full [blog](http://hallard.me/category/tinfo/) about French teleinformation stuff -- Added Library to be used for decoding Teleinfo (French Metering Smart Meter) - Change IRremoteESP8266 library updated to v2.7.7 - Change Adafruit_SGP30 library from v1.0.3 to v1.2.0 (#8519) - Change Energy JSON Total field from ``"Total":[33.736,11.717,16.978]`` to ``"Total":33.736,"TotalTariff":[11.717,16.978]`` @@ -81,3 +79,5 @@ The following binary downloads have been compiled with ESP8266/Arduino library c - Add initial support for Telegram bot (#8619) - Add support for HP303B Temperature and Pressure sensor by Robert Jaakke (#8638) - Add rule trigger ``System#Init`` to allow early rule execution without wifi and mqtt initialized yet +- Created Energy sensor (Denky) for French Smart Metering meter provided by global Energy Providers, need a adaptater. See dedicated full [blog](http://hallard.me/category/tinfo/) about French teleinformation stuff +- Added Library to be used for decoding Teleinfo (French Metering Smart Meter) diff --git a/tasmota/tasmota_template.h b/tasmota/tasmota_template.h index a0146aece..dab425f01 100644 --- a/tasmota/tasmota_template.h +++ b/tasmota/tasmota_template.h @@ -778,7 +778,7 @@ enum SupportedModules { SONOFF_S31, ZENGGE_ZF_WF017, SONOFF_POW_R2, SONOFF_IFAN02, BLITZWOLF_BWSHP, SHELLY1, SHELLY2, PHILIPS, NEO_COOLCAM, ESP_SWITCH, OBI, TECKIN, APLIC_WDP303075, TUYA_DIMMER, GOSUND, ARMTRONIX_DIMMERS, SK03_TUYA, PS_16_DZ, TECKIN_US, MANZOKU_EU_4, OBI2, YTF_IR_BRIDGE, DIGOO, KA10, ZX2820, MI_DESK_LAMP, SP10, WAGA, SYF05, SONOFF_L1, - SONOFF_IFAN03, EXS_DIMMER, PWM_DIMMER, SONOFF_D1, DENKY, + SONOFF_IFAN03, EXS_DIMMER, PWM_DIMMER, SONOFF_D1, MAXMODULE}; #define USER_MODULE 255 @@ -791,7 +791,7 @@ const char kModuleNames[] PROGMEM = "Sonoff S31|Zengge WF017|Sonoff Pow R2|Sonoff iFan02|BlitzWolf SHP|Shelly 1|Shelly 2|Xiaomi Philips|Neo Coolcam|ESP Switch|" "OBI Socket|Teckin|AplicWDP303075|Tuya MCU|Gosund SP1 v23|ARMTR Dimmer|SK03 Outdoor|PS-16-DZ|Teckin US|Manzoku strip|" "OBI Socket 2|YTF IR Bridge|Digoo DG-SP202|KA10|Luminea ZX2820|Mi Desk Lamp|SP10|WAGA CHCZ02MB|SYF05|Sonoff L1|" - "Sonoff iFan03|EXS Dimmer|PWM Dimmer|Sonoff D1|Denky (Teleinfo)" + "Sonoff iFan03|EXS Dimmer|PWM Dimmer|Sonoff D1" ; const uint8_t kModuleNiceList[] PROGMEM = { @@ -2174,26 +2174,6 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { GPIO_LED1_INV, // GPIO13 WiFi Blue Led - Link and Power status 0, 0, 0, 0 }, - { // Denky (Teleinfo) Any ESP8266 device - GPIO_WS2812, // GPIO00 WS2812 RGB LED - GPIO_USER, // GPIO01 TX Serial RXD - GPIO_USER, // GPIO02 D4 Wemos DHT Shield - GPIO_TELEINFO_RX, // GPIO03 Smart Meter RX Serial - GPIO_I2C_SDA, // GPIO04 D2 Wemos I2C SDA - GPIO_I2C_SCL, // GPIO05 D1 Wemos I2C SCL - // GPIO06 (SD_CLK Flash) - // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) - // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) - GPIO_USER, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) - GPIO_USER, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) - // GPIO11 (SD_CMD Flash) - GPIO_USER, // GPIO12 D6 - GPIO_USER, // GPIO13 D7 - GPIO_USER, // GPIO14 D5 - GPIO_USER, // GPIO15 D8 - GPIO_USER, // GPIO16 D0 Wemos Wake - ADC0_USER // ADC0 A0 Analog input - }, { // SONOFF_IFAN03 - Sonoff iFan03 (ESP8285) GPIO_KEY1, // GPIO00 WIFI_KEY0 Button 1 GPIO_TXD, // GPIO01 ESP_TXD Serial RXD connection to P0.5 of RF microcontroller From 7a297d1828285b1c2500e201ee16e948b6f6a2e4 Mon Sep 17 00:00:00 2001 From: Charles Date: Mon, 15 Jun 2020 22:01:45 +0200 Subject: [PATCH 21/24] Added code size --- tasmota/tasmota_configurations.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tasmota/tasmota_configurations.h b/tasmota/tasmota_configurations.h index af10f9ce5..eb58d30e5 100644 --- a/tasmota/tasmota_configurations.h +++ b/tasmota/tasmota_configurations.h @@ -168,7 +168,7 @@ #define USE_DDSU666 // Add support for Chint DDSU666 Modbus energy monitor (+0k6 code) //#define USE_SOLAX_X1 // Add support for Solax X1 series Modbus log info (+3k1 code) //#define USE_LE01MR // Add support for F&F LE-01MR modbus energy meter (+2k code) -//#define USE_TELEINFO // Add support for French Energy Provider metering telemetry +//#define USE_TELEINFO // Add support for French Energy Provider metering telemetry (+5k2 code, +168 RAM + SmartMeter LinkedList Values RAM) #define USE_DHT // Add support for DHT11, AM2301 (DHT21, DHT22, AM2302, AM2321) and SI7021 Temperature and Humidity sensor #define USE_MAX31855 // Add support for MAX31855 K-Type thermocouple sensor using softSPI From a4e5b3e14ee6bb7b7ff9b5f1ab18eacfbc35020c Mon Sep 17 00:00:00 2001 From: Charles Date: Tue, 16 Jun 2020 18:58:56 +0200 Subject: [PATCH 22/24] Rebuild Travis CI --- tasmota/xnrg_15_teleinfo.ino | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tasmota/xnrg_15_teleinfo.ino b/tasmota/xnrg_15_teleinfo.ino index aefced128..6a8362233 100644 --- a/tasmota/xnrg_15_teleinfo.ino +++ b/tasmota/xnrg_15_teleinfo.ino @@ -296,6 +296,8 @@ void TInfoInit(void) #elif defined (ESP32) AddLog_P2(LOG_LEVEL_INFO, PSTR("TIC: using ESP32 hardware serial")); + // Waiting TasmotaSerial PR merged to change that + //TInfoSerial->reconf(TINFO_SPEED, SERIAL_7E1); #endif From 29f7506dd67e29bd96aa79eed25067c193811bc6 Mon Sep 17 00:00:00 2001 From: Charles Date: Wed, 17 Jun 2020 12:09:36 +0200 Subject: [PATCH 23/24] Fixed after Theo's review --- tasmota/tasmota_template.h | 4 ---- tasmota/tasmota_template_ESP32.h | 5 ++--- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/tasmota/tasmota_template.h b/tasmota/tasmota_template.h index 0543fc7cd..6be969043 100644 --- a/tasmota/tasmota_template.h +++ b/tasmota/tasmota_template.h @@ -692,10 +692,6 @@ const uint8_t kGpioNiceList[] PROGMEM = { #ifdef USE_AS3935 GPIO_AS3935, #endif -#ifdef USE_TCP_BRIDGE - AGPIO(GPIO_TCP_TX), // TCP Serial bridge - AGPIO(GPIO_TCP_RX), // TCP Serial bridge -#endif #ifdef USE_TELEINFO GPIO_TELEINFO_RX, GPIO_TELEINFO_ENABLE, diff --git a/tasmota/tasmota_template_ESP32.h b/tasmota/tasmota_template_ESP32.h index d85ec1a6f..8f599c5b1 100644 --- a/tasmota/tasmota_template_ESP32.h +++ b/tasmota/tasmota_template_ESP32.h @@ -225,7 +225,6 @@ const char kSensorNames[] PROGMEM = D_SENSOR_BL0940_RX "|" D_SENSOR_TCP_TXD "|" D_SENSOR_TCP_RXD "|" D_SENSOR_ETH_PHY_POWER "|" D_SENSOR_ETH_PHY_MDC "|" D_SENSOR_ETH_PHY_MDIO "|" - D_SENSOR_TCP_TXD "|" D_SENSOR_TCP_RXD "|" D_SENSOR_TELEINFO_RX "|" D_SENSOR_TELEINFO_ENABLE ; @@ -624,13 +623,13 @@ typedef struct MYTMPLT { /********************************************************************************************/ // Supported hardware modules enum SupportedModules { - WEMOS, ESP32_CAM_AITHINKER, ESP32_DENKY, + WEMOS, ESP32_CAM_AITHINKER, MAXMODULE}; #define USER_MODULE 255 const char kModuleNames[] PROGMEM = - "ESP32-DevKit|ESP32 Cam AiThinker|Denky (Teleinfo)"; + "ESP32-DevKit|ESP32 Cam AiThinker"; // Default module settings const uint8_t kModuleNiceList[MAXMODULE] PROGMEM = { From cf039ef7bf5c08e9bd6b1066f21f5b74c5bae04f Mon Sep 17 00:00:00 2001 From: Charles Date: Wed, 17 Jun 2020 12:42:08 +0200 Subject: [PATCH 24/24] Removed one denky reference --- tasmota/tasmota_template_ESP32.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tasmota/tasmota_template_ESP32.h b/tasmota/tasmota_template_ESP32.h index 8f599c5b1..6571dec1c 100644 --- a/tasmota/tasmota_template_ESP32.h +++ b/tasmota/tasmota_template_ESP32.h @@ -634,8 +634,7 @@ const char kModuleNames[] PROGMEM = // Default module settings const uint8_t kModuleNiceList[MAXMODULE] PROGMEM = { WEMOS, - ESP32_CAM_AITHINKER, - ESP32_DENKY + ESP32_CAM_AITHINKER }; const mytmplt kModules PROGMEM =