mirror of
https://github.com/OpenEPaperLink/OpenEPaperLink.git
synced 2026-03-21 06:06:23 +01:00
rework of apinfo screen + variables in jsontemplate
- AP info screen content card. Can run on any tag.
- now, you can use {variables} in the 'text' entries in a json template. You can set variables via a http call. If you update a variable, all tags with a json template containing that variable get updated.
- font name in json template is more flexible. You can just use 'filename.ttf' or 'filename.vlw'. A full path is still possible.
- colors in the json template can now be set using #rrggbb color values, and using 'black', 'white' or 'red'.
- added direct output for the TFT display for the yellow esp32-s3. No file writes needed.
- added POST variable 'ttl' to json template upload and image upload, to set the next checkin time
- added /variables-demo.html to demonstrate the variables.
- json templates received from jsonupload are now saved in /current, and reused.
- known issue: 'backup db' button doesn't work due to some browser policy change. Fixing.
thanks to @steinwedel for the inspiration on the variables and some other fixes.
This commit is contained in:
@@ -33,6 +33,16 @@
|
||||
"10": {
|
||||
"title": [ 10, 15, "t0_14b_tf" ],
|
||||
"pos": [ 76, 20 ]
|
||||
}
|
||||
},
|
||||
"21": [
|
||||
{ "text": [ 2, 5, "OpenEpaperLink", "bahnschrift20", 1, 0, 0 ] },
|
||||
{ "text": [ 2, 25, "Access Point", "bahnschrift20", 1, 0, 0 ] },
|
||||
{ "text": [ 3, 65, "IP address:", "glasstown_nbp_tf", 1, 0, 0 ] },
|
||||
{ "text": [ 10, 80, "{ap_ip}", "t0_14b_tf", 1, 0, 0 ] },
|
||||
{ "text": [ 3, 95, "Channel:", "glasstown_nbp_tf", 1, 0, 0 ] },
|
||||
{ "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 ] }
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,6 +59,15 @@
|
||||
"items": 7,
|
||||
"red": [0, 21, 296, 14],
|
||||
"line": [5, 32, 15, "t0_14b_tf", 50]
|
||||
}
|
||||
},
|
||||
"21": [
|
||||
{ "text": [ 5, 5, "OpenEpaperLink AP", "bahnschrift20", 1, 0, 0 ] },
|
||||
{ "text": [ 5, 50, "IP address:", "t0_14b_tf", 1, 0, 0 ] },
|
||||
{ "text": [ 120, 50, "{ap_ip}", "t0_14b_tf", 1, 0, 0 ] },
|
||||
{ "text": [ 5, 70, "Channel:", "t0_14b_tf", 1, 0, 0 ] },
|
||||
{ "text": [ 120, 70, "{ap_ch}", "t0_14b_tf", 1, 0, 0 ] },
|
||||
{ "text": [ 5, 90, "Tag count:", "t0_14b_tf", 1, 0, 0 ] },
|
||||
{ "text": [ 120, 90, "{ap_tagcount}", "t0_14b_tf", 1, 0, 0 ] }
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,18 @@
|
||||
"gray": [ 150, 150, 150 ]
|
||||
},
|
||||
"capabilities": [ ],
|
||||
"contentids": [ 0, 1, 2, 3, 4, 8, 16, 9, 7, 19, 10, 11 ],
|
||||
"usetemplate": 1
|
||||
"contentids": [ 0, 1, 2, 3, 4, 8, 16, 9, 7, 19, 10, 11, 21 ],
|
||||
"usetemplate": 1,
|
||||
"template": {
|
||||
"21": [
|
||||
{ "box": [ 0, 0, 320, 170, 1 ] },
|
||||
{ "text": [ 5, 5, "OpenEpaperLink AP", "calibrib30", 2, 0, 0, 1 ] },
|
||||
{ "text": [ 5, 60, "IP address:", "bahnschrift20", "#888888", 0, 0, 1 ] },
|
||||
{ "text": [ 120, 60, "{ap_ip}", "bahnschrift20", 0, 0, 0, 1 ] },
|
||||
{ "text": [ 5, 85, "Channel:", "bahnschrift20", "#888888", 0, 0, 1 ] },
|
||||
{ "text": [ 120, 85, "{ap_ch}", "bahnschrift20", 0, 0, 0, "1" ] },
|
||||
{ "text": [ 5, 110, "Tag count:", "bahnschrift20", "#888888", 0, 0, 1 ] },
|
||||
{ "text": [ 120, 110, "{ap_tagcount}", "bahnschrift20", 0, 0, 0, "1" ] }
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,25 +16,26 @@ struct contentTypes {
|
||||
};
|
||||
|
||||
void contentRunner();
|
||||
void checkVars();
|
||||
void drawNew(uint8_t mac[8], bool buttonPressed, tagRecord *&taginfo);
|
||||
bool updateTagImage(String &filename, uint8_t *dst, uint16_t nextCheckin, tagRecord *&taginfo, imgParam &imageParams);
|
||||
void drawString(TFT_eSprite &spr, String content, int16_t posx, int16_t posy, String font, byte align = 0, uint16_t color = TFT_BLACK, uint16_t size = 0);
|
||||
void drawString(TFT_eSprite &spr, String content, int16_t posx, int16_t posy, String font, byte align = 0, uint16_t color = TFT_BLACK, uint16_t size = 30, uint16_t bgcolor = TFT_WHITE);
|
||||
void initSprite(TFT_eSprite &spr, int w, int h, imgParam &imageParams);
|
||||
void drawDate(String &filename, tagRecord *&taginfo, imgParam &imageParams);
|
||||
void drawNumber(String &filename, int32_t count, int32_t thresholdred, tagRecord *&taginfo, imgParam &imageParams);
|
||||
void drawWeather(String &filename, JsonObject &cfgobj, tagRecord *&taginfo, imgParam &imageParams);
|
||||
void drawForecast(String &filename, JsonObject &cfgobj, tagRecord *&taginfo, imgParam &imageParams);
|
||||
void drawIdentify(String &filename, tagRecord *&taginfo, imgParam &imageParams);
|
||||
int getImgURL(String &filename, String URL, time_t fetched, imgParam &imageParams, String MAC);
|
||||
bool getRssFeed(String &filename, String URL, String title, tagRecord *&taginfo, imgParam &imageParams);
|
||||
bool getCalFeed(String &filename, String URL, String title, tagRecord *&taginfo, imgParam &imageParams);
|
||||
void drawQR(String &filename, String qrcontent, String title, tagRecord *&taginfo, imgParam &imageParams);
|
||||
uint8_t drawBuienradar(String &filename, JsonObject &cfgobj, tagRecord *&taginfo, imgParam &imageParams);
|
||||
void drawAPinfo(String &filename, JsonObject &cfgobj, tagRecord *&taginfo, imgParam &imageParams);
|
||||
int getJsonTemplateFile(String &filename, String jsonfile, tagRecord *&taginfo, imgParam &imageParams);
|
||||
int getJsonTemplateUrl(String &filename, String URL, time_t fetched, String MAC, tagRecord *&taginfo, imgParam &imageParams);
|
||||
void drawJsonStream(Stream &stream, String &filename, tagRecord *&taginfo, imgParam &imageParams);
|
||||
void drawElement(const JsonObject &element, TFT_eSprite &spr);
|
||||
uint16_t getColor(uint8_t color);
|
||||
uint16_t getColor(String color);
|
||||
char *formatHttpDate(time_t t);
|
||||
String urlEncode(const char *msg);
|
||||
int windSpeedToBeaufort(float windSpeed);
|
||||
@@ -45,4 +46,3 @@ void prepareLUTreq(uint8_t *dst, String input);
|
||||
void prepareConfigFile(uint8_t *dst, JsonObject config);
|
||||
void getTemplate(JsonDocument &json, uint8_t id, uint8_t hwtype);
|
||||
void setU8G2Font(const String &title, U8g2_for_TFT_eSPI &u8f);
|
||||
void showIpAddress(String dst);
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
extern TFT_eSPI tft;
|
||||
|
||||
struct imgParam {
|
||||
bool hasRed;
|
||||
uint8_t dataType;
|
||||
|
||||
@@ -76,10 +76,16 @@ struct HwType {
|
||||
uint8_t bpp;
|
||||
};
|
||||
|
||||
struct varStruct {
|
||||
String value;
|
||||
bool changed;
|
||||
};
|
||||
|
||||
// extern SemaphoreHandle_t tagDBOwner;
|
||||
extern Config config;
|
||||
extern std::vector<tagRecord*> tagDB;
|
||||
extern std::unordered_map<int, HwType> hwtype;
|
||||
extern std::unordered_map<std::string, varStruct> varDB;
|
||||
extern DynamicJsonDocument APconfig;
|
||||
String tagDBtoJson(uint8_t mac[8] = nullptr, uint8_t startPos = 0);
|
||||
bool deleteRecord(uint8_t mac[8]);
|
||||
@@ -88,11 +94,13 @@ void saveDB(String filename);
|
||||
void loadDB(String filename);
|
||||
void destroyDB();
|
||||
uint32_t getTagCount();
|
||||
uint32_t getTagCount(uint32_t& timeoutcount);
|
||||
void mac2hex(uint8_t* mac, char* hexBuffer);
|
||||
bool hex2mac(const String& hexString, uint8_t* mac);
|
||||
void clearPending(tagRecord* taginfo);
|
||||
void initAPconfig();
|
||||
void saveAPconfig();
|
||||
HwType getHwType(uint8_t id);
|
||||
bool setVarDB(const std::string& key, const String& value);
|
||||
|
||||
#pragma pack(pop)
|
||||
#pragma pack(pop)
|
||||
|
||||
@@ -35,10 +35,6 @@
|
||||
#include "truetype.h"
|
||||
#include "web.h"
|
||||
|
||||
#define PAL_BLACK TFT_BLACK
|
||||
#define PAL_WHITE TFT_WHITE
|
||||
#define PAL_RED TFT_RED
|
||||
|
||||
// https://csvjson.com/json_beautifier
|
||||
|
||||
void contentRunner() {
|
||||
@@ -47,8 +43,7 @@ void contentRunner() {
|
||||
time_t now;
|
||||
time(&now);
|
||||
|
||||
// xSemaphoreTake(tagDBOwner, portMAX_DELAY);
|
||||
for (int16_t c = 0; c < tagDB.size(); c++) {
|
||||
for (int32_t c = 0; c < tagDB.size(); c++) {
|
||||
tagRecord *taginfo = nullptr;
|
||||
taginfo = tagDB.at(c);
|
||||
|
||||
@@ -69,7 +64,40 @@ void contentRunner() {
|
||||
|
||||
vTaskDelay(1 / portTICK_PERIOD_MS); // add a small delay to allow other threads to run
|
||||
}
|
||||
// xSemaphoreGive(tagDBOwner);
|
||||
}
|
||||
|
||||
void checkVars() {
|
||||
DynamicJsonDocument doc(500);
|
||||
for (int32_t c = 0; c < tagDB.size(); c++) {
|
||||
tagRecord *tag = nullptr;
|
||||
tag = tagDB.at(c);
|
||||
if (tag->contentMode == 19) {
|
||||
deserializeJson(doc, tag->modeConfigJson);
|
||||
JsonObject cfgobj = doc.as<JsonObject>();
|
||||
if (cfgobj["filename"]) {
|
||||
String jsonfile = cfgobj["filename"].as<String>();
|
||||
File file = contentFS->open(jsonfile, "r");
|
||||
if (file) {
|
||||
size_t fileSize = file.size();
|
||||
std::unique_ptr<char[]> fileContent(new char[fileSize + 1]);
|
||||
file.readBytes(fileContent.get(), fileSize);
|
||||
file.close();
|
||||
fileContent[fileSize] = '\0';
|
||||
char *contentPtr = fileContent.get();
|
||||
for (const auto &entry : varDB) {
|
||||
if (entry.second.changed && strstr(contentPtr, entry.first.c_str()) != nullptr) {
|
||||
Serial.println("updating " + jsonfile + " because of var " + entry.first.c_str());
|
||||
tag->nextupdate = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const auto &entry : varDB) {
|
||||
if (entry.second.changed) varDB[entry.first].changed = false;
|
||||
}
|
||||
}
|
||||
|
||||
void drawNew(uint8_t mac[8], bool buttonPressed, tagRecord *&taginfo) {
|
||||
@@ -83,9 +111,21 @@ void drawNew(uint8_t mac[8], bool buttonPressed, tagRecord *&taginfo) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t wifimac[8];
|
||||
WiFi.macAddress(wifimac);
|
||||
memset(&wifimac[6], 0, 2);
|
||||
|
||||
if ((taginfo->wakeupReason == WAKEUP_REASON_FIRSTBOOT || taginfo->wakeupReason == WAKEUP_REASON_WDT_RESET) && taginfo->contentMode == 0 && memcmp(mac, wifimac, 8) == 0) {
|
||||
taginfo->contentMode = 21;
|
||||
taginfo->nextupdate = 0;
|
||||
}
|
||||
|
||||
char hexmac[17];
|
||||
mac2hex(mac, hexmac);
|
||||
String filename = "/" + String(hexmac) + ".raw";
|
||||
#ifdef YELLOW_IPS_AP
|
||||
if (memcmp(mac, wifimac, 8) == 0) filename = "direct";
|
||||
#endif
|
||||
|
||||
struct tm time_info;
|
||||
getLocalTime(&time_info);
|
||||
@@ -291,7 +331,7 @@ void drawNew(uint8_t mac[8], bool buttonPressed, tagRecord *&taginfo) {
|
||||
if (cfgobj["filename"]) {
|
||||
int result = getJsonTemplateFile(filename, cfgobj["filename"], taginfo, imageParams);
|
||||
if (result) {
|
||||
updateTagImage(filename, mac, 0, taginfo, imageParams);
|
||||
updateTagImage(filename, mac, cfgobj["interval"].as<int>(), taginfo, imageParams);
|
||||
} else {
|
||||
wsErr("error opening file " + cfgobj["filename"].as<String>());
|
||||
}
|
||||
@@ -310,6 +350,22 @@ void drawNew(uint8_t mac[8], bool buttonPressed, tagRecord *&taginfo) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 20: // display a copy
|
||||
break;
|
||||
|
||||
case 21: // ap info
|
||||
drawAPinfo(filename, cfgobj, taginfo, imageParams);
|
||||
/*
|
||||
if (imageParams.bpp == 16) {
|
||||
taginfo->nextupdate = now + 60;
|
||||
} else {
|
||||
taginfo->nextupdate = now + 600;
|
||||
}
|
||||
*/
|
||||
taginfo->nextupdate = 3216153600;
|
||||
updateTagImage(filename, mac, 0, taginfo, imageParams);
|
||||
break;
|
||||
}
|
||||
|
||||
taginfo->modeConfigJson = doc.as<String>();
|
||||
@@ -325,63 +381,94 @@ bool updateTagImage(String &filename, uint8_t *dst, uint16_t nextCheckin, tagRec
|
||||
return true;
|
||||
}
|
||||
|
||||
void drawString(TFT_eSprite &spr, String content, int16_t posx, int16_t posy, String font, byte align, uint16_t color, uint16_t size) {
|
||||
// drawString(spr,"test",100,10,"bahnschrift30",TC_DATUM,PAL_RED);
|
||||
if (font != "" && font != "null" && !font.startsWith("fonts/") && !font.startsWith("/fonts/")) {
|
||||
// u8g2 font
|
||||
U8g2_for_TFT_eSPI u8f;
|
||||
u8f.begin(spr);
|
||||
setU8G2Font(font, u8f);
|
||||
u8f.setForegroundColor(color);
|
||||
u8f.setBackgroundColor(PAL_WHITE);
|
||||
if (align == TC_DATUM) {
|
||||
posx -= u8f.getUTF8Width(content.c_str()) / 2;
|
||||
}
|
||||
if (align == TR_DATUM) {
|
||||
posx -= u8f.getUTF8Width(content.c_str());
|
||||
}
|
||||
u8f.setCursor(posx, posy);
|
||||
u8f.print(content);
|
||||
uint8_t processFontPath(String &font) {
|
||||
if (font == "") return 3;
|
||||
if (font == "glasstown_nbp_tf") return 1;
|
||||
if (font == "7x14_tf") return 1;
|
||||
if (font == "t0_14b_tf") return 1;
|
||||
if (font.indexOf('/') == -1) font = "/fonts/" + font;
|
||||
if (!font.startsWith("/")) font = "/" + font;
|
||||
if (font.endsWith(".vlw")) font = font.substring(0, font.length() - 4);
|
||||
if (font.endsWith(".ttf")) return 2;
|
||||
return 3;
|
||||
}
|
||||
|
||||
} else if (size > 0) {
|
||||
// truetype
|
||||
time_t t = millis();
|
||||
truetypeClass truetype = truetypeClass();
|
||||
void *framebuffer = spr.getPointer();
|
||||
truetype.setFramebuffer(spr.width(), spr.height(), spr.getColorDepth(), static_cast<uint8_t *>(framebuffer));
|
||||
File fontFile = contentFS->open(font, "r");
|
||||
if (!truetype.setTtfFile(fontFile)) {
|
||||
Serial.println("read ttf failed");
|
||||
return;
|
||||
}
|
||||
void replaceVariables(String &format) {
|
||||
size_t startIndex = 0;
|
||||
size_t openBraceIndex, closeBraceIndex;
|
||||
|
||||
truetype.setCharacterSize(size);
|
||||
truetype.setCharacterSpacing(0);
|
||||
if (align == TC_DATUM) {
|
||||
posx -= truetype.getStringWidth(content) / 2;
|
||||
while ((openBraceIndex = format.indexOf('{', startIndex)) != -1 &&
|
||||
(closeBraceIndex = format.indexOf('}', openBraceIndex + 1)) != -1) {
|
||||
std::string variableName = format.substring(openBraceIndex + 1, closeBraceIndex).c_str();
|
||||
std::string varKey = "{" + variableName + "}";
|
||||
if (varDB.count(variableName) > 0) {
|
||||
format.replace(varKey.c_str(), varDB.at(variableName).value);
|
||||
}
|
||||
if (align == TR_DATUM) {
|
||||
posx -= truetype.getStringWidth(content);
|
||||
}
|
||||
truetype.setTextBoundary(posx, spr.width(), spr.height());
|
||||
truetype.setTextColor(spr.color16to8(color), spr.color16to8(color));
|
||||
truetype.textDraw(posx, posy, content);
|
||||
truetype.end();
|
||||
// Serial.println("text: '" + content + "' " + String(millis() - t) + "ms");
|
||||
startIndex = closeBraceIndex + 1;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
// vlw bitmap font
|
||||
spr.setTextDatum(align);
|
||||
if (font != "") spr.loadFont(font, *contentFS);
|
||||
spr.setTextColor(color, PAL_WHITE);
|
||||
spr.drawString(content, posx, posy);
|
||||
if (font != "") spr.unloadFont();
|
||||
void drawString(TFT_eSprite &spr, String content, int16_t posx, int16_t posy, String font, byte align, uint16_t color, uint16_t size, uint16_t bgcolor) {
|
||||
// drawString(spr,"test",100,10,"bahnschrift30",TC_DATUM,TFT_RED);
|
||||
replaceVariables(content);
|
||||
switch (processFontPath(font)) {
|
||||
case 1: {
|
||||
// u8g2 font
|
||||
U8g2_for_TFT_eSPI u8f;
|
||||
u8f.begin(spr);
|
||||
setU8G2Font(font, u8f);
|
||||
u8f.setForegroundColor(color);
|
||||
u8f.setBackgroundColor(bgcolor);
|
||||
if (align == TC_DATUM) {
|
||||
posx -= u8f.getUTF8Width(content.c_str()) / 2;
|
||||
}
|
||||
if (align == TR_DATUM) {
|
||||
posx -= u8f.getUTF8Width(content.c_str());
|
||||
}
|
||||
u8f.setCursor(posx, posy);
|
||||
u8f.print(content);
|
||||
} break;
|
||||
case 2: {
|
||||
// truetype
|
||||
time_t t = millis();
|
||||
truetypeClass truetype = truetypeClass();
|
||||
void *framebuffer = spr.getPointer();
|
||||
truetype.setFramebuffer(spr.width(), spr.height(), spr.getColorDepth(), static_cast<uint8_t *>(framebuffer));
|
||||
File fontFile = contentFS->open(font, "r");
|
||||
if (!truetype.setTtfFile(fontFile)) {
|
||||
Serial.println("read ttf failed");
|
||||
return;
|
||||
}
|
||||
|
||||
truetype.setCharacterSize(size);
|
||||
truetype.setCharacterSpacing(0);
|
||||
if (align == TC_DATUM) {
|
||||
posx -= truetype.getStringWidth(content) / 2;
|
||||
}
|
||||
if (align == TR_DATUM) {
|
||||
posx -= truetype.getStringWidth(content);
|
||||
}
|
||||
truetype.setTextBoundary(posx, spr.width(), spr.height());
|
||||
truetype.setTextColor(spr.color16to8(color), spr.color16to8(color));
|
||||
truetype.textDraw(posx, posy, content);
|
||||
truetype.end();
|
||||
// Serial.println("text: '" + content + "' " + String(millis() - t) + "ms");
|
||||
} break;
|
||||
case 3: {
|
||||
// vlw bitmap font
|
||||
spr.setTextDatum(align);
|
||||
if (font != "") spr.loadFont(font.substring(1), *contentFS);
|
||||
spr.setTextColor(color, bgcolor);
|
||||
spr.drawString(content, posx, posy);
|
||||
if (font != "") spr.unloadFont();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void initSprite(TFT_eSprite &spr, int w, int h, imgParam &imageParams) {
|
||||
spr.setColorDepth(8);
|
||||
spr.createSprite(w, h);
|
||||
spr.setRotation(3);
|
||||
if (spr.getPointer() == nullptr) {
|
||||
wsErr("low on memory. Fallback to 1bpp");
|
||||
Serial.println("Maximum Continuous Heap Space: " + String(heap_caps_get_largest_free_block(MALLOC_CAP_DEFAULT)));
|
||||
@@ -393,7 +480,7 @@ void initSprite(TFT_eSprite &spr, int w, int h, imgParam &imageParams) {
|
||||
if (spr.getPointer() == nullptr) {
|
||||
wsErr("Failed to create sprite");
|
||||
}
|
||||
spr.fillSprite(PAL_WHITE);
|
||||
spr.fillSprite(TFT_WHITE);
|
||||
}
|
||||
|
||||
void drawDate(String &filename, tagRecord *&taginfo, imgParam &imageParams) {
|
||||
@@ -412,7 +499,6 @@ void drawDate(String &filename, tagRecord *&taginfo, imgParam &imageParams) {
|
||||
return;
|
||||
}
|
||||
|
||||
TFT_eSPI tft = TFT_eSPI();
|
||||
TFT_eSprite spr = TFT_eSprite(&tft);
|
||||
|
||||
StaticJsonDocument<512> loc;
|
||||
@@ -421,12 +507,12 @@ void drawDate(String &filename, tagRecord *&taginfo, imgParam &imageParams) {
|
||||
initSprite(spr, imageParams.width, imageParams.height, imageParams);
|
||||
|
||||
if (loc["date"]) {
|
||||
drawString(spr, languageDays[getCurrentLanguage()][timeinfo.tm_wday], loc["weekday"][0], loc["weekday"][1], loc["weekday"][2], TC_DATUM, PAL_RED);
|
||||
drawString(spr, languageDays[getCurrentLanguage()][timeinfo.tm_wday], loc["weekday"][0], loc["weekday"][1], loc["weekday"][2], TC_DATUM, TFT_RED);
|
||||
drawString(spr, String(timeinfo.tm_mday) + " " + languageMonth[getCurrentLanguage()][timeinfo.tm_mon], loc["date"][0], loc["date"][1], loc["date"][2], TC_DATUM);
|
||||
} else {
|
||||
drawString(spr, languageDays[getCurrentLanguage()][timeinfo.tm_wday], loc["weekday"][0], loc["weekday"][1], loc["weekday"][2], TC_DATUM, PAL_BLACK);
|
||||
drawString(spr, languageDays[getCurrentLanguage()][timeinfo.tm_wday], loc["weekday"][0], loc["weekday"][1], loc["weekday"][2], TC_DATUM, TFT_BLACK);
|
||||
drawString(spr, String(languageMonth[getCurrentLanguage()][timeinfo.tm_mon]), loc["month"][0], loc["month"][1], loc["month"][2], TC_DATUM);
|
||||
drawString(spr, String(timeinfo.tm_mday), loc["day"][0], loc["day"][1], loc["day"][2], TC_DATUM, PAL_RED);
|
||||
drawString(spr, String(timeinfo.tm_mday), loc["day"][0], loc["day"][1], loc["day"][2], TC_DATUM, TFT_RED);
|
||||
}
|
||||
|
||||
spr2buffer(spr, filename, imageParams);
|
||||
@@ -453,7 +539,6 @@ void drawNumber(String &filename, int32_t count, int32_t thresholdred, tagRecord
|
||||
return;
|
||||
}
|
||||
|
||||
TFT_eSPI tft = TFT_eSPI();
|
||||
TFT_eSprite spr = TFT_eSprite(&tft);
|
||||
|
||||
StaticJsonDocument<512> loc;
|
||||
@@ -462,9 +547,9 @@ void drawNumber(String &filename, int32_t count, int32_t thresholdred, tagRecord
|
||||
initSprite(spr, imageParams.width, imageParams.height, imageParams);
|
||||
spr.setTextDatum(MC_DATUM);
|
||||
if (count > thresholdred) {
|
||||
spr.setTextColor(PAL_RED, PAL_WHITE);
|
||||
spr.setTextColor(TFT_RED, TFT_WHITE);
|
||||
} else {
|
||||
spr.setTextColor(PAL_BLACK, PAL_WHITE);
|
||||
spr.setTextColor(TFT_BLACK, TFT_WHITE);
|
||||
}
|
||||
String font = loc["fonts"][0].as<String>();
|
||||
if (count > 99) font = loc["fonts"][1].as<String>();
|
||||
@@ -541,26 +626,25 @@ void drawWeather(String &filename, JsonObject &cfgobj, tagRecord *&taginfo, imgP
|
||||
weatherIcons[2] = "\uf086";
|
||||
}
|
||||
|
||||
TFT_eSPI tft = TFT_eSPI();
|
||||
TFT_eSprite spr = TFT_eSprite(&tft);
|
||||
tft.setTextWrap(false, false);
|
||||
|
||||
initSprite(spr, imageParams.width, imageParams.height, imageParams);
|
||||
drawString(spr, cfgobj["location"], loc["location"][0], loc["location"][1], loc["location"][2]);
|
||||
drawString(spr, String(wind), loc["wind"][0], loc["wind"][1], loc["wind"][2], TR_DATUM, (wind > 4 ? PAL_RED : PAL_BLACK));
|
||||
drawString(spr, String(wind), loc["wind"][0], loc["wind"][1], loc["wind"][2], TR_DATUM, (wind > 4 ? TFT_RED : TFT_BLACK));
|
||||
|
||||
char tmpOutput[5];
|
||||
dtostrf(temperature, 2, 1, tmpOutput);
|
||||
drawString(spr, String(tmpOutput), loc["temp"][0], loc["temp"][1], loc["temp"][2], TL_DATUM, (temperature < 0 ? PAL_RED : PAL_BLACK));
|
||||
drawString(spr, String(tmpOutput), loc["temp"][0], loc["temp"][1], loc["temp"][2], TL_DATUM, (temperature < 0 ? TFT_RED : TFT_BLACK));
|
||||
|
||||
int iconcolor = PAL_BLACK;
|
||||
int iconcolor = TFT_BLACK;
|
||||
if (weathercode == 55 || weathercode == 65 || weathercode == 75 || weathercode == 82 || weathercode == 86 || weathercode == 95 || weathercode == 96 || weathercode == 99) {
|
||||
iconcolor = PAL_RED;
|
||||
iconcolor = TFT_RED;
|
||||
}
|
||||
drawString(spr, weatherIcons[weathercode], loc["icon"][0], loc["icon"][1], "/fonts/weathericons.ttf", loc["icon"][3], iconcolor, loc["icon"][2]);
|
||||
drawString(spr, windDirectionIcon(winddirection), loc["dir"][0], loc["dir"][1], "/fonts/weathericons.ttf", TC_DATUM, PAL_BLACK, loc["dir"][2]);
|
||||
drawString(spr, windDirectionIcon(winddirection), loc["dir"][0], loc["dir"][1], "/fonts/weathericons.ttf", TC_DATUM, TFT_BLACK, loc["dir"][2]);
|
||||
if (weathercode > 10) {
|
||||
drawString(spr, "\uf084", loc["umbrella"][0], loc["umbrella"][1], "/fonts/weathericons.ttf", TC_DATUM, PAL_RED, loc["umbrella"][2]);
|
||||
drawString(spr, "\uf084", loc["umbrella"][0], loc["umbrella"][1], "/fonts/weathericons.ttf", TC_DATUM, TFT_RED, loc["umbrella"][2]);
|
||||
}
|
||||
|
||||
spr2buffer(spr, filename, imageParams);
|
||||
@@ -572,7 +656,6 @@ void drawWeather(String &filename, JsonObject &cfgobj, tagRecord *&taginfo, imgP
|
||||
}
|
||||
|
||||
void drawForecast(String &filename, JsonObject &cfgobj, tagRecord *&taginfo, imgParam &imageParams) {
|
||||
TFT_eSPI tft = TFT_eSPI();
|
||||
TFT_eSprite spr = TFT_eSprite(&tft);
|
||||
|
||||
wsLog("get weather");
|
||||
@@ -608,23 +691,23 @@ void drawForecast(String &filename, JsonObject &cfgobj, tagRecord *&taginfo, img
|
||||
getTemplate(loc, 8, taginfo->hwType);
|
||||
initSprite(spr, imageParams.width, imageParams.height, imageParams);
|
||||
|
||||
drawString(spr, cfgobj["location"], loc["location"][0], loc["location"][1], loc["location"][2], TL_DATUM, PAL_BLACK);
|
||||
drawString(spr, cfgobj["location"], loc["location"][0], loc["location"][1], loc["location"][2], TL_DATUM, TFT_BLACK);
|
||||
for (uint8_t dag = 0; dag < loc["column"][0]; dag++) {
|
||||
time_t weatherday = doc["daily"]["time"][dag].as<time_t>();
|
||||
struct tm *datum = localtime(&weatherday);
|
||||
|
||||
drawString(spr, String(languageDaysShort[getCurrentLanguage()][datum->tm_wday]), dag * loc["column"][1].as<int>() + loc["day"][0].as<int>(), loc["day"][1], loc["day"][2], TC_DATUM, PAL_BLACK);
|
||||
drawString(spr, String(languageDaysShort[getCurrentLanguage()][datum->tm_wday]), dag * loc["column"][1].as<int>() + loc["day"][0].as<int>(), loc["day"][1], loc["day"][2], TC_DATUM, TFT_BLACK);
|
||||
|
||||
uint8_t weathercode = doc["daily"]["weathercode"][dag].as<int>();
|
||||
if (weathercode > 40) weathercode -= 40;
|
||||
|
||||
int iconcolor = PAL_BLACK;
|
||||
int iconcolor = TFT_BLACK;
|
||||
if (weathercode == 55 || weathercode == 65 || weathercode == 75 || weathercode == 82 || weathercode == 86 || weathercode == 95 || weathercode == 96 || weathercode == 99) {
|
||||
iconcolor = PAL_RED;
|
||||
iconcolor = TFT_RED;
|
||||
}
|
||||
drawString(spr, weatherIcons[weathercode], loc["icon"][0].as<int>() + dag * loc["column"][1].as<int>(), loc["icon"][1], "/fonts/weathericons.ttf", TC_DATUM, iconcolor, loc["icon"][2]);
|
||||
|
||||
drawString(spr, windDirectionIcon(doc["daily"]["winddirection_10m_dominant"][dag]), loc["wind"][0].as<int>() + dag * loc["column"][1].as<int>(), loc["wind"][1], "/fonts/weathericons.ttf", TC_DATUM, PAL_BLACK, loc["icon"][2]);
|
||||
drawString(spr, windDirectionIcon(doc["daily"]["winddirection_10m_dominant"][dag]), loc["wind"][0].as<int>() + dag * loc["column"][1].as<int>(), loc["wind"][1], "/fonts/weathericons.ttf", TC_DATUM, TFT_BLACK, loc["icon"][2]);
|
||||
|
||||
int8_t tmin = round(doc["daily"]["temperature_2m_min"][dag].as<double>());
|
||||
int8_t tmax = round(doc["daily"]["temperature_2m_max"][dag].as<double>());
|
||||
@@ -635,17 +718,17 @@ void drawForecast(String &filename, JsonObject &cfgobj, tagRecord *&taginfo, img
|
||||
if (loc["rain"]) {
|
||||
int8_t rain = round(doc["daily"]["precipitation_sum"][dag].as<double>());
|
||||
if (rain > 0) {
|
||||
drawString(spr, String(rain) + "mm", dag * loc["column"][1].as<int>() + loc["rain"][0].as<int>(), loc["rain"][1], "", TC_DATUM, (rain > 10 ? PAL_RED : PAL_BLACK));
|
||||
drawString(spr, String(rain) + "mm", dag * loc["column"][1].as<int>() + loc["rain"][0].as<int>(), loc["rain"][1], "", TC_DATUM, (rain > 10 ? TFT_RED : TFT_BLACK));
|
||||
}
|
||||
}
|
||||
|
||||
drawString(spr, String(tmin) + " ", dag * loc["column"][1].as<int>() + loc["day"][0].as<int>(), loc["day"][4], "", TR_DATUM, (tmin < 0 ? PAL_RED : PAL_BLACK));
|
||||
drawString(spr, String(" ") + String(tmax), dag * loc["column"][1].as<int>() + loc["day"][0].as<int>(), loc["day"][4], "", TL_DATUM, (tmax < 0 ? PAL_RED : PAL_BLACK));
|
||||
drawString(spr, String(" ") + String(wind), dag * loc["column"][1].as<int>() + loc["day"][0].as<int>(), loc["day"][3], "", TL_DATUM, (wind > 5 ? PAL_RED : PAL_BLACK));
|
||||
drawString(spr, String(tmin) + " ", dag * loc["column"][1].as<int>() + loc["day"][0].as<int>(), loc["day"][4], "", TR_DATUM, (tmin < 0 ? TFT_RED : TFT_BLACK));
|
||||
drawString(spr, String(" ") + String(tmax), dag * loc["column"][1].as<int>() + loc["day"][0].as<int>(), loc["day"][4], "", TL_DATUM, (tmax < 0 ? TFT_RED : TFT_BLACK));
|
||||
drawString(spr, String(" ") + String(wind), dag * loc["column"][1].as<int>() + loc["day"][0].as<int>(), loc["day"][3], "", TL_DATUM, (wind > 5 ? TFT_RED : TFT_BLACK));
|
||||
spr.unloadFont();
|
||||
if (dag > 0) {
|
||||
for (int i = loc["line"][0]; i < loc["line"][1]; i += 3) {
|
||||
spr.drawPixel(dag * loc["column"][1].as<int>(), i, PAL_BLACK);
|
||||
spr.drawPixel(dag * loc["column"][1].as<int>(), i, TFT_BLACK);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -700,7 +783,6 @@ bool getRssFeed(String &filename, String URL, String title, tagRecord *&taginfo,
|
||||
const char *tag = "title";
|
||||
const int rssArticleSize = 128;
|
||||
|
||||
TFT_eSPI tft = TFT_eSPI();
|
||||
TFT_eSprite spr = TFT_eSprite(&tft);
|
||||
U8g2_for_TFT_eSPI u8f;
|
||||
u8f.begin(spr);
|
||||
@@ -710,13 +792,13 @@ bool getRssFeed(String &filename, String URL, String title, tagRecord *&taginfo,
|
||||
initSprite(spr, imageParams.width, imageParams.height, imageParams);
|
||||
|
||||
if (title == "" || title == "null") title = "RSS feed";
|
||||
drawString(spr, title, loc["title"][0], loc["title"][1], loc["title"][2], TL_DATUM, PAL_BLACK);
|
||||
drawString(spr, title, loc["title"][0], loc["title"][1], loc["title"][2], TL_DATUM, TFT_BLACK);
|
||||
|
||||
setU8G2Font(loc["font"], u8f);
|
||||
u8f.setFontMode(0);
|
||||
u8f.setFontDirection(0);
|
||||
u8f.setForegroundColor(PAL_BLACK);
|
||||
u8f.setBackgroundColor(PAL_WHITE);
|
||||
u8f.setForegroundColor(TFT_BLACK);
|
||||
u8f.setBackgroundColor(TFT_WHITE);
|
||||
|
||||
int n = reader.getArticles(url, tag, rssArticleSize, loc["items"]);
|
||||
for (int i = 0; i < n; i++) {
|
||||
@@ -782,7 +864,6 @@ bool getCalFeed(String &filename, String URL, String title, tagRecord *&taginfo,
|
||||
}
|
||||
http.end();
|
||||
|
||||
TFT_eSPI tft = TFT_eSPI();
|
||||
TFT_eSprite spr = TFT_eSprite(&tft);
|
||||
U8g2_for_TFT_eSPI u8f;
|
||||
u8f.begin(spr);
|
||||
@@ -792,8 +873,8 @@ bool getCalFeed(String &filename, String URL, String title, tagRecord *&taginfo,
|
||||
initSprite(spr, imageParams.width, imageParams.height, imageParams);
|
||||
|
||||
if (title == "" || title == "null") title = "Calendar";
|
||||
drawString(spr, title, loc["title"][0], loc["title"][1], loc["title"][2], TL_DATUM, PAL_BLACK);
|
||||
drawString(spr, dateString, loc["date"][0], loc["date"][1], loc["title"][2], TR_DATUM, PAL_BLACK);
|
||||
drawString(spr, title, loc["title"][0], loc["title"][1], loc["title"][2], TL_DATUM, TFT_BLACK);
|
||||
drawString(spr, dateString, loc["date"][0], loc["date"][1], loc["title"][2], TR_DATUM, TFT_BLACK);
|
||||
|
||||
u8f.setFontMode(0);
|
||||
u8f.setFontDirection(0);
|
||||
@@ -806,12 +887,12 @@ bool getCalFeed(String &filename, String URL, String title, tagRecord *&taginfo,
|
||||
time_t endtime = obj["end"];
|
||||
setU8G2Font(loc["line"][3], u8f);
|
||||
if (starttime <= now && endtime > now) {
|
||||
u8f.setForegroundColor(PAL_WHITE);
|
||||
u8f.setBackgroundColor(PAL_RED);
|
||||
spr.fillRect(loc["red"][0], loc["red"][1].as<int>() + i * loc["line"][2].as<int>(), loc["red"][2], loc["red"][3], PAL_RED);
|
||||
u8f.setForegroundColor(TFT_WHITE);
|
||||
u8f.setBackgroundColor(TFT_RED);
|
||||
spr.fillRect(loc["red"][0], loc["red"][1].as<int>() + i * loc["line"][2].as<int>(), loc["red"][2], loc["red"][3], TFT_RED);
|
||||
} else {
|
||||
u8f.setForegroundColor(PAL_BLACK);
|
||||
u8f.setBackgroundColor(PAL_WHITE);
|
||||
u8f.setForegroundColor(TFT_BLACK);
|
||||
u8f.setBackgroundColor(TFT_WHITE);
|
||||
}
|
||||
u8f.setCursor(loc["line"][0], loc["line"][1].as<int>() + i * loc["line"][2].as<int>());
|
||||
if (starttime > 0) u8f.print(epoch_to_display(obj["start"]));
|
||||
@@ -827,7 +908,6 @@ bool getCalFeed(String &filename, String URL, String title, tagRecord *&taginfo,
|
||||
|
||||
void drawQR(String &filename, String qrcontent, String title, tagRecord *&taginfo, imgParam &imageParams) {
|
||||
#ifdef CONTENT_QR
|
||||
TFT_eSPI tft = TFT_eSPI();
|
||||
TFT_eSprite spr = TFT_eSprite(&tft);
|
||||
Storage.begin();
|
||||
|
||||
@@ -851,7 +931,7 @@ void drawQR(String &filename, String qrcontent, String title, tagRecord *&taginf
|
||||
for (int y = 0; y < size; y++) {
|
||||
for (int x = 0; x < size; x++) {
|
||||
if (qrcode_getModule(&qrcode, x, y)) {
|
||||
spr.fillRect(xpos + x * dotsize, ypos + y * dotsize, dotsize, dotsize, PAL_BLACK);
|
||||
spr.fillRect(xpos + x * dotsize, ypos + y * dotsize, dotsize, dotsize, TFT_BLACK);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -877,7 +957,6 @@ uint8_t drawBuienradar(String &filename, JsonObject &cfgobj, tagRecord *&taginfo
|
||||
int httpCode = http.GET();
|
||||
|
||||
if (httpCode == 200) {
|
||||
TFT_eSPI tft = TFT_eSPI();
|
||||
TFT_eSprite spr = TFT_eSprite(&tft);
|
||||
U8g2_for_TFT_eSPI u8f;
|
||||
u8f.begin(spr);
|
||||
@@ -893,13 +972,10 @@ uint8_t drawBuienradar(String &filename, JsonObject &cfgobj, tagRecord *&taginfo
|
||||
drawString(spr, cfgobj["location"], loc["location"][0], loc["location"][1], loc["location"][2]);
|
||||
|
||||
for (int i = 0; i < 295; i += 4) {
|
||||
spr.drawPixel(i, 110, PAL_BLACK);
|
||||
spr.drawPixel(i, 91, PAL_BLACK);
|
||||
spr.drawPixel(i, 82, PAL_BLACK);
|
||||
spr.drawPixel(i, 72, PAL_BLACK);
|
||||
spr.drawPixel(i, 62, PAL_BLACK);
|
||||
spr.drawPixel(i, 56, PAL_BLACK);
|
||||
spr.drawPixel(i, 52, PAL_BLACK);
|
||||
int yCoordinates[] = {110, 91, 82, 72, 62, 56, 52};
|
||||
for (int y : yCoordinates) {
|
||||
spr.drawPixel(i, y, TFT_BLACK);
|
||||
}
|
||||
}
|
||||
|
||||
drawString(spr, "Buienradar", loc["title"][0], loc["title"][1], loc["title"][2]);
|
||||
@@ -914,7 +990,7 @@ uint8_t drawBuienradar(String &filename, JsonObject &cfgobj, tagRecord *&taginfo
|
||||
if (value > 70 && i < 12) refresh = 5;
|
||||
if (value > 70 && refresh > 5) refresh = 15;
|
||||
|
||||
spr.fillRect(i * loc["cols"][2].as<int>() + loc["bars"][0].as<int>(), loc["bars"][1].as<int>() - (value - 70), loc["bars"][2], (value - 70), (value > 130 ? PAL_RED : PAL_BLACK));
|
||||
spr.fillRect(i * loc["cols"][2].as<int>() + loc["bars"][0].as<int>(), loc["bars"][1].as<int>() - (value - 70), loc["bars"][2], (value - 70), (value > 130 ? TFT_RED : TFT_BLACK));
|
||||
|
||||
if (minutes % 15 == 0) {
|
||||
drawString(spr, timestring, i * loc["cols"][2].as<int>() + loc["cols"][0].as<int>(), loc["cols"][1], loc["cols"][3]);
|
||||
@@ -931,6 +1007,27 @@ uint8_t drawBuienradar(String &filename, JsonObject &cfgobj, tagRecord *&taginfo
|
||||
return refresh;
|
||||
}
|
||||
|
||||
void drawAPinfo(String &filename, JsonObject &cfgobj, tagRecord *&taginfo, imgParam &imageParams) {
|
||||
if (taginfo->hwType == SOLUM_SEG_UK) {
|
||||
imageParams.symbols = 0x00;
|
||||
sprintf(imageParams.segments, "");
|
||||
return;
|
||||
}
|
||||
|
||||
TFT_eSprite spr = TFT_eSprite(&tft);
|
||||
StaticJsonDocument<2048> loc;
|
||||
getTemplate(loc, 21, taginfo->hwType);
|
||||
|
||||
initSprite(spr, imageParams.width, imageParams.height, imageParams);
|
||||
JsonArray jsonArray = loc.as<JsonArray>();
|
||||
for (JsonVariant elem : jsonArray) {
|
||||
drawElement(elem, spr);
|
||||
}
|
||||
|
||||
spr2buffer(spr, filename, imageParams);
|
||||
spr.deleteSprite();
|
||||
}
|
||||
|
||||
int getJsonTemplateFile(String &filename, String jsonfile, tagRecord *&taginfo, imgParam &imageParams) {
|
||||
if (jsonfile.c_str()[0] != '/') {
|
||||
jsonfile = "/" + jsonfile;
|
||||
@@ -939,7 +1036,7 @@ int getJsonTemplateFile(String &filename, String jsonfile, tagRecord *&taginfo,
|
||||
if (file) {
|
||||
drawJsonStream(file, filename, taginfo, imageParams);
|
||||
file.close();
|
||||
contentFS->remove(jsonfile);
|
||||
// contentFS->remove(jsonfile);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
@@ -966,7 +1063,6 @@ int getJsonTemplateUrl(String &filename, String URL, time_t fetched, String MAC,
|
||||
}
|
||||
|
||||
void drawJsonStream(Stream &stream, String &filename, tagRecord *&taginfo, imgParam &imageParams) {
|
||||
TFT_eSPI tft = TFT_eSPI();
|
||||
TFT_eSprite spr = TFT_eSprite(&tft);
|
||||
initSprite(spr, imageParams.width, imageParams.height, imageParams);
|
||||
DynamicJsonDocument doc(300);
|
||||
@@ -991,35 +1087,34 @@ void drawJsonStream(Stream &stream, String &filename, tagRecord *&taginfo, imgPa
|
||||
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;
|
||||
uint16_t size = textArray[6] | 0;
|
||||
drawString(spr, textArray[2], textArray[0].as<int>(), textArray[1].as<int>(), textArray[3], align, getColor(color), size);
|
||||
String bgcolorstr = textArray[7].as<String>();
|
||||
|
||||
uint16_t bgcolor = (bgcolorstr.length() > 0) ? getColor(bgcolorstr) : TFT_WHITE;
|
||||
drawString(spr, textArray[2], textArray[0].as<int>(), textArray[1].as<int>(), textArray[3], align, getColor(textArray[4]), size, bgcolor);
|
||||
} else if (element.containsKey("box")) {
|
||||
const JsonArray &boxArray = element["box"];
|
||||
uint16_t color = boxArray[4] | 1;
|
||||
spr.fillRect(boxArray[0].as<int>(), boxArray[1].as<int>(), boxArray[2].as<int>(), boxArray[3].as<int>(), getColor(color));
|
||||
spr.fillRect(boxArray[0].as<int>(), boxArray[1].as<int>(), boxArray[2].as<int>(), boxArray[3].as<int>(), getColor(boxArray[4]));
|
||||
} else if (element.containsKey("line")) {
|
||||
const JsonArray &lineArray = element["line"];
|
||||
uint16_t color = lineArray[4] | 1;
|
||||
spr.drawLine(lineArray[0].as<int>(), lineArray[1].as<int>(), lineArray[2].as<int>(), lineArray[3].as<int>(), getColor(color));
|
||||
spr.drawLine(lineArray[0].as<int>(), lineArray[1].as<int>(), lineArray[2].as<int>(), lineArray[3].as<int>(), getColor(lineArray[4]));
|
||||
} else if (element.containsKey("triangle")) {
|
||||
const JsonArray &lineArray = element["triangle"];
|
||||
uint16_t color = lineArray[6] | 1;
|
||||
spr.fillTriangle(lineArray[0].as<int>(), lineArray[1].as<int>(), lineArray[2].as<int>(), lineArray[3].as<int>(), lineArray[4].as<int>(), lineArray[5].as<int>(), getColor(color));
|
||||
spr.fillTriangle(lineArray[0].as<int>(), lineArray[1].as<int>(), lineArray[2].as<int>(), lineArray[3].as<int>(), lineArray[4].as<int>(), lineArray[5].as<int>(), getColor(lineArray[6]));
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t getColor(uint8_t color) {
|
||||
switch (color) {
|
||||
case 0:
|
||||
return PAL_WHITE;
|
||||
case 1:
|
||||
return PAL_BLACK;
|
||||
case 2:
|
||||
return PAL_RED;
|
||||
uint16_t getColor(String color) {
|
||||
if (color == "0" or color == "white") return TFT_WHITE;
|
||||
if (color == "1" or color == "" or color == "black") return TFT_BLACK;
|
||||
if (color == "2" or color == "red") return TFT_RED;
|
||||
uint16_t r, g, b;
|
||||
if (color.length() == 7 && color[0] == '#' &&
|
||||
sscanf(color.c_str(), "#%2hx%2hx%2hx", &r, &g, &b) == 3) {
|
||||
return ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
|
||||
}
|
||||
return PAL_WHITE;
|
||||
return TFT_WHITE;
|
||||
}
|
||||
|
||||
char *formatHttpDate(time_t t) {
|
||||
@@ -1153,7 +1248,7 @@ void prepareConfigFile(uint8_t *dst, JsonObject config) {
|
||||
|
||||
void getTemplate(JsonDocument &json, uint8_t id, uint8_t hwtype) {
|
||||
StaticJsonDocument<80> filter;
|
||||
StaticJsonDocument<1024> doc;
|
||||
StaticJsonDocument<2048> doc;
|
||||
|
||||
const String idstr = String(id);
|
||||
const char *templateKey = "template";
|
||||
@@ -1167,11 +1262,14 @@ void getTemplate(JsonDocument &json, uint8_t id, uint8_t hwtype) {
|
||||
filter["usetemplate"] = true;
|
||||
DeserializationError error = deserializeJson(doc, jsonFile, DeserializationOption::Filter(filter));
|
||||
jsonFile.close();
|
||||
if (!error && doc.containsKey(templateKey) && doc[templateKey].containsKey(idstr)) {
|
||||
json.set(doc[templateKey][idstr]);
|
||||
return;
|
||||
}
|
||||
if (!error && doc.containsKey("usetemplate")) {
|
||||
getTemplate(json, id, doc["usetemplate"]);
|
||||
return;
|
||||
}
|
||||
if (!error && json.set(doc[templateKey][idstr])) return;
|
||||
Serial.println("json error in " + String(filename));
|
||||
Serial.println(error.c_str());
|
||||
} else {
|
||||
@@ -1184,47 +1282,3 @@ void setU8G2Font(const String &title, U8g2_for_TFT_eSPI &u8f) {
|
||||
if (title == "7x14_tf") u8f.setFont(u8g2_font_7x14_tf);
|
||||
if (title == "t0_14b_tf") u8f.setFont(u8g2_font_t0_14b_tf);
|
||||
}
|
||||
|
||||
void showIpAddress(String dst) {
|
||||
uint8_t mac[8];
|
||||
if (hex2mac(dst, mac)) {
|
||||
tagRecord *taginfo = nullptr;
|
||||
taginfo = tagRecord::findByMAC(mac);
|
||||
if (taginfo != nullptr) {
|
||||
String json = String("[");
|
||||
json += String("{\"text\": [0,5,\"OpenEPaperLink\",\"fonts/bahnschrift20\",2]}");
|
||||
json += String(",");
|
||||
json += String("{\"text\": [0,25,\"MAC:\",\"fonts/bahnschrift20\",1]}");
|
||||
json += String(",");
|
||||
json += String("{\"text\": [10,55,\"") + dst + String("\",\"glasstown_nbp_tf\",1]}");
|
||||
|
||||
if ((uint32_t)WiFi.localIP() == (uint32_t)0) {
|
||||
json += String(",");
|
||||
json += String("{\"text\": [0,65,\"Connect to my \",\"fonts/bahnschrift20\",1]}");
|
||||
json += String(",");
|
||||
json += String("{\"text\": [0,85,\"WiFi, browse to:\",\"fonts/bahnschrift20\",1]}");
|
||||
json += String(",");
|
||||
json += String("{\"text\": [0,105,\"192.168.4.1/setup\",\"fonts/bahnschrift20\",1]}");
|
||||
json += String(",");
|
||||
json += String("{\"text\": [0,125,\"to configure me\",\"fonts/bahnschrift20\",1]}");
|
||||
} else {
|
||||
json += String(",");
|
||||
json += String("{\"text\": [0,65,\"IP:\",\"fonts/bahnschrift20\",1]}");
|
||||
json += String(",");
|
||||
json += String("{\"text\": [0,85,\"") + WiFi.localIP().toString() + String("\",\"fonts/bahnschrift20\",1]}");
|
||||
}
|
||||
|
||||
json += String("]");
|
||||
File file = LittleFS.open("/" + dst + ".json", "w");
|
||||
if (!file) {
|
||||
Serial.print("Failed to create file\n");
|
||||
return;
|
||||
}
|
||||
file.print(json);
|
||||
file.close();
|
||||
taginfo->modeConfigJson = "{\"filename\":\"" + dst + ".json\"}";
|
||||
taginfo->contentMode = 19;
|
||||
taginfo->nextupdate = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,11 +57,14 @@ void yellow_ap_display_loop(void) {
|
||||
sendAvail(0);
|
||||
last_checkin = millis();
|
||||
}
|
||||
if (millis() - last_update >= 500) {
|
||||
if (millis() - last_update >= 1000) {
|
||||
if (first_run == 0) {
|
||||
sendAvail(0xFC);
|
||||
first_run = 1;
|
||||
}
|
||||
|
||||
// if ((uint32_t)WiFi.localIP() == (uint32_t)0) {}
|
||||
|
||||
tagRecord* tag = nullptr;
|
||||
tag = tagDB.at(tftid);
|
||||
if (tag->pending) {
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
#include "storage.h"
|
||||
#include "contentmanager.h"
|
||||
#include "flasher.h"
|
||||
#include "makeimage.h"
|
||||
#include "serialap.h"
|
||||
#include "settings.h"
|
||||
#include "system.h"
|
||||
@@ -40,7 +39,10 @@ void timeTask(void* parameter) {
|
||||
time_t now;
|
||||
time(&now);
|
||||
|
||||
if (now % 5 == 0 || apInfo.state != AP_STATE_ONLINE || config.runStatus != RUNSTATUS_RUN) wsSendSysteminfo();
|
||||
if (now % 5 == 0 || apInfo.state != AP_STATE_ONLINE || config.runStatus != RUNSTATUS_RUN) {
|
||||
wsSendSysteminfo();
|
||||
checkVars();
|
||||
}
|
||||
if (now % 300 == 6 && config.runStatus != RUNSTATUS_STOP) saveDB("/current/tagDB.json");
|
||||
if (apInfo.state == AP_STATE_ONLINE) contentRunner();
|
||||
|
||||
|
||||
@@ -203,6 +203,14 @@ void spr2buffer(TFT_eSprite &spr, String &fileout, imgParam &imageParams) {
|
||||
long t = millis();
|
||||
Storage.begin();
|
||||
|
||||
#ifdef YELLOW_IPS_AP
|
||||
if (fileout == "direct") {
|
||||
tft.setRotation(3);
|
||||
spr.pushSprite(0, 0);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
fs::File f_out = contentFS->open(fileout, "w");
|
||||
|
||||
switch (imageParams.bpp) {
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#include <HTTPClient.h>
|
||||
#include "storage.h"
|
||||
#include <MD5Builder.h>
|
||||
#include <makeimage.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "storage.h"
|
||||
@@ -121,8 +120,16 @@ void prepareDataAvail(uint8_t* data, uint16_t len, uint8_t dataType, uint8_t* ds
|
||||
bool prepareDataAvail(String* filename, uint8_t dataType, uint8_t* dst, uint16_t nextCheckin) {
|
||||
if (nextCheckin > config.maxsleep) nextCheckin = config.maxsleep;
|
||||
if (wsClientCount() && config.stopsleep == 1) nextCheckin=0;
|
||||
|
||||
tagRecord* taginfo = nullptr;
|
||||
#ifdef YELLOW_IPS_AP
|
||||
if (*filename == "direct") {
|
||||
char dst_path[64];
|
||||
sprintf(dst_path, "/current/%02X%02X%02X%02X%02X%02X%02X%02X.raw\0", dst[7], dst[6], dst[5], dst[4], dst[3], dst[2], dst[1], dst[0]);
|
||||
contentFS->remove(dst_path);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
tagRecord* taginfo = nullptr;
|
||||
taginfo = tagRecord::findByMAC(dst);
|
||||
if (taginfo == nullptr) {
|
||||
wsErr("Tag not found, this shouldn't happen.");
|
||||
@@ -507,11 +514,11 @@ void processDataReq(struct espAvailDataReq* eadr, bool local) {
|
||||
}
|
||||
if (local) {
|
||||
sprintf(buffer, "<ADR %02X%02X%02X%02X%02X%02X%02X%02X\n\0", eadr->src[7], eadr->src[6], eadr->src[5], eadr->src[4], eadr->src[3], eadr->src[2], eadr->src[1], eadr->src[0]);
|
||||
Serial.print(buffer);
|
||||
} else {
|
||||
sprintf(buffer, "<REMOTE ADR %02X%02X%02X%02X%02X%02X%02X%02X\n\0", eadr->src[7], eadr->src[6], eadr->src[5], eadr->src[4], eadr->src[3], eadr->src[2], eadr->src[1], eadr->src[0]);
|
||||
// sprintf(buffer, "<REMOTE ADR %02X%02X%02X%02X%02X%02X%02X%02X\n\0", eadr->src[7], eadr->src[6], eadr->src[5], eadr->src[4], eadr->src[3], eadr->src[2], eadr->src[1], eadr->src[0]);
|
||||
}
|
||||
|
||||
Serial.print(buffer);
|
||||
wsSendTaginfo(eadr->src, SYNC_TAGSTATUS);
|
||||
if (local) {
|
||||
udpsync.netProcessDataReq(eadr);
|
||||
|
||||
@@ -533,17 +533,11 @@ void rxSerialTask(void* parameter) {
|
||||
}
|
||||
|
||||
void ShowAPInfo() {
|
||||
Serial.printf("| AP Information - type %02X |\n", apInfo.type);
|
||||
Serial.printf("| Channel | 0x%02X |\n", apInfo.channel);
|
||||
Serial.printf("| Power | %02X |\n", apInfo.power);
|
||||
Serial.printf("| MAC | %02X%02X%02X%02X%02X%02X%02X%02X |\n", apInfo.mac[7], apInfo.mac[6], apInfo.mac[5], apInfo.mac[4], apInfo.mac[3], apInfo.mac[2], apInfo.mac[1], apInfo.mac[0]);
|
||||
Serial.printf("| Version | 0x%04X |\n", apInfo.version);
|
||||
|
||||
if (apInfo.type == SOLUM_154_SSD1619 || apInfo.type == SOLUM_29_SSD1619 || apInfo.type == SOLUM_29_UC8151 || apInfo.type == SOLUM_42_SSD1619) {
|
||||
char macString[50];
|
||||
sprintf(macString, "%02X%02X%02X%02X%02X%02X%02X%02X", apInfo.mac[7], apInfo.mac[6], apInfo.mac[5], apInfo.mac[4], apInfo.mac[3], apInfo.mac[2], apInfo.mac[1], apInfo.mac[0]);
|
||||
showIpAddress(macString);
|
||||
}
|
||||
Serial.printf("| AP Info - type %02X |\n", apInfo.type);
|
||||
Serial.printf("| Ch | 0x%02X |\n", apInfo.channel);
|
||||
Serial.printf("| Power| %02X |\n", apInfo.power);
|
||||
Serial.printf("| MAC | %02X%02X%02X%02X%02X%02X%02X%02X |\n", apInfo.mac[7], apInfo.mac[6], apInfo.mac[5], apInfo.mac[4], apInfo.mac[3], apInfo.mac[2], apInfo.mac[1], apInfo.mac[0]);
|
||||
Serial.printf("| Ver | 0x%04X |\n", apInfo.version);
|
||||
}
|
||||
|
||||
void notifySegmentedFlash() {
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "storage.h"
|
||||
|
||||
std::vector<tagRecord*> tagDB;
|
||||
std::unordered_map<std::string, varStruct> varDB;
|
||||
std::unordered_map<int, HwType> hwdata = {
|
||||
{0, {152, 152, 0, 2}},
|
||||
{1, {296, 128, 1, 2}},
|
||||
@@ -20,7 +21,7 @@ Config config;
|
||||
// SemaphoreHandle_t tagDBOwner;
|
||||
|
||||
tagRecord* tagRecord::findByMAC(uint8_t mac[8]) {
|
||||
for (int16_t c = 0; c < tagDB.size(); c++) {
|
||||
for (int32_t c = 0; c < tagDB.size(); c++) {
|
||||
tagRecord* tag = nullptr;
|
||||
tag = tagDB.at(c);
|
||||
if (memcmp(tag->mac, mac, 8) == 0) {
|
||||
@@ -31,7 +32,7 @@ tagRecord* tagRecord::findByMAC(uint8_t mac[8]) {
|
||||
}
|
||||
|
||||
bool deleteRecord(uint8_t mac[8]) {
|
||||
for (int16_t c = 0; c < tagDB.size(); c++) {
|
||||
for (int32_t c = 0; c < tagDB.size(); c++) {
|
||||
tagRecord* tag = nullptr;
|
||||
tag = tagDB.at(c);
|
||||
if (memcmp(tag->mac, mac, 8) == 0) {
|
||||
@@ -91,7 +92,7 @@ String tagDBtoJson(uint8_t mac[8], uint8_t startPos) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (doc.capacity() - doc.memoryUsage() < doc.memoryUsage() / (c + 1) + 150) {
|
||||
if (doc.capacity() - doc.memoryUsage() < doc.memoryUsage() / (c + 1) + 500) {
|
||||
doc["continu"] = c + 1;
|
||||
break;
|
||||
}
|
||||
@@ -143,7 +144,7 @@ void saveDB(String filename) {
|
||||
|
||||
file.write('[');
|
||||
|
||||
for (int16_t c = 0; c < tagDB.size(); c++) {
|
||||
for (int32_t c = 0; c < tagDB.size(); c++) {
|
||||
doc.clear();
|
||||
tagRecord* taginfo = nullptr;
|
||||
taginfo = tagDB.at(c);
|
||||
@@ -205,7 +206,7 @@ void loadDB(String filename) {
|
||||
taginfo->lastseen = (uint32_t)tag["lastseen"];
|
||||
taginfo->nextupdate = (uint32_t)tag["nextupdate"];
|
||||
taginfo->expectedNextCheckin = (uint16_t)tag["nextcheckin"];
|
||||
if (taginfo->expectedNextCheckin < now - 1800) {
|
||||
if (taginfo->expectedNextCheckin < now) {
|
||||
taginfo->expectedNextCheckin = now + 1800;
|
||||
}
|
||||
taginfo->pending = false;
|
||||
@@ -255,11 +256,25 @@ void destroyDB() {
|
||||
}
|
||||
|
||||
uint32_t getTagCount() {
|
||||
uint32_t temp = 0;
|
||||
return getTagCount(temp);
|
||||
}
|
||||
|
||||
uint32_t getTagCount(uint32_t& timeoutcount) {
|
||||
uint32_t tagcount = 0;
|
||||
time_t now;
|
||||
time(&now);
|
||||
// Serial.printf("now: %d\n", now);
|
||||
for (uint32_t c = 0; c < tagDB.size(); c++) {
|
||||
tagRecord* taginfo = nullptr;
|
||||
taginfo = tagDB.at(c);
|
||||
if (taginfo->isExternal == false) tagcount++;
|
||||
int32_t timeout1 = now - taginfo->lastseen;
|
||||
int32_t timeout2 = taginfo->lastseen - taginfo->expectedNextCheckin;
|
||||
// Serial.printf("%d expected: %d lastseen: %d -> %d %d\n", c, taginfo->expectedNextCheckin, timeout1, timeout2);
|
||||
if (((taginfo->expectedNextCheckin < 3600 && timeout1 > 3600) ||
|
||||
(taginfo->expectedNextCheckin > 3600 && timeout2 > 600)) &&
|
||||
now > 3600 && millis() > 60000) timeoutcount++;
|
||||
}
|
||||
return tagcount;
|
||||
}
|
||||
@@ -356,3 +371,22 @@ HwType getHwType(uint8_t id) {
|
||||
return {0, 0, 0, 0};
|
||||
}
|
||||
}
|
||||
|
||||
bool setVarDB(const std::string& key, const String& value) {
|
||||
auto it = varDB.find(key);
|
||||
if (it == varDB.end()) {
|
||||
varStruct newVar;
|
||||
newVar.value = value;
|
||||
newVar.changed = true;
|
||||
varDB[key] = newVar;
|
||||
return true;
|
||||
} else {
|
||||
if (it->second.value != value) {
|
||||
it->second.value = value;
|
||||
it->second.changed = true;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,6 +89,18 @@ void wsSendSysteminfo() {
|
||||
sys["wifistatus"] = WiFi.status();
|
||||
sys["wifissid"] = WiFi.SSID();
|
||||
|
||||
uint32_t timeoutcount = 0;
|
||||
uint32_t tagcount = getTagCount(timeoutcount);
|
||||
char result[40];
|
||||
if (timeoutcount > 0) {
|
||||
snprintf(result, sizeof(result), "%lu / %lu, %lu timeout", tagcount, tagDB.size(), timeoutcount);
|
||||
} else {
|
||||
snprintf(result, sizeof(result), "%lu / %lu", tagcount, tagDB.size());
|
||||
}
|
||||
setVarDB("ap_tagcount", result);
|
||||
setVarDB("ap_ip", WiFi.localIP().toString());
|
||||
setVarDB("ap_ch", String(apInfo.channel));
|
||||
|
||||
xSemaphoreTake(wsMutex, portMAX_DELAY);
|
||||
ws.textAll(doc.as<String>());
|
||||
xSemaphoreGive(wsMutex);
|
||||
@@ -364,6 +376,37 @@ void init_web() {
|
||||
request->send(200, "text/plain", "Ok, saved");
|
||||
});
|
||||
|
||||
server.on("/set_var", HTTP_POST, [](AsyncWebServerRequest *request) {
|
||||
if (request->hasParam("key", true) && request->hasParam("val", true)) {
|
||||
std::string key = request->getParam("key", true)->value().c_str();
|
||||
String val = request->getParam("val", true)->value();
|
||||
Serial.printf("set key %s value %s\n", key.c_str(), val);
|
||||
setVarDB(key, val);
|
||||
request->send(200, "text/plain", "Ok, saved");
|
||||
} else {
|
||||
request->send(500, "text/plain", "param error");
|
||||
}
|
||||
});
|
||||
server.on("/set_vars", HTTP_POST, [](AsyncWebServerRequest *request) {
|
||||
if (request->hasParam("json", true)) {
|
||||
DynamicJsonDocument jsonDocument(2048);
|
||||
DeserializationError error = deserializeJson(jsonDocument, request->getParam("json", true)->value());
|
||||
if (error) {
|
||||
request->send(400, "text/plain", "Failed to parse JSON");
|
||||
return;
|
||||
}
|
||||
for (JsonPair kv : jsonDocument.as<JsonObject>()) {
|
||||
std::string key = kv.key().c_str();
|
||||
String val = kv.value().as<String>();
|
||||
Serial.printf("set key %s value %s\n", key.c_str(), val);
|
||||
setVarDB(key, val);
|
||||
}
|
||||
request->send(200, "text/plain", "JSON uploaded and processed");
|
||||
} else {
|
||||
request->send(400, "text/plain", "No 'json' parameter found in request");
|
||||
}
|
||||
});
|
||||
|
||||
// setup
|
||||
|
||||
server.on("/setup", HTTP_GET, [](AsyncWebServerRequest *request) {
|
||||
@@ -438,9 +481,14 @@ void init_web() {
|
||||
// end of setup
|
||||
|
||||
server.on("/backup_db", HTTP_GET, [](AsyncWebServerRequest *request) {
|
||||
saveDB("/current/tagDB.json");
|
||||
// saveDB("/current/tagDB.json");
|
||||
File file = contentFS->open("/current/tagDB.json", "r");
|
||||
if (!file) {
|
||||
request->send(404);
|
||||
return;
|
||||
}
|
||||
AsyncWebServerResponse *response = request->beginResponse(file, "tagDB.json", String(), true);
|
||||
response->addHeader("Content-Disposition", "attachment; filename=tagDB.json");
|
||||
request->send(response);
|
||||
file.close();
|
||||
});
|
||||
@@ -490,16 +538,20 @@ void doImageUpload(AsyncWebServerRequest *request, String filename, size_t index
|
||||
request->_tempFile.close();
|
||||
if (request->hasParam("mac", true)) {
|
||||
String dst = request->getParam("mac", true)->value();
|
||||
bool dither = true;
|
||||
if (request->hasParam("dither", true)) {
|
||||
if (request->getParam("dither", true)->value() == "0") dither = false;
|
||||
}
|
||||
uint8_t mac[8];
|
||||
if (hex2mac(dst, mac)) {
|
||||
tagRecord *taginfo = nullptr;
|
||||
taginfo = tagRecord::findByMAC(mac);
|
||||
if (taginfo != nullptr) {
|
||||
taginfo->modeConfigJson = "{\"filename\":\"" + dst + ".jpg\",\"timetolive\":\"0\",\"dither\":\"" + String(dither) + "\",\"delete\":\"1\"}";
|
||||
bool dither = true;
|
||||
if (request->hasParam("dither", true)) {
|
||||
if (request->getParam("dither", true)->value() == "0") dither = false;
|
||||
}
|
||||
uint32_t ttl = 0;
|
||||
if (request->hasParam("ttl", true)) {
|
||||
ttl = request->getParam("ttl", true)->value().toInt();
|
||||
}
|
||||
taginfo->modeConfigJson = "{\"filename\":\"" + dst + ".jpg\",\"timetolive\":\"" + String(ttl) + "\",\"dither\":\"" + String(dither) + "\",\"delete\":\"1\"}";
|
||||
taginfo->contentMode = 0;
|
||||
taginfo->nextupdate = 0;
|
||||
wsSendTaginfo(mac, SYNC_USERCFG);
|
||||
@@ -521,19 +573,23 @@ void doJsonUpload(AsyncWebServerRequest *request) {
|
||||
}
|
||||
if (request->hasParam("mac", true) && request->hasParam("json", true)) {
|
||||
String dst = request->getParam("mac", true)->value();
|
||||
File file = LittleFS.open("/" + dst + ".json", "w");
|
||||
if (!file) {
|
||||
request->send(400, "text/plain", "Failed to create file");
|
||||
return;
|
||||
}
|
||||
file.print(request->getParam("json", true)->value());
|
||||
file.close();
|
||||
uint8_t mac[8];
|
||||
if (hex2mac(dst, mac)) {
|
||||
File file = LittleFS.open("/current/" + dst + ".json", "w");
|
||||
if (!file) {
|
||||
request->send(400, "text/plain", "Failed to create file");
|
||||
return;
|
||||
}
|
||||
file.print(request->getParam("json", true)->value());
|
||||
file.close();
|
||||
tagRecord *taginfo = nullptr;
|
||||
taginfo = tagRecord::findByMAC(mac);
|
||||
if (taginfo != nullptr) {
|
||||
taginfo->modeConfigJson = "{\"filename\":\"/" + dst + ".json\"}";
|
||||
uint32_t ttl = 0;
|
||||
if (request->hasParam("ttl", true)) {
|
||||
ttl = request->getParam("ttl", true)->value().toInt();
|
||||
}
|
||||
taginfo->modeConfigJson = "{\"filename\":\"/current/" + dst + ".json\",\"interval\":\"" + String(ttl) + "\"}";
|
||||
taginfo->contentMode = 19;
|
||||
taginfo->nextupdate = 0;
|
||||
wsSendTaginfo(mac, SYNC_USERCFG);
|
||||
|
||||
@@ -293,13 +293,19 @@
|
||||
{
|
||||
"key": "url",
|
||||
"name": "URL",
|
||||
"desc": "Full URL of the json template. See OpenEpaperLink wiki for the right json format",
|
||||
"desc": "Full URL of the json template. See OpenEpaperLink wiki for the right json format. Specify a url OR a filename",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"key": "filename",
|
||||
"name": "Filename",
|
||||
"desc": "Filename of the json template. See OpenEpaperLink wiki for the right json format. Specify a url OR a filename",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"key": "interval",
|
||||
"name": "Interval",
|
||||
"desc": "How often (in minutes) the template is being fetched. Minimum is 3 minutes.",
|
||||
"desc": "In case of an url, wow often (in minutes) the template is being fetched. Minimum is 3 minutes.",
|
||||
"type": "int"
|
||||
}
|
||||
]
|
||||
@@ -607,5 +613,11 @@
|
||||
"type": "text"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 21,
|
||||
"name": "Display access point info",
|
||||
"desc": "Displays information about the currently connected access point",
|
||||
"hwtype": [0, 1]
|
||||
}
|
||||
]
|
||||
@@ -271,10 +271,11 @@ function processTags(tagArray) {
|
||||
}
|
||||
|
||||
function updatecards() {
|
||||
if (servertimediff > 1000000000) servertimediff = 0;
|
||||
$('#taglist').querySelectorAll('[data-mac]').forEach(item => {
|
||||
let tagmac = item.dataset.mac;
|
||||
|
||||
if (item.dataset.lastseen && item.dataset.lastseen > 1672531200) {
|
||||
if (item.dataset.lastseen && item.dataset.lastseen > (Date.now() / 1000) - servertimediff - 30 * 24 * 3600 * 60) {
|
||||
let idletime = (Date.now() / 1000) - servertimediff - item.dataset.lastseen;
|
||||
$('#tag' + tagmac + ' .lastseen').innerHTML = "<span>last seen</span>" + displayTime(Math.floor(idletime)) + " ago";
|
||||
if ((Date.now() / 1000) - servertimediff - 600 > item.dataset.nextcheckin) {
|
||||
@@ -297,6 +298,8 @@ function updatecards() {
|
||||
if (item.dataset.nextcheckin > 1672531200 && parseInt(item.dataset.wakeupreason) == 0) {
|
||||
let nextcheckin = item.dataset.nextcheckin - ((Date.now() / 1000) - servertimediff);
|
||||
$('#tag' + tagmac + ' .nextcheckin').innerHTML = "<span>expected checkin</span>" + displayTime(Math.floor(nextcheckin));
|
||||
} else {
|
||||
$('#tag' + tagmac + ' .nextcheckin').innerHTML = "";
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -387,7 +390,7 @@ $('#cfgsave').onclick = function () {
|
||||
formData.append("alias", $('#cfgalias').value);
|
||||
|
||||
if (contentMode) {
|
||||
extraoptions.forEach(element => {
|
||||
extraoptions?.forEach(element => {
|
||||
if ($('#opt' + element.key)) {
|
||||
obj[element.key] = $('#opt' + element.key).value;
|
||||
}
|
||||
@@ -573,7 +576,7 @@ function contentselected() {
|
||||
}
|
||||
$('#paintbutton').style.display = (contentMode == 0 ? 'inline-block' : 'none');
|
||||
let extraoptions = contentDef?.param ?? null;
|
||||
extraoptions.forEach(element => {
|
||||
extraoptions?.forEach(element => {
|
||||
var label = document.createElement("label");
|
||||
label.innerHTML = element.name;
|
||||
label.setAttribute("for", 'opt' + element.key);
|
||||
@@ -629,7 +632,7 @@ function populateSelectTag(hwtype, capabilities) {
|
||||
var option;
|
||||
cardconfig.forEach(item => {
|
||||
var capcheck = item.capabilities ?? 0;
|
||||
var hwtypeArray = item.hwtype;
|
||||
var hwtypeArray = item.hwtype ?? [];
|
||||
if ((hwtypeArray.includes(hwtype) || tagTypes[hwtype].contentids.includes(item.id)) && (capabilities & capcheck || capcheck == 0)) {
|
||||
option = document.createElement("option");
|
||||
option.value = item.id;
|
||||
@@ -706,10 +709,15 @@ function processQueue() {
|
||||
}
|
||||
isProcessing = true;
|
||||
const { id, imageSrc } = imageQueue.shift();
|
||||
const hwtype = $('#tag' + id).dataset.hwtype;
|
||||
if (tagTypes[hwtype] && tagTypes[hwtype].busy) {
|
||||
imageQueue.push({ id, imageSrc });
|
||||
setTimeout(processQueue, 50);
|
||||
return;
|
||||
};
|
||||
|
||||
const canvas = $('#tag' + id + ' .tagimg');
|
||||
canvas.style.display = 'block';
|
||||
const hwtype = $('#tag' + id).dataset.hwtype;
|
||||
if (tagTypes[hwtype] && tagTypes[hwtype].busy) setTimeout(processQueue, 50);
|
||||
|
||||
fetch(imageSrc, { cache: "force-cache" })
|
||||
.then(response => response.arrayBuffer())
|
||||
@@ -719,11 +727,11 @@ function processQueue() {
|
||||
const ctx = canvas.getContext('2d');
|
||||
const imageData = ctx.createImageData(canvas.width, canvas.height);
|
||||
const data = new Uint8ClampedArray(buffer);
|
||||
if (data.length == 0) canvas.style.display = 'none';
|
||||
|
||||
if (tagTypes[hwtype].bpp == 16) {
|
||||
|
||||
const is16Bit = data.length == tagTypes[hwtype].width * tagTypes[hwtype].height * 2;
|
||||
for (let i = 0; i < tagTypes[hwtype].width * tagTypes[hwtype].height; i++) {
|
||||
for (let i = 0; i < min(tagTypes[hwtype].width * tagTypes[hwtype].height, data.length); i++) {
|
||||
const dataIndex = is16Bit ? i * 2 : i;
|
||||
const rgb = is16Bit ? (data[dataIndex] << 8) | data[dataIndex + 1] : data[dataIndex];
|
||||
|
||||
|
||||
41
ESP32_AP-Flasher/wwwroot/variables-demo.html
Normal file
41
ESP32_AP-Flasher/wwwroot/variables-demo.html
Normal file
@@ -0,0 +1,41 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Variables upload Form</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h3>demo Json variables</h3>
|
||||
<p>You can use this as an example how to change variables to be uses in a json template. Look at the html source for the workings. You can use the variables in any json template, using <pre>{variablename}</pre>. As soon as a variable is changed, the tag is being refreshed with the new info.</p>
|
||||
<p>
|
||||
Change one variable:<br>
|
||||
<form method="POST" action="/set_var">
|
||||
key: <input type="text" name="key" value="testkey"><br>
|
||||
value: <input type="text" name="val" value="MyCoolValue"><br>
|
||||
<input type="submit" value="submit"><br>
|
||||
</form>
|
||||
</p>
|
||||
<p>
|
||||
Change multiple variables, using json:<br>
|
||||
<form method="POST" action="/set_vars">
|
||||
<p>
|
||||
<label for="vars">Place the json string here</label><br>
|
||||
<textarea id="vars" name="json" style="width:500px;height:80px;">
|
||||
{ "temperature": 28.5,
|
||||
"door": "open",
|
||||
"testkey": "MyCoolValue"
|
||||
}
|
||||
</textarea>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<input type="submit" value="submit json">
|
||||
</p>
|
||||
|
||||
</form>
|
||||
</p>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
Reference in New Issue
Block a user