mirror of
https://github.com/UtilitechAS/amsreader-firmware.git
synced 2026-02-15 20:37:19 +00:00
Added support for 15 minute price resolution (#1031)
* 15min prices WIP * WIP more changes for 15min prices * More work on 15min pricing * Fixed some errors * Some changes after testing * Graphical changes for 15min pricing * Adjustments on MQTT handlers after switching to 15min prices * Reverted some MQTT changes * Adapted HA integration for 15min pricing * Adapted JSON payload for 15min * Adjustments during testing * Set default price interval * Fixed refresh of price graph when data changes * Bugfixes * Fixed some issues with raw payload * Adjustments for meter timestamp from Kamstrup * Updated readme * Added detailed breakdown of payloads coming from Norwegian meters * Minor changes relating to price * Fixed byte alignment on price config * Changes to support RC upgraders
This commit is contained in:
@@ -127,6 +127,8 @@ void AmsWebServer::setup(AmsConfiguration* config, GpioConfig* gpioConfig, AmsDa
|
||||
server.on(context + F("/dayplot.json"), HTTP_GET, std::bind(&AmsWebServer::dayplotJson, this));
|
||||
server.on(context + F("/monthplot.json"), HTTP_GET, std::bind(&AmsWebServer::monthplotJson, this));
|
||||
server.on(context + F("/energyprice.json"), HTTP_GET, std::bind(&AmsWebServer::energyPriceJson, this));
|
||||
server.on(context + F("/importprice.json"), HTTP_GET, std::bind(&AmsWebServer::importPriceJson, this));
|
||||
server.on(context + F("/exportprice.json"), HTTP_GET, std::bind(&AmsWebServer::exportPriceJson, this));
|
||||
server.on(context + F("/temperature.json"), HTTP_GET, std::bind(&AmsWebServer::temperatureJson, this));
|
||||
server.on(context + F("/tariff.json"), HTTP_GET, std::bind(&AmsWebServer::tariffJson, this));
|
||||
server.on(context + F("/realtime.json"), HTTP_GET, std::bind(&AmsWebServer::realtimeJson, this));
|
||||
@@ -584,8 +586,8 @@ void AmsWebServer::dataJson() {
|
||||
mqttStatus = 3;
|
||||
}
|
||||
|
||||
float price = ea->getPriceForHour(PRICE_DIRECTION_IMPORT, 0);
|
||||
float exportPrice = ea->getPriceForHour(PRICE_DIRECTION_EXPORT, 0);
|
||||
float price = ps == NULL ? PRICE_NO_VALUE : ps->getCurrentPrice(PRICE_DIRECTION_IMPORT);
|
||||
float exportPrice = ps == NULL ? PRICE_NO_VALUE : ps->getCurrentPrice(PRICE_DIRECTION_EXPORT);
|
||||
|
||||
String peaks = "";
|
||||
for(uint8_t i = 1; i <= ea->getConfig()->hours; i++) {
|
||||
@@ -712,18 +714,24 @@ void AmsWebServer::monthplotJson() {
|
||||
}
|
||||
}
|
||||
|
||||
// Deprecated
|
||||
void AmsWebServer::energyPriceJson() {
|
||||
if(!checkSecurity(2))
|
||||
return;
|
||||
|
||||
if(ps == NULL || !ps->hasPrice()) {
|
||||
notFound();
|
||||
return;
|
||||
}
|
||||
|
||||
float prices[36];
|
||||
for(int i = 0; i < 36; i++) {
|
||||
prices[i] = ps == NULL ? PRICE_NO_VALUE : ps->getValueForHour(PRICE_DIRECTION_IMPORT, i);
|
||||
prices[i] = ps->getPriceForRelativeHour(PRICE_DIRECTION_IMPORT, i);
|
||||
}
|
||||
|
||||
uint16_t pos = snprintf_P(buf, BufferSize, PSTR("{\"currency\":\"%s\",\"source\":\"%s\""),
|
||||
ps == NULL ? "" : ps->getCurrency(),
|
||||
ps == NULL ? "" : ps->getSource()
|
||||
ps->getCurrency(),
|
||||
ps->getSource()
|
||||
);
|
||||
|
||||
for(uint8_t i = 0;i < 36; i++) {
|
||||
@@ -744,6 +752,58 @@ void AmsWebServer::energyPriceJson() {
|
||||
server.send(200, MIME_JSON, buf);
|
||||
}
|
||||
|
||||
void AmsWebServer::importPriceJson() {
|
||||
priceJson(PRICE_DIRECTION_IMPORT);
|
||||
}
|
||||
|
||||
void AmsWebServer::exportPriceJson() {
|
||||
priceJson(PRICE_DIRECTION_EXPORT);
|
||||
}
|
||||
|
||||
void AmsWebServer::priceJson(uint8_t direction) {
|
||||
if(!checkSecurity(2))
|
||||
return;
|
||||
|
||||
if(ps == NULL || !ps->hasPrice()) {
|
||||
notFound();
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t numberOfPoints = ps->getNumberOfPointsAvailable();
|
||||
|
||||
float prices[numberOfPoints];
|
||||
for(int i = 0; i < numberOfPoints; i++) {
|
||||
prices[i] = ps->getPricePoint(direction, i);
|
||||
}
|
||||
|
||||
snprintf_P(buf, BufferSize, PSTR("{\"currency\":\"%s\",\"source\":\"%s\",\"resolution\":%d,\"direction\":\"%s\",\"importExportPriceDifferent\":%s,\"prices\":["),
|
||||
ps->getCurrency(),
|
||||
ps->getSource(),
|
||||
ps->getResolutionInMinutes(),
|
||||
direction == PRICE_DIRECTION_IMPORT ? "import" : direction == PRICE_DIRECTION_EXPORT ? "export" : "both",
|
||||
ps->isExportPricesDifferentFromImport() ? "true" : "false"
|
||||
);
|
||||
|
||||
addConditionalCloudHeaders();
|
||||
server.sendHeader(HEADER_CACHE_CONTROL, CACHE_CONTROL_NO_CACHE);
|
||||
server.sendHeader(HEADER_PRAGMA, PRAGMA_NO_CACHE);
|
||||
server.sendHeader(HEADER_EXPIRES, EXPIRES_OFF);
|
||||
|
||||
server.setContentLength(CONTENT_LENGTH_UNKNOWN);
|
||||
server.send(200, MIME_JSON, buf);
|
||||
|
||||
for(uint8_t i = 0;i < numberOfPoints; i++) {
|
||||
if(prices[i] == PRICE_NO_VALUE) {
|
||||
snprintf_P(buf, BufferSize, PSTR("%snull"), i == 0 ? "" : ",");
|
||||
server.sendContent(buf);
|
||||
} else {
|
||||
snprintf_P(buf, BufferSize, PSTR("%s%.4f"), i == 0 ? "" : ",", prices[i]);
|
||||
server.sendContent(buf);
|
||||
}
|
||||
}
|
||||
server.sendContent_P(PSTR("]}"));
|
||||
}
|
||||
|
||||
void AmsWebServer::temperatureJson() {
|
||||
if(!checkSecurity(2))
|
||||
return;
|
||||
@@ -988,7 +1048,8 @@ void AmsWebServer::configurationJson() {
|
||||
price.enabled ? "true" : "false",
|
||||
price.entsoeToken,
|
||||
price.area,
|
||||
price.currency
|
||||
price.currency,
|
||||
price.resolutionInMinutes
|
||||
);
|
||||
server.sendContent(buf);
|
||||
snprintf_P(buf, BufferSize, CONF_DEBUG_JSON,
|
||||
@@ -1333,18 +1394,20 @@ void AmsWebServer::handleSave() {
|
||||
|
||||
if(server.hasArg(F("w")) && server.arg(F("w")) == F("true")) {
|
||||
long mode = server.arg(F("nc")).toInt();
|
||||
if(mode > 0 && mode < 3) {
|
||||
if(mode > 0) {
|
||||
NetworkConfig network;
|
||||
config->getNetworkConfig(network);
|
||||
network.mode = mode;
|
||||
strcpy(network.ssid, server.arg(F("ws")).c_str());
|
||||
String psk = server.arg(F("wp"));
|
||||
if(!psk.equals("***")) {
|
||||
strcpy(network.psk, psk.c_str());
|
||||
if(mode < 3) {
|
||||
strcpy(network.ssid, server.arg(F("ws")).c_str());
|
||||
String psk = server.arg(F("wp"));
|
||||
if(!psk.equals("***")) {
|
||||
strcpy(network.psk, psk.c_str());
|
||||
}
|
||||
network.power = server.arg(F("ww")).toFloat() * 10;
|
||||
network.sleep = server.arg(F("wz")).toInt();
|
||||
network.use11b = server.hasArg(F("wb")) && server.arg(F("wb")) == F("true");
|
||||
}
|
||||
network.power = server.arg(F("ww")).toFloat() * 10;
|
||||
network.sleep = server.arg(F("wz")).toInt();
|
||||
network.use11b = server.hasArg(F("wb")) && server.arg(F("wb")) == F("true");
|
||||
|
||||
if(server.hasArg(F("nm"))) {
|
||||
if(server.arg(F("nm")) == "static") {
|
||||
@@ -1564,6 +1627,7 @@ void AmsWebServer::handleSave() {
|
||||
strcpy(price.entsoeToken, server.arg(F("pt")).c_str());
|
||||
strcpy(price.area, priceRegion.c_str());
|
||||
strcpy(price.currency, server.arg(F("pc")).c_str());
|
||||
price.resolutionInMinutes = server.arg(F("pm")).toInt();
|
||||
config->setPriceServiceConfig(price);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user