Merge pull request #1 from IoTManagerProject/beta

Beta
This commit is contained in:
Yuri Trikoz
2020-10-17 22:58:00 +03:00
committed by GitHub
228 changed files with 8680 additions and 2706 deletions

61
.vscode/settings.json vendored
View File

@@ -1,66 +1,7 @@
{
"terminal.integrated.env.windows": {
"PATH": "C:\\Users\\ytrikoz\\.platformio\\penv\\Scripts;C:\\Users\\ytrikoz\\.platformio\\penv;C:\\Program Files (x86)\\Borland\\Delphi7\\Bin;C:\\Program Files (x86)\\Borland\\Delphi7\\Projects\\Bpl\\;C:\\WINDOWS\\system32;C:\\WINDOWS;C:\\WINDOWS\\System32\\Wbem;C:\\WINDOWS\\System32\\WindowsPowerShell\\v1.0\\;C:\\WINDOWS\\System32\\OpenSSH\\;C:\\Program Files\\Git\\cmd\\;c:\\android-studio\\jre\\jre\\bin\\;C:\\Program Files (x86)\\Microsoft SQL Server\\150\\DTS\\Binn\\;C:\\Front\\Shared\\;C:\\Program Files (x86)\\Plantronics\\Spokes3G\\;C:\\Program Files\\Microsoft SQL Server\\130\\Tools\\Binn\\;C:\\Program Files\\Microsoft SQL Server\\Client SDK\\ODBC\\170\\Tools\\Binn\\;C:\\Program Files\\nodejs\\;C:\\ProgramData\\chocolatey\\bin;C:\\Program Files\\dotnet\\;C:\\Users\\ytrikoz\\AppData\\Local\\Microsoft\\WindowsApps;C:\\Users\\ytrikoz\\AppData\\Local\\Programs\\Microsoft VS Code\\bin;C:\\Users\\ytrikoz\\AppData\\Roaming\\npm;C:\\MinGW\\bin;;C:\\Program Files (x86)\\West Wind Html Help Builder;C:\\Program Files (x86)\\Borland\\Delphi7\\Bin;C:\\Program Files (x86)\\Borland\\Delphi7\\Projects\\Bpl\\;C:\\WINDOWS\\system32;C:\\WINDOWS;C:\\WINDOWS\\System32\\Wbem;C:\\WINDOWS\\System32\\WindowsPowerShell\\v1.0\\;C:\\WINDOWS\\System32\\OpenSSH\\;C:\\Program Files\\Git\\cmd\\;c:\\android-studio\\jre\\jre\\bin\\;C:\\Program Files (x86)\\Microsoft SQL Server\\150\\DTS\\Binn\\;C:\\Front\\Shared\\;C:\\Program Files (x86)\\Plantronics\\Spokes3G\\;C:\\Program Files\\Microsoft SQL Server\\130\\Tools\\Binn\\;C:\\Program Files\\Microsoft SQL Server\\Client SDK\\ODBC\\170\\Tools\\Binn\\;C:\\Program Files\\nodejs\\;C:\\ProgramData\\chocolatey\\bin;C:\\Program Files\\dotnet\\;C:\\Users\\ytrikoz\\AppData\\Local\\Microsoft\\WindowsApps;C:\\Users\\ytrikoz\\AppData\\Local\\Programs\\Microsoft VS Code\\bin;C:\\Users\\ytrikoz\\AppData\\Roaming\\npm;C:\\MinGW\\bin;;C:\\Program Files (x86)\\West Wind Html Help Builder",
"PLATFORMIO_CALLER": "vscode"
},
"files.associations": {
"*.cpp": "cpp",
"functional": "cpp",
"*.tcc": "cpp",
"optional": "cpp",
"ratio": "cpp",
"system_error": "cpp",
"array": "cpp",
"regex": "cpp",
"tuple": "cpp",
"type_traits": "cpp",
"utility": "cpp",
"bitset": "cpp",
"chrono": "cpp",
"algorithm": "cpp",
"random": "cpp",
"atomic": "cpp",
"cctype": "cpp",
"cerrno": "cpp",
"cfloat": "cpp",
"climits": "cpp",
"clocale": "cpp",
"cmath": "cpp",
"cstdarg": "cpp",
"cstddef": "cpp",
"cstdint": "cpp",
"cstdio": "cpp",
"cstdlib": "cpp",
"ctime": "cpp",
"cwchar": "cpp",
"cwctype": "cpp",
"deque": "cpp",
"list": "cpp",
"map": "cpp",
"set": "cpp",
"string": "cpp",
"unordered_map": "cpp",
"vector": "cpp",
"exception": "cpp",
"iterator": "cpp",
"memory": "cpp",
"numeric": "cpp",
"fstream": "cpp",
"initializer_list": "cpp",
"ios": "cpp",
"iosfwd": "cpp",
"istream": "cpp",
"limits": "cpp",
"locale": "cpp",
"new": "cpp",
"ostream": "cpp",
"queue": "cpp",
"sstream": "cpp",
"stack": "cpp",
"stdexcept": "cpp",
"streambuf": "cpp",
"cinttypes": "cpp",
"cstdbool": "cpp",
"typeinfo": "cpp"
"algorithm": "cpp"
}
}

View File

@@ -3,8 +3,8 @@
"chipID": "",
"apssid": "IoTmanager",
"appass": "",
"routerssid": "rise",
"routerpass": "hostel3333",
"routerssid": "home",
"routerpass": "kisa3333",
"timezone": 2,
"ntp": "pool.ntp.org",
"mqttServer": "91.204.228.124",
@@ -17,6 +17,6 @@
"weblogin": "admin",
"webpass": "admin",
"udponoff": "1",
"blink": "1",
"blink": "0",
"oneWirePin": "2"
}

Binary file not shown.

View File

@@ -1,12 +0,0 @@
button 1 na Включить#все Реле 0 1
button 2 13 Прихожая Реле 0 2
button 3 14 Кухня Реле 0 3
pwm 1 3 Яркость#коредор: Реле 1023 4
pwm 2 4 Яркость#ванная: Реле 510 5
analog adc 0 Аналоговый#вход Датчики fillgauge 1 1023 1 1023 6
logging adc 1 100 Аналоговый#вход Датчики 7
//Это демо конфигурация. В ней показано как связать кнопки c помощью сценариев
//Кнопка номер 1 связана с кнопкой 2, 3 и с pwm 2
//Так же продемонстрированна система логгирования данных строкой logging
//1 - это интервал между точками в минутах, 100 это количество точек

View File

@@ -1,13 +0,0 @@
button1 = 1
buttonSet 2 1
buttonSet 3 1
pwmSet 2 1024
end
button1 = 0
buttonSet 2 0
buttonSet 3 0
pwmSet 2 0
end
adc > 50
buttonSet 2 1
end

658
data/edit.htm Normal file
View File

