mirror of https://github.com/arendst/Tasmota.git
fix teleinfo standard mode
This commit is contained in:
parent
db678eb654
commit
b6d366870d
|
@ -69,12 +69,12 @@ void TInfo::init(_Mode_e mode)
|
|||
// We're in INIT in term of receive data
|
||||
_state = TINFO_INIT;
|
||||
|
||||
if ( mode == TINFO_MODE_STANDARD ) {
|
||||
_mode = mode;
|
||||
if ( _mode == TINFO_MODE_STANDARD ) {
|
||||
_separator = TINFO_HT;
|
||||
} else {
|
||||
_separator = ' ';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* ======================================================================
|
||||
|
@ -215,6 +215,8 @@ ValueList * TInfo::valueAdd(char * name, char * value, uint8_t checksum, uint8_t
|
|||
TI_Debug(F("' Not added bad checksum calculated '"));
|
||||
TI_Debug((char) thischeck);
|
||||
TI_Debugln(F("'"));
|
||||
AddLog(1, PSTR("LibTeleinfo::valueAdd Err checksum 0x%02X != 0x%02X"), thischeck, checksum);
|
||||
|
||||
} else {
|
||||
// Got one and all seems good ?
|
||||
if (me && lgname && lgvalue && checksum) {
|
||||
|
@ -640,10 +642,27 @@ Input : label name
|
|||
label timestamp
|
||||
Output : checksum
|
||||
Comments: return '\0' in case of error
|
||||
|
||||
Group format in legacy mode (Mode Historique) - Last space not included in checksum
|
||||
LF etiquette SP donnee SP Chk CR
|
||||
0A 20 20 0D
|
||||
\____check________/
|
||||
|
||||
|
||||
Group format in standard mode with timestamp (horodatage) - Last HT included in checksum
|
||||
LF etiquette HT horodatage HT donnee HT Chk CR
|
||||
0A 09 09 09 0D
|
||||
\____________checkum_______________/
|
||||
|
||||
Group format in standard mode without timestamp (horodatage) - Last HT included in checksum
|
||||
LF etiquette HT donnee HT Chk CR
|
||||
0A 09 09 0D
|
||||
\_____checkum________/
|
||||
|
||||
====================================================================== */
|
||||
unsigned char TInfo::calcChecksum(char *etiquette, char *valeur, char * horodate)
|
||||
{
|
||||
uint8_t sum = _separator ; // Somme des codes ASCII du message + un separateur
|
||||
uint8_t sum = (_mode == TINFO_MODE_HISTORIQUE) ? _separator : (2 * _separator); // Somme des codes ASCII du message + 2 separateurs
|
||||
|
||||
// avoid dead loop, always check all is fine
|
||||
if (etiquette && valeur) {
|
||||
|
@ -767,15 +786,19 @@ ValueList * TInfo::checkLine(char * pline)
|
|||
int sep =0;
|
||||
bool hasts = false ; // Assume timestamp on line
|
||||
|
||||
if (pline==NULL)
|
||||
if (pline==NULL) {
|
||||
//AddLog(3, PSTR("LibTeleinfo: Error 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 || len >= TINFO_BUFSIZE)
|
||||
if ( len < 7 || len >= TINFO_BUFSIZE) {
|
||||
//AddLog(3, PSTR("LibTeleinfo: Error len < 7 || len >= TINFO_BUFSIZE"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
p = &buff[0];
|
||||
sep = 0;
|
||||
|
@ -852,12 +875,14 @@ ValueList * TInfo::checkLine(char * pline)
|
|||
// Always check to avoid bad behavior
|
||||
if(strlen(ptok) && strlen(pvalue)) {
|
||||
// Is checksum is OK
|
||||
if ( calcChecksum(ptok,pvalue,pts) == checksum) {
|
||||
char calc_checksum = calcChecksum(ptok,pvalue,pts);
|
||||
if ( calc_checksum == 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);
|
||||
//AddLog(3, PSTR("LibTeleinfo: %s = %s"), ptok, pvalue);
|
||||
ValueList * me = valueAdd(ptok, pvalue, checksum, &flags, pts);
|
||||
|
||||
// value correctly added/changed
|
||||
if ( me ) {
|
||||
|
@ -872,6 +897,10 @@ ValueList * TInfo::checkLine(char * pline)
|
|||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AddLog(1, PSTR("LibTeleinfo::checkLine Err checksum 0x%02X != 0x%02X"), calc_checksum, checksum);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -899,6 +928,7 @@ _State_e TInfo::process(char c)
|
|||
switch (c) {
|
||||
// start of transmission ???
|
||||
case TINFO_STX:
|
||||
//AddLog(3, PSTR("LibTeleinfo: case TINFO_STX <<<<<<<<<<<<<<<<<<"));
|
||||
// Clear buffer, begin to store in it
|
||||
clearBuffer();
|
||||
|
||||
|
@ -909,12 +939,14 @@ _State_e TInfo::process(char c)
|
|||
// We were waiting fo this one ?
|
||||
if (_state == TINFO_INIT || _state == TINFO_WAIT_STX ) {
|
||||
TI_Debugln(F("TINFO_WAIT_ETX"));
|
||||
//AddLog(3, PSTR("LibTeleinfo: state => TINFO_WAIT_ETX"));
|
||||
_state = TINFO_WAIT_ETX;
|
||||
}
|
||||
break;
|
||||
|
||||
// End of transmission ?
|
||||
case TINFO_ETX:
|
||||
//AddLog(3, PSTR("LibTeleinfo: case TINFO_ETX >>>>>>>>>>>>>>>>>>"));
|
||||
|
||||
// Normal working mode ?
|
||||
if (_state == TINFO_READY) {
|
||||
|
@ -940,10 +972,12 @@ _State_e TInfo::process(char c)
|
|||
// We were waiting fo this one ?
|
||||
if (_state == TINFO_WAIT_ETX) {
|
||||
TI_Debugln(F("TINFO_READY"));
|
||||
//AddLog(3, PSTR("LibTeleinfo: state => TINFO_READY"));
|
||||
_state = TINFO_READY;
|
||||
}
|
||||
else if ( _state == TINFO_INIT) {
|
||||
TI_Debugln(F("TINFO_WAIT_STX"));
|
||||
//AddLog(3, PSTR("LibTeleinfo: state => TINFO_WAIT_STX"));
|
||||
_state = TINFO_WAIT_STX ;
|
||||
}
|
||||
|
||||
|
@ -953,10 +987,13 @@ _State_e TInfo::process(char c)
|
|||
case TINFO_SGR:
|
||||
// Do nothing we'll work at end of group
|
||||
// we can safely ignore this char
|
||||
//AddLog(3, PSTR("LibTeleinfo: case TINFO_SGR _recv_idx=%d"), _recv_idx);
|
||||
break;
|
||||
|
||||
// End of group \r ?
|
||||
case TINFO_EGR:
|
||||
//AddLog(3, PSTR("LibTeleinfo: case TINFO_EGR _recv_idx=%d"), _recv_idx);
|
||||
|
||||
// Are we ready to process ?
|
||||
if (_state == TINFO_READY) {
|
||||
// Store data recceived (we'll need it)
|
||||
|
@ -967,6 +1004,7 @@ _State_e TInfo::process(char c)
|
|||
memset(&_recv_buff[_recv_idx], 0, TINFO_BUFSIZE-_recv_idx);
|
||||
|
||||
// check the group we've just received
|
||||
//AddLog(3, PSTR("LibTeleinfo: Group received %d bytes %s"), _recv_idx, _recv_buff);
|
||||
checkLine(_recv_buff) ;
|
||||
|
||||
// Whatever error or not, we done
|
||||
|
@ -982,10 +1020,12 @@ _State_e TInfo::process(char c)
|
|||
// If buffer is not full, Store data
|
||||
if ( _recv_idx < TINFO_BUFSIZE)
|
||||
_recv_buff[_recv_idx++]=c;
|
||||
else
|
||||
else {
|
||||
AddLog(1, PSTR("LibTeleinfo: _recv_idx = %d/%d buffer overflow"), _recv_idx, TINFO_BUFSIZE);
|
||||
clearBuffer();
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -46,12 +46,13 @@
|
|||
// I prefix debug macro to be sure to use specific for THIS library
|
||||
// debugging, this should not interfere with main sketch or other
|
||||
// libraries
|
||||
void AddLog(uint32_t loglevel, PGM_P formatP, ...);
|
||||
#define TI_Errorf(...) AddLog(LOG_LEVEL_ERROR, __VA_ARGS__);
|
||||
#ifdef TI_DEBUG
|
||||
// Tasmota build
|
||||
#ifdef CODE_IMAGE_STR
|
||||
#define TI_Debug(x) AddLog_P2(LOG_LEVEL_DEBUG, x);
|
||||
#define TI_Debugln(x) AddLog_P2(LOG_LEVEL_DEBUG, x);
|
||||
#define TI_Debugf(...) AddLog_P2(LOG_LEVEL_DEBUG, __VA_ARGS__);
|
||||
// Only TI_Debugf() can work with Tasmota
|
||||
#define TI_Debugf(...) AddLog(LOG_LEVEL_DEBUG, __VA_ARGS__);
|
||||
#define TI_Debugflush {}
|
||||
#else
|
||||
#ifdef ESP8266
|
||||
|
@ -86,9 +87,7 @@ typedef struct _ValueList ValueList;
|
|||
struct _ValueList
|
||||
{
|
||||
ValueList *next; // next element
|
||||
//#ifdef USE_TELEINFO_STANDARD
|
||||
time_t ts; // TimeStamp of data if any
|
||||
//#endif
|
||||
uint8_t checksum;// checksum
|
||||
uint8_t flags; // specific flags
|
||||
char * name; // LABEL of value name
|
||||
|
@ -120,13 +119,8 @@ enum _State_e {
|
|||
#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
|
||||
#ifdef USE_TELEINFO_STANDARD
|
||||
// Linky and standard mode may have longer lines
|
||||
// maximum size for Standard
|
||||
#define TINFO_BUFSIZE 128
|
||||
#else
|
||||
#define TINFO_BUFSIZE 64
|
||||
#endif
|
||||
|
||||
// Teleinfo start and end of frame characters
|
||||
#define TINFO_STX 0x02
|
||||
|
@ -144,7 +138,7 @@ class TInfo
|
|||
{
|
||||
public:
|
||||
TInfo();
|
||||
void init(_Mode_e mode = TINFO_MODE_HISTORIQUE);
|
||||
void init(_Mode_e mode); // mode MUST be specified
|
||||
_State_e process (char c);
|
||||
void attachADPS(void (*_fn_ADPS)(uint8_t phase));
|
||||
void attachData(void (*_fn_data)(ValueList * valueslist, uint8_t state));
|
||||
|
@ -168,6 +162,7 @@ class TInfo
|
|||
void customLabel( char * plabel, char * pvalue, uint8_t * pflags) ;
|
||||
ValueList * checkLine(char * pline) ;
|
||||
|
||||
_Mode_e _mode; // Teleinfo mode (legacy/historique vs standard)
|
||||
_State_e _state; // Teleinfo machine state
|
||||
ValueList _valueslist; // Linked list of teleinfo values
|
||||
char _recv_buff[TINFO_BUFSIZE]; // line receive buffer
|
||||
|
|
|
@ -702,7 +702,6 @@
|
|||
#define LE01MR_ADDR 1 // LE-01MR modbus address (default: 0x01)
|
||||
#define USE_BL0940 // Add support for BL0940 Energy monitor as used in Blitzwolf SHP-10 (+1k6 code)
|
||||
//#define USE_TELEINFO // Add support for Teleinfo via serial RX interface (+5k2 code, +168 RAM + SmartMeter LinkedList Values RAM)
|
||||
// #define USE_TELEINFO_STANDARD // Use standard mode (9600 bps) else it's historical mode (1200 bps)
|
||||
//#define USE_IEM3000 // Add support for Schneider Electric iEM3000-Modbus series energy monitor (+0k8 code)
|
||||
#define IEM3000_SPEED 19200 // iEM3000-Modbus RS485 serial speed (default: 19200 baud)
|
||||
#define IEM3000_ADDR 1 // iEM3000-Modbus modbus address (default: 0x01)
|
||||
|
|
|
@ -105,6 +105,10 @@ const char kLabel[] PROGMEM =
|
|||
"|DEMAIN"
|
||||
;
|
||||
|
||||
#define TELEINFO_SERIAL_BUFFER_STANDARD 512 // Receive buffer size for Standard mode
|
||||
#define TELEINFO_SERIAL_BUFFER_HISTORIQUE 512 // Receive buffer size for Legacy mode
|
||||
#define TELEINFO_PROCESS_BUFFER 32 // Local processing buffer
|
||||
|
||||
TInfo tinfo; // Teleinfo object
|
||||
TasmotaSerial *TInfoSerial = nullptr;
|
||||
_Mode_e tinfo_mode = TINFO_MODE_HISTORIQUE;
|
||||
|
@ -202,19 +206,19 @@ void DataCallback(struct _ValueList * me, uint8_t flags)
|
|||
break;
|
||||
}
|
||||
}
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("TIC: Tarif changed, now '%s' (%d)"), me->value, tarif);
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("TIC: Tariff changed, now '%s' (%d)"), me->value, tarif);
|
||||
}
|
||||
|
||||
// Current tariff (standard is in clear text in value)
|
||||
else if (ilabel == LABEL_LTARF)
|
||||
{
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("TIC: Tarif name changed, now '%s'"), me->value);
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("TIC: Tariff name changed, now '%s'"), me->value);
|
||||
}
|
||||
// Current tariff (standard index is is in clear text in value)
|
||||
else if (ilabel == LABEL_NTARF)
|
||||
{
|
||||
tarif = atoi(me->value);
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("TIC: Tarif index changed, now '%d'"), tarif);
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("TIC: Tariff index changed, now '%d'"), tarif);
|
||||
}
|
||||
|
||||
|
||||
|
@ -409,7 +413,7 @@ void NewFrameCallback(struct _ValueList * me)
|
|||
ResponseJsonEnd();
|
||||
// Publish adding ADCO serial number into the topic
|
||||
// Need setOption4 to be enabled
|
||||
MqttPublishPrefixTopic_P(RESULT_OR_TELE, serialNumber, false);
|
||||
MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, serialNumber, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -437,21 +441,23 @@ Comments: -
|
|||
void TInfoInit(void)
|
||||
{
|
||||
int baudrate;
|
||||
int serial_buffer_size;
|
||||
|
||||
|
||||
// SetOption102 - Set Baud rate for Teleinfo serial communication (0 = 1200 or 1 = 9600)
|
||||
if (Settings.flag4.teleinfo_baudrate) {
|
||||
baudrate = 9600;
|
||||
tinfo_mode = TINFO_MODE_STANDARD;
|
||||
serial_buffer_size = TELEINFO_SERIAL_BUFFER_STANDARD;
|
||||
} else {
|
||||
baudrate = 1200;
|
||||
tinfo_mode = TINFO_MODE_HISTORIQUE;
|
||||
serial_buffer_size = TELEINFO_SERIAL_BUFFER_HISTORIQUE;
|
||||
}
|
||||
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("TIC: inferface speed %d bps"),baudrate);
|
||||
|
||||
if (PinUsed(GPIO_TELEINFO_RX)) {
|
||||
uint8_t rx_pin = Pin(GPIO_TELEINFO_RX);
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("TIC: RX on GPIO%d"), rx_pin);
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("TIC: RX on GPIO%d, baudrate %d"), rx_pin, baudrate);
|
||||
|
||||
// Enable Teleinfo pin used, control it
|
||||
if (PinUsed(GPIO_TELEINFO_ENABLE)) {
|
||||
|
@ -465,11 +471,13 @@ void TInfoInit(void)
|
|||
|
||||
#ifdef ESP8266
|
||||
// Allow GPIO3 AND GPIO13 with hardware fallback to 2
|
||||
TInfoSerial = new TasmotaSerial(rx_pin, -1, 2);
|
||||
// Set buffer to nnn char to support 250ms loop at 9600 baud
|
||||
TInfoSerial = new TasmotaSerial(rx_pin, -1, 2, 0, serial_buffer_size);
|
||||
//pinMode(rx_pin, INPUT_PULLUP);
|
||||
#endif // ESP8266
|
||||
#ifdef ESP32
|
||||
TInfoSerial = new TasmotaSerial(rx_pin, -1, 1);
|
||||
// Set buffer to nnn char to support 250ms loop at 9600 baud
|
||||
TInfoSerial = new TasmotaSerial(rx_pin, -1, 1, 0, serial_buffer_size);
|
||||
#endif // ESP32
|
||||
|
||||
// Trick here even using SERIAL_7E1 or TS_SERIAL_7E1
|
||||
|
@ -494,6 +502,7 @@ void TInfoInit(void)
|
|||
}
|
||||
#endif // ESP8266
|
||||
#ifdef ESP32
|
||||
SetSerialConfig(TS_SERIAL_7E1);
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("TIC: using ESP32 hardware serial"));
|
||||
#endif // ESP32
|
||||
// Init teleinfo
|
||||
|
@ -510,30 +519,47 @@ void TInfoInit(void)
|
|||
}
|
||||
|
||||
/* ======================================================================
|
||||
Function: TInfoEvery250ms
|
||||
Purpose : Tasmota callback executed every 250ms
|
||||
Function: TInfoProcess
|
||||
Purpose : Tasmota callback executed often enough to read serial
|
||||
Input : -
|
||||
Output : -
|
||||
Comments: -
|
||||
====================================================================== */
|
||||
void TInfoEvery250ms(void)
|
||||
//#define MEASURE_PERF // Define to enable performance measurments
|
||||
|
||||
void TInfoProcess(void)
|
||||
{
|
||||
static char buff[TELEINFO_PROCESS_BUFFER];
|
||||
#ifdef MEASURE_PERF
|
||||
static unsigned long max_time = 0;
|
||||
unsigned long duration = millis();
|
||||
static int max_size = 0;
|
||||
int tmp_size = 0;
|
||||
#endif
|
||||
|
||||
if (!tinfo_found) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (TInfoSerial->available()) {
|
||||
unsigned long start = millis();
|
||||
char c;
|
||||
|
||||
// We received some data, process but never more than 100ms ?
|
||||
while (TInfoSerial->available()>8 && millis()-start < 100) {
|
||||
// get char
|
||||
c = TInfoSerial->read();
|
||||
int size = TInfoSerial->read(buff,TELEINFO_PROCESS_BUFFER);
|
||||
while ( size ) {
|
||||
#ifdef MEASURE_PERF
|
||||
tmp_size += size;
|
||||
#endif
|
||||
// Process as many bytes as available in serial buffer
|
||||
for(int i = 0; size; i++, size--)
|
||||
{
|
||||
buff[i] &= 0x7F;
|
||||
// data processing
|
||||
tinfo.process(c & 0x7F);
|
||||
tinfo.process(buff[i]);
|
||||
}
|
||||
size = TInfoSerial->read(buff,TELEINFO_PROCESS_BUFFER);
|
||||
}
|
||||
#ifdef MEASURE_PERF
|
||||
duration = millis()-duration;
|
||||
if (duration > max_time) { max_time = duration; AddLog(LOG_LEVEL_INFO,PSTR("TIC: max_time=%lu"), max_time); }
|
||||
if (tmp_size > max_size) { max_size = tmp_size; AddLog(LOG_LEVEL_INFO,PSTR("TIC: max_size=%d"), max_size); }
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ======================================================================
|
||||
|
@ -641,7 +667,7 @@ bool Xnrg15(uint8_t function)
|
|||
switch (function)
|
||||
{
|
||||
case FUNC_EVERY_250_MSECOND:
|
||||
TInfoEvery250ms();
|
||||
TInfoProcess();
|
||||
break;
|
||||
case FUNC_JSON_APPEND:
|
||||
TInfoShow(1);
|
||||
|
|
Loading…
Reference in New Issue