diff --git a/tasmota/xnrg_15_teleinfo.ino b/tasmota/xnrg_15_teleinfo.ino index 094f07bc8..83a20648f 100644 --- a/tasmota/xnrg_15_teleinfo.ino +++ b/tasmota/xnrg_15_teleinfo.ino @@ -34,47 +34,44 @@ #define TINFO_READ_TIMEOUT 400 enum TInfoContrat{ - CONTRAT_BAS = 1, // BASE => Option Base. - CONTRAT_HC, // HC.. => Option Heures Creuses. - CONTRAT_EJP, // EJP. => Option EJP. - CONTRAT_BBR // BBRx => Option Tempo + CONTRAT_BAS = 1, // BASE => Option Base. + CONTRAT_HC, // HC.. => Option Heures Creuses. + CONTRAT_EJP, // EJP. => Option EJP. + CONTRAT_BBR // BBRx => Option Tempo }; enum TInfoTarif{ - TARIF_TH = 1, // Toutes les Heures. - TARIF_HC, // Heures Creuses. - TARIF_HP, // Heures Pleines. - TARIF_HN // BBRx => Option Tempo + TARIF_TH = 1, // Toutes les Heures. + TARIF_HC, // Heures Creuses. + TARIF_HP, // Heures Pleines. + TARIF_HN, // BBRx => Option Tempo + TARIF_PM, // Heures de Pointe Mobile. + TARIF_CB, // Heures Creuses Jours Bleus. + TARIF_CW, // Heures Creuses Jours Blancs (White). + TARIF_CR, // Heures Creuses Jours Rouges. + TARIF_PB, // Heures Pleines Jours Bleus. + TARIF_PW, // Heures Pleines Jours Blancs (White). + TARIF_PR // Heures Pleines Jours Rouges. }; -//const char kTARIF_TH[] PROGMEM = ""; -//const char kTARIF_HC[] PROGMEM = "Heures Creuses"; -//const char kTARIF_HP[] PROGMEM = "Heures Pleines"; -//const char kTARIF_HN[] PROGMEM = "Heures Normales"; - -//const char kTtarifNames[] PROGMEM = { kTARIF_TH, kTARIF_HC, kTARIF_HP, kTARIF_HN }; - -/* - strcpy_P(buffer, (char*)pgm_read_dword(&(kTtarifNames[i]))); - - if ( label == "PTEC") { - // La période tarifaire en cours (Groupe "PTEC"), est codée sur 4 caractères - // J'ai pris un nombre arbitraire codé dans l'ordre ci-dessous - if (value=="TH..") value= 1; - else if (value=="HC..") value= 2; - else if (value=="HP..") value= 3; / - else if (value=="HN..") value= 4; - else if (value=="PM..") value= 5; // Heures de Pointe Mobile. - else if (value=="HCJB") value= 6; // Heures Creuses Jours Bleus. - else if (value=="HCJW") value= 7; // Heures Creuses Jours Blancs (White). - else if (value=="HCJR") value= 8; // Heures Creuses Jours Rouges. - else if (value=="HPJB") value= 9; // Heures Pleines Jours Bleus. - else if (value=="HPJW") value= 10;// Heures Pleines Jours Blancs (White). - else if (value=="HPJR") value= 11;// Heures Pleines Jours Rouges. - else value = 0; - -*/ +const char kTARIF_TH[] PROGMEM = "Toutes"; +const char kTARIF_HC[] PROGMEM = "Creuses"; +const char kTARIF_HP[] PROGMEM = "Pleines"; +const char kTARIF_HN[] PROGMEM = "Normales"; +const char kTARIF_PM[] PROGMEM = "Pointe Mobile"; +const char kTARIF_CB[] PROGMEM = "Creuses Bleu"; +const char kTARIF_CW[] PROGMEM = "Creuses Blanc"; +const char kTARIF_CR[] PROGMEM = "Creuses Rouge"; +const char kTARIF_PB[] PROGMEM = "Pleines Bleu"; +const char kTARIF_PW[] PROGMEM = "Pleines Blanc"; +const char kTARIF_PR[] PROGMEM = "Pleines Rouge"; +const char * kTtarifNames[] PROGMEM = { + kTARIF_TH, + kTARIF_HC, kTARIF_HP, + kTARIF_HN, kTARIF_PM, + kTARIF_CB, kTARIF_CW, kTARIF_CR, kTARIF_PB, kTARIF_PW, kTARIF_PR +}; TInfo tinfo; // Teleinfo object TasmotaSerial *TInfoSerial = nullptr; @@ -127,32 +124,112 @@ void DataCallback(struct _ValueList * me, uint8_t flags) if (!strcmp("PTEC", me->name)) { if (!strcmp("TH..", me->name)) { tarif = TARIF_TH; } - if (!strcmp("HC..", me->name)) { tarif = TARIF_HC; } - if (!strcmp("HP..", me->name)) { tarif = TARIF_HP; } - if (!strcmp("HN..", me->name)) { tarif = TARIF_HN; } + else if (!strcmp("HC..", me->name)) { tarif = TARIF_HC; } + else if (!strcmp("HP..", me->name)) { tarif = TARIF_HP; } + else if (!strcmp("HN..", me->name)) { tarif = TARIF_HN; } + else if (!strcmp("PM..", me->name)) { tarif = TARIF_PM; } + else if (!strcmp("HCJB", me->name)) { tarif = TARIF_CB; } + else if (!strcmp("HCJW", me->name)) { tarif = TARIF_CW; } + else if (!strcmp("HCJR", me->name)) { tarif = TARIF_CR; } + else if (!strcmp("HPJB", me->name)) { tarif = TARIF_PB; } + else if (!strcmp("HPJW", me->name)) { tarif = TARIF_PW; } + else if (!strcmp("HPJR", me->name)) { tarif = TARIF_PR; } + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TIC: Tarif changed, now '%s' (%d)"), me->value, tarif); } + // Voltage V (not present on all Smart Meter) + else if (!strcmp("TENSION", me->name)) + { + Energy.voltage_available = true; + int i = atoi(me->value); + 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, i); + } // Current I else if (!strcmp("IINST", me->name)) { - int i = atoi(me->value); - Energy.current[0] = (float) i; - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TIC: Current changed %s, now %d"), me->value, i); + if (!Energy.voltage_available) { + int i = atoi(me->value); + 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]); } // Current P else if (!strcmp("PAPP", me->name)) { int papp = atoi(me->value); - Energy.active_power[0] = (float) papp; - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TIC: Power changed %s, now %d"), me->value, papp); + Energy.active_power[0] = (float) atoi(me->value); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TIC: Power %s, now %d"), me->value, papp); + + // Update current + if (Energy.voltage_available && Energy.voltage[0]) { + Energy.current[0] = Energy.active_power[0] / Energy.voltage[0] ; + } + } + // kWh indexes + else if (!strcmp("HCHC", me->name) || !strcmp("HCHP", me->name)) + { + char value[32]; + unsigned long hc = 0; + unsigned long hp = 0; + unsigned long total = 0; + + if ( tinfo.valueGet((char *)"HCHC", value) ) { hc = atol(value);} + if ( tinfo.valueGet((char *)"HCHP", value) ) { hp = atol(value);} + total = hc+hp; + + EnergyUpdateTotal(total/1000.0f, true); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TIC: HC:%ld HP:%ld Total:%ld"), hc, hp, total); } } AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TIC: %c %s=%s"),c , me->name, me->value); } +/* ====================================================================== +Function: NewFrameCallback +Purpose : callback when we received a complete Teleinfo frama +Input : linked list pointer on the concerned data +Output : - +Comments: - +====================================================================== */ +void NewFrameCallback(struct _ValueList * me) +{ + // Reset Energy Watchdog + Energy.data_valid[0] = 0; +} + +/* ====================================================================== +Function: NewFrameCallback +Purpose : callback when we received a complete Teleinfo frama +Input : label to search for +Output : value filled +Comments: - +====================================================================== */ +char * getDataValue(char * label, char * value) +{ + if (!tinfo.valueGet(label, value) ) { + *value = '\0'; + } + return value; +} + + + void TInfoDrvInit(void) { if (PinUsed(GPIO_TELEINFO_RX)) { energy_flg = XNRG_15; + Energy.voltage_available = false; + //Energy.current_available = false; + Energy.type_dc = true; } } @@ -188,6 +265,9 @@ void TInfoInit(void) if (TInfoSerial->begin(TINFO_SPEED, SERIAL_7E1)) { if (TInfoSerial->hardwareSerial()) { + // This is a dirty hack to bypass HW serial init when for Teleinfo + // This protocol needs 7E1 configuration so on ESP8266 this is + // working only on Serial RX pin (Hardware Serial) for now Serial.end(); Serial.begin(TINFO_SPEED, SERIAL_7E1); ClaimSerial(); @@ -200,6 +280,7 @@ void TInfoInit(void) // Attach needed callbacks tinfo.attachADPS(ADPSCallback); tinfo.attachData(DataCallback); + tinfo.attachNewFrame(NewFrameCallback); tinfo_found = true; AddLog_P2(LOG_LEVEL_INFO, PSTR("TIC: Ready")); @@ -228,21 +309,52 @@ void TInfoLoop(void) } } + void TInfoEvery250ms(void) { } +#ifdef USE_WEBSERVER +const char HTTP_ENERGY_INDEX_TELEINFO[] PROGMEM = "{s}%s{m}%s " D_UNIT_KILOWATTHOUR "{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_TARIF_TELEINFO[] PROGMEM = "{s}Tarif{m}%s{e}" ; +#endif // USE_WEBSERVER + void TInfoShow(bool json) { + char value[32]; // TBD if (json) { - ResponseAppend_P(PSTR(",\"Contrat\":%d,\"Tarif\":%d"),contrat, tarif); - + if ( tinfo.valueGet((char *)"PTEC", value) ) { + ResponseAppend_P(PSTR(",\"" "TARIF" "\":%s"), value); + } + if ( tinfo.valueGet((char *)"IINST", value) ) { + ResponseAppend_P(PSTR(",\"" D_CURRENT "\":%s"), value); + } + if ( tinfo.valueGet((char *)"PAPP", value) ) { + ResponseAppend_P(PSTR(",\"" D_POWERUSAGE "\":%s"), value); + } + if ( tinfo.valueGet((char *)"HCHC", value) ) { + ResponseAppend_P(PSTR(",\"" "HC" "\":%s"), value); + } + if ( tinfo.valueGet((char *)"HCHP", value) ) { + ResponseAppend_P(PSTR(",\"" "HP" "\":%s"), value); + } #ifdef USE_WEBSERVER } else { + getDataValue("HCHC", value); + WSContentSend_PD(HTTP_ENERGY_INDEX_TELEINFO, kTARIF_HC, value); + getDataValue("HCHP", value); + WSContentSend_PD(HTTP_ENERGY_INDEX_TELEINFO, kTARIF_HP, value); + if (tarif) { + WSContentSend_PD(HTTP_ENERGY_TARIF_TELEINFO, kTtarifNames[tarif-1]); + } + + #endif // USE_WEBSERVER } } @@ -263,6 +375,7 @@ bool Xnrg15(uint8_t function) if (uptime > 4) { TInfoEvery250ms(); } break; case FUNC_JSON_APPEND: + TInfoShow(1); break; #ifdef USE_WEBSERVER