mirror of https://github.com/arendst/Tasmota.git
Merge pull request #8695 from hallard/teleinfo
Prep for French Metering xnrg_15_teleinfo
This commit is contained in:
commit
5730ced6b8
|
@ -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 |
|
||||
|
|
|
@ -81,4 +81,6 @@ 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)
|
||||
- Add basic support for ESP32 ethernet adding commands ``Wifi 0/1`` and ``Ethernet 0/1`` both default ON
|
||||
|
|
|
@ -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`.
|
||||
<br/>
|
||||
Pour trouver votre dossier de sketchbook, dans l'environnement IDE, allez dans File>Preferences.
|
||||
<br/>
|
||||
allez voir ce [tutorial][2] sur les librairies Arduino si beoin.
|
||||
<br/>
|
||||
|
||||
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
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"name": "LibTeleinfo",
|
||||
"version": "1.1.2",
|
||||
"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": "*"
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
name=LibTeleinfo
|
||||
version=1.1.2
|
||||
author=Charles-Henri Hallard <hallard.me>
|
||||
maintainer=Charles-Henri Hallard <community.hallard.me>
|
||||
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=*
|
|
@ -0,0 +1,881 @@
|
|||
// **********************************************************************************
|
||||
// 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 "Arduino.h"
|
||||
#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) && strcmp(me->name, name)==0) {
|
||||
// Already got also this value return US
|
||||
if (lgvalue==strlen(me->value) && strcmp(me->value, value) == 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 + 1 );
|
||||
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 + 1 );
|
||||
return ( value );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// not found
|
||||
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
|
||||
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, pline, 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;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,147 @@
|
|||
// **********************************************************************************
|
||||
// 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
|
||||
|
||||
#include "Arduino.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
|
||||
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
|
||||
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
|
||||
|
||||
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:
|
||||
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);
|
||||
char * valueGet_P(const 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
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -600,6 +600,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)
|
||||
|
|
|
@ -584,7 +584,10 @@ void GetFeatures(void)
|
|||
#ifdef USE_TCP_BRIDGE
|
||||
feature6 |= 0x00020000; // xdrv_41_tcp_bridge.ino
|
||||
#endif
|
||||
// feature6 |= 0x00040000;
|
||||
#ifdef USE_TELEINFO
|
||||
feature6 |= 0x00040000; // xnrg_15_teleinfo.ino
|
||||
#endif
|
||||
|
||||
// feature6 |= 0x00080000;
|
||||
|
||||
// feature6 |= 0x00100000;
|
||||
|
|
|
@ -168,6 +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 (+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
|
||||
|
@ -264,6 +265,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)
|
||||
|
@ -354,6 +357,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)
|
||||
|
||||
|
@ -497,6 +501,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
|
||||
|
@ -622,6 +628,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
|
||||
|
|
|
@ -236,6 +236,8 @@ enum UserSelectablePins {
|
|||
GPIO_BL0940_RX, // BL0940 serial interface
|
||||
GPIO_TCP_TX, // TCP Serial bridge
|
||||
GPIO_TCP_RX, // TCP Serial bridge
|
||||
GPIO_TELEINFO_RX, // TELEINFO serial interface
|
||||
GPIO_TELEINFO_ENABLE,// TELEINFO Enable PIN
|
||||
GPIO_SENSOR_END };
|
||||
|
||||
// Programmer selectable GPIO functionality
|
||||
|
@ -326,8 +328,9 @@ 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_TCP_TXD "|" D_SENSOR_TCP_RXD
|
||||
D_SENSOR_BL0940_RX "|"
|
||||
D_SENSOR_TCP_TXD "|" D_SENSOR_TCP_RXD "|"
|
||||
D_SENSOR_TELEINFO_RX "|" D_SENSOR_TELEINFO_ENABLE
|
||||
;
|
||||
|
||||
const char kSensorNamesFixed[] PROGMEM =
|
||||
|
@ -689,6 +692,10 @@ const uint8_t kGpioNiceList[] PROGMEM = {
|
|||
#ifdef USE_AS3935
|
||||
GPIO_AS3935,
|
||||
#endif
|
||||
#ifdef USE_TELEINFO
|
||||
GPIO_TELEINFO_RX,
|
||||
GPIO_TELEINFO_ENABLE,
|
||||
#endif
|
||||
};
|
||||
|
||||
/********************************************************************************************/
|
||||
|
@ -2257,8 +2264,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
|
||||
|
|
|
@ -131,6 +131,8 @@ enum UserSelectablePins {
|
|||
GPIO_BL0940_RX, // BL0940 serial interface
|
||||
GPIO_TCP_TX, GPIO_TCP_RX, // TCP to serial bridge
|
||||
GPIO_ETH_PHY_POWER, GPIO_ETH_PHY_MDC, GPIO_ETH_PHY_MDIO, // Ethernet
|
||||
GPIO_TELEINFO_RX, // Teleinfo telemetry data receive pin
|
||||
GPIO_TELEINFO_ENABLE, // Teleinfo Enable Receive Pin
|
||||
GPIO_SENSOR_END };
|
||||
|
||||
enum ProgramSelectablePins {
|
||||
|
@ -222,7 +224,8 @@ const char kSensorNames[] PROGMEM =
|
|||
D_SENSOR_WINDMETER_SPEED "|" D_SENSOR_BUTTON "_tc|"
|
||||
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_ETH_PHY_POWER "|" D_SENSOR_ETH_PHY_MDC "|" D_SENSOR_ETH_PHY_MDIO "|"
|
||||
D_SENSOR_TELEINFO_RX "|" D_SENSOR_TELEINFO_ENABLE
|
||||
;
|
||||
|
||||
const char kSensorNamesFixed[] PROGMEM =
|
||||
|
@ -532,6 +535,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
|
||||
|
|
|
@ -0,0 +1,424 @@
|
|||
/*
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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 <TasmotaSerial.h>
|
||||
|
||||
#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
|
||||
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.
|
||||
};
|
||||
|
||||
// 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";
|
||||
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;
|
||||
bool tinfo_found = false;
|
||||
uint8_t contrat;
|
||||
uint8_t tarif;
|
||||
|
||||
/*********************************************************************************************/
|
||||
|
||||
/* ======================================================================
|
||||
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 = ' ';
|
||||
|
||||
// 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_P(LABEL_PTEC, me->name))
|
||||
{
|
||||
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_P(LABEL_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_P(LABEL_IINST, me->name))
|
||||
{
|
||||
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_P(LABEL_PAPP, me->name))
|
||||
{
|
||||
int papp = atoi(me->value);
|
||||
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_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_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);
|
||||
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_P(const char * label, char * value)
|
||||
{
|
||||
if (!tinfo.valueGet_P(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;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if (PinUsed(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))
|
||||
{
|
||||
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(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))
|
||||
{
|
||||
#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);
|
||||
|
||||
TInfoSerial->setTimeout(TINFO_READ_TIMEOUT);
|
||||
|
||||
#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
|
||||
|
||||
|
||||
// Init teleinfo
|
||||
tinfo.init();
|
||||
|
||||
// Attach needed callbacks
|
||||
tinfo.attachADPS(ADPSCallback);
|
||||
tinfo.attachData(DataCallback);
|
||||
tinfo.attachNewFrame(NewFrameCallback);
|
||||
|
||||
tinfo_found = true;
|
||||
AddLog_P2(LOG_LEVEL_INFO, PSTR("TIC: Ready"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TInfoLoop(void)
|
||||
{
|
||||
char c;
|
||||
if (!tinfo_found)
|
||||
return;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
if ( tinfo.valueGet_P(LABEL_PTEC, value) ) {
|
||||
ResponseAppend_P(PSTR(",\"" "TARIF" "\":%s"), value);
|
||||
}
|
||||
if ( tinfo.valueGet_P(LABEL_IINST, value) ) {
|
||||
ResponseAppend_P(PSTR(",\"" D_CURRENT "\":%s"), value);
|
||||
}
|
||||
if ( tinfo.valueGet_P(LABEL_PAPP, value) ) {
|
||||
ResponseAppend_P(PSTR(",\"" D_POWERUSAGE "\":%s"), value);
|
||||
}
|
||||
if ( tinfo.valueGet_P(LABEL_HCHC, value) ) {
|
||||
ResponseAppend_P(PSTR(",\"" "HC" "\":%s"), value);
|
||||
}
|
||||
if ( tinfo.valueGet_P(LABEL_HCHP, value) ) {
|
||||
ResponseAppend_P(PSTR(",\"" "HP" "\":%s"), value);
|
||||
}
|
||||
#ifdef USE_WEBSERVER
|
||||
}
|
||||
else
|
||||
{
|
||||
getDataValue_P(LABEL_HCHC, value);
|
||||
WSContentSend_PD(HTTP_ENERGY_INDEX_TELEINFO, kTARIF_HC, 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]);
|
||||
}
|
||||
|
||||
|
||||
#endif // USE_WEBSERVER
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Interface
|
||||
\*********************************************************************************************/
|
||||
|
||||
bool Xnrg15(uint8_t function)
|
||||
{
|
||||
|
||||
switch (function)
|
||||
{
|
||||
case FUNC_LOOP:
|
||||
if (TInfoSerial) { TInfoLoop(); }
|
||||
break;
|
||||
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
|
Loading…
Reference in New Issue