tag database, web interface.

Caution, this crashes. Investigating.
This commit is contained in:
Nic Limper
2023-01-30 23:40:14 +01:00
parent 2fbb77bc34
commit e4a106ee23
11 changed files with 493 additions and 63 deletions

View File

@@ -1,3 +1,55 @@
{
"C_Cpp.clang_format_fallbackStyle": "{ BasedOnStyle: Google, IndentWidth: 4, ColumnLimit: 0}"
"C_Cpp.clang_format_fallbackStyle": "{ BasedOnStyle: Google, IndentWidth: 4, ColumnLimit: 0}",
"files.associations": {
"array": "cpp",
"atomic": "cpp",
"*.tcc": "cpp",
"bitset": "cpp",
"cctype": "cpp",
"clocale": "cpp",
"cmath": "cpp",
"cstdarg": "cpp",
"cstddef": "cpp",
"cstdint": "cpp",
"cstdio": "cpp",
"cstdlib": "cpp",
"cstring": "cpp",
"ctime": "cpp",
"cwchar": "cpp",
"cwctype": "cpp",
"deque": "cpp",
"unordered_map": "cpp",
"unordered_set": "cpp",
"vector": "cpp",
"exception": "cpp",
"algorithm": "cpp",
"functional": "cpp",
"iterator": "cpp",
"map": "cpp",
"memory": "cpp",
"memory_resource": "cpp",
"numeric": "cpp",
"optional": "cpp",
"random": "cpp",
"regex": "cpp",
"string": "cpp",
"string_view": "cpp",
"system_error": "cpp",
"tuple": "cpp",
"type_traits": "cpp",
"utility": "cpp",
"fstream": "cpp",
"initializer_list": "cpp",
"iomanip": "cpp",
"iosfwd": "cpp",
"istream": "cpp",
"limits": "cpp",
"new": "cpp",
"ostream": "cpp",
"sstream": "cpp",
"stdexcept": "cpp",
"streambuf": "cpp",
"cinttypes": "cpp",
"typeinfo": "cpp"
}
}

View File

@@ -14,6 +14,41 @@
<div class="logo">Solum - alternative proto AP</div>
</header>
<div id="configbox">
<div class="closebtn">&#10006;</div>
<h3 id="cfgmac">00000000</h3>
<p>
<label for="alias">Alias</label>
<input name="alias" id="cfgalias" type="text">
</p>
<p>
<label for="model">Model</label>
<select name="model" id="cfgmodel">
<option value="0">unknown</option>
<option value="1">1.54" 152x152px</option>
<option value="2">2.9" 296x128px</option>
<option value="3">4.2" 400x300px</option>
</select>
</p>
<p>
<label for="content">Content</label>
<select name="content" id="cfgcontent">
<option value="0">static image</option>
<option value="1">current date</option>
<option value="2">count days</option>
<option value="3">count hours</option>
<option value="4">current weather</option>
<option value="5">public transport</option>
<option value="6">memo text</option>
</select>
</p>
<p>
<input type="button" value="Save" id="cfgsave">
<span id="cfgdelete"><img src="data:image/gif;base64,R0lGODlhEAAQAPMAANXV1e3t7d/f39HR0dvb2/Hx8dTU1OLi4urq6mZmZpmZmf///wAAAAAAAAAAAAAAACH5BAEAAAwALAAAAAAQABAAAARBkMlJq71Yrp3ZXkr4WWCYnOZSgQVyEMYwJCq1nHhe20qgCAoA7QLyAYU7njE4JPV+zOSkCEUSFbmTVPPpbjvgTAQAOw==
"></span>
</p>
</div>
<form>
<div class="container">
@@ -60,19 +95,25 @@
<div class="currimg"><img class="tagimg" src=""></div>
<div class="mac"></div>
<div class="alias"></div>
<div class="model"></div>
<div class="pending"></div>
<div class="contentmode"></div>
last: <span class="lastseen"></span>
last: <span class="lastseen"></span><span class="idletime"></span>
<div class="nextupdate"></div>
<div class="corner">
<div class="warningicon">&#9888;</div>
<div class="configicon"></div>
</div>
</div>
</div>
<div class="logbox">
<p>logging <span><img id="clearlog" src="data:image/gif;base64,R0lGODlhEAAQAPMAANXV1e3t7d/f39HR0dvb2/Hx8dTU1OLi4urq6mZmZpmZmf///wAAAAAAAAAAAAAAACH5BAEAAAwALAAAAAAQABAAAARBkMlJq71Yrp3ZXkr4WWCYnOZSgQVyEMYwJCq1nHhe20qgCAoA7QLyAYU7njE4JPV+zOSkCEUSFbmTVPPpbjvgTAQAOw==
"></span></p>
<p>
<span>logging</span>
<span><img id="clearlog" src="data:image/gif;base64,R0lGODlhEAAQAPMAANXV1e3t7d/f39HR0dvb2/Hx8dTU1OLi4urq6mZmZpmZmf///wAAAAAAAAAAAAAAACH5BAEAAAwALAAAAAAQABAAAARBkMlJq71Yrp3ZXkr4WWCYnOZSgQVyEMYwJCq1nHhe20qgCAoA7QLyAYU7njE4JPV+zOSkCEUSFbmTVPPpbjvgTAQAOw==
"></span>
<span id="sysinfo"></span>
</p>
<ul id="messages" class="messages">
</ul>
</div>

