mirror of https://github.com/arendst/Tasmota.git
Merge pull request #11651 from hallard/teleinfo
Rewrite Teleinfo config settings
This commit is contained in:
commit
4426693170
|
@ -121,13 +121,13 @@ typedef union { // Restricted by MISRA-C Rule 18.4 bu
|
|||
uint32_t zerocross_dimmer : 1; // bit 17 (v8.3.1.4) - SetOption99 - (PWM Dimmer) Enable zerocross dimmer (1)
|
||||
uint32_t remove_zbreceived : 1; // bit 18 (v8.3.1.7) - SetOption100 - (Zigbee) Remove ZbReceived form JSON message (1)
|
||||
uint32_t zb_index_ep : 1; // bit 19 (v8.3.1.7) - SetOption101 - (Zigbee) Add the source endpoint as suffix to attributes, ex `Power3` (1) instead of `Power` (0) if sent from endpoint 3
|
||||
uint32_t teleinfo_baudrate : 1; // bit 20 (v8.4.0.1) - SetOption102 - (Teleinfo) Set Baud rate for Teleinfo communication to 1200 (0) or 9600 (1)
|
||||
uint32_t obsolete1 : 1; // bit 20 (v9.3.1.3) - SetOption102 - teleinfo_baudrate Obsolete Teleinfo config has now a dedicated bit field
|
||||
uint32_t mqtt_tls : 1; // bit 21 (v8.4.0.1) - SetOption103 - (MQTT TLS) Enable TLS mode (1) (requires TLS version)
|
||||
uint32_t mqtt_no_retain : 1; // bit 22 (v8.4.0.1) - SetOption104 - (MQTT) No Retain (1) - disable all MQTT retained messages, some brokers don't support it: AWS IoT, Losant
|
||||
uint32_t white_blend_mode : 1; // bit 23 (v8.4.0.1) - SetOption105 - (Light) White Blend Mode (1) - used to be `RGBWWTable` last value `0`, now deprecated in favor of this option
|
||||
uint32_t virtual_ct : 1; // bit 24 (v8.4.0.1) - SetOption106 - (Light) Virtual CT (1) - Creates a virtual White ColorTemp for RGBW lights
|
||||
uint32_t virtual_ct_cw : 1; // bit 25 (v8.4.0.1) - SetOption107 - (Light) Virtual CT Channel (1) - signals whether the hardware white is cold CW (true) or warm WW (false)
|
||||
uint32_t teleinfo_rawdata : 1; // bit 26 (v8.4.0.2) - SetOption108 - (Teleinfo) Enable Teleinfo + Tasmota Energy device (0) or Teleinfo raw data only (1)
|
||||
uint32_t obsolete2 : 1; // bit 26 (v9.3.1.3) - SetOption108 - teleinfo_rawdata Obsolete Teleinfo config has now a dedicated bit field
|
||||
uint32_t alexa_gen_1 : 1; // bit 27 (v8.4.0.3) - SetOption109 - (Alexa) Gen1 mode (1) - if you only have Echo Dot 2nd gen devices
|
||||
uint32_t zb_disable_autobind : 1; // bit 28 (v8.5.0.1) - SetOption110 - (Zigbee) Disable auto-config (1) when pairing new devices
|
||||
uint32_t buzzer_freq_mode : 1; // bit 29 (v8.5.0.1) - SetOption111 - (Buzzer) Use frequency output (1) for buzzer pin instead of on/off signal (0)
|
||||
|
|
|
@ -38,6 +38,27 @@
|
|||
|
||||
#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 TELEINFO_COMMAND_SETTINGS[] PROGMEM = "TIC: Settings Mode:%s, Raw:%s, Skip:%d, Limit:%d";
|
||||
|
||||
#define MAX_TINFO_COMMAND_NAME 16+1 // Change this if one of the following kTInfo_Commands is higher then 16 char
|
||||
const char kTInfo_Commands[] PROGMEM = "historique|standard|noraw|full|changed|skip|limit";
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
|
||||
// All contract type for legacy, standard mode has in clear text
|
||||
enum TInfoContrat{
|
||||
CONTRAT_BAS = 1, // BASE => Option Base.
|
||||
|
@ -126,6 +147,7 @@ bool tinfo_found = false;
|
|||
int contrat;
|
||||
int tarif;
|
||||
int isousc;
|
||||
int raw_skip;
|
||||
|
||||
/*********************************************************************************************/
|
||||
|
||||
|
@ -366,15 +388,17 @@ 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
|
||||
Output : -
|
||||
: select if append all data or just changed one
|
||||
Output : false if asked for changed value and none has changed else true
|
||||
Comments: -
|
||||
====================================================================== */
|
||||
void ResponseAppendTInfo(char sep)
|
||||
bool ResponseAppendTInfo(char sep, bool all)
|
||||
{
|
||||
struct _ValueList * me = tinfo.getList();
|
||||
|
||||
char * p ;
|
||||
boolean isNumber ;
|
||||
bool isNumber ;
|
||||
bool hasValue = false;
|
||||
|
||||
// Loop thru all the teleinfo frame but
|
||||
// always check we don't buffer overflow of MQTT data
|
||||
|
@ -383,34 +407,41 @@ 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;
|
||||
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++;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* ======================================================================
|
||||
|
@ -425,15 +456,29 @@ 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 ) {
|
||||
Response_P(PSTR("{"));
|
||||
// send teleinfo full frame or only changed data
|
||||
bool hasData = ResponseAppendTInfo(' ', Settings.teleinfo.raw_report_changed ? false : true );
|
||||
ResponseJsonEnd();
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
// Reset frame skip counter (if 0 it's disabled)
|
||||
raw_skip = Settings.teleinfo.raw_skip;
|
||||
} else {
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("TIC: not sending yet, will do in %d frame(s)"), raw_skip);
|
||||
raw_skip--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -463,9 +508,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 +520,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 +579,180 @@ 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) {
|
||||
bool serviced = false;
|
||||
char command[CMDSZ];
|
||||
//uint8_t name_len = strlen(D_NAME_TELEINFO);
|
||||
|
||||
// At least "EnergyConfig"
|
||||
if (CMND_ENERGYCONFIG == Energy.command_code) {
|
||||
|
||||
AddLog_P(LOG_LEVEL_DEBUG, PSTR("TIC: len %d, data '%s'"), XdrvMailbox.data_len, XdrvMailbox.data ? XdrvMailbox.data : "null" );
|
||||
|
||||
// Just "EnergyConfig" no more parameter
|
||||
// Show Teleinfo configuration
|
||||
if (XdrvMailbox.data_len == 0) {
|
||||
|
||||
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);
|
||||
|
||||
AddLog_P(LOG_LEVEL_INFO, TELEINFO_COMMAND_SETTINGS, mode_name, raw_name, Settings.teleinfo.raw_skip, Settings.teleinfo.raw_limit);
|
||||
|
||||
serviced = true;
|
||||
|
||||
// At least "EnergyConfig xyz" plus one space and one (or more) char
|
||||
// so "EnergyConfig 0" or "EnergyConfig Teleinfo Standard"
|
||||
} else if (XdrvMailbox.data_len) {
|
||||
// Now point on parameter
|
||||
char *pParam = XdrvMailbox.data;
|
||||
char *p = pParam;
|
||||
char *pValue = nullptr;
|
||||
// Check for sub parameter ie : EnergyConfig Teleinfo Skip value
|
||||
while(*p) {
|
||||
if (*p == ' ') {
|
||||
if (*(p+1)) {
|
||||
// Skip parameter by emptying th string so below getcommandcode works
|
||||
*p++ = 0x00;
|
||||
// Save parameter value for later
|
||||
pValue = p;
|
||||
}
|
||||
break;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
|
||||
int command_code = GetCommandCode(command, sizeof(command), pParam, kTInfo_Commands);
|
||||
|
||||
AddLog_P(LOG_LEVEL_DEBUG, PSTR("TIC: param '%s' cmnd %d"), pParam, command_code);
|
||||
|
||||
switch (command_code) {
|
||||
case CMND_TELEINFO_STANDARD:
|
||||
case CMND_TELEINFO_HISTORIQUE: {
|
||||
char mode_name[MAX_TINFO_COMMAND_NAME];
|
||||
|
||||
// Get the mode name
|
||||
GetTextIndexed(mode_name, MAX_TINFO_COMMAND_NAME, command_code, kTInfo_Commands);
|
||||
|
||||
// Only if current settings is different than previous
|
||||
if ( (tinfo_mode==TINFO_MODE_STANDARD && command_code==CMND_TELEINFO_HISTORIQUE) ||
|
||||
(tinfo_mode==TINFO_MODE_HISTORIQUE && command_code==CMND_TELEINFO_STANDARD) ) {
|
||||
|
||||
// Cleanup Serial not sure it will works since
|
||||
// there is no end() or close() on tasmotaserial class
|
||||
if (TInfoSerial) {
|
||||
TInfoSerial->flush();
|
||||
//TInfoSerial->end();
|
||||
free(TInfoSerial);
|
||||
}
|
||||
|
||||
// Change mode
|
||||
Settings.teleinfo.mode_standard = command_code == CMND_TELEINFO_STANDARD ? 1 : 0;
|
||||
|
||||
AddLog_P(LOG_LEVEL_INFO, PSTR("TIC: '%s' mode"), mode_name);
|
||||
|
||||
// Re init teleinfo (LibTeleinfo always free linked list on init)
|
||||
TInfoInit();
|
||||
|
||||
serviced = true;
|
||||
|
||||
} else {
|
||||
AddLog_P(LOG_LEVEL_INFO, PSTR("TIC: No change to '%s' mode"), mode_name);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case CMND_TELEINFO_RAW_DISABLE:
|
||||
case CMND_TELEINFO_RAW_FULL:
|
||||
case CMND_TELEINFO_RAW_CHANGE: {
|
||||
|
||||
// Enable all RAW frame send
|
||||
char raw_name[MAX_TINFO_COMMAND_NAME];
|
||||
|
||||
// Get the raw name
|
||||
GetTextIndexed(raw_name, MAX_TINFO_COMMAND_NAME, command_code, kTInfo_Commands);
|
||||
|
||||
if (command_code == CMND_TELEINFO_RAW_DISABLE) {
|
||||
// disable raw mode
|
||||
Settings.teleinfo.raw_send = 0;
|
||||
} else {
|
||||
// enable raw mode
|
||||
Settings.teleinfo.raw_send = 1;
|
||||
Settings.teleinfo.raw_report_changed = command_code == CMND_TELEINFO_RAW_CHANGE ? 1 : 0;
|
||||
}
|
||||
|
||||
AddLog_P(LOG_LEVEL_INFO, PSTR("TIC: Raw to '%s'"), raw_name);
|
||||
serviced = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case CMND_TELEINFO_SKIP: {
|
||||
// Set Raw mode skip frame number
|
||||
char skip_name[MAX_TINFO_COMMAND_NAME];
|
||||
// Get the raw name
|
||||
GetTextIndexed(skip_name, MAX_TINFO_COMMAND_NAME, command_code, kTInfo_Commands);
|
||||
int l = strlen(skip_name);
|
||||
|
||||
// At least "EnergyConfig Teleinfo skip" plus one space and one (or more) digit
|
||||
// so "EnergyConfig Skip 0" or "EnergyConfig Skip 123"
|
||||
if ( pValue ) {
|
||||
int value = atoi(pValue);
|
||||
if (value >= 0 && value <= 255) {
|
||||
raw_skip = value;
|
||||
Settings.teleinfo.raw_skip = raw_skip;
|
||||
|
||||
if (raw_skip ==0) {
|
||||
AddLog_P(LOG_LEVEL_INFO, PSTR("TIC: Raw no skip"));
|
||||
} else {
|
||||
AddLog_P(LOG_LEVEL_INFO, PSTR("TIC: Raw each %d frame(s)"), raw_skip+1);
|
||||
}
|
||||
serviced = true;
|
||||
} else {
|
||||
AddLog_P(LOG_LEVEL_INFO, PSTR("TIC: skip can be 0 to 255"));
|
||||
}
|
||||
} else {
|
||||
AddLog_P(LOG_LEVEL_INFO, PSTR("TIC: no skip value"));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
AddLog_P(LOG_LEVEL_INFO, PSTR("TIC: bad cmd param '%s'"), pParam);
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
return serviced ;
|
||||
}
|
||||
|
||||
/* ======================================================================
|
||||
Function: TInfoProcess
|
||||
Purpose : Tasmota callback executed often enough to read serial
|
||||
|
@ -614,7 +829,7 @@ void TInfoShow(bool json)
|
|||
}
|
||||
|
||||
// add teleinfo full frame
|
||||
ResponseAppendTInfo(',');
|
||||
ResponseAppendTInfo(',', true);
|
||||
|
||||
#ifdef USE_WEBSERVER
|
||||
}
|
||||
|
@ -696,11 +911,16 @@ void TInfoShow(bool json)
|
|||
\*********************************************************************************************/
|
||||
bool Xnrg15(uint8_t function)
|
||||
{
|
||||
bool result = false;
|
||||
switch (function)
|
||||
{
|
||||
case FUNC_EVERY_250_MSECOND:
|
||||
TInfoProcess();
|
||||
break;
|
||||
case FUNC_COMMAND:
|
||||
result = TInfoCmd();
|
||||
break;
|
||||
|
||||
case FUNC_JSON_APPEND:
|
||||
TInfoShow(1);
|
||||
break;
|
||||
|
@ -716,7 +936,7 @@ bool Xnrg15(uint8_t function)
|
|||
TInfoDrvInit();
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif // USE_TELEINFO
|
||||
|
|
Loading…
Reference in New Issue