mirror of
https://github.com/UtilitechAS/amsreader-firmware.git
synced 2026-03-04 18:55:00 +00:00
Adjustments on MQTT handlers after switching to 15min prices
This commit is contained in:
@@ -105,16 +105,16 @@ const HomeAssistantSensor RealtimeExportSensors[RealtimeExportSensorCount] PROGM
|
||||
const HomeAssistantSensor RealtimePeakSensor PROGMEM = {"Current month peak %d", "/realtime", "peaks[%d]", 4000, "kWh", "energy", ""};
|
||||
const HomeAssistantSensor RealtimeThresholdSensor PROGMEM = {"Tariff threshold %d", "/realtime", "thresholds[%d]", 4000, "kWh", "energy", ""};
|
||||
|
||||
const uint8_t PriceSensorCount PROGMEM = 5;
|
||||
const uint8_t PriceSensorCount PROGMEM = 6;
|
||||
const HomeAssistantSensor PriceSensors[PriceSensorCount] PROGMEM = {
|
||||
{"Minimum price ahead", "/prices", "prices.min", 4000, "", "monetary", ""},
|
||||
{"Maximum price ahead", "/prices", "prices.max", 4000, "", "monetary", ""},
|
||||
{"Cheapest 1hr period ahead", "/prices", "prices.cheapest1hr",4000, "", "timestamp", ""},
|
||||
{"Cheapest 3hr period ahead", "/prices", "prices.cheapest3hr",4000, "", "timestamp", ""},
|
||||
{"Cheapest 6hr period ahead", "/prices", "prices.cheapest6hr",4000, "", "timestamp", ""}
|
||||
{"Import price", "/prices", "prices.import.current", 4000, "", "monetary", ""},
|
||||
{"Minimum price ahead", "/prices", "prices.min", 4000, "", "monetary", ""},
|
||||
{"Maximum price ahead", "/prices", "prices.max", 4000, "", "monetary", ""},
|
||||
{"Cheapest 1hr period ahead", "/prices", "prices.cheapest1hr", 4000, "", "timestamp", ""},
|
||||
{"Cheapest 3hr period ahead", "/prices", "prices.cheapest3hr", 4000, "", "timestamp", ""},
|
||||
{"Cheapest 6hr period ahead", "/prices", "prices.cheapest6hr", 4000, "", "timestamp", ""}
|
||||
};
|
||||
|
||||
const HomeAssistantSensor PriceSensor PROGMEM = {"Current %s price", "/prices", "prices.%s[%d]", 4000, "", "monetary", "total"};
|
||||
const HomeAssistantSensor ExportPriceSensor PROGMEM = {"Export price", "/prices", "prices.export.current", 4000, "", "monetary", ""};
|
||||
|
||||
const uint8_t SystemSensorCount PROGMEM = 3;
|
||||
const HomeAssistantSensor SystemSensors[SystemSensorCount] PROGMEM = {
|
||||
|
||||
@@ -442,7 +442,10 @@ bool HomeAssistantMqttHandler::publishPrices(PriceService* ps) {
|
||||
sprintf_P(ts6hr, PSTR("%04d-%02d-%02dT%02d:00:00Z"), tm.Year+1970, tm.Month, tm.Day, tm.Hour);
|
||||
}
|
||||
|
||||
uint16_t pos = snprintf_P(json, BufferSize, PSTR("{\"id\":\"%s\",\"prices\":{\"import\":["), WiFi.macAddress().c_str());
|
||||
uint16_t pos = snprintf_P(json, BufferSize, PSTR("{\"id\":\"%s\",\"prices\":{\"import\":{\"current\":%.4f,\"all\":["),
|
||||
WiFi.macAddress().c_str(),
|
||||
ps->getCurrentPrice(PRICE_DIRECTION_IMPORT)
|
||||
);
|
||||
uint8_t numberOfPoints = ps->getNumberOfPointsAvailable();
|
||||
for(int i = 0; i < numberOfPoints; i++) {
|
||||
float val = ps->getPricePoint(PRICE_DIRECTION_IMPORT, i);
|
||||
@@ -453,7 +456,8 @@ bool HomeAssistantMqttHandler::publishPrices(PriceService* ps) {
|
||||
}
|
||||
}
|
||||
if(rteInit && ps->isExportPricesDifferentFromImport()) {
|
||||
pos += snprintf_P(json+pos-1, BufferSize-pos, PSTR("],\"export\":["));
|
||||
pos--;
|
||||
pos += snprintf_P(json+pos, BufferSize-pos, PSTR("]},\"export\":{\"current\":%.4f,\"all\":["), ps->getCurrentPrice(PRICE_DIRECTION_EXPORT));
|
||||
for(int i = 0; i < numberOfPoints; i++) {
|
||||
float val = ps->getPricePoint(PRICE_DIRECTION_EXPORT, i);
|
||||
if(val == PRICE_NO_VALUE) {
|
||||
@@ -464,7 +468,8 @@ bool HomeAssistantMqttHandler::publishPrices(PriceService* ps) {
|
||||
}
|
||||
}
|
||||
|
||||
pos += snprintf_P(json+pos-1, BufferSize-pos, PSTR("],\"min\":%.4f,\"max\":%.4f,\"cheapest1hr\":\"%s\",\"cheapest3hr\":\"%s\",\"cheapest6hr\":\"%s\"}"),
|
||||
pos--;
|
||||
pos += snprintf_P(json+pos, BufferSize-pos, PSTR("]},\"min\":%.4f,\"max\":%.4f,\"cheapest1hr\":\"%s\",\"cheapest3hr\":\"%s\",\"cheapest6hr\":\"%s\"}}"),
|
||||
min == INT16_MAX ? 0.0 : min,
|
||||
max == INT16_MIN ? 0.0 : max,
|
||||
ts1hr,
|
||||
@@ -697,35 +702,47 @@ void HomeAssistantMqttHandler::publishPriceSensors(PriceService* ps) {
|
||||
pInit = true;
|
||||
}
|
||||
if(!prInit && ps->hasPrice()) {
|
||||
char path[strlen(PriceSensor.path)+1];
|
||||
snprintf(path, strlen(PriceSensor.path)+1, PriceSensor.path, "import", 0);
|
||||
HomeAssistantSensor sensor = {
|
||||
"Current import price",
|
||||
PriceSensor.topic,
|
||||
PriceSensor.path,
|
||||
PriceSensor.ttl,
|
||||
uom.c_str(),
|
||||
PriceSensor.devcl,
|
||||
PriceSensor.stacl
|
||||
};
|
||||
publishSensor(sensor);
|
||||
for(uint8_t i = 0; i < ps->getNumberOfPointsAvailable(); i++) {
|
||||
char name[32];
|
||||
snprintf_P(name, 32, PSTR("Import price point %02d"), i);
|
||||
char path[32];
|
||||
snprintf_P(path, 32, PSTR("prices.import.all[%d]"), i);
|
||||
HomeAssistantSensor sensor = {
|
||||
name,
|
||||
"/prices",
|
||||
path,
|
||||
ps->getResolutionInMinutes() * 60 + 30,
|
||||
uom.c_str(),
|
||||
"monetary",
|
||||
""
|
||||
};
|
||||
publishSensor(sensor);
|
||||
}
|
||||
prInit = true;
|
||||
}
|
||||
|
||||
if(rteInit && !preInit && ps->isExportPricesDifferentFromImport()) {
|
||||
char path[strlen(PriceSensor.path)+1];
|
||||
snprintf(path, strlen(PriceSensor.path)+1, PriceSensor.path, "export", 0);
|
||||
HomeAssistantSensor sensor = {
|
||||
"Current export price",
|
||||
PriceSensor.topic,
|
||||
PriceSensor.path,
|
||||
PriceSensor.ttl,
|
||||
uom.c_str(),
|
||||
PriceSensor.devcl,
|
||||
PriceSensor.stacl
|
||||
};
|
||||
HomeAssistantSensor sensor = ExportPriceSensor;
|
||||
sensor.uom = uom.c_str();
|
||||
publishSensor(sensor);
|
||||
prInit = true;
|
||||
|
||||
for(uint8_t i = 0; i < ps->getNumberOfPointsAvailable(); i++) {
|
||||
char name[32];
|
||||
snprintf_P(name, 32, PSTR("Export price point %02d"), i);
|
||||
char path[32];
|
||||
snprintf_P(path, 32, PSTR("prices.export.all[%d]"), i);
|
||||
HomeAssistantSensor sensor = {
|
||||
name,
|
||||
"/prices",
|
||||
path,
|
||||
ps->getResolutionInMinutes() * 60 + 30,
|
||||
uom.c_str(),
|
||||
"monetary",
|
||||
""
|
||||
};
|
||||
publishSensor(sensor);
|
||||
}
|
||||
preInit = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -365,10 +365,10 @@ bool JsonMqttHandler::publishPrices(PriceService* ps) {
|
||||
|
||||
char pf[4];
|
||||
uint16_t pos = snprintf_P(json, BufferSize, PSTR("{\"id\":\"%s\","), WiFi.macAddress().c_str());
|
||||
uint8_t numberOfPoints = ps->getNumberOfPointsAvailable();
|
||||
if(mqttConfig.payloadFormat != 6) {
|
||||
memset(pf, 0, 4);
|
||||
pos += snprintf_P(json+pos, BufferSize-pos, PSTR("\"prices\":{\"import\":["));
|
||||
uint8_t numberOfPoints = ps->getNumberOfPointsAvailable();
|
||||
pos += snprintf_P(json+pos, BufferSize-pos, PSTR("\"prices\":{\"import\":{\"current\":%.4f,\"all\":["), ps->getCurrentPrice(PRICE_DIRECTION_IMPORT));
|
||||
for(int i = 0; i < numberOfPoints; i++) {
|
||||
float val = ps->getPricePoint(PRICE_DIRECTION_IMPORT, i);
|
||||
if(val == PRICE_NO_VALUE) {
|
||||
@@ -378,7 +378,8 @@ bool JsonMqttHandler::publishPrices(PriceService* ps) {
|
||||
}
|
||||
}
|
||||
if(hasExport && ps->isExportPricesDifferentFromImport()) {
|
||||
pos += snprintf_P(json+pos-1, BufferSize-pos, PSTR("],\"export\":["));
|
||||
pos--;
|
||||
pos += snprintf_P(json+pos, BufferSize-pos, PSTR("]},\"export\":{\"current\":%.4f,\"all\":["), ps->getCurrentPrice(PRICE_DIRECTION_EXPORT));
|
||||
for(int i = 0; i < numberOfPoints; i++) {
|
||||
float val = ps->getPricePoint(PRICE_DIRECTION_EXPORT, i);
|
||||
if(val == PRICE_NO_VALUE) {
|
||||
@@ -388,14 +389,38 @@ bool JsonMqttHandler::publishPrices(PriceService* ps) {
|
||||
}
|
||||
}
|
||||
}
|
||||
pos += snprintf_P(json+pos-1, BufferSize-pos, PSTR("],"));
|
||||
pos--;
|
||||
pos += snprintf_P(json+pos, BufferSize-pos, PSTR("]},"));
|
||||
} else {
|
||||
strcpy_P(pf, PSTR("pr_"));
|
||||
for(uint8_t i = 0;i < 38; i++) {
|
||||
if(values[i] == PRICE_NO_VALUE) {
|
||||
pos += snprintf_P(json+pos, BufferSize-pos, PSTR("\"%s%d\":null,"), pf, i);
|
||||
float val = ps->getCurrentPrice(PRICE_DIRECTION_IMPORT);
|
||||
if(val == PRICE_NO_VALUE) {
|
||||
pos += snprintf_P(json+pos, BufferSize-pos, PSTR("\"%sc\":null,"), pf);
|
||||
} else {
|
||||
pos += snprintf_P(json+pos, BufferSize-pos, PSTR("\"%sc\":%.4f,"), pf, val);
|
||||
}
|
||||
for(uint8_t i = 0;i < numberOfPoints; i++) {
|
||||
val = ps->getPricePoint(PRICE_DIRECTION_IMPORT, i);
|
||||
if(val == PRICE_NO_VALUE) {
|
||||
pos += snprintf_P(json+pos, BufferSize-pos, PSTR("\"%s%02d\":null,"), pf, i);
|
||||
} else {
|
||||
pos += snprintf_P(json+pos, BufferSize-pos, PSTR("\"%s%d\":%.4f,"), pf, i, values[i]);
|
||||
pos += snprintf_P(json+pos, BufferSize-pos, PSTR("\"%s%02d\":%.4f,"), pf, i, val);
|
||||
}
|
||||
}
|
||||
if(hasExport && ps->isExportPricesDifferentFromImport()) {
|
||||
float val = ps->getCurrentPrice(PRICE_DIRECTION_EXPORT);
|
||||
if(val == PRICE_NO_VALUE) {
|
||||
pos += snprintf_P(json+pos, BufferSize-pos, PSTR("\"%sec\":null,"), pf);
|
||||
} else {
|
||||
pos += snprintf_P(json+pos, BufferSize-pos, PSTR("\"%sec\":%.4f,"), pf, val);
|
||||
}
|
||||
for(uint8_t i = 0;i < numberOfPoints; i++) {
|
||||
val = ps->getPricePoint(PRICE_DIRECTION_EXPORT, i);
|
||||
if(val == PRICE_NO_VALUE) {
|
||||
pos += snprintf_P(json+pos, BufferSize-pos, PSTR("\"%se%02d\":null,"), pf, i);
|
||||
} else {
|
||||
pos += snprintf_P(json+pos, BufferSize-pos, PSTR("\"%se%02d\":%.4f,"), pf, i, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,7 +109,7 @@ private:
|
||||
PriceServiceConfig* config = NULL;
|
||||
HTTPClient* http = NULL;
|
||||
|
||||
uint8_t currentDay = 0, currentHour = 0;
|
||||
uint8_t currentDay = 0, currentPricePoint = 0;
|
||||
uint8_t tomorrowFetchMinute = 15; // How many minutes over 13:00 should it fetch prices
|
||||
uint8_t nextFetchDelayMinutes = 15;
|
||||
uint64_t lastTodayFetch = 0;
|
||||
@@ -140,5 +140,6 @@ private:
|
||||
bool timeIsInPeriod(tmElements_t tm, PriceConfig pc);
|
||||
float getFixedPrice(uint8_t direction, int8_t hour);
|
||||
float getEnergyPricePoint(uint8_t direction, uint8_t point);
|
||||
uint8_t getCurrentPricePointIndex();
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -168,7 +168,7 @@ float PriceService::getCurrentPrice(uint8_t direction) {
|
||||
time_t ts = time(nullptr);
|
||||
tmElements_t tm;
|
||||
breakTime(tz->toLocal(ts), tm);
|
||||
uint8_t pos = ((tm.Hour * 60) + tm.Minute) / today->getResolutionInMinutes();
|
||||
uint8_t pos = getCurrentPricePointIndex();
|
||||
|
||||
return getPricePoint(direction, pos);
|
||||
}
|
||||
@@ -307,7 +307,7 @@ bool PriceService::loop() {
|
||||
#endif
|
||||
debugger->printf_P(PSTR("(PriceService) Day init\n"));
|
||||
currentDay = tm.Day;
|
||||
currentHour = tm.Hour;
|
||||
currentPricePoint = getCurrentPricePointIndex();
|
||||
}
|
||||
|
||||
if(currentDay != tm.Day) {
|
||||
@@ -321,14 +321,14 @@ bool PriceService::loop() {
|
||||
tomorrow = NULL;
|
||||
}
|
||||
currentDay = tm.Day;
|
||||
currentHour = tm.Hour;
|
||||
currentPricePoint = getCurrentPricePointIndex();
|
||||
return today != NULL || (!config->enabled && priceConfig.capacity() != 0); // Only trigger MQTT publish if we have todays prices.
|
||||
} else if(currentHour != tm.Hour) {
|
||||
} else if(currentPricePoint != getCurrentPricePointIndex()) {
|
||||
#if defined(AMS_REMOTE_DEBUG)
|
||||
if (debugger->isActive(RemoteDebug::INFO))
|
||||
#endif
|
||||
debugger->printf_P(PSTR("(PriceService) Hour reset\n"));
|
||||
currentHour = tm.Hour;
|
||||
debugger->printf_P(PSTR("(PriceService) Price point reset\n"));
|
||||
currentPricePoint = getCurrentPricePointIndex();
|
||||
return today != NULL || (!config->enabled && priceConfig.capacity() != 0); // Only trigger MQTT publish if we have todays prices.
|
||||
}
|
||||
|
||||
@@ -348,6 +348,7 @@ bool PriceService::loop() {
|
||||
}
|
||||
today = NULL;
|
||||
}
|
||||
currentPricePoint = getCurrentPricePointIndex();
|
||||
return today != NULL && !readyToFetchForTomorrow; // Only trigger MQTT publish if we have todays prices and we are not immediately ready to fetch price for tomorrow.
|
||||
}
|
||||
|
||||
@@ -364,6 +365,7 @@ bool PriceService::loop() {
|
||||
}
|
||||
tomorrow = NULL;
|
||||
}
|
||||
currentPricePoint = getCurrentPricePointIndex();
|
||||
return tomorrow != NULL;
|
||||
}
|
||||
|
||||
@@ -582,7 +584,8 @@ PricesContainer* PriceService::fetchPrices(time_t t) {
|
||||
int32_t* points = (int32_t*) &header[1];
|
||||
|
||||
for(uint8_t i = 0; i < header->numberOfPoints; i++) {
|
||||
float value = ntohl(points[i]) / 10000.0;
|
||||
int32_t intval = ntohl(points[i]);
|
||||
float value = intval / 10000.0;
|
||||
#if defined(AMS_REMOTE_DEBUG)
|
||||
if (debugger->isActive(RemoteDebug::VERBOSE))
|
||||
#endif
|
||||
@@ -591,7 +594,8 @@ PricesContainer* PriceService::fetchPrices(time_t t) {
|
||||
}
|
||||
if(header->differentExportPrices) {
|
||||
for(uint8_t i = 0; i < header->numberOfPoints; i++) {
|
||||
float value = ntohl(points[i]) / 10000.0;
|
||||
int32_t intval = ntohl(points[i]);
|
||||
float value = intval / 10000.0;
|
||||
#if defined(AMS_REMOTE_DEBUG)
|
||||
if (debugger->isActive(RemoteDebug::VERBOSE))
|
||||
#endif
|
||||
@@ -761,4 +765,13 @@ bool PriceService::timeIsInPeriod(tmElements_t tm, PriceConfig pc) {
|
||||
}
|
||||
|
||||
return makeTime(tms) <= makeTime(tm) && makeTime(tme) >= makeTime(tm);
|
||||
}
|
||||
|
||||
uint8_t PriceService::getCurrentPricePointIndex() {
|
||||
if(today == NULL) return 0;
|
||||
|
||||
time_t ts = time(nullptr);
|
||||
tmElements_t tm;
|
||||
breakTime(tz->toLocal(ts), tm);
|
||||
return ((tm.Hour * 60) + tm.Minute) / today->getResolutionInMinutes();
|
||||
}
|
||||
@@ -317,24 +317,31 @@ bool RawMqttHandler::publishPrices(PriceService* ps) {
|
||||
sprintf(ts6hr, "%04d-%02d-%02dT%02d:00:00Z", tm.Year+1970, tm.Month, tm.Day, tm.Hour);
|
||||
}
|
||||
|
||||
uint8_t numberOfPoints = ps->getNumberOfPointsAvailable();
|
||||
mqtt.publish(topic + "/price/import/current", String(ps->getCurrentPrice(PRICE_DIRECTION_IMPORT), 4), true, 0);
|
||||
mqtt.loop();
|
||||
if(hasExport && ps->isExportPricesDifferentFromImport()) {
|
||||
mqtt.publish(topic + "/price/export/current", String(ps->getCurrentPrice(PRICE_DIRECTION_EXPORT), 4), true, 0);
|
||||
mqtt.loop();
|
||||
}
|
||||
|
||||
uint8_t numberOfPoints = ps->getNumberOfPointsAvailable();
|
||||
for(int i = 0; i < numberOfPoints; i++) {
|
||||
float importVal = ps->getPricePoint(PRICE_DIRECTION_IMPORT, i);
|
||||
if(importVal == PRICE_NO_VALUE) {
|
||||
mqtt.publish(topic + "/price/import/" + String(i), "", true, 0);
|
||||
mqtt.publish(topic + "/price/import/all/" + String(i), "", true, 0);
|
||||
mqtt.loop();
|
||||
} else {
|
||||
mqtt.publish(topic + "/price/import/" + String(i), String(importVal, 4), true, 0);
|
||||
mqtt.publish(topic + "/price/import/all/" + String(i), String(importVal, 4), true, 0);
|
||||
mqtt.loop();
|
||||
}
|
||||
|
||||
if(hasExport && ps->isExportPricesDifferentFromImport()) {
|
||||
float exportVal = ps->getPricePoint(PRICE_DIRECTION_EXPORT, i);
|
||||
if(exportVal == PRICE_NO_VALUE) {
|
||||
mqtt.publish(topic + "/price/export/" + String(i), "", true, 0);
|
||||
mqtt.publish(topic + "/price/export/all/" + String(i), "", true, 0);
|
||||
mqtt.loop();
|
||||
} else {
|
||||
mqtt.publish(topic + "/price/export/" + String(i), String(exportVal, 4), true, 0);
|
||||
mqtt.publish(topic + "/price/export/all/" + String(i), String(exportVal, 4), true, 0);
|
||||
mqtt.loop();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user