From 04cd6ac38773db210f17b17b22704e1a24a5689d Mon Sep 17 00:00:00 2001 From: Gunnar Skjold Date: Sat, 3 Sep 2022 14:37:31 +0200 Subject: [PATCH] Some changes to make Svelte UI work --- lib/SvelteUi/include/.gitignore | 1 + lib/SvelteUi/include/AmsWebHeaders.h | 16 + lib/SvelteUi/include/AmsWebServer.h | 2 + lib/SvelteUi/json/data.json | 57 +++ lib/SvelteUi/json/dayplot.json | 50 +++ lib/SvelteUi/json/energyprice.json | 39 ++ lib/SvelteUi/json/monthplot.json | 64 +++ lib/SvelteUi/scripts/generate_includes.py | 58 +-- lib/SvelteUi/src/AmsWebServer.cpp | 490 +++++++++++++++++++++- 9 files changed, 747 insertions(+), 30 deletions(-) create mode 100644 lib/SvelteUi/include/AmsWebHeaders.h create mode 100644 lib/SvelteUi/json/data.json create mode 100644 lib/SvelteUi/json/dayplot.json create mode 100644 lib/SvelteUi/json/energyprice.json create mode 100644 lib/SvelteUi/json/monthplot.json diff --git a/lib/SvelteUi/include/.gitignore b/lib/SvelteUi/include/.gitignore index bf7da504..ed940275 100644 --- a/lib/SvelteUi/include/.gitignore +++ b/lib/SvelteUi/include/.gitignore @@ -1 +1,2 @@ html/*.h +json/*.h diff --git a/lib/SvelteUi/include/AmsWebHeaders.h b/lib/SvelteUi/include/AmsWebHeaders.h new file mode 100644 index 00000000..d118aea2 --- /dev/null +++ b/lib/SvelteUi/include/AmsWebHeaders.h @@ -0,0 +1,16 @@ +static const char HEADER_CACHE_CONTROL[] PROGMEM = "Cache-Control"; +static const char HEADER_PRAGMA[] PROGMEM = "Pragma"; +static const char HEADER_EXPIRES[] PROGMEM = "Expires"; +static const char HEADER_AUTHENTICATE[] PROGMEM = "WWW-Authenticate"; + +static const char CACHE_CONTROL_NO_CACHE[] PROGMEM = "no-cache, no-store, must-revalidate"; +static const char CACHE_1HR[] PROGMEM = "public, max-age=3600"; +static const char PRAGMA_NO_CACHE[] PROGMEM = "no-cache"; +static const char EXPIRES_OFF[] PROGMEM = "-1"; +static const char AUTHENTICATE_BASIC[] PROGMEM = "Basic realm=\"Secure Area\""; + +static const char MIME_PLAIN[] PROGMEM = "text/plain"; +static const char MIME_HTML[] PROGMEM = "text/html"; +static const char MIME_CSS[] PROGMEM = "text/css"; +static const char MIME_JS[] PROGMEM = "text/javascript"; +static const char MIME_JSON[] PROGMEM = "application/json"; diff --git a/lib/SvelteUi/include/AmsWebServer.h b/lib/SvelteUi/include/AmsWebServer.h index b2649cec..e0747fad 100644 --- a/lib/SvelteUi/include/AmsWebServer.h +++ b/lib/SvelteUi/include/AmsWebServer.h @@ -81,6 +81,8 @@ private: void monthplotJson(); void energyPriceJson(); void temperatureJson(); + + void notFound(); }; #endif diff --git a/lib/SvelteUi/json/data.json b/lib/SvelteUi/json/data.json new file mode 100644 index 00000000..0581d6ac --- /dev/null +++ b/lib/SvelteUi/json/data.json @@ -0,0 +1,57 @@ +{ + "im" : %d, + "om" : %d, + "mf" : %d, + "i" : %d, + "e" : %d, + "ri" : %d, + "re" : %d, + "ic" : %.3f, + "ec" : %.3f, + "ric" : %.3f, + "rec" : %.3f, + "u1" : %.2f, + "u2" : %.2f, + "u3" : %.2f, + "i1" : %.2f, + "i2" : %.2f, + "i3" : %.2f, + "f" : %.2f, + "f1" : %.2f, + "f2" : %.2f, + "f3" : %.2f, + "v" : %.3f, + "r" : %d, + "t" : %.2f, + "u" : %lu, + "m" : %lu, + "em" : %d, + "hm" : %d, + "wm" : %d, + "mm" : %d, + "me" : %d, + "p" : %s, + "mt" : %d, + "ds" : %d, + "ea" : { + "x" : %.1f, + "p" : [ %s ], + "t" : %d, + "h" : { + "u" : %.2f, + "c" : %.2f, + "p" : %.2f + }, + "d" : { + "u" : %.2f, + "c" : %.2f, + "p" : %.2f + }, + "m" : { + "u" : %.2f, + "c" : %.2f, + "p" : %.2f + } + }, + "c" : %lu +} \ No newline at end of file diff --git a/lib/SvelteUi/json/dayplot.json b/lib/SvelteUi/json/dayplot.json new file mode 100644 index 00000000..ed782610 --- /dev/null +++ b/lib/SvelteUi/json/dayplot.json @@ -0,0 +1,50 @@ +{ + "i00" : %.2f, + "i01" : %.2f, + "i02" : %.2f, + "i03" : %.2f, + "i04" : %.2f, + "i05" : %.2f, + "i06" : %.2f, + "i07" : %.2f, + "i08" : %.2f, + "i09" : %.2f, + "i10" : %.2f, + "i11" : %.2f, + "i12" : %.2f, + "i13" : %.2f, + "i14" : %.2f, + "i15" : %.2f, + "i16" : %.2f, + "i17" : %.2f, + "i18" : %.2f, + "i19" : %.2f, + "i20" : %.2f, + "i21" : %.2f, + "i22" : %.2f, + "i23" : %.2f, + "e00" : %.2f, + "e01" : %.2f, + "e02" : %.2f, + "e03" : %.2f, + "e04" : %.2f, + "e05" : %.2f, + "e06" : %.2f, + "e07" : %.2f, + "e08" : %.2f, + "e09" : %.2f, + "e10" : %.2f, + "e11" : %.2f, + "e12" : %.2f, + "e13" : %.2f, + "e14" : %.2f, + "e15" : %.2f, + "e16" : %.2f, + "e17" : %.2f, + "e18" : %.2f, + "e19" : %.2f, + "e20" : %.2f, + "e21" : %.2f, + "e22" : %.2f, + "e23" : %.2f +} diff --git a/lib/SvelteUi/json/energyprice.json b/lib/SvelteUi/json/energyprice.json new file mode 100644 index 00000000..9231ba9c --- /dev/null +++ b/lib/SvelteUi/json/energyprice.json @@ -0,0 +1,39 @@ +{ + "currency" : "%s", + "00" : %s, + "01" : %s, + "02" : %s, + "03" : %s, + "04" : %s, + "05" : %s, + "06" : %s, + "07" : %s, + "08" : %s, + "09" : %s, + "10" : %s, + "11" : %s, + "12" : %s, + "13" : %s, + "14" : %s, + "15" : %s, + "16" : %s, + "17" : %s, + "18" : %s, + "19" : %s, + "20" : %s, + "21" : %s, + "22" : %s, + "23" : %s, + "24" : %s, + "25" : %s, + "26" : %s, + "27" : %s, + "28" : %s, + "29" : %s, + "30" : %s, + "31" : %s, + "32" : %s, + "33" : %s, + "34" : %s, + "35" : %s +} diff --git a/lib/SvelteUi/json/monthplot.json b/lib/SvelteUi/json/monthplot.json new file mode 100644 index 00000000..e4271129 --- /dev/null +++ b/lib/SvelteUi/json/monthplot.json @@ -0,0 +1,64 @@ +{ + "i01" : %.2f, + "i02" : %.2f, + "i03" : %.2f, + "i04" : %.2f, + "i05" : %.2f, + "i06" : %.2f, + "i07" : %.2f, + "i08" : %.2f, + "i09" : %.2f, + "i10" : %.2f, + "i11" : %.2f, + "i12" : %.2f, + "i13" : %.2f, + "i14" : %.2f, + "i15" : %.2f, + "i16" : %.2f, + "i17" : %.2f, + "i18" : %.2f, + "i19" : %.2f, + "i20" : %.2f, + "i21" : %.2f, + "i22" : %.2f, + "i23" : %.2f, + "i24" : %.2f, + "i25" : %.2f, + "i26" : %.2f, + "i27" : %.2f, + "i28" : %.2f, + "i29" : %.2f, + "i30" : %.2f, + "i31" : %.2f, + "e01" : %.2f, + "e02" : %.2f, + "e03" : %.2f, + "e04" : %.2f, + "e05" : %.2f, + "e06" : %.2f, + "e07" : %.2f, + "e08" : %.2f, + "e09" : %.2f, + "e10" : %.2f, + "e11" : %.2f, + "e12" : %.2f, + "e13" : %.2f, + "e14" : %.2f, + "e15" : %.2f, + "e16" : %.2f, + "e17" : %.2f, + "e18" : %.2f, + "e19" : %.2f, + "e20" : %.2f, + "e21" : %.2f, + "e22" : %.2f, + "e23" : %.2f, + "e24" : %.2f, + "e25" : %.2f, + "e26" : %.2f, + "e27" : %.2f, + "e28" : %.2f, + "e29" : %.2f, + "e30" : %.2f, + "e31" : %.2f +} diff --git a/lib/SvelteUi/scripts/generate_includes.py b/lib/SvelteUi/scripts/generate_includes.py index a8a81ebc..0cbc873f 100644 --- a/lib/SvelteUi/scripts/generate_includes.py +++ b/lib/SvelteUi/scripts/generate_includes.py @@ -25,7 +25,6 @@ except: print("WARN: Unable to load minifier") -webroot = "lib/SvelteUi/app/dist" srcroot = "lib/SvelteUi/include/html" version = os.environ.get('GITHUB_TAG') @@ -45,36 +44,37 @@ if os.path.exists(srcroot): else: os.mkdir(srcroot) -for filename in os.listdir(webroot): - basename = re.sub("[^0-9a-zA-Z]+", "_", filename) +for webroot in ["lib/SvelteUi/app/dist", "lib/SvelteUi/json"]: + for filename in os.listdir(webroot): + basename = re.sub("[^0-9a-zA-Z]+", "_", filename) - srcfile = webroot + "/" + filename - dstfile = srcroot + "/" + basename + ".h" + srcfile = webroot + "/" + filename + dstfile = srcroot + "/" + basename + ".h" - varname = basename.upper() + varname = basename.upper() - with open(srcfile, encoding="utf-8") as f: - content = f.read().replace("${version}", version) + with open(srcfile, encoding="utf-8") as f: + content = f.read().replace("${version}", version) - try: - if filename.endswith(".html"): - content = html_minify(content) - elif filename.endswith(".css"): - content = css_minify(content) - elif (filename.endswith(".js") and filename != 'gaugemeter.js') or filename.endswith(".json"): - content = js_minify(content) - except: - print("WARN: Unable to minify") + try: + if filename.endswith(".html"): + content = html_minify(content) + elif filename.endswith(".css"): + content = css_minify(content) + elif filename.endswith(".json"): + content = js_minify(content) + except: + print("WARN: Unable to minify") - with open(dstfile, "w") as dst: - dst.write("static const char ") - dst.write(varname) - dst.write("[] PROGMEM = R\"==\"==(") - dst.write(content) - dst.write(")==\"==\";\n") - dst.write("const int "); - dst.write(varname) - dst.write("_LEN PROGMEM = "); - dst.write(str(len(content))) - dst.write(";"); - \ No newline at end of file + with open(dstfile, "w") as dst: + dst.write("static const char ") + dst.write(varname) + dst.write("[] PROGMEM = R\"==\"==(") + dst.write(content) + dst.write(")==\"==\";\n") + dst.write("const int "); + dst.write(varname) + dst.write("_LEN PROGMEM = "); + dst.write(str(len(content))) + dst.write(";"); + \ No newline at end of file diff --git a/lib/SvelteUi/src/AmsWebServer.cpp b/lib/SvelteUi/src/AmsWebServer.cpp index bf7f1239..9af61c1c 100644 --- a/lib/SvelteUi/src/AmsWebServer.cpp +++ b/lib/SvelteUi/src/AmsWebServer.cpp @@ -1,4 +1,17 @@ #include "AmsWebServer.h" +#include "AmsWebHeaders.h" +#include "base64.h" + +#include "html/index_html.h" +#include "html/index_css.h" +#include "html/index_js.h" +#include "html/github_svg.h" +#include "html/data_json.h" +#include "html/dayplot_json.h" +#include "html/monthplot_json.h" +#include "html/energyprice_json.h" + + AmsWebServer::AmsWebServer(uint8_t* buf, RemoteDebug* Debug, HwTools* hw) { this->debugger = Debug; @@ -13,4 +26,479 @@ void AmsWebServer::setup(AmsConfiguration* config, GpioConfig* gpioConfig, Meter this->meterState = meterState; this->ds = ds; this->ea = ea; -} \ No newline at end of file + + // TODO + server.on("/", HTTP_GET, std::bind(&AmsWebServer::indexHtml, this)); + server.on("/index.css", HTTP_GET, std::bind(&AmsWebServer::indexCss, this)); + server.on("/index.js", HTTP_GET, std::bind(&AmsWebServer::indexJs, this)); + server.on("/github.svg", HTTP_GET, std::bind(&AmsWebServer::githubSvg, this)); + server.on("/data.json", HTTP_GET, std::bind(&AmsWebServer::dataJson, this)); + server.on("/dayplot.json", HTTP_GET, std::bind(&AmsWebServer::dayplotJson, this)); + server.on("/monthplot.json", HTTP_GET, std::bind(&AmsWebServer::monthplotJson, this)); + server.on("/energyprice.json", HTTP_GET, std::bind(&AmsWebServer::energyPriceJson, this)); + + server.onNotFound(std::bind(&AmsWebServer::notFound, this)); + + server.begin(); // Web server start + + config->getWebConfig(webConfig); + MqttConfig mqttConfig; + config->getMqttConfig(mqttConfig); + mqttEnabled = strlen(mqttConfig.host) > 0; +} + + +void AmsWebServer::setMqtt(MQTTClient* mqtt) { + this->mqtt = mqtt; +} + +void AmsWebServer::setTimezone(Timezone* tz) { + this->tz = tz; +} + +void AmsWebServer::setMqttEnabled(bool enabled) { + mqttEnabled = enabled; +} + +void AmsWebServer::setEntsoeApi(EntsoeApi* eapi) { + this->eapi = eapi; +} + +void AmsWebServer::loop() { + server.handleClient(); + + if(maxPwr == 0 && meterState->getListType() > 1 && meterConfig->mainFuse > 0 && meterConfig->distributionSystem > 0) { + int voltage = meterConfig->distributionSystem == 2 ? 400 : 230; + if(meterState->isThreePhase()) { + maxPwr = meterConfig->mainFuse * sqrt(3) * voltage; + } else if(meterState->isTwoPhase()) { + maxPwr = meterConfig->mainFuse * voltage; + } else { + maxPwr = meterConfig->mainFuse * 230; + } + } +} + +bool AmsWebServer::checkSecurity(byte level) { + bool access = WiFi.getMode() == WIFI_AP || webConfig.security < level; + if(!access && webConfig.security >= level && server.hasHeader("Authorization")) { + String expectedAuth = String(webConfig.username) + ":" + String(webConfig.password); + + String providedPwd = server.header("Authorization"); + providedPwd.replace("Basic ", ""); + + #if defined(ESP8266) + String expectedBase64 = base64::encode(expectedAuth, false); + #elif defined(ESP32) + String expectedBase64 = base64::encode(expectedAuth); + #endif + + debugger->printf("Expected auth: %s\n", expectedBase64.c_str()); + debugger->printf("Provided auth: %s\n", providedPwd.c_str()); + + access = providedPwd.equals(expectedBase64); + } + + if(!access) { + server.sendHeader(HEADER_AUTHENTICATE, AUTHENTICATE_BASIC); + server.setContentLength(0); + server.send(401, MIME_HTML, ""); + } + return access; +} + +void AmsWebServer::notFound() { + server.sendHeader(HEADER_CACHE_CONTROL, CACHE_1HR); + server.send(404); +} +void AmsWebServer::githubSvg() { + if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf("Serving /github.svg over http...\n"); + + server.sendHeader(HEADER_CACHE_CONTROL, CACHE_1HR); + server.send_P(200, "image/svg+xml", GITHUB_SVG); +} + +void AmsWebServer::dataJson() { + if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf("Serving /data.json over http...\n"); + uint64_t now = millis64(); + + if(!checkSecurity(2)) + return; + + float vcc = hw->getVcc(); + int rssi = hw->getWifiRssi(); + + uint8_t espStatus; + #if defined(ESP8266) + if(vcc == 0) { + espStatus = 1; + } else if(vcc > 3.1 && vcc < 3.5) { + espStatus = 1; + } else if(vcc > 3.0 && vcc < 3.6) { + espStatus = 2; + } else { + espStatus = 3; + } + #elif defined(ESP32) + if(vcc == 0) { + espStatus = 1; + } else if(vcc > 2.8 && vcc < 3.5) { + espStatus = 1; + } else if(vcc > 2.7 && vcc < 3.6) { + espStatus = 2; + } else { + espStatus = 3; + } + #endif + + + uint8_t hanStatus; + if(meterConfig->baud == 0) { + hanStatus = 0; + } else if(now - meterState->getLastUpdateMillis() < 15000) { + hanStatus = 1; + } else if(now - meterState->getLastUpdateMillis() < 30000) { + hanStatus = 2; + } else { + hanStatus = 3; + } + + uint8_t wifiStatus; + if(rssi > -75) { + wifiStatus = 1; + } else if(rssi > -95) { + wifiStatus = 2; + } else { + wifiStatus = 3; + } + + uint8_t mqttStatus; + if(!mqttEnabled) { + mqttStatus = 0; + } else if(mqtt != NULL && mqtt->connected()) { + mqttStatus = 1; + } else if(mqtt != NULL && mqtt->lastError() == 0) { + mqttStatus = 2; + } else { + mqttStatus = 3; + } + + float price = ENTSOE_NO_VALUE; + if(eapi != NULL && strlen(eapi->getToken()) > 0) + price = eapi->getValueForHour(0); + + String peaks = ""; + for(uint8_t i = 1; i <= ea->getConfig()->hours; i++) { + if(!peaks.isEmpty()) peaks += ","; + peaks += String(ea->getPeak(i)); + } + + snprintf_P(buf, BufferSize, DATA_JSON, + maxPwr == 0 ? meterState->isThreePhase() ? 20000 : 10000 : maxPwr, + meterConfig->productionCapacity, + meterConfig->mainFuse == 0 ? 32 : meterConfig->mainFuse, + meterState->getActiveImportPower(), + meterState->getActiveExportPower(), + meterState->getReactiveImportPower(), + meterState->getReactiveExportPower(), + meterState->getActiveImportCounter(), + meterState->getActiveExportCounter(), + meterState->getReactiveImportCounter(), + meterState->getReactiveExportCounter(), + meterState->getL1Voltage(), + meterState->getL2Voltage(), + meterState->getL3Voltage(), + meterState->getL1Current(), + meterState->getL2Current(), + meterState->getL3Current(), + meterState->getPowerFactor(), + meterState->getL1PowerFactor(), + meterState->getL2PowerFactor(), + meterState->getL3PowerFactor(), + vcc, + rssi, + hw->getTemperature(), + (uint32_t) (now / 1000), + ESP.getFreeHeap(), + espStatus, + hanStatus, + wifiStatus, + mqttStatus, + mqtt == NULL ? 0 : (int) mqtt->lastError(), + price == ENTSOE_NO_VALUE ? "null" : String(price, 2).c_str(), + meterState->getMeterType(), + meterConfig->distributionSystem, + 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(), + (uint32_t) time(nullptr) + ); + + server.sendHeader(HEADER_CACHE_CONTROL, CACHE_CONTROL_NO_CACHE); + server.sendHeader(HEADER_PRAGMA, PRAGMA_NO_CACHE); + server.sendHeader(HEADER_EXPIRES, EXPIRES_OFF); + + server.setContentLength(strlen(buf)); + server.send(200, MIME_JSON, buf); +} + +void AmsWebServer::dayplotJson() { + if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf("Serving /dayplot.json over http...\n"); + + if(!checkSecurity(2)) + return; + + if(ds == NULL) { + notFound(); + } else { + snprintf_P(buf, BufferSize, DAYPLOT_JSON, + ds->getHourImport(0) / 1000.0, + ds->getHourImport(1) / 1000.0, + ds->getHourImport(2) / 1000.0, + ds->getHourImport(3) / 1000.0, + ds->getHourImport(4) / 1000.0, + ds->getHourImport(5) / 1000.0, + ds->getHourImport(6) / 1000.0, + ds->getHourImport(7) / 1000.0, + ds->getHourImport(8) / 1000.0, + ds->getHourImport(9) / 1000.0, + ds->getHourImport(10) / 1000.0, + ds->getHourImport(11) / 1000.0, + ds->getHourImport(12) / 1000.0, + ds->getHourImport(13) / 1000.0, + ds->getHourImport(14) / 1000.0, + ds->getHourImport(15) / 1000.0, + ds->getHourImport(16) / 1000.0, + ds->getHourImport(17) / 1000.0, + ds->getHourImport(18) / 1000.0, + ds->getHourImport(19) / 1000.0, + ds->getHourImport(20) / 1000.0, + ds->getHourImport(21) / 1000.0, + ds->getHourImport(22) / 1000.0, + ds->getHourImport(23) / 1000.0, + ds->getHourExport(0) / 1000.0, + ds->getHourExport(1) / 1000.0, + ds->getHourExport(2) / 1000.0, + ds->getHourExport(3) / 1000.0, + ds->getHourExport(4) / 1000.0, + ds->getHourExport(5) / 1000.0, + ds->getHourExport(6) / 1000.0, + ds->getHourExport(7) / 1000.0, + ds->getHourExport(8) / 1000.0, + ds->getHourExport(9) / 1000.0, + ds->getHourExport(10) / 1000.0, + ds->getHourExport(11) / 1000.0, + ds->getHourExport(12) / 1000.0, + ds->getHourExport(13) / 1000.0, + ds->getHourExport(14) / 1000.0, + ds->getHourExport(15) / 1000.0, + ds->getHourExport(16) / 1000.0, + ds->getHourExport(17) / 1000.0, + ds->getHourExport(18) / 1000.0, + ds->getHourExport(19) / 1000.0, + ds->getHourExport(20) / 1000.0, + ds->getHourExport(21) / 1000.0, + ds->getHourExport(22) / 1000.0, + ds->getHourExport(23) / 1000.0 + ); + + server.sendHeader(HEADER_CACHE_CONTROL, CACHE_CONTROL_NO_CACHE); + server.sendHeader(HEADER_PRAGMA, PRAGMA_NO_CACHE); + server.sendHeader(HEADER_EXPIRES, EXPIRES_OFF); + + server.setContentLength(strlen(buf)); + server.send(200, MIME_JSON, buf); + } +} + +void AmsWebServer::monthplotJson() { + if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf("Serving /monthplot.json over http...\n"); + + if(!checkSecurity(2)) + return; + + if(ds == NULL) { + notFound(); + } else { + snprintf_P(buf, BufferSize, MONTHPLOT_JSON, + ds->getDayImport(1) / 1000.0, + ds->getDayImport(2) / 1000.0, + ds->getDayImport(3) / 1000.0, + ds->getDayImport(4) / 1000.0, + ds->getDayImport(5) / 1000.0, + ds->getDayImport(6) / 1000.0, + ds->getDayImport(7) / 1000.0, + ds->getDayImport(8) / 1000.0, + ds->getDayImport(9) / 1000.0, + ds->getDayImport(10) / 1000.0, + ds->getDayImport(11) / 1000.0, + ds->getDayImport(12) / 1000.0, + ds->getDayImport(13) / 1000.0, + ds->getDayImport(14) / 1000.0, + ds->getDayImport(15) / 1000.0, + ds->getDayImport(16) / 1000.0, + ds->getDayImport(17) / 1000.0, + ds->getDayImport(18) / 1000.0, + ds->getDayImport(19) / 1000.0, + ds->getDayImport(20) / 1000.0, + ds->getDayImport(21) / 1000.0, + ds->getDayImport(22) / 1000.0, + ds->getDayImport(23) / 1000.0, + ds->getDayImport(24) / 1000.0, + ds->getDayImport(25) / 1000.0, + ds->getDayImport(26) / 1000.0, + ds->getDayImport(27) / 1000.0, + ds->getDayImport(28) / 1000.0, + ds->getDayImport(29) / 1000.0, + ds->getDayImport(30) / 1000.0, + ds->getDayImport(31) / 1000.0, + ds->getDayExport(1) / 1000.0, + ds->getDayExport(2) / 1000.0, + ds->getDayExport(3) / 1000.0, + ds->getDayExport(4) / 1000.0, + ds->getDayExport(5) / 1000.0, + ds->getDayExport(6) / 1000.0, + ds->getDayExport(7) / 1000.0, + ds->getDayExport(8) / 1000.0, + ds->getDayExport(9) / 1000.0, + ds->getDayExport(10) / 1000.0, + ds->getDayExport(11) / 1000.0, + ds->getDayExport(12) / 1000.0, + ds->getDayExport(13) / 1000.0, + ds->getDayExport(14) / 1000.0, + ds->getDayExport(15) / 1000.0, + ds->getDayExport(16) / 1000.0, + ds->getDayExport(17) / 1000.0, + ds->getDayExport(18) / 1000.0, + ds->getDayExport(19) / 1000.0, + ds->getDayExport(20) / 1000.0, + ds->getDayExport(21) / 1000.0, + ds->getDayExport(22) / 1000.0, + ds->getDayExport(23) / 1000.0, + ds->getDayExport(24) / 1000.0, + ds->getDayExport(25) / 1000.0, + ds->getDayExport(26) / 1000.0, + ds->getDayExport(27) / 1000.0, + ds->getDayExport(28) / 1000.0, + ds->getDayExport(29) / 1000.0, + ds->getDayExport(30) / 1000.0, + ds->getDayExport(31) / 1000.0 + ); + + server.sendHeader(HEADER_CACHE_CONTROL, CACHE_CONTROL_NO_CACHE); + server.sendHeader(HEADER_PRAGMA, PRAGMA_NO_CACHE); + server.sendHeader(HEADER_EXPIRES, EXPIRES_OFF); + + server.setContentLength(strlen(buf)); + server.send(200, MIME_JSON, buf); + } +} + +void AmsWebServer::energyPriceJson() { + if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf("Serving /energyprice.json over http...\n"); + + if(!checkSecurity(2)) + return; + + float prices[36]; + for(int i = 0; i < 36; i++) { + prices[i] = eapi == NULL ? ENTSOE_NO_VALUE : eapi->getValueForHour(i); + } + + snprintf_P(buf, BufferSize, ENERGYPRICE_JSON, + eapi == NULL ? "" : eapi->getCurrency(), + prices[0] == ENTSOE_NO_VALUE ? "null" : String(prices[0], 4).c_str(), + prices[1] == ENTSOE_NO_VALUE ? "null" : String(prices[1], 4).c_str(), + prices[2] == ENTSOE_NO_VALUE ? "null" : String(prices[2], 4).c_str(), + prices[3] == ENTSOE_NO_VALUE ? "null" : String(prices[3], 4).c_str(), + prices[4] == ENTSOE_NO_VALUE ? "null" : String(prices[4], 4).c_str(), + prices[5] == ENTSOE_NO_VALUE ? "null" : String(prices[5], 4).c_str(), + prices[6] == ENTSOE_NO_VALUE ? "null" : String(prices[6], 4).c_str(), + prices[7] == ENTSOE_NO_VALUE ? "null" : String(prices[7], 4).c_str(), + prices[8] == ENTSOE_NO_VALUE ? "null" : String(prices[8], 4).c_str(), + prices[9] == ENTSOE_NO_VALUE ? "null" : String(prices[9], 4).c_str(), + prices[10] == ENTSOE_NO_VALUE ? "null" : String(prices[10], 4).c_str(), + prices[11] == ENTSOE_NO_VALUE ? "null" : String(prices[11], 4).c_str(), + prices[12] == ENTSOE_NO_VALUE ? "null" : String(prices[12], 4).c_str(), + prices[13] == ENTSOE_NO_VALUE ? "null" : String(prices[13], 4).c_str(), + prices[14] == ENTSOE_NO_VALUE ? "null" : String(prices[14], 4).c_str(), + prices[15] == ENTSOE_NO_VALUE ? "null" : String(prices[15], 4).c_str(), + prices[16] == ENTSOE_NO_VALUE ? "null" : String(prices[16], 4).c_str(), + prices[17] == ENTSOE_NO_VALUE ? "null" : String(prices[17], 4).c_str(), + prices[18] == ENTSOE_NO_VALUE ? "null" : String(prices[18], 4).c_str(), + prices[19] == ENTSOE_NO_VALUE ? "null" : String(prices[19], 4).c_str(), + prices[20] == ENTSOE_NO_VALUE ? "null" : String(prices[20], 4).c_str(), + prices[21] == ENTSOE_NO_VALUE ? "null" : String(prices[21], 4).c_str(), + prices[22] == ENTSOE_NO_VALUE ? "null" : String(prices[22], 4).c_str(), + prices[23] == ENTSOE_NO_VALUE ? "null" : String(prices[23], 4).c_str(), + prices[24] == ENTSOE_NO_VALUE ? "null" : String(prices[24], 4).c_str(), + prices[25] == ENTSOE_NO_VALUE ? "null" : String(prices[25], 4).c_str(), + prices[26] == ENTSOE_NO_VALUE ? "null" : String(prices[26], 4).c_str(), + prices[27] == ENTSOE_NO_VALUE ? "null" : String(prices[27], 4).c_str(), + prices[28] == ENTSOE_NO_VALUE ? "null" : String(prices[28], 4).c_str(), + prices[29] == ENTSOE_NO_VALUE ? "null" : String(prices[29], 4).c_str(), + prices[30] == ENTSOE_NO_VALUE ? "null" : String(prices[30], 4).c_str(), + prices[31] == ENTSOE_NO_VALUE ? "null" : String(prices[31], 4).c_str(), + prices[32] == ENTSOE_NO_VALUE ? "null" : String(prices[32], 4).c_str(), + prices[33] == ENTSOE_NO_VALUE ? "null" : String(prices[33], 4).c_str(), + prices[34] == ENTSOE_NO_VALUE ? "null" : String(prices[34], 4).c_str(), + prices[35] == ENTSOE_NO_VALUE ? "null" : String(prices[35], 4).c_str() + ); + + server.sendHeader(HEADER_CACHE_CONTROL, CACHE_CONTROL_NO_CACHE); + server.sendHeader(HEADER_PRAGMA, PRAGMA_NO_CACHE); + server.sendHeader(HEADER_EXPIRES, EXPIRES_OFF); + + server.setContentLength(strlen(buf)); + server.send(200, MIME_JSON, buf); +} + +void AmsWebServer::indexHtml() { + if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf("Serving /index.html over http...\n"); + + server.sendHeader(HEADER_CACHE_CONTROL, CACHE_CONTROL_NO_CACHE); + server.sendHeader(HEADER_PRAGMA, PRAGMA_NO_CACHE); + server.sendHeader(HEADER_EXPIRES, EXPIRES_OFF); + + if(!checkSecurity(2)) + return; + server.setContentLength(INDEX_HTML_LEN); + server.send_P(200, MIME_HTML, INDEX_HTML); +} + +void AmsWebServer::indexCss() { + if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf("Serving /index.css over http...\n"); + + server.sendHeader(HEADER_CACHE_CONTROL, CACHE_CONTROL_NO_CACHE); + server.sendHeader(HEADER_PRAGMA, PRAGMA_NO_CACHE); + server.sendHeader(HEADER_EXPIRES, EXPIRES_OFF); + + if(!checkSecurity(2)) + return; + + server.setContentLength(INDEX_CSS_LEN); + server.send_P(200, MIME_CSS, INDEX_CSS); +} + +void AmsWebServer::indexJs() { + if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf("Serving /index.js over http...\n"); + + server.sendHeader(HEADER_CACHE_CONTROL, CACHE_CONTROL_NO_CACHE); + server.sendHeader(HEADER_PRAGMA, PRAGMA_NO_CACHE); + server.sendHeader(HEADER_EXPIRES, EXPIRES_OFF); + + if(!checkSecurity(2)) + return; + + server.setContentLength(INDEX_JS_LEN); + server.send_P(200, MIME_JS, INDEX_JS); +}