Crossing fingers

This commit is contained in:
Gunnar Skjold
2023-04-18 22:06:29 +02:00
parent c4005f10a3
commit 61040e3e7c
12 changed files with 578 additions and 389 deletions

View File

@@ -9,6 +9,10 @@
#include "HwTools.h"
#include "EntsoeApi.h"
#if defined(ESP32)
#include <esp_task_wdt.h>
#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

View File

@@ -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();

View File

@@ -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:

View File

@@ -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;
}
}
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;
}

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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;
}
}
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;
}

View File

@@ -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://")))) {

View File

@@ -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

View File

@@ -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);

View File

@@ -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;