diff --git a/ESP32_AP-Flasher/include/newproto.h b/ESP32_AP-Flasher/include/newproto.h
index 7746a2db..90a95986 100644
--- a/ESP32_AP-Flasher/include/newproto.h
+++ b/ESP32_AP-Flasher/include/newproto.h
@@ -7,7 +7,7 @@ extern void processBlockRequest(struct espBlockRequest* br);
extern void prepareCancelPending(const uint8_t dst[8]);
extern void prepareIdleReq(const uint8_t* dst, uint16_t nextCheckin);
extern void prepareDataAvail(uint8_t* data, uint16_t len, uint8_t dataType, const uint8_t* dst);
-extern bool prepareDataAvail(String& filename, uint8_t dataType, const uint8_t* dst, uint16_t nextCheckin);
+extern bool prepareDataAvail(String& filename, uint8_t dataType, const uint8_t* dst, uint16_t nextCheckin, bool resend = false);
extern void prepareExternalDataAvail(struct pendingData* pending, IPAddress remoteIP);
extern void processXferComplete(struct espXferComplete* xfc, bool local);
extern void processXferTimeout(struct espXferComplete* xfc, bool local);
diff --git a/ESP32_AP-Flasher/include/storage.h b/ESP32_AP-Flasher/include/storage.h
index a1732e25..c17713e8 100644
--- a/ESP32_AP-Flasher/include/storage.h
+++ b/ESP32_AP-Flasher/include/storage.h
@@ -35,5 +35,8 @@ class DynStorage {
extern DynStorage Storage;
extern fs::FS *contentFS;
+extern void copyFile(File in, File out);
+
+#endif
+
-#endif
\ No newline at end of file
diff --git a/ESP32_AP-Flasher/include/tag_db.h b/ESP32_AP-Flasher/include/tag_db.h
index 2125dc08..1d415fb7 100644
--- a/ESP32_AP-Flasher/include/tag_db.h
+++ b/ESP32_AP-Flasher/include/tag_db.h
@@ -66,6 +66,8 @@ struct Config {
uint8_t preview;
uint8_t wifiPower;
char timeZone[52];
+ uint8_t sleepTime1;
+ uint8_t sleepTime2;
};
struct HwType {
diff --git a/ESP32_AP-Flasher/include/util.h b/ESP32_AP-Flasher/include/util.h
index 6719cacc..551c4cb5 100644
--- a/ESP32_AP-Flasher/include/util.h
+++ b/ESP32_AP-Flasher/include/util.h
@@ -104,4 +104,24 @@ static inline bool isEmptyOrNull(const String &str) {
return str.isEmpty() || str == "null";
}
+/// @brief checks if the current time is between sleeptime1 and sleeptime2
+///
+/// @param sleeptime1 Start of time block
+/// @param sleeptime2 End of time block
+/// @return True if within time block, false is outside time block
+static bool isSleeping(int sleeptime1, int sleeptime2) {
+ if (sleeptime1 == sleeptime2) return false;
+
+ struct tm timeinfo;
+ getLocalTime(&timeinfo);
+ int currentHour = timeinfo.tm_hour;
+
+ if (sleeptime1 < sleeptime2) {
+ return currentHour >= sleeptime1 && currentHour < sleeptime2;
+ } else {
+ return currentHour >= sleeptime1 || currentHour < sleeptime2;
+ }
+}
+
+
} // namespace util
diff --git a/ESP32_AP-Flasher/src/contentmanager.cpp b/ESP32_AP-Flasher/src/contentmanager.cpp
index 82b2635d..34e2a188 100644
--- a/ESP32_AP-Flasher/src/contentmanager.cpp
+++ b/ESP32_AP-Flasher/src/contentmanager.cpp
@@ -20,9 +20,7 @@
#include "storage.h"
-#if defined CONTENT_RSS || defined CONTENT_CAL
#include "U8g2_for_TFT_eSPI.h"
-#endif
#include "commstructs.h"
#include "makeimage.h"
#include "newproto.h"
@@ -45,19 +43,31 @@ void contentRunner() {
time(&now);
for (tagRecord *taginfo : tagDB) {
- if (taginfo->RSSI && (now >= taginfo->nextupdate || taginfo->wakeupReason == WAKEUP_REASON_GPIO || taginfo->wakeupReason == WAKEUP_REASON_NFC) && config.runStatus == RUNSTATUS_RUN && Storage.freeSpace() > 31000) {
+ if (taginfo->RSSI && (now >= taginfo->nextupdate || taginfo->wakeupReason == WAKEUP_REASON_GPIO || taginfo->wakeupReason == WAKEUP_REASON_NFC) && config.runStatus == RUNSTATUS_RUN && Storage.freeSpace() > 31000 && !util::isSleeping(config.sleepTime1, config.sleepTime2)) {
drawNew(taginfo->mac, (taginfo->wakeupReason == WAKEUP_REASON_GPIO), taginfo);
taginfo->wakeupReason = 0;
}
if (taginfo->expectedNextCheckin > now - 10 && taginfo->expectedNextCheckin < now + 30 && taginfo->pendingIdle == 0 && taginfo->pending == false) {
- uint16_t minutesUntilNextUpdate = (taginfo->nextupdate - now) / 60;
+ int16_t minutesUntilNextUpdate = (taginfo->nextupdate - now) / 60;
if (minutesUntilNextUpdate > config.maxsleep) {
minutesUntilNextUpdate = config.maxsleep;
}
+ if (util::isSleeping(config.sleepTime1, config.sleepTime2)) {
+ struct tm timeinfo;
+ getLocalTime(&timeinfo);
+ struct tm nextSleepTimeinfo = timeinfo;
+ nextSleepTimeinfo.tm_hour = config.sleepTime2;
+ nextSleepTimeinfo.tm_min = 0;
+ nextSleepTimeinfo.tm_sec = 0;
+ time_t nextWakeTime = mktime(&nextSleepTimeinfo);
+ if (nextWakeTime < now) nextWakeTime += 24 * 3600;
+ minutesUntilNextUpdate = (nextWakeTime - now) / 60 - 2;
+ }
if (minutesUntilNextUpdate > 1 && (wsClientCount() == 0 || config.stopsleep == 0)) {
taginfo->pendingIdle = minutesUntilNextUpdate;
if (taginfo->isExternal == false) {
+ Serial.printf("sleeping for %d more minutes\n", minutesUntilNextUpdate);
prepareIdleReq(taginfo->mac, minutesUntilNextUpdate);
}
}
@@ -186,15 +196,29 @@ void drawNew(const uint8_t mac[8], const bool buttonPressed, tagRecord *&taginfo
switch (taginfo->contentMode) {
case 0: // Image
{
- const String configFilename = cfgobj["filename"].as
+ + + and + +
diff --git a/ESP32_AP-Flasher/wwwroot/main.js b/ESP32_AP-Flasher/wwwroot/main.js index 74e35d44..7d49c84e 100644 --- a/ESP32_AP-Flasher/wwwroot/main.js +++ b/ESP32_AP-Flasher/wwwroot/main.js @@ -32,6 +32,9 @@ let servertimediff = 0; let paintLoaded = false, paintShow = false; let cardconfig; let otamodule; +let socket; +let finishedInitialLoading = false; +let getTagtypeBusy = false; window.addEventListener("load", function () { fetch('/content_cards.json') @@ -55,16 +58,17 @@ window.addEventListener("load", function () { } }); dropUpload(); + populateTimes($('#apcnight1')); + populateTimes($('#apcnight2')); }); -let socket; - function loadTags(pos) { fetch("/get_db?pos=" + pos) .then(response => response.json()) .then(data => { processTags(data.tags); if (data.continu && data.continu > pos) loadTags(data.continu); + finishedInitialLoading = true; }) //.catch(error => showMessage('loadTags error: ' + error)); } @@ -489,6 +493,8 @@ $('#apconfigbutton').onclick = function () { $("#apcpreview").value = data.preview; $("#apcwifipower").value = data.wifipower; $("#apctimezone").value = data.timezone; + $("#apcnight1").value = data.sleeptime1; + $("#apcnight2").value = data.sleeptime2; }) $('#apconfigbox').style.display = 'block' } @@ -504,6 +510,8 @@ $('#apcfgsave').onclick = function () { formData.append('preview', $('#apcpreview').value); formData.append('wifipower', $('#apcwifipower').value); formData.append('timezone', $('#apctimezone').value); + formData.append('sleeptime1', $('#apcnight1').value); + formData.append('sleeptime2', $('#apcnight2').value); fetch("/save_apcfg", { method: "POST", body: formData @@ -706,11 +714,15 @@ function processQueue() { return; } isProcessing = true; + if (!finishedInitialLoading) { + setTimeout(processQueue, 100); + return; + } const { id, imageSrc } = imageQueue.shift(); const hwtype = $('#tag' + id).dataset.hwtype; if (tagTypes[hwtype]?.busy) { imageQueue.push({ id, imageSrc }); - setTimeout(processQueue, 50); + setTimeout(processQueue, 100); return; }; @@ -869,6 +881,21 @@ $('#toggleFilters').addEventListener('click', () => { }); async function getTagtype(hwtype) { + if (tagTypes[hwtype]) { + return tagTypes[hwtype]; + } + + if (getTagtypeBusy) { + await new Promise(resolve => { + const checkBusy = setInterval(() => { + if (!getTagtypeBusy) { + clearInterval(checkBusy); + resolve(); + } + }, 50); + }); + } + if (tagTypes[hwtype]?.busy) { await new Promise(resolve => { const checkBusy = setInterval(() => { @@ -886,10 +913,12 @@ async function getTagtype(hwtype) { try { tagTypes[hwtype] = { busy: true }; + getTagtypeBusy = true; const response = await fetch('/tagtypes/' + hwtype.toString(16).padStart(2, '0').toUpperCase() + '.json'); if (!response.ok) { let data = { name: 'unknown id ' + hwtype, width: 0, height: 0, bpp: 0, rotatebuffer: 0, colortable: [], busy: false }; tagTypes[hwtype] = data; + getTagtypeBusy = false; return data; } const jsonData = await response.json(); @@ -904,10 +933,12 @@ async function getTagtype(hwtype) { busy: false }; tagTypes[hwtype] = data; + getTagtypeBusy = false; return data; } catch (error) { console.error('Error fetching data:', error); + getTagtypeBusy = false; return null; } } @@ -1074,3 +1105,12 @@ $('#taglist').addEventListener('contextmenu', (e) => { document.addEventListener('click', () => { contextMenu.style.display = 'none'; }); + +function populateTimes(element) { + for (let i = 0; i < 24; i++) { + const option = document.createElement("option"); + option.value = i; + option.text = i.toString().padStart(2, "0") + ":00"; + element.appendChild(option); + } +} \ No newline at end of file