mirror of
https://github.com/OpenEPaperLink/OpenEPaperLink.git
synced 2026-03-21 06:06:23 +01:00
tag database, web interface.
Caution, this crashes. Investigating.
This commit is contained in:
54
esp32_fw/.vscode/settings.json
vendored
54
esp32_fw/.vscode/settings.json
vendored
@@ -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"
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,41 @@
|
||||
<div class="logo">Solum - alternative proto AP</div>
|
||||
</header>
|
||||
|
||||
<div id="configbox">
|
||||
<div class="closebtn">✖</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">⚠</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>
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 ┇ db size: ' + msg.sys.dbsize + ' bytes ┇ db record count: ' + msg.sys.recordcount + ' ┇ 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
36
esp32_fw/include/tag_db.h
Normal 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);
|
||||
@@ -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;
|
||||
@@ -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() {
|
||||
|
||||
@@ -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
51
esp32_fw/src/tag_db.cpp
Normal 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>();
|
||||
}
|
||||
@@ -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", "-");
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user