View File

@@ -3,7 +3,6 @@
padding:0;
border:0;
list-style-type: none;
-webkit-appearance: none;
outline: none;
font-weight: 400;
-webkit-box-sizing: border-box;
@@ -76,19 +75,61 @@ label {
background-color: white;
}
.actionbox input {
border: solid 1px black;
input {
border: solid 1px #666666;
padding: 4px;
}
.actionbox input[type=button] {
input[type=button] {
border: 0px;
padding: 4px;
cursor:pointer;
}
.actionbox input[type=button]:hover {
input[type=button]:hover {
background-color:#aaaaaa;
}
select {
padding: 4px;
}
#configbox {
display: none;
position: fixed;
top: 80px;
left: 50px;
width: 500px;
padding: 15px;
background-color: #f0e6d3;
z-index: 999;
box-shadow: 7px 10px 52px -19px rgba(0, 0, 0, 0.63);
}
#configbox p {
padding: 5px;
}
#configbox h3 {
font-size: 1.5em;
font-weight: bold;
}
#cfgdelete {
position: absolute;
bottom: 15px;
right: 15px;
cursor:pointer;
}
.closebtn {
border: 1px solid black;
float: right;
width: 19px;
height: 20px;
font-size: 1.1em;
text-align: center;
margin: 5px;
cursor: pointer;
}
.logbox {
margin: 5px;
@@ -104,13 +145,21 @@ label {
cursor:pointer;
}
.logbox #sysinfo {
float: right;
}
.taglist {
display: flex;
flex-wrap: wrap;
}
#tagtemplate {
display:none;
}
.tagcard {
width: 220px;
width: 225px;
position: relative;
height: 170px;
margin: 5px;
@@ -151,6 +200,16 @@ label {
background-image: url("data: image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAQAAAAngNWGAAABXklEQVQoz43SP2tUQRQF8N99ecFKFEVh0Y1ZbFQ2xEoIQkoLW0t7C/OVLGzyHay1EAQjRFGrLMkjKSwWsRGV3WvxZvc9XQtnivl35sydc048nfuvVkW0k8XYtT936pVja5jJv/Z7wPZo0wNzLzQSHWnVwTZtqY1su2to3bZhj7dewEYeu+iDawi7bhn7Yl9TWGsikrzksnNxr9zfsIErcaEAMysyZXrvE5mp6w7zc8rMzFJjGNlxFWHmWKMVd2DHsHuadQ+NkcKxZ2pPXC8FHHhu1v91X6ZcUZHYy8xwwyju5wAzJypDFdHka5OiaN1yHDl100BaMyq84cwrs1JjtTBu7E5xIpeebLndOZOlnK859d1bZ0JoHPiRU986ZxYZmdjP8/HRrkfSS2+MTTXlycyawhlHJBOH5k789A6x/H/sZQuMKKNatjGLvkoreUy/lsnsq1mXJOe/Ut6tM38DZpmDFxwTi8EAAAAASUVORK5CYII=");
}
.warningicon {
display:none;
font-size: 1.3em;
background-color: yellow;
color: black;
height: 20px;
width: 20px;
vertical-align: top;
text-align: center;
}
ul.messages {
padding: 5px;

View File

@@ -1,6 +1,21 @@
const $ = document.querySelector.bind(document);
const contentModes = ["static image", "current date", "count days", "count hours","current weather","public transport","memo text"];
const models = ["unknown", "1.54\" 152x152px", "2.9\" 296x128px", "4.2\" 400x300px"];
let socket;
connect();
setInterval(updatecards, 1000);
window.addEventListener("load", function () {
fetch("/get_db")
.then(response => response.json())
.then(data => {
processTags(data.tags);
})
.catch(error => showMessage('Error: ' + error));
});
function connect() {
socket = new WebSocket("ws://" + location.host + "/ws");
@@ -10,7 +25,7 @@ function connect() {
});
socket.addEventListener("message", (event) => {
console.log(event.data)
console.log(event.data);
const msg = JSON.parse(event.data);
if (msg.logMsg) {
showMessage(msg.logMsg);
@@ -18,6 +33,9 @@ function connect() {
if (msg.tags) {
processTags(msg.tags);
}
if (msg.sys) {
$('#sysinfo').innerHTML = 'free heap: ' + msg.sys.heap + ' bytes &#x2507; db size: ' + msg.sys.dbsize + ' bytes &#x2507; db record count: ' + msg.sys.recordcount + ' &#x2507; littlefs free: ' + msg.sys.littlefsfree + ' bytes';
}
});
socket.addEventListener("close", (event) => {
@@ -26,40 +44,65 @@ function connect() {
});
}
connect();
function processTags(tagArray) {
var date = new Date(),
dateString = date.toLocaleDateString('nl-NL', { day: '2-digit', month: '2-digit', year: 'numeric' }),
time = date.toLocaleTimeString('nl-NL', { hour12: false, hour: '2-digit', minute: '2-digit', second: '2-digit' });
for (const element of tagArray) {
tagmac = element.mac;
if ($('#tag' + tagmac) == null) {
const div = $('#tagtemplate').cloneNode(true);
var div = $('#tag' + tagmac);
if (div == null) {
div = $('#tagtemplate').cloneNode(true);
div.setAttribute('id', 'tag'+tagmac);
div.dataset.mac = tagmac;
$('#taglist').appendChild(div);
$('#tag' + tagmac + ' .mac').innerHTML = tagmac;
$('#tag' + tagmac + ' .alias').innerHTML = tagmac;
$('#tag' + tagmac + ' .lastseen').innerHTML = dateString+' '+time;
var img = $('#tag' + tagmac + ' .tagimg')
var img = $('#tag' + tagmac + ' .tagimg');
img.addEventListener('error', function handleError() {
img.style.display = 'none';
});
img.style.display = 'block';
img.src = '/edit?edit=current/' + tagmac +'.bmp';
//+'<br>button: '+element.buttonstate
$('#taglist').appendChild(div);
} else {
$('#tag' + tagmac + ' .lastseen').innerHTML = dateString + ' ' + time;
var img = $('#tag' + tagmac + ' .tagimg')
img.style.display = 'block';
img.src = '/edit?edit=current/' + tagmac + '.bmp&' + date;
}
console.log(element.buttonstate);
}
div.style.display = 'block';
let alias = element.alias;
if (!alias) alias = tagmac;
$('#tag' + tagmac + ' .alias').innerHTML = alias;
var img = $('#tag' + tagmac + ' .tagimg');
img.style.display = 'block';
img.src = '/edit?edit=current/' + tagmac + '.bmp&' + (new Date()).getTime();
$('#tag' + tagmac + ' .contentmode').innerHTML = contentModes[element.contentmode];
$('#tag' + tagmac + ' .model').innerHTML = models[element.model];
var date = new Date(element.nextupdate * 1000);
var options = { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false };
$('#tag' + tagmac + ' .nextupdate').innerHTML = date.toLocaleString('nl-NL', options).replace(',', '');
date = new Date(element.lastseen * 1000);
var options = { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false};
$('#tag' + tagmac + ' .lastseen').innerHTML = date.toLocaleString('nl-NL', options).replace(',', '');
div.dataset.lastseen = element.lastseen;
div.dataset.lastseenlocaltime = Date.now();
$('#tag' + tagmac + ' .warningicon').style.display = 'none';
if (element.pending) $('#tag' + tagmac + ' .pending').innerHTML = "pending..."; else $('#tag' + tagmac + ' .pending').innerHTML = "";
}
}
function updatecards() {
document.querySelectorAll('[data-mac]').forEach(item => {
var tagmac = item.dataset.mac;
var idletime = Date.now() - item.dataset.lastseenlocaltime;
$('#tag' + tagmac + ' .idletime').innerHTML = int(idletime);
if (idletime > 300000) $('#tag' + tagmac + ' .warningicon').style.display='inline-block';
if (idletime > 1800000) $('#tag' + tagmac).style.display = 'none';
})
}
$('#send_image').onclick = function() {
let formData = new FormData();
formData.append("dst", $("#dstmac").value);
@@ -103,6 +146,10 @@ $('#clearlog').onclick = function () {
$('#messages').innerHTML='';
}
$('.closebtn').onclick = function (event) {
event.target.parentNode.style.display='none';
}
$('#taglist').addEventListener("click", (event) => {
let currentElement = event.target;
while (currentElement !== $('#taglist')) {
@@ -119,10 +166,41 @@ $('#taglist').addEventListener("click", (event) => {
$('#dstmac').value=mac;
}
if (event.target.classList.contains("configicon")) {
console.log('config')
$('#cfgmac').innerHTML = mac;
$('#cfgmac').dataset.mac = mac;
fetch("/get_db?mac=" + mac)
.then(response => response.json())
.then(data => {
console.log(data);
var tagdata = data.tags[0];
$('#cfgalias').value = tagdata.alias;
$('#cfgcontent').value = tagdata.contentmode;
$('#cfgmodel').value = tagdata.model;
$('#configbox').style.display = 'block';
})
.catch(error => showMessage('Error: ' + error));
}
})
});
$('#cfgsave').onclick = function () {
let formData = new FormData();
formData.append("mac", $('#cfgmac').dataset.mac);
formData.append("alias", $('#cfgalias').value);
formData.append("contentmode", $('#cfgcontent').value);
formData.append("model", $('#cfgmodel').value);
fetch("/save_cfg", {
method: "POST",
body: formData
})
.then(response => response.text())
.then(data => showMessage(data))
.catch(error => showMessage('Error: ' + error));
$('#configbox').style.display = 'none';
}
$('#cfgdelete').onclick = function () {
let mac = $('#cfgmac').dataset.mac;
}
function showMessage(message) {
const messages = $('#messages');

36
esp32_fw/include/tag_db.h Normal file
View File

@@ -0,0 +1,36 @@
#include <Arduino.h>
#include <vector>
#pragma pack(push, 1)
#pragma once
enum contentModes {
Image,
Today,
CountDays,
CountHours,
Weather,
PubTrans,
Memo,
};
class tagRecord {
public:
tagRecord() : mac{0}, model(0), alias(""), lastseen(0), nextupdate(0), contentMode(Image), pending(false), button(false), currFilename(""), pendingFilename("") {}
uint8_t mac[6];
u_int8_t model;
String alias;
uint32_t lastseen;
uint32_t nextupdate;
contentModes contentMode;
bool pending;
bool button;
String currFilename;
String pendingFilename;
static tagRecord* findByMAC(uint8_t mac[6]);
};
extern std::vector<tagRecord*> tagDB;
String tagDBtoJson(uint8_t mac[6] = nullptr);

View File

@@ -5,12 +5,13 @@
void init_web();
void doImageUpload(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final);
extern void webSocketSendProcess(void *parameter);
extern void wsString(String text);
extern void wsSendTaginfo(uint8_t src[8]);
//extern void webSocketSendProcess(void *parameter);
void wsString(String text);
void wsSendTaginfo(uint8_t mac[6]);
void wsSendSysteminfo();
extern uint64_t swap64(uint64_t x);
extern AsyncWebSocket ws;//("/ws");
extern AsyncWebSocket ws; //("/ws");
extern SemaphoreHandle_t wsMutex;
extern TaskHandle_t websocketUpdater;

View File

@@ -4,15 +4,22 @@
#include <time.h>
#include "flasher.h"
#include "makeimage.h"
#include "pendingdata.h"
#include "serial.h"
#include "soc/rtc_wdt.h"
#include "tag_db.h"
#include "web.h"
#include "makeimage.h"
void freeHeapTask(void* parameter) {
while (1) {
//Serial.printf("Free heap=%d\n", ESP.getFreeHeap());
//time_t now;
tm tm;
if (!getLocalTime(&tm)) {
Serial.println("Failed to obtain time");
}
wsSendSysteminfo();
vTaskDelay(30000 / portTICK_PERIOD_MS);
}
}
@@ -22,20 +29,13 @@ void setup() {
Serial.print(">\n");
init_web();
long timezone = 2;
byte daysavetime = 1;
configTime(0, 3600, "time.nist.gov", "0.pool.ntp.org", "1.pool.ntp.org");
struct tm tmstruct;
delay(2000);
tmstruct.tm_year = 0;
getLocalTime(&tmstruct, 5000);
Serial.printf("\nNow is : %d-%02d-%02d %02d:%02d:%02d\n", (tmstruct.tm_year) + 1900, (tmstruct.tm_mon) + 1, tmstruct.tm_mday, tmstruct.tm_hour, tmstruct.tm_min, tmstruct.tm_sec);
Serial.println("");
configTzTime("CET-1CEST,M3.5.0,M10.5.0/3", "europe.pool.ntp.org", "time.nist.gov");
// https://github.com/nayarsystems/posix_tz_db/blob/master/zones.csv
xTaskCreate(freeHeapTask, "print free heap", 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(webSocketSendProcess, "ws", 5000, NULL,configMAX_PRIORITIES-10, NULL);
}
void loop() {

View File

@@ -4,12 +4,14 @@
#include <Arduino.h>
#include <MD5Builder.h>
#include <makeimage.h>
#include <time.h>
#include "LittleFS.h"
#include "commstructs.h"
#include "pendingdata.h"
#include "serial.h"
#include "settings.h"
#include "tag_db.h"
#include "web.h"
extern void sendBlock(const void* data, const uint16_t len);
@@ -128,6 +130,17 @@ bool prepareDataAvail(String* filename, uint8_t dataType, uint8_t* dst, uint16_t
int bytes_written = file.write(pendinginfo->data, pendinginfo->len);
file.close();
uint8_t src[8];
*((uint64_t*)src) = swap64(*((uint64_t*)dst));
uint8_t mac[6];
memcpy(mac, src + 2, sizeof(mac));
tagRecord* taginfo = nullptr;
taginfo = tagRecord::findByMAC(mac);
if (taginfo != nullptr) {
taginfo->pending = true;
}
wsSendTaginfo(mac);
return true;
}
@@ -180,7 +193,15 @@ void processXferComplete(struct espXferComplete* xfc) {
sprintf(buffer, "< %02X%02X%02X%02X%02X%02X reports xfer complete\n\0", src[2], src[3], src[4], src[5], src[6], src[7]);
wsString((String)buffer);
Serial.print(buffer);
wsSendTaginfo(src);
uint8_t mac[6];
memcpy(mac, src + 2, sizeof(mac));
tagRecord* taginfo = nullptr;
taginfo = tagRecord::findByMAC(mac);
if (taginfo != nullptr) {
taginfo->pending = false;
}
wsSendTaginfo(mac);
char src_path[64];
char dst_path[64];
@@ -198,8 +219,25 @@ void processDataReq(struct espAvailDataReq* eadr) {
char buffer[64];
uint8_t src[8];
*((uint64_t*)src) = swap64(*((uint64_t*)eadr->src));
sprintf(buffer, "<ADR %02X%02X%02X%02X%02X%02X button: %02X\n\0", src[2], src[3], src[4], src[5], src[6], src[7], eadr->adr.buttonState);
wsString((String)buffer);
tagRecord* taginfo = nullptr;
uint8_t mac[6];
memcpy(mac, src + 2, sizeof(mac));
taginfo = tagRecord::findByMAC(mac);
time_t now;
time(&now);
if (taginfo == nullptr) {
taginfo = new tagRecord;
memcpy(taginfo->mac, src + 2, sizeof(taginfo->mac));
taginfo->pending = false;
tagDB.push_back(taginfo);
}
taginfo->lastseen = now;
taginfo->button = (eadr->adr.buttonState == 1);
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(src);
wsString((String)buffer);
wsSendTaginfo(mac);
}

51
esp32_fw/src/tag_db.cpp Normal file
View File

@@ -0,0 +1,51 @@
#include <Arduino.h>
#include "tag_db.h"
#include <ArduinoJson.h>
#include <vector>
std::vector<tagRecord*> tagDB;
tagRecord* tagRecord::findByMAC(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) {
return tag;
}
}
return nullptr;
}
String tagDBtoJson(uint8_t mac[6]) {
DynamicJsonDocument doc(1000);
JsonArray tags = doc.createNestedArray("tags");
for (int16_t c = 0; c < tagDB.size(); c++) {
tagRecord* taginfo = nullptr;
taginfo = tagDB.at(c);
bool select = false;
if (mac) {
if (memcmp(taginfo->mac, mac, 6) == 0) {
select = true;
}
} else {
select = true;
}
if (select) {
JsonObject tag = tags.createNestedObject();
char buffer[64];
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;
tag["lastseen"] = taginfo->lastseen;
tag["nextupdate"] = taginfo->nextupdate;
tag["model"] = taginfo->model;
tag["pending"] = taginfo->pending;
tag["button"] = taginfo->button;
tag["alias"] = taginfo->alias;
tag["contentmode"] = taginfo->contentMode;
}
}
return doc.as<String>();
}

View File

@@ -14,6 +14,7 @@
#include "commstructs.h"
#include "newproto.h"
#include "settings.h"
#include "tag_db.h"
extern uint8_t data_to_send[];
@@ -189,21 +190,49 @@ void onEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType
}
void wsString(String text) {
DynamicJsonDocument doc(1500);
DynamicJsonDocument doc(100);
doc["logMsg"] = text;
xSemaphoreTake(wsMutex, portMAX_DELAY);
ws.textAll(doc.as<String>());
xSemaphoreGive(wsMutex);
}
void wsSendTaginfo(uint8_t src[8]) {
DynamicJsonDocument doc(1500);
void wsSendSysteminfo() {
DynamicJsonDocument doc(250);
JsonObject sys = doc.createNestedObject("sys");
time_t now;
time(&now);
sys["currtime"] = now;
sys["heap"] = ESP.getFreeHeap();
sys["recordcount"] = tagDB.size();
sys["dbsize"] = tagDB.size() * sizeof(tagRecord);
sys["littlefsfree"] = LittleFS.totalBytes() - LittleFS.usedBytes();
xSemaphoreTake(wsMutex, portMAX_DELAY);
ws.textAll(doc.as<String>());
xSemaphoreGive(wsMutex);
}
void wsSendTaginfo(uint8_t mac[6]) {
DynamicJsonDocument doc(1000);
JsonArray tags = doc.createNestedArray("tags");
JsonObject tag = tags.createNestedObject();
char buffer[64];
sprintf(buffer, "%02X%02X%02X%02X%02X%02X\0", src[2], src[3], src[4], src[5], src[6], src[7]);
sprintf(buffer, "%02X%02X%02X%02X%02X%02X\0", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
tag["mac"] = (String)buffer;
//tag["buttonstate"] = eadr->adr.buttonState;
tagRecord *taginfo = nullptr;
taginfo = tagRecord::findByMAC(mac);
if (taginfo != nullptr) {
tag["lastseen"] = taginfo->lastseen;
tag["nextupdate"] = taginfo->nextupdate;
tag["model"] = taginfo->model;
tag["pending"] = taginfo->pending;
tag["button"] = taginfo->button;
tag["alias"] = taginfo->alias;
tag["contentmode"] = taginfo->contentMode;
}
xSemaphoreTake(wsMutex, portMAX_DELAY);
ws.textAll(doc.as<String>());
xSemaphoreGive(wsMutex);
@@ -240,10 +269,6 @@ void init_web() {
ws.onEvent(onEvent);
server.addHandler(&ws);
server.on("/heap", HTTP_GET, [](AsyncWebServerRequest *request) {
request->send(200, "text/plain", String(ESP.getFreeHeap()));
});
server.on("/reboot", HTTP_POST, [](AsyncWebServerRequest *request) {
request->send(200, "text/plain", "OK Reboot");
ESP.restart();
@@ -349,6 +374,41 @@ void init_web() {
return;
});
server.on("/get_db", HTTP_GET, [](AsyncWebServerRequest *request) {
String json = "";
if (request->hasParam("mac")) {
String dst = request->getParam("mac")->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) {
json = tagDBtoJson(mac);
}
} else {
json = tagDBtoJson();
}
request->send(200, "application/json", json);
});
server.on("/save_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) {
tagRecord *taginfo = nullptr;
taginfo = tagRecord::findByMAC(mac);
if (taginfo != nullptr) {
taginfo->alias = request->getParam("alias", true)->value();
taginfo->contentMode = (contentModes)atoi(request->getParam("contentmode", true)->value().c_str());
taginfo->model = atoi(request->getParam("model", true)->value().c_str());
wsSendTaginfo(mac);
request->send(200, "text/plain", "Ok, saved");
} else {
request->send(200, "text/plain", "Error while saving: mac not found");
}
}
}
request->send(200, "text/plain", "Ok, saved");
});
server.onNotFound([](AsyncWebServerRequest *request) {
if (request->url() == "/" || request->url() == "index.htm") {
request->send(200, "text/html", "-");

View File

@@ -1,6 +1,20 @@
@echo off
del fs154.bin
del fw29.bin
del fw42.bin
makeit clean
makeit
makeit BUILD=zbs154v033 CPU=8051 SOC=zbs243
pause
ren main.bin fw154.bin
makeit clean
makeit BUILD=zbs29v033 CPU=8051 SOC=zbs243
pause
ren main.bin fw29.bin
makeit clean
makeit BUILD=zbs42v033 CPU=8051 SOC=zbs243
pause
ren main.bin fw42.bin
del /s *.asm
del /s *.lst
del /s *.rst