@@ -0,0 +1,658 @@
<!--This is the plain html source of the hex encoded Editor-Page embedded in SPIFFSEditor.cpp -->
<!DOCTYPE html>
<html lang="en">
<head>
<title>FS Editor</title>
<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 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 span {
margin-bottom: 5px;
padding: 0 0 0 18px;
cursor: pointer;
display: inline-block;
height: 16px;
vertical-align: middle;
background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAC1+jfqAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAADoSURBVBgZBcExblNBGAbA2ceegTRBuIKOgiihSZNTcC5LUHAihNJR0kGKCDcYJY6D3/77MdOinTvzAgCw8ysThIvn/VojIyMjIyPP+bS1sUQIV2s95pBDDvmbP/mdkft83tpYguZq5Jh/OeaYh+yzy8hTHvNlaxNNczm+la9OTlar1UdA/+C2A4trRCnD3jS8BB1obq2Gk6GU6QbQAS4BUaYSQAf4bhhKKTFdAzrAOwAxEUAH+KEM01SY3gM6wBsEAQB0gJ+maZoC3gI6iPYaAIBJsiRmHU0AALOeFC3aK2cWAACUXe7+AwO0lc9eTHYTAAAAAElFTkSuQmCC') no-repeat;
background-position: 0px 0px;
}
.tvu span:hover {
text-decoration: underline;
}
@media screen and (-webkit-min-device-pixel-ratio:0) {
.tvu {
-webkit-animation: webkit-adjacent-element-selector-bugfix infinite 1s;
}
@-webkit-keyframes webkit-adjacent-element-selector-bugfix {
from {
padding: 0;
}
to {
padding: 0;
}
}
}
#uploader {
position: absolute;
top: 0;
right: 0;
left: 0;
height: 28px;
line-height: 24px;
padding-left: 10px;
background-color: #444;
color: #EEE;
}
#tree {
position: absolute;
top: 28px;
bottom: 0;
left: 0;
width: 160px;
padding: 8px;
}
#editor,
#preview {
position: absolute;
top: 28px;
right: 0;
bottom: 0;
left: 160px;
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: 240px;
height: 240px;
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 input = ce("input");
input.type = "file";
input.multiple = false;
input.name = "data";
input.id = "upload-select";
ge(element).appendChild(input);
var path = ce("input");
path.id = "upload-path";
path.type = "text";
path.name = "path";
path.defaultValue = "/";
ge(element).appendChild(path);
var button = ce("button");
button.innerHTML = 'Upload';
ge(element).appendChild(button);
var mkfile = ce("button");
mkfile.innerHTML = 'Create';
ge(element).appendChild(mkfile);
var filename = ce("input");
filename.id = "editor-filename";
filename.type = "text";
filename.disabled = true;
filename.size = 20;
ge(element).appendChild(filename);
var savefile = ce("button");
savefile.innerHTML = ' Save ';
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(path.value);
editor.loadUrl(path.value);
path.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], path.value);
requests.add("POST", "/edit", formData, httpPostProcessRequest);
var uploadPath = ge("upload-path");
uploadPath.value = "/";
var uploadSelect = ge("upload-select");
uploadSelect.value = "";
};
input.onchange = function (e) {
if (input.files.length === 0) return;
var filename = input.files[0].name;
var ext = /(?:\.([^.]+))?$/.exec(filename)[1];
var name = /(.*)\.[^.]+$/.exec(filename)[1];
if (typeof name !== undefined) {
filename = name;
}
path.value = "/" + filename + "." + ext;
};
}
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) {
var edfname = ge("editor-filename");
edfname.value = path;
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 = name;
var label = ce("span");
label.innerHTML = name;
leaf.appendChild(label);
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 addList(parent, path, items) {
sortByKey(items, 'name');
var list = ce("ul");
parent.appendChild(list);
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));
}
}
function isTextFile(path) {
var ext = /(?:\.([^.]+))?$/.exec(path)[1];
if (typeof ext !== undefined) {
switch (ext) {
case "cnv":
case "txt":
case "htm":
case "html":
case "js":
case "css":
case "xml":
case "json":
case "conf":
case "ini":
return true;
}
}
return false;
}
function isImageFile(path) {
var ext = /(?:\.([^.]+))?$/.exec(path)[1];
if (typeof ext !== undefined) {
switch (ext) {
case "png":
case "jpg":
case "jpeg":
case "gif":
case "bmp":
return true;
}
}
return false;
}
this.refreshPath = function (path) {
treeRoot.removeChild(treeRoot.childNodes[0]);
httpGet(treeRoot, "/");
};
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 "cnv": lang = "plain"; break;
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 "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) {
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 = "/dev_conf.txt";
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>

Binary file not shown.

View File

