mirror of
https://github.com/OpenEPaperLink/OpenEPaperLink.git
synced 2026-03-21 07:06:36 +01:00
jpeg2bmp, bmp2grays, refactor website
- new webpage to manage tags (work in progress), gets rid of jquery ;-) - built in jpg and 24bpp bmp converter. the jpeg-converter auto-rotates the image, so uploading a 296x128px jpeg for a 2.9" tag is fine now. 24bpp bmp is also fine, but no autorotation (more complex, and imho unnecessary) - changed websockets communication to json - small fixes and cleanup
This commit is contained in:
BIN
esp32_fw/data/bmp24bpp-h.bmp
Normal file
BIN
esp32_fw/data/bmp24bpp-h.bmp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 111 KiB |
BIN
esp32_fw/data/bmp24bpp-v.bmp
Normal file
BIN
esp32_fw/data/bmp24bpp-v.bmp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 111 KiB |
@@ -1,66 +1,89 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0"/>
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0" />
|
||||
|
||||
<title>Solum - alternative proto AP</title>
|
||||
<link rel="stylesheet" href="main.css" type="text/css"/>
|
||||
<title>Solum - alternative proto AP</title>
|
||||
<link rel="stylesheet" href="main.css" type="text/css" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<header>
|
||||
<div class="logo">Solum - alternative proto AP</div>
|
||||
</header>
|
||||
<header>
|
||||
<div class="logo">Solum - alternative proto AP</div>
|
||||
</header>
|
||||
|
||||
<div class="container">
|
||||
<form>
|
||||
<div class="container">
|
||||
|
||||
<div class="blocks"><ul></ul></div>
|
||||
<div class="window">
|
||||
|
||||
<div class="actionbox">
|
||||
<div>
|
||||
<label for="dst">Destination MAC</label>
|
||||
<input name="dst" class="dst" id="dstmac" size=12 maxlength=12 type="text" placeholder="001122334455">
|
||||
</div>
|
||||
<div class="columns">
|
||||
<div>
|
||||
<p>
|
||||
<label for="filename">Filename</label>
|
||||
<input name="filename" id="imgfile" type="text" placeholder="default.bmp">
|
||||
</p>
|
||||
<p>
|
||||
<label for="ttl">Next check-in</label>
|
||||
<input name="ttl" id="ttl" type="text" placeholder="1"> min
|
||||
</p>
|
||||
<p>
|
||||
<input type="button" value="Send Image" id="send_image">
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<p>
|
||||
<label for="filename">Filename</label>
|
||||
<input name="filename" id="fwfile" type="text" placeholder="update.bin">
|
||||
</p>
|
||||
<p>
|
||||
<input type="button" value="Send FW Update" id="send_fw">
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<p>
|
||||
<input type="button" value="Request Check-in" id="req_checkin">
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="taglist" class="taglist">
|
||||
<div class="tagcard" id="tagtemplate">
|
||||
<div class="currimg"><img class="tagimg" src=""></div>
|
||||
<div class="mac"></div>
|
||||
<div class="alias"></div>
|
||||
<div class="pending"></div>
|
||||
<div class="contentmode"></div>
|
||||
last: <span class="lastseen"></span>
|
||||
<div class="nextupdate"></div>
|
||||
<div class="corner">
|
||||
<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>
|
||||
<ul id="messages" class="messages">
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="window">
|
||||
</div>
|
||||
</form>
|
||||
|
||||
|
||||
<iframe name="empty" style="border:1px solid darkgrey; width:100%; height:4em;"></iframe>
|
||||
|
||||
<div class="actionbox">
|
||||
<form action="send_image" method="POST" target="empty">
|
||||
DST:<input name="dst" class="dst" size=12 maxlength=12 type="text" placeholder="001122334455">
|
||||
Filename:<input name="filename" type="text" placeholder="default.bmp">
|
||||
Next check-in:<input name="ttl" type="text" placeholder="1"> min
|
||||
<input type="submit" value="Send Image">
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="actionbox">
|
||||
<form action="send_fw" method="POST" target="empty">
|
||||
DST:<input name="dst" class="dst" size=12 maxlength=12 type="text" placeholder="001122334455">
|
||||
Filename:<input name="filename" type="text" placeholder="update.bin">
|
||||
<input type="submit" value="Send FW Update">
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="actionbox">
|
||||
<form action="req_checkin" method="POST" target="empty">
|
||||
DST:<input name="dst" class="dst" size=12 maxlength=12 type="text" placeholder="001122334455">
|
||||
<input type="submit" value="Request Check-in">
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div id="messages">
|
||||
<ul class="messages">
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
<script src="jquery.js"></script>
|
||||
<script src="main.js"></script>
|
||||
<script src="main.js"></script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
BIN
esp32_fw/data/jpeg-h.jpg
Normal file
BIN
esp32_fw/data/jpeg-h.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
BIN
esp32_fw/data/jpeg-v.jpg
Normal file
BIN
esp32_fw/data/jpeg-v.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
6
esp32_fw/data/jquery.js
vendored
6
esp32_fw/data/jquery.js
vendored
File diff suppressed because one or more lines are too long
@@ -16,6 +16,7 @@
|
||||
html, body {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
font-size: 12px;
|
||||
font-family: Helvetica, Arial, Verdana, sans-serif;
|
||||
@@ -28,144 +29,144 @@ body {
|
||||
header {
|
||||
height: 50px;
|
||||
background-color: #666;
|
||||
|
||||
}
|
||||
|
||||
label {
|
||||
width:100px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.logo {
|
||||
margin: 0 auto;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
text-indent: 100px;
|
||||
text-indent: 50px;
|
||||
overflow:hidden;
|
||||
background: url('p2000.svg') center center no-repeat;
|
||||
background-size: 50px 50px;
|
||||
font-size: 2.5em;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.container {
|
||||
|
||||
}
|
||||
|
||||
.blocks {
|
||||
padding: 21px 0;
|
||||
overflow-x: auto;
|
||||
text-align:center;
|
||||
}
|
||||
.blocks ul {
|
||||
display:table;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.blocks ul li {
|
||||
display:table-cell;
|
||||
vertical-align:top;
|
||||
padding: 0 4px;
|
||||
position: relative;
|
||||
}
|
||||
.blocks ul li:nth-child(6) div.b:before, .blocks ul li:nth-child(6) div.b:after {
|
||||
content:"";
|
||||
position:absolute;
|
||||
margin-left: -5px;
|
||||
left: 50%;
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
.blocks ul li:nth-child(6) div.b:before {
|
||||
top: -5px;
|
||||
border-left: 5px solid transparent;
|
||||
border-right: 5px solid transparent;
|
||||
border-top: 5px solid #c30;
|
||||
}
|
||||
.blocks ul li:nth-child(6) div.b:after {
|
||||
bottom: -5px;
|
||||
border-left: 5px solid transparent;
|
||||
border-right: 5px solid transparent;
|
||||
border-bottom: 5px solid #c30;
|
||||
}
|
||||
.blocks ul li, .blocks ul li div {
|
||||
|
||||
}
|
||||
.blocks ul li div {
|
||||
width: 80px;
|
||||
padding: 0 4px;
|
||||
|
||||
}
|
||||
.blocks ul li div.b {
|
||||
position:relative;
|
||||
padding: 6px 0;
|
||||
background: #fff;
|
||||
}
|
||||
.blocks ul li div.rxt {
|
||||
background-color: #e5f9ea;
|
||||
}
|
||||
.blocks ul li div.txt {
|
||||
background-color: #f9eae5;
|
||||
}
|
||||
.blocks ul li div.b {
|
||||
|
||||
}
|
||||
.window {
|
||||
margin: 0 auto;
|
||||
max-width: 94%;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
form {
|
||||
padding: 3px;
|
||||
.actionbox>div:first-child {
|
||||
padding: 10px;
|
||||
background-color: white;
|
||||
margin: 5px;
|
||||
}
|
||||
|
||||
.actionbox .dst {
|
||||
size:12em;
|
||||
.actionbox p {
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.actionbox .columns {
|
||||
display:flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.columns div {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.actionbox div div {
|
||||
padding: 5px;
|
||||
margin: 5px;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
|
||||
.actionbox input {
|
||||
border: solid 1px black;
|
||||
padding: 2px;
|
||||
border: solid 1px black;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
input.actionbox {
|
||||
border: solid 1px black;
|
||||
.actionbox input[type=button] {
|
||||
border: 0px;
|
||||
padding: 4px;
|
||||
cursor:pointer;
|
||||
}
|
||||
.actionbox input[type=button]:hover {
|
||||
background-color:#aaaaaa;
|
||||
}
|
||||
|
||||
.logbox {
|
||||
margin: 5px;
|
||||
}
|
||||
|
||||
.logbox p {
|
||||
background-color: #ffffff;
|
||||
padding: 5px 10px;
|
||||
}
|
||||
|
||||
.logbox img {
|
||||
vertical-align: bottom;
|
||||
cursor:pointer;
|
||||
}
|
||||
|
||||
.taglist {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.tagcard {
|
||||
width: 220px;
|
||||
position: relative;
|
||||
height: 170px;
|
||||
margin: 5px;
|
||||
padding: 5px;
|
||||
background-color: #dddddd;
|
||||
}
|
||||
|
||||
.currimg {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.currimg img {
|
||||
max-width: 50px;
|
||||
}
|
||||
|
||||
.mac {
|
||||
font-size: 0.9em;
|
||||
cursor:pointer;
|
||||
}
|
||||
|
||||
.alias {
|
||||
font-size: 1.4em;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.corner {
|
||||
position: absolute;
|
||||
right: 0px;
|
||||
bottom: 0px;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.configicon {
|
||||
display: inline-block;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
cursor:pointer;
|
||||
background-image: url("data: image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAQAAAAngNWGAAABXklEQVQoz43SP2tUQRQF8N99ecFKFEVh0Y1ZbFQ2xEoIQkoLW0t7C/OVLGzyHay1EAQjRFGrLMkjKSwWsRGV3WvxZvc9XQtnivl35sydc048nfuvVkW0k8XYtT936pVja5jJv/Z7wPZo0wNzLzQSHWnVwTZtqY1su2to3bZhj7dewEYeu+iDawi7bhn7Yl9TWGsikrzksnNxr9zfsIErcaEAMysyZXrvE5mp6w7zc8rMzFJjGNlxFWHmWKMVd2DHsHuadQ+NkcKxZ2pPXC8FHHhu1v91X6ZcUZHYy8xwwyju5wAzJypDFdHka5OiaN1yHDl100BaMyq84cwrs1JjtTBu7E5xIpeebLndOZOlnK859d1bZ0JoHPiRU986ZxYZmdjP8/HRrkfSS2+MTTXlycyawhlHJBOH5k789A6x/H/sZQuMKKNatjGLvkoreUy/lsnsq1mXJOe/Ut6tM38DZpmDFxwTi8EAAAAASUVORK5CYII=");
|
||||
}
|
||||
|
||||
|
||||
ul.messages {
|
||||
padding: 12px 0;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
ul.messages li {
|
||||
line-height: 22px;
|
||||
position: relative;
|
||||
padding: 0 12px;
|
||||
}
|
||||
|
||||
ul.messages li.new {
|
||||
-webkit-animation-name: new;
|
||||
-webkit-animation-duration: 1400ms;
|
||||
-webkit-animation-iteration-count: 1;
|
||||
-webkit-animation-timing-function: ease-in-out;
|
||||
animation-name: new;
|
||||
animation-duration: 1400ms;
|
||||
animation-iteration-count: 1;
|
||||
animation-timing-function: ease-in-out;
|
||||
}
|
||||
|
||||
ul.messages li div.message {
|
||||
padding-left: 58px;
|
||||
}
|
||||
ul.messages li div.date {
|
||||
position: absolute;
|
||||
left: 12px
|
||||
}
|
||||
span.pending {
|
||||
padding-left: 28px;
|
||||
}
|
||||
span.pending:before {
|
||||
content:"";
|
||||
position:absolute;
|
||||
display:inline-block;
|
||||
top: 0;
|
||||
left: 12px;
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
background: url('roll.svg') center center no-repeat;
|
||||
background-size: 22px 22px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@media(max-width: 460px) {
|
||||
@@ -183,14 +184,7 @@ span.pending:before {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@-webkit-keyframes new {
|
||||
@keyframes new {
|
||||
0% {
|
||||
background-color: rgba(255, 255, 204, 1);
|
||||
}
|
||||
|
||||
@@ -1,23 +1,138 @@
|
||||
$.fn.htmlTo = function(elem) {
|
||||
return this.each(function() {
|
||||
$(elem).html($(this).html());
|
||||
const $ = document.querySelector.bind(document);
|
||||
|
||||
let socket;
|
||||
|
||||
function connect() {
|
||||
socket = new WebSocket("ws://" + location.host + "/ws");
|
||||
|
||||
socket.addEventListener("open", (event) => {
|
||||
showMessage("websocket connected");
|
||||
});
|
||||
|
||||
socket.addEventListener("message", (event) => {
|
||||
console.log(event.data)
|
||||
const msg = JSON.parse(event.data);
|
||||
if (msg.logMsg) {
|
||||
showMessage(msg.logMsg);
|
||||
}
|
||||
if (msg.tags) {
|
||||
processTags(msg.tags);
|
||||
}
|
||||
});
|
||||
|
||||
socket.addEventListener("close", (event) => {
|
||||
showMessage(`websocket closed ${event.code}`);
|
||||
setTimeout(connect, 5000);
|
||||
});
|
||||
}
|
||||
|
||||
let socket = new WebSocket("ws://" + location.host + "/ws");
|
||||
connect();
|
||||
|
||||
socket.onmessage = function(event) {
|
||||
let incomingMessage = event.data;
|
||||
showMessage(incomingMessage);
|
||||
};
|
||||
|
||||
socket.onclose = event => console.log(`Closed ${event.code}`);
|
||||
|
||||
function showMessage(message) {
|
||||
$( "<li/>", {
|
||||
"class": "new",
|
||||
html: message
|
||||
}).prependTo( "ul.messages" );
|
||||
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);
|
||||
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')
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
$('#send_image').onclick = function() {
|
||||
let formData = new FormData();
|
||||
formData.append("dst", $("#dstmac").value);
|
||||
formData.append("filename", $("#imgfile").value);
|
||||
formData.append("ttl", $("#ttl").value);
|
||||
fetch("/send_image", {
|
||||
method: "POST",
|
||||
body: formData
|
||||
})
|
||||
.then(response => response.text())
|
||||
.then(data => showMessage(data))
|
||||
.catch(error => showMessage('Error: ' + error));
|
||||
}
|
||||
|
||||
$('#send_fw').onclick = function () {
|
||||
let formData = new FormData();
|
||||
formData.append("dst", $("#dstmac").value);
|
||||
formData.append("filename", $("#fwfile").value);
|
||||
fetch("/send_fw", {
|
||||
method: "POST",
|
||||
body: formData
|
||||
})
|
||||
.then(response => response.text())
|
||||
.then(data => showMessage(data))
|
||||
.catch(error => showMessage('Error: ' + error));
|
||||
}
|
||||
|
||||
$('#req_checkin').onclick = function () {
|
||||
let formData = new FormData();
|
||||
formData.append("dst", $("#dstmac").value);
|
||||
fetch("/req_checkin", {
|
||||
method: "POST",
|
||||
body: formData
|
||||
})
|
||||
.then(response => response.text())
|
||||
.then(data => showMessage(data))
|
||||
.catch(error => showMessage('Error: ' + error));
|
||||
}
|
||||
|
||||
$('#clearlog').onclick = function () {
|
||||
$('#messages').innerHTML='';
|
||||
}
|
||||
|
||||
$('#taglist').addEventListener("click", (event) => {
|
||||
let currentElement = event.target;
|
||||
while (currentElement !== $('#taglist')) {
|
||||
if (currentElement.classList.contains("tagcard")) {
|
||||
break;
|
||||
}
|
||||
currentElement = currentElement.parentNode;
|
||||
}
|
||||
if (!currentElement.classList.contains("tagcard")) {
|
||||
return;
|
||||
}
|
||||
const mac = currentElement.dataset.mac;
|
||||
if (event.target.classList.contains("mac")) {
|
||||
$('#dstmac').value=mac;
|
||||
}
|
||||
if (event.target.classList.contains("configicon")) {
|
||||
console.log('config')
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
function showMessage(message) {
|
||||
const messages = $('#messages');
|
||||
var date = new Date(),
|
||||
time = date.toLocaleTimeString('en-US', {hour12: false, hour: '2-digit', minute:'2-digit', second:'2-digit'});
|
||||
messages.insertAdjacentHTML("afterbegin", '<li class="new">'+htmlEncode(time+' '+message)+'</li>');
|
||||
}
|
||||
|
||||
function htmlEncode(input) {
|
||||
const textArea = document.createElement("textarea");
|
||||
textArea.innerText = input;
|
||||
return textArea.innerHTML.split("<br>").join("\n");
|
||||
}
|
||||
@@ -29,4 +29,6 @@ enum EinkClut {
|
||||
|
||||
void tftinit();
|
||||
void spr2grays(TFT_eSprite &spr, long w, long h, String fileout);
|
||||
void bmp2grays(String filein,String fileout);
|
||||
void jpg2grays(String filein, String fileout);
|
||||
void bmp2grays(String filein, String fileout);
|
||||
|
||||
|
||||
@@ -3,9 +3,12 @@
|
||||
#include <ESPAsyncWebServer.h>
|
||||
|
||||
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 uint64_t swap64(uint64_t x);
|
||||
extern AsyncWebSocket ws;//("/ws");
|
||||
|
||||
|
||||
@@ -23,5 +23,6 @@ lib_deps =
|
||||
https://github.com/tzapu/WiFiManager.git#feature_asyncwebserver
|
||||
bblanchon/ArduinoJson
|
||||
bodmer/TFT_eSPI
|
||||
https://github.com/Bodmer/TJpg_Decoder.git
|
||||
upload_port = COM5
|
||||
monitor_port = COM5
|
||||
|
||||
@@ -21,7 +21,6 @@ void setup() {
|
||||
Serial.begin(115200);
|
||||
Serial.print(">\n");
|
||||
init_web();
|
||||
tftinit();
|
||||
|
||||
long timezone = 2;
|
||||
byte daysavetime = 1;
|
||||
@@ -33,22 +32,10 @@ void setup() {
|
||||
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("");
|
||||
|
||||
// WiFiManager wm;
|
||||
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);
|
||||
|
||||
/*
|
||||
wm.setWiFiAutoReconnect(true);
|
||||
wm.setConfigPortalTimeout(180);
|
||||
bool res = wm.autoConnect("ESP32ZigbeeBase", "password"); // password protected ap
|
||||
if (!res) {
|
||||
Serial.println("Failed to connect");
|
||||
ESP.restart();
|
||||
}
|
||||
wm.setWiFiAutoReconnect(true);
|
||||
*/
|
||||
}
|
||||
|
||||
void loop() {
|
||||
|
||||
@@ -2,14 +2,16 @@
|
||||
#include <FS.h>
|
||||
#include <LittleFS.h>
|
||||
#include <TFT_eSPI.h>
|
||||
#include <TJpg_Decoder.h>
|
||||
#include <makeimage.h>
|
||||
|
||||
TFT_eSPI tft = TFT_eSPI();
|
||||
TFT_eSprite spr = TFT_eSprite(&tft);
|
||||
|
||||
void tftinit() {
|
||||
TFT_eSPI tft = TFT_eSPI();
|
||||
TFT_eSprite spr = TFT_eSprite(&tft);
|
||||
//tijdelijk: voorbeeld voor aanmaak van plaatje
|
||||
|
||||
LittleFS.begin();
|
||||
|
||||
long w = 296, h = 128; // mag staand of liggend
|
||||
spr.createSprite(w, h);
|
||||
spr.setColorDepth(8);
|
||||
@@ -20,13 +22,32 @@ void tftinit() {
|
||||
spr.drawString("zondag", w / 2, 10);
|
||||
spr.loadFont("calibrib50", LittleFS);
|
||||
spr.setTextColor(TFT_BLACK, TFT_WHITE);
|
||||
spr.drawString("28 januari", w / 2, 73);
|
||||
spr.drawString("29 januari", w / 2, 73);
|
||||
spr.unloadFont();
|
||||
|
||||
spr2grays(spr, w, h, "/testspr3.bmp");
|
||||
|
||||
spr.deleteSprite();
|
||||
// bmp2grays("/test.bmp", "/testgrays3.bmp");
|
||||
}
|
||||
|
||||
bool spr_output(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t *bitmap) {
|
||||
spr.pushImage(x, y, w, h, bitmap);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void jpg2grays(String filein, String fileout) {
|
||||
TJpgDec.setJpgScale(1);
|
||||
TJpgDec.setCallback(spr_output);
|
||||
uint16_t w = 0, h = 0;
|
||||
TJpgDec.getFsJpgSize(&w, &h, filein);
|
||||
|
||||
spr.createSprite(w, h);
|
||||
spr.setColorDepth(8);
|
||||
spr.fillSprite(TFT_WHITE);
|
||||
TJpgDec.drawFsJpg(0, 0, filein);
|
||||
|
||||
spr2grays(spr, w, h, fileout);
|
||||
spr.deleteSprite();
|
||||
}
|
||||
|
||||
static uint32_t repackPackedVals(uint32_t val, uint32_t pixelsPerPackedUnit, uint32_t packedMultiplyVal) {
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <MD5Builder.h>
|
||||
#include <makeimage.h>
|
||||
|
||||
#include "LittleFS.h"
|
||||
#include "commstructs.h"
|
||||
@@ -29,7 +30,7 @@ bool checkCRC(void* p, uint8_t len) {
|
||||
return ((uint8_t*)p)[0] == total;
|
||||
}
|
||||
|
||||
uint8_t* getDataForFile(File* file) {
|
||||
uint8_t* getDataForFile(fs::File* file) {
|
||||
uint8_t* ret = nullptr;
|
||||
ret = (uint8_t*)malloc(file->size());
|
||||
if (ret) {
|
||||
@@ -50,13 +51,45 @@ void prepareCancelPending(uint64_t ver) {
|
||||
bool prepareDataAvail(String* filename, uint8_t dataType, uint8_t* dst, uint16_t nextCheckin) {
|
||||
*filename = "/" + *filename;
|
||||
if (!LittleFS.exists(*filename)) return false;
|
||||
File file = LittleFS.open(*filename);
|
||||
fs::File file = LittleFS.open(*filename);
|
||||
|
||||
if (file.size() == 0) {
|
||||
Serial.print("opened a file with size 0??\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (filename->endsWith(".bmp") || filename->endsWith(".BMP")) {
|
||||
struct BitmapFileHeader hdr;
|
||||
file.read((uint8_t*)&hdr, sizeof(hdr));
|
||||
if (hdr.width == 296 && hdr.height == 128) {
|
||||
//sorry, can't rotate
|
||||
Serial.println("when using BMP files, remember to only use 128px width and 296px height");
|
||||
wsString("when using BMP files, remember to only use 128px width and 296px height");
|
||||
return false;
|
||||
}
|
||||
if (hdr.sig[0] == 'B' && hdr.sig[1] == 'M' && hdr.bpp == 24) {
|
||||
Serial.println("converting 24bpp bmp to grays");
|
||||
wsString("converting 24bpp bmp to grays");
|
||||
char fileout[64];
|
||||
sprintf(fileout, "/temp/%02X%02X%02X%02X%02X%02X.bmp\0", dst[5], dst[4], dst[3], dst[2], dst[1], dst[0]);
|
||||
bmp2grays(*filename,(String)fileout);
|
||||
*filename = (String)fileout;
|
||||
file.close();
|
||||
file = LittleFS.open(*filename);
|
||||
}
|
||||
}
|
||||
|
||||
if (filename->endsWith(".jpg") || filename->endsWith(".JPG")) {
|
||||
Serial.println("converting jpg to grays");
|
||||
wsString("converting jpg to grays");
|
||||
char fileout[64];
|
||||
sprintf(fileout, "/temp/%02X%02X%02X%02X%02X%02X.bmp\0", dst[5], dst[4], dst[3], dst[2], dst[1], dst[0]);
|
||||
jpg2grays(*filename, (String)fileout);
|
||||
*filename = (String)fileout;
|
||||
file.close();
|
||||
file = LittleFS.open(*filename);
|
||||
}
|
||||
|
||||
uint8_t md5bytes[16];
|
||||
{
|
||||
MD5Builder md5;
|
||||
@@ -84,10 +117,17 @@ bool prepareDataAvail(String* filename, uint8_t dataType, uint8_t* dst, uint16_t
|
||||
pendinginfo->len = pending.availdatainfo.dataSize;
|
||||
pendinginfo->data = nullptr;
|
||||
pendinginfo->timeout = PENDING_TIMEOUT;
|
||||
// pendinginfo->data = getDataForFile(&file);
|
||||
pendinginfo->data = getDataForFile(&file);
|
||||
file.close();
|
||||
pendinginfo->timeout = 1800;
|
||||
pendingfiles.push_back(pendinginfo);
|
||||
|
||||
char dst_path[64];
|
||||
sprintf(dst_path, "/current/%02X%02X%02X%02X%02X%02X.pending\0", dst[5], dst[4], dst[3], dst[2], dst[1], dst[0]);
|
||||
file = LittleFS.open(dst_path, "w");
|
||||
int bytes_written = file.write(pendinginfo->data, pendinginfo->len);
|
||||
file.close();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -105,7 +145,7 @@ void processBlockRequest(struct espBlockRequest* br) {
|
||||
} else {
|
||||
if (pd->data == nullptr) {
|
||||
// not cached. open file, cache the data
|
||||
File file = LittleFS.open(pd->filename);
|
||||
fs::File file = LittleFS.open(pd->filename);
|
||||
if (!file) {
|
||||
Serial.print("Dunno how this happened... File pending but deleted in the meantime?\n");
|
||||
}
|
||||
@@ -140,12 +180,26 @@ 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);
|
||||
|
||||
char src_path[64];
|
||||
char dst_path[64];
|
||||
char tmp_path[64];
|
||||
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]);
|
||||
LittleFS.rename(src_path, dst_path);
|
||||
if (LittleFS.exists(tmp_path)) {
|
||||
LittleFS.remove(tmp_path);
|
||||
}
|
||||
}
|
||||
|
||||
void processDataReq(struct espAvailDataReq* eadr) {
|
||||
char buffer[64];
|
||||
uint8_t src[8];
|
||||
sprintf(buffer, "<ADR %02X%02X%02X%02X%02X%02X%02X%02X button: %02X\n\0", eadr->src[7], eadr->src[6], eadr->src[5], eadr->src[4], eadr->src[3], eadr->src[2], eadr->src[1], eadr->src[0], eadr->adr.buttonState);
|
||||
*((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);
|
||||
Serial.print(buffer);
|
||||
wsSendTaginfo(src);
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@ void webSocketSendProcess(void *parameter) {
|
||||
auto buffer = std::make_shared<std::vector<uint8_t>>(len);
|
||||
serializeJson(doc, buffer->data(), len);
|
||||
// ws.textAll((char*)buffer->data());
|
||||
ws.textAll("ohai");
|
||||
//ws.textAll("ohai");
|
||||
xSemaphoreGive(wsMutex);
|
||||
}
|
||||
}
|
||||
@@ -188,16 +188,42 @@ void onEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType
|
||||
}
|
||||
}
|
||||
|
||||
void doImageUpload(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final);
|
||||
|
||||
void wsString(String text) {
|
||||
DynamicJsonDocument doc(1500);
|
||||
doc["logMsg"] = text;
|
||||
xSemaphoreTake(wsMutex, portMAX_DELAY);
|
||||
ws.textAll(text);
|
||||
ws.textAll(doc.as<String>());
|
||||
xSemaphoreGive(wsMutex);
|
||||
}
|
||||
|
||||
void wsSendTaginfo(uint8_t src[8]) {
|
||||
DynamicJsonDocument doc(1500);
|
||||
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]);
|
||||
tag["mac"] = (String)buffer;
|
||||
//tag["buttonstate"] = eadr->adr.buttonState;
|
||||
xSemaphoreTake(wsMutex, portMAX_DELAY);
|
||||
ws.textAll(doc.as<String>());
|
||||
xSemaphoreGive(wsMutex);
|
||||
}
|
||||
|
||||
void init_web() {
|
||||
LittleFS.begin(true);
|
||||
|
||||
if (!LittleFS.exists("/.exclude.files")) {
|
||||
Serial.println("littlefs exclude.files aanmaken");
|
||||
File f = LittleFS.open("/.exclude.files", "w");
|
||||
f.close();
|
||||
}
|
||||
if (!LittleFS.exists("/current")) {
|
||||
LittleFS.mkdir("/current");
|
||||
}
|
||||
if (!LittleFS.exists("/temp")) {
|
||||
LittleFS.mkdir("/temp");
|
||||
}
|
||||
|
||||
WiFi.mode(WIFI_STA);
|
||||
WiFiManager wm;
|
||||
bool res;
|
||||
|
||||
Reference in New Issue
Block a user