diff --git a/lib/AmsData/include/AmsMqttHandler.h b/lib/AmsData/include/AmsMqttHandler.h index 209da56c..08732819 100644 --- a/lib/AmsData/include/AmsMqttHandler.h +++ b/lib/AmsData/include/AmsMqttHandler.h @@ -9,6 +9,10 @@ #include "HwTools.h" #include "EntsoeApi.h" +#if defined(ESP32) +#include +#endif + class AmsMqttHandler { public: AmsMqttHandler(MQTTClient* mqtt, char* buf) { @@ -26,6 +30,8 @@ protected: MQTTClient* mqtt; char* json; uint16_t BufferSize = 2048; + + bool loop(); }; #endif diff --git a/lib/EnergyAccounting/src/EnergyAccounting.cpp b/lib/EnergyAccounting/src/EnergyAccounting.cpp index 66b2ae68..072fece2 100644 --- a/lib/EnergyAccounting/src/EnergyAccounting.cpp +++ b/lib/EnergyAccounting/src/EnergyAccounting.cpp @@ -167,7 +167,7 @@ void EnergyAccounting::calcDayCost() { costDay = 0; incomeDay = 0; } - for(int i = 0; i < currentHour; i++) { + for(uint8_t i = 0; i < currentHour; i++) { float price = getPriceForHour(i - local.Hour); if(price == ENTSOE_NO_VALUE) break; breakTime(now - ((local.Hour - i) * 3600), utc); @@ -192,7 +192,7 @@ float EnergyAccounting::getUseToday() { if(tz == NULL) return 0.0; tmElements_t utc, local; breakTime(tz->toLocal(now), local); - for(int i = 0; i < currentHour; i++) { + for(uint8_t i = 0; i < currentHour; i++) { breakTime(now - ((local.Hour - i) * 3600), utc); ret += ds->getHourImport(utc.Hour) / 1000.0; } @@ -203,7 +203,7 @@ float EnergyAccounting::getUseThisMonth() { time_t now = time(nullptr); if(now < BUILD_EPOCH) return 0.0; float ret = 0; - for(int i = 0; i < currentDay; i++) { + for(uint8_t i = 0; i < currentDay; i++) { ret += ds->getDayImport(i) / 1000.0; } return ret + getUseToday(); @@ -219,7 +219,7 @@ float EnergyAccounting::getProducedToday() { if(now < BUILD_EPOCH) return 0.0; tmElements_t utc, local; breakTime(tz->toLocal(now), local); - for(int i = 0; i < currentHour; i++) { + for(uint8_t i = 0; i < currentHour; i++) { breakTime(now - ((local.Hour - i) * 3600), utc); ret += ds->getHourExport(utc.Hour) / 1000.0; } @@ -230,7 +230,7 @@ float EnergyAccounting::getProducedThisMonth() { time_t now = time(nullptr); if(now < BUILD_EPOCH) return 0.0; float ret = 0; - for(int i = 0; i < currentDay; i++) { + for(uint8_t i = 0; i < currentDay; i++) { ret += ds->getDayExport(i) / 1000.0; } return ret + getProducedToday(); diff --git a/lib/HomeAssistantMqttHandler/include/HomeAssistantMqttHandler.h b/lib/HomeAssistantMqttHandler/include/HomeAssistantMqttHandler.h index 676cf371..3157b9e2 100644 --- a/lib/HomeAssistantMqttHandler/include/HomeAssistantMqttHandler.h +++ b/lib/HomeAssistantMqttHandler/include/HomeAssistantMqttHandler.h @@ -57,20 +57,8 @@ public: bool publishPrices(EntsoeApi*); bool publishSystem(HwTools* hw, EntsoeApi* eapi, EnergyAccounting* ea); - void publishSensor(const HomeAssistantSensor& sensor); - void publishList1Sensors(); - void publishList1ExportSensors(); - void publishList2Sensors(); - void publishList2ExportSensors(); - void publishList3Sensors(); - void publishList3ExportSensors(); - void publishList4Sensors(); - void publishList4ExportSensors(); - void publishRealtimeSensors(EnergyAccounting* ea, EntsoeApi* eapi); - void publishRealtimeExportSensors(EnergyAccounting* ea, EntsoeApi* eapi); - void publishTemperatureSensor(uint8_t index, String id); - void publishPriceSensors(EntsoeApi* eapi); - void publishSystemSensors(); +protected: + bool loop(); private: String deviceName; @@ -90,6 +78,27 @@ private: String topic; HwTools* hw; + bool publishList1(AmsData* data, EnergyAccounting* ea); + bool publishList2(AmsData* data, EnergyAccounting* ea); + bool publishList3(AmsData* data, EnergyAccounting* ea); + bool publishList4(AmsData* data, EnergyAccounting* ea); + String getMeterModel(AmsData* data); + bool publishRealtime(AmsData* data, EnergyAccounting* ea, EntsoeApi* eapi); + void publishSensor(const HomeAssistantSensor& sensor); + void publishList1Sensors(); + void publishList1ExportSensors(); + void publishList2Sensors(); + void publishList2ExportSensors(); + void publishList3Sensors(); + void publishList3ExportSensors(); + void publishList4Sensors(); + void publishList4ExportSensors(); + void publishRealtimeSensors(EnergyAccounting* ea, EntsoeApi* eapi); + void publishRealtimeExportSensors(EnergyAccounting* ea, EntsoeApi* eapi); + void publishTemperatureSensor(uint8_t index, String id); + void publishPriceSensors(EntsoeApi* eapi); + void publishSystemSensors(); + String boardTypeToString(uint8_t b) { switch(b) { case 5: diff --git a/lib/HomeAssistantMqttHandler/src/HomeAssistantMqttHandler.cpp b/lib/HomeAssistantMqttHandler/src/HomeAssistantMqttHandler.cpp index 8fff5760..04174cee 100644 --- a/lib/HomeAssistantMqttHandler/src/HomeAssistantMqttHandler.cpp +++ b/lib/HomeAssistantMqttHandler/src/HomeAssistantMqttHandler.cpp @@ -20,111 +20,136 @@ bool HomeAssistantMqttHandler::publish(AmsData* data, AmsData* previousState, En return false; if(data->getListType() >= 3) { // publish energy counts - publishList3Sensors(); - if(data->getActiveExportCounter() > 0.0) publishList3ExportSensors(); - snprintf_P(json, BufferSize, HA2_JSON, - data->getActiveImportCounter(), - data->getActiveExportCounter(), - data->getReactiveImportCounter(), - data->getReactiveExportCounter(), - data->getMeterTimestamp() - ); - mqtt->publish(topic + "/energy", json); - mqtt->loop(); - delay(10); - } - String meterModel = data->getMeterModel(); - meterModel.replace("\\", "\\\\"); - if(data->getListType() == 1) { // publish power counts - publishList1Sensors(); - snprintf_P(json, BufferSize, HA1_JSON, - data->getActiveImportPower() - ); - mqtt->publish(topic + "/power", json); - } else if(data->getListType() <= 3) { // publish power counts and volts/amps - publishList2Sensors(); - if(data->getActiveExportPower() > 0) publishList2ExportSensors(); - snprintf_P(json, BufferSize, HA3_JSON, - data->getListId().c_str(), - data->getMeterId().c_str(), - meterModel.c_str(), - data->getActiveImportPower(), - data->getReactiveImportPower(), - data->getActiveExportPower(), - data->getReactiveExportPower(), - data->getL1Current(), - data->getL2Current(), - data->getL3Current(), - data->getL1Voltage(), - data->getL2Voltage(), - data->getL3Voltage() - ); - mqtt->publish(topic + "/power", json); - } else if(data->getListType() == 4) { // publish power counts and volts/amps/phase power and PF - publishList4Sensors(); - if(data->getL1ActiveExportPower() > 0 || data->getL2ActiveExportPower() > 0 || data->getL3ActiveExportPower() > 0) publishList4ExportSensors(); - snprintf_P(json, BufferSize, HA4_JSON, - data->getListId().c_str(), - data->getMeterId().c_str(), - meterModel.c_str(), - data->getActiveImportPower(), - data->getL1ActiveImportPower(), - data->getL2ActiveImportPower(), - data->getL3ActiveImportPower(), - data->getReactiveImportPower(), - data->getActiveExportPower(), - data->getL1ActiveExportPower(), - data->getL2ActiveExportPower(), - data->getL3ActiveExportPower(), - data->getReactiveExportPower(), - data->getL1Current(), - data->getL2Current(), - data->getL3Current(), - data->getL1Voltage(), - data->getL2Voltage(), - data->getL3Voltage(), - data->getPowerFactor() == 0 ? 1 : data->getPowerFactor(), - data->getPowerFactor() == 0 ? 1 : data->getL1PowerFactor(), - data->getPowerFactor() == 0 ? 1 : data->getL2PowerFactor(), - data->getPowerFactor() == 0 ? 1 : data->getL3PowerFactor() - ); - mqtt->publish(topic + "/power", json); + publishList3(data, ea); + loop(); } - if(ea->isInitialized()) { - publishRealtimeSensors(ea, eapi); - if(ea->getProducedThisHour() > 0.0 || ea->getProducedToday() > 0.0 || ea->getProducedThisMonth() > 0.0) publishRealtimeExportSensors(ea, eapi); - String peaks = ""; - uint8_t peakCount = ea->getConfig()->hours; - if(peakCount > 5) peakCount = 5; - for(uint8_t i = 1; i <= peakCount; i++) { - if(!peaks.isEmpty()) peaks += ","; - peaks += String(ea->getPeak(i).value / 100.0, 2); - } - snprintf_P(json, BufferSize, REALTIME_JSON, - ea->getMonthMax(), - peaks.c_str(), - ea->getCurrentThreshold(), - ea->getUseThisHour(), - ea->getCostThisHour(), - ea->getProducedThisHour(), - ea->getIncomeThisHour(), - ea->getUseToday(), - ea->getCostToday(), - ea->getProducedToday(), - ea->getIncomeToday(), - ea->getUseThisMonth(), - ea->getCostThisMonth(), - ea->getProducedThisMonth(), - ea->getIncomeThisMonth() - ); - mqtt->publish(topic + "/realtime", json); + if(data->getListType() == 1) { // publish power counts + publishList1(data, ea); + } else if(data->getListType() <= 3) { // publish power counts and volts/amps + publishList2(data, ea); + } else if(data->getListType() == 4) { // publish power counts and volts/amps/phase power and PF + publishList4(data, ea); + } + loop(); + + if(ea->isInitialized()) { + publishRealtime(data, ea, eapi); + loop(); } - mqtt->loop(); - delay(10); return true; } +bool HomeAssistantMqttHandler::publishList1(AmsData* data, EnergyAccounting* ea) { + publishList1Sensors(); + snprintf_P(json, BufferSize, HA1_JSON, + data->getActiveImportPower() + ); + return mqtt->publish(topic + "/power", json); +} + +bool HomeAssistantMqttHandler::publishList2(AmsData* data, EnergyAccounting* ea) { + publishList2Sensors(); + if(data->getActiveExportPower() > 0) publishList2ExportSensors(); + snprintf_P(json, BufferSize, HA3_JSON, + data->getListId().c_str(), + data->getMeterId().c_str(), + getMeterModel(data).c_str(), + data->getActiveImportPower(), + data->getReactiveImportPower(), + data->getActiveExportPower(), + data->getReactiveExportPower(), + data->getL1Current(), + data->getL2Current(), + data->getL3Current(), + data->getL1Voltage(), + data->getL2Voltage(), + data->getL3Voltage() + ); + return mqtt->publish(topic + "/power", json); +} + +bool HomeAssistantMqttHandler::publishList3(AmsData* data, EnergyAccounting* ea) { + publishList3Sensors(); + if(data->getActiveExportCounter() > 0.0) publishList3ExportSensors(); + snprintf_P(json, BufferSize, HA2_JSON, + data->getActiveImportCounter(), + data->getActiveExportCounter(), + data->getReactiveImportCounter(), + data->getReactiveExportCounter(), + data->getMeterTimestamp() + ); + return mqtt->publish(topic + "/energy", json); +} + +bool HomeAssistantMqttHandler::publishList4(AmsData* data, EnergyAccounting* ea) { + publishList4Sensors(); + if(data->getL1ActiveExportPower() > 0 || data->getL2ActiveExportPower() > 0 || data->getL3ActiveExportPower() > 0) publishList4ExportSensors(); + snprintf_P(json, BufferSize, HA4_JSON, + data->getListId().c_str(), + data->getMeterId().c_str(), + getMeterModel(data).c_str(), + data->getActiveImportPower(), + data->getL1ActiveImportPower(), + data->getL2ActiveImportPower(), + data->getL3ActiveImportPower(), + data->getReactiveImportPower(), + data->getActiveExportPower(), + data->getL1ActiveExportPower(), + data->getL2ActiveExportPower(), + data->getL3ActiveExportPower(), + data->getReactiveExportPower(), + data->getL1Current(), + data->getL2Current(), + data->getL3Current(), + data->getL1Voltage(), + data->getL2Voltage(), + data->getL3Voltage(), + data->getPowerFactor() == 0 ? 1 : data->getPowerFactor(), + data->getPowerFactor() == 0 ? 1 : data->getL1PowerFactor(), + data->getPowerFactor() == 0 ? 1 : data->getL2PowerFactor(), + data->getPowerFactor() == 0 ? 1 : data->getL3PowerFactor() + ); + return mqtt->publish(topic + "/power", json); +} + +String HomeAssistantMqttHandler::getMeterModel(AmsData* data) { + String meterModel = data->getMeterModel(); + meterModel.replace("\\", "\\\\"); + return meterModel; +} + +bool HomeAssistantMqttHandler::publishRealtime(AmsData* data, EnergyAccounting* ea, EntsoeApi* eapi) { + publishRealtimeSensors(ea, eapi); + if(ea->getProducedThisHour() > 0.0 || ea->getProducedToday() > 0.0 || ea->getProducedThisMonth() > 0.0) publishRealtimeExportSensors(ea, eapi); + String peaks = ""; + uint8_t peakCount = ea->getConfig()->hours; + if(peakCount > 5) peakCount = 5; + for(uint8_t i = 1; i <= peakCount; i++) { + if(!peaks.isEmpty()) peaks += ","; + peaks += String(ea->getPeak(i).value / 100.0, 2); + } + snprintf_P(json, BufferSize, REALTIME_JSON, + ea->getMonthMax(), + peaks.c_str(), + ea->getCurrentThreshold(), + ea->getUseThisHour(), + ea->getCostThisHour(), + ea->getProducedThisHour(), + ea->getIncomeThisHour(), + ea->getUseToday(), + ea->getCostToday(), + ea->getProducedToday(), + ea->getIncomeToday(), + ea->getUseThisMonth(), + ea->getCostThisMonth(), + ea->getProducedThisMonth(), + ea->getIncomeThisMonth() + ); + return mqtt->publish(topic + "/realtime", json); +} + + bool HomeAssistantMqttHandler::publishTemperatures(AmsConfiguration* config, HwTools* hw) { int count = hw->getTempSensorCount(); if(count < 2) return false; @@ -149,7 +174,9 @@ bool HomeAssistantMqttHandler::publishTemperatures(AmsConfiguration* config, HwT } char* pos = buf+strlen(buf); snprintf_P(count == 0 ? pos : pos-1, 8, PSTR("}}")); - return mqtt->publish(topic + "/temperatures", buf); + bool ret = mqtt->publish(topic + "/temperatures", buf); + loop(); + return ret; } bool HomeAssistantMqttHandler::publishPrices(EntsoeApi* eapi) { @@ -283,7 +310,9 @@ bool HomeAssistantMqttHandler::publishPrices(EntsoeApi* eapi) { ts3hr, ts6hr ); - return mqtt->publish(topic + "/prices", json, true, 0); + bool ret = mqtt->publish(topic + "/prices", json, true, 0); + loop(); + return ret; } bool HomeAssistantMqttHandler::publishSystem(HwTools* hw, EntsoeApi* eapi, EnergyAccounting* ea) { @@ -302,7 +331,9 @@ bool HomeAssistantMqttHandler::publishSystem(HwTools* hw, EntsoeApi* eapi, Energ hw->getTemperature(), VERSION ); - return mqtt->publish(topic + "/state", json); + bool ret = mqtt->publish(topic + "/state", json); + loop(); + return ret; } void HomeAssistantMqttHandler::publishSensor(const HomeAssistantSensor& sensor) { @@ -330,16 +361,7 @@ void HomeAssistantMqttHandler::publishSensor(const HomeAssistantSensor& sensor) strlen_P(sensor.stacl) > 0 ? (char *) FPSTR(sensor.stacl) : "" ); mqtt->publish(discoveryTopic + deviceUid + "_" + uid.c_str() + "/config", json, true, 0); - mqtt->loop(); - delay(10); - - #if defined(ESP32) - esp_task_wdt_reset(); - #elif defined(ESP8266) - ESP.wdtFeed(); - #endif - - yield(); + loop(); } void HomeAssistantMqttHandler::publishList1Sensors() { @@ -513,4 +535,16 @@ void HomeAssistantMqttHandler::publishSystemSensors() { publishSensor(SystemSensors[i]); } sInit = true; -} \ No newline at end of file +} + +bool HomeAssistantMqttHandler::loop() { + bool ret = mqtt->loop(); + delay(10); + yield(); + #if defined(ESP32) + esp_task_wdt_reset(); + #elif defined(ESP8266) + ESP.wdtFeed(); + #endif + return ret; +} diff --git a/lib/JsonMqttHandler/include/JsonMqttHandler.h b/lib/JsonMqttHandler/include/JsonMqttHandler.h index db75a1b9..8bccdc3b 100644 --- a/lib/JsonMqttHandler/include/JsonMqttHandler.h +++ b/lib/JsonMqttHandler/include/JsonMqttHandler.h @@ -15,9 +15,18 @@ public: bool publishPrices(EntsoeApi*); bool publishSystem(HwTools* hw, EntsoeApi* eapi, EnergyAccounting* ea); +protected: + bool loop(); + private: String clientId; String topic; HwTools* hw; + + bool publishList1(AmsData* data, EnergyAccounting* ea); + bool publishList2(AmsData* data, EnergyAccounting* ea); + bool publishList3(AmsData* data, EnergyAccounting* ea); + bool publishList4(AmsData* data, EnergyAccounting* ea); + String getMeterModel(AmsData* data); }; #endif diff --git a/lib/JsonMqttHandler/src/JsonMqttHandler.cpp b/lib/JsonMqttHandler/src/JsonMqttHandler.cpp index 26a9d74d..01313683 100644 --- a/lib/JsonMqttHandler/src/JsonMqttHandler.cpp +++ b/lib/JsonMqttHandler/src/JsonMqttHandler.cpp @@ -15,140 +15,159 @@ bool JsonMqttHandler::publish(AmsData* data, AmsData* previousState, EnergyAccou bool ret = false; + if(data->getListType() == 1) { + ret = publishList1(data, ea); + } else if(data->getListType() == 2) { + ret = publishList2(data, ea); + } else if(data->getListType() == 3) { + ret = publishList3(data, ea); + } else if(data->getListType() == 4) { + ret = publishList4(data, ea); + } + loop(); + return ret; +} + +bool JsonMqttHandler::publishList1(AmsData* data, EnergyAccounting* ea) { + snprintf_P(json, BufferSize, JSON1_JSON, + WiFi.macAddress().c_str(), + clientId.c_str(), + (uint32_t) (millis64()/1000), + data->getPackageTimestamp(), + hw->getVcc(), + hw->getWifiRssi(), + hw->getTemperature(), + data->getActiveImportPower(), + ea->getUseThisHour(), + ea->getUseToday(), + ea->getCurrentThreshold(), + ea->getMonthMax(), + ea->getProducedThisHour(), + ea->getProducedToday() + ); + return mqtt->publish(topic, json); +} + +bool JsonMqttHandler::publishList2(AmsData* data, EnergyAccounting* ea) { + snprintf_P(json, BufferSize, JSON2_JSON, + WiFi.macAddress().c_str(), + clientId.c_str(), + (uint32_t) (millis64()/1000), + data->getPackageTimestamp(), + hw->getVcc(), + hw->getWifiRssi(), + hw->getTemperature(), + data->getListId().c_str(), + data->getMeterId().c_str(), + getMeterModel(data).c_str(), + data->getActiveImportPower(), + data->getReactiveImportPower(), + data->getActiveExportPower(), + data->getReactiveExportPower(), + data->getL1Current(), + data->getL2Current(), + data->getL3Current(), + data->getL1Voltage(), + data->getL2Voltage(), + data->getL3Voltage(), + ea->getUseThisHour(), + ea->getUseToday(), + ea->getCurrentThreshold(), + ea->getMonthMax(), + ea->getProducedThisHour(), + ea->getProducedToday() + ); + return mqtt->publish(topic, json); +} + +bool JsonMqttHandler::publishList3(AmsData* data, EnergyAccounting* ea) { + snprintf_P(json, BufferSize, JSON3_JSON, + WiFi.macAddress().c_str(), + clientId.c_str(), + (uint32_t) (millis64()/1000), + data->getPackageTimestamp(), + hw->getVcc(), + hw->getWifiRssi(), + hw->getTemperature(), + data->getListId().c_str(), + data->getMeterId().c_str(), + getMeterModel(data).c_str(), + data->getActiveImportPower(), + data->getReactiveImportPower(), + data->getActiveExportPower(), + data->getReactiveExportPower(), + data->getL1Current(), + data->getL2Current(), + data->getL3Current(), + data->getL1Voltage(), + data->getL2Voltage(), + data->getL3Voltage(), + data->getActiveImportCounter(), + data->getActiveExportCounter(), + data->getReactiveImportCounter(), + data->getReactiveExportCounter(), + data->getMeterTimestamp(), + ea->getUseThisHour(), + ea->getUseToday(), + ea->getCurrentThreshold(), + ea->getMonthMax(), + ea->getProducedThisHour(), + ea->getProducedToday() + ); + return mqtt->publish(topic, json); +} + +bool JsonMqttHandler::publishList4(AmsData* data, EnergyAccounting* ea) { + snprintf_P(json, BufferSize, JSON4_JSON, + WiFi.macAddress().c_str(), + clientId.c_str(), + (uint32_t) (millis64()/1000), + data->getPackageTimestamp(), + hw->getVcc(), + hw->getWifiRssi(), + hw->getTemperature(), + data->getListId().c_str(), + data->getMeterId().c_str(), + getMeterModel(data).c_str(), + data->getActiveImportPower(), + data->getL1ActiveImportPower(), + data->getL2ActiveImportPower(), + data->getL3ActiveImportPower(), + data->getReactiveImportPower(), + data->getActiveExportPower(), + data->getL1ActiveExportPower(), + data->getL2ActiveExportPower(), + data->getL3ActiveExportPower(), + data->getReactiveExportPower(), + data->getL1Current(), + data->getL2Current(), + data->getL3Current(), + data->getL1Voltage(), + data->getL2Voltage(), + data->getL3Voltage(), + data->getPowerFactor(), + data->getL1PowerFactor(), + data->getL2PowerFactor(), + data->getL3PowerFactor(), + data->getActiveImportCounter(), + data->getActiveExportCounter(), + data->getReactiveImportCounter(), + data->getReactiveExportCounter(), + data->getMeterTimestamp(), + ea->getUseThisHour(), + ea->getUseToday(), + ea->getCurrentThreshold(), + ea->getMonthMax(), + ea->getProducedThisHour(), + ea->getProducedToday() + ); + return mqtt->publish(topic, json); +} + +String JsonMqttHandler::getMeterModel(AmsData* data) { String meterModel = data->getMeterModel(); meterModel.replace("\\", "\\\\"); - if(data->getListType() == 1) { - snprintf_P(json, BufferSize, JSON1_JSON, - WiFi.macAddress().c_str(), - clientId.c_str(), - (uint32_t) (millis64()/1000), - data->getPackageTimestamp(), - hw->getVcc(), - hw->getWifiRssi(), - hw->getTemperature(), - data->getActiveImportPower(), - ea->getUseThisHour(), - ea->getUseToday(), - ea->getCurrentThreshold(), - ea->getMonthMax(), - ea->getProducedThisHour(), - ea->getProducedToday() - ); - ret = mqtt->publish(topic, json); - } else if(data->getListType() == 2) { - snprintf_P(json, BufferSize, JSON2_JSON, - WiFi.macAddress().c_str(), - clientId.c_str(), - (uint32_t) (millis64()/1000), - data->getPackageTimestamp(), - hw->getVcc(), - hw->getWifiRssi(), - hw->getTemperature(), - data->getListId().c_str(), - data->getMeterId().c_str(), - meterModel.c_str(), - data->getActiveImportPower(), - data->getReactiveImportPower(), - data->getActiveExportPower(), - data->getReactiveExportPower(), - data->getL1Current(), - data->getL2Current(), - data->getL3Current(), - data->getL1Voltage(), - data->getL2Voltage(), - data->getL3Voltage(), - ea->getUseThisHour(), - ea->getUseToday(), - ea->getCurrentThreshold(), - ea->getMonthMax(), - ea->getProducedThisHour(), - ea->getProducedToday() - ); - ret = mqtt->publish(topic, json); - } else if(data->getListType() == 3) { - snprintf_P(json, BufferSize, JSON3_JSON, - WiFi.macAddress().c_str(), - clientId.c_str(), - (uint32_t) (millis64()/1000), - data->getPackageTimestamp(), - hw->getVcc(), - hw->getWifiRssi(), - hw->getTemperature(), - data->getListId().c_str(), - data->getMeterId().c_str(), - meterModel.c_str(), - data->getActiveImportPower(), - data->getReactiveImportPower(), - data->getActiveExportPower(), - data->getReactiveExportPower(), - data->getL1Current(), - data->getL2Current(), - data->getL3Current(), - data->getL1Voltage(), - data->getL2Voltage(), - data->getL3Voltage(), - data->getActiveImportCounter(), - data->getActiveExportCounter(), - data->getReactiveImportCounter(), - data->getReactiveExportCounter(), - data->getMeterTimestamp(), - ea->getUseThisHour(), - ea->getUseToday(), - ea->getCurrentThreshold(), - ea->getMonthMax(), - ea->getProducedThisHour(), - ea->getProducedToday() - ); - ret = mqtt->publish(topic, json); - } else if(data->getListType() == 4) { - snprintf_P(json, BufferSize, JSON4_JSON, - WiFi.macAddress().c_str(), - clientId.c_str(), - (uint32_t) (millis64()/1000), - data->getPackageTimestamp(), - hw->getVcc(), - hw->getWifiRssi(), - hw->getTemperature(), - data->getListId().c_str(), - data->getMeterId().c_str(), - meterModel.c_str(), - data->getActiveImportPower(), - data->getL1ActiveImportPower(), - data->getL2ActiveImportPower(), - data->getL3ActiveImportPower(), - data->getReactiveImportPower(), - data->getActiveExportPower(), - data->getL1ActiveExportPower(), - data->getL2ActiveExportPower(), - data->getL3ActiveExportPower(), - data->getReactiveExportPower(), - data->getL1Current(), - data->getL2Current(), - data->getL3Current(), - data->getL1Voltage(), - data->getL2Voltage(), - data->getL3Voltage(), - data->getPowerFactor(), - data->getL1PowerFactor(), - data->getL2PowerFactor(), - data->getL3PowerFactor(), - data->getActiveImportCounter(), - data->getActiveExportCounter(), - data->getReactiveImportCounter(), - data->getReactiveExportCounter(), - data->getMeterTimestamp(), - ea->getUseThisHour(), - ea->getUseToday(), - ea->getCurrentThreshold(), - ea->getMonthMax(), - ea->getProducedThisHour(), - ea->getProducedToday() - ); - ret = mqtt->publish(topic, json); - } - mqtt->loop(); - delay(10); - return ret; + return meterModel; } bool JsonMqttHandler::publishTemperatures(AmsConfiguration* config, HwTools* hw) { @@ -173,8 +192,7 @@ bool JsonMqttHandler::publishTemperatures(AmsConfiguration* config, HwTools* hw) char* pos = json+strlen(json); snprintf_P(count == 0 ? pos : pos-1, 8, PSTR("}}")); bool ret = mqtt->publish(topic, json); - mqtt->loop(); - delay(10); + loop(); return ret; } @@ -308,8 +326,7 @@ bool JsonMqttHandler::publishPrices(EntsoeApi* eapi) { ts6hr ); bool ret = mqtt->publish(topic, json); - mqtt->loop(); - delay(10); + loop(); return ret; } @@ -327,7 +344,18 @@ bool JsonMqttHandler::publishSystem(HwTools* hw, EntsoeApi* eapi, EnergyAccounti VERSION ); bool ret = mqtt->publish(topic, json); - mqtt->loop(); - delay(10); + loop(); + return ret; +} + +bool JsonMqttHandler::loop() { + bool ret = mqtt->loop(); + delay(10); + yield(); + #if defined(ESP32) + esp_task_wdt_reset(); + #elif defined(ESP8266) + ESP.wdtFeed(); + #endif return ret; } diff --git a/lib/RawMqttHandler/include/RawMqttHandler.h b/lib/RawMqttHandler/include/RawMqttHandler.h index 5f3ce754..5ab9b1bb 100644 --- a/lib/RawMqttHandler/include/RawMqttHandler.h +++ b/lib/RawMqttHandler/include/RawMqttHandler.h @@ -14,8 +14,17 @@ public: bool publishPrices(EntsoeApi*); bool publishSystem(HwTools* hw, EntsoeApi* eapi, EnergyAccounting* ea); +protected: + bool loop(); + private: String topic; bool full; + + bool publishList1(AmsData* data, AmsData* meterState); + bool publishList2(AmsData* data, AmsData* meterState); + bool publishList3(AmsData* data, AmsData* meterState); + bool publishList4(AmsData* data, AmsData* meterState); + bool publishRealtime(EnergyAccounting* ea); }; #endif diff --git a/lib/RawMqttHandler/src/RawMqttHandler.cpp b/lib/RawMqttHandler/src/RawMqttHandler.cpp index 41258854..a906dfb3 100644 --- a/lib/RawMqttHandler/src/RawMqttHandler.cpp +++ b/lib/RawMqttHandler/src/RawMqttHandler.cpp @@ -11,103 +11,133 @@ bool RawMqttHandler::publish(AmsData* data, AmsData* meterState, EnergyAccountin } switch(data->getListType()) { case 4: - if(full || meterState->getL1ActiveImportPower() != data->getL1ActiveImportPower()) { - mqtt->publish(topic + "/meter/import/l1", String(data->getL1ActiveImportPower(), 2)); - } - if(full || meterState->getL2ActiveImportPower() != data->getL2ActiveImportPower()) { - mqtt->publish(topic + "/meter/import/l2", String(data->getL2ActiveImportPower(), 2)); - } - if(full || meterState->getL3ActiveImportPower() != data->getL3ActiveImportPower()) { - mqtt->publish(topic + "/meter/import/l3", String(data->getL3ActiveImportPower(), 2)); - } - if(full || meterState->getL1ActiveExportPower() != data->getL1ActiveExportPower()) { - mqtt->publish(topic + "/meter/export/l1", String(data->getL1ActiveExportPower(), 2)); - } - if(full || meterState->getL2ActiveExportPower() != data->getL2ActiveExportPower()) { - mqtt->publish(topic + "/meter/export/l2", String(data->getL2ActiveExportPower(), 2)); - } - if(full || meterState->getL3ActiveExportPower() != data->getL3ActiveExportPower()) { - mqtt->publish(topic + "/meter/export/l3", String(data->getL3ActiveExportPower(), 2)); - } - if(full || meterState->getPowerFactor() != data->getPowerFactor()) { - mqtt->publish(topic + "/meter/powerfactor", String(data->getPowerFactor(), 2)); - } - if(full || meterState->getL1PowerFactor() != data->getL1PowerFactor()) { - mqtt->publish(topic + "/meter/l1/powerfactor", String(data->getL1PowerFactor(), 2)); - } - if(full || meterState->getL2PowerFactor() != data->getL2PowerFactor()) { - mqtt->publish(topic + "/meter/l2/powerfactor", String(data->getL2PowerFactor(), 2)); - } - if(full || meterState->getL3PowerFactor() != data->getL3PowerFactor()) { - mqtt->publish(topic + "/meter/l3/powerfactor", String(data->getL3PowerFactor(), 2)); - } + publishList4(data, meterState); + loop(); case 3: - // ID and type belongs to List 2, but I see no need to send that every 10s - mqtt->publish(topic + "/meter/id", data->getMeterId(), true, 0); - mqtt->publish(topic + "/meter/type", data->getMeterModel(), true, 0); - mqtt->publish(topic + "/meter/clock", String(data->getMeterTimestamp())); - mqtt->publish(topic + "/meter/import/reactive/accumulated", String(data->getReactiveImportCounter(), 3), true, 0); - mqtt->publish(topic + "/meter/import/active/accumulated", String(data->getActiveImportCounter(), 3), true, 0); - mqtt->publish(topic + "/meter/export/reactive/accumulated", String(data->getReactiveExportCounter(), 3), true, 0); - mqtt->publish(topic + "/meter/export/active/accumulated", String(data->getActiveExportCounter(), 3), true, 0); + publishList3(data, meterState); + loop(); case 2: - // Only send data if changed. ID and Type is sent on the 10s interval only if changed - if(full || meterState->getMeterId() != data->getMeterId()) { - mqtt->publish(topic + "/meter/id", data->getMeterId()); - } - if(full || meterState->getMeterModel() != data->getMeterModel()) { - mqtt->publish(topic + "/meter/type", data->getMeterModel()); - } - if(full || meterState->getL1Current() != data->getL1Current()) { - mqtt->publish(topic + "/meter/l1/current", String(data->getL1Current(), 2)); - } - if(full || meterState->getL1Voltage() != data->getL1Voltage()) { - mqtt->publish(topic + "/meter/l1/voltage", String(data->getL1Voltage(), 2)); - } - if(full || meterState->getL2Current() != data->getL2Current()) { - mqtt->publish(topic + "/meter/l2/current", String(data->getL2Current(), 2)); - } - if(full || meterState->getL2Voltage() != data->getL2Voltage()) { - mqtt->publish(topic + "/meter/l2/voltage", String(data->getL2Voltage(), 2)); - } - if(full || meterState->getL3Current() != data->getL3Current()) { - mqtt->publish(topic + "/meter/l3/current", String(data->getL3Current(), 2)); - } - if(full || meterState->getL3Voltage() != data->getL3Voltage()) { - mqtt->publish(topic + "/meter/l3/voltage", String(data->getL3Voltage(), 2)); - } - if(full || meterState->getReactiveExportPower() != data->getReactiveExportPower()) { - mqtt->publish(topic + "/meter/export/reactive", String(data->getReactiveExportPower())); - } - if(full || meterState->getActiveExportPower() != data->getActiveExportPower()) { - mqtt->publish(topic + "/meter/export/active", String(data->getActiveExportPower())); - } - if(full || meterState->getReactiveImportPower() != data->getReactiveImportPower()) { - mqtt->publish(topic + "/meter/import/reactive", String(data->getReactiveImportPower())); - } + publishList2(data, meterState); + loop(); case 1: - if(full || meterState->getActiveImportPower() != data->getActiveImportPower()) { - mqtt->publish(topic + "/meter/import/active", String(data->getActiveImportPower())); - } + publishList1(data, meterState); + loop(); } if(ea->isInitialized()) { - mqtt->publish(topic + "/realtime/import/hour", String(ea->getUseThisHour(), 3)); - mqtt->publish(topic + "/realtime/import/day", String(ea->getUseToday(), 2)); - mqtt->publish(topic + "/realtime/import/month", String(ea->getUseThisMonth(), 1)); - uint8_t peakCount = ea->getConfig()->hours; - if(peakCount > 5) peakCount = 5; - for(uint8_t i = 1; i <= peakCount; i++) { - mqtt->publish(topic + "/realtime/import/peak/" + String(i, 10), String(ea->getPeak(i).value / 100.0, 10), true, 0); - } - mqtt->publish(topic + "/realtime/import/threshold", String(ea->getCurrentThreshold(), 10), true, 0); - mqtt->publish(topic + "/realtime/import/monthmax", String(ea->getMonthMax(), 3), true, 0); - mqtt->publish(topic + "/realtime/export/hour", String(ea->getProducedThisHour(), 3)); - mqtt->publish(topic + "/realtime/export/day", String(ea->getProducedToday(), 2)); - mqtt->publish(topic + "/realtime/export/month", String(ea->getProducedThisMonth(), 1)); + publishRealtime(ea); + loop(); } return true; } +bool RawMqttHandler::publishList1(AmsData* data, AmsData* meterState) { + if(full || meterState->getActiveImportPower() != data->getActiveImportPower()) { + mqtt->publish(topic + "/meter/import/active", String(data->getActiveImportPower())); + } + return true; +} + +bool RawMqttHandler::publishList2(AmsData* data, AmsData* meterState) { + // Only send data if changed. ID and Type is sent on the 10s interval only if changed + if(full || meterState->getMeterId() != data->getMeterId()) { + mqtt->publish(topic + "/meter/id", data->getMeterId()); + } + if(full || meterState->getMeterModel() != data->getMeterModel()) { + mqtt->publish(topic + "/meter/type", data->getMeterModel()); + } + if(full || meterState->getL1Current() != data->getL1Current()) { + mqtt->publish(topic + "/meter/l1/current", String(data->getL1Current(), 2)); + } + if(full || meterState->getL1Voltage() != data->getL1Voltage()) { + mqtt->publish(topic + "/meter/l1/voltage", String(data->getL1Voltage(), 2)); + } + if(full || meterState->getL2Current() != data->getL2Current()) { + mqtt->publish(topic + "/meter/l2/current", String(data->getL2Current(), 2)); + } + if(full || meterState->getL2Voltage() != data->getL2Voltage()) { + mqtt->publish(topic + "/meter/l2/voltage", String(data->getL2Voltage(), 2)); + } + if(full || meterState->getL3Current() != data->getL3Current()) { + mqtt->publish(topic + "/meter/l3/current", String(data->getL3Current(), 2)); + } + if(full || meterState->getL3Voltage() != data->getL3Voltage()) { + mqtt->publish(topic + "/meter/l3/voltage", String(data->getL3Voltage(), 2)); + } + if(full || meterState->getReactiveExportPower() != data->getReactiveExportPower()) { + mqtt->publish(topic + "/meter/export/reactive", String(data->getReactiveExportPower())); + } + if(full || meterState->getActiveExportPower() != data->getActiveExportPower()) { + mqtt->publish(topic + "/meter/export/active", String(data->getActiveExportPower())); + } + if(full || meterState->getReactiveImportPower() != data->getReactiveImportPower()) { + mqtt->publish(topic + "/meter/import/reactive", String(data->getReactiveImportPower())); + } + return true; +} + +bool RawMqttHandler::publishList3(AmsData* data, AmsData* meterState) { + // ID and type belongs to List 2, but I see no need to send that every 10s + mqtt->publish(topic + "/meter/id", data->getMeterId(), true, 0); + mqtt->publish(topic + "/meter/type", data->getMeterModel(), true, 0); + mqtt->publish(topic + "/meter/clock", String(data->getMeterTimestamp())); + mqtt->publish(topic + "/meter/import/reactive/accumulated", String(data->getReactiveImportCounter(), 3), true, 0); + mqtt->publish(topic + "/meter/import/active/accumulated", String(data->getActiveImportCounter(), 3), true, 0); + mqtt->publish(topic + "/meter/export/reactive/accumulated", String(data->getReactiveExportCounter(), 3), true, 0); + mqtt->publish(topic + "/meter/export/active/accumulated", String(data->getActiveExportCounter(), 3), true, 0); + return true; +} + +bool RawMqttHandler::publishList4(AmsData* data, AmsData* meterState) { + if(full || meterState->getL1ActiveImportPower() != data->getL1ActiveImportPower()) { + mqtt->publish(topic + "/meter/import/l1", String(data->getL1ActiveImportPower(), 2)); + } + if(full || meterState->getL2ActiveImportPower() != data->getL2ActiveImportPower()) { + mqtt->publish(topic + "/meter/import/l2", String(data->getL2ActiveImportPower(), 2)); + } + if(full || meterState->getL3ActiveImportPower() != data->getL3ActiveImportPower()) { + mqtt->publish(topic + "/meter/import/l3", String(data->getL3ActiveImportPower(), 2)); + } + if(full || meterState->getL1ActiveExportPower() != data->getL1ActiveExportPower()) { + mqtt->publish(topic + "/meter/export/l1", String(data->getL1ActiveExportPower(), 2)); + } + if(full || meterState->getL2ActiveExportPower() != data->getL2ActiveExportPower()) { + mqtt->publish(topic + "/meter/export/l2", String(data->getL2ActiveExportPower(), 2)); + } + if(full || meterState->getL3ActiveExportPower() != data->getL3ActiveExportPower()) { + mqtt->publish(topic + "/meter/export/l3", String(data->getL3ActiveExportPower(), 2)); + } + if(full || meterState->getPowerFactor() != data->getPowerFactor()) { + mqtt->publish(topic + "/meter/powerfactor", String(data->getPowerFactor(), 2)); + } + if(full || meterState->getL1PowerFactor() != data->getL1PowerFactor()) { + mqtt->publish(topic + "/meter/l1/powerfactor", String(data->getL1PowerFactor(), 2)); + } + if(full || meterState->getL2PowerFactor() != data->getL2PowerFactor()) { + mqtt->publish(topic + "/meter/l2/powerfactor", String(data->getL2PowerFactor(), 2)); + } + if(full || meterState->getL3PowerFactor() != data->getL3PowerFactor()) { + mqtt->publish(topic + "/meter/l3/powerfactor", String(data->getL3PowerFactor(), 2)); + } + return true; +} + +bool RawMqttHandler::publishRealtime(EnergyAccounting* ea) { + mqtt->publish(topic + "/realtime/import/hour", String(ea->getUseThisHour(), 3)); + mqtt->publish(topic + "/realtime/import/day", String(ea->getUseToday(), 2)); + mqtt->publish(topic + "/realtime/import/month", String(ea->getUseThisMonth(), 1)); + uint8_t peakCount = ea->getConfig()->hours; + if(peakCount > 5) peakCount = 5; + for(uint8_t i = 1; i <= peakCount; i++) { + mqtt->publish(topic + "/realtime/import/peak/" + String(i, 10), String(ea->getPeak(i).value / 100.0, 10), true, 0); + } + mqtt->publish(topic + "/realtime/import/threshold", String(ea->getCurrentThreshold(), 10), true, 0); + mqtt->publish(topic + "/realtime/import/monthmax", String(ea->getMonthMax(), 3), true, 0); + mqtt->publish(topic + "/realtime/export/hour", String(ea->getProducedThisHour(), 3)); + mqtt->publish(topic + "/realtime/export/day", String(ea->getProducedToday(), 2)); + mqtt->publish(topic + "/realtime/export/month", String(ea->getProducedThisMonth(), 1)); + return true; +} + bool RawMqttHandler::publishTemperatures(AmsConfiguration* config, HwTools* hw) { uint8_t c = hw->getTempSensorCount(); for(int i = 0; i < c; i++) { @@ -248,4 +278,16 @@ bool RawMqttHandler::publishSystem(HwTools* hw, EntsoeApi* eapi, EnergyAccountin mqtt->publish(topic + "/temperature", String(hw->getTemperature(), 2)); } return true; -} \ No newline at end of file +} + +bool RawMqttHandler::loop() { + bool ret = mqtt->loop(); + delay(10); + yield(); + #if defined(ESP32) + esp_task_wdt_reset(); + #elif defined(ESP8266) + ESP.wdtFeed(); + #endif + return ret; +} diff --git a/lib/SvelteUi/src/AmsWebServer.cpp b/lib/SvelteUi/src/AmsWebServer.cpp index 3b416f3a..5ad5000b 100644 --- a/lib/SvelteUi/src/AmsWebServer.cpp +++ b/lib/SvelteUi/src/AmsWebServer.cpp @@ -1604,6 +1604,7 @@ void AmsWebServer::firmwarePost() { if(rebootForUpgrade) { server.send(200); } else { + config->setUpgradeInformation(0xFF, 0xFF, VERSION, ""); if(server.hasArg(F("url"))) { String url = server.arg(F("url")); if(!url.isEmpty() && (url.startsWith(F("http://")) || url.startsWith(F("https://")))) { diff --git a/platformio.ini b/platformio.ini index ad903c15..cadab69a 100755 --- a/platformio.ini +++ b/platformio.ini @@ -20,7 +20,7 @@ build_flags = lib_deps = WiFi, ESPmDNS, WiFiClientSecure, HTTPClient, FS, Update, HTTPUpdate, WebServer, ${common.lib_deps} [env:esp8266] -platform = espressif8266@3.2.0 +platform = espressif8266@4.2.0 framework = arduino board = esp12e board_build.ldscript = eagle.flash.4m2m.ld @@ -32,7 +32,7 @@ lib_ignore = ${common.lib_ignore} extra_scripts = ${common.extra_scripts} [env:esp32] -platform = https://github.com/tasmota/platform-espressif32/releases/download/v2.0.5.3/platform-espressif32-2.0.5.3.zip +platform = https://github.com/tasmota/platform-espressif32/releases/download/2023.02.00/platform-espressif32.zip framework = arduino board = esp32dev board_build.f_cpu = 160000000L @@ -47,7 +47,7 @@ extra_scripts = ${common.extra_scripts} # https://github.com/Jason2866/esp32-arduino-lib-builder [env:esp32s2] -platform = https://github.com/tasmota/platform-espressif32/releases/download/v2.0.5.3/platform-espressif32-2.0.5.3.zip +platform = https://github.com/tasmota/platform-espressif32/releases/download/2023.02.00/platform-espressif32.zip framework = arduino board = esp32-s2-saola-1 board_build.mcu = esp32s2 @@ -63,7 +63,7 @@ lib_ignore = ${common.lib_ignore} extra_scripts = ${common.extra_scripts} [env:esp32solo] -platform = https://github.com/tasmota/platform-espressif32/releases/download/v2.0.5.3/platform-espressif32-2.0.5.3.zip +platform = https://github.com/tasmota/platform-espressif32/releases/download/2023.02.00/platform-espressif32.zip framework = arduino board = esp32-solo1 board_build.f_cpu = 160000000L @@ -75,7 +75,7 @@ lib_ignore = ${common.lib_ignore} extra_scripts = ${common.extra_scripts} [env:esp32c3] -platform = https://github.com/tasmota/platform-espressif32/releases/download/v2.0.5.3/platform-espressif32-2.0.5.3.zip +platform = https://github.com/tasmota/platform-espressif32/releases/download/2023.02.00/platform-espressif32.zip framework = arduino board = esp32-c3-devkitm-1 board_build.mcu = esp32c3 diff --git a/src/AmsToMqttBridge.ino b/src/AmsToMqttBridge.ino index 4cd04d45..054f2a13 100644 --- a/src/AmsToMqttBridge.ino +++ b/src/AmsToMqttBridge.ino @@ -109,6 +109,7 @@ Stream *hanSerial; SoftwareSerial *swSerial = NULL; HardwareSerial *hwSerial = NULL; size_t rxBufferSize = 128; +uint8_t rxBufferErrors = 0; GpioConfig gpioConfig; MeterConfig meterConfig; @@ -117,6 +118,8 @@ String topic = "ams"; AmsData meterState; bool ntpEnabled = false; +bool mdnsEnabled = false; + AmsDataStorage ds(&Debug); EnergyAccounting ea(&Debug); @@ -306,6 +309,7 @@ void setup() { } flashed = Update.end(true); } + config.setUpgradeInformation(flashed ? 2 : 0, 0xFF, VERSION, ""); firmwareFile.close(); } else { debugW_P(PSTR("AP button pressed, skipping firmware update and deleting firmware file.")); @@ -430,27 +434,32 @@ void loop() { if(hwSerial != NULL) { #if defined ESP8266 if(hwSerial->hasRxError()) { + debugE_P(PSTR("Serial RX error")); meterState.setLastError(METER_ERROR_RX); } if(hwSerial->hasOverrun()) { + debugE_P(PSTR("Serial buffer overflow")); meterState.setLastError(METER_ERROR_BUFFER); - if(rxBufferSize < MAX_RX_BUFFER_SIZE) { - /* - rxBufferSize += 64; + rxBufferErrors++; + if(rxBufferErrors > 3 && rxBufferSize < MAX_RX_BUFFER_SIZE) { + rxBufferSize += 128; debugI_P(PSTR("Increasing RX buffer to %d bytes"), rxBufferSize); config.setMeterChanged(); - */ + rxBufferErrors = 0; } } #endif } else if(swSerial != NULL) { if(swSerial->overflow()) { + debugE_P(PSTR("Serial buffer overflow")); meterState.setLastError(METER_ERROR_BUFFER); - /* - rxBufferSize += 64; - debugI_P(PSTR("Increasing RX buffer to %d bytes"), rxBufferSize); - config.setMeterChanged(); - */ + rxBufferErrors++; + if(rxBufferErrors > 3 && rxBufferSize < MAX_RX_BUFFER_SIZE) { + rxBufferSize += 128; + debugI_P(PSTR("Increasing RX buffer to %d bytes"), rxBufferSize); + config.setMeterChanged(); + rxBufferErrors = 0; + } } } @@ -516,9 +525,11 @@ void loop() { debugI_P(PSTR("GW: %s"), WiFi.gatewayIP().toString().c_str()); debugI_P(PSTR("DNS: %s"), WiFi.dnsIP().toString().c_str()); } + mdnsEnabled = false; if(strlen(wifi.hostname) > 0 && wifi.mdns) { debugD_P(PSTR("mDNS is enabled, using host: %s"), wifi.hostname); if(MDNS.begin(wifi.hostname)) { + mdnsEnabled = true; MDNS.addService(F("http"), F("tcp"), 80); } else { debugE_P(PSTR("Failed to set up mDNS!")); @@ -548,7 +559,14 @@ void loop() { config.ackNtpChange(); } #if defined ESP8266 - MDNS.update(); + if(mdnsEnabled) { + start = millis(); + MDNS.update(); + end = millis(); + if(end - start > 1000) { + debugW_P(PSTR("Used %dms to update mDNS"), millis()-start); + } + } #endif if (mqttEnabled || config.isMqttChanged()) { @@ -576,6 +594,11 @@ void loop() { if(end - start > 1000) { debugW_P(PSTR("Used %dms to publish prices to MQTT"), millis()-start); } + } else { + end = millis(); + if(end - start > 1000) { + debugW_P(PSTR("Used %dms to handle price API"), millis()-start); + } } } @@ -648,7 +671,7 @@ void loop() { if(readHanPort() || now - meterState.getLastUpdateMillis() > 30000) { end = millis(); if(end - start > 1000) { - debugW_P(PSTR("Used %dms to read HAN port"), millis()-start); + debugW_P(PSTR("Used %dms to read HAN port (true)"), millis()-start); } if(now - lastTemperatureRead > 15000) { start = millis(); @@ -675,6 +698,11 @@ void loop() { debugW_P(PSTR("Used %dms to send system update to MQTT"), millis()-start); } } + } else { + end = millis(); + if(end - start > 1000) { + debugW_P(PSTR("Used %dms to read HAN port (false)"), millis()-start); + } } } catch(const std::exception& e) { debugE_P(PSTR("Exception in readHanPort (%s)"), e.what()); @@ -704,7 +732,8 @@ void loop() { meterState.setLastError(METER_ERROR_AUTODETECT); } - delay(1); // Needed for auto modem sleep + delay(10); // Needed for auto modem sleep + start = millis(); #if defined(ESP32) esp_task_wdt_reset(); #elif defined(ESP8266) @@ -713,6 +742,10 @@ void loop() { yield(); end = millis(); + if(end-start > 1000) { + debugW_P(PSTR("Used %dms to feed WDT"), end-start); + } + if(end-now > 2000) { debugW_P(PSTR("loop() used %dms"), end-now); } @@ -726,14 +759,14 @@ void rxerr(int err) { debugE_P(PSTR("Serial break error")); break; case 2: - debugE_P(PSTR("Serial buffer full")); - /* - if(rxBufferSize < MAX_RX_BUFFER_SIZE) { - rxBufferSize += 64; + debugE_P(PSTR("Serial buffer overflow")); + rxBufferErrors++; + if(rxBufferErrors > 3 && rxBufferSize < MAX_RX_BUFFER_SIZE) { + rxBufferSize += 128; debugI_P(PSTR("Increasing RX buffer to %d bytes"), rxBufferSize); config.setMeterChanged(); + rxBufferErrors = 0; } - */ break; case 3: debugE_P(PSTR("Serial FIFO overflow")); @@ -886,6 +919,8 @@ void setupHanPort(GpioConfig& gpioConfig, uint32_t baud, uint8_t parityOrdinal, pinMode(gpioConfig.hanPin, INPUT); } + hanSerial->setTimeout(250); + // Empty buffer before starting while (hanSerial->available() > 0) { hanSerial->read(); @@ -988,7 +1023,10 @@ void swapWifiMode() { int len = 0; bool serialInit = false; bool readHanPort() { - if(!hanSerial->available()) return false; + unsigned long start, end; + if(!hanSerial->available()) { + return false; + } // Before reading, empty serial buffer to increase chance of getting first byte of a data transfer if(!serialInit) { @@ -1001,6 +1039,7 @@ bool readHanPort() { strcpy_P((char*) ctx.system_title, PSTR("")); int pos = DATA_PARSE_INCOMPLETE; // For each byte received, check if we have a complete frame we can handle + start = millis(); while(hanSerial->available() && pos == DATA_PARSE_INCOMPLETE) { // If buffer was overflowed, reset if(len >= BUF_SIZE_HAN) { @@ -1024,14 +1063,23 @@ bool readHanPort() { return false; } } + yield(); } + end = millis(); + if(end-start > 1000) { + debugW_P(PSTR("Used %dms to unwrap HAN data"), end-start); + } + if(pos == DATA_PARSE_INCOMPLETE) { return false; } else if(pos == DATA_PARSE_UNKNOWN_DATA) { + debugW_P(PSTR("Unknown data received")); meterState.setLastError(pos); - debugV_P(PSTR("Unknown data payload:")); len = len + hanSerial->readBytes(hanBuffer+len, BUF_SIZE_HAN-len); - if(Debug.isActive(RemoteDebug::VERBOSE)) debugPrint(hanBuffer, 0, len); + if(Debug.isActive(RemoteDebug::VERBOSE)) { + debugV_P(PSTR(" payload:")); + debugPrint(hanBuffer, 0, len); + } len = 0; return false; } @@ -1097,9 +1145,17 @@ bool readHanPort() { len = 0; if(data.getListType() > 0) { + if(rxBufferErrors > 0) rxBufferErrors--; if(!hw.ledBlink(LED_GREEN, 1)) hw.ledBlink(LED_INTERNAL, 1); + if(mqttEnabled && mqttHandler != NULL && mqtt != NULL) { + #if defined(ESP32) + esp_task_wdt_reset(); + #elif defined(ESP8266) + ESP.wdtFeed(); + #endif + yield(); if(mqttHandler->publish(&data, &meterState, &ea, eapi)) { mqtt->loop(); delay(10); @@ -1120,9 +1176,6 @@ bool readHanPort() { settimeofday(&tv, nullptr); } } - if(meterState.getListType() < 3 && now > BUILD_EPOCH) { - // TODO: Load an estimated value from dayplot - } meterState.apply(data); diff --git a/src/IEC6205675.cpp b/src/IEC6205675.cpp index f86dbcd3..03ba8f09 100644 --- a/src/IEC6205675.cpp +++ b/src/IEC6205675.cpp @@ -160,7 +160,6 @@ IEC6205675::IEC6205675(const char* d, uint8_t useMeterType, MeterConfig* meterCo } } // Try system title - /* if(meterType == AmsTypeUnknown) { if(memcmp(ctx.system_title, "SAGY", 4) == 0) { meterType = AmsTypeSagemcom; @@ -168,7 +167,6 @@ IEC6205675::IEC6205675(const char* d, uint8_t useMeterType, MeterConfig* meterCo meterType = AmsTypeKaifa; } } - */ if(meterType == AmsTypeKamstrup || meterType == AmsTypeAidon) { this->packageTimestamp = this->packageTimestamp > 0 ? tz.toUTC(this->packageTimestamp) : 0;