diff --git a/esp32_fw/data/www/index.html b/esp32_fw/data/www/index.html index 0cfbbcfa..637013b6 100644 --- a/esp32_fw/data/www/index.html +++ b/esp32_fw/data/www/index.html @@ -52,8 +52,9 @@
+
Currently active tags:
+
reboot AP
- Currently active tags:
diff --git a/esp32_fw/data/www/main.css b/esp32_fw/data/www/main.css index fbc054f5..61c312b9 100644 --- a/esp32_fw/data/www/main.css +++ b/esp32_fw/data/www/main.css @@ -52,28 +52,32 @@ label { .actionbox>div:first-child { padding: 10px; - background-color: white; - margin: 5px; + background-color: white; + margin: 5px; } -.actionbox p { - padding: 5px; +.actionbox>div:first-child>div:first-child { + flex-grow: 2; } -.actionbox .columns { +.actionbox>div { display:flex; - flex-wrap: wrap; + gap: 20px; } -.filebutton { - padding:2px 5px; +#rebootbutton { + padding: 2px 5px; background-color: #cccccc; text-decoration: none; color: black; + cursor: pointer; } -.editbtn { - float:right; +.filebutton { + padding: 2px 5px; + background-color: #cccccc; + text-decoration: none; + color: black; } .columns div { diff --git a/esp32_fw/data/www/main.js b/esp32_fw/data/www/main.js index c0ea7d21..d9fc8d66 100644 --- a/esp32_fw/data/www/main.js +++ b/esp32_fw/data/www/main.js @@ -259,7 +259,28 @@ $('#cfgsave').onclick = function () { } $('#cfgdelete').onclick = function () { - let mac = $('#cfgmac').dataset.mac; + let formData = new FormData(); + formData.append("mac", $('#cfgmac').dataset.mac); + fetch("/delete_cfg", { + method: "POST", + body: formData + }) + .then(response => response.text()) + .then(data => { + var div = $('#tag' + $('#cfgmac').dataset.mac); + div.remove(); + showMessage(data); + }) + .catch(error => showMessage('Error: ' + error)); + $('#configbox').style.display = 'none'; +} + +$('#rebootbutton').onclick = function () { + showMessage("rebooting AP....",true); + fetch("/reboot", { + method: "POST" + }); + socket.close(); } function contentselected() { diff --git a/esp32_fw/include/newproto.h b/esp32_fw/include/newproto.h index 5d98df56..306c050b 100644 --- a/esp32_fw/include/newproto.h +++ b/esp32_fw/include/newproto.h @@ -9,4 +9,5 @@ extern bool prepareDataAvail(String* filename, uint8_t dataType, uint8_t* dst, u extern void processJoinNetwork(struct espJoinNetwork* xjn); extern void processXferComplete(struct espXferComplete* xfc); extern void processXferTimeout(struct espXferComplete* xfc); -extern void processDataReq(struct espAvailDataReq* adr); \ No newline at end of file +extern void processDataReq(struct espAvailDataReq* adr); +void refreshAllPending(); \ No newline at end of file diff --git a/esp32_fw/include/pendingdata.h b/esp32_fw/include/pendingdata.h index 88b09054..eced4e64 100644 --- a/esp32_fw/include/pendingdata.h +++ b/esp32_fw/include/pendingdata.h @@ -8,9 +8,7 @@ class pendingdata { public: String filename; - //uint8_t dst[8]; uint64_t ver; - String md5; uint32_t timeout; uint8_t datatimeout; uint8_t* data = nullptr; diff --git a/esp32_fw/include/tag_db.h b/esp32_fw/include/tag_db.h index 3e7e713e..50606a72 100644 --- a/esp32_fw/include/tag_db.h +++ b/esp32_fw/include/tag_db.h @@ -43,6 +43,7 @@ class tagRecord { extern std::vector tagDB; String tagDBtoJson(uint8_t mac[6] = nullptr, uint8_t startPos = 0); +bool deleteRecord(uint8_t mac[6]); void fillNode(JsonObject &tag, tagRecord* &taginfo); void saveDB(String filename); void loadDB(String filename); diff --git a/esp32_fw/src/contentmanager.cpp b/esp32_fw/src/contentmanager.cpp index b4559cc8..c8ac6acc 100644 --- a/esp32_fw/src/contentmanager.cpp +++ b/esp32_fw/src/contentmanager.cpp @@ -200,7 +200,7 @@ void initSprite(TFT_eSprite &spr, int w, int h) { spr.setColorDepth(8); spr.createSprite(w, h); if (spr.getPointer() == nullptr) { - wsErr("Failed to create sprite in drawNumber"); + wsErr("Failed to create sprite"); } spr.fillSprite(TFT_WHITE); } diff --git a/esp32_fw/src/main.cpp b/esp32_fw/src/main.cpp index 9dc18d5d..9a4efe08 100644 --- a/esp32_fw/src/main.cpp +++ b/esp32_fw/src/main.cpp @@ -44,10 +44,10 @@ void setup() { init_web(); loadDB("/current/tagDB.json"); - xTaskCreate(timeTask, "timed tasks", 10000, NULL, 2, NULL); xTaskCreate(zbsRxTask, "zbsRX Process", 10000, NULL, 2, NULL); xTaskCreate(garbageCollection, "pending-data cleanup", 5000, NULL, 1, NULL); xTaskCreate(webSocketSendProcess, "ws", 5000, NULL,configMAX_PRIORITIES-10, NULL); + xTaskCreate(timeTask, "timed tasks", 10000, NULL, 2, NULL); } void loop() { diff --git a/esp32_fw/src/newproto.cpp b/esp32_fw/src/newproto.cpp index a39ac298..88c0ed34 100644 --- a/esp32_fw/src/newproto.cpp +++ b/esp32_fw/src/newproto.cpp @@ -63,7 +63,6 @@ void prepareIdleReq(uint8_t* dst, uint16_t nextCheckin) { 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); @@ -135,7 +134,7 @@ bool prepareDataAvail(String* filename, uint8_t dataType, uint8_t* dst, uint16_t if (taginfo != nullptr) { if (memcmp(md5bytes, taginfo->md5pending, 16) == 0) { - wsLog("new image is the same as current image. not updating tag."); + wsLog("new image is the same as current or already pending image. not updating tag."); wsSendTaginfo(mac); return true; } @@ -147,7 +146,6 @@ bool prepareDataAvail(String* filename, uint8_t dataType, uint8_t* dst, uint16_t lut = EPD_LUT_DEFAULT; // full update once a day taginfo->lastfullupdate = now; } - Serial.println("last midnight: "+String(last_midnight)+" last full: "+String(taginfo->lastfullupdate) + " -> lut: " + String(lut)); } else { wsErr("Tag not found, this shouldn't happen."); } @@ -266,10 +264,14 @@ void processXferComplete(struct espXferComplete* xfc) { sprintf(src_path, "/current/%02X%02X%02X%02X%02X%02X.pending\0", src[2], src[3], src[4], src[5], src[6], src[7]); sprintf(dst_path, "/current/%02X%02X%02X%02X%02X%02X.bmp\0", src[2], src[3], src[4], src[5], src[6], src[7]); sprintf(tmp_path, "/temp/%02X%02X%02X%02X%02X%02X.bmp\0", src[2], src[3], src[4], src[5], src[6], src[7]); - if (LittleFS.exists(dst_path)) { + if (LittleFS.exists(dst_path) && LittleFS.exists(src_path)) { LittleFS.remove(dst_path); } - LittleFS.rename(src_path, dst_path); + if (LittleFS.exists(src_path)) { + LittleFS.rename(src_path, dst_path); + } else { + wsErr("hm, weird, no pending image found after xfercomplete."); + } if (LittleFS.exists(tmp_path)) { LittleFS.remove(tmp_path); } @@ -362,11 +364,23 @@ void processDataReq(struct espAvailDataReq* eadr) { taginfo->capabilities = eadr->adr.capabilities; } - Serial.printf("t=%d, lqi=%d, rssi=%d, ", eadr->adr.temperature, eadr->adr.lastPacketLQI, eadr->adr.lastPacketRSSI); - Serial.printf("hwtype=%d, reason=%d, volt=%d", eadr->adr.hwType,eadr->adr.wakeupReason,eadr->adr.batteryMv); sprintf(buffer, "pending) { + taginfo->pending = false; + taginfo->nextupdate = 0; + memset(taginfo->md5, 0, 16 * sizeof(uint8_t)); + memset(taginfo->md5pending, 0, 16 * sizeof(uint8_t)); + wsSendTaginfo(taginfo->mac); + } + } +}; \ No newline at end of file diff --git a/esp32_fw/src/serial.cpp b/esp32_fw/src/serial.cpp index 2331151a..9698faf3 100644 --- a/esp32_fw/src/serial.cpp +++ b/esp32_fw/src/serial.cpp @@ -251,6 +251,8 @@ void zbsRxTask(void* parameter) { 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(); + wsErr("The AP tag crashed. Restarting tag, regenerating all pending info."); + refreshAllPending(); } } diff --git a/esp32_fw/src/tag_db.cpp b/esp32_fw/src/tag_db.cpp index e6b6224f..2f585d24 100644 --- a/esp32_fw/src/tag_db.cpp +++ b/esp32_fw/src/tag_db.cpp @@ -20,6 +20,19 @@ tagRecord* tagRecord::findByMAC(uint8_t mac[6]) { return nullptr; } +bool deleteRecord(uint8_t mac[6]) { + for (int16_t c = 0; c < tagDB.size(); c++) { + tagRecord* tag = nullptr; + tag = tagDB.at(c); + if (memcmp(tag->mac, mac, 6) == 0) { + delete tagDB[c]; + tagDB.erase(tagDB.begin() + c); + return true; + } + } + return false; +} + String tagDBtoJson(uint8_t mac[6], uint8_t startPos) { DynamicJsonDocument doc(2500); JsonArray tags = doc.createNestedArray("tags"); @@ -55,9 +68,12 @@ void fillNode(JsonObject &tag, tagRecord* &taginfo) { char buffer[16]; sprintf(buffer, "%02X%02X%02X%02X%02X%02X\0", taginfo->mac[0], taginfo->mac[1], taginfo->mac[2], taginfo->mac[3], taginfo->mac[4], taginfo->mac[5]); tag["mac"] = (String)buffer; - char hex[7]; - sprintf(hex, "%02x%02x%02x\0", taginfo->md5[0], taginfo->md5[1], taginfo->md5[2]); - tag["hash"] = hex; + + char hex[33]; + for (uint8_t i = 0; i < 16; i++) { + sprintf(hex + (i * 2), "%02x", taginfo->md5[i]); + } + tag["hash"] = (String)hex; tag["lastseen"] = taginfo->lastseen; tag["nextupdate"] = taginfo->nextupdate; tag["nextcheckin"] = taginfo->expectedNextCheckin; @@ -140,8 +156,14 @@ void loadDB(String filename) { memcpy(taginfo->mac, mac, sizeof(taginfo->mac)); tagDB.push_back(taginfo); } + String md5 = tag["hash"].as(); + if (md5.length() >= 32) { + for (int i = 0; i < 16; i++) { + taginfo->md5[i] = strtoul(md5.substring(i * 2, i * 2 + 2).c_str(), NULL, 16); + } + } + memcpy(taginfo->md5pending, taginfo->md5, sizeof(taginfo->md5)); taginfo->lastseen = (uint32_t)tag["lastseen"]; - //taginfo->lastseen = 0; taginfo->nextupdate = (uint32_t)tag["nextupdate"]; taginfo->expectedNextCheckin = (uint16_t)tag["nextcheckin"]; if (taginfo->expectedNextCheckin < now - 1800) { diff --git a/esp32_fw/src/web.cpp b/esp32_fw/src/web.cpp index 0bdcf4be..4da1b13f 100644 --- a/esp32_fw/src/web.cpp +++ b/esp32_fw/src/web.cpp @@ -42,30 +42,11 @@ uint64_t swap64(uint64_t x) { } void webSocketSendProcess(void *parameter) { - uint32_t ulNotificationValue; - Serial.print("websocket thread started\n"); websocketUpdater = xTaskGetCurrentTaskHandle(); wsMutex = xSemaphoreCreateMutex(); while (true) { - ulNotificationValue = ulTaskNotifyTake(pdTRUE, 1000 / portTICK_RATE_MS); - if (ulNotificationValue == 0) { // timeout, so every 1s - ws.cleanupClients(); - } else { - // if (ws.count()) - // sendStatus(STATUS_WIFI_ACTIVITY); - DynamicJsonDocument doc(1500); - if (ulNotificationValue & 2) { // WS_SEND_MODE_STATUS) { - } - /* - JsonArray statusframes = doc.createNestedArray("frames"); - }*/ - size_t len = measureJson(doc); - xSemaphoreTake(wsMutex, portMAX_DELAY); - auto buffer = std::make_shared>(len); - serializeJson(doc, buffer->data(), len); - // ws.textAll((char*)buffer->data()); - xSemaphoreGive(wsMutex); - } + ws.cleanupClients(); + vTaskDelay(1000 / portTICK_PERIOD_MS); } } @@ -146,17 +127,17 @@ void onEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType void wsLog(String text) { StaticJsonDocument<500> doc; doc["logMsg"] = text; - xSemaphoreTake(wsMutex, portMAX_DELAY); + if (wsMutex) xSemaphoreTake(wsMutex, portMAX_DELAY); ws.textAll(doc.as()); - xSemaphoreGive(wsMutex); + if (wsMutex) xSemaphoreGive(wsMutex); } void wsErr(String text) { StaticJsonDocument<500> doc; doc["errMsg"] = text; - xSemaphoreTake(wsMutex, portMAX_DELAY); + if (wsMutex) xSemaphoreTake(wsMutex, portMAX_DELAY); ws.textAll(doc.as()); - xSemaphoreGive(wsMutex); + if (wsMutex) xSemaphoreGive(wsMutex); } void wsSendSysteminfo() { @@ -214,6 +195,12 @@ void init_web() { server.on("/reboot", HTTP_POST, [](AsyncWebServerRequest *request) { request->send(200, "text/plain", "OK Reboot"); + wsErr("REBOOTING"); + ws.enable(false); + refreshAllPending(); + saveDB("/current/tagDB.json"); + ws.closeAll(); + delay(100); ESP.restart(); }); @@ -226,34 +213,6 @@ void init_web() { }, doImageUpload); - server.on("/req_checkin", HTTP_POST, [](AsyncWebServerRequest *request) { - String filename; - String dst; - if (request->hasParam("dst", true)) { - dst = request->getParam("dst", true)->value(); - uint8_t mac_addr[12]; // I expected this to return like 8 values, but if I make the array 8 bytes long, things die. - mac_addr[0] = 0x00; - mac_addr[1] = 0x00; - if (sscanf(dst.c_str(), "%02X%02X%02X%02X%02X%02X", - &mac_addr[2], - &mac_addr[3], - &mac_addr[4], - &mac_addr[5], - &mac_addr[6], - &mac_addr[7]) != 6) { - request->send(200, "text/plain", "Something went wrong trying to parse the mac address"); - } else { - *((uint64_t *)mac_addr) = swap64(*((uint64_t *)mac_addr)); - if (prepareDataAvail(&filename, DATATYPE_NOUPDATE, mac_addr,0)) { - request->send(200, "text/plain", "Sending check-in request to " + dst); - } - } - return; - } - request->send(200, "text/plain", "Didn't get the required params"); - return; - }); - server.on("/get_db", HTTP_GET, [](AsyncWebServerRequest *request) { String json = ""; if (request->hasParam("mac")) { @@ -284,8 +243,8 @@ void init_web() { taginfo->modeConfigJson = request->getParam("modecfgjson", true)->value(); taginfo->contentMode = atoi(request->getParam("contentmode", true)->value().c_str()); taginfo->nextupdate = 0; - memset(taginfo->md5, 0, 16 * sizeof(uint8_t)); - memset(taginfo->md5pending, 0, 16 * sizeof(uint8_t)); + //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"); @@ -297,6 +256,22 @@ void init_web() { request->send(200, "text/plain", "Ok, saved"); }); + server.on("/delete_cfg", HTTP_POST, [](AsyncWebServerRequest *request) { + if (request->hasParam("mac", true)) { + String dst = request->getParam("mac", true)->value(); + uint8_t mac[6]; + if (sscanf(dst.c_str(), "%02X%02X%02X%02X%02X%02X", &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]) == 6) { + if (deleteRecord(mac)) { + request->send(200, "text/plain", "Ok, deleted"); + } else { + request->send(200, "text/plain", "Error while saving: mac not found"); + } + } + } else { + request->send(500, "text/plain", "no mac"); + } + }); + server.onNotFound([](AsyncWebServerRequest *request) { if (request->url() == "/" || request->url() == "index.htm") { request->send(200, "text/html", "-");