diff --git a/tasmota/xnrg_15_teleinfo.ino b/tasmota/xnrg_15_teleinfo.ino index c1e0fc9d9..604936a82 100755 --- a/tasmota/xnrg_15_teleinfo.ino +++ b/tasmota/xnrg_15_teleinfo.ino @@ -38,6 +38,28 @@ #define TINFO_READ_TIMEOUT 400 +#define D_NAME_TELEINFO "Teleinfo" + +// Json Command +const char S_JSON_TELEINFO_COMMAND_STRING[] PROGMEM = "{\"" D_NAME_TELEINFO "\":{\"%s\":%s}}"; +const char S_JSON_TELEINFO_COMMAND_NVALUE[] PROGMEM = "{\"" D_NAME_TELEINFO "\":{\"%s\":%d}}"; +const char S_JSON_TELEINFO_COMMAND_SETTINGS[] PROGMEM = "{\"TIC_Settings\":{\"Mode\":%s,\"Raw\":%s,\"Skip\":%d,\"Limit\":%d}}"; + +#define MAX_TINFO_COMMAND_NAME 17 // Change this if one of the following kTInfo_Commands is higher then 16 char +const char kTInfo_Commands[] PROGMEM = "historique|standard|none|full|changed|skip|limit|config"; + +enum TInfoCommands { // commands for Console + CMND_TELEINFO_HISTORIQUE=0, // Set Legacy mode + CMND_TELEINFO_STANDARD, // Set Standard Mode + CMND_TELEINFO_RAW_DISABLE, // Disable Raw frame sending + CMND_TELEINFO_RAW_FULL, // Enable all RAW frame send + CMND_TELEINFO_RAW_CHANGE, // Enable only changed values RAW frame send + CMND_TELEINFO_SKIP, // Set number of frame to skip when raw mode is enabled + CMND_TELEINFO_LIMIT, // Limit RAW frame to values subject to fast change (Power, Current, ...), TBD + CMND_TELEINFO_CONFIG // Show Teleinfo current settings +}; + + // All contract type for legacy, standard mode has in clear text enum TInfoContrat{ CONTRAT_BAS = 1, // BASE => Option Base. @@ -126,6 +148,7 @@ bool tinfo_found = false; int contrat; int tarif; int isousc; +int raw_skip; /*********************************************************************************************/ @@ -366,10 +389,11 @@ void DataCallback(struct _ValueList * me, uint8_t flags) Function: responseDumpTInfo Purpose : add teleinfo values into JSON response Input : 1st separator space if begining of JSON, else comma + : select if append all data or just changed one Output : - Comments: - ====================================================================== */ -void ResponseAppendTInfo(char sep) +void ResponseAppendTInfo(char sep, bool all) { struct _ValueList * me = tinfo.getList(); @@ -383,32 +407,37 @@ void ResponseAppendTInfo(char sep) me = me->next; if (me->name && me->value && *me->name && *me->value) { - isNumber = 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; + // 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) ) ) ) { + + isNumber = 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++; } + + 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 =','; } } } @@ -425,15 +454,28 @@ void NewFrameCallback(struct _ValueList * me) // Reset Energy Watchdog Energy.data_valid[0] = 0; - // send teleinfo full frame only if setup like that - // see setOption108 - if (Settings.flag4.teleinfo_rawdata) { - Response_P(PSTR("{")); - ResponseAppendTInfo(' '); - ResponseJsonEnd(); - // Publish adding ADCO serial number into the topic - // Need setOption4 to be enabled - MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, serialNumber, false); + // Deprecated see setOption108 + // send teleinfo raw data only if setup like that + if (Settings.teleinfo.raw_send) { + // Do we need to skip this frame + if (raw_skip>0) { + raw_skip--; + } + + if (raw_skip == 0 ) { + Response_P(PSTR("{")); + // send teleinfo full frame or only changed data + ResponseAppendTInfo(' ', Settings.teleinfo.raw_report_changed ? false : true ); + ResponseJsonEnd(); + // Publish adding ADCO serial number into the topic + // Need setOption4 to be enabled + MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, serialNumber, false); + + // Reset frame skip counter (if 0 it's disabled) + raw_skip = Settings.teleinfo.raw_skip; + } else { + AddLog(LOG_LEVEL_INFO, PSTR("TIC: not sending yet, will do in %d frame(s)"), raw_skip); + } } } @@ -463,9 +505,9 @@ 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) { + // Deprecated SetOption102 - Set Baud rate for Teleinfo serial communication (0 = 1200 or 1 = 9600) + // now set in bit field TeleinfoCfg + if (Settings.teleinfo.mode_standard) { baudrate = 9600; tinfo_mode = TINFO_MODE_STANDARD; serial_buffer_size = TELEINFO_SERIAL_BUFFER_STANDARD; @@ -475,6 +517,7 @@ void TInfoInit(void) serial_buffer_size = TELEINFO_SERIAL_BUFFER_HISTORIQUE; } + 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); @@ -533,11 +576,80 @@ void TInfoInit(void) 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")); } } } + +/* ====================================================================== +Function: TInfoCmd +Purpose : Tasmota core command engine for Teleinfo commands +Input : - +Output : - +Comments: - +====================================================================== */ +bool TInfoCmd(void) { + char command[CMDSZ]; + + uint8_t name_len = strlen(D_NAME_TELEINFO); + + if (!strncasecmp_P(XdrvMailbox.topic, PSTR(D_NAME_TELEINFO), name_len)) { + + uint32_t command_code = GetCommandCode(command, sizeof(command), XdrvMailbox.topic + name_len, kTInfo_Commands); + switch (command_code) { + case CMND_TELEINFO_STANDARD: + case CMND_TELEINFO_HISTORIQUE: { + char mode_name[MAX_TINFO_COMMAND_NAME]; + if (XdrvMailbox.data_len) { + Settings.teleinfo.mode_standard = command_code == CMND_TELEINFO_STANDARD ? 1 : 0; + // Get the mode and raw name + GetTextIndexed(mode_name, MAX_TINFO_COMMAND_NAME, command_code, kTInfo_Commands); + } + Response_P(S_JSON_TELEINFO_COMMAND_STRING, command, mode_name); + } + break; + + case CMND_TELEINFO_CONFIG: { + if (!XdrvMailbox.data_len) { + char mode_name[MAX_TINFO_COMMAND_NAME]; + char raw_name[MAX_TINFO_COMMAND_NAME]; + + int index_mode = Settings.teleinfo.mode_standard ? CMND_TELEINFO_STANDARD : CMND_TELEINFO_HISTORIQUE; + int index_raw = Settings.teleinfo.raw_send ? CMND_TELEINFO_RAW_FULL : CMND_TELEINFO_RAW_DISABLE; + + if (Settings.teleinfo.raw_send && Settings.teleinfo.raw_report_changed) { + index_raw = CMND_TELEINFO_RAW_CHANGE; + } + + // Get the mode and raw name + GetTextIndexed(mode_name, MAX_TINFO_COMMAND_NAME, index_mode, kTInfo_Commands); + GetTextIndexed(raw_name, MAX_TINFO_COMMAND_NAME, index_raw, kTInfo_Commands); + + Response_P(S_JSON_TELEINFO_COMMAND_SETTINGS, mode_name, raw_name, Settings.teleinfo.raw_skip, Settings.teleinfo.raw_limit ); + } + } + break; + + default: + return false; + } + + return true; + + } else { + return false; + } +} + + /* ====================================================================== Function: TInfoProcess Purpose : Tasmota callback executed often enough to read serial @@ -614,7 +726,7 @@ void TInfoShow(bool json) } // add teleinfo full frame - ResponseAppendTInfo(','); + ResponseAppendTInfo(',', true); #ifdef USE_WEBSERVER } @@ -696,11 +808,17 @@ void TInfoShow(bool json) \*********************************************************************************************/ bool Xnrg15(uint8_t function) { + bool result = false; switch (function) { case FUNC_EVERY_250_MSECOND: TInfoProcess(); break; + case FUNC_COMMAND: + AddLog(LOG_LEVEL_INFO, PSTR("TIC: FUNC_COMMAND")); + result = TInfoCmd(); + break; + case FUNC_JSON_APPEND: TInfoShow(1); break; @@ -716,7 +834,7 @@ bool Xnrg15(uint8_t function) TInfoDrvInit(); break; } - return false; + return result; } #endif // USE_TELEINFO