Fetch prices from hub

This commit is contained in:
Gunnar Skjold 2022-08-12 20:41:53 +02:00
parent 508c14a671
commit 1a92cd1978
11 changed files with 255 additions and 128 deletions

View File

@ -10,7 +10,7 @@ platform = espressif8266@3.2.0
framework = arduino
board = esp12e
board_build.ldscript = eagle.flash.4m2m.ld
build_flags = -D WEBSOCKET_DISABLED=1
build_flags = -D WEBSOCKET_DISABLED=1 -fexceptions
lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
extra_scripts =

View File

@ -67,7 +67,7 @@ bool AmsDataStorage::update(AmsData* data) {
}
tmElements_t last;
breakTime(day.lastMeterReadTime, last);
for(int i = last.Hour; i < utc.Hour; i++) {
for(int i = last.Hour; i <= utc.Hour; i++) {
if(debugger->isActive(RemoteDebug::VERBOSE)) {
debugger->printf("(AmsDataStorage) Clearing hour: %d\n", i);
}
@ -90,7 +90,7 @@ bool AmsDataStorage::update(AmsData* data) {
}
tmElements_t last;
breakTime(tz->toLocal(month.lastMeterReadTime), last);
for(int i = last.Day; i < ltz.Day; i++) {
for(int i = last.Day; i <= ltz.Day; i++) {
if(debugger->isActive(RemoteDebug::VERBOSE)) {
debugger->printf("(AmsDataStorage) Clearing day: %d\n", i);
}

View File

@ -195,14 +195,11 @@ void setup() {
hw.ledBlink(LED_GREEN, 1);
hw.ledBlink(LED_BLUE, 1);
#if defined(ESP32)
EntsoeConfig entsoe;
if(config.getEntsoeConfig(entsoe) && strlen(entsoe.token) > 0) {
eapi = new EntsoeApi(&Debug);
eapi->setup(entsoe);
ws.setEntsoeApi(eapi);
}
#endif
eapi = new EntsoeApi(&Debug);
config.getEntsoeConfig(entsoe);
eapi->setup(entsoe);
ws.setEntsoeApi(eapi);
bool shared = false;
config.getMeterConfig(meterConfig);
@ -514,7 +511,6 @@ void loop() {
mqtt->disconnect();
}
#if defined(ESP32)
try {
if(eapi != NULL && ntpEnabled) {
if(eapi->loop() && mqtt != NULL && mqttHandler != NULL && mqtt->connected()) {
@ -524,24 +520,19 @@ void loop() {
if(config.isEntsoeChanged()) {
EntsoeConfig entsoe;
if(config.getEntsoeConfig(entsoe) && strlen(entsoe.token) > 0) {
if(config.getEntsoeConfig(entsoe)) {
if(eapi == NULL) {
eapi = new EntsoeApi(&Debug);
ea.setEapi(eapi);
ws.setEntsoeApi(eapi);
}
eapi->setup(entsoe);
} else if(eapi != NULL) {
delete eapi;
eapi = NULL;
ws.setEntsoeApi(NULL);
}
config.ackEntsoeChange();
}
} catch(const std::exception& e) {
debugE("Exception in ENTSO-E loop (%s)", e.what());
}
#endif
ws.loop();
}
if(mqtt != NULL) {

View File

@ -102,3 +102,35 @@ size_t EntsoeA44Parser::write(uint8_t byte) {
}
return 1;
}
void EntsoeA44Parser::get(PricesContainer* container) {
strcpy(container->currency, currency);
strcpy(container->measurementUnit, measurementUnit);
container->points[0] = points[0] == ENTSOE_NO_VALUE ? ENTSOE_NO_VALUE : points[0] * 10000;
container->points[1] = points[1] == ENTSOE_NO_VALUE ? ENTSOE_NO_VALUE : points[1] * 10000;
container->points[2] = points[2] == ENTSOE_NO_VALUE ? ENTSOE_NO_VALUE : points[2] * 10000;
container->points[3] = points[3] == ENTSOE_NO_VALUE ? ENTSOE_NO_VALUE : points[3] * 10000;
container->points[4] = points[4] == ENTSOE_NO_VALUE ? ENTSOE_NO_VALUE : points[4] * 10000;
container->points[5] = points[5] == ENTSOE_NO_VALUE ? ENTSOE_NO_VALUE : points[5] * 10000;
container->points[6] = points[6] == ENTSOE_NO_VALUE ? ENTSOE_NO_VALUE : points[6] * 10000;
container->points[7] = points[7] == ENTSOE_NO_VALUE ? ENTSOE_NO_VALUE : points[7] * 10000;
container->points[8] = points[8] == ENTSOE_NO_VALUE ? ENTSOE_NO_VALUE : points[8] * 10000;
container->points[9] = points[9] == ENTSOE_NO_VALUE ? ENTSOE_NO_VALUE : points[9] * 10000;
container->points[10] = points[10] == ENTSOE_NO_VALUE ? ENTSOE_NO_VALUE : points[10] * 10000;
container->points[11] = points[11] == ENTSOE_NO_VALUE ? ENTSOE_NO_VALUE : points[11] * 10000;
container->points[12] = points[12] == ENTSOE_NO_VALUE ? ENTSOE_NO_VALUE : points[12] * 10000;
container->points[13] = points[13] == ENTSOE_NO_VALUE ? ENTSOE_NO_VALUE : points[13] * 10000;
container->points[14] = points[14] == ENTSOE_NO_VALUE ? ENTSOE_NO_VALUE : points[14] * 10000;
container->points[15] = points[15] == ENTSOE_NO_VALUE ? ENTSOE_NO_VALUE : points[15] * 10000;
container->points[16] = points[16] == ENTSOE_NO_VALUE ? ENTSOE_NO_VALUE : points[16] * 10000;
container->points[17] = points[17] == ENTSOE_NO_VALUE ? ENTSOE_NO_VALUE : points[17] * 10000;
container->points[18] = points[18] == ENTSOE_NO_VALUE ? ENTSOE_NO_VALUE : points[18] * 10000;
container->points[19] = points[19] == ENTSOE_NO_VALUE ? ENTSOE_NO_VALUE : points[19] * 10000;
container->points[20] = points[20] == ENTSOE_NO_VALUE ? ENTSOE_NO_VALUE : points[20] * 10000;
container->points[21] = points[21] == ENTSOE_NO_VALUE ? ENTSOE_NO_VALUE : points[21] * 10000;
container->points[22] = points[22] == ENTSOE_NO_VALUE ? ENTSOE_NO_VALUE : points[22] * 10000;
container->points[23] = points[23] == ENTSOE_NO_VALUE ? ENTSOE_NO_VALUE : points[23] * 10000;
}

View File

@ -2,6 +2,7 @@
#define _ENTSOEA44PARSER_H
#include "Stream.h"
#include "PricesContainer.h"
#define DOCPOS_SEEK 0
#define DOCPOS_CURRENCY 1
@ -25,6 +26,7 @@ public:
void flush();
size_t write(const uint8_t *buffer, size_t size);
size_t write(uint8_t);
void get(PricesContainer*);
private:
char currency[4];

View File

@ -5,6 +5,8 @@
#include "DnbCurrParser.h"
#include "version.h"
#include "ams/GcmParser.h"
#if defined(ESP32)
#include <esp_task_wdt.h>
#endif
@ -31,6 +33,12 @@ void EntsoeApi::setup(EntsoeConfig& config) {
if(today != NULL) delete today;
if(tomorrow != NULL) delete tomorrow;
today = tomorrow = NULL;
http.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS);
http.setReuse(false);
http.setTimeout(60000);
http.setUserAgent("ams2mqtt/" + String(VERSION));
http.useHTTP10(true);
}
char* EntsoeApi::getToken() {
@ -60,25 +68,33 @@ float EntsoeApi::getValueForHour(time_t cur, int8_t hour) {
if(pos > 23) {
if(tomorrow == NULL)
return ENTSOE_NO_VALUE;
value = tomorrow->getPoint(pos-24);
if(value != ENTSOE_NO_VALUE && strcmp(tomorrow->getMeasurementUnit(), "MWH") == 0) {
if(tomorrow->points[pos-24] == ENTSOE_NO_VALUE)
return ENTSOE_NO_VALUE;
value = tomorrow->points[pos-24] / 10000.0;
if(strcmp(tomorrow->measurementUnit, "KWH") == 0) {
// Multiplier is 1
} else if(strcmp(tomorrow->measurementUnit, "MWH") == 0) {
multiplier *= 0.001;
} else {
return ENTSOE_NO_VALUE;
}
float mult = getCurrencyMultiplier(tomorrow->getCurrency(), config->currency);
float mult = getCurrencyMultiplier(tomorrow->currency, config->currency);
if(mult == 0) return ENTSOE_NO_VALUE;
multiplier *= mult;
} else if(pos >= 0) {
if(today == NULL)
return ENTSOE_NO_VALUE;
value = today->getPoint(pos);
if(value != ENTSOE_NO_VALUE && strcmp(today->getMeasurementUnit(), "MWH") == 0) {
if(today->points[pos] == ENTSOE_NO_VALUE)
return ENTSOE_NO_VALUE;
value = today->points[pos] / 10000.0;
if(strcmp(today->measurementUnit, "KWH") == 0) {
// Multiplier is 1
} else if(strcmp(today->measurementUnit, "MWH") == 0) {
multiplier *= 0.001;
} else {
return ENTSOE_NO_VALUE;
}
float mult = getCurrencyMultiplier(today->getCurrency(), config->currency);
float mult = getCurrencyMultiplier(today->currency, config->currency);
if(mult == 0) return ENTSOE_NO_VALUE;
multiplier *= mult;
}
@ -86,15 +102,22 @@ float EntsoeApi::getValueForHour(time_t cur, int8_t hour) {
}
bool EntsoeApi::loop() {
if(strlen(getToken()) == 0)
return false;
uint64_t now = millis64();
if(now < 10000) return false; // Grace period
time_t t = time(nullptr);
if(t < BUILD_EPOCH) return false;
#ifndef AMS2MQTT_PRICE_KEY
if(strlen(getToken()) == 0) {
return false;
}
#endif
if(strlen(config->area) == 0)
return false;
if(strlen(config->currency) == 0)
return false;
bool ret = false;
tmElements_t tm;
breakTime(tz->toLocal(t), tm);
@ -120,39 +143,10 @@ bool EntsoeApi::loop() {
midnightMillis = 0; // Force new midnight millis calculation
return true;
} else {
breakTime(t, tm); // Break UTC to find UTC midnight
if(today == NULL && (lastTodayFetch == 0 || now - lastTodayFetch > 60000)) {
lastTodayFetch = now;
time_t e1 = t - (tm.Hour * 3600) - (tm.Minute * 60) - tm.Second; // UTC midnight
time_t e2 = e1 + SECS_PER_DAY;
tmElements_t d1, d2;
breakTime(tz->toUTC(e1), d1); // To get day and hour for CET/CEST at UTC midnight
breakTime(tz->toUTC(e2), d2);
snprintf(buf, BufferSize, "%s?securityToken=%s&documentType=A44&periodStart=%04d%02d%02d%02d%02d&periodEnd=%04d%02d%02d%02d%02d&in_Domain=%s&out_Domain=%s",
"https://transparency.entsoe.eu/api", getToken(),
d1.Year+1970, d1.Month, d1.Day, d1.Hour, 00,
d2.Year+1970, d2.Month, d2.Day, d2.Hour, 00,
config->area, config->area);
#if defined(ESP32)
esp_task_wdt_reset();
#elif defined(ESP8266)
ESP.wdtFeed();
#endif
if(debugger->isActive(RemoteDebug::INFO)) debugger->printf("(EntsoeApi) Fetching prices for today\n");
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf("(EntsoeApi) url: %s\n", buf);
EntsoeA44Parser* a44 = new EntsoeA44Parser();
if(retrieve(buf, a44) && a44->getPoint(0) != ENTSOE_NO_VALUE) {
today = a44;
return true;
} else if(a44 != NULL) {
delete a44;
today = NULL;
return false;
}
today = fetchPrices(t);
return today != NULL;
}
// Prices for next day are published at 13:00 CE(S)T, but to avoid heavy server traffic at that time, we will
@ -161,49 +155,18 @@ bool EntsoeApi::loop() {
&& midnightMillis - now < tomorrowFetchMillis
&& (lastTomorrowFetch == 0 || now - lastTomorrowFetch > 900000)
) {
breakTime(t+SECS_PER_DAY, tm); // Break UTC tomorrow to find UTC midnight
lastTomorrowFetch = now;
time_t e1 = t - (tm.Hour * 3600) - (tm.Minute * 60) - tm.Second + (SECS_PER_DAY);
time_t e2 = e1 + SECS_PER_DAY;
tmElements_t d1, d2;
breakTime(tz->toUTC(e1), d1);
breakTime(tz->toUTC(e2), d2);
snprintf(buf, BufferSize, "%s?securityToken=%s&documentType=A44&periodStart=%04d%02d%02d%02d%02d&periodEnd=%04d%02d%02d%02d%02d&in_Domain=%s&out_Domain=%s",
"https://transparency.entsoe.eu/api", getToken(),
d1.Year+1970, d1.Month, d1.Day, d1.Hour, 00,
d2.Year+1970, d2.Month, d2.Day, d2.Hour, 00,
config->area, config->area);
#if defined(ESP32)
esp_task_wdt_reset();
#elif defined(ESP8266)
ESP.wdtFeed();
#endif
if(debugger->isActive(RemoteDebug::INFO)) debugger->printf("(EntsoeApi) Fetching prices for tomorrow\n");
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf("(EntsoeApi) url: %s\n", buf);
EntsoeA44Parser* a44 = new EntsoeA44Parser();
if(retrieve(buf, a44) && a44->getPoint(0) != ENTSOE_NO_VALUE) {
tomorrow = a44;
return true;
} else if(a44 != NULL) {
delete a44;
tomorrow = NULL;
return false;
}
tomorrow = fetchPrices(t+SECS_PER_DAY);
return tomorrow != NULL;
}
}
return ret;
}
bool EntsoeApi::retrieve(const char* url, Stream* doc) {
HTTPClient https;
https.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS);
https.setReuse(false);
https.setTimeout(50000);
https.setUserAgent("ams2mqtt/" + String(VERSION));
#if defined(ESP32)
if(https.begin(url)) {
if(http.begin(url)) {
printD("Connection established");
#if defined(ESP32)
@ -212,7 +175,7 @@ bool EntsoeApi::retrieve(const char* url, Stream* doc) {
ESP.wdtFeed();
#endif
int status = https.GET();
int status = http.GET();
#if defined(ESP32)
esp_task_wdt_reset();
@ -222,15 +185,15 @@ bool EntsoeApi::retrieve(const char* url, Stream* doc) {
if(status == HTTP_CODE_OK) {
printD("Receiving data");
https.writeToStream(doc);
https.end();
http.writeToStream(doc);
http.end();
return true;
} else {
if(debugger->isActive(RemoteDebug::ERROR)) debugger->printf("(EntsoeApi) Communication error, returned status: %d\n", status);
printE(https.errorToString(status));
printD(https.getString());
printE(http.errorToString(status));
printD(http.getString());
https.end();
http.end();
return false;
}
} else {
@ -282,6 +245,115 @@ float EntsoeApi::getCurrencyMultiplier(const char* from, const char* to) {
return currencyMultiplier;
}
PricesContainer* EntsoeApi::fetchPrices(time_t t) {
tmElements_t tm;
breakTime(t, tm);
if(strlen(getToken()) == 0) {
String data;
snprintf(buf, BufferSize, "%s/%s/%d/%d/%d?currency=%s",
"http://ams2mqtt.rewiredinvent.no/hub/price",
config->area,
tm.Year+1970,
tm.Month,
tm.Day,
config->currency
);
#if defined(ESP8266)
WiFiClient client;
client.setTimeout(5000);
if(http.begin(client, buf)) {
#elif defined(ESP32)
if(http.begin(buf)) {
#endif
int status = http.GET();
#if defined(ESP32)
esp_task_wdt_reset();
#elif defined(ESP8266)
ESP.wdtFeed();
#endif
if(status == HTTP_CODE_OK) {
printD("Receiving data");
data = http.getString();
http.end();
} else {
if(debugger->isActive(RemoteDebug::ERROR)) debugger->printf("(EntsoeApi) Communication error, returned status: %d\n", status);
printE(http.errorToString(status));
printD(http.getString());
http.end();
}
}
uint8_t* content = (uint8_t*) (data.c_str());
if(debugger->isActive(RemoteDebug::DEBUG)) {
printD("Received content for prices:");
debugPrint(content, 0, data.length());
}
#if defined(AMS2MQTT_PRICE_KEY)
uint8_t key[] = AMS2MQTT_PRICE_KEY;
#else
uint8_t key[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
#endif
#if defined(AMS2MQTT_PRICE_AUTHENTICATION)
uint8_t auth[] = AMS2MQTT_PRICE_AUTHENTICATION;
#else
uint8_t auth[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
#endif
DataParserContext ctx;
ctx.length = data.length();
GCMParser gcm(key, auth);
int8_t gcmRet = gcm.parse(content, ctx);
if(debugger->isActive(RemoteDebug::DEBUG)) {
printD("Decrypted content for prices:");
debugPrint(content, 0, data.length());
}
if(gcmRet > 0) {
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf("(EntsoeApi) Price data starting at: %d\n", gcmRet);
PricesContainer* ret = new PricesContainer();
memcpy(ret, content+gcmRet, sizeof(*ret));
for(uint8_t i = 0; i < 24; i++) {
ret->points[i] = ntohl(ret->points[i]);
}
return ret;
} else {
if(debugger->isActive(RemoteDebug::ERROR)) debugger->printf("(EntsoeApi) Error code while decrypting prices: %d\n", gcmRet);
}
} else {
time_t e1 = t - (tm.Hour * 3600) - (tm.Minute * 60) - tm.Second; // UTC midnight
time_t e2 = e1 + SECS_PER_DAY;
tmElements_t d1, d2;
breakTime(tz->toUTC(e1), d1); // To get day and hour for CET/CEST at UTC midnight
breakTime(tz->toUTC(e2), d2);
snprintf(buf, BufferSize, "%s?securityToken=%s&documentType=A44&periodStart=%04d%02d%02d%02d%02d&periodEnd=%04d%02d%02d%02d%02d&in_Domain=%s&out_Domain=%s",
"https://transparency.entsoe.eu/api", getToken(),
d1.Year+1970, d1.Month, d1.Day, d1.Hour, 00,
d2.Year+1970, d2.Month, d2.Day, d2.Hour, 00,
config->area, config->area);
#if defined(ESP32)
esp_task_wdt_reset();
#elif defined(ESP8266)
ESP.wdtFeed();
#endif
if(debugger->isActive(RemoteDebug::INFO)) debugger->printf("(EntsoeApi) Fetching prices for %d.%d.%d\n", tm.Day, tm.Month, tm.Year+1970);
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf("(EntsoeApi) url: %s\n", buf);
EntsoeA44Parser a44;
if(retrieve(buf, &a44) && a44.getPoint(0) != ENTSOE_NO_VALUE) {
PricesContainer* ret = new PricesContainer();
a44.get(ret);
return ret;
} else {
return NULL;
}
}
return NULL;
}
void EntsoeApi::printD(String fmt, ...) {
va_list args;
va_start(args, fmt);
@ -295,3 +367,19 @@ void EntsoeApi::printE(String fmt, ...) {
if(debugger->isActive(RemoteDebug::ERROR)) debugger->printf(String("(EntsoeApi)" + fmt + "\n").c_str(), args);
va_end(args);
}
void EntsoeApi::debugPrint(byte *buffer, int start, int length) {
for (int i = start; i < start + length; i++) {
if (buffer[i] < 0x10)
debugger->print("0");
debugger->print(buffer[i], HEX);
debugger->print(" ");
if ((i - start + 1) % 16 == 0)
debugger->println("");
else if ((i - start + 1) % 4 == 0)
debugger->print(" ");
yield(); // Let other get some resources too
}
debugger->println("");
}

View File

@ -4,8 +4,9 @@
#include "TimeLib.h"
#include "Timezone.h"
#include "RemoteDebug.h"
#include "EntsoeA44Parser.h"
#include "AmsConfiguration.h"
#include "PricesFromHubStream.h"
#include "EntsoeA44Parser.h"
#if defined(ESP8266)
#include <ESP8266HTTPClient.h>
@ -31,6 +32,7 @@ public:
private:
RemoteDebug* debugger;
EntsoeConfig* config = NULL;
HTTPClient http;
uint8_t currentDay = 0, currentHour = 0;
uint32_t tomorrowFetchMillis = 36000000; // Number of ms before midnight. Default fetch 10hrs before midnight (14:00 CE(S)T)
@ -38,8 +40,8 @@ private:
uint64_t lastTodayFetch = 0;
uint64_t lastTomorrowFetch = 0;
uint64_t lastCurrencyFetch = 0;
EntsoeA44Parser* today = NULL;
EntsoeA44Parser* tomorrow = NULL;
PricesContainer* today = NULL;
PricesContainer* tomorrow = NULL;
Timezone* tz = NULL;
@ -48,10 +50,12 @@ private:
float currencyMultiplier = 0;
PricesContainer* fetchPrices(time_t);
bool retrieve(const char* url, Stream* doc);
float getCurrencyMultiplier(const char* from, const char* to);
void printD(String fmt, ...);
void printE(String fmt, ...);
void debugPrint(byte *buffer, int start, int length);
};
#endif

View File

@ -0,0 +1,8 @@
#ifndef _PRICESCONTAINER_H
#define _PRICESCONTAINER_H
struct PricesContainer {
char currency[4];
char measurementUnit[4];
int32_t points[24];
};
#endif

View File

@ -27,3 +27,7 @@ size_t PricesFromHubStream::write(uint8_t b) {
buf[pos++] = b;
return 1;
}
void PricesFromHubStream::get(PricesContainer* container) {
memcpy(container, buf, pos);
}

View File

@ -2,6 +2,7 @@
#define _PRICESFROMHUBSTREAM_H
#include "Stream.h"
#include "PricesContainer.h"
class PricesFromHubStream: public Stream {
public:
@ -9,6 +10,7 @@ public:
int read();
int peek();
void flush();
void get(PricesContainer*);
size_t write(const uint8_t *buffer, size_t size);
size_t write(uint8_t);

View File

@ -547,38 +547,34 @@ void AmsWebServer::configEntsoeHtml() {
EntsoeConfig entsoe;
config->getEntsoeConfig(entsoe);
if(ESP.getFreeHeap() > 25000) {
String html = String((const __FlashStringHelper*) ENTSOE_HTML);
String html = String((const __FlashStringHelper*) ENTSOE_HTML);
html.replace("{et}", entsoe.token);
html.replace("{em}", String(entsoe.multiplier / 1000.0, 3));
html.replace("{et}", entsoe.token);
html.replace("{em}", String(entsoe.multiplier / 1000.0, 3));
html.replace("{eaNo1}", strcmp(entsoe.area, "10YNO-1--------2") == 0 ? "selected" : "");
html.replace("{eaNo2}", strcmp(entsoe.area, "10YNO-2--------T") == 0 ? "selected" : "");
html.replace("{eaNo3}", strcmp(entsoe.area, "10YNO-3--------J") == 0 ? "selected" : "");
html.replace("{eaNo4}", strcmp(entsoe.area, "10YNO-4--------9") == 0 ? "selected" : "");
html.replace("{eaNo5}", strcmp(entsoe.area, "10Y1001A1001A48H") == 0 ? "selected" : "");
html.replace("{eaNo1}", strcmp(entsoe.area, "10YNO-1--------2") == 0 ? "selected" : "");
html.replace("{eaNo2}", strcmp(entsoe.area, "10YNO-2--------T") == 0 ? "selected" : "");
html.replace("{eaNo3}", strcmp(entsoe.area, "10YNO-3--------J") == 0 ? "selected" : "");
html.replace("{eaNo4}", strcmp(entsoe.area, "10YNO-4--------9") == 0 ? "selected" : "");
html.replace("{eaNo5}", strcmp(entsoe.area, "10Y1001A1001A48H") == 0 ? "selected" : "");
html.replace("{eaSe1}", strcmp(entsoe.area, "10Y1001A1001A44P") == 0 ? "selected" : "");
html.replace("{eaSe2}", strcmp(entsoe.area, "10Y1001A1001A45N") == 0 ? "selected" : "");
html.replace("{eaSe3}", strcmp(entsoe.area, "10Y1001A1001A46L") == 0 ? "selected" : "");
html.replace("{eaSe4}", strcmp(entsoe.area, "10Y1001A1001A47J") == 0 ? "selected" : "");
html.replace("{eaSe1}", strcmp(entsoe.area, "10Y1001A1001A44P") == 0 ? "selected" : "");
html.replace("{eaSe2}", strcmp(entsoe.area, "10Y1001A1001A45N") == 0 ? "selected" : "");
html.replace("{eaSe3}", strcmp(entsoe.area, "10Y1001A1001A46L") == 0 ? "selected" : "");
html.replace("{eaSe4}", strcmp(entsoe.area, "10Y1001A1001A47J") == 0 ? "selected" : "");
html.replace("{eaDk1}", strcmp(entsoe.area, "10YDK-1--------W") == 0 ? "selected" : "");
html.replace("{eaDk2}", strcmp(entsoe.area, "10YDK-2--------M") == 0 ? "selected" : "");
html.replace("{eaDk1}", strcmp(entsoe.area, "10YDK-1--------W") == 0 ? "selected" : "");
html.replace("{eaDk2}", strcmp(entsoe.area, "10YDK-2--------M") == 0 ? "selected" : "");
html.replace("{ecNOK}", strcmp(entsoe.currency, "NOK") == 0 ? "selected" : "");
html.replace("{ecSEK}", strcmp(entsoe.currency, "SEK") == 0 ? "selected" : "");
html.replace("{ecDKK}", strcmp(entsoe.currency, "DKK") == 0 ? "selected" : "");
html.replace("{ecEUR}", strcmp(entsoe.currency, "EUR") == 0 ? "selected" : "");
html.replace("{ecNOK}", strcmp(entsoe.currency, "NOK") == 0 ? "selected" : "");
html.replace("{ecSEK}", strcmp(entsoe.currency, "SEK") == 0 ? "selected" : "");
html.replace("{ecDKK}", strcmp(entsoe.currency, "DKK") == 0 ? "selected" : "");
html.replace("{ecEUR}", strcmp(entsoe.currency, "EUR") == 0 ? "selected" : "");
server.setContentLength(html.length() + HEAD_HTML_LEN + FOOT_HTML_LEN);
server.send_P(200, MIME_HTML, HEAD_HTML);
server.sendContent(html);
server.sendContent_P(FOOT_HTML);
} else {
notFound();
}
server.setContentLength(html.length() + HEAD_HTML_LEN + FOOT_HTML_LEN);
server.send_P(200, MIME_HTML, HEAD_HTML);
server.sendContent(html);
server.sendContent_P(FOOT_HTML);
}
void AmsWebServer::configThresholdsHtml() {
@ -705,7 +701,7 @@ void AmsWebServer::dataJson() {
}
float price = ENTSOE_NO_VALUE;
if(eapi != NULL && strlen(eapi->getToken()) > 0)
if(eapi != NULL)
price = eapi->getValueForHour(0);
snprintf_P(buf, BufferSize, DATA_JSON,