diff --git a/esp32_fw/data/fonts/GillSC16.vlw b/esp32_fw/data/fonts/GillSC16.vlw new file mode 100644 index 00000000..04ebc30c Binary files /dev/null and b/esp32_fw/data/fonts/GillSC16.vlw differ diff --git a/esp32_fw/data/fonts/GillSC20.vlw b/esp32_fw/data/fonts/GillSC20.vlw new file mode 100644 index 00000000..80d75f5e Binary files /dev/null and b/esp32_fw/data/fonts/GillSC20.vlw differ diff --git a/esp32_fw/data/fonts/weathericons50.vlw b/esp32_fw/data/fonts/weathericons50.vlw deleted file mode 100644 index 4019f131..00000000 Binary files a/esp32_fw/data/fonts/weathericons50.vlw and /dev/null differ diff --git a/esp32_fw/data/fonts/weathericons70.vlw b/esp32_fw/data/fonts/weathericons70.vlw new file mode 100644 index 00000000..1807f1ec Binary files /dev/null and b/esp32_fw/data/fonts/weathericons70.vlw differ diff --git a/esp32_fw/data/www/index.html b/esp32_fw/data/www/index.html index 81c2c6da..0cfbbcfa 100644 --- a/esp32_fw/data/www/index.html +++ b/esp32_fw/data/www/index.html @@ -30,6 +30,8 @@ + + diff --git a/esp32_fw/data/www/main.js b/esp32_fw/data/www/main.js index 504bd8cf..7e29a4bd 100644 --- a/esp32_fw/data/www/main.js +++ b/esp32_fw/data/www/main.js @@ -1,6 +1,13 @@ const $ = document.querySelector.bind(document); -const contentModes = ["Static image", "Current date", "Counting days", "Counting hours", "Current weather", "Firmware update", "Memo text", "Image url"]; +const WAKEUP_REASON_TIMED = 0; +const WAKEUP_REASON_GPIO = 2; +const WAKEUP_REASON_NFC = 3; +const WAKEUP_REASON_FIRSTBOOT = 0xFC; +const WAKEUP_REASON_NETWORK_SCAN = 0xFD; +const WAKEUP_REASON_WDT_RESET = 0xFE; + +const contentModes = ["Static image", "Current date", "Counting days", "Counting hours", "Current weather", "Firmware update", "Memo text", "Image url", "Weather forecast","RSS feed"]; const models = ["1.54\" 152x152px", "2.9\" 296x128px", "4.2\" 400x300px"]; const contentModeOptions = []; contentModeOptions[0] = ["filename","timetolive"]; @@ -11,6 +18,8 @@ contentModeOptions[4] = ["location"]; contentModeOptions[5] = ["filename"]; contentModeOptions[6] = ["text"]; contentModeOptions[7] = ["url","interval"]; +contentModeOptions[8] = ["location"]; +contentModeOptions[9] = ["title", "url", "interval"]; const imageQueue = []; let isProcessing = false; @@ -123,6 +132,28 @@ function processTags(tagArray) { div.dataset.hash = element.hash; $('#tag' + tagmac + ' .warningicon').style.display = 'none'; $('#tag' + tagmac).style.background = "inherit"; + switch (element.wakeupReason) { + case WAKEUP_REASON_TIMED: + break; + case WAKEUP_REASON_GPIO: + $('#tag' + tagmac + ' .nextcheckin').innerHTML = "GPIO wakeup" + break; + case WAKEUP_REASON_NFC: + $('#tag' + tagmac + ' .nextcheckin').innerHTML = "NFC wakeup" + break; + case WAKEUP_REASON_FIRSTBOOT: + $('#tag' + tagmac + ' .nextcheckin').innerHTML = "First boot" + $('#tag' + tagmac).style.background = "purple"; + break; + case WAKEUP_REASON_NETWORK_SCAN: + $('#tag' + tagmac + ' .nextcheckin').innerHTML = "Network scan" + $('#tag' + tagmac).style.background = "green"; + break; + case WAKEUP_REASON_WDT_RESET: + $('#tag' + tagmac + ' .nextcheckin').innerHTML = "Watchdog reset!" + $('#tag' + tagmac).style.background = "red"; + break; + } $('#tag' + tagmac + ' .pendingicon').style.display = (element.pending ? 'inline-block' : 'none'); div.classList.add("tagflash"); (function(tagmac) { diff --git a/esp32_fw/include/commstructs.h b/esp32_fw/include/commstructs.h index 7918df07..a52e6c4b 100644 --- a/esp32_fw/include/commstructs.h +++ b/esp32_fw/include/commstructs.h @@ -22,10 +22,12 @@ struct blockData { #define SOLUM_29_033 1 #define SOLUM_42_033 2 -#define WAKEUP_REASON_TIMED 0 -#define WAKEUP_REASON_BOOTUP 1 -#define WAKEUP_REASON_GPIO 2 -#define WAKEUP_REASON_NFC 3 +#define WAKEUP_REASON_TIMED 0 +#define WAKEUP_REASON_GPIO 2 +#define WAKEUP_REASON_NFC 3 +#define WAKEUP_REASON_FIRSTBOOT 0xFC +#define WAKEUP_REASON_NETWORK_SCAN 0xFD +#define WAKEUP_REASON_WDT_RESET 0xFE struct AvailDataReq { uint8_t checksum; @@ -49,6 +51,11 @@ struct espAvailDataReq { #define DATATYPE_IMGRAW 2 #define DATATYPE_UPDATE 3 +#define EPD_LUT_DEFAULT 0 +#define EPD_LUT_NO_REPEATS 1 +#define EPD_LUT_FAST_NO_REDS 2 +#define EPD_LUT_FAST 3 + struct AvailDataInfo { uint8_t checksum; uint64_t dataVer; // MD5 of potential traffic diff --git a/esp32_fw/include/contentmanager.h b/esp32_fw/include/contentmanager.h index 02b58235..ef6a41d0 100644 --- a/esp32_fw/include/contentmanager.h +++ b/esp32_fw/include/contentmanager.h @@ -6,6 +6,15 @@ #include "tag_db.h" #include +struct contentTypes { + uint16_t id; + String name; + uint16_t tagTypes; + void (*functionname)(); + String description; + String optionList; +}; + void contentRunner(); void drawNew(uint8_t mac[8], bool buttonPressed, tagRecord *&taginfo); bool updateTagImage(String &filename, uint8_t *dst, uint16_t nextCheckin); @@ -14,8 +23,10 @@ void initSprite(TFT_eSprite &spr, int w, int h); void drawDate(String &filename, tagRecord *&taginfo); void drawNumber(String &filename, int32_t count, int32_t thresholdred, tagRecord *&taginfo); void drawWeather(String &filename, String location, tagRecord *&taginfo); +void drawForecast(String &filename, String location, tagRecord *&taginfo); void drawIdentify(String &filename, tagRecord *&taginfo); bool getImgURL(String &filename, String URL, time_t fetched); +bool getRSSfeed(String &filename, String URL, String title, tagRecord *&taginfo); char *formatHttpDate(time_t t); String urlEncode(const char *msg); int windSpeedToBeaufort(float windSpeed); diff --git a/esp32_fw/include/tag_db.h b/esp32_fw/include/tag_db.h index 4e8f147b..3e7e713e 100644 --- a/esp32_fw/include/tag_db.h +++ b/esp32_fw/include/tag_db.h @@ -18,7 +18,7 @@ class tagRecord { public: uint16_t nextCheckinpending; - tagRecord() : mac{0}, alias(""), lastseen(0), nextupdate(0), contentMode(0), pending(false), md5{0}, md5pending{0}, CheckinInMinPending(0), expectedNextCheckin(0), modeConfigJson(""), LQI(0), RSSI(0), temperature(0), batteryMv(0), hwType(0), wakeupReason(0), capabilities(0) {} + tagRecord() : mac{0}, alias(""), lastseen(0), nextupdate(0), contentMode(0), pending(false), md5{0}, md5pending{0}, expectedNextCheckin(0), modeConfigJson(""), LQI(0), RSSI(0), temperature(0), batteryMv(0), hwType(0), wakeupReason(0), capabilities(0), lastfullupdate(0) {} uint8_t mac[6]; String alias; @@ -28,7 +28,6 @@ class tagRecord { bool pending; uint8_t md5[16]; uint8_t md5pending[16]; - uint16_t CheckinInMinPending; uint32_t expectedNextCheckin; String modeConfigJson; uint8_t LQI; @@ -37,7 +36,8 @@ class tagRecord { uint16_t batteryMv; uint8_t hwType; uint8_t wakeupReason; - uint8_t capabilities; + uint8_t capabilities; + uint32_t lastfullupdate; static tagRecord* findByMAC(uint8_t mac[6]); }; diff --git a/esp32_fw/platformio.ini b/esp32_fw/platformio.ini index 77108edd..e92c1d78 100644 --- a/esp32_fw/platformio.ini +++ b/esp32_fw/platformio.ini @@ -24,5 +24,7 @@ lib_deps = bblanchon/ArduinoJson bodmer/TFT_eSPI https://github.com/Bodmer/TJpg_Decoder.git + https://github.com/garretlab/shoddyxml2 + https://github.com/Bodmer/U8g2_for_TFT_eSPI upload_port = COM12 monitor_port = COM12 diff --git a/esp32_fw/src/contentmanager.cpp b/esp32_fw/src/contentmanager.cpp index fb5e96df..a5d0fdf4 100644 --- a/esp32_fw/src/contentmanager.cpp +++ b/esp32_fw/src/contentmanager.cpp @@ -6,8 +6,10 @@ #include "newproto.h" #include #include +#include #include +#include "U8g2_for_TFT_eSPI.h" #include "commstructs.h" #include "makeimage.h" #include "web.h" @@ -21,6 +23,8 @@ enum contentModes { Firmware, Memo, ImageUrl, + Forecast, + RSSFeed, }; @@ -122,6 +126,13 @@ void drawNew(uint8_t mac[8], bool buttonPressed, tagRecord *&taginfo) { updateTagImage(filename, mac, 15); break; + case Forecast: + + drawForecast(filename, cfgobj["location"], taginfo); + taginfo->nextupdate = now + 3 * 3600; + updateTagImage(filename, mac, 15); + break; + case Firmware: filename = cfgobj["filename"].as(); @@ -156,6 +167,16 @@ void drawNew(uint8_t mac[8], bool buttonPressed, tagRecord *&taginfo) { taginfo->nextupdate = now + 300; } break; + + case RSSFeed: + + if (getRSSfeed(filename, cfgobj["url"], cfgobj["title"], taginfo)) { + taginfo->nextupdate = now + 60 * (cfgobj["interval"].as() < 5 ? 5 : cfgobj["interval"].as()); + updateTagImage(filename, mac, cfgobj["interval"].as()); + } else { + taginfo->nextupdate = now + 300; + } + break; } taginfo->modeConfigJson = doc.as(); @@ -169,10 +190,10 @@ bool updateTagImage(String &filename, uint8_t *dst, uint16_t nextCheckin) { void drawString(TFT_eSprite &spr, String content, uint16_t posx, uint16_t posy, String font, byte align,uint16_t color) { // drawString(spr,"test",100,10,"bahnschrift30",TC_DATUM,TFT_RED); spr.setTextDatum(align); - spr.loadFont(font, LittleFS); + if (font != "") spr.loadFont(font, LittleFS); spr.setTextColor(color, TFT_WHITE); spr.drawString(content, posx, posy); - spr.unloadFont(); + if (font != "") spr.unloadFont(); } void initSprite(TFT_eSprite &spr, int w, int h) { @@ -316,8 +337,6 @@ void drawWeather(String &filename, String location, tagRecord *&taginfo) { weatherIcons[2] = "\0uf086"; } - String windIcons[] = {"\uf0b7", "\uf0b8", "\uf0b9", "\uf0ba", "\uf0bb", "\uf0bc", "\uf0bd", "\uf0be", "\uf0bf", "\uf0c0", "\uf0c1", "\uf0c2", "\uf0c3"}; - doc.clear(); LittleFS.begin(); @@ -327,33 +346,27 @@ void drawWeather(String &filename, String location, tagRecord *&taginfo) { initSprite(spr, 296, 128); - drawString(spr, location, 10, 10, "fonts/bahnschrift30"); + drawString(spr, location, 5, 5, "fonts/bahnschrift30"); + drawString(spr, String(wind), 280, 5, "fonts/bahnschrift30", TR_DATUM, (wind > 4 ? TFT_RED : TFT_BLACK)); char tmpOutput[5]; dtostrf(temperature, 2, 1, tmpOutput); drawString(spr, String(tmpOutput), 5, 65, "fonts/bahnschrift70", TL_DATUM, (temperature < 0 ? TFT_RED : TFT_BLACK)); - spr.loadFont("fonts/weathericons78", LittleFS); + spr.loadFont("fonts/weathericons70", LittleFS); if (weathercode == 55 || weathercode == 65 || weathercode == 75 || weathercode == 82 || weathercode == 86 || weathercode == 95 || weathercode == 99) { spr.setTextColor(TFT_RED, TFT_WHITE); } else { spr.setTextColor(TFT_BLACK, TFT_WHITE); } - spr.setCursor(185, 20); + + spr.setCursor(185, 32); spr.printToSprite(weatherIcons[weathercode]); spr.unloadFont(); spr.loadFont("fonts/weathericons30", LittleFS); - if (wind > 4) { - spr.setTextColor(TFT_RED, TFT_WHITE); - } else { - spr.setTextColor(TFT_BLACK, TFT_WHITE); - } - spr.setCursor(255, 0); - spr.printToSprite(windIcons[wind]); - spr.setTextColor(TFT_BLACK, TFT_WHITE); - spr.setCursor(230, -5); + spr.setCursor(235, -3); spr.printToSprite(windDirectionIcon(winddirection)); if (weathercode > 10) { spr.setTextColor(TFT_RED, TFT_WHITE); @@ -381,21 +394,16 @@ void drawWeather(String &filename, String location, tagRecord *&taginfo) { } else { spr.setTextColor(TFT_BLACK, TFT_WHITE); } - spr.setCursor(35, 25); + + spr.setCursor(30, 33); spr.printToSprite(weatherIcons[weathercode]); spr.unloadFont(); - spr.loadFont("fonts/weathericons30", LittleFS); - if (wind > 4) { - spr.setTextColor(TFT_RED, TFT_WHITE); - } else { - spr.setTextColor(TFT_BLACK, TFT_WHITE); - } - spr.setCursor(115, -5); - spr.printToSprite(windIcons[wind]); + drawString(spr, String(wind), 140, 10, "fonts/bahnschrift30", TR_DATUM, (wind > 4 ? TFT_RED : TFT_BLACK)); + spr.loadFont("fonts/weathericons30", LittleFS); spr.setTextColor(TFT_BLACK, TFT_WHITE); - spr.setCursor(90, -5); + spr.setCursor(100, -2); spr.printToSprite(windDirectionIcon(winddirection)); if (weathercode > 10) { spr.setTextColor(TFT_RED, TFT_WHITE); @@ -413,6 +421,109 @@ void drawWeather(String &filename, String location, tagRecord *&taginfo) { http.end(); } +void drawForecast(String &filename, String location, tagRecord *&taginfo) { + TFT_eSPI tft = TFT_eSPI(); + TFT_eSprite spr = TFT_eSprite(&tft); + + wsLog("get weather"); + HTTPClient http; + http.begin("https://geocoding-api.open-meteo.com/v1/search?name=" + urlEncode(location.c_str()) + "&count=1"); + http.setTimeout(5000); // timeout in ms + int httpCode = http.GET(); + if (httpCode == 200) { + DynamicJsonDocument doc(2000); + DeserializationError error = deserializeJson(doc, http.getStream()); + http.end(); + + http.begin("https://api.open-meteo.com/v1/forecast?latitude=" + doc["results"][0]["latitude"].as() + "&longitude=" + doc["results"][0]["longitude"].as() + "&daily=weathercode,temperature_2m_max,temperature_2m_min,precipitation_sum,windspeed_10m_max,winddirection_10m_dominant&windspeed_unit=ms&timeformat=unixtime&timezone=" + doc["results"][0]["timezone"].as()); + + doc.clear(); + http.setTimeout(5000); // timeout in ms + int httpCode = http.GET(); + + if (httpCode == 200) { + StaticJsonDocument<500> filter; + filter["daily"]["time"][0] = true; + filter["daily"]["weathercode"][0] = true; + filter["daily"]["temperature_2m_max"][0] = true; + filter["daily"]["temperature_2m_min"][0] = true; + filter["daily"]["precipitation_sum"][0] = true; + filter["daily"]["windspeed_10m_max"][0] = true; + filter["daily"]["winddirection_10m_dominant"][0] = true; + + //DeserializationError error = deserializeJson(doc, http.getString(), DeserializationOption::Filter(filter)); + DeserializationError error = deserializeJson(doc, http.getString()); + if (error) { + Serial.println(F("deserializeJson() failed: ")); + Serial.println(error.c_str()); + } + + static const char *weekday_name[] = {"ZO", "MA", "DI", "WO", "DO", "VR", "ZA"}; + + String weatherIcons[] = {"\uf00d", "\uf00c", "\uf002", "\uf013", "\uf013", "\uf014", "-", "-", "\uf014", "-", "-", + "\uf01a", "-", "\uf01a", "-", "\uf01a", "\uf017", "\uf017", "-", "-", "-", + "\uf019", "-", "\uf019", "-", "\uf019", "\uf015", "\uf015", "-", "-", "-", + "\uf01b", "-", "\uf01b", "-", "\uf01b", "-", "\uf076", "-", "-", "\uf01a", + "\uf01a", "\uf01a", "-", "-", "\uf064", "\uf064", "-", "-", "-", "-", + "-", "-", "-", "-", "\uf01e", "\uf01d", "-", "-", "\uf01e"}; + + LittleFS.begin(); + tft.setTextWrap(false, false); + + if (taginfo->hwType == SOLUM_29_033) { + initSprite(spr, 296, 128); + + spr.setTextFont(2); + spr.setTextColor(TFT_BLACK, TFT_WHITE); + spr.drawString(location, 5, 0); + + for (uint8_t dag = 0; dag < 5; dag++) { + time_t weatherday = doc["daily"]["time"][dag].as(); + struct tm *datum = localtime(&weatherday); + drawString(spr, String(weekday_name[datum->tm_wday]), dag * 59 + 30, 18, "fonts/twbold20", TC_DATUM, TFT_BLACK); + + uint8_t weathercode = doc["daily"]["weathercode"][dag].as(); + if (weathercode > 40) weathercode -= 40; + + spr.loadFont("fonts/weathericons30", LittleFS); + if (weathercode == 55 || weathercode == 65 || weathercode == 75 || weathercode == 82 || weathercode == 86 || weathercode == 95 || weathercode == 99) { + spr.setTextColor(TFT_RED, TFT_WHITE); + } else { + spr.setTextColor(TFT_BLACK, TFT_WHITE); + } + spr.setTextDatum(TL_DATUM); + spr.setCursor(12 + dag * 59, 58); + spr.printToSprite(weatherIcons[weathercode]); + + spr.setTextColor(TFT_BLACK, TFT_WHITE); + spr.setCursor(17 + dag * 59, 27); + spr.printToSprite(windDirectionIcon(doc["daily"]["winddirection_10m_dominant"][dag])); + spr.unloadFont(); + + int8_t tmin = round(doc["daily"]["temperature_2m_min"][dag].as()); + int8_t tmax = round(doc["daily"]["temperature_2m_max"][dag].as()); + uint8_t wind = windSpeedToBeaufort(doc["daily"]["windspeed_10m_max"][dag].as()); + + spr.loadFont("fonts/GillSC20", LittleFS); + drawString(spr, String(tmin) + " ", dag * 59 + 30, 108, "", TR_DATUM, (tmin < 0 ? TFT_RED : TFT_BLACK)); + drawString(spr, String(" ") + String(tmax), dag * 59 + 30, 108, "", TL_DATUM, (tmax < 0 ? TFT_RED : TFT_BLACK)); + drawString(spr, String(" ") + String(wind), dag * 59 + 30, 43, "", TL_DATUM, (wind > 5 ? TFT_RED : TFT_BLACK)); + spr.unloadFont(); + if (dag>0) { + for (int i = 20; i < 128; i+=3) { + spr.drawPixel(dag * 59, i, TFT_BLACK); + } + } + } + + } + spr2grays(spr, spr.width(), spr.height(), filename); + spr.deleteSprite(); + } + } + http.end(); +} + void drawIdentify(String &filename, tagRecord *&taginfo) { TFT_eSPI tft = TFT_eSPI(); @@ -463,6 +574,62 @@ bool getImgURL(String &filename, String URL, time_t fetched) { return (httpCode == 200 || httpCode == 304); } +rssClass reader; + +bool getRSSfeed(String &filename, String URL, String title, tagRecord *&taginfo) { + // https://github.com/garretlab/shoddyxml2 + + // http://feeds.feedburner.com/tweakers/nieuws + // https://www.nu.nl/rss/Algemeen + + Serial.println("RSS feed"); + struct tm timeInfo; + char header[32]; + getLocalTime(&timeInfo); + sprintf(header, "%02d-%02d-%04d %02d:%02d", timeInfo.tm_mday, timeInfo.tm_mon + 1, timeInfo.tm_year + 1900, timeInfo.tm_hour, timeInfo.tm_min); + + const char *url = URL.c_str(); + const char *tag = "title"; + const int rssArticleSize = 128; + const int rssNumArticle = 8; + + TFT_eSPI tft = TFT_eSPI(); + TFT_eSprite spr = TFT_eSprite(&tft); + U8g2_for_TFT_eSPI u8f; + u8f.begin(spr); + + if (taginfo->hwType == SOLUM_29_033) { + initSprite(spr, 296, 128); + if (title=="" || title=="null") title="RSS feed"; + drawString(spr, title, 5, 3, "fonts/bahnschrift20", TL_DATUM, TFT_RED); + + u8f.setFont(u8g2_font_glasstown_nbp_tr); // select u8g2 font from here: https://github.com/olikraus/u8g2/wiki/fntlistall + u8f.setFontMode(0); + u8f.setFontDirection(0); + u8f.setForegroundColor(TFT_BLACK); + u8f.setBackgroundColor(TFT_WHITE); + u8f.setCursor(220, 20); + u8f.print(header); + + // u8g2_font_nine_by_five_nbp_tr + // u8g2_font_7x14_tr + // u8g2_font_crox1h_tr + // u8g2_font_miranda_nbp_tr + u8f.setFont(u8g2_font_glasstown_nbp_tr); // select u8g2 font from here: https://github.com/olikraus/u8g2/wiki/fntlistall + + int n = reader.getArticles(url, tag, rssArticleSize, rssNumArticle); + for (int i = 0; i < n; i++) { + u8f.setCursor(5, 34+i*13); // start writing at this position + u8f.print(reader.itemData[i]); + } + } + + spr2grays(spr, spr.width(), spr.height(), filename); + spr.deleteSprite(); + + return true; +} + char *formatHttpDate(time_t t) { static char buf[40]; struct tm *timeinfo; diff --git a/esp32_fw/src/makeimage.cpp b/esp32_fw/src/makeimage.cpp index 54e8660d..2a35bcbe 100644 --- a/esp32_fw/src/makeimage.cpp +++ b/esp32_fw/src/makeimage.cpp @@ -152,6 +152,12 @@ void spr2grays(TFT_eSprite &spr, long w, long h, String &fileout) { f_out.write(0x00); } + const int dither_matrix[4][4] = { + {1, 9, 3, 11}, + {13, 5, 15, 7}, + {4, 12, 2, 10}, + {0, 8, 14, 6}}; + while (numRows--) { uint32_t pixelValsPackedSoFar = 0, numPixelsPackedSoFar = 0, valSoFar = 0, bytesIn = 0, bytesOut = 0, bitsSoFar = 0; @@ -170,8 +176,10 @@ void spr2grays(TFT_eSprite &spr, long w, long h, String &fileout) { uint8_t green = ((color565 >> 5) & 0x3F) * 4; uint8_t blue = (color565 & 0x1F) * 8; - if (dither) - ditherFudge = (rand() % 255 - 127) / (int)numGrays; + if (dither) { + // ditherFudge = (rand() % 255 - 127) / (int)numGrays; // -64 to 64 + ditherFudge = (dither_matrix[numRows % 4][c % 4] - 8) * 24 / (int)numGrays; + } for (i = 0; i < hdr.numColors; i++) { int64_t dist = 0; @@ -253,7 +261,7 @@ void bmp2grays(String filein, String fileout) { struct BitmapFileHeader hdr; enum EinkClut clutType; uint8_t clut[256][3]; - bool dither = true; + bool dither = false; int skipBytes; srand(0); diff --git a/esp32_fw/src/newproto.cpp b/esp32_fw/src/newproto.cpp index efad9f80..735d9782 100644 --- a/esp32_fw/src/newproto.cpp +++ b/esp32_fw/src/newproto.cpp @@ -124,7 +124,8 @@ bool prepareDataAvail(String* filename, uint8_t dataType, uint8_t* dst, uint16_t md5.getBytes(md5bytes); } - uint16_t attempts = 60; + uint16_t attempts = 60 * 24; + uint8_t lut = EPD_LUT_DEFAULT; uint8_t src[8]; *((uint64_t*)src) = swap64(*((uint64_t*)dst)); uint8_t mac[6]; @@ -141,9 +142,13 @@ bool prepareDataAvail(String* filename, uint8_t dataType, uint8_t* dst, uint16_t time_t now; time(&now); + time_t last_midnight = now - now % (24 * 60 * 60) + 3 * 3600; // somewhere in the middle of the night + if (taginfo->lastfullupdate > last_midnight) lut = EPD_LUT_NO_REPEATS; // fast updates during the day + /* uint16_t minutesUntilNextCheckin = 0; if (taginfo->expectedNextCheckin > now) minutesUntilNextCheckin = (taginfo->expectedNextCheckin - now) / 60; attempts += minutesUntilNextCheckin; + */ } else { wsErr("Tag not found, this shouldn't happen."); } @@ -154,6 +159,7 @@ bool prepareDataAvail(String* filename, uint8_t dataType, uint8_t* dst, uint16_t pending.availdatainfo.dataType = dataType; pending.availdatainfo.dataVer = *((uint64_t*)md5bytes); pending.availdatainfo.dataSize = file.size(); + pending.availdatainfo.dataTypeArgument = EPD_LUT_NO_REPEATS; pending.availdatainfo.nextCheckIn = nextCheckin; pending.attemptsLeft = attempts; sendDataAvail(&pending); @@ -185,14 +191,15 @@ bool prepareDataAvail(String* filename, uint8_t dataType, uint8_t* dst, uint16_t wsLog("new image pending: " + String(dst_path)); if (taginfo != nullptr) { + time_t now; + time(&now); taginfo->pending = true; - taginfo->CheckinInMinPending = nextCheckin; + taginfo->expectedNextCheckin = now + nextCheckin * 60 + 60; memcpy(taginfo->md5pending, md5bytes, sizeof(md5bytes)); - } - } - else { - wsLog("firmware upload pending"); } + } else { + wsLog("firmware upload pending"); + } file.close(); wsSendTaginfo(mac); @@ -275,17 +282,13 @@ void processXferComplete(struct espXferComplete* xfc) { if (taginfo != nullptr) { uint16_t minutesUntilNextUpdate = 0; - if (taginfo->nextupdate > now + 60 * taginfo->CheckinInMinPending + 3) { - minutesUntilNextUpdate = (taginfo->nextupdate - now) / 60 - taginfo->CheckinInMinPending; - if (minutesUntilNextUpdate > taginfo->CheckinInMinPending) minutesUntilNextUpdate = taginfo->CheckinInMinPending; + if (taginfo->nextupdate > now + 2) { + minutesUntilNextUpdate = (taginfo->nextupdate - now) / 60; if (minutesUntilNextUpdate > MIN_RESPONSE_TIME) minutesUntilNextUpdate = MIN_RESPONSE_TIME; - taginfo->expectedNextCheckin = now + 60 * minutesUntilNextUpdate + 60; - if (minutesUntilNextUpdate > 0) prepareIdleReq (xfc->src, minutesUntilNextUpdate); - taginfo->CheckinInMinPending = minutesUntilNextUpdate; + if (minutesUntilNextUpdate > 1) prepareIdleReq (xfc->src, minutesUntilNextUpdate); } else { taginfo->expectedNextCheckin = now + 60; - taginfo->CheckinInMinPending = 0; } taginfo->pending = false; @@ -310,7 +313,6 @@ void processXferTimeout(struct espXferComplete* xfc) { taginfo = tagRecord::findByMAC(mac); if (taginfo != nullptr) { taginfo->expectedNextCheckin = now + 60; - taginfo->CheckinInMinPending = 0; taginfo->pending = false; memset(taginfo->md5pending, 0, 16 * sizeof(uint8_t)); } @@ -341,15 +343,13 @@ void processDataReq(struct espAvailDataReq* eadr) { taginfo->lastseen = now; uint16_t minutesUntilNextUpdate = 0; - if (taginfo->nextupdate > now + 60 * taginfo->CheckinInMinPending + 3 && taginfo->pending == false) { - minutesUntilNextUpdate = (taginfo->nextupdate - now) / 60 - taginfo->CheckinInMinPending; - if (minutesUntilNextUpdate > taginfo->CheckinInMinPending) minutesUntilNextUpdate = taginfo->CheckinInMinPending; + if (taginfo->nextupdate > now + 2) { + minutesUntilNextUpdate = (taginfo->nextupdate - now) / 60; if (minutesUntilNextUpdate > MIN_RESPONSE_TIME) minutesUntilNextUpdate = MIN_RESPONSE_TIME; taginfo->expectedNextCheckin = now + 60 * minutesUntilNextUpdate + 60; - if (minutesUntilNextUpdate > 0) prepareIdleReq(eadr->src, minutesUntilNextUpdate); - taginfo->CheckinInMinPending = minutesUntilNextUpdate; + if (minutesUntilNextUpdate > 1 && taginfo->pending == false) prepareIdleReq(eadr->src, minutesUntilNextUpdate); } else { - taginfo->expectedNextCheckin = now + 60 * taginfo->CheckinInMinPending + 60; + taginfo->expectedNextCheckin = now + 60; } if (eadr->adr.lastPacketRSSI != 0) { diff --git a/esp32_fw/src/web.cpp b/esp32_fw/src/web.cpp index e18d6f74..0bdcf4be 100644 --- a/esp32_fw/src/web.cpp +++ b/esp32_fw/src/web.cpp @@ -284,7 +284,6 @@ void init_web() { taginfo->modeConfigJson = request->getParam("modecfgjson", true)->value(); taginfo->contentMode = atoi(request->getParam("contentmode", true)->value().c_str()); taginfo->nextupdate = 0; - taginfo->CheckinInMinPending = 0; memset(taginfo->md5, 0, 16 * sizeof(uint8_t)); memset(taginfo->md5pending, 0, 16 * sizeof(uint8_t)); wsSendTaginfo(mac);