Prices and realtime HA sensors

This commit is contained in:
Gunnar Skjold
2022-09-28 20:13:03 +02:00
parent 2a4772fe25
commit e7c25fafda
12 changed files with 149 additions and 35 deletions

View File

@@ -594,7 +594,7 @@ void loop() {
} }
if(now - lastSysupdate > 10000) { if(now - lastSysupdate > 10000) {
if(mqtt != NULL && mqttHandler != NULL && WiFi.getMode() != WIFI_AP && WiFi.status() == WL_CONNECTED && mqtt->connected() && !topic.isEmpty()) { if(mqtt != NULL && mqttHandler != NULL && WiFi.getMode() != WIFI_AP && WiFi.status() == WL_CONNECTED && mqtt->connected() && !topic.isEmpty()) {
mqttHandler->publishSystem(&hw); mqttHandler->publishSystem(&hw, eapi, &ea);
} }
lastSysupdate = now; lastSysupdate = now;
} }
@@ -1379,7 +1379,7 @@ void MQTT_connect() {
if (Debug.isActive(RemoteDebug::INFO)) debugI("Successfully connected to MQTT!"); if (Debug.isActive(RemoteDebug::INFO)) debugI("Successfully connected to MQTT!");
if(mqttHandler != NULL) { if(mqttHandler != NULL) {
mqttHandler->publishSystem(&hw); mqttHandler->publishSystem(&hw, eapi, &ea);
} }
// Subscribe to the chosen MQTT topic, if set in configuration // Subscribe to the chosen MQTT topic, if set in configuration

View File

@@ -19,7 +19,7 @@ public:
virtual bool publish(AmsData* data, AmsData* previousState, EnergyAccounting* ea); virtual bool publish(AmsData* data, AmsData* previousState, EnergyAccounting* ea);
virtual bool publishTemperatures(AmsConfiguration*, HwTools*); virtual bool publishTemperatures(AmsConfiguration*, HwTools*);
virtual bool publishPrices(EntsoeApi* eapi); virtual bool publishPrices(EntsoeApi* eapi);
virtual bool publishSystem(HwTools*); virtual bool publishSystem(HwTools*, EntsoeApi*, EnergyAccounting*);
protected: protected:
MQTTClient* mqtt; MQTTClient* mqtt;

View File

@@ -71,6 +71,6 @@ bool DomoticzMqttHandler::publishPrices(EntsoeApi* eapi) {
return false; return false;
} }
bool DomoticzMqttHandler::publishSystem(HwTools* hw) { bool DomoticzMqttHandler::publishSystem(HwTools* hw, EntsoeApi* eapi, EnergyAccounting* ea) {
return false; return false;
} }

View File

@@ -12,7 +12,7 @@ public:
bool publish(AmsData* data, AmsData* previousState, EnergyAccounting* ea); bool publish(AmsData* data, AmsData* previousState, EnergyAccounting* ea);
bool publishTemperatures(AmsConfiguration*, HwTools*); bool publishTemperatures(AmsConfiguration*, HwTools*);
bool publishPrices(EntsoeApi*); bool publishPrices(EntsoeApi*);
bool publishSystem(HwTools*); bool publishSystem(HwTools* hw, EntsoeApi* eapi, EnergyAccounting* ea);
private: private:
DomoticzConfig config; DomoticzConfig config;

View File

