From 747dc2864251b2cf05f14c3e15aaad632c31b156 Mon Sep 17 00:00:00 2001 From: Charles Date: Tue, 20 Apr 2021 19:15:02 +0200 Subject: [PATCH 1/6] send also label name in ADPS callback --- lib/lib_div/LibTeleinfo/src/LibTeleinfo.cpp | 5 +++-- lib/lib_div/LibTeleinfo/src/LibTeleinfo.h | 6 +++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/lib_div/LibTeleinfo/src/LibTeleinfo.cpp b/lib/lib_div/LibTeleinfo/src/LibTeleinfo.cpp index 93ad25924..549df0688 100644 --- a/lib/lib_div/LibTeleinfo/src/LibTeleinfo.cpp +++ b/lib/lib_div/LibTeleinfo/src/LibTeleinfo.cpp @@ -17,6 +17,7 @@ // V2.00 2020-06-11 - Integration into Tasmota // V2.01 2020-08-11 - Merged LibTeleinfo official and Tasmota version // Added support for new standard mode of linky smart meter +// V2.02 2021-04-20 - Add label field to overload callback (ADPS) // // All text above must be included in any redistribution. // @@ -84,7 +85,7 @@ Input : callback function Output : - Comments: - ====================================================================== */ -void TInfo::attachADPS(void (*fn_ADPS)(uint8_t phase)) +void TInfo::attachADPS(void (*fn_ADPS)(uint8_t phase, char * label)) { // indicate the user callback _fn_ADPS = fn_ADPS; @@ -759,7 +760,7 @@ void TInfo::customLabel( char * plabel, char * pvalue, uint8_t * pflags) // Traitement de l'ADPS demandé par le sketch if (_fn_ADPS) - _fn_ADPS(phase); + _fn_ADPS(phase, plabel); } } diff --git a/lib/lib_div/LibTeleinfo/src/LibTeleinfo.h b/lib/lib_div/LibTeleinfo/src/LibTeleinfo.h index e5cb81486..1be54ff5f 100644 --- a/lib/lib_div/LibTeleinfo/src/LibTeleinfo.h +++ b/lib/lib_div/LibTeleinfo/src/LibTeleinfo.h @@ -129,7 +129,7 @@ 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_ADPS) (uint8_t, char *); typedef void (*_fn_data) (ValueList *, uint8_t); typedef void (*_fn_new_frame) (ValueList *); typedef void (*_fn_updated_frame) (ValueList *); @@ -140,7 +140,7 @@ class TInfo TInfo(); void init(_Mode_e mode); // mode MUST be specified _State_e process (char c); - void attachADPS(void (*_fn_ADPS)(uint8_t phase)); + void attachADPS(void (*_fn_ADPS)(uint8_t phase, char * label)); 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)); @@ -169,7 +169,7 @@ class TInfo char _separator; 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_ADPS)(uint8_t phase, char * label); void (*_fn_data)(ValueList * valueslist, uint8_t state); void (*_fn_new_frame)(ValueList * valueslist); void (*_fn_updated_frame)(ValueList * valueslist); From 16e07969004f09e7e6b82632a10a18a72c2c323c Mon Sep 17 00:00:00 2001 From: Charles Date: Tue, 20 Apr 2021 19:16:55 +0200 Subject: [PATCH 2/6] fix standard mode crash changed MQTT telemetry format with TIC object 3 phases management OK added blacklist label (to avoid too much MQTT buffer) --- tasmota/xnrg_15_teleinfo.ino | 288 +++++++++++++++++++++++------------ 1 file changed, 190 insertions(+), 98 deletions(-) diff --git a/tasmota/xnrg_15_teleinfo.ino b/tasmota/xnrg_15_teleinfo.ino index 75ff81cef..631851960 100755 --- a/tasmota/xnrg_15_teleinfo.ino +++ b/tasmota/xnrg_15_teleinfo.ino @@ -25,6 +25,8 @@ * * Denky ESP32 Teleinfo Template * {"NAME":"Denky (Teleinfo)","GPIO":[1,1,1,1,5664,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1376,1,1,0,0,0,0,1,5632,1,1,1,0,0,1],"FLAG":0,"BASE":1} + * Denky D4 ESP Pico V3 Teleinfo Template + * {"NAME":"DenkyD4","GPIO":[32,0,0,0,1,0,0,0,0,1,0,1,0,0,0,0,0,640,608,0,0,450,449,448,0,0,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":1} * * Denky (aka WifInfo) ESP8266 Teleinfo Template * {"NAME":"WifInfo v1.0a","GPIO":[17,255,255,255,6,5,255,255,7,210,255,255,255],"FLAG":15,"BASE":18} @@ -120,8 +122,9 @@ enum TInfoLabel{ LABEL_ADCO, LABEL_ADSC, LABEL_HCHC, LABEL_HCHP, LABEL_EAST, LABEL_EASF01, LABEL_EASF02, LABEL_OPTARIF, LABEL_NGTF, LABEL_ISOUSC, LABEL_PREF, LABEL_PTEC, LABEL_LTARF, LABEL_NTARF, - LABEL_PAPP, LABEL_SINSTS, LABEL_IINST, LABEL_IRMS1, LABEL_TENSION, LABEL_URMS1, - LABEL_IMAX, LABEL_PMAX, LABEL_SMAXSN, + LABEL_PAPP, LABEL_SINSTS, LABEL_IINST, LABEL_IINST1, LABEL_IINST2, LABEL_IINST3, LABEL_IRMS1, LABEL_IRMS2, LABEL_IRMS3, + LABEL_TENSION, LABEL_URMS1, LABEL_URMS2, LABEL_URMS3, + LABEL_IMAX, LABEL_IMAX1, LABEL_IMAX2, LABEL_IMAX3, LABEL_PMAX, LABEL_SMAXSN, LABEL_DEMAIN, LABEL_END }; @@ -130,11 +133,20 @@ const char kLabel[] PROGMEM = "|BASE|ADCO|ADSC" "|HCHC|HCHP|EAST|EASF01|EASF02" "|OPTARIF|NGTF|ISOUSC|PREF|PTEC|LTARF|NTARF" - "|PAPP|SINSTS|IINST|IRMS1|TENSION|URMS1" - "|IMAX|PMAX|SMAXSN" + "|PAPP|SINSTS|IINST|IINST1|IINST2|IINST3|IRMS1|IRMS2|IRMS3" + "|TENSION|URMS1|URMS2|URMS3" + "|IMAX|IMAX1|IMAX2|IMAX3|PMAX|SMAXSN" "|DEMAIN" ; +// Blacklisted label from telemetry +// Each label shoud be enclosed by pipe +const char kLabelBlacklist[] PROGMEM = + "|PJOURF+1" + "|MSG1" + "|" + ; + #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 @@ -142,8 +154,10 @@ const char kLabel[] PROGMEM = TInfo tinfo; // Teleinfo object TasmotaSerial *TInfoSerial = nullptr; _Mode_e tinfo_mode = TINFO_MODE_HISTORIQUE; +uint8_t tic_rx_pin = NOT_A_PIN; char serialNumber[13] = ""; // Serial number is 12 char long bool tinfo_found = false; +int nb_phase = 1; int contrat; int tarif; int isousc; @@ -175,11 +189,12 @@ Input : phase number 1 for ADIR1 triphase 2 for ADIR2 triphase 3 for ADIR3 triphase + label (different on Normal, 3 phases, historique or standard) Output : - Comments: should have been initialised with a tinfo.attachADPSCallback(ADPSCallback()) ====================================================================== */ -void ADPSCallback(uint8_t phase) +void ADPSCallback(uint8_t phase, char * label) { // n = phase number 1 to 3 if (phase == 0){ @@ -187,11 +202,11 @@ void ADPSCallback(uint8_t phase) } Response_P(PSTR("{")); - ResponseAppend_P(TasmotaGlobal.mqtt_data, sizeof(TasmotaGlobal.mqtt_data), PSTR("{\"%s\":{\"ADPS\":%i}}"), serialNumber, phase ); + ResponseAppend_P(TasmotaGlobal.mqtt_data, sizeof(TasmotaGlobal.mqtt_data), PSTR("{\"TIC\":{\"%s\":%i}}"), label, phase ); ResponseJsonEnd(); // Publish adding ADCO serial number into the topic - MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, serialNumber, false); + MqttPublishPrefixTopicRulesProcess_P(TELE, PSTR(D_RSLT_SENSOR), false); AddLog(LOG_LEVEL_INFO, PSTR("ADPS on phase %d"), phase); } @@ -266,14 +281,28 @@ void DataCallback(struct _ValueList * me, uint8_t flags) Energy.voltage_available = true; Energy.voltage[0] = (float) atoi(me->value); AddLog(LOG_LEVEL_DEBUG, PSTR("TIC: Voltage %s, now %d"), me->value, (int) Energy.voltage[0]); + } else if ( ilabel == LABEL_URMS2) { + Energy.voltage[1] = (float) atoi(me->value); + AddLog(LOG_LEVEL_DEBUG, PSTR("TIC: Voltage %s, now %d"), me->value, (int) Energy.voltage[1]); + } else if ( ilabel == LABEL_URMS3) { + nb_phase = 3; + Energy.voltage[2] = (float) atoi(me->value); + AddLog(LOG_LEVEL_DEBUG, PSTR("TIC: Voltage %s, now %d"), me->value, (int) Energy.voltage[2]); } - // Current I - else if (ilabel == LABEL_IINST || ilabel == LABEL_IRMS1) + // Current I phase 1 to 3 + else if (ilabel == LABEL_IINST || ilabel == LABEL_IINST1|| ilabel == LABEL_IRMS1) { Energy.current_available = true; Energy.current[0] = (float) atoi(me->value); AddLog(LOG_LEVEL_DEBUG, PSTR("TIC: Current %s, now %d"), me->value, (int) Energy.current[0]); + } else if (ilabel == LABEL_IINST2 || ilabel == LABEL_IRMS2) { + Energy.current[1] = (float) atoi(me->value); + AddLog(LOG_LEVEL_DEBUG, PSTR("TIC: Current %s, now %d"), me->value, (int) Energy.current[1]); + } else if (ilabel == LABEL_IINST3 || ilabel == LABEL_IRMS3) { + nb_phase = 3; + Energy.current[2] = (float) atoi(me->value); + AddLog(LOG_LEVEL_DEBUG, PSTR("TIC: Current %s, now %d"), me->value, (int) Energy.current[2]); } // Power P @@ -281,7 +310,7 @@ void DataCallback(struct _ValueList * me, uint8_t flags) { Energy.active_power[0] = (float) atoi(me->value);; AddLog(LOG_LEVEL_DEBUG, PSTR("TIC: Power %s, now %d"), me->value, (int) Energy.active_power[0]); - } + } // Wh indexes (legacy) else if ( ilabel == LABEL_HCHC || ilabel == LABEL_HCHP || ilabel == LABEL_BASE) @@ -383,6 +412,18 @@ void DataCallback(struct _ValueList * me, uint8_t flags) } } } + +/* ====================================================================== +Function: isBlacklistedLabel +Purpose : check is a label is blacklisted for telemetry data +Input : label name +Output : true if blacklisted +Comments: - +====================================================================== */ +bool isBlacklistedLabel(char * name) +{ + return strstr( kLabelBlacklist, name)==nullptr ? false : true; +} /* ====================================================================== Function: responseDumpTInfo @@ -408,39 +449,50 @@ bool ResponseAppendTInfo(char sep, bool all) if (me->name && me->value && *me->name && *me->value) { - // Add values only if we want all data or if data has changed - if (all || ( Settings.teleinfo.raw_report_changed && (me->flags & (TINFO_FLAGS_UPDATED | TINFO_FLAGS_ADDED | TINFO_FLAGS_ALERT) ) ) ) { + // Does this label blacklisted ? + if (!isBlacklistedLabel(me->name)) { - isNumber = true; - hasValue = true; - p = me->value; + // Add values only if we want all data or if data has changed + if (all || ( Settings.teleinfo.raw_report_changed && (me->flags & (TINFO_FLAGS_UPDATED | TINFO_FLAGS_ADDED | TINFO_FLAGS_ALERT) ) ) ) { - // Specific treatment serial number don't convert to number later - if (strcmp(me->name, "ADCO")==0 || strcmp(me->name, "ADSC")==0) { - isNumber = false; - } else { - // check if value is number - while (*p && isNumber) { - if ( *p < '0' || *p > '9' ) { - isNumber = false; + isNumber = true; + hasValue = true; + p = me->value; + + // Specific treatment serial number don't convert to number later + if (strcmp(me->name, "ADCO")==0 || strcmp(me->name, "ADSC")==0) { + isNumber = false; + } else { + // check if value is number + while (*p && isNumber) { + if ( *p < '0' || *p > '9' ) { + isNumber = false; + } + p++; } - p++; } + + // Avoid unneeded space + if (sep == ' ') { + ResponseAppend_P( PSTR("\"%s\":"), me->name ); + } else { + ResponseAppend_P( PSTR("%c\"%s\":"), sep, me->name ); + } + + if (!isNumber) { + ResponseAppend_P( PSTR("\"%s\""), me->value ); + } else { + ResponseAppend_P( PSTR("%d"), atoi(me->value)); + } + + // Now JSON separator is needed + sep =','; } - - ResponseAppend_P( PSTR("%c\"%s\":"), sep, me->name ); - - if (!isNumber) { - ResponseAppend_P( PSTR("\"%s\""), me->value ); - } else { - ResponseAppend_P( PSTR("%d"), atoi(me->value)); - } - - // Now JSON separator is needed - sep =','; } + } } + return hasValue; } @@ -461,16 +513,18 @@ void NewFrameCallback(struct _ValueList * me) if (Settings.teleinfo.raw_send) { // Do we need to skip this frame if (raw_skip == 0 ) { - Response_P(PSTR("{")); + Response_P(PSTR("{\"TIC\":{")); // send teleinfo full frame or only changed data bool hasData = ResponseAppendTInfo(' ', Settings.teleinfo.raw_report_changed ? false : true ); - ResponseJsonEnd(); + ResponseJsonEndEnd(); // Publish adding ADCO serial number into the topic // Need setOption4 to be enabled // No need to send empty payload if (hasData) { - MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, serialNumber, false); + //MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, serialNumber, false); + //MqttPublishPrefixTopicRulesProcess_P(TELE, serialNumber, false); + MqttPublishPrefixTopicRulesProcess_P(TELE, PSTR(D_RSLT_SENSOR), false); } // Reset frame skip counter (if 0 it's disabled) @@ -490,10 +544,24 @@ Output : - Comments: - ====================================================================== */ void TInfoDrvInit(void) { - if (PinUsed(GPIO_TELEINFO_RX)) { - TasmotaGlobal.energy_driver = XNRG_15; - Energy.voltage_available = false; - } + // If one TInfo RX pin declared use it + if (PinUsed(GPIO_TELEINFO_RX)) { + tic_rx_pin = Pin(GPIO_TELEINFO_RX); + } else { + // Case we are on denky V4 board without any TInfo RX pin selected + #ifdef ARDUINO_DENKY_PICOV3 + tic_rx_pin = 8; + AddLog(LOG_LEVEL_INFO, PSTR("TIC: Denky D4 board, RX on GPIO%d"), tic_rx_pin); + #endif + } + + // Enable teleinfo + if (tic_rx_pin != NOT_A_PIN) { + TasmotaGlobal.energy_driver = XNRG_15; + Energy.voltage_available = false; + } else { + AddLog(LOG_LEVEL_ERROR, PSTR("TIC: Device has no RX pin")); + } } /* ====================================================================== @@ -501,7 +569,8 @@ Function: TInfoInit Purpose : Tasmota core device init Input : - Output : - -Comments: - +Comments: this one is called (driver enabled) ONLY if + TInfoDrvInit has a valid teleinfo RX pin setup ====================================================================== */ void TInfoInit(void) { @@ -520,74 +589,70 @@ void TInfoInit(void) serial_buffer_size = TELEINFO_SERIAL_BUFFER_HISTORIQUE; } + AddLog(LOG_LEVEL_INFO, PSTR("TIC: RX on GPIO%d, baudrate %d"), tic_rx_pin, baudrate); - if (PinUsed(GPIO_TELEINFO_RX)) { - int8_t rx_pin = Pin(GPIO_TELEINFO_RX); - 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)) { - int8_t en_pin = Pin(GPIO_TELEINFO_ENABLE); - pinMode(en_pin, OUTPUT); - digitalWrite(en_pin, HIGH); - AddLog(LOG_LEVEL_INFO, PSTR("TIC: Enable with GPIO%d"), en_pin); - } else { - AddLog(LOG_LEVEL_INFO, PSTR("TIC: always enabled")); - } + // Enable Teleinfo pin used, control it + if (PinUsed(GPIO_TELEINFO_ENABLE)) { + int8_t en_pin = Pin(GPIO_TELEINFO_ENABLE); + pinMode(en_pin, OUTPUT); + digitalWrite(en_pin, HIGH); + AddLog(LOG_LEVEL_INFO, PSTR("TIC: Enable with GPIO%d"), en_pin); + } else { + AddLog(LOG_LEVEL_INFO, PSTR("TIC: always enabled")); + } #ifdef ESP8266 - // Allow GPIO3 AND GPIO13 with hardware fallback to 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); + // Allow GPIO3 AND GPIO13 with hardware fallback to 2 + // Set buffer to nnn char to support 250ms loop at 9600 baud + TInfoSerial = new TasmotaSerial(tic_rx_pin, -1, 2, 0, serial_buffer_size); + //pinMode(rx_pin, INPUT_PULLUP); #endif // ESP8266 #ifdef ESP32 - // Set buffer to nnn char to support 250ms loop at 9600 baud - TInfoSerial = new TasmotaSerial(rx_pin, -1, 1, 0, serial_buffer_size); + // Set buffer to nnn char to support 250ms loop at 9600 baud + TInfoSerial = new TasmotaSerial(tic_rx_pin, -1, 1, 0, serial_buffer_size); #endif // ESP32 - // Trick here even using SERIAL_7E1 or TS_SERIAL_7E1 - // this is not working, need to call SetSerialConfig after - if (TInfoSerial->begin(baudrate)) { + // Trick here even using SERIAL_7E1 or TS_SERIAL_7E1 + // this is not working, need to call SetSerialConfig after + if (TInfoSerial->begin(baudrate)) { #ifdef ESP8266 - if (TInfoSerial->hardwareSerial() ) { - ClaimSerial(); + if (TInfoSerial->hardwareSerial() ) { + ClaimSerial(); - // This is a 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 + // This is a 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); + //SetSerialConfig(TS_SERIAL_7E1); + //TInfoSerial->setTimeout(TINFO_READ_TIMEOUT); - AddLog(LOG_LEVEL_INFO, PSTR("TIC: using hardware serial")); - } else { - AddLog(LOG_LEVEL_INFO, PSTR("TIC: using software serial")); - } + AddLog(LOG_LEVEL_INFO, PSTR("TIC: using hardware serial")); + } else { + AddLog(LOG_LEVEL_INFO, PSTR("TIC: using software serial")); + } #endif // ESP8266 #ifdef ESP32 - SetSerialConfig(TS_SERIAL_7E1); - AddLog(LOG_LEVEL_INFO, PSTR("TIC: using ESP32 hardware serial")); + SetSerialConfig(TS_SERIAL_7E1); + AddLog(LOG_LEVEL_INFO, PSTR("TIC: using ESP32 hardware serial")); #endif // ESP32 - // Init teleinfo - tinfo.init(tinfo_mode); - // Attach needed callbacks - tinfo.attachADPS(ADPSCallback); - tinfo.attachData(DataCallback); - tinfo.attachNewFrame(NewFrameCallback); - tinfo_found = true; + // Init teleinfo + tinfo.init(tinfo_mode); + // Attach needed callbacks + tinfo.attachADPS(ADPSCallback); + tinfo.attachData(DataCallback); + tinfo.attachNewFrame(NewFrameCallback); + tinfo_found = true; - if (Settings.teleinfo.raw_send) { - raw_skip = Settings.teleinfo.raw_skip; - AddLog(LOG_LEVEL_INFO, PSTR("TIC: Raw mode enabled")); - if (raw_skip) { - AddLog(LOG_LEVEL_INFO, PSTR("TIC: Sending only one frame over %d "), raw_skip+1); - } - } - AddLog(LOG_LEVEL_INFO, PSTR("TIC: Ready")); + if (Settings.teleinfo.raw_send) { + raw_skip = Settings.teleinfo.raw_skip; + AddLog(LOG_LEVEL_INFO, PSTR("TIC: Raw mode enabled")); + if (raw_skip) { + AddLog(LOG_LEVEL_INFO, PSTR("TIC: Sending only one frame over %d "), raw_skip+1); + } } + AddLog(LOG_LEVEL_INFO, PSTR("TIC: Ready")); } } @@ -814,6 +879,11 @@ const char HTTP_ENERGY_CONTRAT_TELEINFO[] PROGMEM = "{s}" D_CONTRACT "{m}%s %d" const char HTTP_ENERGY_LOAD_TELEINFO[] PROGMEM = "{s}" D_POWER_LOAD "{m}%d" D_UNIT_PERCENT "{e}" ; const char HTTP_ENERGY_IMAX_TELEINFO[] PROGMEM = "{s}" D_MAX_CURRENT "{m}%d" D_UNIT_AMPERE "{e}" ; const char HTTP_ENERGY_PMAX_TELEINFO[] PROGMEM = "{s}" D_MAX_POWER "{m}%d" D_UNIT_WATT "{e}" ; +const char HTTP_ENERGY_LOAD_BAR[] PROGMEM = "
" + "
" + "load %d%%
" + "
\n"; + #endif // USE_WEBSERVER void TInfoShow(bool json) @@ -823,13 +893,17 @@ void TInfoShow(bool json) // Just add the raw label/values of the teleinfo frame if (json) { - // Calculated values + // Add new value (not part of TIC JSON Object) if (isousc) { ResponseAppend_P(PSTR(",\"Load\":%d"),(int) ((Energy.current[0]*100.0f) / isousc)); } + // Add TIC JSON Object + ResponseAppend_P(PSTR("},\"TIC\":{")); + // Calculated values // add teleinfo full frame - ResponseAppendTInfo(',', true); + ResponseAppendTInfo(' ', true); + //ResponseAppend_P(PSTR("}")); #ifdef USE_WEBSERVER } @@ -837,6 +911,26 @@ void TInfoShow(bool json) { char name[33]; char value[33]; + int percent; + + if (isousc) { + uint8_t hue; + uint8_t red, green, blue; + char phase_color[8]; + + for (int i=0; i 100) { + percent = 100; + } + // Gradiant from green (low load), yellow, roange and ending red (high load) + // Hue from 128 (green) to 0 (red) so reversed from percent + hue = changeUIntScale(100-percent, 0, 100, 0, 128); + HsToRgb(hue, 128, &red, &green, &blue); + snprintf_P(phase_color, sizeof(phase_color), PSTR("#%02X%02X%02X"), red, green, blue); + WSContentSend_PD (HTTP_ENERGY_LOAD_BAR, phase_color, percent, percent); + } + } if (tinfo_mode==TINFO_MODE_HISTORIQUE ) { if (getValueFromLabelIndex(LABEL_BASE, value) ) { @@ -863,10 +957,9 @@ void TInfoShow(bool json) WSContentSend_PD(HTTP_ENERGY_TARIF_TELEINFO, name); } if (contrat && isousc) { - int percent = (int) ((Energy.current[0]*100.0f) / isousc) ; GetTextIndexed(name, sizeof(name), contrat, kContratName); WSContentSend_PD(HTTP_ENERGY_CONTRAT_TELEINFO, name, isousc); - WSContentSend_PD(HTTP_ENERGY_LOAD_TELEINFO, percent); + //WSContentSend_PD(HTTP_ENERGY_LOAD_TELEINFO, percent); } } else if (tinfo_mode==TINFO_MODE_STANDARD ) { @@ -890,7 +983,6 @@ void TInfoShow(bool json) } if (getValueFromLabelIndex(LABEL_NGTF, value) ) { if (isousc) { - int percent = (int) ((Energy.current[0]*100.0f) / isousc) ; WSContentSend_PD(HTTP_ENERGY_CONTRAT_TELEINFO, value, isousc); WSContentSend_PD(HTTP_ENERGY_LOAD_TELEINFO, percent); } From e719c116dd664ab1cde35a6511b920386600508c Mon Sep 17 00:00:00 2001 From: Charles Date: Sat, 1 May 2021 18:32:03 +0200 Subject: [PATCH 3/6] process all data to Energy Module --- lib/lib_div/LibTeleinfo/src/LibTeleinfo.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/lib_div/LibTeleinfo/src/LibTeleinfo.cpp b/lib/lib_div/LibTeleinfo/src/LibTeleinfo.cpp index 549df0688..cdaa8aa9e 100644 --- a/lib/lib_div/LibTeleinfo/src/LibTeleinfo.cpp +++ b/lib/lib_div/LibTeleinfo/src/LibTeleinfo.cpp @@ -892,10 +892,14 @@ ValueList * TInfo::checkLine(char * pline) // this frame will for sure be updated _frame_updated = true; - // Do we need to advertise user callback - if (_fn_data) - _fn_data(me, flags); } + + // Tasmota need to to calulation on Energy Module + // So always pass data value even if it's the same than previous value + // Do we need to advertise user callback + if (_fn_data) + _fn_data(me, flags); + } } else From c644146b553301838eff8869cbb0f78a6c3901c5 Mon Sep 17 00:00:00 2001 From: Charles Date: Sat, 1 May 2021 18:32:29 +0200 Subject: [PATCH 4/6] Added 3 phases mode --- tasmota/xnrg_15_teleinfo.ino | 208 ++++++++++++++++++++--------------- 1 file changed, 117 insertions(+), 91 deletions(-) diff --git a/tasmota/xnrg_15_teleinfo.ino b/tasmota/xnrg_15_teleinfo.ino index 631851960..71c13ff32 100755 --- a/tasmota/xnrg_15_teleinfo.ino +++ b/tasmota/xnrg_15_teleinfo.ino @@ -141,7 +141,12 @@ const char kLabel[] PROGMEM = // Blacklisted label from telemetry // Each label shoud be enclosed by pipe +#ifdef ESP8266 +// dclared as progmem for ESP8266 crash on strstr +const char kLabelBlacklist[] = +#else const char kLabelBlacklist[] PROGMEM = +#endif "|PJOURF+1" "|MSG1" "|" @@ -157,7 +162,7 @@ _Mode_e tinfo_mode = TINFO_MODE_HISTORIQUE; uint8_t tic_rx_pin = NOT_A_PIN; char serialNumber[13] = ""; // Serial number is 12 char long bool tinfo_found = false; -int nb_phase = 1; +int serial_buffer_size; int contrat; int tarif; int isousc; @@ -202,7 +207,7 @@ void ADPSCallback(uint8_t phase, char * label) } Response_P(PSTR("{")); - ResponseAppend_P(TasmotaGlobal.mqtt_data, sizeof(TasmotaGlobal.mqtt_data), PSTR("{\"TIC\":{\"%s\":%i}}"), label, phase ); + ResponseAppend_P(TasmotaGlobal.mqtt_data, sizeof(TasmotaGlobal.mqtt_data), PSTR("\"TIC\":{\"%s\":%i}"), label, phase ); ResponseJsonEnd(); // Publish adding ADCO serial number into the topic @@ -224,22 +229,68 @@ void DataCallback(struct _ValueList * me, uint8_t flags) char c = ' '; int ilabel ; - // Does this value is new or changed? - if (flags & (TINFO_FLAGS_ADDED | TINFO_FLAGS_UPDATED) ) { - char labelName[16]; - // Find the label index - for ( ilabel = 1 ; ilabel < LABEL_END ; ilabel++) { - GetTextIndexed(labelName, sizeof(labelName), ilabel, kLabel); - if (!strcmp(labelName, me->name)) { - break; + char labelName[17]; + // Find the label index + for ( ilabel = 1 ; ilabel < LABEL_END ; ilabel++) { + GetTextIndexed(labelName, sizeof(labelName), ilabel, kLabel); + if (!strcmp(labelName, me->name)) { + break; + } + } + + // We found valid label + if (ilabelvalue); + AddLog(LOG_LEVEL_DEBUG, PSTR("TIC: Voltage %s=%s, now %d"), me->name, me->value, (int) volt); + + if ( ilabel == LABEL_URMS2) { + Energy.voltage[1] = volt; + } else if ( ilabel == LABEL_URMS3) { + Energy.voltage[2] = volt; + } else { + Energy.voltage[0] = volt; } } - if (flags & TINFO_FLAGS_ADDED) { c = '#'; } - if (flags & TINFO_FLAGS_UPDATED) { c = '*'; } - AddLog(LOG_LEVEL_DEBUG, PSTR("TIC: [%d]%c %s=%s"), ilabel, c , me->name, me->value); + // Current I phase 1 to 3 + else if (ilabel == LABEL_IINST + || ilabel == LABEL_IINST1 || ilabel == LABEL_IRMS1 + || ilabel == LABEL_IINST2 || ilabel == LABEL_IRMS2 + || ilabel == LABEL_IINST3 || ilabel == LABEL_IRMS3 ) + { + Energy.current_available = true; + float current = (float) atoi(me->value); + AddLog(LOG_LEVEL_DEBUG, PSTR("TIC: Current %s=%s, now %d"), me->name, me->value, (int) current); - if (ilabelvalue);; + AddLog(LOG_LEVEL_DEBUG, PSTR("TIC: Power %s, now %d"), me->value, (int) Energy.active_power[0]); + } + + // Ok now not so real time values Does this value is new or changed? + else if (flags & (TINFO_FLAGS_ADDED | TINFO_FLAGS_UPDATED) ) { + + if (flags & TINFO_FLAGS_ADDED) { c = '#'; } + if (flags & TINFO_FLAGS_UPDATED) { c = '*'; } + AddLog(LOG_LEVEL_DEBUG, PSTR("TIC: [%d]%c %s=%s"), ilabel, c , me->name, me->value); // Current tariff (legacy) if (ilabel == LABEL_PTEC) @@ -275,43 +326,6 @@ void DataCallback(struct _ValueList * me, uint8_t flags) AddLog(LOG_LEVEL_DEBUG, PSTR("TIC: Tariff index changed, now '%d'"), index); } - // Voltage V (not present on all Smart Meter) - else if ( ilabel == LABEL_TENSION || ilabel == LABEL_URMS1) - { - Energy.voltage_available = true; - Energy.voltage[0] = (float) atoi(me->value); - AddLog(LOG_LEVEL_DEBUG, PSTR("TIC: Voltage %s, now %d"), me->value, (int) Energy.voltage[0]); - } else if ( ilabel == LABEL_URMS2) { - Energy.voltage[1] = (float) atoi(me->value); - AddLog(LOG_LEVEL_DEBUG, PSTR("TIC: Voltage %s, now %d"), me->value, (int) Energy.voltage[1]); - } else if ( ilabel == LABEL_URMS3) { - nb_phase = 3; - Energy.voltage[2] = (float) atoi(me->value); - AddLog(LOG_LEVEL_DEBUG, PSTR("TIC: Voltage %s, now %d"), me->value, (int) Energy.voltage[2]); - } - - // Current I phase 1 to 3 - else if (ilabel == LABEL_IINST || ilabel == LABEL_IINST1|| ilabel == LABEL_IRMS1) - { - Energy.current_available = true; - Energy.current[0] = (float) atoi(me->value); - AddLog(LOG_LEVEL_DEBUG, PSTR("TIC: Current %s, now %d"), me->value, (int) Energy.current[0]); - } else if (ilabel == LABEL_IINST2 || ilabel == LABEL_IRMS2) { - Energy.current[1] = (float) atoi(me->value); - AddLog(LOG_LEVEL_DEBUG, PSTR("TIC: Current %s, now %d"), me->value, (int) Energy.current[1]); - } else if (ilabel == LABEL_IINST3 || ilabel == LABEL_IRMS3) { - nb_phase = 3; - Energy.current[2] = (float) atoi(me->value); - AddLog(LOG_LEVEL_DEBUG, PSTR("TIC: Current %s, now %d"), me->value, (int) Energy.current[2]); - } - - // Power P - else if (ilabel == LABEL_PAPP || ilabel == LABEL_SINSTS) - { - Energy.active_power[0] = (float) atoi(me->value);; - AddLog(LOG_LEVEL_DEBUG, PSTR("TIC: Power %s, now %d"), me->value, (int) Energy.active_power[0]); - } - // Wh indexes (legacy) else if ( ilabel == LABEL_HCHC || ilabel == LABEL_HCHP || ilabel == LABEL_BASE) { @@ -408,11 +422,10 @@ void DataCallback(struct _ValueList * me, uint8_t flags) strcpy(serialNumber, me->value); AddLog(LOG_LEVEL_DEBUG, PSTR("TIC: %s set to %s"), me->name, serialNumber); } - } } } - + /* ====================================================================== Function: isBlacklistedLabel Purpose : check is a label is blacklisted for telemetry data @@ -422,7 +435,15 @@ Comments: - ====================================================================== */ bool isBlacklistedLabel(char * name) { - return strstr( kLabelBlacklist, name)==nullptr ? false : true; + bool bl = false; + // return strstr( kLabelBlacklist, name)==nullptr ? false : true; + if ( strstr(kLabelBlacklist, name) ) { + //if ( strstr("|PJOURF+1|MSG1|ADCO|", name) ) { + bl = true; + AddLog(LOG_LEVEL_DEBUG, PSTR("TIC: %s is blacklisted"), name); + } + + return bl; } /* ====================================================================== @@ -489,7 +510,6 @@ bool ResponseAppendTInfo(char sep, bool all) sep =','; } } - } } @@ -522,8 +542,6 @@ void NewFrameCallback(struct _ValueList * me) // Need setOption4 to be enabled // No need to send empty payload if (hasData) { - //MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, serialNumber, false); - //MqttPublishPrefixTopicRulesProcess_P(TELE, serialNumber, false); MqttPublishPrefixTopicRulesProcess_P(TELE, PSTR(D_RSLT_SENSOR), false); } @@ -559,6 +577,7 @@ void TInfoDrvInit(void) { if (tic_rx_pin != NOT_A_PIN) { TasmotaGlobal.energy_driver = XNRG_15; Energy.voltage_available = false; + Energy.phase_count = 1; } else { AddLog(LOG_LEVEL_ERROR, PSTR("TIC: Device has no RX pin")); } @@ -569,13 +588,11 @@ Function: TInfoInit Purpose : Tasmota core device init Input : - Output : - -Comments: this one is called (driver enabled) ONLY if - TInfoDrvInit has a valid teleinfo RX pin setup +Comments: - ====================================================================== */ void TInfoInit(void) { int baudrate; - int serial_buffer_size; // Deprecated SetOption102 - Set Baud rate for Teleinfo serial communication (0 = 1200 or 1 = 9600) // now set in bit field TeleinfoCfg @@ -873,17 +890,18 @@ Comments: - const char HTTP_ENERGY_ID_TELEINFO[] PROGMEM = "{s}ID{m}%s{e}" ; const char HTTP_ENERGY_INDEX_TELEINFO[] PROGMEM = "{s}%s{m}%s " D_UNIT_WATTHOUR "{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_IINST_TELEINFO[] PROGMEM = "{s}" D_CURRENT "%s{m}%d " D_UNIT_AMPERE "{e}" ; const char HTTP_ENERGY_TARIF_TELEINFO[] PROGMEM = "{s}" D_CURRENT_TARIFF "{m}Heures %s{e}" ; const char HTTP_ENERGY_CONTRAT_TELEINFO[] PROGMEM = "{s}" D_CONTRACT "{m}%s %d" D_UNIT_AMPERE "{e}" ; const char HTTP_ENERGY_LOAD_TELEINFO[] PROGMEM = "{s}" D_POWER_LOAD "{m}%d" D_UNIT_PERCENT "{e}" ; const char HTTP_ENERGY_IMAX_TELEINFO[] PROGMEM = "{s}" D_MAX_CURRENT "{m}%d" D_UNIT_AMPERE "{e}" ; +const char HTTP_ENERGY_IMAX3_TELEINFO[] PROGMEM = "{s}" D_MAX_CURRENT "{m}%d / %d / %d " D_UNIT_AMPERE "{e}" ; const char HTTP_ENERGY_PMAX_TELEINFO[] PROGMEM = "{s}" D_MAX_POWER "{m}%d" D_UNIT_WATT "{e}" ; +const char HTTP_ENERGY_PMAX3_TELEINFO[] PROGMEM = "{s}" D_MAX_POWER "{m}%d / %d / %d " D_UNIT_WATT "{e}" ; const char HTTP_ENERGY_LOAD_BAR[] PROGMEM = "
" "
" - "load %d%%
" - "
\n"; - + "%d%%" + ""; #endif // USE_WEBSERVER void TInfoShow(bool json) @@ -898,19 +916,15 @@ void TInfoShow(bool json) ResponseAppend_P(PSTR(",\"Load\":%d"),(int) ((Energy.current[0]*100.0f) / isousc)); } - // Add TIC JSON Object - ResponseAppend_P(PSTR("},\"TIC\":{")); - // Calculated values // add teleinfo full frame - ResponseAppendTInfo(' ', true); - //ResponseAppend_P(PSTR("}")); + ResponseAppendTInfo(',', true); #ifdef USE_WEBSERVER } else { char name[33]; - char value[33]; + char value[33]; int percent; if (isousc) { @@ -918,80 +932,92 @@ void TInfoShow(bool json) uint8_t red, green, blue; char phase_color[8]; - for (int i=0; i 100) { percent = 100; } - // Gradiant from green (low load), yellow, roange and ending red (high load) + // Gradiant from green (low load), yellow, orange and ending red (high load) // Hue from 128 (green) to 0 (red) so reversed from percent hue = changeUIntScale(100-percent, 0, 100, 0, 128); HsToRgb(hue, 128, &red, &green, &blue); snprintf_P(phase_color, sizeof(phase_color), PSTR("#%02X%02X%02X"), red, green, blue); - WSContentSend_PD (HTTP_ENERGY_LOAD_BAR, phase_color, percent, percent); + WSContentSend_P(HTTP_ENERGY_LOAD_BAR, phase_color, percent, percent); } } if (tinfo_mode==TINFO_MODE_HISTORIQUE ) { if (getValueFromLabelIndex(LABEL_BASE, value) ) { GetTextIndexed(name, sizeof(name), LABEL_BASE, kLabel); - WSContentSend_PD(HTTP_ENERGY_INDEX_TELEINFO, name, value); + WSContentSend_P(HTTP_ENERGY_INDEX_TELEINFO, name, value); } if (getValueFromLabelIndex(LABEL_HCHC, value) ) { GetTextIndexed(name, sizeof(name), LABEL_HCHC, kLabel); - WSContentSend_PD(HTTP_ENERGY_INDEX_TELEINFO, name, value); + WSContentSend_P(HTTP_ENERGY_INDEX_TELEINFO, name, value); } if (getValueFromLabelIndex(LABEL_HCHP, value) ) { GetTextIndexed(name, sizeof(name), LABEL_HCHP, kLabel); - WSContentSend_PD(HTTP_ENERGY_INDEX_TELEINFO, name, value); + WSContentSend_P(HTTP_ENERGY_INDEX_TELEINFO, name, value); } - if (getValueFromLabelIndex(LABEL_IMAX, value) ) { - WSContentSend_PD(HTTP_ENERGY_IMAX_TELEINFO, atoi(value)); + if (Energy.phase_count==3) { + int imax[3]; + for (int i=LABEL_IMAX1; i<=LABEL_IMAX3; i++) { + if (getValueFromLabelIndex(i, value) ) { + imax[i-LABEL_IMAX1] = atoi(value); + } + } + WSContentSend_P(HTTP_ENERGY_IMAX3_TELEINFO, imax[0], imax[1], imax[2]); + } else { + if (getValueFromLabelIndex(LABEL_IMAX, value) ) { + WSContentSend_P(HTTP_ENERGY_IMAX_TELEINFO, atoi(value)); + } } + + if (getValueFromLabelIndex(LABEL_PMAX, value) ) { - WSContentSend_PD(HTTP_ENERGY_PMAX_TELEINFO, atoi(value)); + WSContentSend_P(HTTP_ENERGY_PMAX_TELEINFO, atoi(value)); } if (tarif) { GetTextIndexed(name, sizeof(name), tarif-1, kTarifName); - WSContentSend_PD(HTTP_ENERGY_TARIF_TELEINFO, name); + WSContentSend_P(HTTP_ENERGY_TARIF_TELEINFO, name); } if (contrat && isousc) { + int percent = (int) ((Energy.current[0]*100.0f) / isousc) ; GetTextIndexed(name, sizeof(name), contrat, kContratName); - WSContentSend_PD(HTTP_ENERGY_CONTRAT_TELEINFO, name, isousc); - //WSContentSend_PD(HTTP_ENERGY_LOAD_TELEINFO, percent); + WSContentSend_P(HTTP_ENERGY_CONTRAT_TELEINFO, name, isousc); + //WSContentSend_P(HTTP_ENERGY_LOAD_TELEINFO, percent); } } else if (tinfo_mode==TINFO_MODE_STANDARD ) { if (getValueFromLabelIndex(LABEL_EAST, value) ) { GetTextIndexed(name, sizeof(name), LABEL_EAST, kLabel); - WSContentSend_PD(HTTP_ENERGY_INDEX_TELEINFO, name, value); + WSContentSend_P(HTTP_ENERGY_INDEX_TELEINFO, name, value); } if (getValueFromLabelIndex(LABEL_EASF01, value) ) { GetTextIndexed(name, sizeof(name), LABEL_EASF01, kLabel); - WSContentSend_PD(HTTP_ENERGY_INDEX_TELEINFO, name, value); + WSContentSend_P(HTTP_ENERGY_INDEX_TELEINFO, name, value); } if (getValueFromLabelIndex(LABEL_EASF02, value) ) { GetTextIndexed(name, sizeof(name), LABEL_EASF02, kLabel); - WSContentSend_PD(HTTP_ENERGY_INDEX_TELEINFO, name, value); + WSContentSend_P(HTTP_ENERGY_INDEX_TELEINFO, name, value); } if (getValueFromLabelIndex(LABEL_SMAXSN, value) ) { - WSContentSend_PD(HTTP_ENERGY_PMAX_TELEINFO, atoi(value)); + WSContentSend_P(HTTP_ENERGY_PMAX_TELEINFO, atoi(value)); } if (getValueFromLabelIndex(LABEL_LTARF, value) ) { - WSContentSend_PD(HTTP_ENERGY_TARIF_TELEINFO, value); + WSContentSend_P(HTTP_ENERGY_TARIF_TELEINFO, value); } if (getValueFromLabelIndex(LABEL_NGTF, value) ) { if (isousc) { - WSContentSend_PD(HTTP_ENERGY_CONTRAT_TELEINFO, value, isousc); - WSContentSend_PD(HTTP_ENERGY_LOAD_TELEINFO, percent); + WSContentSend_P(HTTP_ENERGY_CONTRAT_TELEINFO, value, isousc); } } } // Serial number ADCO or ADSC if found if (*serialNumber) { - WSContentSend_PD(HTTP_ENERGY_ID_TELEINFO, serialNumber); + WSContentSend_P(HTTP_ENERGY_ID_TELEINFO, serialNumber); } #endif // USE_WEBSERVER @@ -1032,4 +1058,4 @@ bool Xnrg15(uint8_t function) } #endif // USE_TELEINFO -#endif // USE_ENERGY_SENSOR +#endif // USE_ENERGY_SENSOR \ No newline at end of file From 089495b9970721c5be210889a1de612c2255090b Mon Sep 17 00:00:00 2001 From: Charles Date: Sun, 2 May 2021 20:39:43 +0200 Subject: [PATCH 5/6] fixed strcmp_P by @barbudor --- tasmota/xnrg_15_teleinfo.ino | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tasmota/xnrg_15_teleinfo.ino b/tasmota/xnrg_15_teleinfo.ino index 71c13ff32..d6ddaa624 100755 --- a/tasmota/xnrg_15_teleinfo.ino +++ b/tasmota/xnrg_15_teleinfo.ino @@ -309,11 +309,11 @@ void DataCallback(struct _ValueList * me, uint8_t flags) // Current tariff (standard) else if (ilabel == LABEL_LTARF) { - if (!strcmp_P(TELEINFO_STD_TARIFF_BASE, me->value)) { + if (!strcmp_P(me->value, TELEINFO_STD_TARIFF_BASE)) { tarif = TARIF_TH; - } else if (!strcmp_P(TELEINFO_STD_TARIFF_HC, me->value)) { + } else if (!strcmp_P(me->value, TELEINFO_STD_TARIFF_HC)) { tarif = TARIF_HC; - } else if (!strcmp_P(TELEINFO_STD_TARIFF_HP, me->value)) { + } else if (!strcmp_P(me->value, TELEINFO_STD_TARIFF_HP)) { tarif = TARIF_HP; } AddLog(LOG_LEVEL_DEBUG, PSTR("TIC: Tariff name changed, now '%s'"), me->value); @@ -400,9 +400,9 @@ void DataCallback(struct _ValueList * me, uint8_t flags) // Contract subscribed (standard is in clear text in value) else if (ilabel == LABEL_NGTF) { - if (!strcmp_P(TELEINFO_STD_CONTRACT_BASE, me->value)) { + if (!strcmp_P(me->value, TELEINFO_STD_CONTRACT_BASE)) { contrat = CONTRAT_BAS; - } else if (!strcmp_P(TELEINFO_STD_CONTRACT_HCHP, me->value)) { + } else if (!strcmp_P(me->value, TELEINFO_STD_CONTRACT_HCHP)) { contrat = CONTRAT_HC; } From 74930eeed1357f592660e12f76ddcc2f54f93245 Mon Sep 17 00:00:00 2001 From: Charles Date: Sun, 2 May 2021 21:00:01 +0200 Subject: [PATCH 6/6] PROGMEM for ESP8266 crash with strstr --- tasmota/xnrg_15_teleinfo.ino | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/tasmota/xnrg_15_teleinfo.ino b/tasmota/xnrg_15_teleinfo.ino index d6ddaa624..75eef09a8 100755 --- a/tasmota/xnrg_15_teleinfo.ino +++ b/tasmota/xnrg_15_teleinfo.ino @@ -141,12 +141,12 @@ const char kLabel[] PROGMEM = // Blacklisted label from telemetry // Each label shoud be enclosed by pipe -#ifdef ESP8266 -// dclared as progmem for ESP8266 crash on strstr -const char kLabelBlacklist[] = -#else -const char kLabelBlacklist[] PROGMEM = +const char kLabelBlacklist[] +// declared as progmem for ESP8266 just crash and reset on strstr() +#ifndef ESP8266 +PROGMEM #endif + = "|PJOURF+1" "|MSG1" "|" @@ -843,7 +843,6 @@ Output : - Comments: - ====================================================================== */ //#define MEASURE_PERF // Define to enable performance measurments - void TInfoProcess(void) { static char buff[TELEINFO_PROCESS_BUFFER];