@@ -23,12 +23,6 @@
"action": "/?set.device",
"class": "btn btn-block btn-default"
},
{
"type": "link",
"title": "Список других устройств в сети",
"action": "/?set.udp",
"class": "btn btn-block btn-default"
},
{
"type": "link",
"title": "Конфигурация WIFI",

View File

@@ -0,0 +1 @@
0;analog-adc;id;fillgauge;Сенсоры;Аналоговый;order;gol;map[0,1024,0,100];c[1]

View File

@@ -0,0 +1 @@
0;bme280-hum;id;anydataHum;Сенсоры;Влажность;order;addr[0x76];c[1]

View File

@@ -0,0 +1 @@
0;bme280-press;id;anydataPress;Сенсоры;Давление;order;addr[0x76];c[1]

View File

@@ -0,0 +1 @@
0;bme280-temp;id;anydataTemp;Сенсоры;Температура;order;addr[0x76];c[1]

View File

@@ -0,0 +1 @@
0;bmp280-press;id;anydataPress;Сенсоры;Давление;order;addr[0x76];c[1]

View File

@@ -0,0 +1 @@
0;bmp280-temp;id;anydataTemp;Сенсоры;Температура;order;addr[0x76];c[1]

1
data/items/button-in.txt Normal file
View File

@@ -0,0 +1 @@
0;button-in;id;toggle;Кнопки;Освещение;order;pin;db[20]

View File

@@ -0,0 +1 @@
0;button-out;id;toggle;Кнопки;Освещение;order;pin;inv[1];st[1]

View File

@@ -0,0 +1 @@
0;button-out;id;toggleSunMoon;Кнопки;Освещение;order;st[0]

View File

@@ -0,0 +1 @@
0;button-out;id;toggle;Кнопки;Освещение;order;pin;st[0]

View File

@@ -0,0 +1 @@
0;dallas-temp;id;anydataTemp;Сенсоры;Температура;order;sal;c[1]

1
data/items/dht11-hum.txt Normal file
View File

@@ -0,0 +1 @@
0;dht-hum;id;anydataHum;Сенсоры;Влажность;order;thd;type[dht11];c[1]

View File

@@ -0,0 +1 @@
0;dht-temp;id;anydataTemp;Сенсоры;Температура;order;thd;type[dht11];c[1]

1
data/items/dht22-hum.txt Normal file
View File

@@ -0,0 +1 @@
0;dht-hum;id;anydataHum;Сенсоры;Влажность;order;thd;type[dht22];c[1]

View File

@@ -0,0 +1 @@
0;dht-temp;id;anydataTemp;Сенсоры;Температура;order;thd;type[dht22];c[1]

View File

@@ -0,0 +1 @@
0;input-digit;id;inputDigit;Ввод;Введите#цифру;order;st[60]

View File

@@ -0,0 +1 @@
0;input-time;id;inputTime;Ввод;Введите#время;order;st[10-00-00]

1
data/items/modbus.txt Normal file
View File

@@ -0,0 +1 @@
0;modbus;id;anydata;Modbus;Регистр;order;addr[1];reg[0];c[1]

View File

@@ -0,0 +1 @@
0;output-text;id;anydata;Вывод;Сигнализация;order;st[Обнаружено#движение]

1
data/items/pwm-out.txt Normal file
View File

@@ -0,0 +1 @@
0;pwm-out;id;range;Ползунки;Яркость;order;pin;st[500]

View File

@@ -0,0 +1 @@
0;ultrasonic-cm;id;anydata;Сенсоры;Расстояние;order;cin;map[0,500,0,100];c[1]

Binary file not shown.

Binary file not shown.

1
data/s.conf.csv Normal file
View File

@@ -0,0 +1 @@
Тип элемента;Id;Виджет;Имя вкладки;Имя виджета;Позиция виджета
1 Тип элемента Id Виджет Имя вкладки Имя виджета Позиция виджета

1
data/s.scen.txt Normal file
View File

@@ -0,0 +1 @@
//

View File

@@ -1,142 +1,171 @@
{
"configs": [
"/config.setup.json",
"/config.option.json",
"/config.live.json",
"/lang/lang.ru.json"
],
"class": "col-sm-offset-1 col-sm-10",
"content": [
{
"type": "h5",
"title": "{{name}}",
"class": "alert-default"
},
{
"type": "link",
"title": "{{ButMainPage}}",
"action": "/",
"class": "btn btn-block btn-default"
},
{
"type": "hr"
},
{
"type": "h4",
"title": "Device ID: {{chipID}}"
},
{
"type": "h4",
"title": "IP address: {{ip}}"
},
{
"type": "h4",
"title": "Time: {{time}}"
},
{
"type": "h4",
"title": "Uptime: {{uptime}}"
},
{
"type": "h4",
"title": "Build version: {{firmware_version}}"
},
{
"type": "h4",
"title": "LittleFS version: 2.3.5"
},
{
"type": "hr"
},
{
"type": "dropdown",
"name": "help-url",
"class": "btn btn-default",
"style": "display:inline",
"title": {
"#": "{{SetDevPreset}}<span class=\"caret\"></span>",
"/set?preset=001": "1.Вкл. выкл. локального реле",
"/set?preset=002": "2.Вкл. выкл. локального реле в определенное время",
"/set?preset=003": "3.Вкл. выкл. локального реле на определенный период времени",
"/set?preset=004": "4.Вкл. выкл. нескольких локальных реле кнопкой в приложении",
"/set?preset=005": "5.Вкл. выкл. локального реле физической кнопкой и кнопкой в приложении параллельно (для выключателя света)",
"/set?preset=006": "6.Вкл. выкл. нескольких удаленных реле кнопкой в приложении (нужно указать Device ID)",
"/set?preset=007": "7.Вкл. выкл. нескольких удаленных реле физической кнопкой (нужно указать Device ID)",
"/set?preset=008": "8.Широтно импульсная модуляция",
"/set?preset=009": "9.Сенсор DHT11 (темп, влажность) и логгирование",
"/set?preset=010": "10.Сенсор DHT22, DHT33, DHT44, AM2302, RHT03 (темп, влажность) и логгирование",
"/set?preset=011": "11.Аналоговый сенсор и логгирование",
"/set?preset=012": "12.Cенсор bmp280 (темп, давление) и логгирование",
"/set?preset=013": "13.Cенсор bme280 (темп, давление, влажность, высота) и логгирование",
"/set?preset=014": "14.Сенсор DS18B20 (темп) и логгирование",
"/set?preset=015": "15.Термостат на DS18B20 с переключением в ручной режим и логгированием",
"/set?preset=016": "16.Котроль уровня в баке (датчик расстояния) на сенсорах: JSN-SR04T, HC-SR04, HY-SRF05 и логгирование",
"/set?preset=017": "17.Датчик движения включающий свет",
"/set?preset=018": "18.Охранный датчик движения",
"/set?preset=019": "19.Система управления шаговыми двигателями на основе драйвера A4988 (открытие закрытие штор)",
"/set?preset=020": "20.Система управления сервоприводами",
"/set?preset=021": "21.Модуль uart (serial). Двухстороняя связь с устройством через uart. Получение данных и отправка команд",
"/set?preset=100": "22.Настройки по умолчанию"
}
},
{
"type": "h2",
"title": "{{SetDevConf}}"
},
{
"type": "file",
"state": "dev_conf.txt",
"style": "width:100%;height:350px",
"title": "Сохранить",
"action": "/set?devinit",
"class": "btn btn-block btn-default"
},
{
"type": "h2",
"title": "Сценарии"
},
{
"type": "checkbox",
"name": "scen",
"title": "Включить сценарии",
"action": "/set?scen=[[scen]]",
"state": "{{scen}}"
},
{
"type": "file",
"state": "dev_scen.txt",
"style": "width:100%;height:350px",
"title": "Сохранить",
"action": "/set?sceninit",
"class": "btn btn-block btn-default"
},
{
"type": "link",
"title": "Инструкция к системе автоматизации",
"action": "https://github.com/DmitryBorisenko33/esp32-esp8266_iot-manager_modules_firmware/wiki/Instruction",
"class": "btn btn-block btn-default"
},
{
"type": "link",
"title": "Очистить логи сенсоров",
"action": "/set?cleanlog",
"class": "btn btn-block btn-default"
},
{
"type": "hr"
},
{
"type": "h3",
"name": "my-block",
"style": "position:fixed;top:50%;left:50%;width:400px;margin-left:-200px;text-align:center;",
"class": "hidden"
},
{
"type": "button",
"title": "Обновить прошивку устройства",
"action": "/check",
"response": "[[my-block]]",
"class": "btn btn-block btn-default"
}
]
"configs": [
"/config.setup.json",
"/config.option.json",
"/config.live.json",
"/lang/lang.ru.json"
],
"class": "col-sm-offset-1 col-sm-10",
"content": [
{
"type": "h5",
"title": "{{name}}",
"class": "alert-default"
},
{
"type": "link",
"title": "{{ButMainPage}}",
"action": "/",
"class": "btn btn-block btn-default"
},
{
"type": "hr"
},
{
"type": "h4",
"title": "Device ID: {{chipID}}"
},
{
"type": "h4",
"title": "IP address: {{ip}}"
},
{
"type": "h4",
"title": "Time: {{time}}"
},
{
"type": "h4",
"title": "Uptime: {{uptime}}"
},
{
"type": "h4",
"title": "Build version: {{firmware_version}}"
},
{
"type": "h4",
"title": "LittleFS version: 257"
},
{
"type": "hr"
},
{
"type": "dropdown",
"name": "help-url",
"class": "btn btn-default",
"style": "display:inline",
"title": {
"#": "Выберите элемент из списка<span class=\"caret\"></span>",
"/set?addItem=button-out.pin": "1.Кнопка управляющая пином",
"/set?addItem=button-out.npin": "2.Кнопка виртуальная",
"/set?addItem=button-in": "4.Кнопка физическая",
"/set?addItem=pwm-out": "3.Широтно импульсная модуляция pwm",
"/set?addItem=input-digit": "5.Окно ввода цифровых значений",
"/set?addItem=input-time": "6.Окно ввода времени",
"/set?addItem=output-text": "7.Окно вывода любого текста, предупреждения, цифры",
"/set?addItem=analog-adc": "8.Датчик аналоговый, чтение аналогового входа",
"/set?addItem=dallas-temp": "9.Датчик температуры ds18b20",
"/set?addItem=ultrasonic-cm": "10.Датчик расстояния ультрозвуковой JSN-SR04T, HC-SR04, HY-SRF05",
"/set?addItem=dht11-temp": "11.Датчик температуры DHT11",
"/set?addItem=dht11-hum": "12.Датчик влажности DHT11",
"/set?addItem=dht22-temp": "13.Датчик температуры DHT22, DHT33, DHT44, AM2302, RHT03",
"/set?addItem=dht22-hum": "14.Датчик влажности DHT22, DHT33, DHT44, AM2302, RHT03",
"/set?addItem=bme280-temp": "15.Датчик температуры bme280",
"/set?addItem=bme280-hum": "16.Датчик влажности bme280",
"/set?addItem=bme280-press": "17.Датчик давления bme280",
"/set?addItem=bmp280-temp": "18.Датчик температуры bmp280",
"/set?addItem=bmp280-press": "19.Датчик давления bmp280",
"/set?addItem=modbus": "20.Прочитать регистр modbus устройства"
}
},
{
"type": "hr"
},
{
"type": "csv",
"title": [
"checkbox",
"html",
"text",
"text",
"text",
"text",
"text"
],
"state": "s.conf.csv",
"style": "width:100%;",
"action": "/set?saveItems",
"class": "btn btn-block btn-default"
},
{
"type": "hr"
},
{
"type": "link",
"title": "Удалить выбранные элементы",
"action": "javascript:{send_request(this,'/set?delChoosingItems');setTimeout(function(){location.href='/?set.device' ; }, 1000);}",
"class": "btn btn-block btn-default"
},
{
"type": "link",
"title": "Удалить все",
"action": "/set?delAllItems",
"class": "btn btn-block btn-default"
},
{
"type": "h2",
"title": "Сценарии"
},
{
"type": "checkbox",
"name": "scen",
"title": "Включить сценарии",
"action": "/set?scen=[[scen]]",
"state": "{{scen}}"
},
{
"type": "file",
"state": "s.scen.txt",
"style": "width:100%;height:350px",
"title": "Сохранить",
"action": "/set?sceninit",
"class": "btn btn-block btn-default"
},
{
"type": "hr"
},
{
"type": "link",
"title": "Ручная настройка",
"action": "/?set.manual",
"class": "btn btn-block btn-default"
},
{
"type": "link",
"title": "Инструкция к системе автоматизации",
"action": "https://github.com/IoTManagerProject/IoTManager/wiki",
"class": "btn btn-block btn-default"
},
{
"type": "link",
"title": "Очистить логи сенсоров",
"action": "/set?cleanlog",
"class": "btn btn-block btn-default"
},
{
"type": "hr"
},
{
"type": "h3",
"name": "my-block",
"style": "position:fixed;top:50%;left:50%;width:400px;margin-left:-200px;text-align:center;",
"class": "hidden"
},
{
"type": "button",
"title": "Обновить прошивку устройства",
"action": "/check",
"response": "[[my-block]]",
"class": "btn btn-block btn-default"
}
]
}

38
data/set.manual.json Normal file
View File

@@ -0,0 +1,38 @@
{
"configs": [
"/config.setup.json",
"/config.option.json",
"/config.live.json",
"/lang/lang.ru.json"
],
"class": "col-sm-offset-1 col-sm-10",
"content": [
{
"type": "h5",
"title": "{{name}}",
"class": "alert-default"
},
{
"type": "link",
"title": "{{ButMainPage}}",
"action": "/",
"class": "btn btn-block btn-default"
},
{
"type": "file",
"state": "s.conf.csv",
"style": "width:100%;height:350px",
"title": "Сохранить",
"action": "/set?saveItems",
"class": "btn btn-block btn-default"
},
{
"type": "file",
"state": "s.scen.txt",
"style": "width:100%;height:350px",
"title": "Сохранить",
"action": "/set?sceninit",
"class": "btn btn-block btn-default"
}
]
}

6
data/widgets/alarm.json Normal file
View File

@@ -0,0 +1,6 @@
{
"widget": "anydata",
"icon": "body",
"color": "red",
"descrColor": "red"
}

View File

@@ -0,0 +1,5 @@
{
"widget": "anydata",
"after": "%",
"icon": "water"
}

View File

@@ -0,0 +1,5 @@
{
"widget": "anydata",
"after": "mm",
"icon": "speedometer"
}

View File

@@ -0,0 +1,5 @@
{
"widget": "anydata",
"after": "°С",
"icon": "thermometer"
}

View File

@@ -0,0 +1,5 @@
{
"widget": "toggle",
"icon": "sunny",
"iconOff": "moon"
}

566
doc/1.txt Normal file
View File

@@ -0,0 +1,566 @@
***
![](https://github.com/DmitryBorisenko33/esp32-esp8266_iot-manager_modules_firmware/blob/master/pictures/1.png?raw=true)
## Возможности
- Объединение различных по типу и назначению устройств: управление, получение данных, и настройка параметров - всё в одном приложении
- Взаимодействие с устройствами осуществляется через "облачный" сервис с использованием протокола mqtt, позволит контролировать их из любой точки Мира (при наличии доступа в Интернет)
- Поддержка нескольких профилей и их переключение "на лету", дает возможность объединить устройства в группы
Настройка (после "прошивки") производится через веб-интерфейс, чтобы получить к нему доступ необходимо соединиться с WiFi AP устройства и набрать в адресной строке браузера http://192.168.4.1.
Далее выбрать типовой шаблон автоматизации, произвести настройку под свои требования и задачи.
Основные разделы интерфейса: конфигурация и сценарии.
В окне конфигурации задаются "объекты", "элементы управления" устройства (dashboard) - им устройство будет представлено в приложении компаньоне проекта. В окне сценариев задаются реакции на события и изменения в параметрах работы системы.
***
![](https://github.com/DmitryBorisenko33/esp32-esp8266_iot-manager_modules_firmware/blob/master/pictures/1.png?raw=true)
## Команды, назначение и применение
Команды служат для настройки и управления устройством и его взаимодействия
**`buttonSet 1 1`** Изменит состояние "кнопки" №1, установит его в значение 1
**`pinSet 13 0`** Установит GPIO 13 состояние 0
**`pinChange 13`** Состояние GPIO 13 будет изменено на противоположное
**`pwmSet 1 500`** Настройка pwm №1 будет использовано значение 500
**`timeSet 1 08-00-00`** Установит для элемента ввода времени - inputTime значение 08:00:00
**`digitSet 1 56`** Элемент №1 (для цифровых параметров) отобразит число 56
**`stepperSet 1 100 1`** Шаговый двигатель №1 - вращение 100 "шагов" по часовой стрелке (для движения в обратную сторону используются отрицательные значения параметра)
**`servoSet 1 180`** Сервопривод №1 принять положение 180°
**`timerStart 1 60 sec`** Установить для таймера №1 обратный отсчёт в 60 секунд
**`timerStop 1`** Остановить таймер №1
**`textSet 1 Привет`** Установить для элемента текстовое поле №1 - "привет"
**`push Внимание Протечка`** Отправить push-уведомление с темой "внимание" и содержанием "протечка"
**`firmwareUpdate`** Обновить прошивку устройства "по воздуху"
**`firmwareVersion Версия прошивки Системные 1`** Узнать версию прошивки устройстве
## Сценарии
Элементарный блок в сценарии состоит из набора команд и триггера - условия для их выполнения
**temp > 60**
digitSet 1 60
stepperSet 1 100 1
textSet 1 Перегрев
**end**
Условие: когда температура превысит 60°
Запустит: команда шаговому двигателю, в приложение отправить сообщение и цифровое значение температуры.
В сценарии может быть несколько блоков, при необходимости из приложения есть возможность "выключать" часть из них.
Неактивные блоки сценария будут проигнорированы.
Для взаимодействия устройств между собой предусмотрены команды mqtt и http
**temp > 60**
mqtt 154348-134 digitSet_1_56
mqtt 154348-136 stepperSet _1_100_1
http 192.168.1.10 textSet_1_Перегрев
**end**
***
![](https://github.com/DmitryBorisenko33/esp32-esp8266_iot-manager_modules_firmware/blob/master/pictures/1.png?raw=true)
## 1.1 Объект "кнопка"
(эти строки мы пишем в "конфигурации устройства")
### a) кнопка управляющая выходом (пином). Пины нумеруются по системе нумирации gpio для esp контроллеров.
`button 1 13 кухня освещение 0 1`
**"button"** это объект создающий кнопку в приложении
**"1"** это номер этой кнопки (необходимый для ее аутентификации)
**"13"** это номер пина которым будет управлять данная кнопка
**"кухня"** это название кнопки в приложении
**"освещение"** это название вкладки в приложении на которой появится данная кнопка
**"0"** это начальное состояние кнопки при старте модуля (выкд 0, вкл 1)
**"1"** это уникальный номер и номер сортировки данной кнопки. Этот номер должен быть уникален для каждого объекта
### б) виртуальная кнопка - кнопка реакцию на которую можно задать в сценариях:
`button 1 na запустить таймеры 0 1`
**"button"** это объект создающий кнопку в приложении
**"1"** это номер этой кнопки (необходимый для ее аутентификации)
**"na"** абривиатура not available означающая что эта кнопка виртуальная и что пин не установлен
**"запустить"** это название кнопки в приложении
**"таймеры"** это название вкладки в приложении на которой появится данная кнопка
**"0"** это начальное состояние кнопки при старте модуля (выкд 0, вкл 1)
**"1"** это уникальный номер и номер сортировки данной кнопки. Этот номер должен быть уникален для каждого объекта
### в) кнопка включающая и выключающая все сценарии:
`button 1 scenario запустить таймеры 0 1`
**"button"** это объект создающий кнопку в приложении
**"1"** это номер этой кнопки (необходимый для ее аутентификации)
**"scenario"** слово означающее что эта кнопка для управления сценариями
**"запустить"** это название кнопки в приложении
**"таймеры"** это название вкладки в приложении на которой появится данная кнопка
**"0"** это начальное состояние кнопки при старте модуля (выкд 0, вкл 1)
**"1"** это уникальный номер и номер сортировки данной кнопки. Этот номер должен быть уникален для каждого объекта
### г) кнопка включающая выключающая определенные блоки сценариев:
`button 1 line1,line3, Включить#отправку#push Оповещение 0 1`
**"button"** это объект создающий кнопку в приложении
**"1"** это номер этой кнопки (необходимый для ее аутентификации)
**"line1,line3,"** это блоки сценариев нумирация сверху вниз. Блоком считается выражение от начала до слова end
**"Включить#отправку#push"** это название кнопки в приложении
**"Оповещение"** это название вкладки в приложении на которой появится данная кнопка
**"0"** это начальное состояние кнопки при старте модуля (выкд 0, вкл 1)
**"1"** это уникальный номер и номер сортировки данной кнопки. Этот номер должен быть уникален для каждого объекта
## 1.2 Команды управления объектом "кнопка"
(эти строки мы пишем в "сценариях")
### а) Команда включения выключения кнопки по ее номеру
`buttonSet 1 1`
**"buttonSet"** команда управления объектом button
**"1"** номер кнопки которой будем управлять
**"1"** состояние включено, 0 - выключено
### б) Команда изменения состояния кнопки на противоположное
`buttonChange 1`
**"buttonChange"** команда управления объектом button
**"1"** номер кнопки которой будем управлять
## 1.3 Вызов событий объектом "кнопока"
(эти строки мы пишем в "сценариях")
объект button может быть равен либо 0 либо 1
`button1 = 1`
`button2 = 0`
Пример использования:
`button1 = 1`
`buttonSet 2 1`
`buttonSet 3 0`
`end`
***
![](https://github.com/DmitryBorisenko33/esp32-esp8266_iot-manager_modules_firmware/blob/master/pictures/1.png?raw=true)
## 2.1 Объект "физическая кнопка"
`switch 1 0 10`
**switch** это объект создающий физическую кнопку
**1** номер кнопки
**0** пин кнопки (при подключении необходим подтягивающий резистор)
**10** задержка для избавления от дребезга с мили секундах
## 2.2 Вызов событий объектом "физическая кнопка"
`switch1` может быть равна нулю или единицы, ноль - событие отбрасывания кнопки, единица - событие нажатия
`switch1 = 1`
`buttonChange 1`
`end`
***
![](https://github.com/DmitryBorisenko33/esp32-esp8266_iot-manager_modules_firmware/blob/master/pictures/1.png?raw=true)
## 3.1 Объект "широтноимпульсная модуляция"
`pwm 1 12 яркость освещение 1023 1`
**"pwm"** это объект создающий управление шим в приложении в виде ползунка
**"1"** это номер этого объекта
**"12"** это номер пина на котором будет генерироваться шим заданной в приложении величены
**"Яркость"** это название кнопки в приложении
**"Оповещение"** это название вкладки в приложении на которой появится данная кнопка
**"1023"** это начальное значение шим сигнала и ползунка (изменяется от 0 до 1023)
**"1"** это уникальный номер и номер сортировки данной кнопки. Этот номер должен быть уникален для каждого объекта
## 3.2 Команда управления объектом "широтноимпульсная модуляция"
`pwmSet 1 500`
**"pwmSet"** команда управления объектом
**"1"** номер объекта, которым будем управлять
**"500"** значение которое установится после выполнения команды (от 0 до 1023)
***
![](https://github.com/DmitryBorisenko33/esp32-esp8266_iot-manager_modules_firmware/blob/master/pictures/1.png?raw=true)
## 4.1 Объект "окно ввода времени"
`inputTime time1 Во#сколько#включить? Таймеры 20-30-00 1`
**inputTime** это объект создающий окно ввода в приложении
**time1** переменная в которую будет записано время введенное в окно
**Во#сколько#включить?** это название окна в приложении
**Таймеры** это название вкладки в приложении
**20-30-00** начальное значение времени после загрузки устройства
**1** это уникальный номер и номер сортировки. Этот номер должен быть уникален для каждого объекта
## 4.2 Управление объектом "окно ввода времени"
`timeSet 1 08-00-00`
**"timeSet"** команда управления объектом
**"1"** номер объекта, которым будем управлять в данном случае окном ввода с `time1`
**"08-00-00"** время которое хотим установить
В окно ввода можно вводить время в приложении но если необходимо изменить время автоматически
по какому нибудь событию то можно использовать команду выше - **timeSet**.
## 4.3 Вызов событий объектом "окно ввода времени"
`timenow = time1`
`buttonSet 1 1`
`end`
`timenow` всегда хранит в себе текущее время, и поэтому исходя из данного сценария кнопка номер 1 включится в то время которое будет введено в окно ввода `time1`
***
![](https://github.com/DmitryBorisenko33/esp32-esp8266_iot-manager_modules_firmware/blob/master/pictures/1.png?raw=true)
## 5.1 Объект "окно ввода цифры"
`inputDigit digit1 Через#сколько#секунд#выключить? Таймеры 5 2`
**inputDigit** это объект создающий окно ввода в приложении
**digit1** переменная в которую будет записана цифра, введенная в окно
**Через#сколько#секунд#выключить?** это название окна в приложении
**Таймеры** это название вкладки в приложении
**5** цифра по умолчанию, после загрузки модуля
**2** это уникальный номер и номер сортировки. Этот номер должен быть уникален для каждого объекта
## 5.2 Управление объектом "окно ввода цифры":
`digitSet 1 56`
**"digitSet"** команда управления объектом
**"1"** номер объекта, которым будем управлять в данном случае окном ввода с `digit1`
**"56"** цифра которую хотим установить
В окно ввода можно вводить цифры в приложении, но если необходимо изменить цифру автоматически
по какому нибудь событию, то можно использовать команду выше - **digitSet**.
## 5.3 Вызов событий объектом "окно ввода цифры"
`dallas > digit1`
`buttonSet 1 0`
`end`
`button1 = 1`
`timerStart 1 digit1 sec`
`end`
***
![](https://github.com/DmitryBorisenko33/esp32-esp8266_iot-manager_modules_firmware/blob/master/pictures/1.png?raw=true)
## 6.1 Объект "dallas" (сенсор температуры ds18b20)
`dallas temp1 2 123456 Водонагреватель,#t°C Термостат any-data 1`
**dallas** это объект чтения датчика температуры
**2** пин датчика температуры
**Водонагреватель,#t°C** это название виджета в приложении
**Датчики** название вкладки в приложении
**any-data** или **progress-round** или **progress-line** три разных варианта виджета отображения
**1** это уникальный номер и номер сортировки. Этот номер должен быть уникален для каждого объекта
## 6.2 Вызов событий объектом "dallas"
В сценариях dallas можно сравнивать с переменной окна ввода `digit1` (>,<,>=,<=,=):
`dallas > digit1`
`buttonSet 1 0`
`end`
Или можно сравнивать с постоянной цифрой (>,<,>=,<=,=):
`dallas > 60`
`buttonSet 1 0`
`end`
***
![](https://github.com/DmitryBorisenko33/esp32-esp8266_iot-manager_modules_firmware/blob/master/pictures/1.png?raw=true)
## 7.1 Объект "analog" (аналоговый вход контроллера)
`analog adc 0 Аналоговый#вход,#% Датчики progress-round 310 620 1 100 1`
**analog** это объект чтения аналогового входа
**adc** это переменная
**0** пин аналогового входа (для esp8266 всегда 0, для esp32 пока что не доделал читаться будет всегда пин 34)
**Аналоговый#вход,#%** это название виджета в приложении
**Датчики** название вкладки в приложении
**any-data** или **progress-round** или **progress-line** три разных варианта виджета отображения
**310** начальная величина читаемого диапазона
**620** конечная величина читаемого диапазона
**1** начальная величина выводимого диапазона
**100** конечная величина выводимого диапазона
**1** это уникальный номер и номер сортировки. Этот номер должен быть уникален для каждого объекта
## 7.2 Вызов событий объектом "analog"
В сценариях analog можно сравнивать с переменной окна ввода `digit1` (>,<,>=,<=,=):
`analog > digit1`
`buttonSet 1 0`
`end`
Или можно сравнивать с постоянной цифрой (>,<,>=,<=,=):
`analog > 50`
`buttonSet 1 0`
`end`
***
![](https://github.com/DmitryBorisenko33/esp32-esp8266_iot-manager_modules_firmware/blob/master/pictures/1.png?raw=true)
## 8.1 Объект "level" (ультразвуковой дальномер JSN-SR04T, HC-SR04, HY-SRF05)
`level Вода#в#баке,#% Датчики any-data 125 20 1`
**level** это объект чтения датчика расстояния
**Вода#в#баке** это название виджета в приложении
**Датчики** название вкладки в приложении
**any-data** или **progress-round** или **progress-line** три разных варианта отображения виджета
**125** расстояние от датчика до дна бака в сантиметрах
**20** расстояние от датчика до поверхности воды, когда бак полный, в сантиметрах
**1** это уникальный номер и номер сортировки. Этот номер должен быть уникален для каждого объекта
Подключать дальномер нужно:
| | trig | echo |
| :-: | :-: | :-: |
| wemos | D5 | D6 |
| esp | 14 | 12 |
## 8.2 Вызов событий объектом "level"
В сценариях level можно сравнивать с переменной окна ввода `digit1` (>,<,>=,<=,=):
`level > digit1`
`buttonSet 1 0`
`end`
Или можно сравнивать с постоянной цифрой (>,<,>=,<=,=):
`level > 95`
`buttonSet 1 0`
`end`
***
![](https://github.com/DmitryBorisenko33/esp32-esp8266_iot-manager_modules_firmware/blob/master/pictures/1.png?raw=true)
## 9.1 Объект "dht" (Сенсоры DHT11, DHT22, DHT33, DHT44, AM2302, RHT03)
dhtT DHT11 2 Температура#DHT,#t°C Датчики any-data 1
dhtH DHT11 2 Влажность#DHT,#% Датчики any-data 2
dhtComfort Степень#комфорта: Датчики 3
dhtPerception Восприятие: Датчики 4
dhtDewpoint Точка#росы: Датчики 5
**dhtT** или **dhtH** температура или влажность
**DHT11** или **DHT22** чтение DHT11 или DHT22, DHT33, DHT44, AM2302, RHT03 соответственно
**2** пин датчика
**Температура#DHT,#t°C** это название виджета в приложении
**Датчики** название вкладки в приложении
**any-data** или **progress-round** или **progress-line** три разных варианта отображения виджета
**1** это уникальный номер и номер сортировки. Этот номер должен быть уникален для каждого объекта
## 9.2 Вызов событий объектом "dhtT" или "dhtH"
В сценариях "dhtT" или "dhtH" можно сравнивать с переменной окна ввода `digit1` (>,<,>=,<=,=):
`dhtT > digit1`
`buttonSet 1 0`
`end`
`dhtH > digit1`
`buttonSet 1 0`
`end`
Или можно сравнивать с постоянной цифрой (>,<,>=,<=,=):
`dhtT > 50`
`buttonSet 1 0`
`end`
`dhtH < 40`
`buttonSet 1 0`
`end`
***
![](https://github.com/DmitryBorisenko33/esp32-esp8266_iot-manager_modules_firmware/blob/master/pictures/1.png?raw=true)
## 10.1 Объект "stepper" (Драйвер шагового двигателя A4988)
stepper 1 12 4
stepper 2 13 5
**stepper** объект создающий шаговый двигатель
**1** номер шаговика
**12** номер пина количества шагов
**4** номер пина направления
## 10.2 управление объектом "stepper"
`stepperSet 1 200 1`
**stepperSet** команда управления шаговым двигателем
**1** номер шагового двигателя (их может быть не более двух)
**200** количество шагов (обратное направление отрицательное значение параметра)
**1** интервал между шагами (мс)
`button1 = 1`
`stepperSet 1 200 1`
`end`
`button1 = 0`
`stepperSet 1 -200 1`
`end`
***
![](https://github.com/DmitryBorisenko33/esp32-esp8266_iot-manager_modules_firmware/blob/master/pictures/1.png?raw=true)
## 11.1 Объект "обратный таймер"
Прежде чем читать этот раздел запустите пресет №3 на устройстве.
Нажав на кнопку "Выберите во что вы хотите превратить esp"
Можно использовать цифры из окон ввода:
`timerStart 1 digit1 sec`
Можно писать цифры прям в объект:
`timerStart 1 10 sec`
Можно установить часы минуты или секунды:
`timerStart 1 10 sec`
`timerStart 1 10 min`
`timerStart 1 10 hours`
Используем это объект в сценариях вот так:
`button1 = 1`
`timerStart 1 digit1 sec`
`end`
Смысл в том что при нажатии на кнопку один запуститься обратный отчет, на величину digit1 секунд. Если напишем например:
`dallas < 60`
`timerStart 1 digit1 sec`
`end`
то такой же отчет запустится когда значение температуры вырастит больше 60 градусов. Таким образом обратный отчет можно запустить реакцией на любое событие. Итак теперь обратный отчет запущен, обратный таймер уменьшается, и нам надо назначить действие на тот момент когда он обнулится. Для этого я придумал выражение: `timer1 = 0`
Используем его и в общем получаем вот такой сценарий:
`button1 = 1`
`timerStart 1 digit1 sec`
`end`
`timer1 = 0`
`buttonSet 1 0`
`end`
Когда таймер закончит отсчёт, кнопка станет "неактивной". Используйте преет №3, как пример подобного сценария
Например:
`dallas < 60`
`buttonSet 1 0`
`buttonSet 2 0`
`pwmSet 1 1023`
`mqtt 2653450020 buttonChange_1`
`mqtt 2653450020 pinSet_13_1`
`http 192.168.1.32 pinSet_14_1`
`end`
Вот что может произойти на разных устройствах по одному событию повышения температуры...
***
![](https://github.com/DmitryBorisenko33/esp32-esp8266_iot-manager_modules_firmware/blob/master/pictures/1.png?raw=true)
## 12 Журнал (лог) данных
`logging analog 1 100 slow Аналоговый#вход Датчики 7`
**logging** объект для логирования
**analog** или **dhtT** или **dhtH** какой сенсор будем логировать, можно указать любой
**1** период между точками в минутах
**100** количество точек (старые точки будут удаляться по мере добавления новых)
**slow** или **fast** метод выгрузки графика в приложение, slow - выгружает график по одной точке (меньше расходуется оперативка, лучше использовать для esp8266), fast - выгрузка графика сразу (больше расход оперативки, подходит для esp32)
**Аналоговый#вход** название графика в приложении
**Датчики** название вкладки в приложении
**7** это уникальный номер и номер сортировки. Этот номер должен быть уникален для каждого объекта
***
![](https://github.com/DmitryBorisenko33/esp32-esp8266_iot-manager_modules_firmware/blob/master/pictures/1.png?raw=true)
## 13 Взаимодействие устройств между собой
Устройства могут между собой обмениваться командами. Команды можно отправлять по http или по mqtt.
По событию на одном устройстве можно вызвать действие на другом. Например на esp01 стоит датчик температуры, реле стоит на esp02.
Настройки esp01:
`dhtT temp 2 dht11 Температура#DHT,#t°C Датчики any-data 1`
`temp < 40`
`http 192.168.10.25 buttonSet_1_1`
`end`
Настройки esp02:
`button 1 13 Включить#реле Реле 0 1`
И теперь когда температура датчика на esp01 станет меньше 40 градусов то на esp02 будет отправлена команда на включение кнопки: buttonSet_1_1
Если вы хотите отправить команду через mqtt то сценарий будет выглядеть следующим образом:
`temp < 40`
`mqtt 12343442-12413131 buttonSet_1_1`
`end`
где `12343442-12413131` id esp02 той на которую отправляем команду. Id можно взять в веб интерфейсе на странице конфигурация устройства. Или в списке устройств в сети.
Теперь рассмотрим вариант внешнего управления esp с помощью get запросов.
`http://192.168.88.239/cmd?command=buttonSet%201%201`
Разберем эту строку. Сама команда в ней выглядит вот так: buttonSet%201%201. `%20` заменяют пробел.
То есть что бы составить get запрос на изменение например pwm нужно:
Взять команду `pwmSet 1 500`
Заменить в ней пробелы на `%20` получится так: `pwmSet%201%20500`
И добавить ее в конец строки `http://192.168.88.239/cmd?command=` где указывается ip адрес устройства
В итоге получится http://192.168.88.239/cmd?command=pwmSet%201%20500

85
doc/2.txt Normal file
View File

@@ -0,0 +1,85 @@
# В этой инструкции будет описано как с esp отправлять email и push
# Часть 1. Привязать email и pushbullet к сайту pushingbox
### 1. Необходимо перейти на сайт: [pushingbox](https://www.pushingbox.com/)
### 2. Войти с помощью google
![](https://github.com/IoTManagerProject/Wiki/tree/master/pictures/push_instruction/Screenshot_1.png)
### 3. Перейти в мои сервисы и добавить новый сервис
![](https://github.com/IoTManagerProject/Wiki/tree/master/pictures/push_instruction/Screenshot_2.png)
### 4. Нас интересуют два сервиса email и pushbullet
![](https://github.com/IoTManagerProject/Wiki/tree/master/pictures/push_instruction/Screenshot_4%2B.png)
### 5. Выбираем сначало сервис для отправки email. В окно `Name of your email configuration` - вводим слово "email". В окно `Email address` - вводим ваш email адрес. жмем submit
![](https://github.com/IoTManagerProject/Wiki/tree/master/pictures/push_instruction/Screenshot_5.png)
manager_modules_firmware/blob/master/push_instruction/Screenshot_6.png)
### 6.1 Привязываем pushbullet. Переходим на сайт [pushbullet.com](https://www.pushbullet.com/)
### 6.2 Входим с гуглом или фейсбуком
### 6.3 Идем в настройки
![](https://github.com/IoTManagerProject/Wiki/tree/master/pictures/push_instruction/Screenshot_7.png)
### 6.4 Создаем токен
![](https://github.com/IoTManagerProject/Wiki/tree/master/pictures/push_instruction/Screenshot_8.png)
### 6.5 Идем опять в сервисы и теперь выбираем сервис pushbullet [pushingbox.com/services](https://www.pushingbox.com/services.php) нажимаем add service
### Берем токен, и вставляем его в окно Access token.
### Окно Device token (optional) оставляем пустым.
### В окно Name of your Pushbullet configuration пишем слово "push".
![](https://github.com/IoTManagerProject/Wiki/tree/master/pictures/push_instruction/Screenshot_6.png)
### 7. Теперь наш email и pushbullet привязаны к pushingbox. Далее можно скачать приложение pushbullet на телефон и войти с гуглом или фейсбуком сответственно с пунктом 6.3 этой инструкции
![](https://github.com/IoTManagerProject/Wiki/tree/master/pictures/push_instruction/Screenshot_9.png)
# Часть 2. Создание сценариев отправки email
### 8.1. Сценарий для отправки email. Заходим в My Scenarios:
![](https://github.com/IoTManagerProject/Wiki/tree/master/pictures/push_instruction/Screenshot_10.png)
### 8.2 Пишем слово email (это имя сценария отправки email) жмем add:
![](https://github.com/IoTManagerProject/Wiki/tree/master/pictures/push_instruction/Screenshot_12.png)
### 8.3 Нажимаем add an action
![](https://github.com/IoTManagerProject/Wiki/tree/master/pictures/push_instruction/Screenshot_14.png)
### 8.4 Выбираем наш email который мы зарегестрировали ранее и нажимаем Add an action with this service
![](https://github.com/IoTManagerProject/Wiki/tree/master/pictures/push_instruction/Screenshot_11.png)
### 8.5 Делаем все как на скриншоте и жмем submit
![](https://github.com/IoTManagerProject/Wiki/tree/master/pictures/push_instruction/Screenshot_15.png)
### 8.6 Возвращаемся на мои сценарии
![](https://github.com/IoTManagerProject/Wiki/tree/master/pictures/push_instruction/Screenshot_17.png)
### 8.7 Вставляем токен в веб интерфейс esp
![](https://github.com/IoTManagerProject/Wiki/tree/master/pictures/push_instruction/Screenshot_18.png)
# Часть 3. Создание сценариев отправки push
### 9.1. Сценарий для отправки push. Заходим в My Scenarios:
![](https://github.com/IoTManagerProject/Wiki/tree/master/pictures/push_instruction/Screenshot_10.png)
### 9.2 Пишем слово push (это имя сценария отправки email) жмем add:
![](https://github.com/IoTManagerProject/Wiki/tree/master/pictures/push_instruction/Screenshot_19.png)
### 9.3 Нажимаем add an action
![](https://github.com/IoTManagerProject/Wiki/tree/master/pictures/push_instruction/Screenshot_20.png)
### 9.4 Выбираем наш pushbullet который мы зарегестрировали ранее и нажимаем Add an action with this service
![](https://github.com/IoTManagerProject/Wiki/tree/master/pictures/push_instruction/Screenshot_11.png)
### 9.5 Делаем все как на скриншоте и жмем submit
![](https://github.com/IoTManagerProject/Wiki/tree/master/pictures/push_instruction/Screenshot_15.png)
### 9.6 Возвращаемся на мои сценарии
![](https://github.com/IoTManagerProject/Wiki/tree/master/pictures/push_instruction/Screenshot_21.png)
### 9.7 Вставляем токен в веб интерфейс esp
![](https://github.com/IoTManagerProject/Wiki/tree/master/pictures/push_instruction/Screenshot_18.png)
# Часть 4. Итог
При создании такой конфигурации как на картинке:
`button 1 na Отправить#push Push 0 1`
`button1 = 1`
`push внимание кнопка#нажата`
`end`
![](https://github.com/IoTManagerProject/Wiki/tree/master/pictures/push_instruction/Screenshot_22.png)
Если мы введем токен для email то будут приходить email
![](https://github.com/IoTManagerProject/Wiki/tree/master/pictures/push_instruction/Screenshot_17.png)
Если для push то будут приходить push в pushbullet
![](https://github.com/IoTManagerProject/Wiki/tree/master/pictures/push_instruction/Screenshot_21.png)
Способ описанный в данной инструкции более сложный в настройке но зато очень надежный.

32
doc/3.txt Normal file
View File

@@ -0,0 +1,32 @@
***
![](https://github.com/DmitryBorisenko33/esp32-esp8266_iot-manager_modules_firmware/blob/master/pictures/1.png?raw=true)
### 1. Скачать архив из [релизов](https://github.com/DmitryBorisenko33/esp32-esp8266_iot-manager_modules_firmware/releases) или из закрепленного сообщения группы телеграм с последней версией прошивки
***
![](https://github.com/DmitryBorisenko33/esp32-esp8266_iot-manager_modules_firmware/blob/master/pictures/1.png?raw=true)
### 2. Для ESP8266 c 4 и больше мб памяти (все сделать как на скриншотах)
![](https://github.com/DmitryBorisenko33/esp32-esp8266_iot-manager_modules_firmware/blob/master/pictures/esp8266_1.png)
![](https://github.com/DmitryBorisenko33/esp32-esp8266_iot-manager_modules_firmware/blob/master/pictures/esp8266_2.png)
***
![](https://github.com/DmitryBorisenko33/esp32-esp8266_iot-manager_modules_firmware/blob/master/pictures/1.png?raw=true)
### 2. Для ESP8266 c 1 мб памяти (все сделать как на скриншотах)
![](https://github.com/DmitryBorisenko33/esp32-esp8266_iot-manager_modules_firmware/blob/master/pictures/esp8266_1mb_1.png)
![](https://github.com/DmitryBorisenko33/esp32-esp8266_iot-manager_modules_firmware/blob/master/pictures/esp8266_1mb_2.png)
***
![](https://github.com/DmitryBorisenko33/esp32-esp8266_iot-manager_modules_firmware/blob/master/pictures/1.png?raw=true)
### 2. Для ESP32 (все сделать как на скриншотах)
![](https://github.com/DmitryBorisenko33/esp32-esp8266_iot-manager_modules_firmware/blob/master/pictures/esp32_1.png)
![](https://github.com/DmitryBorisenko33/esp32-esp8266_iot-manager_modules_firmware/blob/master/pictures/esp32_2.png)

BIN
doc/orders.xlsm Normal file

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 381 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 76 KiB

8
include/BufferExecute.h Normal file
View File

@@ -0,0 +1,8 @@
#pragma once
#include <Arduino.h>
extern void loopCmdAdd(const String &cmdStr);
extern void fileCmdExecute(const String &filename);
extern void csvCmdExecute(String &cmdStr);
extern void spaceCmdExecute(String &cmdStr);
extern void loopCmdExecute();

4
include/Bus.h Normal file
View File

@@ -0,0 +1,4 @@
#pragma once
#include <Arduino.h>
void busInit();
String i2c_scan();

View File

@@ -1,56 +0,0 @@
#pragma once
#include <Arduino.h>
class BusScanner {
public:
BusScanner(const char* tag, String& out, size_t tries) : _found{0},
_tries{tries},
_out{&out} {
_tag = new char(strlen(tag) + 1);
strcpy(_tag, tag);
}
void scan() {
init();
bool res;
do {
res = syncScan();
} while (!res && --_tries);
if (!_found) {
addResult("не найдено");
}
}
const char* tag() {
return _tag;
}
protected:
virtual void init(){};
virtual boolean syncScan() = 0;
protected:
void addResult(const String& str) {
_out->concat(str);
}
void addResult(uint8_t addr, boolean last = true) {
_found++;
String str = "0x";
if (addr < 16) {
str += "0";
}
str += String(addr, HEX);
str += !last ? ", " : ", ";
addResult(str);
};
private:
char* _tag;
size_t _found;
size_t _tries;
String* _out;
};

View File

@@ -1,18 +0,0 @@
#pragma once
#include "Bus/BusScanner.h"
#include "Bus/I2CScanner.h"
#include "Consts.h"
#include "Utils/JsonUtils.h"
class BusScannerFactory {
public:
static BusScanner* get(String& config, BusScanner_t type, String& str) {
switch (type) {
case BS_I2C:
return new I2CScanner(str);
default:
return nullptr;
}
}
};

View File

@@ -1,12 +0,0 @@
#pragma once
#include "Bus/BusScanner.h"
class I2CScanner : public BusScanner {
public:
I2CScanner(String& out);
protected:
virtual void init() override;
virtual boolean syncScan() override;
};

View File

@@ -0,0 +1,26 @@
#pragma once
#include <Arduino.h>
#include <stdint.h>
#include <functional>
// Декларируем тип - сигнатуру метода , который мы готовы принять в данном случае это
// должен быть метод без результата и без параметров.
// Новый тип мы называем AsynсActionCb - хотя можешь назвать вообще как нравиться а что значит callBack
typedef std::function<void()> AsyncActionCb; //метод без результата и параметров
typedef std::function<bool(const String)> AsyncParamActionCb; //метод без результата и параметров
class CallBackTest {
private:
long count;
AsyncActionCb _cb;
AsyncParamActionCb _pcb;
public:
CallBackTest();
void loop();
void setCallback(AsyncActionCb cb);
void setCallback(AsyncParamActionCb pcb);
};
//extern CallBackTest* CB;

View File

@@ -3,6 +3,7 @@
#include <Arduino.h>
#include "Global.h"
#include "Utils/JsonUtils.h"
class LineParsing {
protected:
@@ -13,12 +14,14 @@ class LineParsing {
String _order;
String _addr;
String _reg;
String _pin;
String _map;
String _c;
String _inv;
String _state;
String _db;
String _type;
public:
LineParsing() :
@@ -29,18 +32,20 @@ class LineParsing {
_descr{""},
_order{""},
_addr{""},
_reg{""},
_pin{""},
_map{""},
_c{""},
_inv{""},
_state{""},
_db{""}
_db{""},
_type{""}
{};
void update() {
//String order = sCmd.order();
//pm.info("create '" + order + "'");
//SerialPrint("I","module","create '" + order + "'");
for (int i = 1; i < 12; i++) {
if (i == 1) _key = sCmd.next();
if (i == 2) _file = sCmd.next();
@@ -49,7 +54,7 @@ class LineParsing {
if (i == 5) _order = sCmd.next();
}
for (int i = 1; i < 6; i++) {
for (int i = 1; i < 10; i++) {
String arg = sCmd.next();
if (arg != "") {
if (arg.indexOf("pin[") != -1) {
@@ -64,15 +69,33 @@ class LineParsing {
if (arg.indexOf("db[") != -1) {
_db = extractInner(arg);
}
if (arg.indexOf("map[") != -1) {
_map = extractInner(arg);
}
if (arg.indexOf("c[") != -1) {
_c = extractInner(arg);
}
if (arg.indexOf("type[") != -1) {
_type = extractInner(arg);
}
if (arg.indexOf("addr[") != -1) {
_addr = extractInner(arg);
}
if (arg.indexOf("reg[") != -1) {
_reg = extractInner(arg);
}
}
}
_page.replace("#", " ");
_descr.replace("#", " ");
_page.replace(".", " ");
_descr.replace(".", " ");
createWidgetClass(_descr, _page, _order, _file, _key);
}
//jsonWriteStr(configOptionJson, _key + "_pin", _pin);
String gkey() {
return _key;
}
@@ -89,14 +112,29 @@ class LineParsing {
return _order;
}
String gpin() {
return _pin;
return _pin; //
}
String ginv() {
return _inv;
return _inv; //
}
String gstate() {
return _state;
}
String gmap() {
return _map;
}
String gc() {
return _c;
}
String gtype() {
return _type;
}
String gaddr() {
return _addr;
}
String gregaddr() {
return _reg;
}
void clear() {
_key = "";
@@ -105,12 +143,14 @@ class LineParsing {
_descr = "";
_order = "";
_addr = "";
_reg = "";
_pin = "";
_map = "";
_c = "";
_inv = "";
_state = "";
_db = "";
_type = "";
}
String extractInnerDigit(String str) {
@@ -120,30 +160,30 @@ class LineParsing {
}
void createWidgetClass(String descr, String page, String order, String filename, String topic) {
String buf = "{}";
if (!loadWidgetClass(filename, buf)) {
return;
}
descr.replace("#", " ");
page.replace("#", " ");
if (filename != "na") {
String buf = "{}";
if (!loadWidgetClass(filename, buf)) {
return;
}
jsonWriteStr(buf, "page", page);
jsonWriteStr(buf, "order", order);
jsonWriteStr(buf, "descr", descr);
jsonWriteStr(buf, "topic", prex + "/" + topic);
jsonWriteStr(buf, "page", page);
jsonWriteStr(buf, "order", order);
jsonWriteStr(buf, "descr", descr);
jsonWriteStr(buf, "topic", prex + "/" + topic);
#ifdef LAYOUT_IN_RAM
all_widgets += widget + "\r\n";
all_widgets += widget + "\r\n";
#else
addFile("layout.txt", buf);
addFileLn("layout.txt", buf);
#endif
}
}
bool loadWidgetClass(const String& filename, String& buf) {
buf = readFile(getWidgetFileClass(filename), 2048);
bool res = !(buf == "Failed" || buf == "Large");
if (!res) {
//pm.error("on load" + filename);
//SerialPrint("[E]","module","on load" + filename);
}
return res;
}
@@ -151,4 +191,13 @@ class LineParsing {
const String getWidgetFileClass(const String& name) {
return "/widgets/" + name + ".json";
}
//String jsonWriteStr1(String& json, String name, String value) {
// DynamicJsonBuffer jsonBuffer;
// JsonObject& root = jsonBuffer.parseObject(json);
// root[name] = value;
// json = "";
// root.printTo(json);
// return json;
//}
};

Some files were not shown because too many files have changed in this diff Show More