mirror of
https://github.com/OpenEPaperLink/OpenEPaperLink.git
synced 2026-03-21 11:06:49 +01:00
Merge pull request #9 from nlimper/development
spiffseditor improvements
This commit is contained in:
BIN
esp32_fw/data/alignment.bmp
Normal file
BIN
esp32_fw/data/alignment.bmp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 111 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 111 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 111 KiB |
BIN
esp32_fw/data/fonts/bahnschrift30.vlw
Normal file
BIN
esp32_fw/data/fonts/bahnschrift30.vlw
Normal file
Binary file not shown.
BIN
esp32_fw/data/fonts/bahnschrift70.vlw
Normal file
BIN
esp32_fw/data/fonts/bahnschrift70.vlw
Normal file
Binary file not shown.
BIN
esp32_fw/data/fonts/bahnschrift80.vlw
Normal file
BIN
esp32_fw/data/fonts/bahnschrift80.vlw
Normal file
Binary file not shown.
BIN
esp32_fw/data/fonts/calibrib30.vlw
Normal file
BIN
esp32_fw/data/fonts/calibrib30.vlw
Normal file
Binary file not shown.
BIN
esp32_fw/data/fonts/calibrib35.vlw
Normal file
BIN
esp32_fw/data/fonts/calibrib35.vlw
Normal file
Binary file not shown.
BIN
esp32_fw/data/fonts/calibrib40.vlw
Normal file
BIN
esp32_fw/data/fonts/calibrib40.vlw
Normal file
Binary file not shown.
BIN
esp32_fw/data/fonts/weathericons30.vlw
Normal file
BIN
esp32_fw/data/fonts/weathericons30.vlw
Normal file
Binary file not shown.
BIN
esp32_fw/data/fonts/weathericons78.vlw
Normal file
BIN
esp32_fw/data/fonts/weathericons78.vlw
Normal file
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 15 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 16 KiB |
777
esp32_fw/data/www/edit.html
Normal file
777
esp32_fw/data/www/edit.html
Normal file
@@ -0,0 +1,777 @@
|
||||
<!--This is the plain html source of the hex encoded Editor-Page embedded in SPIFFSEditor.cpp -->
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<title>ESP Editor</title>
|
||||
<link rel="icon" href="data:,">
|
||||
<style type="text/css" media="screen">
|
||||
.cm {
|
||||
z-index: 300;
|
||||
position: absolute;
|
||||
left: 5px;
|
||||
border: 1px solid #444;
|
||||
background-color: #F5F5F5;
|
||||
display: none;
|
||||
box-shadow: 0 0 10px rgba(0, 0, 0, .4);
|
||||
font-size: 12px;
|
||||
font-family: sans-serif;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.cm ul {
|
||||
list-style: none;
|
||||
top: 0;
|
||||
left: 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.cm li {
|
||||
position: relative;
|
||||
min-width: 60px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.cm span {
|
||||
color: #444;
|
||||
display: inline-block;
|
||||
padding: 6px;
|
||||
}
|
||||
|
||||
.cm li:hover {
|
||||
background: #444;
|
||||
}
|
||||
|
||||
.cm li:hover span {
|
||||
color: #EEE;
|
||||
}
|
||||
|
||||
.tvu ul,
|
||||
.tvu li {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.tvu li {
|
||||
display: flex;
|
||||
justify-content: stretch;
|
||||
}
|
||||
|
||||
.tvu input {
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.tvu {
|
||||
font: normal 12px Verdana, Arial, Sans-serif;
|
||||
-moz-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
user-select: none;
|
||||
color: #444;
|
||||
line-height: 16px;
|
||||
}
|
||||
|
||||
.tvu .icon {
|
||||
padding: 0 0 0 5px;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
width: 20px;
|
||||
text-align: center;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
.tvu .filename {
|
||||
padding: 2px 0 0 2px;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
width: auto;
|
||||
flex: 2;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.tvu .size {
|
||||
padding: 2px 5px 0 5px;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.tvu li:hover {
|
||||
background-color:#cccccc;
|
||||
}
|
||||
|
||||
#uploader {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
background-color: #444;
|
||||
color: #EEE;
|
||||
height: 45px;
|
||||
}
|
||||
|
||||
button {
|
||||
background-color: #eeeeee;
|
||||
border: 0px;
|
||||
cursor: pointer;
|
||||
padding: 3px 5px;
|
||||
margin: 10px;
|
||||
appearance: none;
|
||||
}
|
||||
|
||||
input {
|
||||
background: #ffffff;
|
||||
border: 0px;
|
||||
appearance: none;
|
||||
padding: 2px 5px;
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
input[type="file"] {
|
||||
background: none;
|
||||
}
|
||||
|
||||
.uploadpath {
|
||||
background: none;
|
||||
color: white;
|
||||
}
|
||||
|
||||
#tree {
|
||||
position: absolute;
|
||||
top: 50px;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 300px;
|
||||
}
|
||||
|
||||
#editor,
|
||||
#preview {
|
||||
position: absolute;
|
||||
top: 45px;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 300px;
|
||||
border-left: 1px solid #EEE;
|
||||
}
|
||||
|
||||
#preview {
|
||||
background-color: #EEE;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
#loader {
|
||||
position: absolute;
|
||||
top: 36%;
|
||||
right: 40%;
|
||||
}
|
||||
|
||||
.loader {
|
||||
z-index: 10000;
|
||||
border: 8px solid #b5b5b5;
|
||||
/* Grey */
|
||||
border-top: 8px solid #3498db;
|
||||
/* Blue */
|
||||
border-bottom: 8px solid #3498db;
|
||||
/* Blue */
|
||||
border-radius: 50%;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
animation: spin 2s linear infinite;
|
||||
display: none;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
if (typeof XMLHttpRequest === "undefined") {
|
||||
XMLHttpRequest = function () {
|
||||
try { return new ActiveXObject("Msxml2.XMLHTTP.6.0"); } catch (e) { }
|
||||
try { return new ActiveXObject("Msxml2.XMLHTTP.3.0"); } catch (e) { }
|
||||
try { return new ActiveXObject("Microsoft.XMLHTTP"); } catch (e) { }
|
||||
throw new Error("This browser does not support XMLHttpRequest.");
|
||||
};
|
||||
}
|
||||
|
||||
function ge(a) {
|
||||
return document.getElementById(a);
|
||||
}
|
||||
function ce(a) {
|
||||
return document.createElement(a);
|
||||
}
|
||||
|
||||
function sortByKey(array, key) {
|
||||
return array.sort(function (a, b) {
|
||||
var x = a[key]; var y = b[key];
|
||||
return ((x < y) ? -1 : ((x > y) ? 1 : 0));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
var QueuedRequester = function () {
|
||||
this.queue = [];
|
||||
this.running = false;
|
||||
this.xmlhttp = null;
|
||||
}
|
||||
QueuedRequester.prototype = {
|
||||
_request: function (req) {
|
||||
this.running = true;
|
||||
if (!req instanceof Object) return;
|
||||
var that = this;
|
||||
|
||||
function ajaxCb(x, d) {
|
||||
return function () {
|
||||
if (x.readyState == 4) {
|
||||
ge("loader").style.display = "none";
|
||||
d.callback(x.status, x.responseText);
|
||||
if (that.queue.length === 0) that.running = false;
|
||||
if (that.running) that._request(that.queue.shift());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ge("loader").style.display = "block";
|
||||
|
||||
var p = "";
|
||||
if (req.params instanceof FormData) {
|
||||
p = req.params;
|
||||
} else if (req.params instanceof Object) {
|
||||
for (var key in req.params) {
|
||||
if (p === "")
|
||||
p += (req.method === "GET") ? "?" : "";
|
||||
else
|
||||
p += "&";
|
||||
p += encodeURIComponent(key) + "=" + encodeURIComponent(req.params[key]);
|
||||
};
|
||||
}
|
||||
|
||||
this.xmlhttp = new XMLHttpRequest();
|
||||
this.xmlhttp.onreadystatechange = ajaxCb(this.xmlhttp, req);
|
||||
if (req.method === "GET") {
|
||||
this.xmlhttp.open(req.method, req.url + p, true);
|
||||
this.xmlhttp.send();
|
||||
} else {
|
||||
this.xmlhttp.open(req.method, req.url, true);
|
||||
if (p instanceof String)
|
||||
this.xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
|
||||
this.xmlhttp.send(p);
|
||||
}
|
||||
},
|
||||
stop: function () {
|
||||
if (this.running) this.running = false;
|
||||
if (this.xmlhttp && this.xmlhttp.readyState < 4) {
|
||||
this.xmlhttp.abort();
|
||||
}
|
||||
},
|
||||
add: function (method, url, params, callback) {
|
||||
this.queue.push({ url: url, method: method, params: params, callback: callback });
|
||||
if (!this.running) {
|
||||
this._request(this.queue.shift());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var requests = new QueuedRequester();
|
||||
|
||||
function createFileUploader(element, tree, editor) {
|
||||
var xmlHttp;
|
||||
|
||||
var refresh = ce("button");
|
||||
refresh.innerHTML = 'Refresh List';
|
||||
ge(element).appendChild(refresh);
|
||||
|
||||
var path = ce("input");
|
||||
path.id = "upload-path";
|
||||
path.type = "text";
|
||||
path.name = "path";
|
||||
path.classList.add("uploadpath");
|
||||
path.defaultValue = "/";
|
||||
ge(element).appendChild(path);
|
||||
|
||||
var input = ce("input");
|
||||
input.type = "file";
|
||||
input.multiple = false;
|
||||
input.name = "data";
|
||||
input.id = "upload-select";
|
||||
ge(element).appendChild(input);
|
||||
|
||||
/*
|
||||
var mkfile = ce("button");
|
||||
mkfile.innerHTML = 'Create';
|
||||
ge(element).appendChild(mkfile);
|
||||
*/
|
||||
|
||||
var filename = ce("input");
|
||||
filename.id = "editor-filename";
|
||||
filename.type = "text";
|
||||
|
||||
filename.size = 20;
|
||||
ge(element).appendChild(filename);
|
||||
|
||||
var button = ce("button");
|
||||
button.id = "button";
|
||||
button.innerHTML = 'Upload';
|
||||
button.style.display = 'none';
|
||||
ge(element).appendChild(button);
|
||||
|
||||
var savefile = ce("button");
|
||||
savefile.id = "savefile";
|
||||
savefile.innerHTML = ' Save ';
|
||||
savefile.style.display = 'none';
|
||||
ge(element).appendChild(savefile);
|
||||
|
||||
function httpPostProcessRequest(status, responseText) {
|
||||
if (status != 200)
|
||||
alert("ERROR[" + status + "]: " + responseText);
|
||||
else
|
||||
tree.refreshPath(path.value);
|
||||
}
|
||||
function createPath(p) {
|
||||
var formData = new FormData();
|
||||
formData.append("path", p);
|
||||
requests.add("PUT", "/edit", formData, httpPostProcessRequest);
|
||||
}
|
||||
|
||||
/*
|
||||
mkfile.onclick = function (e) {
|
||||
createPath(filename.value);
|
||||
editor.loadUrl(filename.value);
|
||||
path.value = (filename.value);
|
||||
};
|
||||
*/
|
||||
|
||||
savefile.onclick = function (e) {
|
||||
editor.execCommand('saveCommand');
|
||||
};
|
||||
|
||||
refresh.onclick = function (e) {
|
||||
tree.refreshPath(path.value);
|
||||
};
|
||||
|
||||
button.onclick = function (e) {
|
||||
if (input.files.length === 0) {
|
||||
return;
|
||||
}
|
||||
var formData = new FormData();
|
||||
formData.append("data", input.files[0], ge("editor-filename").value);
|
||||
requests.add("POST", "/edit", formData, httpPostProcessRequest);
|
||||
var uploadSelect = ge("upload-select");
|
||||
uploadSelect.value = "";
|
||||
};
|
||||
input.onchange = function (e) {
|
||||
if (input.files.length === 0) return;
|
||||
var filename = input.files[0].name;
|
||||
ge("editor-filename").value = path.value + (path.value=="/" ? "" : "/") + filename;
|
||||
button.style.display = 'inline-block';
|
||||
savefile.style.display = 'none';
|
||||
};
|
||||
}
|
||||
|
||||
function createTree(element, editor) {
|
||||
var preview = ge("preview");
|
||||
var treeRoot = ce("div");
|
||||
treeRoot.className = "tvu";
|
||||
ge(element).appendChild(treeRoot);
|
||||
|
||||
function loadDownload(path) {
|
||||
ge('download-frame').src = "/edit?download=" + path;
|
||||
}
|
||||
|
||||
function loadPreview(path) {
|
||||
ge("button").style.display = 'none';
|
||||
ge("savefile").style.display = 'none';
|
||||
|
||||
var edfname = ge("editor-filename");
|
||||
|
||||
var filename = path;
|
||||
var ext = /(?:\.([^.]+))?$/.exec(filename)[1];
|
||||
var name = /(.*)\.[^.]+$/.exec(filename)[1];
|
||||
if (typeof name !== undefined) {
|
||||
filename = name;
|
||||
}
|
||||
|
||||
edfname.value = filename + "." + ext;
|
||||
ge("editor").style.display = "none";
|
||||
preview.style.display = "block";
|
||||
preview.innerHTML = '<img src="/edit?edit=' + path + '&_cb=' + Date.now() + '" style="max-width:100%; max-height:100%; margin:auto; display:block;" />';
|
||||
}
|
||||
|
||||
function fillFileMenu(el, path) {
|
||||
var list = ce("ul");
|
||||
el.appendChild(list);
|
||||
var action = ce("li");
|
||||
list.appendChild(action);
|
||||
if (isImageFile(path)) {
|
||||
action.innerHTML = "<span>Preview</span>";
|
||||
action.onclick = function (e) {
|
||||
loadPreview(path);
|
||||
if (document.body.getElementsByClassName('cm').length > 0) document.body.removeChild(el);
|
||||
};
|
||||
} else if (isTextFile(path)) {
|
||||
action.innerHTML = "<span>Edit</span>";
|
||||
action.onclick = function (e) {
|
||||
editor.loadUrl(path);
|
||||
if (document.body.getElementsByClassName('cm').length > 0) document.body.removeChild(el);
|
||||
};
|
||||
}
|
||||
var download = ce("li");
|
||||
list.appendChild(download);
|
||||
download.innerHTML = "<span>Download</span>";
|
||||
download.onclick = function (e) {
|
||||
loadDownload(path);
|
||||
if (document.body.getElementsByClassName('cm').length > 0) document.body.removeChild(el);
|
||||
};
|
||||
var delFile = ce("li");
|
||||
list.appendChild(delFile);
|
||||
delFile.innerHTML = "<span>Delete</span>";
|
||||
delFile.onclick = function (e) {
|
||||
httpDelete(path);
|
||||
if (document.body.getElementsByClassName('cm').length > 0) document.body.removeChild(el);
|
||||
};
|
||||
}
|
||||
|
||||
function showContextMenu(event, path, isfile) {
|
||||
var divContext = ce("div");
|
||||
var scrollTop = document.body.scrollTop ? document.body.scrollTop : document.documentElement.scrollTop;
|
||||
var scrollLeft = document.body.scrollLeft ? document.body.scrollLeft : document.documentElement.scrollLeft;
|
||||
var left = event.clientX + scrollLeft;
|
||||
var top = event.clientY + scrollTop;
|
||||
divContext.className = 'cm';
|
||||
divContext.style.display = 'block';
|
||||
divContext.style.left = left + 'px';
|
||||
divContext.style.top = top + 'px';
|
||||
fillFileMenu(divContext, path);
|
||||
document.body.appendChild(divContext);
|
||||
var width = divContext.offsetWidth;
|
||||
var height = divContext.offsetHeight;
|
||||
divContext.onmouseout = function (e) {
|
||||
if (e.clientX < left || e.clientX > (left + width) || e.clientY < top || e.clientY > (top + height)) {
|
||||
if (document.body.getElementsByClassName('cm').length > 0) document.body.removeChild(divContext);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function createTreeLeaf(path, name, size) {
|
||||
var leaf = ce("li");
|
||||
leaf.id = path + (path != "/" ? "/":"") + name;
|
||||
|
||||
var icon = ce("span");
|
||||
icon.innerHTML = "📄";
|
||||
icon.classList.add("icon");
|
||||
leaf.appendChild(icon);
|
||||
|
||||
var label = ce("span");
|
||||
label.innerHTML = name;
|
||||
label.classList.add("filename");
|
||||
leaf.appendChild(label);
|
||||
|
||||
var filesize = ce("span");
|
||||
filesize.innerHTML = formatBytes(size);
|
||||
filesize.classList.add("size");
|
||||
leaf.appendChild(filesize);
|
||||
|
||||
leaf.onclick = function (e) {
|
||||
if (isTextFile(leaf.id.toLowerCase())) {
|
||||
editor.loadUrl(leaf.id);
|
||||
} else if (isImageFile(leaf.id.toLowerCase())) {
|
||||
loadPreview(leaf.id);
|
||||
}
|
||||
};
|
||||
leaf.oncontextmenu = function (e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
showContextMenu(e, leaf.id, true);
|
||||
};
|
||||
return leaf;
|
||||
}
|
||||
|
||||
function createDirLeaf(path, name, size) {
|
||||
var leaf = ce("li");
|
||||
leaf.id = path + (path != "/" ? "/" : "") + name;
|
||||
|
||||
var icon = ce("span");
|
||||
icon.innerHTML = "📁";
|
||||
icon.classList.add("icon");
|
||||
leaf.appendChild(icon);
|
||||
|
||||
var label = ce("span");
|
||||
label.innerHTML = name;
|
||||
label.classList.add("filename");
|
||||
leaf.appendChild(label);
|
||||
|
||||
var filesize = ce("span");
|
||||
filesize.innerHTML = "";
|
||||
filesize.classList.add("size");
|
||||
leaf.appendChild(filesize);
|
||||
|
||||
leaf.onclick = function (e) {
|
||||
treeRoot.removeChild(treeRoot.childNodes[0]);
|
||||
if (name == "..") {
|
||||
httpGet(treeRoot, "/");
|
||||
} else {
|
||||
httpGet(treeRoot, "/" + name);
|
||||
}
|
||||
};
|
||||
leaf.oncontextmenu = function (e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
showContextMenu(e, leaf.id, true);
|
||||
};
|
||||
return leaf;
|
||||
}
|
||||
|
||||
function formatBytes(bytes, decimalPlaces = 2) {
|
||||
if (bytes === 0) return '';
|
||||
const k = 1024;
|
||||
const dm = decimalPlaces < 0 ? 0 : decimalPlaces;
|
||||
const sizes = ['B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
|
||||
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
||||
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
|
||||
}
|
||||
|
||||
function addList(parent, path, items) {
|
||||
ge("upload-path").value = path
|
||||
ge("editor-filename").value = path
|
||||
sortByKey(items, 'name');
|
||||
var list = ce("ul");
|
||||
parent.appendChild(list);
|
||||
if (path != "/") {
|
||||
list.appendChild(createDirLeaf("/", "..", 0));
|
||||
}
|
||||
var ll = items.length;
|
||||
for (var i = 0; i < ll; i++) {
|
||||
if (items[i].type === "file") {
|
||||
list.appendChild(createTreeLeaf(path, items[i].name, items[i].size));
|
||||
}
|
||||
if (items[i].type === "dir") {
|
||||
list.insertBefore(createDirLeaf(path, items[i].name, items[i].size), list.firstChild);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function isTextFile(path) {
|
||||
var ext = /(?:\.([^.]+))?$/.exec(path)[1];
|
||||
if (typeof ext !== undefined) {
|
||||
switch (ext) {
|
||||
case "txt":
|
||||
case "htm":
|
||||
case "html":
|
||||
case "js":
|
||||
case "css":
|
||||
case "xml":
|
||||
case "json":
|
||||
case "conf":
|
||||
case "ini":
|
||||
case "h":
|
||||
case "c":
|
||||
case "cpp":
|
||||
case "php":
|
||||
case "hex":
|
||||
case "ino":
|
||||
case "pde":
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function isImageFile(path) {
|
||||
var ext = /(?:\.([^.]+))?$/.exec(path)[1];
|
||||
if (typeof ext !== undefined) {
|
||||
switch (ext) {
|
||||
case "png":
|
||||
case "jpg":
|
||||
case "gif":
|
||||
case "bmp":
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
this.refreshPath = function (path) {
|
||||
treeRoot.removeChild(treeRoot.childNodes[0]);
|
||||
httpGet(treeRoot, path);
|
||||
};
|
||||
|
||||
function delCb(path) {
|
||||
return function (status, responseText) {
|
||||
if (status != 200) {
|
||||
alert("ERROR[" + status + "]: " + responseText);
|
||||
} else {
|
||||
treeRoot.removeChild(treeRoot.childNodes[0]);
|
||||
httpGet(treeRoot, "/");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function httpDelete(filename) {
|
||||
var formData = new FormData();
|
||||
formData.append("path", filename);
|
||||
requests.add("DELETE", "/edit", formData, delCb(filename));
|
||||
}
|
||||
|
||||
function getCb(parent, path) {
|
||||
return function (status, responseText) {
|
||||
if (status == 200)
|
||||
addList(parent, path, JSON.parse(responseText));
|
||||
}
|
||||
}
|
||||
|
||||
function httpGet(parent, path) {
|
||||
requests.add("GET", "/edit", { list: path }, getCb(parent, path));
|
||||
}
|
||||
|
||||
httpGet(treeRoot, "/");
|
||||
return this;
|
||||
}
|
||||
|
||||
function createEditor(element, file, lang, theme, type) {
|
||||
function getLangFromFilename(filename) {
|
||||
var lang = "plain";
|
||||
var ext = /(?:\.([^.]+))?$/.exec(filename)[1];
|
||||
if (typeof ext !== undefined) {
|
||||
switch (ext) {
|
||||
case "txt": lang = "plain"; break;
|
||||
case "hex": lang = "plain"; break;
|
||||
case "conf": lang = "plain"; break;
|
||||
case "htm": lang = "html"; break;
|
||||
case "js": lang = "javascript"; break;
|
||||
case "h": lang = "c_cpp"; break;
|
||||
case "c": lang = "c_cpp"; break;
|
||||
case "cpp": lang = "c_cpp"; break;
|
||||
case "css":
|
||||
case "scss":
|
||||
case "php":
|
||||
case "html":
|
||||
case "json":
|
||||
case "xml":
|
||||
case "ini": lang = ext;
|
||||
}
|
||||
}
|
||||
return lang;
|
||||
}
|
||||
|
||||
if (typeof file === "undefined") file = "/index.html";
|
||||
|
||||
if (typeof lang === "undefined") {
|
||||
lang = getLangFromFilename(file);
|
||||
}
|
||||
|
||||
if (typeof theme === "undefined") theme = "textmate";
|
||||
|
||||
if (typeof type === "undefined") {
|
||||
type = "text/" + lang;
|
||||
if (lang === "c_cpp") type = "text/plain";
|
||||
}
|
||||
|
||||
var editor = ace.edit(element);
|
||||
function httpPostProcessRequest(status, responseText) {
|
||||
if (status != 200) alert("ERROR[" + status + "]: " + responseText);
|
||||
}
|
||||
function httpPost(filename, data, type) {
|
||||
var formData = new FormData();
|
||||
formData.append("data", new Blob([data], { type: type }), filename);
|
||||
requests.add("POST", "/edit", formData, httpPostProcessRequest);
|
||||
}
|
||||
function httpGetProcessRequest(status, responseText) {
|
||||
ge("preview").style.display = "none";
|
||||
ge("editor").style.display = "block";
|
||||
if (status == 200)
|
||||
editor.setValue(responseText);
|
||||
else
|
||||
editor.setValue("");
|
||||
editor.clearSelection();
|
||||
}
|
||||
function httpGet(theUrl) {
|
||||
requests.add("GET", "/edit", { edit: theUrl }, httpGetProcessRequest);
|
||||
}
|
||||
|
||||
if (lang !== "plain") editor.getSession().setMode("ace/mode/" + lang);
|
||||
editor.setTheme("ace/theme/" + theme);
|
||||
editor.$blockScrolling = Infinity;
|
||||
editor.getSession().setUseSoftTabs(true);
|
||||
editor.getSession().setTabSize(2);
|
||||
editor.setHighlightActiveLine(true);
|
||||
editor.setShowPrintMargin(false);
|
||||
editor.commands.addCommand({
|
||||
name: 'saveCommand',
|
||||
bindKey: { win: 'Ctrl-S', mac: 'Command-S' },
|
||||
exec: function (editor) {
|
||||
httpPost(file, editor.getValue() + "", type);
|
||||
},
|
||||
readOnly: false
|
||||
});
|
||||
editor.commands.addCommand({
|
||||
name: 'undoCommand',
|
||||
bindKey: { win: 'Ctrl-Z', mac: 'Command-Z' },
|
||||
exec: function (editor) {
|
||||
editor.getSession().getUndoManager().undo(false);
|
||||
},
|
||||
readOnly: false
|
||||
});
|
||||
editor.commands.addCommand({
|
||||
name: 'redoCommand',
|
||||
bindKey: { win: 'Ctrl-Shift-Z', mac: 'Command-Shift-Z' },
|
||||
exec: function (editor) {
|
||||
editor.getSession().getUndoManager().redo(false);
|
||||
},
|
||||
readOnly: false
|
||||
});
|
||||
editor.loadUrl = function (filename) {
|
||||
ge("button").style.display = 'none';
|
||||
ge("savefile").style.display = 'inline-block';
|
||||
var edfname = ge("editor-filename");
|
||||
edfname.value = filename;
|
||||
file = filename;
|
||||
lang = getLangFromFilename(file);
|
||||
type = "text/" + lang;
|
||||
if (lang !== "plain") editor.getSession().setMode("ace/mode/" + lang);
|
||||
httpGet(file);
|
||||
};
|
||||
return editor;
|
||||
}
|
||||
function onBodyLoad() {
|
||||
var vars = {};
|
||||
var parts = window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, function (m, key, value) { vars[key] = value; });
|
||||
var editor = createEditor("editor", vars.file, vars.lang, vars.theme);
|
||||
var tree = createTree("tree", editor);
|
||||
createFileUploader("uploader", tree, editor);
|
||||
if (typeof vars.file === "undefined") vars.file = "/index.htm";
|
||||
editor.loadUrl(vars.file);
|
||||
};
|
||||
</script>
|
||||
<script id='ace' src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.2.6/ace.js" type="text/javascript"
|
||||
charset="utf-8"></script>
|
||||
<script>
|
||||
if (typeof ace.edit == "undefined") {
|
||||
var script = document.createElement('script');
|
||||
script.src = "/ace.js";
|
||||
script.async = false;
|
||||
document.head.appendChild(script);
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body onload="onBodyLoad();">
|
||||
<div id="loader" class="loader"></div>
|
||||
<div id="uploader"></div>
|
||||
<div id="tree"></div>
|
||||
<div id="editor"></div>
|
||||
<div id="preview" style="display:none;"></div>
|
||||
<iframe id=download-frame style='display:none;'></iframe>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
<title>Solum - alternative proto AP</title>
|
||||
<link rel="stylesheet" href="main.css" type="text/css" />
|
||||
<link rel="icon" href="data:,">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
@@ -24,10 +25,10 @@
|
||||
<p>
|
||||
<label for="cfgmodel">Model</label>
|
||||
<select 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>
|
||||
<option value="99">unknown</option>
|
||||
<option value="0">1.54" 152x152px</option>
|
||||
<option value="1">2.9" 296x128px</option>
|
||||
<option value="2">4.2" 400x300px</option>
|
||||
</select>
|
||||
</p>
|
||||
<p>
|
||||
@@ -37,8 +38,8 @@
|
||||
<option value="1">current date</option>
|
||||
<option value="2">count days</option>
|
||||
<option value="3">count hours</option>
|
||||
<option value="4" disabled>current weather</option>
|
||||
<option value="6" disabled>memo text</option>
|
||||
<option value="4">current weather</option>
|
||||
<option value="6">memo text</option>
|
||||
<option value="7">image url</option>
|
||||
<option value="5">firmware update</option>
|
||||
</select>
|
||||
@@ -58,6 +59,7 @@
|
||||
|
||||
<div class="actionbox">
|
||||
<div>
|
||||
<div class="editbtn"><a href="/edit" target="littlefs" class="filebutton">edit littleFS</a></div>
|
||||
Currently active tags:<br>
|
||||
</div>
|
||||
</div>
|
||||
@@ -65,16 +65,21 @@ label {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.filebutton {
|
||||
padding:2px 5px;
|
||||
background-color: #cccccc;
|
||||
text-decoration: none;
|
||||
color: black;
|
||||
}
|
||||
|
||||
.editbtn {
|
||||
float:right;
|
||||
}
|
||||
|
||||
.columns div {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.actionbox div div {
|
||||
padding: 5px;
|
||||
margin: 5px;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
input {
|
||||
border: solid 1px #666666;
|
||||
padding: 4px;
|
||||
@@ -239,6 +244,9 @@ ul.messages li.new {
|
||||
animation-timing-function: ease-in-out;
|
||||
}
|
||||
|
||||
.error {
|
||||
color: red;
|
||||
}
|
||||
|
||||
|
||||
@media(max-width: 460px) {
|
||||
@@ -1,7 +1,7 @@
|
||||
const $ = document.querySelector.bind(document);
|
||||
|
||||
const contentModes = ["static image", "current date", "counting days", "counting hours", "current weather", "firmware update", "memo text", "image url"];
|
||||
const models = ["unknown type", "1.54\" 152x152px", "2.9\" 296x128px", "4.2\" 400x300px"];
|
||||
const models = ["1.54\" 152x152px", "2.9\" 296x128px", "4.2\" 400x300px"];
|
||||
const contentModeOptions = [];
|
||||
contentModeOptions[0] = ["filename","timetolive"];
|
||||
contentModeOptions[1] = [];
|
||||
@@ -42,7 +42,10 @@ function connect() {
|
||||
console.log(event.data);
|
||||
const msg = JSON.parse(event.data);
|
||||
if (msg.logMsg) {
|
||||
showMessage(msg.logMsg);
|
||||
showMessage(msg.logMsg,false);
|
||||
}
|
||||
if (msg.errMsg) {
|
||||
showMessage(msg.errMsg,true);
|
||||
}
|
||||
if (msg.tags) {
|
||||
processTags(msg.tags);
|
||||
@@ -226,11 +229,15 @@ function contentselected() {
|
||||
});
|
||||
}
|
||||
|
||||
function showMessage(message) {
|
||||
function showMessage(message,iserr) {
|
||||
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>');
|
||||
if (iserr) {
|
||||
messages.insertAdjacentHTML("afterbegin", '<li class="new error">' + htmlEncode(time + ' ' + message) + '</li>');
|
||||
} else {
|
||||
messages.insertAdjacentHTML("afterbegin", '<li class="new">'+htmlEncode(time+' '+message)+'</li>');
|
||||
}
|
||||
}
|
||||
|
||||
function htmlEncode(input) {
|
||||
@@ -9,7 +9,11 @@
|
||||
void contentRunner();
|
||||
void drawNew(uint8_t mac[8], bool buttonPressed, tagRecord *&taginfo);
|
||||
bool updateTagImage(String &filename, uint8_t *dst, uint16_t nextCheckin);
|
||||
void drawDate(String &filename);
|
||||
void drawNumber(String &filename, int32_t count, int32_t thresholdred);
|
||||
void drawDate(String &filename, tagRecord *&taginfo);
|
||||
void drawNumber(String &filename, int32_t count, int32_t thresholdred, tagRecord *&taginfo);
|
||||
void drawWeather(String &filename, String location, tagRecord *&taginfo);
|
||||
bool getImgURL(String &filename, String URL, time_t fetched);
|
||||
char *formatHttpDate(time_t t);
|
||||
char *formatHttpDate(time_t t);
|
||||
String urlEncode(const char *msg);
|
||||
int windSpeedToBeaufort(float windSpeed);
|
||||
String windDirectionIcon(int degrees);
|
||||
|
||||
@@ -24,6 +24,9 @@
|
||||
// this determines how long images will be cached;
|
||||
#define PENDING_DATA_TIMEOUT 60
|
||||
|
||||
#define SOLUM_154_033 0
|
||||
#define SOLUM_29_033 1
|
||||
#define SOLUM_42_033 2
|
||||
|
||||
// flasher options
|
||||
#define CUSTOM_MAC_HDR 0x0000
|
||||
|
||||
@@ -7,7 +7,8 @@ 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);
|
||||
void wsString(String text);
|
||||
void wsLog(String text);
|
||||
void wsErr(String text);
|
||||
void wsSendTaginfo(uint8_t mac[6]);
|
||||
void wsSendSysteminfo();
|
||||
|
||||
|
||||
@@ -2,396 +2,9 @@
|
||||
|
||||
#include <FS.h>
|
||||
|
||||
// File: edit.htm.gz, Size: 4151
|
||||
#define edit_htm_gz_len 4151
|
||||
const uint8_t edit_htm_gz[] PROGMEM = {
|
||||
0x1F, 0x8B, 0x08, 0x08, 0xB8, 0x94, 0xB1, 0x59, 0x00, 0x03, 0x65, 0x64, 0x69, 0x74, 0x2E, 0x68,
|
||||
0x74, 0x6D, 0x00, 0xB5, 0x3A, 0x0B, 0x7B, 0xDA, 0xB8, 0xB2, 0x7F, 0xC5, 0x71, 0xCF, 0x66, 0xED,
|
||||
0x83, 0x31, 0x90, 0xA4, 0xD9, 0xD6, 0xC4, 0xC9, 0x42, 0x92, 0x36, 0x6D, 0xF3, 0x6A, 0x80, 0xB6,
|
||||
0x69, 0x4F, 0xEE, 0x7E, 0xC2, 0x16, 0xA0, 0xC6, 0x96, 0x5D, 0x5B, 0x0E, 0x49, 0x59, 0xFE, 0xFB,
|
||||
0x9D, 0x91, 0x6C, 0xB0, 0x09, 0x69, 0x77, 0xCF, 0xBD, 0xBB, 0xDD, 0x2D, 0x92, 0x46, 0x33, 0x9A,
|
||||
0x19, 0xCD, 0x53, 0xDE, 0xBD, 0x8D, 0xA3, 0x8B, 0xC3, 0xFE, 0xF5, 0xE5, 0xB1, 0x36, 0x11, 0x61,
|
||||
0xB0, 0xBF, 0x87, 0x7F, 0x6B, 0x01, 0xE1, 0x63, 0x97, 0xF2, 0xFD, 0x3D, 0xC1, 0x44, 0x40, 0xF7,
|
||||
0x8F, 0x7B, 0x97, 0xDA, 0xB1, 0xCF, 0x44, 0x94, 0xEC, 0x35, 0xD4, 0xCA, 0x5E, 0x2A, 0x1E, 0x02,
|
||||
0xAA, 0x85, 0xD4, 0x67, 0xC4, 0x4D, 0xBD, 0x84, 0xC2, 0x66, 0xDB, 0x0B, 0x67, 0xDF, 0xEB, 0x8C,
|
||||
0xFB, 0xF4, 0xDE, 0xD9, 0x6E, 0x36, 0xDB, 0x71, 0x94, 0x32, 0xC1, 0x22, 0xEE, 0x90, 0x61, 0x1A,
|
||||
0x05, 0x99, 0xA0, 0xED, 0x80, 0x8E, 0x84, 0xF3, 0x3C, 0xBE, 0x6F, 0x0F, 0xA3, 0xC4, 0xA7, 0x89,
|
||||
0xD3, 0x8A, 0xEF, 0x35, 0x00, 0x31, 0x5F, 0x7B, 0xB6, 0xB3, 0xB3, 0xD3, 0x1E, 0x12, 0xEF, 0x76,
|
||||
0x9C, 0x44, 0x19, 0xF7, 0xEB, 0x5E, 0x14, 0x44, 0x89, 0xF3, 0x6C, 0xF4, 0x1C, 0xFF, 0xB4, 0x7D,
|
||||
0x96, 0xC6, 0x01, 0x79, 0x70, 0x78, 0xC4, 0x29, 0xE0, 0xDE, 0xD7, 0xD3, 0x09, 0xF1, 0xA3, 0xA9,
|
||||
0xD3, 0xD4, 0x9A, 0x5A, 0xAB, 0x09, 0x44, 0x92, 0xF1, 0x90, 0x18, 0x4D, 0x0B, 0xFF, 0xD8, 0x3B,
|
||||
0x66, 0x7B, 0x14, 0x71, 0x51, 0x4F, 0xD9, 0x77, 0xEA, 0xB4, 0xB6, 0xE0, 0x34, 0x39, 0x1D, 0x91,
|
||||
0x90, 0x05, 0x0F, 0x4E, 0x4A, 0x78, 0x5A, 0x4F, 0x69, 0xC2, 0x46, 0x6A, 0x79, 0x4A, 0xD9, 0x78,
|
||||
0x22, 0x9C, 0xDF, 0x9A, 0xCD, 0x39, 0xF0, 0xAF, 0x65, 0xC1, 0x2C, 0x60, 0x29, 0x20, 0xA3, 0x78,
|
||||
0xEA, 0x3C, 0x11, 0xC5, 0x4E, 0x53, 0xB1, 0xDE, 0x6C, 0x87, 0x24, 0x19, 0x33, 0x0E, 0x83, 0x98,
|
||||
0xF8, 0x3E, 0xE3, 0x63, 0x47, 0xA1, 0x05, 0x6C, 0xB6, 0x90, 0x36, 0xA1, 0x01, 0x11, 0xEC, 0x8E,
|
||||
0xB6, 0x43, 0xC6, 0xEB, 0x53, 0xE6, 0x8B, 0x89, 0xB3, 0x0B, 0x3C, 0xB6, 0xBD, 0x2C, 0x49, 0x41,
|
||||
0xA6, 0x38, 0x62, 0x5C, 0xD0, 0x44, 0xA2, 0xA5, 0x31, 0xE1, 0xB3, 0x5C, 0x54, 0x54, 0x40, 0x21,
|
||||
0x27, 0xE3, 0x01, 0xE3, 0xB4, 0x3E, 0x0C, 0x22, 0xEF, 0x76, 0x71, 0xD2, 0x6E, 0x7C, 0x9F, 0x9F,
|
||||
0xE5, 0x4C, 0xA2, 0x3B, 0x9A, 0xCC, 0x96, 0xEA, 0x92, 0xD8, 0x15, 0x60, 0x85, 0x34, 0xA5, 0x74,
|
||||
0x6E, 0x8B, 0xBB, 0x0C, 0xA0, 0x96, 0xFC, 0x05, 0x29, 0x17, 0xFC, 0x2F, 0x45, 0x5A, 0x11, 0x5C,
|
||||
0xA1, 0x30, 0x1E, 0x67, 0x62, 0xF6, 0xF8, 0x2A, 0xA3, 0x98, 0x78, 0x4C, 0x3C, 0xA0, 0xFC, 0xB0,
|
||||
0x6D, 0x86, 0xBA, 0x04, 0xAC, 0x24, 0x24, 0x81, 0x86, 0x3A, 0xD7, 0x3E, 0xD0, 0xC4, 0x27, 0x9C,
|
||||
0x58, 0x9D, 0x84, 0x91, 0xC0, 0xEA, 0x2D, 0xB5, 0x5E, 0x0F, 0xA3, 0xEF, 0xF5, 0x0C, 0xC6, 0x30,
|
||||
0x0F, 0xA8, 0x27, 0x94, 0x92, 0xE1, 0x1E, 0x86, 0xB7, 0x4C, 0x3C, 0x06, 0x3C, 0x5A, 0x28, 0xA9,
|
||||
0x4B, 0x2A, 0x69, 0xA2, 0x2E, 0xB0, 0x25, 0xD5, 0x83, 0x1C, 0x4B, 0xC9, 0x95, 0x50, 0xF5, 0x61,
|
||||
0x24, 0x44, 0x14, 0x4A, 0x93, 0x5B, 0x08, 0xAC, 0x49, 0xAB, 0x79, 0xF1, 0xE8, 0x46, 0xD6, 0x6B,
|
||||
0xBF, 0x44, 0xBE, 0x0D, 0x7A, 0x15, 0xCC, 0x23, 0x41, 0x9D, 0x04, 0x6C, 0xCC, 0x9D, 0x90, 0xF9,
|
||||
0x7E, 0x40, 0x4B, 0x56, 0xEB, 0x64, 0x49, 0x60, 0xF8, 0x44, 0x10, 0x87, 0x85, 0x64, 0x4C, 0x1B,
|
||||
0x31, 0x1F, 0x03, 0x34, 0xA5, 0xBB, 0x3B, 0x16, 0xFB, 0xD0, 0xBD, 0xB8, 0x9A, 0x36, 0xDF, 0xBD,
|
||||
0x1E, 0x47, 0x1D, 0xF8, 0xE7, 0xBC, 0x37, 0x98, 0x1C, 0x0F, 0xC6, 0x30, 0xEA, 0xE2, 0xB4, 0xF3,
|
||||
0xFE, 0xB0, 0xF3, 0x1E, 0x7E, 0x0E, 0x5B, 0xB5, 0xAF, 0xA3, 0x6F, 0xB8, 0xD0, 0x7D, 0xED, 0x77,
|
||||
0xFB, 0x83, 0xE3, 0x4E, 0xE7, 0x5D, 0xE3, 0xCD, 0xF9, 0xF4, 0xE3, 0xBB, 0x5D, 0x04, 0x77, 0x83,
|
||||
0xE6, 0xD5, 0x87, 0x49, 0x73, 0xB0, 0xF5, 0x32, 0xF4, 0x4F, 0xFC, 0x89, 0x17, 0x0E, 0x3A, 0xEF,
|
||||
0x3F, 0x5E, 0xDD, 0x5D, 0x87, 0x83, 0x71, 0xEF, 0x63, 0x6B, 0xF2, 0x79, 0xEB, 0x43, 0xEF, 0xF3,
|
||||
0xC7, 0x57, 0xB7, 0xF4, 0xD3, 0xC9, 0xDB, 0xCF, 0xFD, 0x29, 0x20, 0x1C, 0x45, 0xBD, 0xC1, 0x55,
|
||||
0xF7, 0x43, 0x77, 0xFC, 0xB9, 0xEB, 0x1D, 0xDF, 0x0F, 0x83, 0xF3, 0xEE, 0xEB, 0xCE, 0xB0, 0xB3,
|
||||
0xE5, 0x51, 0x3A, 0xEE, 0x5F, 0x75, 0xB3, 0x37, 0xEF, 0x2E, 0xC6, 0x8C, 0x4D, 0x7A, 0x9F, 0xCF,
|
||||
0xFB, 0xDE, 0xE1, 0xF3, 0xD3, 0xC1, 0x49, 0x87, 0x4D, 0xCE, 0xDF, 0x5E, 0x35, 0x6F, 0x5F, 0xBF,
|
||||
0x3B, 0x3C, 0xF2, 0xAE, 0xDF, 0x5E, 0xEF, 0x1E, 0x6D, 0x37, 0x7E, 0xFB, 0xED, 0xCC, 0xBF, 0x60,
|
||||
0xBC, 0x7F, 0xF7, 0xBD, 0x33, 0x3E, 0x9C, 0xBE, 0x78, 0x48, 0xFB, 0x93, 0x37, 0x77, 0xBC, 0xF1,
|
||||
0x21, 0xFA, 0xFA, 0xE6, 0xE1, 0x0C, 0xFE, 0xBB, 0xBC, 0xAC, 0x0D, 0x7B, 0xAD, 0x74, 0xF0, 0xFE,
|
||||
0xCD, 0x87, 0xAD, 0xF4, 0xE5, 0xF3, 0xB8, 0x7B, 0x74, 0x74, 0x17, 0x0E, 0x2F, 0x1B, 0xA1, 0x7F,
|
||||
0x3B, 0x12, 0x2F, 0xB6, 0x45, 0x7C, 0x3D, 0xCE, 0x3E, 0x7F, 0x7B, 0xFE, 0x76, 0xD2, 0xB8, 0xA0,
|
||||
0xE4, 0x7A, 0x52, 0x7B, 0xF8, 0xFE, 0xF0, 0x62, 0xD2, 0x3F, 0xB9, 0x3B, 0x0F, 0xC8, 0xFD, 0xF9,
|
||||
0xB9, 0xF7, 0x3D, 0xAC, 0x05, 0xE4, 0xE5, 0x45, 0x3F, 0x20, 0x49, 0x6B, 0xE0, 0x77, 0x1A, 0xB5,
|
||||
0xC3, 0xAD, 0xCE, 0x8E, 0x48, 0xAE, 0x0E, 0xF9, 0xD1, 0xF6, 0xD7, 0xDE, 0x8B, 0x6E, 0xB7, 0x15,
|
||||
0x0D, 0xBF, 0x6D, 0xBD, 0xBE, 0xDD, 0x7D, 0x3D, 0xD8, 0x7D, 0x3F, 0x7C, 0xDF, 0xE9, 0xED, 0x74,
|
||||
0x07, 0xE4, 0xBA, 0xF7, 0xBE, 0x33, 0xDA, 0x19, 0x4E, 0x26, 0xEF, 0xDE, 0xF5, 0x5F, 0xF9, 0x9D,
|
||||
0xEF, 0x49, 0xE7, 0x62, 0xDA, 0xB9, 0x3F, 0x1E, 0x74, 0x4E, 0x6A, 0xEF, 0x8E, 0xCF, 0x9A, 0xAD,
|
||||
0xDE, 0xF5, 0xF6, 0xF8, 0x6C, 0x77, 0xDA, 0x4D, 0x8F, 0x3B, 0xEF, 0xBB, 0xCD, 0xF1, 0xDB, 0x5A,
|
||||
0x48, 0x3E, 0x47, 0x87, 0xDB, 0xE3, 0x37, 0xBB, 0xEC, 0xF2, 0x9A, 0x74, 0xDE, 0x74, 0xDF, 0xA6,
|
||||
0xEC, 0x2A, 0x3C, 0x19, 0x34, 0x3B, 0x9D, 0xD3, 0x0B, 0xFA, 0xEA, 0x70, 0x9B, 0xBC, 0xDB, 0xF2,
|
||||
0x3E, 0x82, 0xFE, 0x07, 0x9F, 0xE8, 0x6F, 0xB5, 0xCE, 0xF4, 0xA2, 0x19, 0x78, 0x2F, 0x69, 0xFF,
|
||||
0xE4, 0xBA, 0x2F, 0x6F, 0xE7, 0x38, 0x78, 0xD5, 0xBF, 0xED, 0x65, 0xEF, 0xC3, 0xC3, 0x43, 0x53,
|
||||
0xE3, 0x51, 0x3D, 0xA1, 0x31, 0x25, 0xA2, 0x1C, 0xAE, 0x16, 0xFE, 0x01, 0xB6, 0xB5, 0xB4, 0xC2,
|
||||
0xDC, 0x4F, 0x05, 0xBD, 0x17, 0x75, 0x9F, 0x7A, 0x51, 0x42, 0xE4, 0x1E, 0x40, 0xA0, 0x09, 0x9A,
|
||||
0xD8, 0xFC, 0x77, 0x19, 0x3F, 0x35, 0x15, 0x3F, 0x35, 0xC2, 0x7D, 0xCD, 0x28, 0x1C, 0x01, 0x83,
|
||||
0x87, 0x4F, 0xEF, 0x98, 0x47, 0xEB, 0x31, 0xBB, 0xA7, 0x41, 0x5D, 0x22, 0x3B, 0x4D, 0x73, 0x26,
|
||||
0xFD, 0xAD, 0xD8, 0x46, 0x38, 0x98, 0x9A, 0xA4, 0x5A, 0x2C, 0xF8, 0x5F, 0x89, 0x47, 0x21, 0xB0,
|
||||
0x81, 0xCB, 0x84, 0xF8, 0xAB, 0x7C, 0x27, 0x4A, 0xEA, 0xC3, 0x6C, 0x3C, 0x62, 0xF7, 0xE0, 0xD0,
|
||||
0x23, 0xC6, 0x99, 0xA0, 0x5A, 0x2B, 0x9D, 0xFF, 0x5E, 0x90, 0xB9, 0xA5, 0x0F, 0xA3, 0x84, 0x84,
|
||||
0x34, 0xD5, 0xFE, 0x22, 0x99, 0xD9, 0x28, 0x89, 0xC2, 0x65, 0x10, 0x99, 0x8B, 0xA8, 0x34, 0x99,
|
||||
0xCF, 0x9F, 0x65, 0x71, 0x10, 0x11, 0x10, 0x73, 0x4D, 0xE4, 0x50, 0xF1, 0x34, 0x91, 0x6E, 0xB5,
|
||||
0x88, 0xAB, 0xB9, 0x9B, 0x6D, 0xA1, 0x5B, 0x96, 0xDD, 0x7A, 0x6B, 0x67, 0xE9, 0xBA, 0x75, 0xB9,
|
||||
0x17, 0xE3, 0xFD, 0x9A, 0x4C, 0x81, 0xF1, 0xA0, 0x14, 0xEE, 0x9E, 0x09, 0x50, 0xE9, 0x13, 0x87,
|
||||
0xCB, 0x43, 0xF2, 0xC8, 0xB0, 0x60, 0x40, 0x05, 0xEA, 0x96, 0x8C, 0xD4, 0x85, 0x24, 0xB0, 0x6F,
|
||||
0xFE, 0x8C, 0xCA, 0xBC, 0x67, 0x3D, 0x8B, 0x13, 0xB8, 0x0D, 0x3A, 0xFD, 0x11, 0xCD, 0x42, 0xA6,
|
||||
0x2A, 0x6D, 0x45, 0x53, 0x65, 0xBC, 0x5C, 0x84, 0x65, 0xDA, 0x93, 0xBC, 0x16, 0xA4, 0x1F, 0x4B,
|
||||
0x05, 0xE0, 0x05, 0x37, 0xCF, 0x91, 0x9B, 0x1F, 0x6A, 0x75, 0x7B, 0xF7, 0x97, 0x9C, 0x87, 0x9D,
|
||||
0xE6, 0x2F, 0x73, 0x3B, 0xDF, 0x5B, 0xA4, 0xE4, 0x56, 0x13, 0xFE, 0x29, 0x32, 0xEF, 0x8B, 0x25,
|
||||
0x0B, 0xC3, 0xE7, 0xF8, 0xA7, 0x60, 0x10, 0xE9, 0x94, 0x80, 0xDB, 0x3B, 0x2F, 0x5F, 0xF8, 0xC3,
|
||||
0x02, 0x98, 0x0B, 0xF6, 0x24, 0x3C, 0x21, 0x3E, 0xCB, 0x52, 0xE7, 0x79, 0xF3, 0x97, 0x5C, 0x9F,
|
||||
0x5B, 0x3B, 0x28, 0xFB, 0xE2, 0x2E, 0x71, 0xB2, 0xB4, 0xD8, 0x34, 0x66, 0x5C, 0xDB, 0x4A, 0x35,
|
||||
0xBC, 0x6F, 0x92, 0x2C, 0x0C, 0xB3, 0x92, 0xED, 0xE7, 0xBF, 0x2F, 0x4D, 0x13, 0xF7, 0xCF, 0x9A,
|
||||
0xBF, 0xCC, 0x44, 0x02, 0xD9, 0x64, 0x04, 0xB9, 0xC6, 0x49, 0x22, 0x41, 0x04, 0x35, 0x9A, 0xE6,
|
||||
0x1C, 0x84, 0x5B, 0x03, 0xD8, 0xDE, 0x6D, 0xFA, 0x74, 0x6C, 0xCE, 0xE7, 0x7B, 0x0D, 0x99, 0xD7,
|
||||
0xA0, 0x6C, 0xF1, 0x12, 0x16, 0x8B, 0xFD, 0x51, 0xC6, 0x3D, 0xE4, 0x41, 0x1B, 0x53, 0x83, 0x9A,
|
||||
0xB3, 0x84, 0x8A, 0x2C, 0xE1, 0x9A, 0x1F, 0x79, 0x19, 0x1A, 0xBB, 0x3D, 0xA6, 0xE2, 0x58, 0xD9,
|
||||
0x7D, 0xF7, 0xE1, 0x8D, 0x0F, 0x3B, 0xE6, 0x0B, 0x04, 0x6F, 0x2D, 0x02, 0x38, 0x30, 0x9C, 0x97,
|
||||
0xE3, 0x54, 0xF6, 0x43, 0x82, 0x01, 0x22, 0xEF, 0xE8, 0x83, 0x41, 0x2D, 0xB1, 0x40, 0xA4, 0x36,
|
||||
0xAE, 0x1B, 0xC5, 0x2E, 0x80, 0x71, 0x73, 0x76, 0x07, 0x4A, 0x20, 0x2E, 0xFD, 0x22, 0x6E, 0x2C,
|
||||
0xE6, 0x72, 0xF8, 0x69, 0xE7, 0xBB, 0xC9, 0x1E, 0x3B, 0xA8, 0xB7, 0x1C, 0xB2, 0xCF, 0x0E, 0x5A,
|
||||
0xE0, 0x5E, 0x65, 0x6E, 0xE4, 0xB9, 0xAF, 0x58, 0x40, 0x07, 0xB9, 0xC3, 0xE1, 0x31, 0x48, 0x6C,
|
||||
0xB1, 0x85, 0x28, 0xE2, 0x5B, 0xCD, 0xE6, 0x86, 0x4B, 0x0F, 0x48, 0x00, 0x39, 0xCC, 0xD0, 0x8F,
|
||||
0xAF, 0xAE, 0x2E, 0xAE, 0xBE, 0xE8, 0x35, 0x5A, 0xD3, 0x6F, 0x1C, 0x4D, 0xAF, 0x71, 0xD3, 0x11,
|
||||
0x76, 0x42, 0x47, 0x09, 0x4D, 0x27, 0x97, 0x44, 0x4C, 0x8C, 0xD4, 0xBE, 0x23, 0x41, 0x56, 0x16,
|
||||
0x84, 0xA1, 0xDC, 0xC8, 0xA2, 0x70, 0x39, 0x9D, 0x6A, 0xAF, 0x40, 0xCD, 0x47, 0x90, 0xEA, 0xDA,
|
||||
0xC2, 0x26, 0x71, 0x4C, 0xB9, 0x6F, 0xE8, 0x31, 0x20, 0xEA, 0x16, 0x35, 0xAD, 0x84, 0x7E, 0xCB,
|
||||
0x68, 0x2A, 0x52, 0x1B, 0x2C, 0xD7, 0xD0, 0x2F, 0x07, 0x7D, 0xDD, 0xD2, 0x1B, 0xE8, 0x47, 0x3A,
|
||||
0xF0, 0x46, 0xCC, 0x39, 0x52, 0x89, 0x5C, 0xD0, 0xA4, 0x3E, 0xCC, 0xC0, 0xA0, 0xB8, 0x6E, 0xB6,
|
||||
0x23, 0x9B, 0x71, 0x4E, 0x93, 0x93, 0xFE, 0xD9, 0xA9, 0xAB, 0x5F, 0x29, 0x46, 0xB4, 0x53, 0x28,
|
||||
0x48, 0x74, 0x4B, 0x5E, 0x51, 0x7E, 0xC8, 0xE1, 0x84, 0x05, 0xBE, 0x11, 0x99, 0x6D, 0x24, 0xE1,
|
||||
0x49, 0x12, 0xB2, 0x40, 0x01, 0x0A, 0x9E, 0x2D, 0x1E, 0x62, 0xEA, 0xEA, 0x23, 0x50, 0x86, 0x6E,
|
||||
0x79, 0x76, 0x98, 0x05, 0x82, 0xC5, 0x01, 0x75, 0x37, 0x5A, 0x30, 0xE3, 0x60, 0x41, 0xAE, 0x8E,
|
||||
0xB9, 0x19, 0x61, 0xCC, 0x77, 0x75, 0x15, 0xA1, 0xF2, 0xB8, 0xB6, 0xEE, 0x14, 0x4F, 0x9D, 0x92,
|
||||
0x56, 0x4E, 0x49, 0xCB, 0xB8, 0x4A, 0xE0, 0x34, 0x3F, 0x18, 0xC3, 0x3C, 0xCE, 0xD4, 0x51, 0x05,
|
||||
0xCC, 0xA7, 0x23, 0x02, 0x9C, 0x7C, 0x40, 0x6D, 0xBA, 0x7A, 0x63, 0xDD, 0x41, 0xA9, 0x3A, 0xC8,
|
||||
0xAF, 0x6A, 0xC4, 0x2F, 0x6B, 0x44, 0xDD, 0xEE, 0x3A, 0x64, 0x5F, 0x21, 0x07, 0x55, 0xE4, 0xA0,
|
||||
0x8C, 0x7C, 0x28, 0x8D, 0x64, 0x1D, 0x72, 0xA0, 0x90, 0x93, 0x8A, 0x88, 0x89, 0x14, 0x51, 0x85,
|
||||
0xBD, 0x3A, 0x6A, 0x13, 0x05, 0xD2, 0xAD, 0xA4, 0x22, 0x66, 0x62, 0x83, 0x97, 0x92, 0x61, 0x40,
|
||||
0x7D, 0x77, 0xA3, 0x09, 0x33, 0x2C, 0xB6, 0xDD, 0xAD, 0xE6, 0x9A, 0x33, 0x12, 0x75, 0x46, 0x56,
|
||||
0x65, 0x30, 0x2B, 0x33, 0xA8, 0xF5, 0xC8, 0x1D, 0xD5, 0xD6, 0x31, 0x98, 0x99, 0x56, 0x60, 0x47,
|
||||
0xDC, 0x0B, 0x98, 0x77, 0xEB, 0x2E, 0xBD, 0xC5, 0x9C, 0xB1, 0x85, 0x85, 0x5A, 0x5C, 0x06, 0xBA,
|
||||
0x01, 0x94, 0x5E, 0x8B, 0xA5, 0x7C, 0x80, 0xFA, 0x9E, 0x5B, 0xD9, 0x5A, 0x02, 0xDC, 0xA6, 0xF7,
|
||||
0xD4, 0x3B, 0x8C, 0xC2, 0x90, 0xA0, 0xED, 0xA6, 0xC0, 0x41, 0x3E, 0xD1, 0xCD, 0xB9, 0x15, 0xAD,
|
||||
0xC5, 0x79, 0xC2, 0x45, 0x2C, 0x7F, 0x3D, 0x8B, 0x23, 0x03, 0x5C, 0xCE, 0xF5, 0x6C, 0xD4, 0x61,
|
||||
0x6A, 0x83, 0x1E, 0xC7, 0x62, 0xF2, 0x13, 0x17, 0x2A, 0x0C, 0x54, 0xA2, 0x7C, 0x69, 0xDE, 0x58,
|
||||
0x0B, 0x91, 0x56, 0x7C, 0xEA, 0xA2, 0xB7, 0xE2, 0x54, 0xA8, 0xBC, 0x8A, 0x5D, 0x9A, 0x4B, 0x1D,
|
||||
0x94, 0x61, 0xB9, 0xBD, 0x2F, 0xA0, 0xFA, 0x7C, 0x0E, 0xE7, 0x01, 0xFF, 0x13, 0x68, 0xF9, 0xE8,
|
||||
0x5F, 0x17, 0x60, 0xC9, 0xA3, 0x34, 0x78, 0x8B, 0xBB, 0x0D, 0xE3, 0xC0, 0xF9, 0x8F, 0x6D, 0x7C,
|
||||
0xF9, 0x1F, 0xFB, 0xA6, 0x66, 0x9A, 0x07, 0xFF, 0x6A, 0x48, 0x0D, 0x1B, 0xC2, 0xFC, 0xD2, 0xBA,
|
||||
0xB1, 0x08, 0x80, 0xED, 0x7F, 0x9B, 0xFF, 0xB1, 0x25, 0xB8, 0x02, 0x6B, 0xDF, 0x45, 0x90, 0x49,
|
||||
0xF0, 0x24, 0x34, 0xB0, 0x68, 0xA4, 0x91, 0xCD, 0x4D, 0x43, 0xB8, 0xA4, 0x72, 0x8D, 0x35, 0x51,
|
||||
0xD3, 0x6D, 0x88, 0x53, 0x50, 0x5B, 0xAC, 0x04, 0xBF, 0x3E, 0x24, 0x7A, 0x15, 0x5B, 0x17, 0x00,
|
||||
0xC9, 0x3D, 0xCA, 0x0C, 0x3D, 0x22, 0x97, 0x52, 0xCB, 0x0C, 0x02, 0x42, 0xA7, 0x89, 0xE7, 0x2A,
|
||||
0xAD, 0x1D, 0x14, 0x30, 0x17, 0xA2, 0xE0, 0xBC, 0x1C, 0x2D, 0x15, 0xEA, 0xAA, 0xFD, 0x17, 0x0A,
|
||||
0xA3, 0xD6, 0x12, 0x8A, 0x04, 0x31, 0xAD, 0xD8, 0x79, 0xC6, 0x72, 0x75, 0x4C, 0x59, 0xBA, 0x35,
|
||||
0x59, 0x5D, 0x96, 0xAD, 0x04, 0xAE, 0x2F, 0x8D, 0xFE, 0xD7, 0x3D, 0x16, 0x8E, 0xB5, 0x12, 0x3F,
|
||||
0xF8, 0x97, 0xFB, 0x2B, 0x46, 0xE4, 0xCD, 0x3F, 0xBC, 0x21, 0x70, 0x05, 0xA6, 0x41, 0x6D, 0x1E,
|
||||
0x4D, 0x0D, 0xB3, 0xF6, 0xAB, 0xAE, 0x49, 0x8A, 0xAE, 0x1E, 0x92, 0xFB, 0xBC, 0xA7, 0xC4, 0x8C,
|
||||
0xD7, 0xD6, 0x70, 0x5E, 0xB4, 0x28, 0xF9, 0x82, 0xEC, 0xE6, 0x48, 0x26, 0xA2, 0xB6, 0x56, 0x64,
|
||||
0x52, 0xD5, 0xCA, 0xE8, 0x5A, 0x63, 0xFF, 0xD7, 0x4A, 0x40, 0xB7, 0x98, 0xBA, 0x4E, 0x15, 0x8C,
|
||||
0xB3, 0x00, 0x1C, 0x93, 0x3E, 0x1D, 0x69, 0x03, 0x26, 0x03, 0x75, 0x35, 0x46, 0x5A, 0x81, 0xC1,
|
||||
0xCC, 0x03, 0xC3, 0x2B, 0xFB, 0xF3, 0x1E, 0x16, 0xBF, 0xFB, 0x97, 0xAA, 0xAA, 0x81, 0xD4, 0x8B,
|
||||
0x33, 0x5D, 0x59, 0x59, 0xD5, 0x4B, 0xE0, 0xD2, 0x08, 0xA0, 0x5B, 0x8B, 0x3C, 0x3A, 0x8C, 0xFC,
|
||||
0x87, 0x52, 0xF6, 0x4D, 0xBB, 0x0F, 0x87, 0x01, 0x49, 0xD3, 0x73, 0xB8, 0x01, 0x43, 0xF7, 0x42,
|
||||
0x50, 0xB8, 0xB2, 0xC2, 0xFD, 0xE6, 0xE6, 0x66, 0x15, 0x29, 0xA1, 0x21, 0x14, 0xDB, 0x8A, 0x2B,
|
||||
0xF0, 0x49, 0xD3, 0xF1, 0x81, 0x30, 0x18, 0xD2, 0x1A, 0xC6, 0xF0, 0x25, 0xE3, 0x47, 0x5C, 0x71,
|
||||
0xF4, 0xF4, 0x22, 0xA6, 0xFC, 0x33, 0xDC, 0x95, 0x32, 0xCB, 0x1A, 0xAD, 0xA6, 0x68, 0xFA, 0x8F,
|
||||
0xD8, 0x3E, 0xCA, 0x0D, 0x76, 0xC1, 0x7A, 0xBA, 0x56, 0xA1, 0xFC, 0x9F, 0x61, 0xB9, 0x94, 0x28,
|
||||
0xD6, 0x70, 0x9C, 0x40, 0x80, 0x5A, 0xC3, 0x31, 0xC4, 0x1A, 0x41, 0x17, 0xFC, 0x26, 0x6B, 0xF9,
|
||||
0xCD, 0xFE, 0x19, 0x7E, 0x97, 0x76, 0x1E, 0x15, 0x25, 0x91, 0xAA, 0xAF, 0x50, 0x02, 0x9F, 0xDD,
|
||||
0xE9, 0xA6, 0x15, 0xB9, 0x55, 0x0A, 0x50, 0x1B, 0x46, 0x41, 0xD0, 0x8F, 0xE2, 0x83, 0x27, 0xD6,
|
||||
0x9D, 0xC5, 0x7A, 0x31, 0xC8, 0xD9, 0x5C, 0x6E, 0xB1, 0xBC, 0xB5, 0x44, 0x4F, 0xA1, 0xEC, 0x5F,
|
||||
0x4B, 0x15, 0x01, 0x3F, 0x23, 0x8B, 0x7B, 0xAC, 0xD4, 0xA5, 0x36, 0x28, 0x0F, 0x56, 0x3F, 0xD5,
|
||||
0x3C, 0xCB, 0x5F, 0xCC, 0xAE, 0x6B, 0x51, 0x9B, 0xC0, 0x38, 0x57, 0x92, 0x8B, 0x4A, 0xB2, 0xC8,
|
||||
0x13, 0x01, 0xA8, 0x58, 0xC7, 0x2E, 0xC4, 0x4D, 0x6B, 0x7A, 0x7C, 0xBF, 0x5C, 0x83, 0xC2, 0xDF,
|
||||
0xF5, 0xD5, 0x12, 0x33, 0x08, 0xC4, 0xD3, 0x95, 0x4B, 0x29, 0x5F, 0x37, 0x29, 0x8A, 0x0E, 0x62,
|
||||
0x47, 0xA3, 0x51, 0x4A, 0xC5, 0x47, 0x0C, 0x49, 0x56, 0xB2, 0x98, 0x9F, 0xC8, 0x90, 0x04, 0x8C,
|
||||
0x45, 0x3C, 0x8C, 0xB2, 0x94, 0x46, 0x99, 0xA8, 0xA4, 0x16, 0x63, 0x21, 0xCC, 0x5E, 0xFA, 0xE7,
|
||||
0x9F, 0x8B, 0xC9, 0x7E, 0x5A, 0x0B, 0x96, 0xD3, 0xEB, 0x3D, 0xBF, 0x34, 0xD9, 0xF7, 0x6B, 0x89,
|
||||
0xB9, 0x7A, 0xE9, 0xFF, 0x67, 0x4B, 0x21, 0x65, 0x4B, 0xF1, 0xB0, 0x54, 0x2E, 0x62, 0x62, 0x29,
|
||||
0xE6, 0xC9, 0x82, 0x91, 0x97, 0x7C, 0x16, 0x0D, 0x1A, 0x2B, 0x25, 0x55, 0x9E, 0x97, 0x7D, 0x95,
|
||||
0x43, 0x40, 0x59, 0x71, 0xE5, 0x35, 0x11, 0x06, 0x34, 0xE0, 0x63, 0x64, 0xF2, 0x41, 0xEB, 0xA7,
|
||||
0xD1, 0x94, 0x26, 0x87, 0x24, 0xA5, 0x06, 0x24, 0xCD, 0x65, 0xDC, 0x41, 0xA8, 0xE9, 0x04, 0xEB,
|
||||
0x76, 0x6D, 0x6E, 0x12, 0x05, 0xCE, 0x33, 0x77, 0xC4, 0xB1, 0x26, 0x03, 0xF9, 0xB2, 0xCA, 0x09,
|
||||
0xD4, 0xC6, 0xBE, 0x12, 0xA4, 0x3E, 0x52, 0x25, 0xA8, 0x61, 0x5A, 0xD0, 0x76, 0xC0, 0x35, 0x5F,
|
||||
0x26, 0x51, 0x4C, 0xC6, 0xB2, 0x07, 0x83, 0x35, 0x74, 0x0F, 0xA4, 0x66, 0x6D, 0x34, 0x91, 0x60,
|
||||
0xA9, 0x73, 0x29, 0xFC, 0x66, 0xD9, 0xC2, 0x70, 0x4B, 0x57, 0xC9, 0xB0, 0xBD, 0xF4, 0xA5, 0x35,
|
||||
0x59, 0x83, 0xE0, 0x0B, 0x6C, 0x62, 0xE0, 0x1E, 0x68, 0x64, 0xF2, 0x7B, 0x00, 0x77, 0x6B, 0xB6,
|
||||
0xA3, 0x3D, 0xD6, 0x8E, 0x6A, 0x35, 0x53, 0x55, 0xE9, 0xAE, 0x0B, 0x6D, 0x4E, 0x74, 0x23, 0x0B,
|
||||
0x4B, 0x10, 0xAA, 0x9A, 0x59, 0x0C, 0x38, 0x1B, 0x81, 0xAA, 0xBA, 0xC0, 0x11, 0xD6, 0x98, 0x66,
|
||||
0xA9, 0x23, 0xF1, 0x97, 0x1D, 0xC9, 0x13, 0xB5, 0x07, 0x95, 0xF5, 0x05, 0xD4, 0x31, 0xAB, 0x25,
|
||||
0x86, 0x30, 0xD3, 0x29, 0x13, 0xDE, 0x04, 0x03, 0x90, 0x07, 0x5A, 0xD5, 0x05, 0x14, 0xB5, 0x8E,
|
||||
0x1C, 0x4D, 0x44, 0xB8, 0x1C, 0x05, 0xF9, 0xF0, 0x6B, 0x9A, 0x0F, 0xBC, 0xB4, 0x18, 0xDD, 0x97,
|
||||
0x80, 0x50, 0xD2, 0xE6, 0xE0, 0x88, 0x8F, 0xF2, 0x21, 0xF4, 0xB2, 0x05, 0x9D, 0x02, 0x58, 0xFC,
|
||||
0xC6, 0x71, 0x3E, 0x8A, 0x27, 0xC5, 0x68, 0x42, 0xEF, 0x17, 0x78, 0x51, 0x01, 0xF5, 0xA9, 0xEE,
|
||||
0x28, 0x1B, 0xDB, 0x68, 0xCE, 0xF3, 0x41, 0x6B, 0x29, 0x7F, 0xF0, 0xFF, 0x28, 0x7F, 0xCC, 0xC7,
|
||||
0x85, 0x34, 0x71, 0x31, 0x1A, 0xB3, 0x42, 0x96, 0x61, 0x18, 0xFF, 0x90, 0x93, 0xA4, 0xD4, 0x13,
|
||||
0x97, 0x7A, 0x5A, 0xF1, 0xB3, 0xB6, 0x53, 0x98, 0x8E, 0x31, 0xAA, 0xF8, 0xE3, 0xC8, 0xF6, 0xF0,
|
||||
0xF7, 0x3C, 0xF2, 0x65, 0x6D, 0x69, 0x5A, 0xA1, 0x31, 0x82, 0x3A, 0x57, 0x37, 0xCB, 0x7E, 0x9A,
|
||||
0xFD, 0xB7, 0xAD, 0xE8, 0xD1, 0xF1, 0xE9, 0x71, 0xFF, 0xB8, 0x5C, 0x38, 0x23, 0xE7, 0x25, 0x93,
|
||||
0x8A, 0x2B, 0x5D, 0xFA, 0xB2, 0x22, 0x80, 0x02, 0x1B, 0x45, 0x01, 0x7B, 0xDD, 0xDC, 0x54, 0x7E,
|
||||
0xF1, 0xB6, 0x77, 0x71, 0x6E, 0xC7, 0x24, 0x01, 0x8F, 0x24, 0x15, 0xE6, 0xC2, 0x82, 0x44, 0xF9,
|
||||
0xE0, 0xD7, 0xC7, 0xA5, 0x72, 0x5D, 0x7E, 0x61, 0x70, 0xC4, 0xDC, 0x52, 0xA7, 0xA9, 0x7E, 0x78,
|
||||
0xE2, 0x62, 0x5D, 0x99, 0xBF, 0x04, 0x41, 0x72, 0x1A, 0x2D, 0x13, 0x55, 0x11, 0x67, 0x46, 0xE5,
|
||||
0x30, 0x2F, 0xEE, 0xB2, 0x75, 0x0D, 0xD3, 0xC8, 0xB4, 0xC4, 0x84, 0xA5, 0xE5, 0x46, 0xA5, 0x12,
|
||||
0x14, 0xFE, 0xA2, 0xB6, 0xE7, 0x8B, 0x91, 0x24, 0xB7, 0x5A, 0x73, 0xAB, 0x6F, 0x41, 0x2A, 0x3E,
|
||||
0x58, 0x04, 0x23, 0x66, 0x39, 0xDB, 0x16, 0x77, 0xA3, 0x43, 0xEE, 0x61, 0x5C, 0x7F, 0xBA, 0x35,
|
||||
0x78, 0xD2, 0x3C, 0x79, 0x61, 0x9E, 0xFC, 0xB1, 0x7B, 0x2E, 0x1C, 0x45, 0xF9, 0xDA, 0xE2, 0x98,
|
||||
0xF6, 0x10, 0x58, 0xBB, 0x6D, 0x2F, 0x7D, 0x18, 0x20, 0xD2, 0x83, 0xCB, 0x00, 0xF4, 0x63, 0x58,
|
||||
0xFF, 0x4A, 0xEE, 0x88, 0x7A, 0x09, 0xAA, 0xA2, 0xAD, 0x73, 0x54, 0xD8, 0xEE, 0xFD, 0x81, 0xA3,
|
||||
0xF2, 0xCE, 0x65, 0x18, 0x48, 0x97, 0xC3, 0x92, 0x37, 0x8B, 0x75, 0xC1, 0x61, 0x19, 0x31, 0x64,
|
||||
0x6C, 0x00, 0xE3, 0xCD, 0x5D, 0x49, 0x13, 0xD5, 0x1C, 0xB4, 0xF0, 0x1B, 0x08, 0x8A, 0x4F, 0x39,
|
||||
0xCE, 0x9A, 0x38, 0xAD, 0x62, 0x72, 0xC5, 0x23, 0xC8, 0x4A, 0x67, 0x89, 0xC0, 0x6E, 0x10, 0x0D,
|
||||
0x0D, 0x7C, 0x64, 0x9A, 0xA1, 0xB6, 0x1D, 0x3E, 0x37, 0xD7, 0xBC, 0xD9, 0x54, 0xFA, 0x4B, 0x62,
|
||||
0x79, 0xD5, 0xB0, 0x8B, 0x1C, 0x56, 0xCC, 0x75, 0x7D, 0x1F, 0xF4, 0xA3, 0x4E, 0x29, 0xAF, 0x48,
|
||||
0xA4, 0x53, 0xD1, 0x83, 0xC4, 0x86, 0xA2, 0x41, 0xBE, 0x91, 0x40, 0x44, 0x72, 0x4A, 0x33, 0x5D,
|
||||
0xC7, 0xCA, 0xD2, 0x0B, 0x28, 0x49, 0x7A, 0xB2, 0x73, 0x95, 0x49, 0x6B, 0x25, 0x06, 0xFE, 0xC8,
|
||||
0xD7, 0xF0, 0xC7, 0xA1, 0xD0, 0xA3, 0x83, 0x9B, 0x49, 0x2B, 0x83, 0xA4, 0x23, 0x64, 0x83, 0xA9,
|
||||
0x37, 0xE4, 0xBB, 0xA8, 0x2D, 0x2F, 0xCB, 0xB4, 0x16, 0x50, 0x70, 0x71, 0x83, 0xBB, 0x11, 0x30,
|
||||
0x52, 0x5A, 0xC4, 0x9E, 0x94, 0xA8, 0xC7, 0x8F, 0x10, 0x1F, 0x53, 0x4A, 0x20, 0x06, 0x20, 0xA6,
|
||||
0x40, 0xD0, 0xA7, 0x42, 0x8A, 0x54, 0xE6, 0x92, 0x53, 0x2A, 0x20, 0xCA, 0x48, 0xCD, 0xE2, 0xC1,
|
||||
0x85, 0x78, 0xD4, 0x46, 0xD6, 0x80, 0xFD, 0xDC, 0xBD, 0x73, 0x33, 0xDE, 0x90, 0x68, 0x09, 0x56,
|
||||
0x36, 0x3D, 0x9A, 0xA6, 0x52, 0x5C, 0x54, 0xC7, 0x19, 0xF8, 0xA8, 0xA1, 0x03, 0x5A, 0x23, 0x84,
|
||||
0x11, 0x1E, 0x84, 0x8A, 0x01, 0x40, 0x7F, 0x42, 0xC3, 0x1C, 0x22, 0x70, 0x08, 0x20, 0x82, 0xA0,
|
||||
0x7F, 0x49, 0x0D, 0xF7, 0x64, 0x05, 0xC9, 0xF8, 0xD8, 0x6D, 0x35, 0xF0, 0x9D, 0x66, 0x95, 0xEC,
|
||||
0x20, 0xA5, 0xBD, 0x68, 0x24, 0xFA, 0x64, 0x98, 0x1A, 0x50, 0x00, 0xAC, 0xD9, 0x01, 0xA0, 0x1E,
|
||||
0x24, 0x5E, 0x63, 0x2B, 0x3F, 0xEF, 0x04, 0x2A, 0xBB, 0x00, 0xAB, 0xBB, 0x8E, 0x87, 0x5F, 0x39,
|
||||
0x4F, 0x19, 0xA7, 0x39, 0x26, 0x00, 0x7B, 0x93, 0x68, 0x7A, 0x99, 0x30, 0x2E, 0xCE, 0x64, 0x1B,
|
||||
0x6A, 0x6C, 0xB4, 0xE4, 0xF5, 0xA9, 0x87, 0x15, 0x79, 0x3F, 0xC5, 0x8B, 0xCB, 0x0C, 0xF3, 0xBA,
|
||||
0x53, 0x79, 0x77, 0xB1, 0x86, 0x70, 0x21, 0x50, 0x66, 0x38, 0xB3, 0x29, 0x74, 0xB0, 0xFA, 0xA1,
|
||||
0x48, 0x82, 0x7A, 0x4F, 0xB7, 0x42, 0xE2, 0xC1, 0x44, 0xED, 0x81, 0xF9, 0xDC, 0xC2, 0xD8, 0xE1,
|
||||
0x94, 0x83, 0x5A, 0x0A, 0xB5, 0x02, 0x45, 0xC6, 0x95, 0xCD, 0x98, 0x35, 0x1D, 0x6A, 0x58, 0x88,
|
||||
0x61, 0xE0, 0xAF, 0xFE, 0x05, 0x0F, 0x1E, 0x1C, 0xC8, 0x55, 0x3F, 0xE1, 0x23, 0xE3, 0x7E, 0xF4,
|
||||
0x23, 0x3E, 0x3E, 0xAF, 0xF0, 0xF1, 0x79, 0x1D, 0x1F, 0xB4, 0xAA, 0x3C, 0x98, 0x0C, 0x80, 0xEC,
|
||||
0x19, 0xE1, 0x64, 0x4C, 0x13, 0x58, 0xC0, 0x43, 0x50, 0x25, 0x7F, 0x8B, 0xB3, 0x84, 0xFE, 0x98,
|
||||
0xB3, 0xDE, 0x84, 0x8D, 0xC4, 0x23, 0xFE, 0x8A, 0xD5, 0xFF, 0x82, 0x4B, 0x3C, 0x70, 0x3D, 0x97,
|
||||
0x79, 0x6D, 0x5A, 0x49, 0x28, 0x3F, 0x7E, 0x2B, 0x91, 0x7E, 0xE4, 0x42, 0x78, 0xA9, 0x38, 0xC8,
|
||||
0xDF, 0xB7, 0xF4, 0x00, 0xBC, 0x11, 0xF8, 0x29, 0x35, 0x75, 0xBC, 0x0B, 0xA5, 0xFC, 0x29, 0x30,
|
||||
0x64, 0xA8, 0xC0, 0x47, 0xDD, 0xD9, 0xDC, 0x12, 0xAE, 0x01, 0x8A, 0xF1, 0xA3, 0x29, 0xB0, 0xEA,
|
||||
0xC9, 0x02, 0xD7, 0x9E, 0x40, 0x26, 0x04, 0x91, 0xE0, 0x48, 0xC8, 0xA7, 0x8D, 0x2F, 0x07, 0x9B,
|
||||
0x37, 0x35, 0xC8, 0x43, 0x2E, 0xFC, 0x98, 0x2E, 0x0C, 0x36, 0x6F, 0xFE, 0x6D, 0x36, 0xC6, 0xCC,
|
||||
0x5A, 0x76, 0xA4, 0x96, 0x4C, 0xF6, 0xF4, 0x0B, 0xBF, 0x71, 0x09, 0x48, 0x5D, 0x49, 0x78, 0x45,
|
||||
0x34, 0x03, 0x6B, 0x43, 0x61, 0xE1, 0x07, 0xFF, 0x47, 0x09, 0xF8, 0x91, 0x9E, 0x07, 0xCE, 0xBD,
|
||||
0xE6, 0x3D, 0x5E, 0x2F, 0x3E, 0x85, 0xE9, 0x56, 0xE9, 0xC1, 0x4A, 0xC7, 0xEF, 0x53, 0x3A, 0x76,
|
||||
0x59, 0xA2, 0x14, 0x4A, 0x14, 0x59, 0x88, 0x1A, 0x6A, 0x50, 0x0E, 0x51, 0x98, 0x89, 0x17, 0xCD,
|
||||
0x81, 0x02, 0x9B, 0x73, 0x34, 0x5B, 0x3A, 0x02, 0x0F, 0xF4, 0xF5, 0x45, 0xEE, 0xFC, 0x74, 0x76,
|
||||
0x7A, 0x22, 0x44, 0x7C, 0xA5, 0x62, 0x22, 0xD0, 0xAA, 0x2E, 0x2C, 0x2F, 0xCF, 0x9C, 0x89, 0xE4,
|
||||
0xA1, 0x28, 0x75, 0x30, 0x31, 0x28, 0x87, 0xFE, 0x74, 0x31, 0xFC, 0x0A, 0x71, 0xD6, 0xD0, 0xCF,
|
||||
0x52, 0x48, 0x58, 0x5B, 0x36, 0xA2, 0xF7, 0xFB, 0x97, 0xF6, 0xAE, 0xDD, 0x84, 0xBA, 0x00, 0xB4,
|
||||
0x0A, 0x69, 0x19, 0xEE, 0x7D, 0xFE, 0xB7, 0x90, 0xB7, 0xFF, 0x1E, 0x32, 0x83, 0xA8, 0x95, 0x42,
|
||||
0x58, 0x2A, 0xF0, 0xAB, 0xB8, 0x93, 0x24, 0x9A, 0x4A, 0xB4, 0xE3, 0x24, 0xC1, 0x4B, 0xE9, 0x43,
|
||||
0x85, 0xA2, 0x0D, 0x61, 0x31, 0xA5, 0x89, 0xE6, 0x47, 0x34, 0xD5, 0x78, 0x24, 0xB4, 0x34, 0x8B,
|
||||
0x63, 0x68, 0x5C, 0x56, 0xF4, 0x61, 0xEB, 0xC5, 0xEB, 0xCB, 0xFB, 0x8C, 0x66, 0xD4, 0xCF, 0x97,
|
||||
0x69, 0x52, 0xD1, 0x0B, 0x56, 0x50, 0xDF, 0x10, 0xEE, 0x7E, 0xB9, 0xC9, 0xEB, 0xA9, 0x8C, 0x73,
|
||||
0x8C, 0xA2, 0x1B, 0x2D, 0x35, 0x07, 0xE9, 0x26, 0x40, 0xD5, 0xE5, 0x59, 0x10, 0xCC, 0xDB, 0x2B,
|
||||
0xB4, 0xA0, 0xF1, 0x8A, 0x44, 0x24, 0x9F, 0xCB, 0x67, 0x7F, 0xE4, 0xC9, 0xA9, 0xE2, 0x82, 0x50,
|
||||
0xF2, 0x54, 0xA9, 0x36, 0xAD, 0x0D, 0x63, 0x83, 0x6A, 0x8C, 0xA7, 0x82, 0x70, 0x0F, 0xAF, 0x51,
|
||||
0xE9, 0xC2, 0x2C, 0x6A, 0x29, 0xDC, 0xDE, 0x46, 0x5F, 0xCB, 0x6D, 0xE9, 0x89, 0x7C, 0x2A, 0x25,
|
||||
0xE3, 0xAE, 0xAE, 0x63, 0x55, 0x45, 0xB1, 0x3E, 0x25, 0x61, 0x5A, 0x26, 0x5B, 0x54, 0x06, 0x26,
|
||||
0x77, 0x0B, 0x70, 0x9B, 0x06, 0x29, 0x1C, 0xBD, 0x7E, 0x7F, 0xCE, 0x46, 0xD1, 0xCE, 0x11, 0x80,
|
||||
0x69, 0xC5, 0x3E, 0x93, 0xD7, 0xE0, 0x24, 0xCC, 0x73, 0x07, 0x32, 0xE9, 0x4A, 0x03, 0x0E, 0xA9,
|
||||
0x98, 0x44, 0xFE, 0x81, 0x7E, 0xA0, 0x3B, 0x3A, 0xFC, 0xBB, 0x09, 0x35, 0x47, 0xCD, 0xA5, 0xD0,
|
||||
0xA4, 0xFA, 0x74, 0x70, 0xF5, 0x06, 0xC2, 0x53, 0x0C, 0xA5, 0x01, 0x17, 0x50, 0x34, 0xD7, 0x74,
|
||||
0x7C, 0x7A, 0x7D, 0x0C, 0x29, 0xC8, 0x7F, 0x21, 0x37, 0x66, 0xBB, 0xAA, 0x6C, 0xB8, 0xF3, 0xEA,
|
||||
0x75, 0x56, 0x2E, 0x03, 0x7A, 0x61, 0x8C, 0x58, 0x0F, 0x29, 0x7E, 0xFB, 0x7B, 0xF4, 0x9E, 0x8D,
|
||||
0x15, 0xD2, 0x6A, 0x5D, 0x6F, 0xCE, 0x76, 0x90, 0x67, 0x89, 0xD5, 0x43, 0x2C, 0x70, 0x97, 0x1F,
|
||||
0x29, 0x59, 0x95, 0x35, 0xDC, 0xF6, 0x48, 0x10, 0xE0, 0xC7, 0x5A, 0x03, 0x1B, 0x6A, 0x22, 0xB2,
|
||||
0xD4, 0x42, 0x22, 0x29, 0x08, 0x90, 0xD2, 0x3E, 0x84, 0x39, 0xD3, 0x92, 0x65, 0x86, 0xB2, 0xA1,
|
||||
0xBC, 0xFF, 0xC5, 0x9A, 0xA3, 0x64, 0x46, 0xE8, 0xCE, 0xF9, 0x6C, 0x73, 0x53, 0xD8, 0x85, 0x99,
|
||||
0x18, 0x05, 0x52, 0x8A, 0x01, 0x1C, 0x9A, 0x7D, 0x68, 0x2D, 0x8C, 0xB2, 0x90, 0x58, 0xAB, 0x3D,
|
||||
0xD2, 0xB6, 0x51, 0x55, 0x03, 0x54, 0x7C, 0x46, 0x01, 0x03, 0xCE, 0xB2, 0x24, 0x80, 0xA8, 0x8B,
|
||||
0x39, 0xBA, 0xB2, 0x2D, 0xC5, 0xBA, 0xD0, 0x84, 0x0E, 0xEC, 0x67, 0xC8, 0x12, 0x95, 0x97, 0xAD,
|
||||
0xA2, 0x27, 0x12, 0xC5, 0x77, 0x95, 0x9E, 0xC8, 0x6F, 0xE5, 0x84, 0xAA, 0xC8, 0x77, 0x88, 0x2F,
|
||||
0x13, 0x5C, 0xD4, 0xD1, 0x13, 0xA0, 0x24, 0x83, 0x52, 0x34, 0x60, 0x2A, 0x2C, 0x37, 0xEE, 0xEB,
|
||||
0xD3, 0xE9, 0xB4, 0x8E, 0xDF, 0x6A, 0xEB, 0x70, 0x82, 0xB2, 0x02, 0x5F, 0x5F, 0xC7, 0x21, 0x47,
|
||||
0x15, 0x58, 0xF8, 0x6E, 0xE1, 0xAC, 0xBA, 0xE8, 0x42, 0x7F, 0x2B, 0xDE, 0xD4, 0xAA, 0xD2, 0x59,
|
||||
0xE1, 0x73, 0x79, 0xDB, 0x7B, 0x3B, 0x2B, 0x20, 0x32, 0xC4, 0xAF, 0xB2, 0x90, 0x69, 0x20, 0x0D,
|
||||
0x3B, 0xE5, 0x46, 0x56, 0x25, 0x85, 0x65, 0x5C, 0xB0, 0xE3, 0x2C, 0x9D, 0x18, 0x33, 0x60, 0xDD,
|
||||
0x11, 0x96, 0xD2, 0x95, 0x43, 0x2D, 0x65, 0xB7, 0x0E, 0xB7, 0x0A, 0xFB, 0x70, 0x30, 0x83, 0x94,
|
||||
0x79, 0xFB, 0xF3, 0x4F, 0x39, 0x5B, 0xDE, 0xF6, 0x92, 0x62, 0x71, 0xE1, 0xF3, 0xFC, 0xA9, 0x35,
|
||||
0xAF, 0x69, 0xA5, 0xD1, 0xAF, 0xC4, 0x97, 0xBD, 0x46, 0xFE, 0x19, 0x3B, 0xFF, 0x9C, 0xAD, 0x81,
|
||||
0xB1, 0x43, 0x23, 0x2A, 0xDC, 0x4C, 0x8C, 0xEA, 0x2F, 0x34, 0xE6, 0x63, 0x79, 0x29, 0xBF, 0x2D,
|
||||
0xA0, 0x54, 0xA9, 0xD3, 0x68, 0x78, 0x3E, 0xFF, 0x9A, 0x42, 0x19, 0x1D, 0x65, 0xFE, 0x28, 0x20,
|
||||
0x09, 0xC5, 0x82, 0xA3, 0x41, 0xBE, 0x92, 0xFB, 0x46, 0xC0, 0x86, 0x69, 0x03, 0x93, 0x6D, 0xCB,
|
||||
0xDE, 0xB2, 0x77, 0x71, 0x64, 0x7F, 0x4D, 0xF7, 0x57, 0x4F, 0xD8, 0x5F, 0x34, 0x69, 0x58, 0x0B,
|
||||
0xE7, 0xB5, 0xAB, 0x8A, 0x4D, 0x6A, 0x83, 0xFB, 0xC4, 0xA7, 0x70, 0x3D, 0x6F, 0xB3, 0xCC, 0xB6,
|
||||
0x1A, 0xE4, 0x5F, 0x60, 0xD4, 0x31, 0xBA, 0x95, 0x2F, 0x92, 0xF4, 0x81, 0x7B, 0x18, 0x5B, 0x17,
|
||||
0x54, 0x26, 0x70, 0x49, 0xD5, 0x87, 0x34, 0xB9, 0xD3, 0x9C, 0x2F, 0x39, 0xC3, 0xB7, 0x3C, 0xA8,
|
||||
0x03, 0xE4, 0x37, 0x9C, 0x72, 0x39, 0xB0, 0xBF, 0x07, 0x5D, 0x33, 0x2A, 0x41, 0x79, 0xB1, 0x26,
|
||||
0x9B, 0xE6, 0x7C, 0x02, 0x82, 0x01, 0x70, 0xB1, 0xA3, 0x48, 0xCD, 0x2B, 0xCB, 0x98, 0x9B, 0x57,
|
||||
0x96, 0x54, 0xE2, 0x5F, 0x59, 0xCC, 0xDB, 0x9F, 0xFC, 0xDB, 0x4C, 0xF9, 0x7F, 0x5B, 0x28, 0x36,
|
||||
0x32, 0xF9, 0xE1, 0x09, 0xF7, 0x56, 0x3F, 0x45, 0xAD, 0x47, 0x51, 0xBB, 0xF7, 0xFF, 0x17, 0x53,
|
||||
0xE8, 0x9D, 0x36, 0x92, 0x29, 0x00, 0x00};
|
||||
|
||||
#define SPIFFS_MAXLENGTH_FILEPATH 32
|
||||
const char *excludeListFile = "/.exclude.files";
|
||||
|
||||
typedef struct ExcludeListS {
|
||||
char *item;
|
||||
ExcludeListS *next;
|
||||
} ExcludeList;
|
||||
|
||||
static ExcludeList *excludes = NULL;
|
||||
|
||||
static bool matchWild(const char *pattern, const char *testee) {
|
||||
const char *nxPat = NULL;
|
||||
const char *nxTst = NULL;
|
||||
|
||||
while (*testee) {
|
||||
if ((*pattern == '?') || (*pattern == *testee)) {
|
||||
++pattern;
|
||||
++testee;
|
||||
continue;
|
||||
}
|
||||
if (*pattern == '*') {
|
||||
nxPat = pattern++;
|
||||
nxTst = testee;
|
||||
continue;
|
||||
}
|
||||
if (nxPat) {
|
||||
pattern = nxPat + 1;
|
||||
testee = ++nxTst;
|
||||
continue;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
while (*pattern == '*') {
|
||||
++pattern;
|
||||
}
|
||||
return (*pattern == 0);
|
||||
}
|
||||
|
||||
static bool addExclude(const char *item) {
|
||||
size_t len = strlen(item);
|
||||
if (!len) {
|
||||
return false;
|
||||
}
|
||||
ExcludeList *e = (ExcludeList *)malloc(sizeof(ExcludeList));
|
||||
if (!e) {
|
||||
return false;
|
||||
}
|
||||
e->item = (char *)malloc(len + 1);
|
||||
if (!e->item) {
|
||||
free(e);
|
||||
return false;
|
||||
}
|
||||
memcpy(e->item, item, len + 1);
|
||||
e->next = excludes;
|
||||
excludes = e;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void loadExcludeList(fs::FS &_fs, const char *filename) {
|
||||
static char linebuf[SPIFFS_MAXLENGTH_FILEPATH];
|
||||
fs::File excludeFile;
|
||||
if (filename[0] != '/') {
|
||||
excludeFile = _fs.open("/" + ((String)filename), "r");
|
||||
} else {
|
||||
excludeFile = _fs.open(filename, "r");
|
||||
}
|
||||
if (!excludeFile) {
|
||||
// addExclude("/*.js.gz");
|
||||
return;
|
||||
}
|
||||
#ifdef ESP32
|
||||
if (excludeFile.isDirectory()) {
|
||||
excludeFile.close();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
if (excludeFile.size() > 0) {
|
||||
uint8_t idx;
|
||||
bool isOverflowed = false;
|
||||
while (excludeFile.available()) {
|
||||
linebuf[0] = '\0';
|
||||
idx = 0;
|
||||
int lastChar;
|
||||
do {
|
||||
lastChar = excludeFile.read();
|
||||
if (lastChar != '\r') {
|
||||
linebuf[idx++] = (char)lastChar;
|
||||
}
|
||||
} while ((lastChar >= 0) && (lastChar != '\n') && (idx < SPIFFS_MAXLENGTH_FILEPATH));
|
||||
|
||||
if (isOverflowed) {
|
||||
isOverflowed = (lastChar != '\n');
|
||||
continue;
|
||||
}
|
||||
isOverflowed = (idx >= SPIFFS_MAXLENGTH_FILEPATH);
|
||||
linebuf[idx - 1] = '\0';
|
||||
if (!addExclude(linebuf)) {
|
||||
excludeFile.close();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
excludeFile.close();
|
||||
}
|
||||
|
||||
static bool isExcluded(fs::FS &_fs, const char *filename) {
|
||||
if (excludes == NULL) {
|
||||
loadExcludeList(_fs, excludeListFile);
|
||||
}
|
||||
ExcludeList *e = excludes;
|
||||
while (e) {
|
||||
if (matchWild(e->item, filename)) {
|
||||
return true;
|
||||
}
|
||||
e = e->next;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// WEB HANDLER IMPLEMENTATION
|
||||
|
||||
#ifdef ESP32
|
||||
SPIFFSEditor::SPIFFSEditor(const fs::FS &fs, const String &username, const String &password)
|
||||
#else
|
||||
SPIFFSEditor::SPIFFSEditor(const String &username, const String &password, const fs::FS &fs)
|
||||
#endif
|
||||
: _fs(fs), _username(username), _password(password), _authenticated(false), _startTime(0) {
|
||||
}
|
||||
|
||||
@@ -406,24 +19,20 @@ bool SPIFFSEditor::canHandle(AsyncWebServerRequest *request) {
|
||||
if (!request->_tempFile) {
|
||||
return false;
|
||||
}
|
||||
#ifdef ESP32
|
||||
if (request->_tempFile.isDirectory()) {
|
||||
request->_tempFile.close();
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (request->hasParam("download")) {
|
||||
request->_tempFile = _fs.open("/" + request->arg("download"), "r");
|
||||
if (!request->_tempFile) {
|
||||
return false;
|
||||
}
|
||||
#ifdef ESP32
|
||||
if (request->_tempFile.isDirectory()) {
|
||||
request->_tempFile.close();
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
request->addInterestingHeader("If-Modified-Since");
|
||||
return true;
|
||||
@@ -442,46 +51,22 @@ void SPIFFSEditor::handleRequest(AsyncWebServerRequest *request) {
|
||||
if (request->method() == HTTP_GET) {
|
||||
if (request->hasParam("list")) {
|
||||
const String path = request->getParam("list")->value();
|
||||
#ifdef ESP32
|
||||
|
||||
File dir = _fs.open(path);
|
||||
#else
|
||||
Dir dir = _fs.openDir(path);
|
||||
#endif
|
||||
String output = "[";
|
||||
#ifdef ESP32
|
||||
File file = dir.openNextFile();
|
||||
while (file) {
|
||||
#else
|
||||
while (dir.next()) {
|
||||
fs::File entry = dir.openFile("r");
|
||||
#endif
|
||||
if (isExcluded(_fs, file.name())) {
|
||||
#ifdef ESP32
|
||||
file = dir.openNextFile();
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
if (output != "[") {
|
||||
output += ',';
|
||||
}
|
||||
output += "{\"type\":\"";
|
||||
output += "file";
|
||||
output += "\",\"name\":\"";
|
||||
output += file.name();
|
||||
output += "\",\"size\":";
|
||||
output += file.size();
|
||||
output += ",\"ver\":";
|
||||
output += file.getLastWrite();
|
||||
output += "}";
|
||||
#ifdef ESP32
|
||||
if (file.isDirectory()) {
|
||||
output += "{\"type\":\"dir\",\"name\":\"" + String(file.name()) + "\",\"size\":" + file.size() + "}";
|
||||
} else {
|
||||
output += "{\"type\":\"file\",\"name\":\"" + String(file.name()) + "\",\"size\":" + file.size() + "}";
|
||||
}
|
||||
file = dir.openNextFile();
|
||||
#else
|
||||
file.close();
|
||||
#endif
|
||||
}
|
||||
#ifdef ESP32
|
||||
dir.close();
|
||||
#endif
|
||||
output += "]";
|
||||
request->send(200, "application/json", output);
|
||||
} else if (request->hasParam("edit") || request->hasParam("download")) {
|
||||
@@ -491,8 +76,7 @@ void SPIFFSEditor::handleRequest(AsyncWebServerRequest *request) {
|
||||
if (request->header("If-Modified-Since").equals(buildTime)) {
|
||||
request->send(304);
|
||||
} else {
|
||||
AsyncWebServerResponse *response = request->beginResponse_P(200, "text/html", edit_htm_gz, edit_htm_gz_len);
|
||||
response->addHeader("Content-Encoding", "gzip");
|
||||
AsyncWebServerResponse *response = request->beginResponse(_fs, "/www/edit.html");
|
||||
response->addHeader("Last-Modified", buildTime);
|
||||
request->send(response);
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ void drawNew(uint8_t mac[8], bool buttonPressed, tagRecord *&taginfo) {
|
||||
deserializeJson(doc, taginfo->modeConfigJson);
|
||||
JsonObject cfgobj = doc.as<JsonObject>();
|
||||
|
||||
Serial.println("Updating " + dst + " mode " + String(taginfo->contentMode) + " nextupdate " + String(taginfo->nextupdate));
|
||||
wsLog("Updating " + dst + " mode " + String(taginfo->contentMode));
|
||||
taginfo->nextupdate = now + 600;
|
||||
|
||||
switch (taginfo->contentMode) {
|
||||
@@ -67,7 +67,7 @@ void drawNew(uint8_t mac[8], bool buttonPressed, tagRecord *&taginfo) {
|
||||
if (prepareDataAvail(&filename, DATATYPE_IMGRAW, mac, cfgobj["timetolive"].as<int>())) {
|
||||
cfgobj["#fetched"] = true;
|
||||
} else {
|
||||
wsString("Error accessing " + filename);
|
||||
wsErr("Error accessing " + filename);
|
||||
}
|
||||
taginfo->nextupdate = 3216153600;
|
||||
}
|
||||
@@ -75,21 +75,17 @@ void drawNew(uint8_t mac[8], bool buttonPressed, tagRecord *&taginfo) {
|
||||
|
||||
case Today:
|
||||
|
||||
Serial.println("heap voor drawDate: " + String(ESP.getFreeHeap()));
|
||||
drawDate(filename);
|
||||
Serial.println("heap na drawDate: " + String(ESP.getFreeHeap()));
|
||||
drawDate(filename, taginfo);
|
||||
// updateTagImage(filename, mac, (midnight - now) / 60 - 10);
|
||||
updateTagImage(filename, mac, 60);
|
||||
updateTagImage(filename, mac, 0);
|
||||
taginfo->nextupdate = midnight;
|
||||
break;
|
||||
|
||||
case CountDays:
|
||||
|
||||
if (buttonPressed) cfgobj["counter"] = 0;
|
||||
Serial.println("heap voor drawnumber: " + String(ESP.getFreeHeap()));
|
||||
drawNumber(filename, (int32_t)cfgobj["counter"], (int32_t)cfgobj["thresholdred"]);
|
||||
Serial.println("heap na drawnumber: " + String(ESP.getFreeHeap()));
|
||||
updateTagImage(filename, mac, 60);
|
||||
drawNumber(filename, (int32_t)cfgobj["counter"], (int32_t)cfgobj["thresholdred"], taginfo);
|
||||
updateTagImage(filename, mac, (buttonPressed?0:60));
|
||||
cfgobj["counter"] = (int32_t)cfgobj["counter"] + 1;
|
||||
taginfo->nextupdate = midnight;
|
||||
break;
|
||||
@@ -97,12 +93,10 @@ void drawNew(uint8_t mac[8], bool buttonPressed, tagRecord *&taginfo) {
|
||||
case CountHours:
|
||||
|
||||
if (buttonPressed) cfgobj["counter"] = 0;
|
||||
Serial.println("heap voor drawnumber: " + String(ESP.getFreeHeap()));
|
||||
drawNumber(filename, (int32_t)cfgobj["counter"], (int32_t)cfgobj["thresholdred"]);
|
||||
Serial.println("heap na drawnumber: " + String(ESP.getFreeHeap()));
|
||||
drawNumber(filename, (int32_t)cfgobj["counter"], (int32_t)cfgobj["thresholdred"], taginfo);
|
||||
// updateTagImage(&filename, mac, (3600 - now % 3600) / 60);
|
||||
// taginfo->nextupdate = now + 3600 - (now % 3600);
|
||||
updateTagImage(filename, mac, 3);
|
||||
updateTagImage(filename, mac, (buttonPressed?0:3));
|
||||
cfgobj["counter"] = (int32_t)cfgobj["counter"] + 1;
|
||||
taginfo->nextupdate = now + 300;
|
||||
break;
|
||||
@@ -110,6 +104,13 @@ void drawNew(uint8_t mac[8], bool buttonPressed, tagRecord *&taginfo) {
|
||||
case Weather:
|
||||
|
||||
// https://open-meteo.com/
|
||||
// https://geocoding-api.open-meteo.com/v1/search?name=eindhoven
|
||||
// https://api.open-meteo.com/v1/forecast?latitude=52.52&longitude=13.41¤t_weather=true
|
||||
// https://github.com/erikflowers/weather-icons
|
||||
|
||||
drawWeather(filename, cfgobj["location"], taginfo);
|
||||
updateTagImage(filename, mac, 0);
|
||||
taginfo->nextupdate = now + 900;
|
||||
break;
|
||||
|
||||
case Firmware:
|
||||
@@ -119,7 +120,7 @@ void drawNew(uint8_t mac[8], bool buttonPressed, tagRecord *&taginfo) {
|
||||
if (prepareDataAvail(&filename, DATATYPE_UPDATE, mac, cfgobj["timetolive"].as<int>())) {
|
||||
cfgobj["#fetched"] = true;
|
||||
} else {
|
||||
wsString("Error accessing " + filename);
|
||||
wsErr("Error accessing " + filename);
|
||||
}
|
||||
cfgobj["filename"]="";
|
||||
taginfo->nextupdate = 3216153600;
|
||||
@@ -149,8 +150,7 @@ bool updateTagImage(String &filename, uint8_t *dst, uint16_t nextCheckin) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void drawDate(String &filename) {
|
||||
|
||||
void drawDate(String &filename, tagRecord *&taginfo) {
|
||||
TFT_eSPI tft = TFT_eSPI();
|
||||
TFT_eSprite spr = TFT_eSprite(&tft);
|
||||
time_t now;
|
||||
@@ -161,59 +161,291 @@ void drawDate(String &filename) {
|
||||
String Maand[] = {"januari", "februari", "maart", "april", "mei", "juni","juli", "augustus", "september", "oktober", "november", "december"};
|
||||
int weekday_number = timeinfo.tm_wday;
|
||||
int month_number = timeinfo.tm_mon;
|
||||
long w,h;
|
||||
|
||||
LittleFS.begin();
|
||||
long w = 296, h = 128; // mag staand of liggend
|
||||
spr.createSprite(w, h);
|
||||
if (spr.getPointer() == nullptr) {
|
||||
Serial.println("Failed to create sprite in drawDate");
|
||||
|
||||
if (taginfo->model == SOLUM_29_033) {
|
||||
w = 296;
|
||||
h = 128;
|
||||
spr.createSprite(w, h);
|
||||
if (spr.getPointer() == nullptr) {
|
||||
wsErr("Failed to create sprite in drawDate");
|
||||
}
|
||||
spr.setColorDepth(8);
|
||||
spr.fillSprite(TFT_WHITE);
|
||||
spr.setTextDatum(TC_DATUM);
|
||||
spr.loadFont("fonts/calibrib62", LittleFS);
|
||||
spr.setTextColor(TFT_RED, TFT_WHITE);
|
||||
spr.drawString(Dag[timeinfo.tm_wday], w / 2, 10);
|
||||
spr.loadFont("fonts/calibrib50", LittleFS);
|
||||
spr.setTextColor(TFT_BLACK, TFT_WHITE);
|
||||
spr.drawString(String(timeinfo.tm_mday) + " " + Maand[timeinfo.tm_mon], w / 2, 73);
|
||||
spr.unloadFont();
|
||||
} else if (taginfo->model == SOLUM_154_033) {
|
||||
w = 154;
|
||||
h = 154;
|
||||
spr.createSprite(w, h);
|
||||
if (spr.getPointer() == nullptr) {
|
||||
wsErr("Failed to create sprite in drawDate");
|
||||
}
|
||||
spr.setColorDepth(8);
|
||||
spr.fillSprite(TFT_WHITE);
|
||||
spr.setTextDatum(TC_DATUM);
|
||||
spr.loadFont("fonts/calibrib30", LittleFS);
|
||||
spr.setTextColor(TFT_BLACK, TFT_WHITE);
|
||||
spr.drawString(Dag[timeinfo.tm_wday], w / 2, 10);
|
||||
spr.drawString(String(Maand[timeinfo.tm_mon]), w / 2, 120);
|
||||
spr.unloadFont();
|
||||
spr.loadFont("fonts/numbers2-1", LittleFS);
|
||||
spr.setTextColor(TFT_RED, TFT_WHITE);
|
||||
spr.drawString(String(timeinfo.tm_mday), w / 2, 42);
|
||||
spr.unloadFont();
|
||||
}
|
||||
spr.setColorDepth(8);
|
||||
spr.fillSprite(TFT_WHITE);
|
||||
spr.setTextDatum(TC_DATUM);
|
||||
spr.loadFont("calibrib62", LittleFS);
|
||||
spr.setTextColor(TFT_RED, TFT_WHITE);
|
||||
spr.drawString(Dag[timeinfo.tm_wday], w / 2, 10);
|
||||
spr.loadFont("calibrib50", LittleFS);
|
||||
spr.setTextColor(TFT_BLACK, TFT_WHITE);
|
||||
spr.drawString(String(timeinfo.tm_mday) + " " + Maand[timeinfo.tm_mon], w / 2, 73);
|
||||
spr.unloadFont();
|
||||
|
||||
spr2grays(spr, w, h, filename);
|
||||
|
||||
spr.deleteSprite();
|
||||
}
|
||||
|
||||
void drawNumber(String &filename, int32_t count, int32_t thresholdred) {
|
||||
void drawNumber(String &filename, int32_t count, int32_t thresholdred, tagRecord *&taginfo) {
|
||||
TFT_eSPI tft = TFT_eSPI();
|
||||
TFT_eSprite spr = TFT_eSprite(&tft);
|
||||
|
||||
LittleFS.begin();
|
||||
long w = 296, h = 128;
|
||||
spr.createSprite(w, h);
|
||||
if (spr.getPointer() == nullptr) {
|
||||
Serial.println("Failed to create sprite in drawNumber");
|
||||
}
|
||||
spr.setColorDepth(8);
|
||||
spr.fillSprite(TFT_WHITE);
|
||||
spr.setTextDatum(MC_DATUM);
|
||||
if (count > thresholdred) {
|
||||
spr.setTextColor(TFT_RED, TFT_WHITE);
|
||||
} else {
|
||||
spr.setTextColor(TFT_BLACK, TFT_WHITE);
|
||||
long w, h;
|
||||
|
||||
if (taginfo->model == SOLUM_29_033) {
|
||||
w = 296;
|
||||
h = 128;
|
||||
spr.createSprite(w, h);
|
||||
if (spr.getPointer() == nullptr) {
|
||||
wsErr("Failed to create sprite in drawNumber");
|
||||
}
|
||||
spr.fillSprite(TFT_WHITE);
|
||||
spr.setTextDatum(MC_DATUM);
|
||||
if (count > thresholdred) {
|
||||
spr.setTextColor(TFT_RED, TFT_WHITE);
|
||||
} else {
|
||||
spr.setTextColor(TFT_BLACK, TFT_WHITE);
|
||||
}
|
||||
String font = "fonts/numbers1-2";
|
||||
if (count > 999) font = "fonts/numbers2-2";
|
||||
if (count > 9999) font = "fonts/numbers3-2";
|
||||
spr.loadFont(font, LittleFS);
|
||||
spr.drawString(String(count), w / 2, h / 2 + 10);
|
||||
spr.unloadFont();
|
||||
} else if (taginfo->model == SOLUM_154_033) {
|
||||
w = 154;
|
||||
h = 154;
|
||||
spr.createSprite(w, h);
|
||||
if (spr.getPointer() == nullptr) {
|
||||
wsErr("Failed to create sprite in drawNumber");
|
||||
}
|
||||
spr.fillSprite(TFT_WHITE);
|
||||
spr.setTextDatum(MC_DATUM);
|
||||
if (count > thresholdred) {
|
||||
spr.setTextColor(TFT_RED, TFT_WHITE);
|
||||
} else {
|
||||
spr.setTextColor(TFT_BLACK, TFT_WHITE);
|
||||
}
|
||||
String font = "fonts/numbers1-1";
|
||||
if (count > 99) font = "fonts/numbers2-1";
|
||||
if (count > 999) font = "fonts/numbers3-1";
|
||||
spr.loadFont(font, LittleFS);
|
||||
spr.drawString(String(count), w / 2, h / 2 + 10);
|
||||
spr.unloadFont();
|
||||
}
|
||||
String font = "numbers1-2";
|
||||
if (count>999) font="numbers2-2";
|
||||
if (count>9999) font="numbers3-2";
|
||||
spr.loadFont(font, LittleFS);
|
||||
spr.drawString(String(count), w/2, h/2+10);
|
||||
spr.unloadFont();
|
||||
|
||||
spr2grays(spr, w, h, filename);
|
||||
|
||||
spr.deleteSprite();
|
||||
}
|
||||
|
||||
void drawWeather(String &filename, String location, tagRecord *&taginfo) {
|
||||
|
||||
TFT_eSPI tft = TFT_eSPI();
|
||||
TFT_eSprite spr = TFT_eSprite(&tft);
|
||||
|
||||
wsLog("get weather");
|
||||
HTTPClient http;
|
||||
http.begin("https://geocoding-api.open-meteo.com/v1/search?name=" + urlEncode(location.c_str()) + "&count=1");
|
||||
http.setTimeout(5000); // timeout in ms
|
||||
int httpCode = http.GET();
|
||||
if (httpCode == 200) {
|
||||
|
||||
StaticJsonDocument<1000> doc;
|
||||
DeserializationError error = deserializeJson(doc, http.getStream());
|
||||
http.end();
|
||||
|
||||
http.begin("https://api.open-meteo.com/v1/forecast?latitude=" + doc["results"][0]["latitude"].as<String>() + "&longitude=" + doc["results"][0]["longitude"].as<String>() + "¤t_weather=true&windspeed_unit=ms&timezone=" + doc["results"][0]["timezone"].as<String>());
|
||||
http.setTimeout(5000); // timeout in ms
|
||||
int httpCode = http.GET();
|
||||
|
||||
if (httpCode == 200) {
|
||||
|
||||
StaticJsonDocument<200> filter;
|
||||
filter["current_weather"]["temperature"] = true;
|
||||
filter["current_weather"]["windspeed"] = true;
|
||||
filter["current_weather"]["winddirection"] = true;
|
||||
filter["current_weather"]["weathercode"] = true;
|
||||
|
||||
doc.clear();
|
||||
DeserializationError error = deserializeJson(doc, http.getString(), DeserializationOption::Filter(filter));
|
||||
if (error) {
|
||||
Serial.println(F("deserializeJson() failed: "));
|
||||
Serial.println(error.c_str());
|
||||
}
|
||||
|
||||
auto temperature = doc["current_weather"]["temperature"].as<double>();
|
||||
auto windspeed = doc["current_weather"]["windspeed"].as<int>();
|
||||
auto winddirection = doc["current_weather"]["winddirection"].as<int>();
|
||||
|
||||
uint8_t weathercode = doc["current_weather"]["weathercode"].as<int>();
|
||||
if (weathercode > 40) weathercode -= 40;
|
||||
int wind = windSpeedToBeaufort(windspeed);
|
||||
|
||||
String weatherIcons[] = {"\uf00d", "\uf00c", "\uf002", "\uf013", "\uf013", "\uf014", "-", "-", "\uf014", "-", "-",
|
||||
"\uf01a", "-", "\uf01a", "-", "\uf01a", "\uf017", "\uf017", "-", "-", "-",
|
||||
"\uf019", "-", "\uf019", "-", "\uf019", "\uf015", "\uf015", "-", "-", "-",
|
||||
"\uf01b", "-", "\uf01b", "-", "\uf01b", "-", "\uf076", "-", "-", "\uf01a",
|
||||
"\uf01a", "\uf01a", "-", "-", "\uf064", "\uf064", "-", "-", "-", "-",
|
||||
"-", "-", "-", "-", "\uf01e", "\uf01d", "-", "-", "\uf01e"};
|
||||
if (1==0) { //nacht
|
||||
weatherIcons[0] = "\0uf02e";
|
||||
weatherIcons[1] = "\0uf083";
|
||||
weatherIcons[2] = "\0uf086";
|
||||
}
|
||||
|
||||
String windIcons[] = {"\uf0b7", "\uf0b8", "\uf0b9", "\uf0ba", "\uf0bb", "\uf0bc", "\uf0bd", "\uf0be", "\uf0bf", "\uf0c0", "\uf0c1", "\uf0c2", "\uf0c3"};
|
||||
|
||||
doc.clear();
|
||||
|
||||
LittleFS.begin();
|
||||
spr.setColorDepth(8);
|
||||
tft.setTextWrap(false,false);
|
||||
|
||||
long w, h;
|
||||
|
||||
if (taginfo->model == SOLUM_29_033) {
|
||||
w = 296;
|
||||
h = 128;
|
||||
spr.createSprite(w, h);
|
||||
if (spr.getPointer() == nullptr) {
|
||||
wsErr("Failed to create sprite in drawWeather");
|
||||
}
|
||||
spr.fillSprite(TFT_WHITE);
|
||||
spr.setTextDatum(TL_DATUM);
|
||||
|
||||
spr.loadFont("fonts/bahnschrift30", LittleFS);
|
||||
spr.setTextColor(TFT_BLACK, TFT_WHITE);
|
||||
spr.drawString(location, 10, 10);
|
||||
spr.unloadFont();
|
||||
|
||||
spr.loadFont("fonts/bahnschrift70", LittleFS);
|
||||
if (temperature < 0) {
|
||||
spr.setTextColor(TFT_RED, TFT_WHITE);
|
||||
} else {
|
||||
spr.setTextColor(TFT_BLACK, TFT_WHITE);
|
||||
}
|
||||
char tmpOutput[5];
|
||||
dtostrf(temperature, 2, 1, tmpOutput);
|
||||
spr.drawString(String(tmpOutput), 5, 65);
|
||||
spr.unloadFont();
|
||||
|
||||
spr.loadFont("fonts/weathericons78", LittleFS);
|
||||
if (weathercode == 55 || weathercode == 65 || weathercode == 75 || weathercode == 82 || weathercode == 86 || weathercode == 95 || weathercode == 99) {
|
||||
spr.setTextColor(TFT_RED, TFT_WHITE);
|
||||
} else {
|
||||
spr.setTextColor(TFT_BLACK, TFT_WHITE);
|
||||
}
|
||||
spr.setTextColor(TFT_BLACK, TFT_WHITE);
|
||||
spr.setCursor(185, 20);
|
||||
spr.printToSprite(weatherIcons[weathercode]);
|
||||
spr.unloadFont();
|
||||
|
||||
spr.loadFont("fonts/weathericons30", LittleFS);
|
||||
if (wind > 4) {
|
||||
spr.setTextColor(TFT_RED, TFT_WHITE);
|
||||
} else {
|
||||
spr.setTextColor(TFT_BLACK, TFT_WHITE);
|
||||
}
|
||||
spr.setCursor(255, 0);
|
||||
spr.printToSprite(windIcons[wind]);
|
||||
|
||||
spr.setTextColor(TFT_BLACK, TFT_WHITE);
|
||||
spr.setCursor(230, -5);
|
||||
spr.printToSprite(windDirectionIcon(winddirection));
|
||||
if (weathercode > 10) {
|
||||
spr.setTextColor(TFT_RED, TFT_WHITE);
|
||||
spr.setCursor(190, 0);
|
||||
spr.printToSprite("\uf084");
|
||||
}
|
||||
} else if (taginfo->model == SOLUM_154_033) {
|
||||
w = 154;
|
||||
h = 154;
|
||||
|
||||
spr.createSprite(w, h);
|
||||
if (spr.getPointer() == nullptr) {
|
||||
wsErr("Failed to create sprite in drawWeather");
|
||||
}
|
||||
spr.fillSprite(TFT_WHITE);
|
||||
spr.setTextDatum(TL_DATUM);
|
||||
|
||||
spr.setTextFont(2);
|
||||
spr.setTextColor(TFT_BLACK, TFT_WHITE);
|
||||
spr.drawString(location, 10, 130);
|
||||
|
||||
spr.loadFont("fonts/bahnschrift30", LittleFS);
|
||||
if (temperature < 0) {
|
||||
spr.setTextColor(TFT_RED, TFT_WHITE);
|
||||
} else {
|
||||
spr.setTextColor(TFT_BLACK, TFT_WHITE);
|
||||
}
|
||||
char tmpOutput[5];
|
||||
dtostrf(temperature, 2, 1, tmpOutput);
|
||||
spr.drawString(String(tmpOutput), 10, 10);
|
||||
spr.unloadFont();
|
||||
|
||||
spr.loadFont("fonts/weathericons78", LittleFS);
|
||||
if (weathercode == 55 || weathercode == 65 || weathercode == 75 || weathercode == 82 || weathercode == 86 || weathercode == 95 || weathercode == 99) {
|
||||
spr.setTextColor(TFT_RED, TFT_WHITE);
|
||||
} else {
|
||||
spr.setTextColor(TFT_BLACK, TFT_WHITE);
|
||||
}
|
||||
spr.setTextColor(TFT_BLACK, TFT_WHITE);
|
||||
spr.setCursor(35, 25);
|
||||
spr.printToSprite(weatherIcons[weathercode]);
|
||||
spr.unloadFont();
|
||||
|
||||
spr.loadFont("fonts/weathericons30", LittleFS);
|
||||
if (wind > 4) {
|
||||
spr.setTextColor(TFT_RED, TFT_WHITE);
|
||||
} else {
|
||||
spr.setTextColor(TFT_BLACK, TFT_WHITE);
|
||||
}
|
||||
spr.setCursor(115, -5);
|
||||
spr.printToSprite(windIcons[wind]);
|
||||
|
||||
spr.setTextColor(TFT_BLACK, TFT_WHITE);
|
||||
spr.setCursor(90, -5);
|
||||
spr.printToSprite(windDirectionIcon(winddirection));
|
||||
if (weathercode > 10) {
|
||||
spr.setTextColor(TFT_RED, TFT_WHITE);
|
||||
spr.setCursor(115, 110);
|
||||
spr.printToSprite("\uf084");
|
||||
}
|
||||
}
|
||||
|
||||
spr.unloadFont();
|
||||
spr2grays(spr, w, h, filename);
|
||||
spr.deleteSprite();
|
||||
}
|
||||
}
|
||||
http.end();
|
||||
}
|
||||
|
||||
bool getImgURL(String &filename, String URL, time_t fetched) {
|
||||
// https://images.klari.net/kat-bw29.jpg
|
||||
|
||||
@@ -233,7 +465,11 @@ bool getImgURL(String &filename, String URL, time_t fetched) {
|
||||
jpg2grays(filename, filename);
|
||||
}
|
||||
} else {
|
||||
Serial.println("http " + String(httpCode));
|
||||
if (httpCode!=304) {
|
||||
wsErr("http " + URL + " " + String(httpCode));
|
||||
} else {
|
||||
wsLog("http " + URL + " " + String(httpCode));
|
||||
}
|
||||
}
|
||||
http.end();
|
||||
return (httpCode == 200);
|
||||
@@ -246,3 +482,41 @@ char *formatHttpDate(time_t t) {
|
||||
strftime(buf, sizeof(buf), "%a, %d %b %Y %H:%M:%S GMT", timeinfo);
|
||||
return buf;
|
||||
}
|
||||
|
||||
String urlEncode(const char *msg) {
|
||||
const char *hex = "0123456789ABCDEF";
|
||||
String encodedMsg = "";
|
||||
|
||||
while (*msg != '\0') {
|
||||
if (
|
||||
('a' <= *msg && *msg <= 'z') || ('A' <= *msg && *msg <= 'Z') || ('0' <= *msg && *msg <= '9') || *msg == '-' || *msg == '_' || *msg == '.' || *msg == '~') {
|
||||
encodedMsg += *msg;
|
||||
} else {
|
||||
encodedMsg += '%';
|
||||
encodedMsg += hex[(unsigned char)*msg >> 4];
|
||||
encodedMsg += hex[*msg & 0xf];
|
||||
}
|
||||
msg++;
|
||||
}
|
||||
return encodedMsg;
|
||||
}
|
||||
|
||||
int windSpeedToBeaufort(float windSpeed) {
|
||||
int beaufort = 0;
|
||||
float speeds[] = {0.3, 1.5, 3.3, 5.5, 8, 10.8, 13.9, 17.2, 20.8, 24.5, 28.5, 32.7};
|
||||
for (int i = 0; i < 12; i++) {
|
||||
if (windSpeed >= speeds[i]) {
|
||||
beaufort = i + 1;
|
||||
}
|
||||
}
|
||||
return beaufort;
|
||||
}
|
||||
|
||||
String windDirectionIcon(int degrees) {
|
||||
String directions[] = {"\uf044", "\uf088", "\uf04d", "\uf057", "\uf058", "\uf087", "\uf048", "\uf043"};
|
||||
int index = (degrees + 22) / 45;
|
||||
if (index >= 8) {
|
||||
index = 0;
|
||||
}
|
||||
return directions[index];
|
||||
}
|
||||
|
||||
@@ -31,11 +31,11 @@ void setup() {
|
||||
Serial.begin(115200);
|
||||
Serial.print(">\n");
|
||||
|
||||
configTzTime("CET-1CEST,M3.5.0,M10.5.0/3", "europe.pool.ntp.org", "time.nist.gov");
|
||||
configTzTime("CET-1CEST,M3.5.0,M10.5.0/3", "0.nl.pool.ntp.org", "europe.pool.ntp.org", "time.nist.gov");
|
||||
// https://github.com/nayarsystems/posix_tz_db/blob/master/zones.csv
|
||||
|
||||
init_web();
|
||||
loadDB("/tagDB.json");
|
||||
loadDB("/current/tagDB.json");
|
||||
|
||||
xTaskCreate(timeTask, "timed tasks", 10000, NULL, 2, NULL);
|
||||
xTaskCreate(zbsRxTask, "zbsRX Process", 10000, NULL, 2, NULL);
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <TFT_eSPI.h>
|
||||
#include <TJpg_Decoder.h>
|
||||
#include <makeimage.h>
|
||||
#include <web.h>
|
||||
|
||||
TFT_eSPI tft = TFT_eSPI();
|
||||
TFT_eSprite spr = TFT_eSprite(&tft);
|
||||
@@ -22,7 +23,7 @@ void jpg2grays(String filein, String fileout) {
|
||||
|
||||
spr.createSprite(w, h);
|
||||
if (spr.getPointer() == nullptr) {
|
||||
Serial.println("Failed to create sprite in jpg2grays");
|
||||
wsErr("Failed to create sprite in jpg2grays");
|
||||
}
|
||||
spr.setColorDepth(8);
|
||||
spr.fillSprite(TFT_WHITE);
|
||||
|
||||
@@ -71,12 +71,11 @@ bool prepareDataAvail(String* filename, uint8_t dataType, uint8_t* dst, uint16_t
|
||||
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");
|
||||
wsErr("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);
|
||||
@@ -88,7 +87,6 @@ bool prepareDataAvail(String* filename, uint8_t dataType, uint8_t* dst, uint16_t
|
||||
|
||||
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);
|
||||
@@ -114,7 +112,7 @@ bool prepareDataAvail(String* filename, uint8_t dataType, uint8_t* dst, uint16_t
|
||||
taginfo = tagRecord::findByMAC(mac);
|
||||
if (taginfo != nullptr) {
|
||||
if (memcmp(md5bytes, taginfo->md5pending, 16) == 0) {
|
||||
wsString("new image is the same as current image. not updating tag.");
|
||||
Serial.println("new image is the same as current image. not updating tag.");
|
||||
wsSendTaginfo(mac);
|
||||
return false;
|
||||
}
|
||||
@@ -156,7 +154,7 @@ bool prepareDataAvail(String* filename, uint8_t dataType, uint8_t* dst, uint16_t
|
||||
}
|
||||
dstfile.close();
|
||||
|
||||
wsString("new image pending: " + String(dst_path));
|
||||
wsLog("new image pending: " + String(dst_path));
|
||||
if (taginfo != nullptr) {
|
||||
taginfo->pending = true;
|
||||
taginfo->CheckinInMinPending = nextCheckin + 1;
|
||||
@@ -164,7 +162,7 @@ bool prepareDataAvail(String* filename, uint8_t dataType, uint8_t* dst, uint16_t
|
||||
}
|
||||
}
|
||||
else {
|
||||
Serial.println("firmware upload pending");
|
||||
wsLog("firmware upload pending");
|
||||
}
|
||||
file.close();
|
||||
|
||||
@@ -211,7 +209,7 @@ void processBlockRequest(struct espBlockRequest* br) {
|
||||
sendBlock(pd->data + (br->blockId * BLOCK_DATA_SIZE), len);
|
||||
char buffer[64];
|
||||
sprintf(buffer, "< Block Request received for MD5 %llu, block %d\n\0", br->ver, br->blockId);
|
||||
wsString((String)buffer);
|
||||
wsLog((String)buffer);
|
||||
Serial.printf("<BlockId=%d\n", br->blockId);
|
||||
}
|
||||
|
||||
@@ -220,7 +218,7 @@ void processXferComplete(struct espXferComplete* xfc) {
|
||||
uint8_t src[8];
|
||||
*((uint64_t*)src) = swap64(*((uint64_t*)xfc->src));
|
||||
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);
|
||||
wsLog((String)buffer);
|
||||
Serial.print(buffer);
|
||||
uint8_t mac[6];
|
||||
memcpy(mac, src + 2, sizeof(mac));
|
||||
@@ -270,12 +268,12 @@ void processDataReq(struct espAvailDataReq* eadr) {
|
||||
time_t now;
|
||||
time(&now);
|
||||
taginfo->lastseen = now;
|
||||
//taginfo->model = eadr->adr.hwType;
|
||||
taginfo->expectedNextCheckin = now + 300;
|
||||
taginfo->button = (eadr->adr.wakeupReason==WAKEUP_REASON_GPIO);
|
||||
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);
|
||||
//wsString((String)buffer);
|
||||
wsSendTaginfo(mac);
|
||||
}
|
||||
|
||||
@@ -138,7 +138,6 @@ void SerialRXLoop() {
|
||||
}
|
||||
if (strncmp(cmdbuffer, "BST>", 4) == 0) {
|
||||
Serial.print(">SYNC BURST\n");
|
||||
wsString(">SYNC BURST");
|
||||
RXState = ZBS_RX_WAIT_HEADER;
|
||||
}
|
||||
if (strncmp(cmdbuffer, "XFC>", 4) == 0) {
|
||||
|
||||
@@ -143,14 +143,22 @@ void onEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType
|
||||
}
|
||||
}
|
||||
|
||||
void wsString(String text) {
|
||||
DynamicJsonDocument doc(100);
|
||||
void wsLog(String text) {
|
||||
StaticJsonDocument<500> doc;
|
||||
doc["logMsg"] = text;
|
||||
xSemaphoreTake(wsMutex, portMAX_DELAY);
|
||||
ws.textAll(doc.as<String>());
|
||||
xSemaphoreGive(wsMutex);
|
||||
}
|
||||
|
||||
void wsErr(String text) {
|
||||
StaticJsonDocument<500> doc;
|
||||
doc["errMsg"] = text;
|
||||
xSemaphoreTake(wsMutex, portMAX_DELAY);
|
||||
ws.textAll(doc.as<String>());
|
||||
xSemaphoreGive(wsMutex);
|
||||
}
|
||||
|
||||
void wsSendSysteminfo() {
|
||||
DynamicJsonDocument doc(250);
|
||||
JsonObject sys = doc.createNestedObject("sys");
|
||||
@@ -181,11 +189,6 @@ void wsSendTaginfo(uint8_t mac[6]) {
|
||||
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");
|
||||
}
|
||||
@@ -214,8 +217,9 @@ void init_web() {
|
||||
ESP.restart();
|
||||
});
|
||||
|
||||
server.serveStatic("/", LittleFS, "/").setDefaultFile("index.htm");
|
||||
|
||||
server.serveStatic("/current", LittleFS, "/current/");
|
||||
server.serveStatic("/", LittleFS, "/www/").setDefaultFile("index.html");
|
||||
|
||||
server.on(
|
||||
"/imgupload", HTTP_POST, [](AsyncWebServerRequest *request) {
|
||||
request->send(200);
|
||||
@@ -282,7 +286,7 @@ void init_web() {
|
||||
taginfo->model = atoi(request->getParam("model", true)->value().c_str());
|
||||
taginfo->nextupdate = 0;
|
||||
wsSendTaginfo(mac);
|
||||
saveDB("/tagDB.json");
|
||||
saveDB("/current/tagDB.json");
|
||||
request->send(200, "text/plain", "Ok, saved");
|
||||
} else {
|
||||
request->send(200, "text/plain", "Error while saving: mac not found");
|
||||
|
||||
Reference in New Issue
Block a user