From 587d7c86c0444b335dab2a85c4bf4dcb62c35ab0 Mon Sep 17 00:00:00 2001 From: Nic Limper Date: Thu, 21 Mar 2024 20:11:12 +0100 Subject: [PATCH] various fixes - added last updated time of a tag in tagdb - day ahead prices choice of whole money units or cents - optimization of file upload during updates - show mac address in wifi setup - fixed reload of display after unexpected reboot of tag --- ESP32_AP-Flasher/data/tagtypes/31.json | 4 +- .../data/www/content_cards.json.gz | Bin 4409 -> 4574 bytes ESP32_AP-Flasher/data/www/main.js.gz | Bin 14349 -> 14321 bytes ESP32_AP-Flasher/data/www/setup.html.gz | Bin 689 -> 736 bytes ESP32_AP-Flasher/data/www/setup.js.gz | Bin 1013 -> 1023 bytes ESP32_AP-Flasher/include/tag_db.h | 3 +- ESP32_AP-Flasher/src/contentmanager.cpp | 21 +++-- ESP32_AP-Flasher/src/newproto.cpp | 7 +- ESP32_AP-Flasher/src/ota.cpp | 80 ++++++++++++++---- ESP32_AP-Flasher/src/tag_db.cpp | 2 + ESP32_AP-Flasher/src/web.cpp | 1 + ESP32_AP-Flasher/wwwroot/content_cards.json | 25 +++++- ESP32_AP-Flasher/wwwroot/setup.html | 8 +- ESP32_AP-Flasher/wwwroot/setup.js | 1 + 14 files changed, 119 insertions(+), 33 deletions(-) diff --git a/ESP32_AP-Flasher/data/tagtypes/31.json b/ESP32_AP-Flasher/data/tagtypes/31.json index e4f78bab..69169e71 100644 --- a/ESP32_AP-Flasher/data/tagtypes/31.json +++ b/ESP32_AP-Flasher/data/tagtypes/31.json @@ -33,8 +33,8 @@ "4": { "location": [ 5, 5, "fonts/bahnschrift30" ], "wind": [ 280, 5, "fonts/bahnschrift30" ], - "temp": [ 5, 65, "fonts/bahnschrift70" ], - "icon": [ 285, 20, 70, 2 ], + "temp": [ 5, 65, "fonts/calibrib80" ], + "icon": [ 275, 20, 90, 2 ], "dir": [ 245, -12, 40 ], "umbrella": [ 190, -50, 25 ] }, diff --git a/ESP32_AP-Flasher/data/www/content_cards.json.gz b/ESP32_AP-Flasher/data/www/content_cards.json.gz index a06edadc5b8923c846bedbf0be8e4484abec78dc..ba51825e277592d02dd88c07f34708bed5a71d8f 100644 GIT binary patch literal 4574 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 literal 4409 zcmV-95ytKxiwFn+00002|6^}%bY*UIUt?i%WOFWRb8l_{?OgqG<2I82f2;N#aK5@4 zyGo<6WP6g#{c+{-$HW_r?Xx_|-EM8AAQF-glK__hEo-jwSoZ?=WY^swD2fCne z%S|eABsK^%8jZ%UKcK(-@ehps7ye;vN5(sE*nY44rg$pg`_7Jk5DOFGgG+5$q}5c; zid@7MIpaA`f&LfvSA6nouhsQ%*z9|3xs?%J{0^Q2Tg+;f3nM?mr@3(N;xqgb={y&aMY>K3E4AvkC*i(V6CmQ9 zSR!9II8C5eqxl(~hlqYgBOURC`S+Pt#7`ovO~ll&IG6Y9FWO~Bz5bHT@U0zB`nC56 zf3bvK^B{MpM3QP2Wbd}f6`S*9YPAw9_HB_*5VD?5`;3}Mi;os_p`ek;628P%*<4#~ z`s^IqTJc~_k1ch-{=P(59qPl zSv~xWhzSN5?{ zJ6e8v&_Q#|lLB^wvMlDdYYWn*2{rqSIktw=1@*Ett-*+7h}OeRpIcO`1*jo$aLB3YkdMui2ZN#dNIM*4A^+EwYFm^M9 z;(HA)>nKF5upQx&a>GcwgcE-bYYhJu1||duD$)9`$Q*Ft_En-`-=QpfBqeB2>I38M z;IIo&~LYIgBXX$I9q&2}AeP~gt)fY)5LCgS2&N=9ynhR zs&fk;Q_u_P)F*^aR!m^qY~FYygj^mI$v?vigx9$7yaJ%G^0tTt+cm;>hN>z&W!tyBM02RK%<-;6o?F>La1lYfLw9>&L>`b-=?ZtA{mnmTW}K-B~o zlQuqVHoy<=CYSwt>21dCX4i|75cj6p03c}HTC&sJZ4i-3!-|y-l2mEC!ufPR@E;luIE(dc*2VX z_y_E@$(4sJ}W8Oq2^;6X@f8Bht1izeY^t}VAB?z0n}Xh6k_lIUXOU#4=om8`UDD&Ty?DZH0T zrbUXB1OG;UTa_EM(nkM&!y+BGL(1MdU}k5EOJ6QTv;FVKg8eOj8EIHV6+Sj;;%&0$ zi16L9i zk7t<%HdBES+g-w8!$Swd_ME%OSz{DHI{!ze z%q*fF+DcPU6K4wGt-RLlSiqjuQGv`5_`*aM0DyTh0ge^~n>2}e=l_>Lo9iD+XRTvg%OZZE)bAEOI4hQM5<$#a_G`2j=9^VNGhF>sO=Fm94MTnBK zNnx!fAH_gZ0PzgoiiFFX!pW6piRhss-U$KlKIhS$KN+c0>dWX7YaJx|Z1$S{6Yy~4J%*#TfXwKElCC4W~1!(~i=>HC_uaoy6$OCy<2ngP~MHz&h zUNl*&EC;qP7jeLLr}b6i%;oiS1^`6fgWtCIEZh%2i~He*+zaQmCA3BZERw2WA=a&={%-{;9N%j4YUum>o6z@ zI|E&6m~B>}LL)Nt_5|(QSJc`lYQITQG zUp?hZJ{LTO?qwv}>HmrzFX0s#G1^+t7Hk&iRt_800NA5~oHuxeDmc4xRNOwIP%ZkR zc=n@?Qu_I_JEh;CRW&xme2G+DJE~czKfwK@wDrMB%n0|`f@&I)SiQjHj*8d(-I=#) zu2?H91J-B9ag6@IG^VHu(yq>~M;;ZUdjUq!;rCZFMU%0wHg~8w^ z?Z%l!uGTj`j(O(dD|yP*vOydDSjI)~TceFgOd}LNZ}T$xK-A(vq!Un&S%Z8zB2%#n zT{r1h16RPAFZhz-wb z{(<&UqVM@#n|R@gqW$LCn21+ai)}#;D=))HMV2yszq93l&o1!}T z-jSvK=+<)Mv)tLiyT!btPW1s{KUl~)&u3u})@Vb(;_jz;56#fv)nI?0QAU#OMrcvC z1&fYf%OAq0Gk?JGaU|Zs?sY}>R;w)dwc7He0d|Lj9+}7C;9uB}$G3aihfZ3-{XZGB zrvkyaG^9PM3h@ zfERXkgR#C)Vf5x&^7P{C^Q!FnA2myS`SZ)TpB^k(FSG#OdKBF1h@Vs{_Zx+ZhpkZY zsn1jbp2?Q2o$_AhdASH>Ae6FQysWqez&CR{9g7hGyGrFkd+;0`xEasm1cNO;o$C5< z?jQPf(9YBn4Ibx`Qwh@pFcu4}Kq&$7`UohSgv$C$V{?4HS&lg6QE-Ld^XMhmuok|q zq_U!WmXRHd`z$zlB$z73?5~d=J8`*r*F;y&Tu>^5G9Je0NMgRj7u3QWc@*JD6v}me zNb_k;gf%hyQMb0Q!&YeexIVa4Q{5esLn`iBTr>{I$=1Ww2?f}db583s+Ua8DAe>+W zXDHFUoy@&<&&k|ZH&G^(+*$xXwia11(iW}|;p=6VGJu#0tCMD5b*KGSkDBBvd6H7m z_ioML@iMF6q)3T8aCetjQ7z-rD8Q~r$=svQ1(MCs<4pxui@8j;EW7@CJ7+T(+t^gW zg9GMt9cb1t1F)J4x-I6Ky1E~Xj-#P`mRXkrg=X&gd*bwehP@pWLD?@GeYg#44d9j; zB>?=iN%6}Rwl64I+4*KaPZouk@*=SzQCw0s2NV9oN zjLwj^nl&srH9!k&gev2ivtCV~u>3Yj=$JH!5y4JAmx^8DIhKUP`r+aYAku`JIVS6b zP$B7Jqmee&pLmT(uNN{lJH7^EQM4TKLr;e_>S%Jb8VM}Vt;kb0PK0R1uaBH(E@QkK zvRJ=r=i9udkTRTvZ-Pl0Z1PR3Nz)l0ez$7!?)u`YIpzHo`SSea2^R zgH>H)QAUH&sV{*dwvFa8a}Wm!n4`h4a0-ykrDZs^$_02W*B`jo1> zZ$nn$7Uq3Izt0d56U-LnQeupH4&2b@Hln;YOILhcz=M!n{S~krse|1q!D$tN<$cI6EECOBuHAP4X%&Hc4divcLhr?Kt z+0``{7?OyaLe+e_03Z?+z|A@PsY$D1e$(dMO_61IB?sQZ9-RPexqLjva0J`$fA>HC zeZ0EdpYz4@i09O0>*J7Y&XglQ=H@Lim$sn8t`=6EF#itz-R)+Fq#?wlJ+O5^k~=moE05AX@gK6_q6B?VWa@{V{ZOj9pl$FqqlfG=Ac%~bfUx2`mqy+SIPPvj~8f% zC$5VZWgn<)RM%1V%-Ow8T++*5vPb!Y5f^wJpJOEd3zs3-6Bk!K-9lrKCOygl3Pn? z_^MIq@gDb?>CnC6w~0Pb$TS1eiCT0s)^&P z)1o0|sQ}&6+4Bo{`p24hF#}%%E9{F?90UZ>Fzo z%t+hu)=$~r3t#KD8znNjt7SPDmNF?Uktf8wNARGaI|K_waYDooQwqtI_cR6G*{gVS zRbCi*iG=(86ueCYZ!H&m`369>PXIY&zEv0 zowy%P+m*^+B{5=k>z@3hT-@XD1W0sK>Gp;bC(c3Sd*mMW5@hMe zfsTp{C4g?0tW|CPW;rRuDpf8j!`}z$bhto}>-ngVxd%XCQkqWQ%9G9 diff --git a/ESP32_AP-Flasher/data/www/main.js.gz b/ESP32_AP-Flasher/data/www/main.js.gz index 0a17864be6f1412371c8235eab942b9f1d36ac2b..a067d57976d7716485bf9ef7ed712de46f1e46d2 100644 GIT binary patch delta 14217 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 IYpezU0IkY!9{>OV delta 679 zcmV;Y0$Bav1+fK?7JpPtZ`&{oy${%b;C$&NiJP5<)($ZAV=K_L0a9StQL*WSt1M{} zoirHs-$&U_leSAcUo4X1Bl$=w`*41HcK2g?0blRFT~FS>%a&Yg`NtEgQcfUWRwFA| zGP@!EYG{=wg*A+ZhrDr^KriJ9;{&G=;uMOd@&P$-xEg*+o__!tRb!s42-nVf-g945 z$;-UN6%{yag#nNuCZ&g=P#W{`0BZF>byM#YO+epDYA%Z71k$#EHXajeoJbyx1E&@U zL%4Nl;9{yAdblQY51)$yLx8Cz!&%yS^zJ&^J?cCOywMnzh?4KpW0fbhA~PyNNFb8X z*WSwMOLvkQw|^I@mPFE(DMy{QgR9gkic$B-RvWYz;x}58DeYP~aSg-oogscLUnemB zcnlt)S2 zdb=B`1gMnp3sfc($mR{RHLXfh;7(mh3J`&^w6hEDRFYd;U;Y!<^~Mg{z05xCl6#u( zmjgWD&T55f?HmqUsI6&Yg8))tQ~Jg+1yVA^#BK3_t!Zf z7xSDobAv3eK)8SHav_)=+7uc5t7Bn@InAM6Z zNv&ce{`U@bv1MJ1#%QNCUUA zd5g=7%Zmb+WZ|2~yof)bjq+C`ziJ^A|b)r&tD4HkL3L4TNy?+(@F#6G}z8{^If`z4GQ zA#p2;bB5E*Os>h2%)BnnJ{rumcmSCjx0UpSyqe8s-lC7MI@mGn2_%^DfO}rbi7v&X zttngqGq6s;ez~*)(4l~p$;Vm6K9s#FOWlQ)=S{&BQr&Amlxoee*!99djoP)UQKcey zW5DBSWPeunc>FXKVDL1}Q$Y@c+Rk8cKE6Z}Co*c1{(&In5MGtD+Qd;9XhQz*a5me^ zHvELV{QaEMx*sgdAPwHcA_?3o&e*1Xf4Lr)?y^-4n*vq^^X=;Pfcq9iL6$HMH^Rhj zm7;fkLsR-XV3*OSpXZe%fRN>hp#uUtCMY3ZnSW%n`R6a%lh{Qgc-ZZ;@&rPF1e#L^)Guz;3fR?XTD1V`H-Ubn2i?bpCUmjW|P?U;Pet81F3O z7poiWUnhUx_m@*NeTJ=+cHJ&))#`=`LvI*%zrYPxgg_I9BV$WSB1w$2uVl$ctRTF) zb!?6{YfS9cS-mc6LOw~68dAU(RW5?%l&yT{r>?F;<=0B#tYgNQAvtM7ujc#qK)2X{ k8Q_zlV~66YpVp$k?Q4(H~2U9KidfRpRo%70PdXu!~g&Q delta 1004 zcmVXRx zcQeFF{O?=E#l~E$!Ui`Ueut>rU!YIBoRF@O`0Dplg#vKLwCG-^`b1J_297mIz zT(c#cxm_GR8qBqL0GS)7mGp$Yn$2eJqK~gS*fH!GB$)Ald%x5MT`ECaAbbVfz&Zi? za_kCV4+X4D9u6M%q3lgr>MpE2ZwjW6>Rx-HRBMjKt``Ps)UH*HD#zO$10GK!v$DtI zr>Ovgr+;al3UZjbb_R>{@gByg%YW1IH<<$7GY%cL5V0#*g{?TYY#`xZn&mT(_#go&LhMfd!Mru22d zE~8IB&nrm)A|x&)z!W z1DIIi8SPIWH`jJ6LJT|rg;6?FZNHHzmeM@G-eq9pM&vV=loOGsq_%deEiHf4|2g}2 z^MCOJvOtM665+1Y+FG0UXZ3tQrwVC0~R6BjAi4di0b5kL2$oa6@~oe_x(=0JD}}R;8Doa*qz%2A@7n|2Vgr&3i43KqJ{L}+ aeW() * 60; - if (interval < 0) { + int32_t interval = cfgobj["interval"].as() * 60; + if (interval == -1440 * 60) { + interval = util::getMidnightTime() - now; + } else if (interval < 0) { interval = -interval; unsigned int secondsUntilNext = (interval - (now % interval)) % interval; interval = secondsUntilNext; @@ -341,8 +342,8 @@ void drawNew(const uint8_t mac[8], tagRecord *&taginfo) { case 8: // Forecast drawForecast(filename, cfgobj, taginfo, imageParams); - taginfo->nextupdate = now + 3600; - updateTagImage(filename, mac, 15, taginfo, imageParams); + taginfo->nextupdate = now + interval; + updateTagImage(filename, mac, interval / 60, taginfo, imageParams); break; case 5: // Firmware @@ -1513,15 +1514,17 @@ bool getDayAheadFeed(String &filename, JsonObject &cfgobj, tagRecord *&taginfo, int n = doc.size(); + int units = cfgobj["units"].as(); + if (units == 0) units = 1; double tarifkwh = cfgobj["tariffkwh"].as(); double tariftax = cfgobj["tarifftax"].as(); - double minPrice = (doc[0]["price"].as() / 10 + tarifkwh) * (1 + tariftax / 100); + double minPrice = (doc[0]["price"].as() / 10 + tarifkwh) * (1 + tariftax / 100) / units; double maxPrice = minPrice; double prices[n]; for (int i = 0; i < n; i++) { const JsonObject &obj = doc[i]; - const double price = (obj["price"].as() / 10 + tarifkwh) * (1 + tariftax / 100); + const double price = (obj["price"].as() / 10 + tarifkwh) * (1 + tariftax / 100) / units; minPrice = min(minPrice, price); maxPrice = max(maxPrice, price); prices[i] = price; @@ -1537,7 +1540,7 @@ 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)), yAxisX, y - 8, loc["yaxis"][0], TL_DATUM, TFT_BLACK); + drawString(spr, String(int(i * units)), yAxisX, y - 8, loc["yaxis"][0], TL_DATUM, TFT_BLACK); } uint16_t barwidth = loc["bars"][1].as() / n; @@ -1552,7 +1555,7 @@ bool getDayAheadFeed(String &filename, JsonObject &cfgobj, tagRecord *&taginfo, struct tm item_timeinfo; localtime_r(&item_time, &item_timeinfo); - const double price = (obj["price"].as() / 10 + tarifkwh) * (1 + tariftax / 100); + const double price = (obj["price"].as() / 10 + tarifkwh) * (1 + tariftax / 100) / units; uint16_t barcolor = getPercentileColor(prices, n, price); uint16_t thisbarh = mapDouble(price, minPrice, maxPrice, 0, loc["bars"][2].as()); diff --git a/ESP32_AP-Flasher/src/newproto.cpp b/ESP32_AP-Flasher/src/newproto.cpp index fa6abf02..c236dc66 100644 --- a/ESP32_AP-Flasher/src/newproto.cpp +++ b/ESP32_AP-Flasher/src/newproto.cpp @@ -461,6 +461,7 @@ void processXferComplete(struct espXferComplete* xfc, bool local) { clearPending(taginfo); memcpy(taginfo->md5, md5bytes, sizeof(md5bytes)); taginfo->updateCount++; + taginfo->updateLast = now; taginfo->pendingCount = countQueueItem(xfc->src); taginfo->wakeupReason = 0; if (taginfo->contentMode == 12 && local == false) { @@ -568,7 +569,10 @@ void processDataReq(struct espAvailDataReq* eadr, bool local, IPAddress remoteIP if (eadr->adr.lastPacketRSSI != 0) { if (eadr->adr.wakeupReason >= 0xE0) { - if (taginfo->pendingCount == 0) taginfo->nextupdate = 0; + if (taginfo->pendingCount == 0) { + taginfo->nextupdate = 0; + memset(taginfo->md5, 0, sizeof(taginfo->md5)); + } if (local) { const char* reason = ""; @@ -643,6 +647,7 @@ void updateContent(const uint8_t* dst) { tagRecord* taginfo = tagRecord::findByMAC(dst); if (taginfo != nullptr) { clearPending(taginfo); + memset(taginfo->md5, 0, sizeof(taginfo->md5)); taginfo->nextupdate = 0; wsSendTaginfo(taginfo->mac, SYNC_TAGSTATUS); } diff --git a/ESP32_AP-Flasher/src/ota.cpp b/ESP32_AP-Flasher/src/ota.cpp index 921958b4..52821fed 100644 --- a/ESP32_AP-Flasher/src/ota.cpp +++ b/ESP32_AP-Flasher/src/ota.cpp @@ -93,34 +93,80 @@ void handleCheckFile(AsyncWebServerRequest* request) { request->send(200, "application/json", jsonResponse); } +#define UPLOAD_BUFFER_SIZE 32768 + +struct UploadInfo { + String filename; + uint8_t buffer[UPLOAD_BUFFER_SIZE]; + size_t bufferSize; +}; + void handleLittleFSUpload(AsyncWebServerRequest* request, String filename, size_t index, uint8_t* data, size_t len, bool final) { + String uploadfilename; bool error = false; if (!index) { String path; if (!request->hasParam("path", true)) { - path = "/temp/null.bin"; final = true; error = true; } else { - path = request->getParam("path", true)->value(); - Serial.println("update " + path); - xSemaphoreTake(fsMutex, portMAX_DELAY); - request->_tempFile = contentFS->open(path, "w", true); + uploadfilename = request->getParam("path", true)->value(); + Serial.println("update " + uploadfilename); + File file = contentFS->open(uploadfilename, "w"); + file.close(); + UploadInfo* uploadInfo = new UploadInfo{uploadfilename, {}, 0}; + request->_tempObject = (void*)uploadInfo; } } - if (len) { - if (!request->_tempFile.write(data, len)) { - error = true; - final = true; + + UploadInfo* uploadInfo = static_cast(request->_tempObject); + + if (uploadInfo != nullptr) { + uploadfilename = uploadInfo->filename; + + if (len) { + if (uploadInfo->bufferSize + len <= UPLOAD_BUFFER_SIZE) { + memcpy(&uploadInfo->buffer[uploadInfo->bufferSize], data, len); + uploadInfo->bufferSize += len; + } else { + xSemaphoreTake(fsMutex, portMAX_DELAY); + File file = contentFS->open(uploadfilename, "a"); + if (file) { + file.write(uploadInfo->buffer, uploadInfo->bufferSize); + file.close(); + uploadInfo->bufferSize = 0; + } else { + logLine("Failed to open file for appending: " + uploadfilename); + final = true; + error = true; + } + xSemaphoreGive(fsMutex); + + memcpy(uploadInfo->buffer, data, len); + uploadInfo->bufferSize = len; + } } - } - if (final) { - request->_tempFile.close(); - xSemaphoreGive(fsMutex); - if (error) { - request->send(507, "text/plain", "Error. Disk full?"); - } else { - request->send(200, "text/plain", "Ok, file written"); + if (final) { + if (uploadInfo->bufferSize > 0) { + xSemaphoreTake(fsMutex, portMAX_DELAY); + File file = contentFS->open(uploadfilename, "a"); + if (file) { + file.write(uploadInfo->buffer, uploadInfo->bufferSize); + file.close(); + } else { + logLine("Failed to open file for appending: " + uploadfilename); + error = true; + } + xSemaphoreGive(fsMutex); + request->_tempObject = nullptr; + delete uploadInfo; + } + + if (error) { + request->send(507, "text/plain", "Error. Disk full?"); + } else { + request->send(200, "text/plain", "Ok, file written"); + } } } } diff --git a/ESP32_AP-Flasher/src/tag_db.cpp b/ESP32_AP-Flasher/src/tag_db.cpp index fc785106..0b909e1b 100644 --- a/ESP32_AP-Flasher/src/tag_db.cpp +++ b/ESP32_AP-Flasher/src/tag_db.cpp @@ -120,6 +120,7 @@ void fillNode(JsonObject& tag, const tagRecord* taginfo) { tag["lut"] = taginfo->lut; tag["invert"] = taginfo->invert; tag["updatecount"] = taginfo->updateCount; + tag["updatelast"] = taginfo->updateLast; tag["ch"] = taginfo->currentChannel; tag["ver"] = taginfo->tagSoftwareVersion; } @@ -228,6 +229,7 @@ bool loadDB(const String& filename) { taginfo->lut = tag["lut"] | 0; taginfo->invert = tag["invert"] | 0; taginfo->updateCount = tag["updatecount"] | 0; + taginfo->updateLast = tag["updatelast"] | 0; taginfo->currentChannel = tag["ch"] | 0; taginfo->tagSoftwareVersion = tag["ver"] | 0; } diff --git a/ESP32_AP-Flasher/src/web.cpp b/ESP32_AP-Flasher/src/web.cpp index 809319dc..09dbde34 100644 --- a/ESP32_AP-Flasher/src/web.cpp +++ b/ESP32_AP-Flasher/src/web.cpp @@ -651,6 +651,7 @@ void init_web() { for (size_t i = 0; i < numKeys; i++) { doc[keys[i]] = preferences.getString(keys[i], ""); } + doc["mac"] = WiFi.macAddress(); serializeJson(doc, *response); request->send(response); }); diff --git a/ESP32_AP-Flasher/wwwroot/content_cards.json b/ESP32_AP-Flasher/wwwroot/content_cards.json index 2fd95154..51d80263 100644 --- a/ESP32_AP-Flasher/wwwroot/content_cards.json +++ b/ESP32_AP-Flasher/wwwroot/content_cards.json @@ -146,6 +146,17 @@ "1": "Fahrenheit / mph / millimeters" } }, + { + "key": "interval", + "name": "Interval", + "desc": "How often the forecast is being refreshed.", + "type": "select", + "options": { + "60": "Every hour", + "180": "-Every three hours", + "-1440": "At midnight" + } + }, { "key": "#lat", "name": "Lat", @@ -380,7 +391,7 @@ { "key": "tariffkwh", "name": "Fixed surcharge", - "desc": "Fixed surcharge per kWh, in 1/100 units (cents)", + "desc": "Fixed surcharge per kWh, in 1/100 units (cents/öre/øre)", "type": "text" }, { @@ -388,7 +399,17 @@ "name": "Tax percentage", "desc": "Percentage to add to the total (for example, 21, for 21% VAT)", "type": "text" - } + }, + { + "key": "units", + "name": "Price units", + "desc": "Display whole units (EUR/NOK/DKK) or cents", + "type": "select", + "options": { + "100": "1/1 units (EUR/NOK/DKK)", + "1": "1/100 units (cents/öre/øre)" + } + } ] }, { diff --git a/ESP32_AP-Flasher/wwwroot/setup.html b/ESP32_AP-Flasher/wwwroot/setup.html index 1e0f6eff..15d4becb 100644 --- a/ESP32_AP-Flasher/wwwroot/setup.html +++ b/ESP32_AP-Flasher/wwwroot/setup.html @@ -9,6 +9,12 @@