diff --git a/ESP32_AP-Flasher/data/www/content_cards.json b/ESP32_AP-Flasher/data/www/content_cards.json index 8c331864..b4969ad9 100644 --- a/ESP32_AP-Flasher/data/www/content_cards.json +++ b/ESP32_AP-Flasher/data/www/content_cards.json @@ -263,6 +263,31 @@ } ] }, + { + "id": 19, + "name": "Template URL", + "desc": "Gets an external json template and displays it", + "hwtype": [ + 0, + 1, + 2, + 17 + ], + "param": [ + { + "key": "url", + "name": "URL", + "desc": "Full URL of the json template. See OpenEpaperLink wiki for the right json format", + "type": "text" + }, + { + "key": "interval", + "name": "Interval", + "desc": "How often (in minutes) the template is being fetched", + "type": "int" + } + ] + }, { "id": 10, "name": "QR code", diff --git a/ESP32_AP-Flasher/include/contentmanager.h b/ESP32_AP-Flasher/include/contentmanager.h index ad1f7883..72687c8f 100644 --- a/ESP32_AP-Flasher/include/contentmanager.h +++ b/ESP32_AP-Flasher/include/contentmanager.h @@ -30,6 +30,10 @@ bool getRssFeed(String &filename, String URL, String title, tagRecord *&taginfo, bool getCalFeed(String &filename, String URL, String title, tagRecord *&taginfo, imgParam &imageParams); void drawQR(String &filename, String qrcontent, String title, tagRecord *&taginfo, imgParam &imageParams); void drawBuienradar(String &filename, JsonObject &cfgobj, tagRecord *&taginfo, imgParam &imageParams); +int getJsonTemplate(String URL, JsonDocument &jsondoc, time_t fetched, String MAC); +void drawJsonTemplate(JsonDocument &doc, String filename, tagRecord *&taginfo, imgParam &imageParams); +void drawElement(const JsonObject &element, TFT_eSprite &spr); +uint16_t getColor(uint8_t color); char *formatHttpDate(time_t t); String urlEncode(const char *msg); int windSpeedToBeaufort(float windSpeed); diff --git a/ESP32_AP-Flasher/src/contentmanager.cpp b/ESP32_AP-Flasher/src/contentmanager.cpp index cad5f669..30c472d7 100644 --- a/ESP32_AP-Flasher/src/contentmanager.cpp +++ b/ESP32_AP-Flasher/src/contentmanager.cpp @@ -4,6 +4,7 @@ #define CONTENT_QR #define CONTENT_RSS #define CONTENT_CAL +#define CONTENT_BUIENRADAR #include #include @@ -300,6 +301,23 @@ void drawNew(uint8_t mac[8], bool buttonPressed, tagRecord *&taginfo) { taginfo->nextupdate = 3216153600; taginfo->contentMode = Image; break; + + case 19: // json template + { + DynamicJsonDocument doc(2000); + int httpcode = getJsonTemplate(cfgobj["url"], doc, (time_t)cfgobj["#fetched"], String(hexmac)); + if (httpcode == 200) { + taginfo->nextupdate = now + 60 * (cfgobj["interval"].as() < 3 ? 15 : cfgobj["interval"].as()); + drawJsonTemplate(doc, filename, taginfo, imageParams); + updateTagImage(filename, mac, cfgobj["interval"].as(), taginfo, imageParams); + cfgobj["#fetched"] = now; + } else if (httpcode == 304) { + taginfo->nextupdate = now + 60 * (cfgobj["interval"].as() < 3 ? 15 : cfgobj["interval"].as()); + } else { + taginfo->nextupdate = now + 300; + } + break; + } } taginfo->modeConfigJson = doc.as(); @@ -836,6 +854,7 @@ void drawQR(String &filename, String qrcontent, String title, tagRecord *&taginf } void drawBuienradar(String &filename, JsonObject &cfgobj, tagRecord *&taginfo, imgParam &imageParams) { +#ifdef CONTENT_BUIENRADAR wsLog("get weather"); getLocation(cfgobj); @@ -902,6 +921,78 @@ void drawBuienradar(String &filename, JsonObject &cfgobj, tagRecord *&taginfo, i spr.deleteSprite(); } http.end(); +#endif +} + +int getJsonTemplate(String URL, JsonDocument &jsondoc, time_t fetched, String MAC) { + Serial.println("get external " + URL); + HTTPClient http; + http.begin(URL); + http.addHeader("If-Modified-Since", formatHttpDate(fetched)); + http.addHeader("X-ESL-MAC", MAC); + http.setTimeout(5000); + int httpCode = http.GET(); + if (httpCode == 200) { + DeserializationError error = deserializeJson(jsondoc, http.getStream()); + if (error) { + wsErr("json error in getJsonTemplate:"); + wsErr(error.c_str()); + return 0; + } + } else { + if (httpCode != 304) { + wsErr("http " + URL + " " + String(httpCode)); + } else { + Serial.println("http 304, image is not changed " + URL); + } + } + http.end(); + return httpCode; +} + +void drawJsonTemplate(JsonDocument &doc, String filename, tagRecord *&taginfo, imgParam &imageParams) { + TFT_eSPI tft = TFT_eSPI(); + TFT_eSprite spr = TFT_eSprite(&tft); + initSprite(spr, hwdata[taginfo->hwType].width, hwdata[taginfo->hwType].height, imageParams); + + for (const JsonVariant& element : doc.as()) { + drawElement(element.as(), spr); + } + spr2buffer(spr, filename, imageParams); + spr.deleteSprite(); +} + +void drawElement(const JsonObject &element, TFT_eSprite &spr) { + if (element.containsKey("text")) { + const JsonArray &textArray = element["text"]; + uint16_t color = textArray[4] | 1; + uint16_t align = textArray[5] | 0; + drawString(spr, textArray[2], textArray[0].as(), textArray[1].as(), textArray[3], align, getColor(color)); + } else if (element.containsKey("box")) { + const JsonArray &boxArray = element["box"]; + uint16_t color = boxArray[4] | 1; + spr.fillRect(boxArray[0].as(), boxArray[1].as(), boxArray[2].as(), boxArray[3].as(), getColor(color)); + } else if (element.containsKey("line")) { + const JsonArray &lineArray = element["line"]; + uint16_t color = lineArray[4] | 1; + spr.drawLine(lineArray[0].as(), lineArray[1].as(), lineArray[2].as(), lineArray[3].as(), getColor(color)); + } else if (element.containsKey("triangle")) { + const JsonArray &lineArray = element["triangle"]; + uint16_t color = lineArray[6] | 1; + spr.fillTriangle(lineArray[0].as(), lineArray[1].as(), lineArray[2].as(), lineArray[3].as(), lineArray[4].as(), lineArray[5].as(), getColor(color)); + } +} + +uint16_t getColor(uint8_t color) { + switch (color) { + case 0: + return PAL_WHITE; + case 1: + return PAL_BLACK; + case 2: + return PAL_RED; + } + return PAL_WHITE; } char *formatHttpDate(time_t t) {