diff --git a/ESP32_AP-Flasher/data/tagtypes/00.json b/ESP32_AP-Flasher/data/tagtypes/00.json
index 711498b5..27035fcc 100644
--- a/ESP32_AP-Flasher/data/tagtypes/00.json
+++ b/ESP32_AP-Flasher/data/tagtypes/00.json
@@ -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 ] }
+ ]
}
}
diff --git a/ESP32_AP-Flasher/data/tagtypes/01.json b/ESP32_AP-Flasher/data/tagtypes/01.json
index 1843494f..34546bf0 100644
--- a/ESP32_AP-Flasher/data/tagtypes/01.json
+++ b/ESP32_AP-Flasher/data/tagtypes/01.json
@@ -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 ] }
+ ]
}
}
diff --git a/ESP32_AP-Flasher/data/tagtypes/E0.json b/ESP32_AP-Flasher/data/tagtypes/E0.json
index 5632e359..99e04246 100644
--- a/ESP32_AP-Flasher/data/tagtypes/E0.json
+++ b/ESP32_AP-Flasher/data/tagtypes/E0.json
@@ -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" ] }
+ ]
+ }
}
diff --git a/ESP32_AP-Flasher/include/contentmanager.h b/ESP32_AP-Flasher/include/contentmanager.h
index c8e3d689..99adb942 100644
--- a/ESP32_AP-Flasher/include/contentmanager.h
+++ b/ESP32_AP-Flasher/include/contentmanager.h
@@ -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);
diff --git a/ESP32_AP-Flasher/include/makeimage.h b/ESP32_AP-Flasher/include/makeimage.h
index 64b6fcfc..8d67fd9e 100644
--- a/ESP32_AP-Flasher/include/makeimage.h
+++ b/ESP32_AP-Flasher/include/makeimage.h
@@ -3,6 +3,8 @@
#pragma once
+extern TFT_eSPI tft;
+
struct imgParam {
bool hasRed;
uint8_t dataType;
diff --git a/ESP32_AP-Flasher/include/tag_db.h b/ESP32_AP-Flasher/include/tag_db.h
index ccd58f19..7ee6386a 100644
--- a/ESP32_AP-Flasher/include/tag_db.h
+++ b/ESP32_AP-Flasher/include/tag_db.h
@@ -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 tagDB;
extern std::unordered_map hwtype;
+extern std::unordered_map 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)
\ No newline at end of file
+#pragma pack(pop)
diff --git a/ESP32_AP-Flasher/src/contentmanager.cpp b/ESP32_AP-Flasher/src/contentmanager.cpp
index 887022dc..5740895f 100644
--- a/ESP32_AP-Flasher/src/contentmanager.cpp
+++ b/ESP32_AP-Flasher/src/contentmanager.cpp
@@ -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();
+ if (cfgobj["filename"]) {
+ String jsonfile = cfgobj["filename"].as();
+ File file = contentFS->open(jsonfile, "r");
+ if (file) {
+ size_t fileSize = file.size();
+ std::unique_ptr 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(), taginfo, imageParams);
} else {
wsErr("error opening file " + cfgobj["filename"].as());
}
@@ -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();
@@ -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(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(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();
if (count > 99) font = loc["fonts"][1].as();
@@ -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();
struct tm *datum = localtime(&weatherday);
- drawString(spr, String(languageDaysShort[getCurrentLanguage()][datum->tm_wday]), dag * loc["column"][1].as() + loc["day"][0].as(), loc["day"][1], loc["day"][2], TC_DATUM, PAL_BLACK);
+ drawString(spr, String(languageDaysShort[getCurrentLanguage()][datum->tm_wday]), dag * loc["column"][1].as() + loc["day"][0].as(), loc["day"][1], loc["day"][2], TC_DATUM, TFT_BLACK);
uint8_t weathercode = doc["daily"]["weathercode"][dag].as();
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() + dag * loc["column"][1].as(), 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() + dag * loc["column"][1].as(), 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() + dag * loc["column"][1].as(), loc["wind"][1], "/fonts/weathericons.ttf", TC_DATUM, TFT_BLACK, loc["icon"][2]);
int8_t tmin = round(doc["daily"]["temperature_2m_min"][dag].as());
int8_t tmax = round(doc["daily"]["temperature_2m_max"][dag].as());
@@ -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());
if (rain > 0) {
- drawString(spr, String(rain) + "mm", dag * loc["column"][1].as() + loc["rain"][0].as(), loc["rain"][1], "", TC_DATUM, (rain > 10 ? PAL_RED : PAL_BLACK));
+ drawString(spr, String(rain) + "mm", dag * loc["column"][1].as() + loc["rain"][0].as(), loc["rain"][1], "", TC_DATUM, (rain > 10 ? TFT_RED : TFT_BLACK));
}
}
- drawString(spr, String(tmin) + " ", dag * loc["column"][1].as() + loc["day"][0].as(), loc["day"][4], "", TR_DATUM, (tmin < 0 ? PAL_RED : PAL_BLACK));
- drawString(spr, String(" ") + String(tmax), dag * loc["column"][1].as() + loc["day"][0].as(), loc["day"][4], "", TL_DATUM, (tmax < 0 ? PAL_RED : PAL_BLACK));
- drawString(spr, String(" ") + String(wind), dag * loc["column"][1].as() + loc["day"][0].as(), loc["day"][3], "", TL_DATUM, (wind > 5 ? PAL_RED : PAL_BLACK));
+ drawString(spr, String(tmin) + " ", dag * loc["column"][1].as() + loc["day"][0].as(), loc["day"][4], "", TR_DATUM, (tmin < 0 ? TFT_RED : TFT_BLACK));
+ drawString(spr, String(" ") + String(tmax), dag * loc["column"][1].as() + loc["day"][0].as(), loc["day"][4], "", TL_DATUM, (tmax < 0 ? TFT_RED : TFT_BLACK));
+ drawString(spr, String(" ") + String(wind), dag * loc["column"][1].as() + loc["day"][0].as(), 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(), i, PAL_BLACK);
+ spr.drawPixel(dag * loc["column"][1].as(), 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() + i * loc["line"][2].as(), 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() + i * loc["line"][2].as(), 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() + i * loc["line"][2].as());
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() + loc["bars"][0].as(), loc["bars"][1].as() - (value - 70), loc["bars"][2], (value - 70), (value > 130 ? PAL_RED : PAL_BLACK));
+ spr.fillRect(i * loc["cols"][2].as() + loc["bars"][0].as(), loc["bars"][1].as() - (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() + loc["cols"][0].as(), 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();
+ 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(), textArray[1].as(), textArray[3], align, getColor(color), size);
+ String bgcolorstr = textArray[7].as();
+
+ uint16_t bgcolor = (bgcolorstr.length() > 0) ? getColor(bgcolorstr) : TFT_WHITE;
+ drawString(spr, textArray[2], textArray[0].as(), textArray[1].as(), 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(), boxArray[1].as(), boxArray[2].as(), boxArray[3].as(), getColor(color));
+ spr.fillRect(boxArray[0].as(), boxArray[1].as(), boxArray[2].as(), boxArray[3].as(), getColor(boxArray[4]));
} 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));
+ spr.drawLine(lineArray[0].as(), lineArray[1].as(), lineArray[2].as(), lineArray[3].as(), getColor(lineArray[4]));
} 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));
+ spr.fillTriangle(lineArray[0].as(), lineArray[1].as(), lineArray[2].as(), lineArray[3].as(), lineArray[4].as(), lineArray[5].as(), 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;
- }
- }
-}
diff --git a/ESP32_AP-Flasher/src/ips_display.cpp b/ESP32_AP-Flasher/src/ips_display.cpp
index e37aa41c..7d5043f4 100644
--- a/ESP32_AP-Flasher/src/ips_display.cpp
+++ b/ESP32_AP-Flasher/src/ips_display.cpp
@@ -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) {
diff --git a/ESP32_AP-Flasher/src/main.cpp b/ESP32_AP-Flasher/src/main.cpp
index 255b46fb..22520bc3 100644
--- a/ESP32_AP-Flasher/src/main.cpp
+++ b/ESP32_AP-Flasher/src/main.cpp
@@ -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();
diff --git a/ESP32_AP-Flasher/src/makeimage.cpp b/ESP32_AP-Flasher/src/makeimage.cpp
index cede5774..c6604037 100644
--- a/ESP32_AP-Flasher/src/makeimage.cpp
+++ b/ESP32_AP-Flasher/src/makeimage.cpp
@@ -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) {
diff --git a/ESP32_AP-Flasher/src/newproto.cpp b/ESP32_AP-Flasher/src/newproto.cpp
index 92d8080c..ea65856b 100644
--- a/ESP32_AP-Flasher/src/newproto.cpp
+++ b/ESP32_AP-Flasher/src/newproto.cpp
@@ -5,7 +5,6 @@
#include
#include "storage.h"
#include
-#include
#include
#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, "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, "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, "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);
diff --git a/ESP32_AP-Flasher/src/serialap.cpp b/ESP32_AP-Flasher/src/serialap.cpp
index 51674531..075043f7 100644
--- a/ESP32_AP-Flasher/src/serialap.cpp
+++ b/ESP32_AP-Flasher/src/serialap.cpp
@@ -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() {
diff --git a/ESP32_AP-Flasher/src/tag_db.cpp b/ESP32_AP-Flasher/src/tag_db.cpp
index 7210bc04..66b8cfa3 100644
--- a/ESP32_AP-Flasher/src/tag_db.cpp
+++ b/ESP32_AP-Flasher/src/tag_db.cpp
@@ -11,6 +11,7 @@
#include "storage.h"
std::vector tagDB;
+std::unordered_map varDB;
std::unordered_map 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;
+ }
+ }
+}
diff --git a/ESP32_AP-Flasher/src/web.cpp b/ESP32_AP-Flasher/src/web.cpp
index 1b423d30..f98bd849 100644
--- a/ESP32_AP-Flasher/src/web.cpp
+++ b/ESP32_AP-Flasher/src/web.cpp
@@ -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());
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()) {
+ std::string key = kv.key().c_str();
+ String val = kv.value().as();
+ 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);
diff --git a/ESP32_AP-Flasher/wwwroot/content_cards.json b/ESP32_AP-Flasher/wwwroot/content_cards.json
index 08dc92b5..07092b75 100644
--- a/ESP32_AP-Flasher/wwwroot/content_cards.json
+++ b/ESP32_AP-Flasher/wwwroot/content_cards.json
@@ -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]
}
]
\ No newline at end of file
diff --git a/ESP32_AP-Flasher/wwwroot/main.js b/ESP32_AP-Flasher/wwwroot/main.js
index b1694376..fb0ef5db 100644
--- a/ESP32_AP-Flasher/wwwroot/main.js
+++ b/ESP32_AP-Flasher/wwwroot/main.js
@@ -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 = "last seen" + 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 = "expected checkin" + 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];
diff --git a/ESP32_AP-Flasher/wwwroot/variables-demo.html b/ESP32_AP-Flasher/wwwroot/variables-demo.html
new file mode 100644
index 00000000..fe0a71d7
--- /dev/null
+++ b/ESP32_AP-Flasher/wwwroot/variables-demo.html
@@ -0,0 +1,41 @@
+
+
+
+
+
+ Variables upload Form
+
+
+
+ demo Json variables
+ 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
{variablename}. As soon as a variable is changed, the tag is being refreshed with the new info.
+
+ Change one variable:
+
+
+
+ Change multiple variables, using json:
+
+
+
+
+