mirror of
https://github.com/OpenEPaperLink/OpenEPaperLink.git
synced 2026-03-26 20:06:41 +01:00
Merge pull request #18 from nlimper/development
bugfix and better handling of AP crash
This commit is contained in:
@@ -52,8 +52,9 @@
|
||||
|
||||
<div class="actionbox">
|
||||
<div>
|
||||
<div>Currently active tags:</div>
|
||||
<div class="rebootbtn"><span id="rebootbutton">reboot AP</span></div>
|
||||
<div class="editbtn"><a href="/edit" target="littlefs" class="filebutton">edit littleFS</a></div>
|
||||
Currently active tags:<br>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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);
|
||||
extern void processDataReq(struct espAvailDataReq* adr);
|
||||
void refreshAllPending();
|
||||
@@ -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;
|
||||
|
||||
@@ -43,6 +43,7 @@ class tagRecord {
|
||||
|
||||
extern std::vector<tagRecord*> 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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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, "<ADR %02X%02X%02X%02X%02X%02X\n\0", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
||||
Serial.print(buffer);
|
||||
wsSendTaginfo(mac);
|
||||
|
||||
digitalWrite(ONBOARD_LED, HIGH);
|
||||
}
|
||||
|
||||
void refreshAllPending() {
|
||||
for (int16_t c = 0; c < tagDB.size(); c++) {
|
||||
tagRecord* taginfo = nullptr;
|
||||
taginfo = tagDB.at(c);
|
||||
if (taginfo->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);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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<String>();
|
||||
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) {
|
||||
|
||||
@@ -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<std::vector<uint8_t>>(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<String>());
|
||||
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<String>());
|
||||
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", "-");
|
||||
|
||||
Reference in New Issue
Block a user