diff --git a/esp32_fw/data/fonts/tw20.vlw b/esp32_fw/data/fonts/tw20.vlw
new file mode 100644
index 00000000..884fc494
Binary files /dev/null and b/esp32_fw/data/fonts/tw20.vlw differ
diff --git a/esp32_fw/data/fonts/twbold20.vlw b/esp32_fw/data/fonts/twbold20.vlw
new file mode 100644
index 00000000..5ed00c42
Binary files /dev/null and b/esp32_fw/data/fonts/twbold20.vlw differ
diff --git a/esp32_fw/data/fonts/weathericons50.vlw b/esp32_fw/data/fonts/weathericons50.vlw
new file mode 100644
index 00000000..4019f131
Binary files /dev/null and b/esp32_fw/data/fonts/weathericons50.vlw differ
diff --git a/esp32_fw/data/fonts/weathericons78.vlw b/esp32_fw/data/fonts/weathericons78.vlw
index a1d9d0b6..073f249c 100644
Binary files a/esp32_fw/data/fonts/weathericons78.vlw and b/esp32_fw/data/fonts/weathericons78.vlw differ
diff --git a/esp32_fw/data/www/edit.html b/esp32_fw/data/www/edit.html
index f5b566f5..4adac442 100644
--- a/esp32_fw/data/www/edit.html
+++ b/esp32_fw/data/www/edit.html
@@ -595,6 +595,7 @@
case "jpg":
case "gif":
case "bmp":
+ case "pending":
return true;
}
}
diff --git a/esp32_fw/data/www/main.js b/esp32_fw/data/www/main.js
index 5d0276da..27d3529f 100644
--- a/esp32_fw/data/www/main.js
+++ b/esp32_fw/data/www/main.js
@@ -139,8 +139,9 @@ function updatecards() {
if (item.dataset.lastseen && item.dataset.lastseen > 1672531200) {
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 > item.dataset.nextcheckin) {
+ if ((Date.now() / 1000) + servertimediff - 60 > item.dataset.nextcheckin) {
$('#tag' + tagmac + ' .warningicon').style.display='inline-block';
+ $('#tag' + tagmac).classList.remove("tagpending")
$('#tag' + tagmac).style.background = '#ffffcc';
}
if (idletime > 24*3600) {
diff --git a/esp32_fw/include/newproto.h b/esp32_fw/include/newproto.h
index 54ffe327..c41b3972 100644
--- a/esp32_fw/include/newproto.h
+++ b/esp32_fw/include/newproto.h
@@ -4,6 +4,7 @@ extern void addCRC(void* p, uint8_t len);
extern bool checkCRC(void* p, uint8_t len);
extern void processBlockRequest(struct espBlockRequest* br);
+extern void prepareIdleReq(uint8_t* dst, uint16_t nextCheckin);
extern bool prepareDataAvail(String* filename, uint8_t dataType, uint8_t* dst, uint16_t nextCheckin);
extern void processJoinNetwork(struct espJoinNetwork* xjn);
extern void processXferComplete(struct espXferComplete* xfc);
diff --git a/esp32_fw/include/pendingdata.h b/esp32_fw/include/pendingdata.h
index 1bbc1e9f..88b09054 100644
--- a/esp32_fw/include/pendingdata.h
+++ b/esp32_fw/include/pendingdata.h
@@ -11,7 +11,7 @@ class pendingdata {
//uint8_t dst[8];
uint64_t ver;
String md5;
- uint16_t timeout;
+ uint32_t timeout;
uint8_t datatimeout;
uint8_t* data = nullptr;
uint32_t len;
diff --git a/esp32_fw/include/serial.h b/esp32_fw/include/serial.h
index d9476e6c..76ed03a1 100644
--- a/esp32_fw/include/serial.h
+++ b/esp32_fw/include/serial.h
@@ -4,4 +4,5 @@ void zbsTx(uint8_t* packetdata, uint8_t len);
void zbsRxTask(void* parameter);
void sendCancelPending(struct pendingData* pending);
-void sendDataAvail(struct pendingData* pending);
\ No newline at end of file
+void sendDataAvail(struct pendingData* pending);
+void Ping();
\ No newline at end of file
diff --git a/esp32_fw/include/settings.h b/esp32_fw/include/settings.h
index bfe32c49..d1ab28cd 100644
--- a/esp32_fw/include/settings.h
+++ b/esp32_fw/include/settings.h
@@ -1,19 +1,16 @@
#include
-#define CHECK_IN_DELAY 900000
-#define RETRY_DELAY 1000
-#define FAILED_TILL_BLANK 2
-#define FAILED_TILL_REASSOCIATE 1
-
// how long the we should keep the transfer metadata
-#define PENDING_TIMEOUT 600
+#define PENDING_TIMEOUT 24*3600
// this determines how long images will be cached;
#define PENDING_DATA_TIMEOUT 60
+// maximum time (in minutes) that a tag is put to sleep if no update is expected.
+#define MIN_RESPONSE_TIME 10
// flasher options
#define CUSTOM_MAC_HDR 0x0000
-/*
+/* Lolin32 lite connections to AP tag
#define RXD1 16
#define TXD1 17
@@ -24,10 +21,13 @@
#define ZBS_Reset 2
#define ZBS_POWER1 13
#define ZBS_POWER2 15
-*/
-#define RXD1 13
-#define TXD1 12
+#define ONBOARD_LED 22
+//*/
+
+//*
+#define RXD1 13
+#define TXD1 12
#define ZBS_SS 21
#define ZBS_CLK 18
@@ -37,5 +37,8 @@
#define ZBS_POWER1 15
#define ZBS_POWER2 2
+#define ONBOARD_LED 22
+//*/
+
#define MAX_WRITE_ATTEMPTS 5
diff --git a/esp32_fw/include/tag_db.h b/esp32_fw/include/tag_db.h
index 703423f3..4e8f147b 100644
--- a/esp32_fw/include/tag_db.h
+++ b/esp32_fw/include/tag_db.h
@@ -6,17 +6,6 @@
#pragma pack(push, 1)
#pragma once
-enum contentModes {
- Image,
- Today,
- CountDays,
- CountHours,
- Weather,
- Firmware,
- Memo,
- ImageUrl,
-};
-
#define SOLUM_154_033 0
#define SOLUM_29_033 1
#define SOLUM_42_033 2
@@ -29,13 +18,13 @@ enum contentModes {
class tagRecord {
public:
uint16_t nextCheckinpending;
- tagRecord() : mac{0}, alias(""), lastseen(0), nextupdate(0), contentMode(Image), 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}, CheckinInMinPending(0), expectedNextCheckin(0), modeConfigJson(""), LQI(0), RSSI(0), temperature(0), batteryMv(0), hwType(0), wakeupReason(0), capabilities(0) {}
uint8_t mac[6];
String alias;
uint32_t lastseen;
uint32_t nextupdate;
- contentModes contentMode;
+ uint8_t contentMode;
bool pending;
uint8_t md5[16];
uint8_t md5pending[16];
diff --git a/esp32_fw/src/contentmanager.cpp b/esp32_fw/src/contentmanager.cpp
index a4c08405..2d0b1d30 100644
--- a/esp32_fw/src/contentmanager.cpp
+++ b/esp32_fw/src/contentmanager.cpp
@@ -12,6 +12,18 @@
#include "makeimage.h"
#include "web.h"
+enum contentModes {
+ Image,
+ Today,
+ CountDays,
+ CountHours,
+ Weather,
+ Firmware,
+ Memo,
+ ImageUrl,
+};
+
+
void contentRunner() {
time_t now;
time(&now);
@@ -76,8 +88,7 @@ void drawNew(uint8_t mac[8], bool buttonPressed, tagRecord *&taginfo) {
case Today:
drawDate(filename, taginfo);
- // updateTagImage(filename, mac, (midnight - now) / 60 - 10);
- updateTagImage(filename, mac, 600);
+ updateTagImage(filename, mac, (midnight - now) / 60 - 10);
taginfo->nextupdate = midnight;
break;
@@ -85,7 +96,7 @@ void drawNew(uint8_t mac[8], bool buttonPressed, tagRecord *&taginfo) {
if (buttonPressed) cfgobj["counter"] = 0;
drawNumber(filename, (int32_t)cfgobj["counter"], (int32_t)cfgobj["thresholdred"], taginfo);
- updateTagImage(filename, mac, (buttonPressed?0:600));
+ updateTagImage(filename, mac, (buttonPressed?0:15));
cfgobj["counter"] = (int32_t)cfgobj["counter"] + 1;
taginfo->nextupdate = midnight;
break;
@@ -94,9 +105,7 @@ void drawNew(uint8_t mac[8], bool buttonPressed, tagRecord *&taginfo) {
if (buttonPressed) cfgobj["counter"] = 0;
drawNumber(filename, (int32_t)cfgobj["counter"], (int32_t)cfgobj["thresholdred"], taginfo);
- // updateTagImage(&filename, mac, (3600 - now % 3600) / 60);
- // taginfo->nextupdate = now + 3600 - (now % 3600);
- updateTagImage(filename, mac, (buttonPressed?0:600));
+ updateTagImage(filename, mac, (buttonPressed?0:5));
cfgobj["counter"] = (int32_t)cfgobj["counter"] + 1;
taginfo->nextupdate = now + 3600;
break;
@@ -109,7 +118,7 @@ void drawNew(uint8_t mac[8], bool buttonPressed, tagRecord *&taginfo) {
// https://github.com/erikflowers/weather-icons
drawWeather(filename, cfgobj["location"], taginfo);
- updateTagImage(filename, mac, 600);
+ updateTagImage(filename, mac, 15);
taginfo->nextupdate = now + 3600;
break;
@@ -134,7 +143,7 @@ void drawNew(uint8_t mac[8], bool buttonPressed, tagRecord *&taginfo) {
drawIdentify(filename, taginfo);
updateTagImage(filename, mac, 0);
- taginfo->nextupdate = now + 24*3600;
+ taginfo->nextupdate = now + 12*3600;
break;
case ImageUrl:
@@ -142,8 +151,10 @@ void drawNew(uint8_t mac[8], bool buttonPressed, tagRecord *&taginfo) {
if (getImgURL(filename, cfgobj["url"], (time_t)cfgobj["#fetched"])) {
updateTagImage(filename, mac, cfgobj["interval"].as());
cfgobj["#fetched"] = now;
+ taginfo->nextupdate = now + 60 * (cfgobj["interval"].as() < 5 ? 5 : cfgobj["interval"].as());
+ } else {
+ taginfo->nextupdate = now + 300;
}
- taginfo->nextupdate = now + 60 * (cfgobj["interval"].as() < 5 ? 5 : cfgobj["interval"].as()) ;
break;
}
@@ -449,7 +460,7 @@ bool getImgURL(String &filename, String URL, time_t fetched) {
}
}
http.end();
- return (httpCode == 200);
+ return (httpCode == 200 || httpCode == 304);
}
char *formatHttpDate(time_t t) {
diff --git a/esp32_fw/src/main.cpp b/esp32_fw/src/main.cpp
index 391c9ae5..9dc18d5d 100644
--- a/esp32_fw/src/main.cpp
+++ b/esp32_fw/src/main.cpp
@@ -8,6 +8,7 @@
#include "makeimage.h"
#include "pendingdata.h"
#include "serial.h"
+#include "settings.h"
#include "soc/rtc_wdt.h"
#include "tag_db.h"
#include "web.h"
@@ -21,7 +22,9 @@ void timeTask(void* parameter) {
Serial.println("Waiting for valid time from NTP-server");
} else {
if (now % 10 == 0) wsSendSysteminfo();
- if (now % 300 == 0) saveDB("/current/tagDB.json");
+ if (now % 60 == 3) Ping();
+ if (now % 300 == 6) saveDB("/current/tagDB.json");
+
contentRunner();
}
vTaskDelay(1000 / portTICK_PERIOD_MS);
@@ -32,6 +35,9 @@ void setup() {
Serial.begin(115200);
Serial.print(">\n");
+ pinMode(ONBOARD_LED, OUTPUT);
+ digitalWrite(ONBOARD_LED, HIGH);
+
configTzTime("CET-1CEST,M3.5.0,M10.5.0/3", "0.nl.pool.ntp.org", "europe.pool.ntp.org", "time.nist.gov");
// https://github.com/nayarsystems/posix_tz_db/blob/master/zones.csv
diff --git a/esp32_fw/src/makeimage.cpp b/esp32_fw/src/makeimage.cpp
index 4bcd7955..54e8660d 100644
--- a/esp32_fw/src/makeimage.cpp
+++ b/esp32_fw/src/makeimage.cpp
@@ -29,7 +29,7 @@ void jpg2grays(String filein, String fileout) {
}
spr.setColorDepth(8);
spr.fillSprite(TFT_WHITE);
- TJpgDec.drawFsJpg(0, 0, filein);
+ TJpgDec.drawFsJpg(0, 0, filein, LittleFS);
spr2grays(spr, w, h, fileout);
spr.deleteSprite();
@@ -236,8 +236,7 @@ void spr2grays(TFT_eSprite &spr, long w, long h, String &fileout) {
f_out.write(0);
}
f_out.close();
- Serial.println(millis() - t);
- Serial.println("finished writing BMP");
+ Serial.println("finished writing BMP " + String(millis() - t) + "ms");
}
void bmp2grays(String filein, String fileout) {
@@ -429,6 +428,5 @@ void bmp2grays(String filein, String fileout) {
}
f_in.close();
f_out.close();
- Serial.println(millis() - t);
- Serial.println("finished writing BMP2");
+ Serial.println("finished converting BMP " + String(millis() - t) + "ms");
}
\ No newline at end of file
diff --git a/esp32_fw/src/newproto.cpp b/esp32_fw/src/newproto.cpp
index a69acb13..bbd2f148 100644
--- a/esp32_fw/src/newproto.cpp
+++ b/esp32_fw/src/newproto.cpp
@@ -49,14 +49,34 @@ void prepareCancelPending(uint64_t ver) {
sendCancelPending(&pending);
}
-bool prepareDataAvail(String* filename, uint8_t dataType, uint8_t* dst, uint16_t nextCheckin) {
+void prepareIdleReq(uint8_t* dst, uint16_t nextCheckin) {
+ if (nextCheckin > MIN_RESPONSE_TIME) {
+ // to prevent very long sleeps of the tag
+ nextCheckin = MIN_RESPONSE_TIME;
+ }
+ struct pendingData pending = {0};
+ memcpy(pending.targetMac, dst, 8);
+ pending.availdatainfo.dataType = DATATYPE_NOUPDATE;
+ pending.availdatainfo.nextCheckIn = nextCheckin;
+ pending.attemptsLeft = 10;
- if (nextCheckin > 1440) {
+ char buffer[64];
+ uint8_t src[8];
+ *((uint64_t*)src) = swap64(*((uint64_t*)dst));
+ sprintf(buffer, "idle request %02X%02X%02X%02X%02X%02X %d minutes\n\0", src[2], src[3], src[4], src[5], src[6], src[7], nextCheckin);
+ Serial.print(buffer);
+
+ sendDataAvail(&pending);
+}
+
+bool prepareDataAvail(String* filename, uint8_t dataType, uint8_t* dst, uint16_t nextCheckin) {
+ if (nextCheckin > MIN_RESPONSE_TIME) {
//to prevent very long sleeps of the tag
- nextCheckin = 0;
+ nextCheckin = MIN_RESPONSE_TIME;
}
*filename = "/" + *filename;
+ LittleFS.begin();
if (!LittleFS.exists(*filename)) return false;
fs::File file = LittleFS.open(*filename);
@@ -137,7 +157,6 @@ bool prepareDataAvail(String* filename, uint8_t dataType, uint8_t* dst, uint16_t
pendinginfo->data = nullptr;
pendinginfo->timeout = PENDING_TIMEOUT;
//pendinginfo->data = getDataForFile(&file);
- pendinginfo->timeout = 1800; // ***fixme... a tag can sleep for a long time when ttl is used.
pendingfiles.push_back(pendinginfo);
if (dataType != DATATYPE_UPDATE) {
@@ -157,7 +176,7 @@ bool prepareDataAvail(String* filename, uint8_t dataType, uint8_t* dst, uint16_t
wsLog("new image pending: " + String(dst_path));
if (taginfo != nullptr) {
taginfo->pending = true;
- taginfo->CheckinInMinPending = nextCheckin + 1;
+ taginfo->CheckinInMinPending = nextCheckin;
memcpy(taginfo->md5pending, md5bytes, sizeof(md5bytes));
}
}
@@ -244,14 +263,31 @@ void processXferComplete(struct espXferComplete* xfc) {
tagRecord* taginfo = nullptr;
taginfo = tagRecord::findByMAC(mac);
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 (minutesUntilNextUpdate > MIN_RESPONSE_TIME) minutesUntilNextUpdate = MIN_RESPONSE_TIME;
+
+ taginfo->expectedNextCheckin = now + 60 * minutesUntilNextUpdate + 60;
+ if (minutesUntilNextUpdate > 0) prepareIdleReq (xfc->src, minutesUntilNextUpdate);
+ taginfo->CheckinInMinPending = minutesUntilNextUpdate;
+ } else {
+ taginfo->expectedNextCheckin = now + 60;
+ taginfo->CheckinInMinPending = 0;
+ }
+
taginfo->pending = false;
- taginfo->expectedNextCheckin = now + 60 * taginfo->CheckinInMinPending + 30;
memcpy(taginfo->md5, taginfo->md5pending, sizeof(taginfo->md5pending));
}
wsSendTaginfo(mac);
}
void processDataReq(struct espAvailDataReq* eadr) {
+
+ digitalWrite(ONBOARD_LED, LOW);
+
char buffer[64];
uint8_t src[8];
*((uint64_t*)src) = swap64(*((uint64_t*)eadr->src));
@@ -270,7 +306,19 @@ void processDataReq(struct espAvailDataReq* eadr) {
time_t now;
time(&now);
taginfo->lastseen = now;
- taginfo->expectedNextCheckin = now + 300;
+
+ 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 (minutesUntilNextUpdate > MIN_RESPONSE_TIME) minutesUntilNextUpdate = MIN_RESPONSE_TIME;
+ taginfo->expectedNextCheckin = now + 60 * minutesUntilNextUpdate + 60;
+ if (minutesUntilNextUpdate > 0) prepareIdleReq(eadr->src, minutesUntilNextUpdate);
+ taginfo->CheckinInMinPending = minutesUntilNextUpdate;
+ } else {
+ taginfo->expectedNextCheckin = now + 60 * taginfo->CheckinInMinPending + 60;
+ }
+
if (eadr->adr.lastPacketRSSI != 0) {
taginfo->LQI = eadr->adr.lastPacketLQI;
taginfo->hwType = eadr->adr.hwType;
@@ -287,4 +335,6 @@ void processDataReq(struct espAvailDataReq* eadr) {
sprintf(buffer, "", 4) == 0) && waitingForVersion) {
- waitingForVersion = false;
+ waitingForVersion = 0;
pktindex = 0;
RXState = ZBS_RX_WAIT_VER;
charindex = 0;
@@ -182,7 +187,8 @@ void SerialRXLoop() {
if (charindex == 4) {
charindex = 0;
version = (uint16_t)strtoul(cmdbuffer, NULL, 16);
- uint16_t fsversion; // BREAK here! break;
+ /*
+ uint16_t fsversion;
lookupFirmwareFile(fsversion);
if ((fsversion) && (version != fsversion)) {
Serial.printf("ZBS/Zigbee FW version: %04X, version on SPIFFS: %04X\n", version, fsversion);
@@ -194,6 +200,7 @@ void SerialRXLoop() {
} else {
Serial.printf("ZBS/Zigbee FW version: %04X\n", version);
}
+ */
RXState = ZBS_RX_WAIT_HEADER;
}
break;
@@ -208,6 +215,7 @@ void zbsRxTask(void* parameter) {
simplePowerOn();
Serial1.print("VER?");
+ waitingForVersion = esp_timer_get_time();
while (1) {
SerialRXLoop();
@@ -216,13 +224,12 @@ void zbsRxTask(void* parameter) {
}
vTaskDelay(1 / portTICK_PERIOD_MS);
if (waitingForVersion) {
- if (millis() > 30000) {
- waitingForVersion = false;
- performDeviceFlash();
- // Serial.printf("We've been waiting for communication from the tag, but got nothing. This is expected if this tag hasn't been flashed yet. We'll try to flash it.\n");
- // doAPUpdate();
+ if (esp_timer_get_time() - waitingForVersion > 10000*1000ULL) {
+ waitingForVersion = esp_timer_get_time();
//performDeviceFlash();
- // SDAtest();
+ Serial.println("I wasn't able to connect to a ZBS tag, trying to reboot the tag.");
+ Serial.println("If this problem persists, please check wiring and definitions in the settings.h file, and presence of the right firmware");
+ simplePowerOn();
}
}
}
diff --git a/esp32_fw/src/tag_db.cpp b/esp32_fw/src/tag_db.cpp
index 65c4f1aa..e6b6224f 100644
--- a/esp32_fw/src/tag_db.cpp
+++ b/esp32_fw/src/tag_db.cpp
@@ -149,7 +149,7 @@ void loadDB(String filename) {
}
taginfo->pending = false;
taginfo->alias = tag["alias"].as();
- taginfo->contentMode = static_cast(tag["contentMode"]);
+ taginfo->contentMode = tag["contentMode"];
taginfo->LQI = tag["LQI"];
taginfo->RSSI = tag["RSSI"];
taginfo->temperature = tag["temperature"];
diff --git a/esp32_fw/src/web.cpp b/esp32_fw/src/web.cpp
index fc01ad0f..e18d6f74 100644
--- a/esp32_fw/src/web.cpp
+++ b/esp32_fw/src/web.cpp
@@ -282,8 +282,11 @@ void init_web() {
if (taginfo != nullptr) {
taginfo->alias = request->getParam("alias", true)->value();
taginfo->modeConfigJson = request->getParam("modecfgjson", true)->value();
- taginfo->contentMode = (contentModes)atoi(request->getParam("contentmode", true)->value().c_str());
+ 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);
saveDB("/current/tagDB.json");
request->send(200, "text/plain", "Ok, saved");