diff --git a/ESP32_AP-Flasher/data/www/content_cards.json.gz b/ESP32_AP-Flasher/data/www/content_cards.json.gz index 247844d8..6878c887 100644 Binary files a/ESP32_AP-Flasher/data/www/content_cards.json.gz and b/ESP32_AP-Flasher/data/www/content_cards.json.gz differ diff --git a/ESP32_AP-Flasher/data/www/ota.js.gz b/ESP32_AP-Flasher/data/www/ota.js.gz index 18cabc8e..30ee03ce 100644 Binary files a/ESP32_AP-Flasher/data/www/ota.js.gz and b/ESP32_AP-Flasher/data/www/ota.js.gz differ diff --git a/ESP32_AP-Flasher/src/contentmanager.cpp b/ESP32_AP-Flasher/src/contentmanager.cpp index 9e6532ca..2e71f4ca 100644 --- a/ESP32_AP-Flasher/src/contentmanager.cpp +++ b/ESP32_AP-Flasher/src/contentmanager.cpp @@ -1541,18 +1541,37 @@ bool getDayAheadFeed(String &filename, JsonObject &cfgobj, tagRecord *&taginfo, int units = cfgobj["units"].as(); if (units == 0) units = 1; - double tarifkwh = cfgobj["tariffkwh"].as(); + double tarifkwh; double tariftax = cfgobj["tarifftax"].as(); - double minPrice = (doc[0]["price"].as() / 10 + tarifkwh) * (1 + tariftax / 100) / units; - double maxPrice = minPrice; + double minPrice = std::numeric_limits::max(); + double maxPrice = std::numeric_limits::lowest(); double prices[n]; + DynamicJsonDocument doc2(500); + JsonArray tariffArray; + std::string tariffString = cfgobj["tariffkwh"].as(); + if (tariffString.front() == '[') { + if (deserializeJson(doc2, tariffString) == DeserializationError::Ok) { + tariffArray = doc2.as(); + } else { + Serial.println("Error in tariffkwh array"); + } + } for (int i = 0; i < n; i++) { const JsonObject &obj = doc[i]; - const double price = (obj["price"].as() / 10 + tarifkwh) * (1 + tariftax / 100) / units; - minPrice = min(minPrice, price); - maxPrice = max(maxPrice, price); - prices[i] = price; + + if (tariffArray.size() == 24) { + const time_t item_time = obj["time"]; + struct tm item_timeinfo; + localtime_r(&item_time, &item_timeinfo); + + tarifkwh = tariffArray[item_timeinfo.tm_hour].as(); + } else { + tarifkwh = cfgobj["tariffkwh"].as(); + } + prices[i] = (obj["price"].as() / 10 + tarifkwh) * (1 + tariftax / 100) / units; + minPrice = std::min(minPrice, prices[i]); + maxPrice = std::max(maxPrice, prices[i]); } std::sort(prices, prices + n); @@ -1565,14 +1584,17 @@ bool getDayAheadFeed(String &filename, JsonObject &cfgobj, tagRecord *&taginfo, for (double i = minPrice; i <= maxPrice; i += yAxisScale.step) { int y = mapDouble(i, minPrice, maxPrice, spr.height() - barBottom, spr.height() - barBottom - loc["bars"][2].as()); spr.drawLine(0, y, spr.width(), y, TFT_BLACK); - drawString(spr, String(int(i * units)), yAxisX, y - 9, loc["yaxis"][0], TL_DATUM, TFT_BLACK); + if (loc["yaxis"][0]) drawString(spr, String(int(i * units)), yAxisX, y - 9, loc["yaxis"][0], TL_DATUM, TFT_BLACK); } uint16_t barwidth = loc["bars"][1].as() / n; uint16_t barheight = loc["bars"][2].as() / (maxPrice - minPrice); - + uint16_t arrowY = 0; + if (loc["bars"].size() >= 5) arrowY = loc["bars"][4].as(); uint16_t barX = loc["bars"][0].as(); double pricenow = std::numeric_limits::quiet_NaN(); + bool showcurrent = true; + if (cfgobj["showcurr"] && cfgobj["showcurr"] == "0") showcurrent = false; for (int i = 0; i < n; i++) { const JsonObject &obj = doc[i]; @@ -1580,27 +1602,40 @@ bool getDayAheadFeed(String &filename, JsonObject &cfgobj, tagRecord *&taginfo, struct tm item_timeinfo; localtime_r(&item_time, &item_timeinfo); + if (tariffArray.size() == 24) { + tarifkwh = tariffArray[item_timeinfo.tm_hour].as(); + } else { + tarifkwh = cfgobj["tariffkwh"].as(); + } + const double price = (obj["price"].as() / 10 + tarifkwh) * (1 + tariftax / 100) / units; uint16_t barcolor = getPercentileColor(prices, n, price, imageParams.hwdata); uint16_t thisbarh = mapDouble(price, minPrice, maxPrice, 0, loc["bars"][2].as()); spr.fillRect(barX + i * barwidth, spr.height() - barBottom - thisbarh, barwidth - 1, thisbarh, barcolor); - if (i % 2 == 0) { + if (i % 2 == 0 && loc["time"][0]) { drawString(spr, String(item_timeinfo.tm_hour), barX + i * barwidth + barwidth / 3 + 1, spr.height() - barBottom + 3, loc["time"][0], TC_DATUM, TFT_BLACK); } - if (now - item_time < 3600 && std::isnan(pricenow)) { - spr.fillRect(barX + i * barwidth + 3, 5, barwidth - 6, 10, imageParams.highlightColor); - spr.fillTriangle(barX + i * barwidth, 15, - barX + i * barwidth + barwidth - 1, 15, - barX + i * barwidth + (barwidth - 1) / 2, 15 + barwidth, imageParams.highlightColor); - spr.drawLine(barX + i * barwidth + (barwidth - 1) / 2, 20 + barwidth, barX + i * barwidth + (barwidth - 1) / 2, spr.height(), getColor("pink")); + if (now - item_time < 3600 && std::isnan(pricenow) && showcurrent) { + spr.fillRect(barX + i * barwidth + (barwidth > 6 ? 3 : 1), 5 + arrowY, (barwidth > 6 ? barwidth - 6 : barwidth - 2), 10, imageParams.highlightColor); + spr.fillTriangle(barX + i * barwidth, 15 + arrowY, + barX + i * barwidth + barwidth - 1, 15 + arrowY, + barX + i * barwidth + (barwidth - 1) / 2, 15 + barwidth + arrowY, imageParams.highlightColor); + spr.drawLine(barX + i * barwidth + (barwidth - 1) / 2, 20 + barwidth + arrowY, barX + i * barwidth + (barwidth - 1) / 2, spr.height(), getColor("pink")); pricenow = price; } } - drawString(spr, String(timeinfo.tm_hour) + ":00", barX, 5, loc["head"][0], TL_DATUM, TFT_BLACK, 30); - drawString(spr, String(pricenow) + "/kWh", spr.width() - barX, 5, loc["head"][0], TR_DATUM, TFT_BLACK, 30); + if (showcurrent) { + if (barwidth < 5) { + drawString(spr, String(timeinfo.tm_hour) + ":00", spr.width() / 2, 5, "calibrib16.vlw", TC_DATUM, TFT_BLACK, 30); + drawString(spr, String(pricenow) + "/kWh", spr.width() / 2, 25, loc["head"][0], TC_DATUM, TFT_BLACK, 30); + } else { + drawString(spr, String(timeinfo.tm_hour) + ":00", barX, 5, loc["head"][0], TL_DATUM, TFT_BLACK, 30); + drawString(spr, String(pricenow) + "/kWh", spr.width() - barX, 5, loc["head"][0], TR_DATUM, TFT_BLACK, 30); + } + } spr2buffer(spr, filename, imageParams); spr.deleteSprite(); diff --git a/ESP32_AP-Flasher/src/web.cpp b/ESP32_AP-Flasher/src/web.cpp index c267c383..bc566ce1 100644 --- a/ESP32_AP-Flasher/src/web.cpp +++ b/ESP32_AP-Flasher/src/web.cpp @@ -147,8 +147,10 @@ void wsSendSysteminfo() { uint32_t tagcount = getTagCount(timeoutcount); char result[40]; if (timeoutcount > 0) { + sys["timeoutcount"] = timeoutcount; snprintf(result, sizeof(result), "%lu/%lu, %lu timeout", tagcount, tagDB.size(), timeoutcount); } else { + sys["timeoutcount"] = 0; snprintf(result, sizeof(result), "%lu / %lu", tagcount, tagDB.size()); } setVarDB("ap_tagcount", result); diff --git a/ESP32_AP-Flasher/wwwroot/content_cards.json b/ESP32_AP-Flasher/wwwroot/content_cards.json index fa5b0d7f..ded082c3 100644 --- a/ESP32_AP-Flasher/wwwroot/content_cards.json +++ b/ESP32_AP-Flasher/wwwroot/content_cards.json @@ -403,7 +403,7 @@ { "key": "tariffkwh", "name": "Fixed surcharge", - "desc": "Fixed surcharge per kWh, in 1/100 units (cents/öre/øre)", + "desc": "Fixed surcharge per kWh, in 1/100 units (cents/öre/øre). Enter one value, or an array of exactly 24 elements for each hour in the form of '[n,n,...,n]'", "type": "text" }, { @@ -421,7 +421,17 @@ "100": "1/1 units (EUR/NOK/DKK)", "1": "1/100 units (cents/öre/øre)" } - } + }, + { + "key": "showcurr", + "name": "Show current", + "desc": "Hourly refresh to show current price (less battery friendly)", + "type": "select", + "options": { + "0": "No", + "1": "-Yes" + } + } ] }, { diff --git a/ESP32_AP-Flasher/wwwroot/ota.js b/ESP32_AP-Flasher/wwwroot/ota.js index d9450b2b..8c09245c 100644 --- a/ESP32_AP-Flasher/wwwroot/ota.js +++ b/ESP32_AP-Flasher/wwwroot/ota.js @@ -594,13 +594,12 @@ async function fetchAndCheckTagtypes(cleanup) { for (const file of fileList) { const filename = file.name; print(filename, "green"); - let check = true; + let check = filename.endsWith('.json'); let hwtype = parseInt(filename, 16); - if (cleanup) { + if (check && cleanup) { let isInUse = Array.from(gridItems).some(element => element.dataset.hwtype == hwtype); if (!isInUse) { - isInUse = Array.from(gridItems).some(element => element.dataset.usetemplate == hwtype); } if (!isInUse) { diff --git a/resources/tagtypes/00.json b/resources/tagtypes/00.json index 2fbf8724..440b55be 100644 --- a/resources/tagtypes/00.json +++ b/resources/tagtypes/00.json @@ -1,5 +1,5 @@ { - "version": 1, + "version": 2, "name": "M2 1.54\"", "width": 152, "height": 152, @@ -12,7 +12,7 @@ }, "shortlut": 2, "options": [ "button", "customlut" ], - "contentids": [ 22, 23, 1, 2, 3, 4, 5, 7, 10, 14, 15, 17, 18, 19, 20, 21 ], + "contentids": [ 22, 23, 1, 2, 3, 4, 5, 7, 10, 14, 15, 17, 18, 19, 20, 21, 27 ], "template": { "1": { "weekday": [ 76, 9, "fonts/calibrib30" ], @@ -44,6 +44,12 @@ { "text": [ 10, 110, "{ap_ch}", "t0_14b_tf", 1, 0, 0 ] }, { "text": [ 3, 125, "Tag count:", "glasstown_nbp_tf", 1, 0, 0 ] }, { "text": [ 10, 140, "{ap_tagcount}", "t0_14b_tf", 1, 0, 0 ] } - ] + ], + "27": { + "bars": [ 4, 152, 70, 1, 50 ], + "time": [ "" ], + "yaxis": [ "tahoma9.vlw", 3, 6 ], + "head": [ "calibrib30.vlw" ] + } } } diff --git a/resources/tagtypes/02.json b/resources/tagtypes/02.json index a92a59b8..02f9c4b3 100644 --- a/resources/tagtypes/02.json +++ b/resources/tagtypes/02.json @@ -1,5 +1,5 @@ { - "version": 3, + "version": 4, "name": "M2 4.2\"", "width": 400, "height": 300, @@ -53,7 +53,7 @@ "gridparam": [ 5, 17, 20, "calibrib16.vlw", "tahoma9.vlw", 14 ] }, "27": { - "bars": [ 15, 385, 240, 20 ], + "bars": [ 15, 385, 225, 20, 22 ], "time": [ "calibrib16.vlw" ], "yaxis": [ "tahoma9.vlw", 3, 6 ], "head": [ "calibrib30.vlw" ]