@@ -9,6 +9,7 @@
#include "web/root/jsonsys_json.h" #include "web/root/jsonsys_json.h"
#include "web/root/jsonprices_json.h" #include "web/root/jsonprices_json.h"
#include "web/root/hadiscover_json.h" #include "web/root/hadiscover_json.h"
#include "web/root/realtime_json.h"
bool HomeAssistantMqttHandler::publish(AmsData* data, AmsData* previousState, EnergyAccounting* ea) { bool HomeAssistantMqttHandler::publish(AmsData* data, AmsData* previousState, EnergyAccounting* ea) {
if(topic.isEmpty() || !mqtt->connected()) if(topic.isEmpty() || !mqtt->connected())
@@ -32,7 +33,7 @@ bool HomeAssistantMqttHandler::publish(AmsData* data, AmsData* previousState, En
snprintf_P(json, BufferSize, HA1_JSON, snprintf_P(json, BufferSize, HA1_JSON,
data->getActiveImportPower() data->getActiveImportPower()
); );
return mqtt->publish(topic + "/power", json); mqtt->publish(topic + "/power", json);
} else if(data->getListType() >= 2) { // publish power counts and volts/amps } else if(data->getListType() >= 2) { // publish power counts and volts/amps
snprintf_P(json, BufferSize, HA3_JSON, snprintf_P(json, BufferSize, HA3_JSON,
data->getListId().c_str(), data->getListId().c_str(),
@@ -53,9 +54,31 @@ bool HomeAssistantMqttHandler::publish(AmsData* data, AmsData* previousState, En
data->getPowerFactor() == 0 ? 1 : data->getL2PowerFactor(), data->getPowerFactor() == 0 ? 1 : data->getL2PowerFactor(),
data->getPowerFactor() == 0 ? 1 : data->getL3PowerFactor() data->getPowerFactor() == 0 ? 1 : data->getL3PowerFactor()
); );
return mqtt->publish(topic + "/power", json); mqtt->publish(topic + "/power", json);
} }
return false;
String peaks = "";
for(uint8_t i = 1; i <= ea->getConfig()->hours; i++) {
if(!peaks.isEmpty()) peaks += ",";
peaks += String(ea->getPeak(i));
}
snprintf_P(json, BufferSize, REALTIME_JSON,
ea->getMonthMax(),
peaks.c_str(),
ea->getCurrentThreshold(),
ea->getUseThisHour(),
ea->getCostThisHour(),
ea->getProducedThisHour(),
ea->getUseToday(),
ea->getCostToday(),
ea->getProducedToday(),
ea->getUseThisMonth(),
ea->getCostThisMonth(),
ea->getProducedThisMonth()
);
mqtt->publish(topic + "/realtime", json);
return true;
} }
bool HomeAssistantMqttHandler::publishTemperatures(AmsConfiguration* config, HwTools* hw) { bool HomeAssistantMqttHandler::publishTemperatures(AmsConfiguration* config, HwTools* hw) {
@@ -187,10 +210,10 @@ bool HomeAssistantMqttHandler::publishPrices(EntsoeApi* eapi) {
ts3hr, ts3hr,
ts6hr ts6hr
); );
return mqtt->publish(topic + "/prices", json); return mqtt->publish(topic + "/prices", json, true, 0);
} }
bool HomeAssistantMqttHandler::publishSystem(HwTools* hw) { bool HomeAssistantMqttHandler::publishSystem(HwTools* hw, EntsoeApi* eapi, EnergyAccounting* ea) {
if(topic.isEmpty() || !mqtt->connected()){ if(topic.isEmpty() || !mqtt->connected()){
sequence = 0; sequence = 0;
return false; return false;
@@ -218,26 +241,42 @@ bool HomeAssistantMqttHandler::publishSystem(HwTools* hw) {
String haUrl = "http://" + haUID + ".local/"; String haUrl = "http://" + haUID + ".local/";
// Could this be necessary? haUID.replace("-", "_"); // Could this be necessary? haUID.replace("-", "_");
for(int i=0;i<sensors;i++){ uint8_t peaks = 0;
for(int i=0;i<HA_SENSOR_COUNT;i++) {
HomeAssistantSensor sensor = HA_SENSORS[i];
String uid = String(sensor.path);
uid.replace(".", "");
uid.replace("[", "");
uid.replace("]", "");
String uom = String(sensor.uom);
if(strncmp(sensor.devcl, "monetary", 8) == 0) {
if(eapi == NULL) continue;
uom = String(eapi->getCurrency());
}
if(strncmp(sensor.path, "peaks[", 6) == 0) {
if(peaks >= ea->getConfig()->hours) continue;
peaks++;
}
snprintf_P(json, BufferSize, HADISCOVER_JSON, snprintf_P(json, BufferSize, HADISCOVER_JSON,
FPSTR(HA_NAMES[i]), FPSTR(sensor.name),
topic.c_str(), FPSTR(HA_TOPICS[i]), topic.c_str(), FPSTR(sensor.topic),
haUID.c_str(), FPSTR(HA_PARAMS[i]), haUID.c_str(), uid.c_str(),
haUID.c_str(), FPSTR(HA_PARAMS[i]), haUID.c_str(), uid.c_str(),
FPSTR(HA_UOM[i]), uom.c_str(),
FPSTR(HA_PARAMS[i]), FPSTR(sensor.path),
FPSTR(HA_DEVCL[i]), FPSTR(sensor.devcl),
haUID.c_str(), haUID.c_str(),
haName.c_str(), haName.c_str(),
haModel.c_str(), haModel.c_str(),
VERSION, VERSION,
haManuf.c_str(), haManuf.c_str(),
haUrl.c_str(), haUrl.c_str(),
strlen_P(HA_STACL[i]) > 0 ? ", \"stat_cla\" :" : "", strlen_P(sensor.stacl) > 0 ? ", \"stat_cla\" :" : "",
strlen_P(HA_STACL[i]) > 0 ? (char *) FPSTR(HA_STACL[i]) : "" strlen_P(sensor.stacl) > 0 ? (char *) FPSTR(sensor.stacl) : ""
); );
mqtt->publish(haTopic + haUID + "_" + FPSTR(HA_PARAMS[i]) + "/config", json, true, 0); mqtt->publish(haTopic + haUID + "_" + uid.c_str() + "/config", json, true, 0);
} }
autodiscoverInit = true; autodiscoverInit = true;
} }
if(listType>0) sequence++; if(listType>0) sequence++;

View File

@@ -13,11 +13,9 @@ public:
bool publish(AmsData* data, AmsData* previousState, EnergyAccounting* ea); bool publish(AmsData* data, AmsData* previousState, EnergyAccounting* ea);
bool publishTemperatures(AmsConfiguration*, HwTools*); bool publishTemperatures(AmsConfiguration*, HwTools*);
bool publishPrices(EntsoeApi*); bool publishPrices(EntsoeApi*);
bool publishSystem(HwTools*); bool publishSystem(HwTools* hw, EntsoeApi* eapi, EnergyAccounting* ea);
private: private:
static const uint8_t sensors = 17;
String haTopic = "homeassistant/sensor/"; String haTopic = "homeassistant/sensor/";
String haName = "AMS reader"; String haName = "AMS reader";

View File

@@ -3,12 +3,69 @@
#include "Arduino.h" #include "Arduino.h"
const char* HA_TOPICS[17] PROGMEM = {"/state", "/state", "/state", "/power", "/power", "/power", "/power", "/power", "/power", "/power", "/power", "/power", "/power", "/energy", "/energy", "/energy", "/energy"}; struct HomeAssistantSensor {
const char* HA_NAMES[17] PROGMEM = {"Status", "Supply volt", "Temperature", "Active import", "Reactive import", "Active export", "Reactive export", "L1 current", "L2 current", "L3 current", char* name;
"L1 voltage", "L2 voltage", "L3 voltage", "Accumulated active import", "Accumulated active export", "Accumulated reactive import", "Accumulated reactive export"}; char* topic;
const char* HA_PARAMS[17] PROGMEM = {"rssi", "vcc", "temp", "P", "Q", "PO", "QO", "I1", "I2", "I3", "U1", "U2", "U3", "tPI", "tPO", "tQI", "tQO"}; char* path;
const char* HA_UOM[17] PROGMEM = {"dBm", "V", "C", "W", "W", "W", "W", "A", "A", "A", "V", "V", "V", "kWh", "kWh", "kWh", "kWh"}; char* uom;
const char* HA_DEVCL[17] PROGMEM = {"signal_strength", "voltage", "temperature", "power", "power", "power", "power", "current", "current", "current", "voltage", "voltage", "voltage", "energy", "energy", "energy", "energy"}; char* devcl;
const char* HA_STACL[17] PROGMEM = {"", "", "", "\"measurement\"", "\"measurement\"", "\"measurement\"", "\"measurement\"", "", "", "", "", "", "", "\"total_increasing\"", "\"total_increasing\"", "\"total_increasing\"", "\"total_increasing\""}; char* stacl;
};
const uint8_t HA_SENSOR_COUNT PROGMEM = 50;
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\""},
{"Reactive import", "/power", "Q", "VAr", "reactive_power", "\"measurement\""},
{"Active export", "/power", "PO", "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\""},
{"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\""},
{"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", ""},
{"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", ""},
};
#endif #endif

View File

@@ -271,7 +271,7 @@ bool JsonMqttHandler::publishPrices(EntsoeApi* eapi) {
return mqtt->publish(topic, json); return mqtt->publish(topic, json);
} }
bool JsonMqttHandler::publishSystem(HwTools* hw) { bool JsonMqttHandler::publishSystem(HwTools* hw, EntsoeApi* eapi, EnergyAccounting* ea) {
if(init || topic.isEmpty() || !mqtt->connected()) if(init || topic.isEmpty() || !mqtt->connected())
return false; return false;

View File

@@ -13,7 +13,7 @@ public:
bool publish(AmsData* data, AmsData* previousState, EnergyAccounting* ea); bool publish(AmsData* data, AmsData* previousState, EnergyAccounting* ea);
bool publishTemperatures(AmsConfiguration*, HwTools*); bool publishTemperatures(AmsConfiguration*, HwTools*);
bool publishPrices(EntsoeApi*); bool publishPrices(EntsoeApi*);
bool publishSystem(HwTools*); bool publishSystem(HwTools* hw, EntsoeApi* eapi, EnergyAccounting* ea);
private: private:
String clientId; String clientId;

View File

@@ -211,7 +211,7 @@ bool RawMqttHandler::publishPrices(EntsoeApi* eapi) {
return true; return true;
} }
bool RawMqttHandler::publishSystem(HwTools* hw) { bool RawMqttHandler::publishSystem(HwTools* hw, EntsoeApi* eapi, EnergyAccounting* ea) {
if(topic.isEmpty() || !mqtt->connected()) if(topic.isEmpty() || !mqtt->connected())
return false; return false;

View File

@@ -12,7 +12,7 @@ public:
bool publish(AmsData* data, AmsData* previousState, EnergyAccounting* ea); bool publish(AmsData* data, AmsData* previousState, EnergyAccounting* ea);
bool publishTemperatures(AmsConfiguration*, HwTools*); bool publishTemperatures(AmsConfiguration*, HwTools*);
bool publishPrices(EntsoeApi*); bool publishPrices(EntsoeApi*);
bool publishSystem(HwTools*); bool publishSystem(HwTools* hw, EntsoeApi* eapi, EnergyAccounting* ea);
private: private:
String topic; String topic;

20
web/realtime.json Normal file
View File

@@ -0,0 +1,20 @@
{
"max" : %.1f,
"peaks" : [ %s ],
"threshold" : %d,
"hour" : {
"use" : %.2f,
"cost" : %.2f,
"produced" : %.2f
},
"day" : {
"use" : %.2f,
"cost" : %.2f,
"produced" : %.2f
},
"month" : {
"use" : %.2f,
"cost" : %.2f,
"produced" : %.2f
}
}