From 0178dc41845bdb19601ab905bb482ceba42768aa Mon Sep 17 00:00:00 2001 From: Gunnar Skjold Date: Sun, 26 Mar 2023 15:12:24 +0200 Subject: [PATCH] Various fixes for HA --- lib/AmsData/include/AmsMqttHandler.h | 2 +- .../include/DomoticzMqttHandler.h | 2 +- .../src/DomoticzMqttHandler.cpp | 2 +- .../include/HomeAssistantMqttHandler.h | 23 +- .../include/HomeAssistantStatic.h | 125 ++++--- .../json/realtime.json | 9 +- .../src/HomeAssistantMqttHandler.cpp | 323 ++++++++++++++---- lib/JsonMqttHandler/include/JsonMqttHandler.h | 2 +- lib/JsonMqttHandler/json/jsonprices.json | 26 ++ lib/JsonMqttHandler/src/JsonMqttHandler.cpp | 34 +- lib/RawMqttHandler/include/RawMqttHandler.h | 2 +- lib/RawMqttHandler/src/RawMqttHandler.cpp | 2 +- src/AmsToMqttBridge.ino | 2 +- 13 files changed, 423 insertions(+), 131 deletions(-) diff --git a/lib/AmsData/include/AmsMqttHandler.h b/lib/AmsData/include/AmsMqttHandler.h index 7aab475e..fc251527 100644 --- a/lib/AmsData/include/AmsMqttHandler.h +++ b/lib/AmsData/include/AmsMqttHandler.h @@ -17,7 +17,7 @@ public: }; virtual ~AmsMqttHandler() {}; - virtual bool publish(AmsData* data, AmsData* previousState, EnergyAccounting* ea); + virtual bool publish(AmsData* data, AmsData* previousState, EnergyAccounting* ea, EntsoeApi* eapi); virtual bool publishTemperatures(AmsConfiguration*, HwTools*); virtual bool publishPrices(EntsoeApi* eapi); virtual bool publishSystem(HwTools*, EntsoeApi*, EnergyAccounting*); diff --git a/lib/DomoticzMqttHandler/include/DomoticzMqttHandler.h b/lib/DomoticzMqttHandler/include/DomoticzMqttHandler.h index 63824a2c..e0630ff4 100644 --- a/lib/DomoticzMqttHandler/include/DomoticzMqttHandler.h +++ b/lib/DomoticzMqttHandler/include/DomoticzMqttHandler.h @@ -9,7 +9,7 @@ public: DomoticzMqttHandler(MQTTClient* mqtt, char* buf, DomoticzConfig config) : AmsMqttHandler(mqtt, buf) { this->config = config; }; - bool publish(AmsData* data, AmsData* previousState, EnergyAccounting* ea); + bool publish(AmsData* data, AmsData* previousState, EnergyAccounting* ea, EntsoeApi* eapi); bool publishTemperatures(AmsConfiguration*, HwTools*); bool publishPrices(EntsoeApi*); bool publishSystem(HwTools* hw, EntsoeApi* eapi, EnergyAccounting* ea); diff --git a/lib/DomoticzMqttHandler/src/DomoticzMqttHandler.cpp b/lib/DomoticzMqttHandler/src/DomoticzMqttHandler.cpp index 4a2cdd5c..b4dc88de 100644 --- a/lib/DomoticzMqttHandler/src/DomoticzMqttHandler.cpp +++ b/lib/DomoticzMqttHandler/src/DomoticzMqttHandler.cpp @@ -1,7 +1,7 @@ #include "DomoticzMqttHandler.h" #include "json/domoticz_json.h" -bool DomoticzMqttHandler::publish(AmsData* data, AmsData* previousState, EnergyAccounting* ea) { +bool DomoticzMqttHandler::publish(AmsData* data, AmsData* previousState, EnergyAccounting* ea, EntsoeApi* eapi) { bool ret = false; if (config.elidx > 0) { if(data->getActiveImportCounter() > 1.0) { diff --git a/lib/HomeAssistantMqttHandler/include/HomeAssistantMqttHandler.h b/lib/HomeAssistantMqttHandler/include/HomeAssistantMqttHandler.h index 878efa4a..16d179a1 100644 --- a/lib/HomeAssistantMqttHandler/include/HomeAssistantMqttHandler.h +++ b/lib/HomeAssistantMqttHandler/include/HomeAssistantMqttHandler.h @@ -2,6 +2,7 @@ #define _HOMEASSISTANTMQTTHANDLER_H #include "AmsMqttHandler.h" +#include "HomeAssistantStatic.h" class HomeAssistantMqttHandler : public AmsMqttHandler { public: @@ -9,12 +10,28 @@ public: this->clientId = clientId; this->topic = String(topic); this->hw = hw; + l1Init = l2Init = l2eInit = l3Init = l3eInit = l4Init = l4eInit = rtInit = rteInit = pInit = sInit = false; }; - bool publish(AmsData* data, AmsData* previousState, EnergyAccounting* ea); + bool publish(AmsData* data, AmsData* previousState, EnergyAccounting* ea, EntsoeApi* eapi); bool publishTemperatures(AmsConfiguration*, HwTools*); 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(); + private: String haTopic = "homeassistant/sensor/"; @@ -26,7 +43,9 @@ private: #endif String haManuf = "AmsToMqttBridge"; - bool autodiscoverInit = false; + bool l1Init, l2Init, l2eInit, l3Init, l3eInit, l4Init, l4eInit, rtInit, rteInit, pInit, sInit; + bool tInit[32] = {false}; + bool prInit[38] = {false}; String clientId; String topic; diff --git a/lib/HomeAssistantMqttHandler/include/HomeAssistantStatic.h b/lib/HomeAssistantMqttHandler/include/HomeAssistantStatic.h index 1ae24f90..3f4399b2 100644 --- a/lib/HomeAssistantMqttHandler/include/HomeAssistantStatic.h +++ b/lib/HomeAssistantMqttHandler/include/HomeAssistantStatic.h @@ -3,7 +3,7 @@ #include "Arduino.h" -struct HomeAssistantSensor { +typedef struct HomeAssistantSensor { const char* name; const char* topic; const char* path; @@ -13,69 +13,100 @@ struct HomeAssistantSensor { }; -const uint8_t HA_SENSOR_COUNT PROGMEM = 60; -HomeAssistantSensor HA_SENSORS[HA_SENSOR_COUNT] PROGMEM = { - {"Status", "/state", "rssi", "dBm", "signal_strength", "\"measurement\""}, - {"Supply volt", "/state", "vcc", "V", "voltage", "\"measurement\""}, - {"Temperature", "/state", "temp", "°C", "temperature", "\"measurement\""}, - {"Active import", "/power", "P", "W", "power", "\"measurement\""}, - {"L1 active import", "/power", "P1", "W", "power", "\"measurement\""}, - {"L2 active import", "/power", "P2", "W", "power", "\"measurement\""}, - {"L3 active import", "/power", "P3", "W", "power", "\"measurement\""}, +const uint8_t List1SensorCount PROGMEM = 1; +const HomeAssistantSensor List1Sensors[List1SensorCount] PROGMEM = { + {"Active import", "/power", "P", "W", "power", "\"measurement\""} +}; + +const uint8_t List2SensorCount PROGMEM = 8; +const HomeAssistantSensor List2Sensors[List2SensorCount] PROGMEM = { {"Reactive import", "/power", "Q", "var", "reactive_power", "\"measurement\""}, - {"Active export", "/power", "PO", "W", "power", "\"measurement\""}, - {"L1 active export", "/power", "PO1", "W", "power", "\"measurement\""}, - {"L2 active export", "/power", "PO2", "W", "power", "\"measurement\""}, - {"L3 active export", "/power", "PO3", "W", "power", "\"measurement\""}, {"Reactive export", "/power", "QO", "var", "reactive_power", "\"measurement\""}, {"L1 current", "/power", "I1", "A", "current", "\"measurement\""}, {"L2 current", "/power", "I2", "A", "current", "\"measurement\""}, {"L3 current", "/power", "I3", "A", "current", "\"measurement\""}, {"L1 voltage", "/power", "U1", "V", "voltage", "\"measurement\""}, {"L2 voltage", "/power", "U2", "V", "voltage", "\"measurement\""}, - {"L3 voltage", "/power", "U3", "V", "voltage", "\"measurement\""}, + {"L3 voltage", "/power", "U3", "V", "voltage", "\"measurement\""} +}; + +const uint8_t List2ExportSensorCount PROGMEM = 1; +const HomeAssistantSensor List2ExportSensors[List2ExportSensorCount] PROGMEM = { + {"Active export", "/power", "PO", "W", "power", "\"measurement\""} +}; + +const uint8_t List3SensorCount PROGMEM = 3; +const HomeAssistantSensor List3Sensors[List3SensorCount] PROGMEM = { {"Accumulated active import", "/energy", "tPI", "kWh", "energy", "\"total_increasing\""}, - {"Accumulated active export", "/energy", "tPO", "kWh", "energy", "\"total_increasing\""}, - {"Accumulated reactive import","/energy", "tQI", "kvarh","energy", "\"total_increasing\""}, - {"Accumulated reactive export","/energy", "tQO", "kvarh","energy", "\"total_increasing\""}, + {"Accumulated reactive import","/energy", "tQI", "", "energy", "\"total_increasing\""}, + {"Accumulated reactive export","/energy", "tQO", "", "energy", "\"total_increasing\""} +}; + +const uint8_t List3ExportSensorCount PROGMEM = 1; +const HomeAssistantSensor List3ExportSensors[List3ExportSensorCount] PROGMEM = { + {"Accumulated active export", "/energy", "tPO", "kWh", "energy", "\"total_increasing\""} +}; + +const uint8_t List4SensorCount PROGMEM = 7; +const HomeAssistantSensor List4Sensors[List4SensorCount] PROGMEM = { {"Power factor", "/power", "PF", "%", "power_factor", "\"measurement\""}, {"L1 power factor", "/power", "PF1", "%", "power_factor", "\"measurement\""}, {"L2 power factor", "/power", "PF2", "%", "power_factor", "\"measurement\""}, {"L3 power factor", "/power", "PF3", "%", "power_factor", "\"measurement\""}, - {"Price current hour", "/prices", "prices['0']", "", "monetary", ""}, - {"Price next hour", "/prices", "prices['1']", "", "monetary", ""}, - {"Price in two hour", "/prices", "prices['2']", "", "monetary", ""}, - {"Price in three hour", "/prices", "prices['3']", "", "monetary", ""}, - {"Price in four hour", "/prices", "prices['4']", "", "monetary", ""}, - {"Price in five hour", "/prices", "prices['5']", "", "monetary", ""}, - {"Price in six hour", "/prices", "prices['6']", "", "monetary", ""}, - {"Price in seven hour", "/prices", "prices['7']", "", "monetary", ""}, - {"Price in eight hour", "/prices", "prices['8']", "", "monetary", ""}, - {"Price in nine hour", "/prices", "prices['9']", "", "monetary", ""}, - {"Price in ten hour", "/prices", "prices['10']", "", "monetary", ""}, - {"Price in eleven hour", "/prices", "prices['11']", "", "monetary", ""}, + {"L1 active import", "/power", "P1", "W", "power", "\"measurement\""}, + {"L2 active import", "/power", "P2", "W", "power", "\"measurement\""}, + {"L3 active import", "/power", "P3", "W", "power", "\"measurement\""} +}; + +const uint8_t List4ExportSensorCount PROGMEM = 3; +const HomeAssistantSensor List4ExportSensors[List4ExportSensorCount] PROGMEM = { + {"L1 active export", "/power", "PO1", "W", "power", "\"measurement\""}, + {"L2 active export", "/power", "PO2", "W", "power", "\"measurement\""}, + {"L3 active export", "/power", "PO3", "W", "power", "\"measurement\""} +}; + +const uint8_t RealtimeSensorCount PROGMEM = 8; +const HomeAssistantSensor RealtimeSensors[RealtimeSensorCount] PROGMEM = { + {"Month max", "/realtime","max", "kWh", "energy", ""}, + {"Tariff threshold", "/realtime","threshold", "kWh", "energy", ""}, + {"Current hour used", "/realtime","hour.use", "kWh", "energy", ""}, + {"Current hour cost", "/realtime","hour.cost", "", "monetary", ""}, + {"Current day used", "/realtime","day.use", "kWh", "energy", ""}, + {"Current day cost", "/realtime","day.cost", "", "monetary", ""}, + {"Current month used", "/realtime","month.use", "kWh", "energy", ""}, + {"Current month cost", "/realtime","month.cost", "", "monetary", ""} +}; + +const uint8_t RealtimeExportSensorCount PROGMEM = 6; +const HomeAssistantSensor RealtimeExportSensors[RealtimeExportSensorCount] PROGMEM = { + {"Current hour produced", "/realtime","hour.produced", "kWh", "energy", ""}, + {"Current hour income", "/realtime","hour.income", "", "monetary", ""}, + {"Current day produced", "/realtime","day.produced", "kWh", "energy", ""}, + {"Current day income", "/realtime","day.income", "", "monetary", ""}, + {"Current month produced", "/realtime","month.produced", "kWh", "energy", ""}, + {"Current month income", "/realtime","month.income", "", "monetary", ""} +}; + +const HomeAssistantSensor RealtimePeakSensor PROGMEM = {"Current month peak %d", "/realtime", "peaks[%d]", "kWh", "energy", ""}; + +const uint8_t PriceSensorCount PROGMEM = 5; +const HomeAssistantSensor PriceSensors[PriceSensorCount] PROGMEM = { {"Minimum price ahead", "/prices", "prices.min", "", "monetary", ""}, {"Maximum price ahead", "/prices", "prices.max", "", "monetary", ""}, {"Cheapest 1hr period ahead", "/prices", "prices.cheapest1hr","", "timestamp", ""}, {"Cheapest 3hr period ahead", "/prices", "prices.cheapest3hr","", "timestamp", ""}, - {"Cheapest 6hr period ahead", "/prices", "prices.cheapest6hr","", "timestamp", ""}, - {"Month max", "/realtime","max", "kWh", "energy", "\"total_increasing\""}, - {"Tariff threshold", "/realtime","threshold", "kWh", "energy", "\"total_increasing\""}, - {"Current hour used", "/realtime","hour.use", "kWh", "energy", "\"total_increasing\""}, - {"Current hour cost", "/realtime","hour.cost", "", "monetary", "\"total_increasing\""}, - {"Current hour produced", "/realtime","hour.produced", "kWh", "energy", "\"total_increasing\""}, - {"Current day used", "/realtime","day.use", "kWh", "energy", "\"total_increasing\""}, - {"Current day cost", "/realtime","day.cost", "", "monetary", "\"total_increasing\""}, - {"Current day produced", "/realtime","day.produced", "kWh", "energy", "\"total_increasing\""}, - {"Current month used", "/realtime","month.use", "kWh", "energy", "\"total_increasing\""}, - {"Current month cost", "/realtime","month.cost", "", "monetary", "\"total_increasing\""}, - {"Current month produced", "/realtime","month.produced", "kWh", "energy", "\"total_increasing\""}, - {"Current month peak 1", "/realtime","peaks[0]", "kWh", "energy", ""}, - {"Current month peak 2", "/realtime","peaks[1]", "kWh", "energy", ""}, - {"Current month peak 3", "/realtime","peaks[2]", "kWh", "energy", ""}, - {"Current month peak 4", "/realtime","peaks[3]", "kWh", "energy", ""}, - {"Current month peak 5", "/realtime","peaks[4]", "kWh", "energy", ""}, + {"Cheapest 6hr period ahead", "/prices", "prices.cheapest6hr","", "timestamp", ""} }; +const HomeAssistantSensor PriceSensor PROGMEM = {"Price in %02d %s", "/prices", "prices['%d']", "", "monetary", ""}; + +const uint8_t SystemSensorCount PROGMEM = 2; +const HomeAssistantSensor SystemSensors[SystemSensorCount] PROGMEM = { + {"Status", "/state", "rssi", "dBm", "signal_strength", "\"measurement\""}, + {"Supply volt", "/state", "vcc", "V", "voltage", "\"measurement\""} +}; + +const HomeAssistantSensor TemperatureSensor PROGMEM = {"Temperature sensor %s", "/temperatures", "temperatures['%s']", "°C", "temperature", "\"measurement\""}; + #endif diff --git a/lib/HomeAssistantMqttHandler/json/realtime.json b/lib/HomeAssistantMqttHandler/json/realtime.json index 06ca2d73..02a86dcb 100644 --- a/lib/HomeAssistantMqttHandler/json/realtime.json +++ b/lib/HomeAssistantMqttHandler/json/realtime.json @@ -5,16 +5,19 @@ "hour" : { "use" : %.2f, "cost" : %.2f, - "produced" : %.2f + "produced" : %.2f, + "income" : %.2f }, "day" : { "use" : %.2f, "cost" : %.2f, - "produced" : %.2f + "produced" : %.2f, + "income" : %.2f }, "month" : { "use" : %.2f, "cost" : %.2f, - "produced" : %.2f + "produced" : %.2f, + "income" : %.2f } } \ No newline at end of file diff --git a/lib/HomeAssistantMqttHandler/src/HomeAssistantMqttHandler.cpp b/lib/HomeAssistantMqttHandler/src/HomeAssistantMqttHandler.cpp index 5f8dc9c8..cf9dd2f0 100644 --- a/lib/HomeAssistantMqttHandler/src/HomeAssistantMqttHandler.cpp +++ b/lib/HomeAssistantMqttHandler/src/HomeAssistantMqttHandler.cpp @@ -1,5 +1,4 @@ #include "HomeAssistantMqttHandler.h" -#include "HomeAssistantStatic.h" #include "hexutils.h" #include "Uptime.h" #include "version.h" @@ -12,11 +11,13 @@ #include "json/hadiscover_json.h" #include "json/realtime_json.h" -bool HomeAssistantMqttHandler::publish(AmsData* data, AmsData* previousState, EnergyAccounting* ea) { +bool HomeAssistantMqttHandler::publish(AmsData* data, AmsData* previousState, EnergyAccounting* ea, EntsoeApi* eapi) { if(topic.isEmpty() || !mqtt->connected()) 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(), @@ -30,11 +31,14 @@ bool HomeAssistantMqttHandler::publish(AmsData* data, AmsData* previousState, En 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(), @@ -52,6 +56,8 @@ bool HomeAssistantMqttHandler::publish(AmsData* data, AmsData* previousState, En ); 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(), @@ -81,6 +87,8 @@ bool HomeAssistantMqttHandler::publish(AmsData* data, AmsData* previousState, En } 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; @@ -95,12 +103,15 @@ bool HomeAssistantMqttHandler::publish(AmsData* data, AmsData* previousState, En ea->getUseThisHour(), ea->getCostThisHour(), ea->getProducedThisHour(), + ea->getIncomeThisHour(), ea->getUseToday(), ea->getCostToday(), ea->getProducedToday(), + ea->getIncomeToday(), ea->getUseThisMonth(), ea->getCostThisMonth(), - ea->getProducedThisMonth() + ea->getProducedThisMonth(), + ea->getIncomeThisMonth() ); mqtt->publish(topic + "/realtime", json); } @@ -110,7 +121,7 @@ bool HomeAssistantMqttHandler::publish(AmsData* data, AmsData* previousState, En bool HomeAssistantMqttHandler::publishTemperatures(AmsConfiguration* config, HwTools* hw) { int count = hw->getTempSensorCount(); - if(count == 0) return false; + if(count < 2) return false; int size = 32 + (count * 26); @@ -121,11 +132,13 @@ bool HomeAssistantMqttHandler::publishTemperatures(AmsConfiguration* config, HwT TempSensorData* data = hw->getTempSensorData(i); if(data != NULL) { char* pos = buf+strlen(buf); + String id = toHex(data->address, 8); snprintf(pos, 26, "\"%s\":%.2f,", - toHex(data->address, 8).c_str(), + id.c_str(), data->lastRead ); data->changed = false; + publishTemperatureSensor(i+1, id); delay(1); } } @@ -140,14 +153,16 @@ bool HomeAssistantMqttHandler::publishPrices(EntsoeApi* eapi) { if(eapi->getValueForHour(0) == ENTSOE_NO_VALUE) return false; + publishPriceSensors(eapi); + time_t now = time(nullptr); float min1hr = 0.0, min3hr = 0.0, min6hr = 0.0; int8_t min1hrIdx = -1, min3hrIdx = -1, min6hrIdx = -1; float min = INT16_MAX, max = INT16_MIN; - float values[24]; - for(int i = 0;i < 24; i++) values[i] = ENTSOE_NO_VALUE; - for(uint8_t i = 0; i < 24; i++) { + float values[38]; + for(int i = 0;i < 38; i++) values[i] = ENTSOE_NO_VALUE; + for(uint8_t i = 0; i < 38; i++) { float val = eapi->getValueForHour(now, i); values[i] = val; @@ -234,6 +249,32 @@ bool HomeAssistantMqttHandler::publishPrices(EntsoeApi* eapi) { values[9], values[10], values[11], + values[12], + values[13], + values[14], + values[15], + values[16], + values[17], + values[18], + values[19], + values[20], + values[21], + values[22], + values[23], + values[24], + values[25], + values[26], + values[27], + values[28], + values[29], + values[30], + values[31], + values[32], + values[33], + values[34], + values[35], + values[36], + values[37], min == INT16_MAX ? 0.0 : min, max == INT16_MIN ? 0.0 : max, ts1hr, @@ -247,6 +288,9 @@ bool HomeAssistantMqttHandler::publishSystem(HwTools* hw, EntsoeApi* eapi, Energ if(topic.isEmpty() || !mqtt->connected()) return false; + publishSystemSensors(); + if(hw->getTemperature() > -50) publishTemperatureSensor(0, ""); + snprintf_P(json, BufferSize, JSONSYS_JSON, WiFi.macAddress().c_str(), clientId.c_str(), @@ -256,64 +300,207 @@ bool HomeAssistantMqttHandler::publishSystem(HwTools* hw, EntsoeApi* eapi, Energ hw->getTemperature(), VERSION ); - mqtt->publish(topic + "/state", json); - - if(!autodiscoverInit) { - #if defined(ESP8266) - String haUID = WiFi.hostname(); - #elif defined(ESP32) - String haUID = WiFi.getHostname(); - #endif - String haUrl = "http://" + haUID + ".local/"; - // Could this be necessary? haUID.replace("-", "_"); - uint8_t peakCount = ea->getConfig()->hours; - if(peakCount > 5) peakCount = 5; - - uint8_t peaks = 0; - for(int i=0;igetCurrency()) + "/kWh"; - } else { - uom = String(eapi->getCurrency()); - } - } - if(strncmp(sensor.path, "peaks[", 6) == 0) { - if(peaks >= peakCount) continue; - peaks++; - } - if(strncmp(sensor.path, "temp", 4) == 0) { - if(hw->getTemperature() < 0) continue; - } - snprintf_P(json, BufferSize, HADISCOVER_JSON, - sensor.name, - topic.c_str(), sensor.topic, - haUID.c_str(), uid.c_str(), - haUID.c_str(), uid.c_str(), - uom.c_str(), - sensor.path, - sensor.devcl, - haUID.c_str(), - haName.c_str(), - haModel.c_str(), - VERSION, - haManuf.c_str(), - haUrl.c_str(), - strlen_P(sensor.stacl) > 0 ? ", \"stat_cla\" :" : "", - strlen_P(sensor.stacl) > 0 ? (char *) FPSTR(sensor.stacl) : "" - ); - mqtt->publish(haTopic + haUID + "_" + uid.c_str() + "/config", json, true, 0); - } - - autodiscoverInit = true; - } - return true; + return mqtt->publish(topic + "/state", json); } + +void HomeAssistantMqttHandler::publishSensor(const HomeAssistantSensor& sensor) { + #if defined(ESP8266) + String haUID = WiFi.hostname(); + #elif defined(ESP32) + String haUID = WiFi.getHostname(); + #endif + String haUrl = "http://" + haUID + ".local/"; + + String uid = String(sensor.path); + uid.replace(".", ""); + uid.replace("[", ""); + uid.replace("]", ""); + uid.replace("'", ""); + String uom = String(sensor.uom); + snprintf_P(json, BufferSize, HADISCOVER_JSON, + sensor.name, + topic.c_str(), sensor.topic, + haUID.c_str(), uid.c_str(), + haUID.c_str(), uid.c_str(), + uom.c_str(), + sensor.path, + sensor.devcl, + haUID.c_str(), + haName.c_str(), + haModel.c_str(), + VERSION, + haManuf.c_str(), + haUrl.c_str(), + strlen_P(sensor.stacl) > 0 ? ", \"stat_cla\" :" : "", + strlen_P(sensor.stacl) > 0 ? (char *) FPSTR(sensor.stacl) : "" + ); + mqtt->publish(haTopic + haUID + "_" + uid.c_str() + "/config", json, true, 0); +} + +void HomeAssistantMqttHandler::publishList1Sensors() { + if(l1Init) return; + for(uint8_t i = 0; i < List1SensorCount; i++) { + publishSensor(List1Sensors[i]); + } + l1Init = true; +} + +void HomeAssistantMqttHandler::publishList2Sensors() { + if(l2Init) return; + for(uint8_t i = 0; i < List2SensorCount; i++) { + publishSensor(List2Sensors[i]); + } + l2Init = true; +} + +void HomeAssistantMqttHandler::publishList2ExportSensors() { + if(l2eInit) return; + for(uint8_t i = 0; i < List2ExportSensorCount; i++) { + publishSensor(List2ExportSensors[i]); + } + l2eInit = true; +} + +void HomeAssistantMqttHandler::publishList3Sensors() { + if(l3Init) return; + for(uint8_t i = 0; i < List3SensorCount; i++) { + publishSensor(List3Sensors[i]); + } + l3Init = true; +} + +void HomeAssistantMqttHandler::publishList3ExportSensors() { + if(l3eInit) return; + for(uint8_t i = 0; i < List3ExportSensorCount; i++) { + publishSensor(List3ExportSensors[i]); + } + l3eInit = true; +} + +void HomeAssistantMqttHandler::publishList4Sensors() { + if(l4Init) return; + for(uint8_t i = 0; i < List4SensorCount; i++) { + publishSensor(List4Sensors[i]); + } + l4Init = true; +} + +void HomeAssistantMqttHandler::publishList4ExportSensors() { + if(l4eInit) return; + for(uint8_t i = 0; i < List4ExportSensorCount; i++) { + publishSensor(List4ExportSensors[i]); + } + l4eInit = true; +} + +void HomeAssistantMqttHandler::publishRealtimeSensors(EnergyAccounting* ea, EntsoeApi* eapi) { + if(rtInit) return; + for(uint8_t i = 0; i < RealtimeSensorCount; i++) { + HomeAssistantSensor sensor = RealtimeSensors[i]; + if(strncmp(sensor.devcl, "monetary", 8) == 0) { + if(eapi == NULL) continue; + sensor.uom = eapi->getCurrency(); + } + publishSensor(sensor); + } + uint8_t peakCount = ea->getConfig()->hours; + if(peakCount > 5) peakCount = 5; + for(uint8_t i = 0; i < peakCount; i++) { + char name[strlen(RealtimePeakSensor.name)]; + snprintf(name, strlen(RealtimePeakSensor.name), RealtimePeakSensor.name, i+1); + char path[strlen(RealtimePeakSensor.path)]; + snprintf(path, strlen(RealtimePeakSensor.path), RealtimePeakSensor.path, i+1); + HomeAssistantSensor sensor = { + name, + RealtimePeakSensor.topic, + path, + RealtimePeakSensor.uom, + RealtimePeakSensor.devcl, + RealtimePeakSensor.stacl + }; + publishSensor(sensor); + } + rtInit = true; +} + +void HomeAssistantMqttHandler::publishRealtimeExportSensors(EnergyAccounting* ea, EntsoeApi* eapi) { + if(rteInit) return; + for(uint8_t i = 0; i < RealtimeExportSensorCount; i++) { + HomeAssistantSensor sensor = RealtimeExportSensors[i]; + if(strncmp(sensor.devcl, "monetary", 8) == 0) { + if(eapi == NULL) continue; + sensor.uom = eapi->getCurrency(); + } + publishSensor(sensor); + } + rteInit = true; +} + +void HomeAssistantMqttHandler::publishTemperatureSensor(uint8_t index, String id) { + if(index > 32) return; + if(tInit[index]) return; + char name[strlen(TemperatureSensor.name)+id.length()]; + snprintf(name, strlen(TemperatureSensor.name)+id.length(), TemperatureSensor.name, id.c_str()); + + char path[strlen(TemperatureSensor.path)+id.length()]; + if(index == 0) { + memcpy_P(path, PSTR("temp\0"), 5); + } else { + snprintf(path, strlen(TemperatureSensor.path)+id.length(), TemperatureSensor.path, id.c_str()); + } + HomeAssistantSensor sensor = { + name, + index == 0 ? SystemSensors[0].topic : TemperatureSensor.topic, + path, + TemperatureSensor.uom, + TemperatureSensor.devcl, + TemperatureSensor.stacl + }; + publishSensor(sensor); + tInit[index] = true; +} + +void HomeAssistantMqttHandler::publishPriceSensors(EntsoeApi* eapi) { + if(eapi == NULL) return; + String uom = String(eapi->getCurrency()) + "/kWh"; + + if(!pInit) { + for(uint8_t i = 0; i < PriceSensorCount; i++) { + HomeAssistantSensor sensor = PriceSensors[i]; + if(strncmp(sensor.devcl, "monetary", 8) == 0) { + sensor.uom = uom.c_str(); + } + publishSensor(sensor); + } + pInit = true; + } + for(uint8_t i = 0; i < 38; i++) { + if(prInit[i]) continue; + float val = eapi->getValueForHour(i); + if(val == ENTSOE_NO_VALUE) continue; + + char name[strlen(PriceSensor.name)+2]; + snprintf(name, strlen(PriceSensor.name)+2, PriceSensor.name, i, i == 1 ? "hour" : "hours"); + char path[strlen(PriceSensor.path)+1]; + snprintf(path, strlen(PriceSensor.path)+1, PriceSensor.path, i); + HomeAssistantSensor sensor = { + i == 0 ? "Price current hour" : name, + PriceSensor.topic, + path, + uom.c_str(), + PriceSensor.devcl, + PriceSensor.stacl + }; + publishSensor(sensor); + prInit[i] = true; + } + +} + +void HomeAssistantMqttHandler::publishSystemSensors() { + if(sInit) return; + for(uint8_t i = 0; i < SystemSensorCount; i++) { + publishSensor(SystemSensors[i]); + } + sInit = true; +} \ No newline at end of file diff --git a/lib/JsonMqttHandler/include/JsonMqttHandler.h b/lib/JsonMqttHandler/include/JsonMqttHandler.h index 63032e36..db75a1b9 100644 --- a/lib/JsonMqttHandler/include/JsonMqttHandler.h +++ b/lib/JsonMqttHandler/include/JsonMqttHandler.h @@ -10,7 +10,7 @@ public: this->topic = String(topic); this->hw = hw; }; - bool publish(AmsData* data, AmsData* previousState, EnergyAccounting* ea); + bool publish(AmsData* data, AmsData* previousState, EnergyAccounting* ea, EntsoeApi* eapi); bool publishTemperatures(AmsConfiguration*, HwTools*); bool publishPrices(EntsoeApi*); bool publishSystem(HwTools* hw, EntsoeApi* eapi, EnergyAccounting* ea); diff --git a/lib/JsonMqttHandler/json/jsonprices.json b/lib/JsonMqttHandler/json/jsonprices.json index 293039ce..71303ced 100644 --- a/lib/JsonMqttHandler/json/jsonprices.json +++ b/lib/JsonMqttHandler/json/jsonprices.json @@ -13,6 +13,32 @@ "9" : %.4f, "10" : %.4f, "11" : %.4f, + "12" : %.4f, + "13" : %.4f, + "14" : %.4f, + "15" : %.4f, + "16" : %.4f, + "17" : %.4f, + "18" : %.4f, + "19" : %.4f, + "20" : %.4f, + "21" : %.4f, + "22" : %.4f, + "23" : %.4f, + "24" : %.4f, + "25" : %.4f, + "26" : %.4f, + "27" : %.4f, + "28" : %.4f, + "29" : %.4f, + "30" : %.4f, + "31" : %.4f, + "32" : %.4f, + "33" : %.4f, + "34" : %.4f, + "35" : %.4f, + "36" : %.4f, + "37" : %.4f, "min" : %.4f, "max" : %.4f, "cheapest1hr" : "%s", diff --git a/lib/JsonMqttHandler/src/JsonMqttHandler.cpp b/lib/JsonMqttHandler/src/JsonMqttHandler.cpp index 8aea11cf..a4bdd0fa 100644 --- a/lib/JsonMqttHandler/src/JsonMqttHandler.cpp +++ b/lib/JsonMqttHandler/src/JsonMqttHandler.cpp @@ -9,7 +9,7 @@ #include "json/jsonsys_json.h" #include "json/jsonprices_json.h" -bool JsonMqttHandler::publish(AmsData* data, AmsData* previousState, EnergyAccounting* ea) { +bool JsonMqttHandler::publish(AmsData* data, AmsData* previousState, EnergyAccounting* ea, EntsoeApi* eapi) { if(topic.isEmpty() || !mqtt->connected()) return false; @@ -183,9 +183,9 @@ bool JsonMqttHandler::publishPrices(EntsoeApi* eapi) { float min1hr = 0.0, min3hr = 0.0, min6hr = 0.0; int8_t min1hrIdx = -1, min3hrIdx = -1, min6hrIdx = -1; float min = INT16_MAX, max = INT16_MIN; - float values[24]; - for(int i = 0;i < 24; i++) values[i] = ENTSOE_NO_VALUE; - for(uint8_t i = 0; i < 24; i++) { + float values[38]; + for(int i = 0;i < 38; i++) values[i] = ENTSOE_NO_VALUE; + for(uint8_t i = 0; i < 38; i++) { float val = eapi->getValueForHour(now, i); values[i] = val; @@ -272,6 +272,32 @@ bool JsonMqttHandler::publishPrices(EntsoeApi* eapi) { values[9], values[10], values[11], + values[12], + values[13], + values[14], + values[15], + values[16], + values[17], + values[18], + values[19], + values[20], + values[21], + values[22], + values[23], + values[24], + values[25], + values[26], + values[27], + values[28], + values[29], + values[30], + values[31], + values[32], + values[33], + values[34], + values[35], + values[36], + values[37], min == INT16_MAX ? 0.0 : min, max == INT16_MIN ? 0.0 : max, ts1hr, diff --git a/lib/RawMqttHandler/include/RawMqttHandler.h b/lib/RawMqttHandler/include/RawMqttHandler.h index 737b72a3..5f3ce754 100644 --- a/lib/RawMqttHandler/include/RawMqttHandler.h +++ b/lib/RawMqttHandler/include/RawMqttHandler.h @@ -9,7 +9,7 @@ public: this->topic = String(topic); this->full = full; }; - bool publish(AmsData* data, AmsData* previousState, EnergyAccounting* ea); + bool publish(AmsData* data, AmsData* previousState, EnergyAccounting* ea, EntsoeApi* eapi); bool publishTemperatures(AmsConfiguration*, HwTools*); bool publishPrices(EntsoeApi*); bool publishSystem(HwTools* hw, EntsoeApi* eapi, EnergyAccounting* ea); diff --git a/lib/RawMqttHandler/src/RawMqttHandler.cpp b/lib/RawMqttHandler/src/RawMqttHandler.cpp index 2ec9e5bc..236baef7 100644 --- a/lib/RawMqttHandler/src/RawMqttHandler.cpp +++ b/lib/RawMqttHandler/src/RawMqttHandler.cpp @@ -2,7 +2,7 @@ #include "hexutils.h" #include "Uptime.h" -bool RawMqttHandler::publish(AmsData* data, AmsData* meterState, EnergyAccounting* ea) { +bool RawMqttHandler::publish(AmsData* data, AmsData* meterState, EnergyAccounting* ea, EntsoeApi* eapi) { if(topic.isEmpty() || !mqtt->connected()) return false; diff --git a/src/AmsToMqttBridge.ino b/src/AmsToMqttBridge.ino index d5fc7d14..161ca9bb 100644 --- a/src/AmsToMqttBridge.ino +++ b/src/AmsToMqttBridge.ino @@ -934,7 +934,7 @@ bool readHanPort() { if(!hw.ledBlink(LED_GREEN, 1)) hw.ledBlink(LED_INTERNAL, 1); if(mqttEnabled && mqttHandler != NULL && mqtt != NULL) { - if(mqttHandler->publish(&data, &meterState, &ea)) { + if(mqttHandler->publish(&data, &meterState, &ea, eapi)) { mqtt->loop(); delay(10); }