mirror of https://github.com/arendst/Tasmota.git
Merge pull request #9095 from hallard/teleinfo
Teleinfo Added setOption108
This commit is contained in:
commit
bfc027a638
|
@ -778,14 +778,13 @@ ValueList * TInfo::checkLine(char * pline)
|
|||
return NULL;
|
||||
|
||||
p = &buff[0];
|
||||
i = len + 1 ;
|
||||
sep = 0;
|
||||
// Get our own working copy and in the
|
||||
// meantime, calculate separator count for
|
||||
// standard mode (to know if timestamped data)
|
||||
while (i--) {
|
||||
// count separator
|
||||
if (*pline == _separator) {
|
||||
for (i=0 ; i<len ; i++) {
|
||||
// count separator, take care, checksum last one can be space separator
|
||||
if (*pline==_separator && *(pline+1)!='\r') {
|
||||
// Label + sep + Date + sep + Etiquette + sep + Checksum
|
||||
if (++sep >=3){
|
||||
hasts = true;
|
||||
|
|
|
@ -46,6 +46,13 @@
|
|||
// debugging, this should not interfere with main sketch or other
|
||||
// libraries
|
||||
#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__);
|
||||
#define TI_Debugflush {}
|
||||
#else
|
||||
#ifdef ESP8266
|
||||
#define TI_Debug(x) Serial1.print(x)
|
||||
#define TI_Debugln(x) Serial1.println(x)
|
||||
|
@ -57,6 +64,7 @@
|
|||
#define TI_Debugf(...) Serial.printf(__VA_ARGS__)
|
||||
#define TI_Debugflush Serial.flush
|
||||
#endif
|
||||
#endif
|
||||
#else
|
||||
#define TI_Debug(x) {}
|
||||
#define TI_Debugln(x) {}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
- Add better config corruption recovery (#9046)
|
||||
- Remove support for 1-step upgrade from versions before 6.6.0.11 to versions after 8.4.0.1
|
||||
- Add command ``SetOption108 0/1`` to enable Teleinfo telemetry into Tasmota Energy MQTT (0) or Teleinfo only (1) in this case MQTT will send RAW Teleinfo telemetry on each frame received and not into Tasmota energy calculation telemetry.
|
||||
- Change White blend mode moved to using ``SetOption 105`` instead of ``RGBWWTable``
|
||||
- Add Virtual CT for 4 channels lights, emulating a 5th channel
|
||||
|
||||
|
|
|
@ -127,8 +127,8 @@ typedef union { // Restricted by MISRA-C Rule 18.4 bu
|
|||
uint32_t white_blend_mode : 1; // bit 23 (v8.4.0.1) - SetOption105 - White Blend Mode - 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 - Virtual CT - Creates a virtual White ColorTemp for RGBW lights
|
||||
uint32_t virtual_ct_cw : 1; // bit 25 (v8.4.0.1) - SetOption107 - Virtual CT Channel - signals whether the hardware white is cold CW (true) or warm WW (false)
|
||||
uint32_t spare26 : 1; // bit 26
|
||||
uint32_t spare27 : 1; // bit 27
|
||||
uint32_t teleinfo_rawdata : 1; // bit 21 (v8.4.0.2) - SetOption108 - enable Teleinfo + Tasmota Energy device (0) or Teleinfo raw data only (1)
|
||||
uint32_t spare27 : 1;
|
||||
uint32_t spare28 : 1; // bit 28
|
||||
uint32_t spare29 : 1; // bit 29
|
||||
uint32_t spare30 : 1; // bit 30
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
* {"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 (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}
|
||||
* {"NAME":"WifInfo","GPIO":[7,255,255,210,6,5,255,255,255,255,255,255,255],"FLAG":15,"BASE":18}
|
||||
*
|
||||
\*********************************************************************************************/
|
||||
|
@ -107,6 +108,7 @@ const char kLabel[] PROGMEM =
|
|||
TInfo tinfo; // Teleinfo object
|
||||
TasmotaSerial *TInfoSerial = nullptr;
|
||||
_Mode_e tinfo_mode = TINFO_MODE_HISTORIQUE;
|
||||
char serialNumber[13] = ""; // Serial number is 12 char long
|
||||
bool tinfo_found = false;
|
||||
int contrat;
|
||||
int tarif;
|
||||
|
@ -144,19 +146,17 @@ Comments: should have been initialised with a
|
|||
====================================================================== */
|
||||
void ADPSCallback(uint8_t phase)
|
||||
{
|
||||
char adco[13];
|
||||
|
||||
// n = phase number 1 to 3
|
||||
if (phase == 0){
|
||||
phase = 1;
|
||||
}
|
||||
|
||||
if (tinfo_mode == TINFO_MODE_HISTORIQUE) {
|
||||
if (getValueFromLabelIndex(LABEL_ADCO, adco) ) {
|
||||
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"%s\":{\"ADPS\":%i}}"), adco, phase );
|
||||
MqttPublishPrefixTopic_P(RESULT_OR_TELE, mqtt_data);
|
||||
}
|
||||
}
|
||||
Response_P(PSTR("{"));
|
||||
ResponseAppend_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"%s\":{\"ADPS\":%i}}"), serialNumber, phase );
|
||||
ResponseJsonEnd();
|
||||
|
||||
// Publish adding ADCO serial number into the topic
|
||||
MqttPublishPrefixTopic_P(RESULT_OR_TELE, serialNumber, false);
|
||||
|
||||
AddLog_P2(LOG_LEVEL_INFO, PSTR("ADPS on phase %d"), phase);
|
||||
}
|
||||
|
@ -185,6 +185,13 @@ void DataCallback(struct _ValueList * me, uint8_t flags)
|
|||
}
|
||||
}
|
||||
|
||||
if (flags & TINFO_FLAGS_ADDED) { c = '#'; }
|
||||
if (flags & TINFO_FLAGS_UPDATED) { c = '*'; }
|
||||
if (flags & TINFO_FLAGS_STRING) { c = '$'; }
|
||||
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TIC: [%d]%c %s=%s"), ilabel, c , me->name, me->value);
|
||||
|
||||
if (ilabel<LABEL_END) {
|
||||
|
||||
// Current tariff (legacy)
|
||||
if (ilabel == LABEL_PTEC)
|
||||
{
|
||||
|
@ -217,34 +224,21 @@ void DataCallback(struct _ValueList * me, uint8_t flags)
|
|||
{
|
||||
Energy.voltage_available = true;
|
||||
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, (int) Energy.voltage[0]);
|
||||
}
|
||||
|
||||
// Current I
|
||||
else if (ilabel == LABEL_IINST || ilabel == LABEL_IRMS1)
|
||||
{
|
||||
if (!Energy.voltage_available) {
|
||||
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]);
|
||||
}
|
||||
|
||||
// Power P
|
||||
else if (ilabel == LABEL_PAPP || ilabel == LABEL_SINSTS)
|
||||
{
|
||||
int papp = atoi(me->value);
|
||||
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TIC: Power %s, now %d"), me->value, papp);
|
||||
Energy.active_power[0] = (float) atoi(me->value);
|
||||
// Update current
|
||||
if (Energy.voltage_available && Energy.voltage[0]) {
|
||||
Energy.current[0] = Energy.active_power[0] / Energy.voltage[0] ;
|
||||
}
|
||||
Energy.active_power[0] = (float) atoi(me->value);;
|
||||
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TIC: Power %s, now %d"), me->value, (int) Energy.active_power[0]);
|
||||
}
|
||||
|
||||
// Wh indexes (legacy)
|
||||
|
@ -258,7 +252,10 @@ void DataCallback(struct _ValueList * me, uint8_t flags)
|
|||
if ( getValueFromLabelIndex(LABEL_HCHC, value) ) { hc = atoi(value);}
|
||||
if ( getValueFromLabelIndex(LABEL_HCHP, value) ) { hp = atoi(value);}
|
||||
total = hc + hp;
|
||||
|
||||
if (!Settings.flag4.teleinfo_rawdata) {
|
||||
EnergyUpdateTotal(total/1000.0f, true);
|
||||
}
|
||||
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TIC: HC:%u HP:%u Total:%u"), hc, hp, total);
|
||||
}
|
||||
|
||||
|
@ -266,7 +263,9 @@ void DataCallback(struct _ValueList * me, uint8_t flags)
|
|||
else if ( ilabel == LABEL_EAST)
|
||||
{
|
||||
uint32_t total = atoi(me->value);
|
||||
if (!Settings.flag4.teleinfo_rawdata) {
|
||||
EnergyUpdateTotal(total/1000.0f, true);
|
||||
}
|
||||
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TIC: Total:%uWh"), total);
|
||||
}
|
||||
|
||||
|
@ -306,11 +305,71 @@ void DataCallback(struct _ValueList * me, uint8_t flags)
|
|||
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TIC: ISousc set to %d"), isousc);
|
||||
}
|
||||
|
||||
// Serial Number of device
|
||||
else if (ilabel == LABEL_ADCO || ilabel == LABEL_ADSC)
|
||||
{
|
||||
strcpy(serialNumber, me->value);
|
||||
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TIC: %s set to %s"), me->name, serialNumber);
|
||||
}
|
||||
|
||||
if (flags & TINFO_FLAGS_ADDED) { c = '#'; }
|
||||
if (flags & TINFO_FLAGS_UPDATED) { c = '*'; }
|
||||
AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("TIC: %c %s=%s"),c , me->name, me->value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
/* ======================================================================
|
||||
Function: responseDumpTInfo
|
||||
Purpose : add teleinfo values into JSON response
|
||||
Input : -
|
||||
Output : -
|
||||
Comments: -
|
||||
====================================================================== */
|
||||
void ResponseAppendTInfo()
|
||||
{
|
||||
struct _ValueList * me = tinfo.getList();
|
||||
|
||||
char sep = ' '; // First JSON value separator
|
||||
char * p ;
|
||||
boolean isNumber ;
|
||||
|
||||
// Loop thru all the teleinfo frame but
|
||||
// always check we don't buffer overflow of MQTT data
|
||||
while (me->next) {
|
||||
// go to next node
|
||||
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;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
ResponseAppend_P( PSTR("%c\"%s\":"), sep, me->name );
|
||||
|
||||
if (!isNumber || (me->flags & TINFO_FLAGS_STRING) ) {
|
||||
ResponseAppend_P( PSTR("\"%s\""), me->value );
|
||||
} else {
|
||||
ResponseAppend_P( PSTR("%d"), atoi(me->value));
|
||||
}
|
||||
|
||||
// Now JSON separator is needed
|
||||
sep =',';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ======================================================================
|
||||
|
@ -324,6 +383,17 @@ 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
|
||||
MqttPublishPrefixTopic_P(RESULT_OR_TELE, serialNumber, false);
|
||||
}
|
||||
}
|
||||
|
||||
/* ======================================================================
|
||||
|
@ -337,8 +407,6 @@ void TInfoDrvInit(void) {
|
|||
if (PinUsed(GPIO_TELEINFO_RX)) {
|
||||
energy_flg = XNRG_15;
|
||||
Energy.voltage_available = false;
|
||||
//Energy.current_available = false;
|
||||
Energy.type_dc = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -433,14 +501,16 @@ Comments: -
|
|||
====================================================================== */
|
||||
void TInfoEvery250ms(void)
|
||||
{
|
||||
char c;
|
||||
if (!tinfo_found)
|
||||
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) {
|
||||
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();
|
||||
// data processing
|
||||
|
@ -457,6 +527,7 @@ Output : -
|
|||
Comments: -
|
||||
====================================================================== */
|
||||
#ifdef USE_WEBSERVER
|
||||
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}" ;
|
||||
|
@ -469,46 +540,19 @@ const char HTTP_ENERGY_PMAX_TELEINFO[] PROGMEM = "{s}" D_MAX_POWER "{m}%d" D_UN
|
|||
|
||||
void TInfoShow(bool json)
|
||||
{
|
||||
char name[32];
|
||||
char value[32];
|
||||
|
||||
// Since it's an Energy device , current, voltage and power are
|
||||
// already present on the telemetry frame. No need to add here
|
||||
// Just add the raw label/values of the teleinfo frame
|
||||
if (json)
|
||||
{
|
||||
struct _ValueList * me = tinfo.getList();
|
||||
|
||||
// Calculated values
|
||||
if (isousc) {
|
||||
ResponseAppend_P(PSTR(",\"Load\":%d"),(int) ((Energy.current[0]*100.0f) / isousc));
|
||||
}
|
||||
|
||||
// Loop thru all the teleinfo frame
|
||||
while (me->next) {
|
||||
// go to next node
|
||||
me = me->next;
|
||||
|
||||
if (me->name && me->value && *me->name && *me->value) {
|
||||
boolean isNumber = true;
|
||||
char * p = me->value;
|
||||
|
||||
// check if value is number
|
||||
while (*p && isNumber) {
|
||||
if ( *p < '0' || *p > '9' ) {
|
||||
isNumber = false;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
|
||||
// this will add "" on not number values
|
||||
ResponseAppend_P(PSTR(",\"%s\":"), me->name);
|
||||
if (!isNumber) {
|
||||
ResponseAppend_P(PSTR("\"%s\""), me->value);
|
||||
} else {
|
||||
ResponseAppend_P(PSTR("%u"), atol(me->value));
|
||||
}
|
||||
}
|
||||
// add teleinfo full frame only if no teleinfo raw data setup
|
||||
if (!Settings.flag4.teleinfo_rawdata) {
|
||||
ResponseAppendTInfo();
|
||||
}
|
||||
|
||||
|
||||
|
@ -516,6 +560,9 @@ void TInfoShow(bool json)
|
|||
}
|
||||
else
|
||||
{
|
||||
char name[32];
|
||||
char value[32];
|
||||
|
||||
if (getValueFromLabelIndex(LABEL_HCHC, value) ) {
|
||||
GetTextIndexed(name, sizeof(name), LABEL_HCHC, kLabel);
|
||||
WSContentSend_PD(HTTP_ENERGY_INDEX_TELEINFO, name, value);
|
||||
|
@ -531,7 +578,7 @@ void TInfoShow(bool json)
|
|||
WSContentSend_PD(HTTP_ENERGY_PMAX_TELEINFO, atoi(value));
|
||||
}
|
||||
|
||||
if (tinfo_mode==TINFO_MODE_STANDARD ) {
|
||||
if (tinfo_mode==TINFO_MODE_HISTORIQUE ) {
|
||||
if (tarif) {
|
||||
GetTextIndexed(name, sizeof(name), tarif-1, kTarifName);
|
||||
WSContentSend_PD(HTTP_ENERGY_TARIF_TELEINFO, name);
|
||||
|
@ -542,7 +589,7 @@ void TInfoShow(bool json)
|
|||
WSContentSend_PD(HTTP_ENERGY_CONTRAT_TELEINFO, name, isousc);
|
||||
WSContentSend_PD(HTTP_ENERGY_LOAD_TELEINFO, percent);
|
||||
}
|
||||
} else {
|
||||
} else if (tinfo_mode==TINFO_MODE_STANDARD ) {
|
||||
if (getValueFromLabelIndex(LABEL_LTARF, name) ) {
|
||||
WSContentSend_PD(HTTP_ENERGY_TARIF_TELEINFO, name);
|
||||
}
|
||||
|
@ -555,6 +602,10 @@ void TInfoShow(bool json)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Serial number ADCO or ADSC
|
||||
WSContentSend_PD(HTTP_ENERGY_ID_TELEINFO, serialNumber);
|
||||
|
||||
#endif // USE_WEBSERVER
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue