Merge branch 'gpio-redesign'

This commit is contained in:
fvanroie 2021-05-20 15:41:29 +02:00
commit 03f891c740
144 changed files with 8679 additions and 4252 deletions

View File

@ -1,4 +1,4 @@
name: Build master branch
name: Build branch
on: [push, workflow_dispatch]

7
.gitignore vendored
View File

@ -5,13 +5,14 @@
.git
.pio
data/*
!data/edit.htm
!data/edit.htm.gz
src/user_setups/active/*
include/user_config_override.h
src/user_config_override.h
user_config_override.h
platformio_override.ini
user_setups/active/*
src/user_setups/active/*
test/config.yaml
build_output/*
build_output/firmware/*.bin
build_output/firmware/*.exe
@ -30,3 +31,5 @@ src/custom/*
.vscode/c_cpp_properties.json
.vscode/launch.json
*.bak
test/config.yaml

439
data/edit.htm Normal file
View File

@ -0,0 +1,439 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset='utf-8'>
<title>File 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: 700
}
.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 li,
.tvu ul {
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: 0 0
}
.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;
padding-right: 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
}
button.right {
float: right
}
input.number {
float: right;
width: 48px
}
</style>
<script>
function createFileUploader(e, t, n) {
var a = document.createElement("button");
a.innerHTML = "Main Menu", document.getElementById(e).appendChild(a);
var o, d = document.createElement("input");
d.type = "file", d.multiple = !1, d.name = "data", document.getElementById(e).appendChild(d);
var c = document.createElement("input");
c.id = "upload-path", c.type = "text", c.name = "path", c.defaultValue = "/", document.getElementById(e).appendChild(c);
var l = document.createElement("button");
l.innerHTML = "Upload", document.getElementById(e).appendChild(l);
var i = document.createElement("button");
i.innerHTML = "Create", document.getElementById(e).appendChild(i);
var s = document.createElement("button");
s.innerHTML = "Reload Pages", document.getElementById(e).appendChild(s), s.className = "right";
var r = document.createElement("button");
r.innerHTML = "Clear Pages", document.getElementById(e).appendChild(r), r.className = "right";
var m = document.createElement("input");
function u() {
4 == o.readyState && (200 != o.status ? alert("ERROR[" + o.status + "]: " + o.responseText) : t.refreshPath(c.value))
}
m.setAttribute("type", "number"), m.setAttribute("min", 1), m.setAttribute("max", 12), document.getElementById(e).appendChild(m), m.className = "number", i.onclick = function (e) {
-1 !== c.value.indexOf(".") && (function (e) {
(o = new XMLHttpRequest).onreadystatechange = u;
var t = new FormData;
t.append("path", e), o.open("PUT", "/edit"), o.send(t)
}(c.value), n.loadUrl(c.value))
}, l.onclick = function (e) {
if (0 !== d.files.length) {
(o = new XMLHttpRequest).onreadystatechange = u;
var t = new FormData;
t.append("data", d.files[0], c.value), o.open("POST", "/edit"), o.send(t)
}
}, d.onchange = function (e) {
if (0 !== d.files.length) {
var t = d.files[0].name,
n = /(?:.([^.]+))?$/.exec(t)[1],
a = /(.*).[^.]+$/.exec(t)[1];
void 0 !== typeof a && (t = a), void 0 !== typeof n && ("html" === n ? n = "htm" : "jpeg" === n && (n = "jpg"), t = t + "." + n), "/" === c.value || 0 === c.value.lastIndexOf("/") ? c.value = "/" + t : c.value = c.value.substring(0, c.value.lastIndexOf("/") + 1) + t
}
}, s.onclick = function (e) {
! function (e) {
(o = new XMLHttpRequest).onreadystatechange = u;
var t = new FormData;
t.append("load", e), o.open("PUT", "/edit"), o.send(t)
}(c.value)
}, r.onclick = function (e) {
! function (e) {
(o = new XMLHttpRequest).onreadystatechange = u;
var t = new FormData;
t.append("init", e), o.open("PUT", "/edit"), o.send(t)
}(c.value)
}, a.onclick = function (e) {
c.value, window.location.href = "/"
}, m.onchange = function (e) {
! function (e) {
(o = new XMLHttpRequest).onreadystatechange = u;
var t = new FormData;
t.append("page", e), o.open("PUT", "/edit"), o.send(t)
}(m.value)
}
}
function createTree(e, t) {
var n = document.getElementById("preview"),
a = document.createElement("div");
function o(e) {
document.getElementById("editor").style.display = "none", n.style.display = "block", n.innerHTML = '<img src="' + e + "?_cb=" + Date.now() + '" style="max-width:100%; max - height: 100 % ; margin: auto; display: block;" />'
}
function d(e, n) {
var d = document.createElement("ul");
e.appendChild(d);
var c = document.createElement("li");
d.appendChild(c), l(n) ? (c.innerHTML = "<span>Edit</span>", c.onclick = function (a) {
t.loadUrl(n), document.body.getElementsByClassName("cm").length > 0 && document.body.removeChild(e)
}) : i(n) && (c.innerHTML = "<span>Preview</span>", c.onclick = function (t) {
o(n), document.body.getElementsByClassName("cm").length > 0 && document.body.removeChild(e)
});
var r = document.createElement("li");
d.appendChild(r), r.innerHTML = "<span>Download</span>", r.onclick = function (t) {
! function (e) {
document.getElementById("download-frame").src = e + "?download=true"
}(n), document.body.getElementsByClassName("cm").length > 0 && document.body.removeChild(e)
};
var m = document.createElement("li");
d.appendChild(m), m.innerHTML = "<span>Delete</span>", m.onclick = function (t) {
! function (e) {
xmlHttp = new XMLHttpRequest, xmlHttp.onreadystatechange = function () {
4 == xmlHttp.readyState && (200 != xmlHttp.status ? alert("ERROR[" + xmlHttp.status + "]: " + xmlHttp.responseText) : (a.removeChild(a.childNodes[0]), s(a, "/")))
};
var t = new FormData;
t.append("path", e), xmlHttp.open("DELETE", "/edit"), xmlHttp.send(t)
}(n), document.body.getElementsByClassName("cm").length > 0 && document.body.removeChild(e)
}
}
function c(e, n, a) {
var c = document.createElement("li");
c.id = ("/" == e ? "" : e) + "/" + n;
var s = document.createElement("span");
return s.innerText = n, c.appendChild(s), c.onclick = function (e) {
l(c.id.toLowerCase()) ? t.loadUrl(c.id) : i(c.id.toLowerCase()) && o(c.id)
}, c.oncontextmenu = function (e) {
e.preventDefault(), e.stopPropagation(),
function (e, t, n) {
var a = document.createElement("div"),
o = document.body.scrollTop ? document.body.scrollTop : document.documentElement.scrollTop,
c = document.body.scrollLeft ? document.body.scrollLeft : document.documentElement.scrollLeft,
l = event.clientX + c,
i = event.clientY + o;
a.className = "cm", a.style.display = "block", a.style.left = l + "px", a.style.top = i + "px", d(a, t), document.body.appendChild(a);
var s = a.offsetWidth,
r = a.offsetHeight;
a.onmouseout = function (e) {
(e.clientX < l || e.clientX > l + s || e.clientY < i || e.clientY > i + r) && document.body.getElementsByClassName("cm").length > 0 && document.body.removeChild(a)
}
}(0, c.id)
}, c
}
function l(e) {
var t = /(?:.([^.]+))?$/.exec(e)[1];
if (void 0 !== typeof t) switch (t) {
case "txt":
case "json":
case "jsonl":
case "htm":
case "js":
case "c":
case "cpp":
case "css":
case "xml":
return !0
}
return !1
}
function i(e) {
var t = /(?:.([^.]+))?$/.exec(e)[1];
if (void 0 !== typeof t) switch (t) {
case "png":
case "jpg":
case "gif":
return !0
}
return !1
}
function s(e, t) {
xmlHttp = new XMLHttpRequest(e, t), xmlHttp.onreadystatechange = function (e, t) {
return function () {
4 == xmlHttp.readyState && 200 == xmlHttp.status && function (e, t, n) {
var a = document.createElement("ul");
e.appendChild(a);
for (var o = n.length, d = 0; d < o; d++) "file" === n[d].type && a.appendChild(c(t, n[d].name, n[d].size))
}(e, t, JSON.parse(xmlHttp.responseText))
}
}(e, t), xmlHttp.open("GET", "/list?dir=" + t, !0), xmlHttp.send(null)
}
return a.className = "tvu", document.getElementById(e).appendChild(a), this.refreshPath = function (e) {
a.removeChild(a.childNodes[0]), s(a, "/")
}, s(a, "/"), this
}
function createEditor(e, t, n, a, o) {
function d(e) {
var t = "plain",
n = /(?:.([^.]+))?$/.exec(e)[1];
if (void 0 !== typeof n) switch (n) {
case "txt":
t = "plain";
break;
case "htm":
t = "html";
break;
case "js":
t = "javascript";
break;
case "jsonl":
t = "json";
break;
case "c":
case "cpp":
t = "c_cpp";
break;
case "css":
case "scss":
case "php":
case "html":
case "json":
case "xml":
t = n
}
return t
}
void 0 === t && (t = "/"), void 0 === n && (n = d(t)), void 0 === a && (a = "textmate"), void 0 === o && (o = "text/" + n, "c_cpp" === n && (o = "text/plain"));
var c = null,
l = ace.edit(e, {
useWorker: !1,
wrap: !0,
indentedSoftWrap: !1
});
function i() {
4 == c.readyState && 200 != c.status && alert("ERROR[" + c.status + "]: " + c.responseText)
}
function s() {
4 == c.readyState && (document.getElementById("preview").style.display = "none", document.getElementById("editor").style.display = "block", function (e, t) {
if (200 == t.status) try {
var n = JSON.parse(t.responseText);
e.setValue(JSON.stringify(n, null, 4))
} catch (n) {
e.setValue(t.responseText)
} else e.setValue("");
e.resize(!0), e.scrollToLine(1, !0, !0, function () { }), e.gotoLine(1, 0, !0), e.clearSelection()
}(l, c))
}
function r(e) {
(c = new XMLHttpRequest).onreadystatechange = s, c.open("GET", e, !0), c.send(null)
}
return "plain" !== n && l.getSession().setMode("ace/mode/" + n), l.setTheme("ace/theme/" + a), l.$blockScrolling = 1 / 0, l.getSession().setUseSoftTabs(!0), l.getSession().setTabSize(2), l.setHighlightActiveLine(!0), l.setShowPrintMargin(!1), l.commands.addCommand({
name: "saveCommand",
bindKey: {
win: "Ctrl-S",
mac: "Command-S"
},
exec: function (e) {
! function (e, t, n) {
(c = new XMLHttpRequest).onreadystatechange = i;
var a = new FormData;
a.append("data", new Blob([t], {
type: n
}), e), c.open("POST", "/edit"), c.send(a)
}(t, function (e) {
var t = e.getValue();
try {
var n = JSON.parse(t);
return JSON.stringify(n)
} catch (e) {
return t + ""
}
}(e), o)
},
readOnly: !1
}), l.commands.addCommand({
name: "undoCommand",
bindKey: {
win: "Ctrl-Z",
mac: "Command-Z"
},
exec: function (e) {
e.getSession().getUndoManager().undo(!1)
},
readOnly: !1
}), l.commands.addCommand({
name: "redoCommand",
bindKey: {
win: "Ctrl-Shift-Z",
mac: "Command-Shift-Z"
},
exec: function (e) {
e.getSession().getUndoManager().redo(!1)
},
readOnly: !1
}), r(t), l.loadUrl = function (e) {
n = d(t = e), o = "text/" + n, "plain" !== n && l.getSession().setMode("ace/mode/" + n), r(t), document.getElementById("upload-path").value = e
}, l
}
function onBodyLoad() {
var e = {},
t = (window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, function (t, n, a) {
e[n] = a
}), createEditor("editor", e.file, e.lang, e.theme));
createFileUploader("uploader", createTree("tree", t), t), e.file && (document.getElementById("upload-path").value = e.file)
}
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.12/ace.js" type="text/javascript"
charset="utf-8"></script>
</head>
<body onload="onBodyLoad();">
<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>

BIN
data/edit.htm.gz Normal file

Binary file not shown.

View File

@ -43,6 +43,10 @@
#define HASP_USE_MQTT (HASP_HAS_NETWORK)
#endif
#ifndef HASP_USE_BROADCAST
#define HASP_USE_BROADCAST 1
#endif
#ifndef MQTT_NODENAME
#define MQTT_NODENAME "plate"
#endif
@ -63,6 +67,10 @@
#define HASP_USE_TELNET 0
#endif
#ifndef HASP_USE_CONSOLE
#define HASP_USE_CONSOLE 1
#endif
/* Filesystem */
#define HASP_HAS_FILESYSTEM (ARDUINO_ARCH_ESP32 > 0 || ARDUINO_ARCH_ESP8266 > 0)
@ -102,10 +110,6 @@
#define HASP_NUM_GPIO_CONFIG 8
#endif
#ifndef HASP_NUM_INPUTS
#define HASP_NUM_INPUTS 4 // Number of ACE Buttons
#endif
// #ifndef HASP_NUM_OUTPUTS
// #define HASP_NUM_OUTPUTS 3
// #endif
@ -217,6 +221,10 @@ static WiFiSpiClass WiFi;
#include "sys/svc/hasp_http.h"
#endif
#if HASP_USE_CONSOLE > 0
#include "sys/svc/hasp_console.h"
#endif
#if HASP_USE_TELNET > 0
#include "sys/svc/hasp_telnet.h"
#endif
@ -240,6 +248,14 @@ static WiFiSpiClass WiFi;
#include "sys/svc/hasp_slave.h"
#endif
#ifndef HASP_ATTRIBUTE_FAST_MEM
#define HASP_ATTRIBUTE_FAST_MEM
#endif
#ifndef IRAM_ATTR
#define IRAM_ATTR
#endif
#ifndef FPSTR
#define FPSTR(pstr_pointer) (reinterpret_cast<const __FlashStringHelper*>(pstr_pointer))
#endif
@ -283,6 +299,7 @@ static WiFiSpiClass WiFi;
#define memcpy_P memcpy
#define strcasecmp_P strcasecmp
#define strcmp_P strcmp
#define strcpy_P strcpy
#define strstr_P strstr
#define halRestartMcu()
#define millis SDL_GetTicks

View File

@ -1,7 +1,3 @@
#ifdef USE_CONFIG_OVERRIDE
#include "user_config_override.h"
#endif
#include "lv_conf_v7.h"
#define LV_THEME_DEFAULT_FLAGS LV_THEME_DEFAULT_FLAG

View File

@ -124,7 +124,9 @@ typedef int16_t lv_coord_t;
* Can be changed in the Input device driver (`lv_indev_drv_t`)*/
/* Input device read period in milliseconds */
#define LV_INDEV_DEF_READ_PERIOD 30
#ifndef LV_INDEV_DEF_READ_PERIOD
#define LV_INDEV_DEF_READ_PERIOD 20
#endif
/* Drag threshold in pixels */
#define LV_INDEV_DEF_DRAG_LIMIT 10
@ -185,16 +187,16 @@ typedef void* lv_group_user_data_t;
typedef void* lv_fs_drv_user_data_t;
/*File system interface*/
#define LV_USE_FS_IF 0
#define LV_USE_FS_IF 1
#if LV_USE_FS_IF
# define LV_FS_IF_FATFS '\0'
#if defined(STM32F4xx) // || defined(ARDUINO_ARCH_ESP8266)
# define LV_FS_IF_PC '\0'
# define LV_FS_IF_SPIFFS '\0' // internal esp Flash
//# define LV_FS_IF_SPIFFS '\0' // internal esp Flash
#else
# define LV_FS_IF_PC '\0'
# define LV_FS_IF_PC 'L' // Local filesystem
# define LV_FS_IF_POSIX '\0'
# define LV_FS_IF_SPIFFS '\0' // no internal esp Flash
//# define LV_FS_IF_SPIFFS '\0' // no internal esp Flash
#endif
#endif /*LV_USE_FS_IF*/
@ -224,6 +226,10 @@ typedef void* lv_fs_drv_user_data_t;
/*Declare the type of the user data of image decoder (can be e.g. `void *`, `int`, `struct`)*/
typedef void* lv_img_decoder_user_data_t;
#if (HASP_USE_PNGDECODE > 0) && (LV_USE_FILESYSTEM > 0)
//#define LV_PNG_USE_LV_FILESYSTEM 1
#endif
/*=====================
* Compiler settings
*====================*/
@ -231,7 +237,9 @@ typedef void* lv_img_decoder_user_data_t;
#define LV_ATTRIBUTE_TICK_INC
/* Define a custom attribute to `lv_task_handler` function */
#ifndef LV_ATTRIBUTE_TASK_HANDLER
#define LV_ATTRIBUTE_TASK_HANDLER
#endif
/* With size optimization (-Os) the compiler might not align data to
* 4 or 8 byte boundary. This alignment will be explicitly applied where needed.
@ -341,6 +349,36 @@ typedef void* lv_indev_drv_user_data_t; /*Type of user data in the in
#if TFT_WIDTH>=320 || TFT_WIDTH>=480
#ifdef WT32SC01
#ifndef HASP_FONT_1
#define HASP_FONT_1 robotocondensed_regular_16_ascii /* 5% Width */
#endif
#ifndef HASP_FONT_2
#define HASP_FONT_2 robotocondensed_regular_24_ascii /* 5% Width */
#endif
#ifndef HASP_FONT_3
#define HASP_FONT_3 robotocondensed_regular_32_ascii /* 10% Width */
#endif
#ifndef HASP_FONT_4
#define HASP_FONT_4 robotocondensed_regular_48_ascii /* 10% Height */
#endif
#ifndef ROBOTOCONDENSED_REGULAR_16_ASCII
#define ROBOTOCONDENSED_REGULAR_16_ASCII 1
#endif
#ifndef ROBOTOCONDENSED_REGULAR_24_ASCII
#define ROBOTOCONDENSED_REGULAR_24_ASCII 1
#endif
#ifndef ROBOTOCONDENSED_REGULAR_32_ASCII
#define ROBOTOCONDENSED_REGULAR_32_ASCII 1
#endif
#ifndef ROBOTOCONDENSED_REGULAR_48_ASCII
#define ROBOTOCONDENSED_REGULAR_48_ASCII 1
#endif
#else // not WT32SC01
#ifndef HASP_FONT_1
#define HASP_FONT_1 robotocondensed_regular_16_latin1 /* 5% Width */
#endif
@ -367,6 +405,8 @@ typedef void* lv_indev_drv_user_data_t; /*Type of user data in the in
#define ROBOTOCONDENSED_REGULAR_48_LATIN1 1
#endif
#endif // WT32SC01
#ifndef HASP_FONT_SIZE_1
#define HASP_FONT_SIZE_1 16
#endif
@ -380,7 +420,7 @@ typedef void* lv_indev_drv_user_data_t; /*Type of user data in the in
#define HASP_FONT_SIZE_4 48
#endif
#else
#else // not 320x480
#ifndef HASP_FONT_1
#define HASP_FONT_1 robotocondensed_regular_12_latin1 /* 5% Width */
@ -732,6 +772,7 @@ typedef struct {
/*LED (dependencies: -)*/
#define LV_USE_LED 1
#define LV_LED_BRIGHT_MIN 0
/*Line (dependencies: -*/
#define LV_USE_LINE 1

View File

@ -88,28 +88,9 @@
#define D_HTTP_COLOR_BUTTON_RESET "#d43535" // Restart/Reset/Delete button color - Strong red
*/
/***************************************************
* Font Settings
**************************************************/
// #define HASP_FONT_1 robotocondensed_regular_16_latin1 // Use available fonts from src/fonts directory
// #define HASP_FONT_2 robotocondensed_regular_22_latin1
// #define HASP_FONT_3 robotocondensed_regular_40_latin1
// #define HASP_FONT_4 robotocondensed_regular_48_latin1
// #define ROBOTOCONDENSED_REGULAR_16_LATIN1 1 // Enable the selected fonts
// #define ROBOTOCONDENSED_REGULAR_22_LATIN1 1
// #define ROBOTOCONDENSED_REGULAR_40_LATIN1 1
// #define ROBOTOCONDENSED_REGULAR_48_LATIN1 1
// #define HASP_FONT_SIZE_1 16 // Define used font sizes
// #define HASP_FONT_SIZE_2 22
// #define HASP_FONT_SIZE_3 40
// #define HASP_FONT_SIZE_4 48
/***************************************************
* Other Settings
**************************************************/
//#define HASP_USE_HA // Enable Home Assistant auto-discovery
//#define HASP_GPIO_TEMPLATE "[2360346,2491680,2623009,2097420,2097678,2097947,0,0]" // Lanbon L8-HS: 3 Relays + Moodlight GPIO config
#endif
#endif

View File

@ -24,10 +24,12 @@
* DEFINES
*********************/
#ifndef LV_FS_PC_PATH
#ifndef WIN32
#define LV_FS_PC_PATH "/fs" /*Projet root*/
#if defined(ESP32)
#define LV_FS_PC_PATH "/littlefs" /*Projet root*/
#elif defined(WIN32)
#define LV_FS_PC_PATH "./" /*Projet root*/
#else
#define LV_FS_PC_PATH ".\\" /*Projet root*/
#define LV_FS_PC_PATH "" /*Projet root*/
#endif
#endif /*LV_FS_PATH*/
@ -144,11 +146,11 @@ static lv_fs_res_t fs_open(lv_fs_drv_t* drv, void* file_p, const char* path, lv_
#ifndef WIN32
char buf[256];
sprintf(buf, LV_FS_PC_PATH "/%s", path);
printf("%s\n", buf);
#else
char buf[256];
sprintf(buf, LV_FS_PC_PATH "\\%s", path);
#endif
printf("Opening file: %s\n", path);
file_t f = fopen(buf, flags);
if(f == NULL) {

View File

@ -22,6 +22,8 @@
#define LV_FS_SPIFFS SPIFFS
#elif HASP_USE_LITTLEFS > 0
#include "LITTLEFS.h"
#include "esp_littlefs.h"
#define LV_FS_SPIFFS LITTLEFS
#endif
#elif defined(ARDUINO_ARCH_ESP8266)
@ -45,13 +47,13 @@
**********************/
/* Create a type to store the required data about your file.*/
typedef File lv_spiffs_file_t;
typedef FILE* lv_spiffs_file_t;
/*Similarly to `file_t` create a type for directory reading too */
#if defined(ARDUINO_ARCH_ESP32)
typedef File lv_spiffs_dir_t;
typedef FILE* lv_spiffs_dir_t;
#elif defined(ARDUINO_ARCH_ESP8266)
typedef Dir lv_spiffs_dir_t;
typedef Dir* lv_spiffs_dir_t;
#define FILE_READ "r"
#define FILE_WRITE "r+"
#endif
@ -93,6 +95,7 @@ void lv_fs_if_spiffs_init(void)
/*----------------------------------------------------
* Initialize your storage device and File System
* -------------------------------------------------*/
Log.verbose(88, "File system init start");
fs_init();
/*---------------------------------------------------
@ -114,16 +117,17 @@ void lv_fs_if_spiffs_init(void)
fs_drv.tell_cb = fs_tell;
fs_drv.free_space_cb = fs_free;
fs_drv.size_cb = fs_size;
fs_drv.remove_cb = fs_remove;
fs_drv.rename_cb = fs_rename;
fs_drv.trunc_cb = fs_trunc;
// fs_drv.remove_cb = fs_remove;
// fs_drv.rename_cb = fs_rename;
// fs_drv.trunc_cb = fs_trunc;
fs_drv.rddir_size = sizeof(lv_spiffs_dir_t);
fs_drv.dir_close_cb = fs_dir_close;
fs_drv.dir_open_cb = fs_dir_open;
fs_drv.dir_read_cb = fs_dir_read;
// fs_drv.rddir_size = sizeof(lv_spiffs_dir_t);
// fs_drv.dir_close_cb = fs_dir_close;
// fs_drv.dir_open_cb = fs_dir_open;
// fs_drv.dir_read_cb = fs_dir_read;
lv_fs_drv_register(&fs_drv);
Log.verbose(88, "File system init complete");
}
/**********************
@ -133,7 +137,42 @@ void lv_fs_if_spiffs_init(void)
/* Initialize your Storage device and File system. */
static void fs_init(void)
{
LV_FS_SPIFFS.begin();
esp_vfs_littlefs_conf_t conf = {.base_path = "/lfs", .partition_label = "spiffs", .format_if_mount_failed = false};
esp_err_t res = esp_vfs_littlefs_register(&conf);
if(res != ESP_OK) {
if(res == ESP_FAIL) {
Log.error(88, "Failed to mount or format filesystem");
} else if(res == ESP_ERR_NOT_FOUND) {
Log.error(88, "Failed to find LittleFS partition");
} else {
Log.error(88, "Failed to initialize LittleFS (%s)", esp_err_to_name(res));
}
return;
}
size_t total = 0, used = 0;
res = esp_littlefs_info(conf.partition_label, &total, &used);
if(res != ESP_OK) {
Log.error(88, "Failed to get LittleFS partition information (%s)", esp_err_to_name(res));
} else {
Log.verbose(88, "Partition size: total: %d, used: %d", total, used);
}
// Use POSIX and C standard library functions to work with files.
// First create a file.
Log.verbose(88, "Opening file /lfs/hello.txt");
FILE* f = fopen("/lfs/hello.txt", "w");
if(f == NULL) {
Log.error(88, "Failed to open file for writing");
return;
}
fprintf(f, "LittleFS Rocks!\n");
fclose(f);
Log.verbose(88, "File written");
Log.verbose(88, "LittleFS init OK");
}
/**
@ -148,35 +187,35 @@ static lv_fs_res_t fs_open(lv_fs_drv_t* drv, void* file_p, const char* path, lv_
{
(void)drv; /*Unused*/
char filename[32];
snprintf_P(filename, sizeof(filename), PSTR("/%s"), path);
const char* flags = "";
lv_spiffs_file_t* fp = (lv_spiffs_file_t*)file_p;
if(fp == NULL) return LV_FS_RES_INV_PARAM;
if(mode == LV_FS_MODE_WR)
flags = "w";
else if(mode == LV_FS_MODE_RD)
flags = "r";
else if(mode == (LV_FS_MODE_WR | LV_FS_MODE_RD))
flags = "rb+";
LOG_VERBOSE(TAG_LVFS, F("Opening %s"), filename);
lv_spiffs_file_t file = LV_FS_SPIFFS.open(filename, mode == LV_FS_MODE_WR ? FILE_WRITE : FILE_READ);
/*Make the path relative to the current directory (the projects root folder)*/
LOG_VERBOSE(TAG_LVFS, F("%d"), __LINE__);
if(!file) {
LOG_VERBOSE(TAG_LVFS, F("Invalid file"));
return LV_FS_RES_NOT_EX;
char complete_path[strlen(path) + 1];
complete_path[0] = '/';
complete_path[1] = '\0';
strcat(complete_path, path);
// } else if((*fp).isDirectory()) {
// LOG_VERBOSE(TAG_LVFS, F("Cannot open directory as a file"));
// return LV_FS_RES_UNKNOWN;
Log.verbose(88, "Opening file %s", path);
lv_spiffs_file_t f = fopen(path, flags);
if(f == NULL) return LV_FS_RES_UNKNOWN;
} else {
// f.seek(0, SeekSet);
// LOG_VERBOSE(TAG_LVFS,F("Assigning %s"), f.name());
LOG_VERBOSE(TAG_LVFS, F("%d"), __LINE__);
// LOG_VERBOSE(TAG_LVFS,F("Copying %s"), f.name());
LOG_VERBOSE(TAG_LVFS, F("%d - %x - %d"), __LINE__, fp, sizeof(lv_spiffs_file_t));
// memcpy(fp,&file,sizeof(lv_spiffs_file_t));
LOG_VERBOSE(TAG_LVFS, F("%d"), __LINE__);
*fp = file;
return LV_FS_RES_OK;
}
/*Be sure we are the beginning of the file*/
fseek(f, 0, SEEK_SET);
/* 'file_p' is pointer to a file descriptor and
* we need to store our file descriptor here*/
lv_spiffs_file_t* fp = (lv_spiffs_file_t*)file_p; /*Just avoid the confusing casings*/
*fp = f;
Log.verbose(88, "Open eof file_p %d", feof(*fp));
return LV_FS_RES_OK;
}
/**
@ -188,23 +227,10 @@ static lv_fs_res_t fs_open(lv_fs_drv_t* drv, void* file_p, const char* path, lv_
*/
static lv_fs_res_t fs_close(lv_fs_drv_t* drv, void* file_p)
{
(void)drv; /*Unused*/
lv_spiffs_file_t* fp = (lv_spiffs_file_t*)file_p;
if(fp == NULL) return LV_FS_RES_INV_PARAM;
lv_spiffs_file_t file = *fp;
if(!file) {
LOG_VERBOSE(TAG_LVFS, F("Invalid file"));
return LV_FS_RES_NOT_EX;
} else if(file.isDirectory()) {
return LV_FS_RES_UNKNOWN;
} else {
file.close();
return LV_FS_RES_OK;
}
(void)drv; /*Unused*/
lv_spiffs_file_t* fp = (lv_spiffs_file_t*)file_p; /*Just avoid the confusing casings*/
fclose(*fp);
return LV_FS_RES_OK;
}
/**
@ -219,33 +245,11 @@ static lv_fs_res_t fs_close(lv_fs_drv_t* drv, void* file_p)
*/
static lv_fs_res_t fs_read(lv_fs_drv_t* drv, void* file_p, void* buf, uint32_t btr, uint32_t* br)
{
(void)drv; /*Unused*/
lv_spiffs_file_t* fp = (lv_spiffs_file_t*)file_p;
if(fp == NULL) return LV_FS_RES_INV_PARAM;
lv_spiffs_file_t file = *fp;
if(!file) {
LOG_ERROR(TAG_LVFS, F("Invalid file"));
return LV_FS_RES_NOT_EX;
} else {
// LOG_VERBOSE(TAG_LVFS, F("Reading %u bytes from %s at position %u"), btr, file.name(), file.position());
uint32_t len = 0;
char* chp = (char*)buf;
if(chp != NULL && btr > 0)
len = file.readBytes(chp, btr);
else
LOG_VERBOSE(TAG_LVFS, F("Buffer is NULL"), btr, file.name(), file.position());
if(br != NULL)
*br = len;
else
LOG_VERBOSE(TAG_LVFS, F("BYTESREAD is NULL"), btr, file.name(), file.position());
Serial.print("!");
return LV_FS_RES_OK;
}
(void)drv; /*Unused*/
lv_spiffs_file_t* fp = (lv_spiffs_file_t*)file_p; /*Just avoid the confusing casings*/
Log.verbose(88, "Read eof %d", feof(*fp));
*br = fread(buf, 1, btr, *fp);
return LV_FS_RES_OK;
}
/**
@ -259,18 +263,10 @@ static lv_fs_res_t fs_read(lv_fs_drv_t* drv, void* file_p, void* buf, uint32_t b
*/
static lv_fs_res_t fs_write(lv_fs_drv_t* drv, void* file_p, const void* buf, uint32_t btw, uint32_t* bw)
{
(void)drv; /*Unused*/
lv_spiffs_file_t file = *(lv_spiffs_file_t*)file_p;
// File file = fp;
if(!file) {
// LOG_VERBOSE(TAG_LVFS,F("Invalid file"));
return LV_FS_RES_NOT_EX;
} else {
*bw = (uint32_t)file.write((byte*)buf, btw);
return LV_FS_RES_OK;
}
(void)drv; /*Unused*/
lv_spiffs_file_t* fp = (lv_spiffs_file_t*)file_p; /*Just avoid the confusing casings*/
Log.verbose(88, "Write eof %d", feof(*fp));
*bw = fwrite(buf, 1, btw, *fp);
}
/**
@ -283,18 +279,10 @@ static lv_fs_res_t fs_write(lv_fs_drv_t* drv, void* file_p, const void* buf, uin
*/
static lv_fs_res_t fs_seek(lv_fs_drv_t* drv, void* file_p, uint32_t pos)
{
(void)drv; /*Unused*/
lv_spiffs_file_t file = *(lv_spiffs_file_t*)file_p;
// File file = fp;
if(!file) {
// LOG_VERBOSE(TAG_LVFS,F("Invalid file"));
return LV_FS_RES_NOT_EX;
} else {
file.seek(pos, SeekSet);
return LV_FS_RES_OK;
}
(void)drv; /*Unused*/
lv_spiffs_file_t* fp = (lv_spiffs_file_t*)file_p; /*Just avoid the confusing casings*/
fseek(*fp, pos, SEEK_SET);
return LV_FS_RES_OK;
}
/**
@ -306,18 +294,12 @@ static lv_fs_res_t fs_seek(lv_fs_drv_t* drv, void* file_p, uint32_t pos)
*/
static lv_fs_res_t fs_size(lv_fs_drv_t* drv, void* file_p, uint32_t* size_p)
{
(void)drv; /*Unused*/
lv_spiffs_file_t file = *(lv_spiffs_file_t*)file_p;
// File file = fp;
if(!file) {
// LOG_VERBOSE(TAG_LVFS,F("Invalid file"));
return LV_FS_RES_NOT_EX;
} else {
*size_p = (uint32_t)file.size();
return LV_FS_RES_OK;
}
(void)drv; /*Unused*/
lv_spiffs_file_t* fp = (lv_spiffs_file_t*)file_p; /*Just avoid the confusing casings*/
fseek(*fp, 0L, SEEK_END);
*size_p = ftell(*fp);
fseek(*fp, 0L, SEEK_SET);
return LV_FS_RES_OK;
}
/**
@ -330,18 +312,10 @@ static lv_fs_res_t fs_size(lv_fs_drv_t* drv, void* file_p, uint32_t* size_p)
*/
static lv_fs_res_t fs_tell(lv_fs_drv_t* drv, void* file_p, uint32_t* pos_p)
{
(void)drv; /*Unused*/
lv_spiffs_file_t file = *(lv_spiffs_file_t*)file_p;
// File file = fp;
if(!file) {
// LOG_VERBOSE(TAG_LVFS,F("Invalid file"));
return LV_FS_RES_NOT_EX;
} else {
*pos_p = (uint32_t)file.position();
return LV_FS_RES_OK;
}
(void)drv; /*Unused*/
lv_spiffs_file_t* fp = (lv_spiffs_file_t*)file_p; /*Just avoid the confusing casings*/
*pos_p = ftell(*fp);
return LV_FS_RES_OK;
}
/**
@ -439,25 +413,25 @@ static lv_fs_res_t fs_free(lv_fs_drv_t* drv, uint32_t* total_p, uint32_t* free_p
* @param path path to a directory
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
*/
static lv_fs_res_t fs_dir_open(lv_fs_drv_t* drv, void* dir_p, const char* path)
{
lv_spiffs_dir_t dir;
// static lv_fs_res_t fs_dir_open(lv_fs_drv_t* drv, void* dir_p, const char* path)
// {
// lv_spiffs_dir_t dir;
#if defined(ARDUINO_ARCH_ESP32)
dir = LV_FS_SPIFFS.open(path);
if(!dir) {
return LV_FS_RES_UNKNOWN;
}
#endif
// #if defined(ARDUINO_ARCH_ESP32)
// dir = &LV_FS_SPIFFS.open(path);
// if(!dir) {
// return LV_FS_RES_UNKNOWN;
// }
// #endif
#if defined(ARDUINO_ARCH_ESP8266)
dir = LV_FS_SPIFFS.openDir(path);
#endif
// #if defined(ARDUINO_ARCH_ESP8266)
// dir = LV_FS_SPIFFS.openDir(path);
// #endif
lv_spiffs_dir_t* dp = (lv_spiffs_dir_t*)dir_p; /*Just avoid the confusing casings*/
*dp = dir;
return LV_FS_RES_OK;
}
// lv_spiffs_dir_t* dp = (lv_spiffs_dir_t*)dir_p; /*Just avoid the confusing casings*/
// *dp = dir;
// return LV_FS_RES_OK;
// }
/**
* Read the next filename form a directory.
@ -467,31 +441,31 @@ static lv_fs_res_t fs_dir_open(lv_fs_drv_t* drv, void* dir_p, const char* path)
* @param fn pointer to a buffer to store the filename
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
*/
static lv_fs_res_t fs_dir_read(lv_fs_drv_t* drv, void* dir_p, char* fn)
{
lv_spiffs_dir_t dir = *(lv_spiffs_dir_t*)dir_p; /*Convert type*/
// static lv_fs_res_t fs_dir_read(lv_fs_drv_t* drv, void* dir_p, char* fn)
// {
// lv_spiffs_dir_t dir = *(lv_spiffs_dir_t*)dir_p; /*Convert type*/
#if defined(ARDUINO_ARCH_ESP32)
File file = dir.openNextFile();
if(file) {
strcpy(fn, file.name());
return LV_FS_RES_OK;
} else {
return LV_FS_RES_UNKNOWN;
}
#endif
// #if defined(ARDUINO_ARCH_ESP32)
// File file = dir.openNextFile();
// if(file) {
// strcpy(fn, file.name());
// return LV_FS_RES_OK;
// } else {
// return LV_FS_RES_UNKNOWN;
// }
// #endif
#if defined(ARDUINO_ARCH_ESP8266)
if(dir.next()) {
strcpy(fn, dir.fileName().c_str());
return LV_FS_RES_OK;
} else {
return LV_FS_RES_UNKNOWN;
}
#endif
// #if defined(ARDUINO_ARCH_ESP8266)
// if(dir.next()) {
// strcpy(fn, dir.fileName().c_str());
// return LV_FS_RES_OK;
// } else {
// return LV_FS_RES_UNKNOWN;
// }
// #endif
return LV_FS_RES_NOT_IMP;
}
// return LV_FS_RES_NOT_IMP;
// }
/**
* Close the directory reading

View File

@ -45,14 +45,14 @@
* @param light_color light color of the QR code
* @return pointer to the created QR code object
*/
lv_obj_t * lv_qrcode_create(lv_obj_t * parent, lv_coord_t size, lv_color_t dark_color, lv_color_t light_color)
lv_obj_t* lv_qrcode_create(lv_obj_t* parent, lv_coord_t size, lv_color_t dark_color, lv_color_t light_color)
{
uint32_t buf_size = LV_CANVAS_BUF_SIZE_INDEXED_1BIT(size, size);
uint8_t * buf = lv_mem_alloc(buf_size);
uint8_t* buf = lv_mem_alloc(buf_size);
LV_ASSERT_MEM(buf);
if(buf == NULL) return NULL;
lv_obj_t * canvas = lv_canvas_create(parent, NULL);
lv_obj_t* canvas = lv_canvas_create(parent, NULL);
lv_canvas_set_buffer(canvas, buf, size, size, LV_IMG_CF_INDEXED_1BIT);
lv_canvas_set_palette(canvas, 0, dark_color);
@ -90,7 +90,7 @@ lv_obj_t * lv_qrcode_create(lv_obj_t * parent, lv_coord_t size, lv_color_t dark_
* @param data_len length of data in bytes
* @return LV_RES_OK: if no error; LV_RES_INV: on error
*/
lv_res_t lv_qrcode_update(lv_obj_t * qrcode, const void * data, uint32_t data_len)
lv_res_t lv_qrcode_update(lv_obj_t* qrcode, const void* data, uint32_t data_len)
{
lv_color_t c;
c.full = 1;
@ -124,7 +124,7 @@ lv_res_t lv_qrcode_update(lv_obj_t * qrcode, const void * data, uint32_t data_le
return LV_RES_OK;
}
lv_res_t lv_qrcode_update2(lv_obj_t * qrcode, const void * data, uint32_t data_len)
lv_res_t lv_qrcode_update2(lv_obj_t* qrcode, const void* data, uint32_t data_len)
{
lv_color_t c;
// c.full = 1;
@ -143,31 +143,27 @@ lv_res_t lv_qrcode_update2(lv_obj_t * qrcode, const void * data, uint32_t data_l
if(!ok) return LV_RES_INV;
// lv_coord_t obj_w = lv_obj_get_width(qrcode);
int qr_size = qrcodegen_getSize(qr_pixels);
int scale = 1;
int scaled = 0;
int margin = 0;
LV_LOG_ERROR("5 OK");
// int scale = 1;
// int scaled = 0;
// int qr_size = qrcodegen_getSize(qr_pixels);
int margin = 0;
lv_img_ext_t * ext = (lv_img_ext_t *)lv_obj_get_ext_attr(qrcode);
lv_img_ext_t* ext = (lv_img_ext_t*)lv_obj_get_ext_attr(qrcode);
if(!ext || !ext->src) return LV_RES_INV;
LV_LOG_ERROR("6 OK");
lv_img_header_t header;
lv_img_decoder_get_info(ext->src, &header);
LV_LOG_ERROR("7 OK");
lv_img_decoder_dsc_t dec_dsc;
lv_res_t res = lv_img_decoder_open(&dec_dsc, ext->src, LV_COLOR_CYAN);
LV_LOG_ERROR("8 OK");
(void)res; // unused
for(int y = 0; y < dec_dsc.header.h; y++) {
for(int x = 0; x < dec_dsc.header.w; x++) {
c = qrcodegen_getModule(qr_pixels, x, y) ? LV_COLOR_WHITE : LV_COLOR_BLACK;
lv_img_buf_set_px_color(dec_dsc.src, x + margin, y + margin, c);
lv_img_buf_set_px_color((lv_img_dsc_t*)dec_dsc.src, x + margin, y + margin, c);
}
}
LV_LOG_ERROR("9 OK");
return LV_RES_OK;
}
@ -176,9 +172,9 @@ lv_res_t lv_qrcode_update2(lv_obj_t * qrcode, const void * data, uint32_t data_l
* Delete a QR code object
* @param qrcode pointer to a QR code obejct
*/
void lv_qrcode_delete(lv_obj_t * qrcode)
void lv_qrcode_delete(lv_obj_t* qrcode)
{
lv_img_dsc_t * img = lv_canvas_get_img(qrcode);
lv_img_dsc_t* img = lv_canvas_get_img(qrcode);
lv_mem_free(img->data);
lv_mem_free(img);
lv_obj_del(qrcode);

View File

@ -55,7 +55,7 @@
// - They are completely thread-safe if the caller does not give the
// same writable buffer to concurrent calls to these functions.
testable void appendBitsToBuffer(unsigned int val, int numBits, uint8_t buffer[], int * bitLen);
testable void appendBitsToBuffer(unsigned int val, int numBits, uint8_t buffer[], int* bitLen);
testable void addEccAndInterleave(uint8_t data[], int version, enum qrcodegen_Ecc ecl, uint8_t result[]);
testable int getNumDataCodewords(int version, enum qrcodegen_Ecc ecl);
@ -135,7 +135,7 @@ static const int PENALTY_N4 = 10;
/*---- High-level QR Code encoding functions ----*/
// Public function - see documentation comment in header file.
bool qrcodegen_encodeText(const char * text, uint8_t tempBuffer[], uint8_t qrcode[], enum qrcodegen_Ecc ecl,
bool qrcodegen_encodeText(const char* text, uint8_t tempBuffer[], uint8_t qrcode[], enum qrcodegen_Ecc ecl,
int minVersion, int maxVersion, enum qrcodegen_Mask mask, bool boostEcl)
{
@ -187,7 +187,7 @@ bool qrcodegen_encodeBinary(uint8_t dataAndTemp[], size_t dataLen, uint8_t qrcod
// Appends the given number of low-order bits of the given value to the given byte-based
// bit buffer, increasing the bit length. Requires 0 <= numBits <= 16 and val < 2^numBits.
testable void appendBitsToBuffer(unsigned int val, int numBits, uint8_t buffer[], int * bitLen)
testable void appendBitsToBuffer(unsigned int val, int numBits, uint8_t buffer[], int* bitLen)
{
assert(0 <= numBits && numBits <= 16 && (unsigned long)val >> numBits == 0);
for(int i = numBits - 1; i >= 0; i--, (*bitLen)++) buffer[*bitLen >> 3] |= ((val >> i) & 1) << (7 - (*bitLen & 7));
@ -235,7 +235,7 @@ bool qrcodegen_encodeSegmentsAdvanced(const struct qrcodegen_Segment segs[], siz
memset(qrcode, 0, qrcodegen_BUFFER_LEN_FOR_VERSION(version) * sizeof(qrcode[0]));
int bitLen = 0;
for(size_t i = 0; i < len; i++) {
const struct qrcodegen_Segment * seg = &segs[i];
const struct qrcodegen_Segment* seg = &segs[i];
appendBitsToBuffer((int)seg->mode, 4, qrcode, &bitLen);
appendBitsToBuffer(seg->numChars, numCharCountBits(seg->mode, version), qrcode, &bitLen);
for(int j = 0; j < seg->bitLength; j++)
@ -305,10 +305,10 @@ testable void addEccAndInterleave(uint8_t data[], int version, enum qrcodegen_Ec
// (not concatenate) the bytes into a single sequence
uint8_t generator[qrcodegen_REED_SOLOMON_DEGREE_MAX];
calcReedSolomonGenerator(blockEccLen, generator);
const uint8_t * dat = data;
const uint8_t* dat = data;
for(int i = 0; i < numBlocks; i++) {
int datLen = shortBlockDataLen + (i < numShortBlocks ? 0 : 1);
uint8_t * ecc = &data[dataLen]; // Temporary storage
int datLen = shortBlockDataLen + (i < numShortBlocks ? 0 : 1);
uint8_t* ecc = &data[dataLen]; // Temporary storage
calcReedSolomonRemainder(dat, datLen, generator, blockEccLen, ecc);
for(int j = 0, k = i; j < datLen; j++, k += numBlocks) { // Copy data
if(j == shortBlockDataLen) k -= numShortBlocks;
@ -782,7 +782,7 @@ static bool getBit(int x, int i)
/*---- Segment handling ----*/
// Public function - see documentation comment in header file.
bool qrcodegen_isAlphanumeric(const char * text)
bool qrcodegen_isAlphanumeric(const char* text)
{
char buffer[64];
snprintf_P(buffer, sizeof(buffer), ALPHANUMERIC_CHARSET);
@ -795,7 +795,7 @@ bool qrcodegen_isAlphanumeric(const char * text)
}
// Public function - see documentation comment in header file.
bool qrcodegen_isNumeric(const char * text)
bool qrcodegen_isNumeric(const char* text)
{
assert(text != NULL);
for(; *text != '\0'; text++) {
@ -860,7 +860,7 @@ struct qrcodegen_Segment qrcodegen_makeBytes(const uint8_t data[], size_t len, u
}
// Public function - see documentation comment in header file.
struct qrcodegen_Segment qrcodegen_makeNumeric(const char * digits, uint8_t buf[])
struct qrcodegen_Segment qrcodegen_makeNumeric(const char* digits, uint8_t buf[])
{
assert(digits != NULL);
struct qrcodegen_Segment result;
@ -893,7 +893,7 @@ struct qrcodegen_Segment qrcodegen_makeNumeric(const char * digits, uint8_t buf[
}
// Public function - see documentation comment in header file.
struct qrcodegen_Segment qrcodegen_makeAlphanumeric(const char * text, uint8_t buf[])
struct qrcodegen_Segment qrcodegen_makeAlphanumeric(const char* text, uint8_t buf[])
{
char buffer[64];
snprintf_P(buffer, sizeof(buffer), ALPHANUMERIC_CHARSET);
@ -911,7 +911,7 @@ struct qrcodegen_Segment qrcodegen_makeAlphanumeric(const char * text, uint8_t b
unsigned int accumData = 0;
int accumCount = 0;
for(; *text != '\0'; text++) {
const char * temp = strchr(buffer, *text); // ALPHANUMERIC_CHARSET
const char* temp = strchr(buffer, *text); // ALPHANUMERIC_CHARSET
assert(temp != NULL);
accumData = accumData * 45 + (unsigned int)(temp - buffer); // ALPHANUMERIC_CHARSET
accumCount++;
@ -963,8 +963,8 @@ testable int getTotalBits(const struct qrcodegen_Segment segs[], size_t len, int
assert(segs != NULL || len == 0);
long result = 0;
for(size_t i = 0; i < len; i++) {
int numChars = segs[i].numChars;
int bitLength = segs[i].bitLength;
int16_t numChars = segs[i].numChars;
int16_t bitLength = segs[i].bitLength;
assert(0 <= numChars && numChars <= INT16_MAX);
assert(0 <= bitLength && bitLength <= INT16_MAX);
int ccbits = numCharCountBits(segs[i].mode, version);

View File

@ -55,9 +55,9 @@ enum zifont_codepage_t8_t { ASCII = 0x01, ISO_8859_1 = 0x03, UTF_8 = 0x18 };
/**********************
* STATIC PROTOTYPES
**********************/
const uint8_t* IRAM_ATTR lv_font_get_bitmap_fmt_zifont(const lv_font_t* font, uint32_t unicode_letter);
bool IRAM_ATTR lv_font_get_glyph_dsc_fmt_zifont(const lv_font_t* font, lv_font_glyph_dsc_t* dsc_out,
uint32_t unicode_letter, uint32_t unicode_letter_next);
HASP_ATTRIBUTE_FAST_MEM const uint8_t* lv_font_get_bitmap_fmt_zifont(const lv_font_t* font, uint32_t unicode_letter);
HASP_ATTRIBUTE_FAST_MEM bool lv_font_get_glyph_dsc_fmt_zifont(const lv_font_t* font, lv_font_glyph_dsc_t* dsc_out,
uint32_t unicode_letter, uint32_t unicode_letter_next);
/**********************
* STATIC VARIABLES
@ -83,8 +83,8 @@ static uint8_t* charBitmap_p;
* GLOBAL FUNCTIONS
**********************/
static void IRAM_ATTR blackAdd(uint8_t* charBitmap_p, uint16_t pos);
static void IRAM_ATTR colorsAdd(uint8_t* charBitmap_p, uint8_t color1, uint16_t pos);
HASP_ATTRIBUTE_FAST_MEM static void blackAdd(uint8_t* charBitmap_p, uint16_t pos);
HASP_ATTRIBUTE_FAST_MEM static void colorsAdd(uint8_t* charBitmap_p, uint8_t color1, uint16_t pos);
// static uint16_t unicode2codepoint(uint32_t unicode, uint8_t codepage);
// static void printBuffer(uint8_t * charBitmap_p, uint8_t w, uint8_t h);
@ -282,7 +282,7 @@ int lv_zifont_font_init(lv_font_t** font, const char* font_path, uint16_t size)
* @param unicode_letter an unicode letter which bitmap should be get
* @return pointer to the bitmap or NULL if not found
*/
const uint8_t* IRAM_ATTR lv_font_get_bitmap_fmt_zifont(const lv_font_t* font, uint32_t unicode_letter)
HASP_ATTRIBUTE_FAST_MEM const uint8_t* lv_font_get_bitmap_fmt_zifont(const lv_font_t* font, uint32_t unicode_letter)
{
/* Bitmap still in buffer */
if(charInBuffer == unicode_letter && charBitmap_p) {
@ -469,8 +469,8 @@ const uint8_t* IRAM_ATTR lv_font_get_bitmap_fmt_zifont(const lv_font_t* font, ui
* @return true: descriptor is successfully loaded into `dsc_out`.
* false: the letter was not found, no data is loaded to `dsc_out`
*/
bool IRAM_ATTR lv_font_get_glyph_dsc_fmt_zifont(const lv_font_t* font, lv_font_glyph_dsc_t* dsc_out,
uint32_t unicode_letter, uint32_t unicode_letter_next)
HASP_ATTRIBUTE_FAST_MEM bool lv_font_get_glyph_dsc_fmt_zifont(const lv_font_t* font, lv_font_glyph_dsc_t* dsc_out,
uint32_t unicode_letter, uint32_t unicode_letter_next)
{
/* Only ascii characteres supported for now */
// returning true with a box_h of 0 does not display an error
@ -564,7 +564,7 @@ bool IRAM_ATTR lv_font_get_glyph_dsc_fmt_zifont(const lv_font_t* font, lv_font_g
return true;
}
static void IRAM_ATTR blackAdd(uint8_t* charBitmap_p, uint16_t pos)
HASP_ATTRIBUTE_FAST_MEM static void blackAdd(uint8_t* charBitmap_p, uint16_t pos)
{
uint8_t col = pos & 0x0001; // remainder
uint16_t map_p = pos >> 1; // devide by 2
@ -576,7 +576,7 @@ static void IRAM_ATTR blackAdd(uint8_t* charBitmap_p, uint16_t pos)
}
}
static inline void IRAM_ATTR colorsAdd(uint8_t* charBitmap_p, uint8_t color1, uint16_t pos)
HASP_ATTRIBUTE_FAST_MEM static inline void colorsAdd(uint8_t* charBitmap_p, uint8_t color1, uint16_t pos)
{
uint32_t col = pos & 0x0001; // remainder
uint32_t map_p = pos >> 1; // devide by 2

View File

@ -49,7 +49,6 @@ build_flags =
-D LV_LVGL_H_INCLUDE_SIMPLE ; for lv_drivers
-D LV_COMP_CONF_INCLUDE_SIMPLE ; for components
-D LV_SYMBOL_DEF_H ; don't load default symbol defines
-D LV_MEM_FULL_DEFRAG_CNT=4 ; stability: run lv_mem_defrag more frequently
; -- ESP build options ------------------------------------
-D SPIFFS_TEMPORAL_FD_CACHE ; speedup opening recent files
; -- ArduinoJson build options ----------------------------
@ -60,23 +59,23 @@ build_flags =
; -- Hasp build options ----------------------------
-D HASP_VER_MAJ=0
-D HASP_VER_MIN=5
-D HASP_VER_REV=2
-D HASP_LOG_LEVEL=LOG_LEVEL_TRACE
-D HASP_VER_MIN=6
-D HASP_VER_REV=0
-D HASP_LOG_LEVEL=LOG_LEVEL_OUTPUT
${override.build_flags}
; -- Shared library dependencies in all environments
; Warning : don't put comments after github links => causes infinite download loop
lib_deps =
bxparks/AceButton@^1.8.2 ; GPIO button library
bblanchon/ArduinoJson@^6.17.3 ; Json(l) parser
bxparks/AceButton@^1.8.3 ; GPIO button library
bblanchon/ArduinoJson@^6.18.0 ; Json(l) parser
bblanchon/StreamUtils@1.6.0 ; for EEPromStream
knolleary/PubSubClient@^2.8.0 ; MQTT client
git+https://github.com/fvanroie/ConsoleInput.git
;git+https://github.com/andrethomas/TasmotaSlave.git
;git+https://github.com/lvgl/lvgl.git
lvgl/lvgl@^7.11.0 ; from PIO library
bodmer/TFT_eSPI@^2.3.62 ; Tft SPI drivers EXACT version 2.3.5 has compile error
bodmer/TFT_eSPI@^2.3.69
;git+https://github.com/Bodmer/TFT_eSPI.git
; ------ Unused / Test libraries
;https://github.com/netwizeBE/TFT_eSPI.git
@ -91,11 +90,14 @@ src_filter = +<*> -<.git/> -<examples/> -<test/> -<tests/> -<stm32f4/> -<lv_font
; -- Platform specific build flags
[esp32]
framework = arduino
platform = espressif32
platform = espressif32@^3.2.0
board_upload.flash_size=4MB
board_upload.maximum_size = 4194304
board_build.partitions = user_setups/esp32/partition_app1704k_spiffs720k.csv
board_build.partitions = user_setups/esp32/partitions_4MB.csv
board_build.filesystem = littlefs
board_build.embed_files =
data/edit.htm.gz
; ----- crash reporter
monitor_filters = esp32_exception_decoder
@ -113,20 +115,26 @@ build_flags =
-D HASP_CONSOLE_BUFFER=256 ; maximum length of a console/telnet command
-D NO_GLOBAL_HTTPUPDATE ; dont instantiate httpUpdate
; -- lvgl build options -----------------------------
-D LV_MEM_SIZE=61440U ; 60kB lvgl memory
-D LV_MEM_SIZE=49152U ; 48 kB lvgl memory
-D LV_ATTRIBUTE_FAST_MEM=IRAM_ATTR
-D LV_ATTRIBUTE_TASK_HANDLER=IRAM_ATTR
;-D LV_FS_PC_PATH="//littlefs" ; this needs to match the vfs mount pount
-D LODEPNG_NO_COMPILE_ALLOCATORS ; use PSram functions
; -- ArduinoJson build options ----------------------------
-D ARDUINOJSON_ENABLE_PROGMEM=1 ; for PROGMEM arguments
; -- tft_espi build options ------------------------
;-D USE_DMA_TO_TFT
; -- openHASP build options ------------------------
-D HASP_ATTRIBUTE_FAST_MEM=IRAM_ATTR
-D HASP_USE_TELNET=1
;-D HASP_USE_SPIFFS=1
-D HASP_USE_LITTLEFS=1
;-D HASP_USE_EEPROM=1
-D HASP_USE_CONFIG=1 ; Native application, not library
-D LV_LOG_TRACE_TIMER=1
-D HASP_USE_PNGDECODE=1
; -- LittleFS build options ------------------------
-D CONFIG_LITTLEFS_FOR_IDF_3_2
;-D CONFIG_LITTLEFS_FOR_IDF_3_2 ; obsolete in IDF 3.3
lib_ignore =
GxTFT
@ -141,12 +149,14 @@ lib_ignore =
lib_deps =
LittleFS_esp32
git+https://github.com/lvgl/lv_lib_png.git
ps_ram =
-DBOARD_HAS_PSRAM
-mfix-esp32-psram-cache-issue
extra_scripts =
tools/littlefsbuilder.py
tools/esp_merge_bin.py
tools/analyze_elf.py
; ${env.extra_scripts}
@ -185,10 +195,13 @@ build_flags=
-D PIO_FRAMEWORK_ARDUINO_LWIP2_LOW_MEMORY
; -- lvgl build options -----------------------------
-D LV_MEM_SIZE=12288U ; 12kB lvgl memory
-D LV_ATTRIBUTE_FAST_MEM=
-D LV_ATTRIBUTE_TASK_HANDLER=
; -- ArduinoJson build options ----------------------------
-D ARDUINOJSON_ENABLE_PROGMEM=1 ; for PROGMEM arguments
-D ARDUINOJSON_ENABLE_STD_STRING=1 ; for std::string
; -- openHASP build options -------------------------
-D HASP_ATTRIBUTE_FAST_MEM=
-D HASP_USE_TELNET=1
;-D HASP_USE_SPIFFS=1
-D HASP_USE_LITTLEFS=1

View File

@ -5,7 +5,7 @@
[platformio]
extra_configs =
; Uncomment or edit the lines to show more User Setups in the PIO sidebar
; Uncomment or edit the lines to show more User Setups in the PIO sidebar
; user_setups/darwin_sdl/*.ini
; user_setups/esp32/*.ini
; user_setups/esp8266/*.ini
@ -21,7 +21,7 @@ build_flags =
;region -- Default Build Environments : Used when Build All ---
extra_default_envs =
; Comment unneeded environments or create extra
; Uncomment specific environments or create extra:
; arduitouch-esp32_ili9341
; d1-mini-esp32_ili9341
; d1-mini-esp8266_ili9341

View File

@ -16,4 +16,24 @@ const char* BaseDevice::get_model()
return PIOENV;
#endif
}
const char* BaseDevice::get_version()
{
#ifdef HASP_MODEL
return (QUOTE(HASP_VER_MAJ) "." QUOTE(HASP_VER_MIN) "." QUOTE(HASP_VER_REV));
#else
return PIOENV;
#endif
}
const char* BaseDevice::get_hostname()
{
return _hostname; //.c_str();
}
void BaseDevice::set_hostname(const char* hostname)
{
strncpy(_hostname, hostname, STR_LEN_HOSTNAME);
}
} // namespace dev

View File

@ -18,6 +18,10 @@
#include "Windows.h"
#endif
#include "ArduinoJson.h"
#define STR_LEN_HOSTNAME 64
namespace dev {
class BaseDevice {
@ -27,13 +31,9 @@ class BaseDevice {
virtual void reboot()
{}
virtual const char* get_hostname()
{
return "";
}
virtual void set_hostname(const char*)
{}
virtual const char* get_core_version()
const char* get_hostname();
void set_hostname(const char*);
const char* get_core_version()
{
return "";
}
@ -41,8 +41,12 @@ class BaseDevice {
{
return "";
}
const char* get_model();
virtual const char* get_model();
virtual const char* get_version();
virtual const char* get_hardware_id()
{
return "";
}
virtual void init()
{}
virtual void show_info()
@ -83,10 +87,22 @@ class BaseDevice {
{
return 0;
}
virtual void get_info(JsonDocument& doc)
{}
virtual bool is_system_pin(uint8_t pin)
{
return false;
}
virtual std::string gpio_name(uint8_t pin)
{
char buffer[8];
snprintf(buffer, sizeof(buffer), "%d", pin);
return buffer;
}
private:
// std::string _hostname;
char _hostname[STR_LEN_HOSTNAME];
};
} // namespace dev

View File

@ -5,25 +5,119 @@
#include "Arduino.h"
#include <Esp.h>
#include <WiFi.h>
#include "esp_system.h"
#include "hasp_conf.h"
#include "../device.h"
#include "esp32.h"
#include <rom/rtc.h> // needed to get the ResetInfo
#include "driver/adc.h"
#include "esp_adc_cal.h"
#include "hasp_conf.h"
#include "../device.h"
#include "esp32.h"
#include "hasp_debug.h"
#define BACKLIGHT_CHANNEL 0
namespace dev {
static String esp32ResetReason(uint8_t cpuid)
{
if(cpuid > 1) {
return F("Invalid CPU id");
}
RESET_REASON reason = rtc_get_reset_reason(cpuid);
String resetReason((char*)0);
resetReason.reserve(128);
resetReason += F("CPU");
resetReason += cpuid;
resetReason += F(": ");
switch(reason) {
case 1:
resetReason += F("POWERON");
break; /**<1, Vbat power on reset*/
case 3:
resetReason += F("SW");
break; /**<3, Software reset digital core*/
case 4:
resetReason += F("OWDT");
break; /**<4, Legacy watch dog reset digital core*/
case 5:
resetReason += F("DEEPSLEEP");
break; /**<5, Deep Sleep reset digital core*/
case 6:
resetReason += F("SDIO");
break; /**<6, Reset by SLC module, reset digital core*/
case 7:
resetReason += F("TG0WDT_SYS");
break; /**<7, Timer Group0 Watch dog reset digital core*/
case 8:
resetReason += F("TG1WDT_SYS");
break; /**<8, Timer Group1 Watch dog reset digital core*/
case 9:
resetReason += F("RTCWDT_SYS");
break; /**<9, RTC Watch dog Reset digital core*/
case 10:
resetReason += F("INTRUSION");
break; /**<10, Instrusion tested to reset CPU*/
case 11:
resetReason += F("TGWDT_CPU");
break; /**<11, Time Group reset CPU*/
case 12:
resetReason += F("SW_CPU");
break; /**<12, Software reset CPU*/
case 13:
resetReason += F("RTCWDT_CPU");
break; /**<13, RTC Watch dog Reset CPU*/
case 14:
resetReason += F("EXT_CPU");
break; /**<14, for APP CPU, reseted by PRO CPU*/
case 15:
resetReason += F("RTCWDT_BROWN_OUT");
break; /**<15, Reset when the vdd voltage is not stable*/
case 16:
resetReason += F("RTCWDT_RTC");
break; /**<16, RTC Watch dog reset digital core and rtc module*/
default:
resetReason += F("NO_MEAN");
return resetReason;
}
resetReason += F("_RESET");
return resetReason;
}
static void halGetResetInfo(String& resetReason)
{
resetReason = String(esp32ResetReason(0));
resetReason += F(" / ");
resetReason += String(esp32ResetReason(1));
}
Esp32Device::Esp32Device()
{
BaseDevice::set_hostname(MQTT_NODENAME);
_backlight_invert = (TFT_BACKLIGHT_ON == LOW);
_backlight_power = 1;
_backlight_level = 255;
_backlight_pin = TFT_BCKL;
/* fill unique identifier with wifi mac */
byte mac[6];
WiFi.macAddress(mac);
_hardware_id.reserve(13);
for(int i = 0; i < 6; ++i) {
if(mac[i] < 0x10) _hardware_id += "0";
_hardware_id += String(mac[i], HEX).c_str();
}
}
void Esp32Device::reboot()
{
ESP.restart();
esp_sleep_enable_timer_wakeup(50 * 1000);
esp_deep_sleep_start();
// ESP.restart();
}
void Esp32Device::show_info()
@ -31,23 +125,14 @@ void Esp32Device::show_info()
LOG_VERBOSE(TAG_DEV, F("Processor : ESP32"));
LOG_VERBOSE(TAG_DEV, F("CPU freq. : %i MHz"), get_cpu_frequency());
// LOG_VERBOSE(TAG_DEV, F("Voltage : %2.2f V"), ESP.getVcc() / 918.0); // 918 empirically determined
}
const char* Esp32Device::get_hostname()
{
return _hostname.c_str();
}
void Esp32Device::set_hostname(const char* hostname)
{
_hostname = hostname;
if(_sketch_size == 0) _sketch_size = ESP.getSketchSize(); // slow: takes ~1 second
}
const char* Esp32Device::get_core_version()
{
return esp_get_idf_version(); // == ESP.getSdkVersion();
}
const char* Esp32Device::get_chip_model()
{
esp_chip_info_t chip_info;
@ -76,6 +161,11 @@ const char* Esp32Device::get_chip_model()
// model += chip_info.revision;
}
const char* Esp32Device::get_hardware_id()
{
return _hardware_id.c_str();
}
void Esp32Device::set_backlight_pin(uint8_t pin)
{
_backlight_pin = pin;
@ -157,6 +247,35 @@ bool Esp32Device::is_system_pin(uint8_t pin)
return false;
}
void Esp32Device::get_info(JsonDocument& doc)
{
char size_buf[64];
String buffer((char*)0);
buffer.reserve(64);
JsonObject info = doc.createNestedObject(F(D_INFO_MODULE));
/* ESP Stats */
buffer = String(get_cpu_frequency());
buffer += F("MHz");
info[F(D_INFO_MODEL)] = get_chip_model(); // 10ms
info[F(D_INFO_FREQUENCY)] = buffer;
info[F(D_INFO_CORE_VERSION)] = get_core_version();
halGetResetInfo(buffer);
info[F(D_INFO_RESET_REASON)] = buffer;
Parser::format_bytes(ESP.getFlashChipSize(), size_buf, sizeof(size_buf)); // 25ms
info[F(D_INFO_FLASH_SIZE)] = size_buf;
if(_sketch_size == 0) _sketch_size = ESP.getSketchSize(); // slow: takes ~1 second
Parser::format_bytes(_sketch_size, size_buf, sizeof(size_buf));
info[F(D_INFO_SKETCH_USED)] = size_buf;
Parser::format_bytes(ESP.getFreeSketchSpace(), size_buf, sizeof(size_buf));
info[F(D_INFO_SKETCH_FREE)] = size_buf;
}
} // namespace dev
#if defined(LANBONL8)

View File

@ -14,21 +14,14 @@ namespace dev {
class Esp32Device : public BaseDevice {
public:
Esp32Device()
{
_hostname = MQTT_NODENAME;
_backlight_invert = (TFT_BACKLIGHT_ON == LOW);
_backlight_power = 1;
_backlight_level = 255;
_backlight_pin = TFT_BCKL;
}
Esp32Device();
void reboot() override;
void show_info() override;
const char* get_hostname();
void set_hostname(const char*);
const char* get_core_version();
const char* get_chip_model();
const char* get_hardware_id();
void set_backlight_pin(uint8_t pin) override;
void set_backlight_level(uint8_t val) override;
@ -40,11 +33,13 @@ class Esp32Device : public BaseDevice {
size_t get_free_heap() override;
uint8_t get_heap_fragmentation() override;
uint16_t get_cpu_frequency() override;
void get_info(JsonDocument& doc) override;
bool is_system_pin(uint8_t pin) override;
private:
std::string _hostname;
std::string _hardware_id;
uint32_t _sketch_size; // cached because function is slow
uint8_t _backlight_pin;
uint8_t _backlight_level;

View File

@ -8,13 +8,32 @@
#include "Arduino.h"
#include "dev/esp32/esp32.h"
#include "driver/pcnt.h" // Pulse count driver
#include "driver/adc.h"
#include "esp_adc_cal.h"
#include "hasp_conf.h"
#include "hasp_debug.h"
#define BACKLIGHT_CHANNEL 0
#define BACKLIGHT_CHANNEL 15
// https://esp32.com/viewtopic.php?t=14660
#define PCNT_FREQ_UNIT PCNT_UNIT_0 // Pulse Count Unit 0
#define PCNT_H_LIM_VAL 10000 // upper limit of counting max. 32767, write +1 to overflow counter, when reached
#define PCNT_L_LIM_VAL -10000 // lower limit of counting max. 32767, write +1 to overflow counter, when reached
#define PCNT_INPUT_SIG_IO 35 // Pulse Input GPIO
#define PCNT_INPUT_CTRL_IO 36 // Pulse Control GPIO
#define PCNT_FILTER_VAL 300 // filter (damping, inertia) value for avoiding glitches in the count, max. 1023
#define MEASURED_WATTS 1580
#define MEASURED_PULSES_PER_SECOND 281
// Per second
int16_t PulseCounter = 0; // pulse counter, max. value is 32535
int OverflowCounter = 0; // pulse counter overflow counter
uint32_t totalPulses;
pcnt_isr_handle_t user_isr_handle = NULL; // interrupt handler - not used
hw_timer_t* timer = NULL; // Instancia do timer
#define REF_VOLTAGE 1100
esp_adc_cal_characteristics_t* adc_chars =
@ -51,8 +70,49 @@ static void print_char_val_type(esp_adc_cal_value_t val_type)
}
}
//------------------------------------------------------------------------------------
void IRAM_ATTR energy_pulse_counter_overflow(void* arg)
{ // Interrupt for overflow of pulse counter
OverflowCounter = OverflowCounter + 1; // increase overflow counter
PCNT.int_clr.val = BIT(PCNT_FREQ_UNIT); // clean overflow flag
pcnt_counter_clear(PCNT_FREQ_UNIT); // zero and reset of pulse counter unit
}
//------------------------------------------------------------
void energy_pulse_counter_init()
{
pcnt_config_t pcntFreqConfig = {}; // initialise pulse counter
pcntFreqConfig.pulse_gpio_num = PCNT_INPUT_SIG_IO; // pin assignment for pulse counter
pcntFreqConfig.ctrl_gpio_num = PCNT_INPUT_CTRL_IO; // pin assignment for control
pcntFreqConfig.channel = PCNT_CHANNEL_0; // select channel 0 of pulse counter unit 0
pcntFreqConfig.unit = PCNT_FREQ_UNIT; // select ESP32 pulse counter unit 0
pcntFreqConfig.pos_mode = PCNT_COUNT_INC; // count rising edges (=change from low to high logical level) as pulses
pcntFreqConfig.neg_mode = PCNT_COUNT_DIS; // Conta na subida do pulso
pcntFreqConfig.lctrl_mode = PCNT_MODE_REVERSE;
pcntFreqConfig.hctrl_mode = PCNT_MODE_KEEP,
pcntFreqConfig.counter_h_lim = PCNT_H_LIM_VAL; // set upper limit of counting
pcntFreqConfig.counter_l_lim = PCNT_L_LIM_VAL; // set lower limit of counting
pcnt_unit_config(&pcntFreqConfig); // configure rigisters of the pulse counter
pcnt_counter_pause(PCNT_FREQ_UNIT); // pause puls counter unit
pcnt_counter_clear(PCNT_FREQ_UNIT); // zero and reset of pulse counter unit
pcnt_event_enable(PCNT_FREQ_UNIT, PCNT_EVT_H_LIM); // enable event for interrupt on reaching upper limit of counting
pcnt_isr_register(energy_pulse_counter_overflow, NULL, 0,
&user_isr_handle); // configure register overflow interrupt handler
pcnt_intr_enable(PCNT_FREQ_UNIT); // enable overflow interrupt
pcnt_set_filter_value(PCNT_FREQ_UNIT, PCNT_FILTER_VAL); // set damping, inertia
pcnt_filter_enable(PCNT_FREQ_UNIT); // enable counter glitch filter (damping)
pcnt_counter_resume(PCNT_FREQ_UNIT); // resume counting on pulse counter unit
}
void LanbonL8::init()
{
energy_pulse_counter_init();
// Check if Two Point or Vref are burned into eFuse
check_efuse();
@ -64,6 +124,30 @@ void LanbonL8::init()
print_char_val_type(val_type);
}
void LanbonL8::loop_5s()
{ // function for reading pulse counter (for timer)
pcnt_get_counter_value(PCNT_FREQ_UNIT, &PulseCounter); // get pulse counter value - maximum value is 16 bits
uint32_t newPulses = OverflowCounter * 10000 + PulseCounter;
uint32_t delta = newPulses - totalPulses;
totalPulses = newPulses;
int16_t watt_10 = DEC / 5 * delta * MEASURED_WATTS / MEASURED_PULSES_PER_SECOND;
int16_t kwh_10 = DEC * totalPulses * MEASURED_WATTS / MEASURED_PULSES_PER_SECOND / 3600 / 1000;
LOG_VERBOSE(TAG_DEV, F("Pulse Counter %d.%d W / %d / %d.%d kWh"), watt_10 / DEC, watt_10 % DEC, totalPulses,
kwh_10 / DEC, kwh_10 % DEC);
}
//------------------------------------------------------------
void Read_Reset_PCNT()
{ // function for reading pulse counter (for timer)
pcnt_get_counter_value(PCNT_FREQ_UNIT, &PulseCounter); // get pulse counter value - maximum value is 16 bits
// resetting counter as if example, delet for application in PiedPiperS
OverflowCounter = 0; // set overflow counter to zero
pcnt_counter_clear(PCNT_FREQ_UNIT); // zero and reset of pulse counter unit
// conterOK = true; // not in use, copy from example code
// ########################################
}
} // namespace dev
dev::LanbonL8 haspDevice;

View File

@ -8,11 +8,14 @@
#if defined(LANBONL8)
void Read_PCNT();
namespace dev {
class LanbonL8 : public Esp32Device {
public:
void init();
void loop_5s();
};
} // namespace dev

View File

@ -5,6 +5,7 @@
#include "Arduino.h"
#include <Esp.h>
#include <ESP8266WiFi.h>
#include "esp8266.h"
@ -15,6 +16,25 @@
namespace dev {
Esp8266Device::Esp8266Device()
{
_hostname = MQTT_NODENAME;
_backlight_invert = (TFT_BACKLIGHT_ON == LOW);
_backlight_power = 1;
_backlight_level = 255;
_core_version = ESP.getCoreVersion().c_str();
_backlight_pin = TFT_BCKL;
/* fill unique identifier with wifi mac */
byte mac[6];
WiFi.macAddress(mac);
_hardware_id.reserve(13);
for(int i = 0; i < 6; ++i) {
if(mac[i] < 0x10) _hardware_id += "0";
_hardware_id += String(mac[i], HEX).c_str();
}
}
void Esp8266Device::reboot()
{
ESP.restart();
@ -46,6 +66,11 @@ const char* Esp8266Device::get_chip_model()
return "ESP8266";
}
const char* Esp8266Device::get_hardware_id()
{
return _hardware_id.c_str();
}
void Esp8266Device::set_backlight_pin(uint8_t pin)
{
_backlight_pin = pin;

View File

@ -14,15 +14,7 @@ namespace dev {
class Esp8266Device : public BaseDevice {
public:
Esp8266Device()
{
_hostname = MQTT_NODENAME;
_backlight_invert = (TFT_BACKLIGHT_ON == LOW);
_backlight_power = 1;
_backlight_level = 255;
_core_version = ESP.getCoreVersion().c_str();
_backlight_pin = TFT_BCKL;
}
Esp8266Device();
void reboot() override;
void show_info() override;
@ -31,6 +23,7 @@ class Esp8266Device : public BaseDevice {
void set_hostname(const char*);
const char* get_core_version();
const char* get_chip_model();
const char* get_hardware_id();
void set_backlight_pin(uint8_t pin) override;
void set_backlight_level(uint8_t val) override;
@ -47,6 +40,7 @@ class Esp8266Device : public BaseDevice {
private:
std::string _hostname;
std::string _hardware_id;
std::string _core_version;
uint8_t _backlight_pin;

View File

@ -30,7 +30,7 @@ PosixDevice::PosixDevice()
// LOG_VERBOSE(0,"Version: %s", uts.version);
// LOG_VERBOSE(0,"Machine: %s", uts.machine);
char version[128];
char version[256];
snprintf(version, sizeof(version), "%s %s", uts.sysname, uts.release);
_core_version = version;
_chip_model = uts.machine;
@ -66,21 +66,29 @@ const char* PosixDevice::get_hostname()
{
return _hostname.c_str();
}
void PosixDevice::set_hostname(const char* hostname)
{
_hostname = hostname;
monitor_title(hostname);
// SDL_SetWindowTitle(monitor.window, hostname);
}
const char* PosixDevice::get_core_version()
{
return _core_version.c_str();
}
const char* PosixDevice::get_chip_model()
{
return _chip_model.c_str();
}
const char* PosixDevice::get_hardware_id()
{
return "223344556677";
}
void PosixDevice::set_backlight_pin(uint8_t pin)
{
// PosixDevice::backlight_pin = pin;

View File

@ -38,6 +38,7 @@ class PosixDevice : public BaseDevice {
void set_hostname(const char*);
const char* get_core_version();
const char* get_chip_model();
const char* get_hardware_id();
void set_backlight_pin(uint8_t pin);
void set_backlight_level(uint8_t val);

View File

@ -30,6 +30,7 @@ const char* Stm32f4Device::get_hostname()
{
return _hostname.c_str();
}
void Stm32f4Device::set_hostname(const char* hostname)
{
_hostname = hostname;
@ -40,6 +41,14 @@ const char* Stm32f4Device::get_core_version()
// return ESP.getCoreVersion().c_str();
}
const char* Stm32f4Device::get_hardware_id()
{
// https://stm32duinoforum.com/forum/viewtopic_f_29_t_2909_start_10.html
// Serial.println("UID [HEX] : "+String(*(uint32_t*)(UID_BASE), HEX)+" "+String(*(uint32_t*)(UID_BASE+0x04),
// HEX)+" "+String(*(uint32_t*)(UID_BASE+0x08), HEX));
return _hardware_id.c_str();
}
void Stm32f4Device::set_backlight_pin(uint8_t pin)
{
_backlight_pin = pin;

View File

@ -30,6 +30,7 @@ class Stm32f4Device : public BaseDevice {
void set_hostname(const char*);
const char* get_core_version();
const char* get_chip_model();
const char* get_chip_hardware_id();
void set_backlight_pin(uint8_t pin) override;
void set_backlight_level(uint8_t val) override;
@ -46,6 +47,7 @@ class Stm32f4Device : public BaseDevice {
private:
std::string _hostname;
std::string _hardware_id;
uint8_t _backlight_pin;
uint8_t _backlight_level;

View File

@ -55,11 +55,17 @@ const char* Win32Device::get_core_version()
{
return _core_version.c_str();
}
const char* Win32Device::get_chip_model()
{
return "SDL2";
}
const char* Win32Device::get_hardware_id()
{
return "112233445566";
}
void Win32Device::set_backlight_pin(uint8_t pin)
{
// Win32Device::_backlight_pin = pin;

View File

@ -59,6 +59,7 @@ class Win32Device : public BaseDevice {
void set_hostname(const char*);
const char* get_core_version();
const char* get_chip_model();
const char* get_hardware_id();
void set_backlight_pin(uint8_t pin);
void set_backlight_level(uint8_t val);

View File

@ -1,10 +1,10 @@
/* MIT License - Copyright (c) 2019-2021 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#include "hasplib.h"
#include "hasp_drv_touch.h"
#include "hasp/hasp.h"
#include "drv/tft_driver.h"
#include "lvgl.h"
#if TOUCH_DRIVER == 2046
#if defined(USE_FSMC)
@ -102,13 +102,13 @@ static inline bool drv_touchpad_getXY(int16_t* touchX, int16_t* touchY)
touched = Touch_getXY(&normal_x, &normal_y, false);
#elif TOUCH_DRIVER == 5206
touched = FT5206_getXY(&normal_x, &normal_y, false);
touched = FT5206_getXY(&normal_x, &normal_y, false); // no debug
#elif TOUCH_DRIVER == 6336
touched = FT6336U_getXY(&normal_x, &normal_y, true);
touched = FT6336U_getXY(&normal_x, &normal_y, false); // no debug
#elif TOUCH_DRIVER == 610
touched = STMPE610_getXY(&normal_x, &normal_y, drv_touch_rotation, true);
touched = STMPE610_getXY(&normal_x, &normal_y, drv_touch_rotation, false); // no debug
#else
// xpt2046_alt_drv_read(indev_driver, data);
@ -174,7 +174,7 @@ static inline bool drv_touchpad_getXY(int16_t* touchX, int16_t* touchY)
return touched;
}
bool drv_touch_read(lv_indev_drv_t* indev_driver, lv_indev_data_t* data)
IRAM_ATTR bool drv_touch_read(lv_indev_drv_t* indev_driver, lv_indev_data_t* data)
{
#if TOUCH_DRIVER > 0
int16_t touchX = 0;
@ -211,7 +211,7 @@ bool drv_touch_read(lv_indev_drv_t* indev_driver, lv_indev_data_t* data)
return false;
}
void drv_touch_loop()
IRAM_ATTR void drv_touch_loop()
{
#if TOUCH_DRIVER == 911
GT911_loop();

View File

@ -4,14 +4,14 @@
#ifndef HASP_DRV_TOUCH_H
#define HASP_DRV_TOUCH_H
#include "lvgl.h"
#include "hasplib.h"
#ifndef TOUCH_DRIVER
#define TOUCH_DRIVER -1 // No Touch
#endif
void drv_touch_init(uint8_t rotation);
bool drv_touch_read(lv_indev_drv_t* indev_driver, lv_indev_data_t* data);
void drv_touch_loop();
IRAM_ATTR bool drv_touch_read(lv_indev_drv_t* indev_driver, lv_indev_data_t* data);
IRAM_ATTR void drv_touch_loop();
#endif

View File

@ -49,7 +49,7 @@ void TftSdl::init(int w, int h)
/* Add a display
* Use the 'monitor' driver which creates window on PC's monitor to simulate a display*/
monitor_init(MONITOR_HOR_RES, MONITOR_VER_RES);
monitor_init(w, h); // (MONITOR_HOR_RES, MONITOR_VER_RES);
monitor_title(haspDevice.get_hostname());
/* Add the mouse as input device

View File

@ -27,11 +27,11 @@ void TftEspi::show_info()
tft.getSetup(tftSetup);
LOG_VERBOSE(TAG_TFT, F("TFT_eSPI : v%s"), tftSetup.version.c_str());
LOG_VERBOSE(TAG_TFT, F("Transactns : %s"), (tftSetup.trans == 1) ? PSTR("Yes") : PSTR("No"));
LOG_VERBOSE(TAG_TFT, F("Transactns : %s"), (tftSetup.trans == 1) ? PSTR(D_YES) : PSTR(D_NO));
LOG_VERBOSE(TAG_TFT, F("Interface : %s"), (tftSetup.serial == 1) ? PSTR("SPI") : PSTR("Parallel"));
#if defined(ARDUINO_ARCH_ESP8266)
LOG_VERBOSE(TAG_TFT, F("SPI overlap: %s"), (tftSetup.overlap == 1) ? PSTR("Yes") : PSTR("No"));
LOG_VERBOSE(TAG_TFT, F("SPI overlap: %s"), (tftSetup.overlap == 1) ? PSTR(D_YES) : PSTR(D_NO));
#endif
if(tftSetup.tft_driver != 0xE9D) // For ePaper displays the size is defined in the sketch
@ -117,25 +117,33 @@ void TftEspi::set_rotation(uint8_t rotation)
void TftEspi::set_invert(bool invert)
{
char buffer[4];
memcpy_P(buffer, invert ? PSTR("yes") : PSTR("no"), sizeof(buffer));
memcpy_P(buffer, invert ? PSTR(D_YES) : PSTR(D_NO), sizeof(buffer));
LOG_VERBOSE(TAG_TFT, F("Invert Disp: %s"), buffer);
tft.invertDisplay(invert);
}
void TftEspi::flush_pixels(lv_disp_drv_t* disp, const lv_area_t* area, lv_color_t* color_p)
/* Update TFT */
void IRAM_ATTR TftEspi::flush_pixels(lv_disp_drv_t* disp, const lv_area_t* area, lv_color_t* color_p)
{
size_t len = lv_area_get_size(area);
uint32_t w = (area->x2 - area->x1 + 1);
uint32_t h = (area->y2 - area->y1 + 1);
// size_t len = lv_area_get_size(area);
uint32_t len = w * h;
/* Update TFT */
tft.startWrite(); /* Start new TFT transaction */
tft.setWindow(area->x1, area->y1, area->x2, area->y2); /* set the working window */
#ifdef USE_DMA_TO_TFT
tft.pushPixelsDMA((uint16_t*)color_p, len); /* Write words at once */
tft.startWrite(); /* Start new TFT transaction */
// tft.setWindow(area->x1, area->y1, area->x2, area->y2);
tft.setAddrWindow(area->x1, area->y1, w, h); /* set the working window */
tft.pushPixelsDMA((uint16_t*)color_p, len); /* Write words at once */
tft.endWrite(); /* terminate TFT transaction */
#else
tft.pushPixels((uint16_t*)color_p, len); /* Write words at once */
tft.startWrite(); /* Start new TFT transaction */
// tft.setWindow(area->x1, area->y1, area->x2, area->y2);
tft.setAddrWindow(area->x1, area->y1, w, h); /* set the working window */
tft.pushPixels((uint16_t*)color_p, len); /* Write words at once */
tft.endWrite(); /* terminate TFT transaction */
#endif
tft.endWrite(); /* terminate TFT transaction */
/* Tell lvgl that flushing is done */
lv_disp_flush_ready(disp);

View File

@ -52,7 +52,7 @@ class TftEspi : BaseTft {
if(pin != -1) {
char buffer[64];
snprintf_P(buffer, sizeof(buffer), PSTR("%-11s: %s (GPIO %02d)"), String(pinfunction).c_str(),
halGpioName(pin).c_str(), pin);
haspDevice.gpio_name(pin).c_str(), pin);
LOG_VERBOSE(TAG_TFT, buffer);
}
}

View File

@ -1,17 +1,17 @@
#if TOUCH_DRIVER == 6336
#include <Wire.h>
#include "FT6336U.h"
#include "ArduinoLog.h"
#include <Wire.h>
#include "FT6336U.h"
#include "ArduinoLog.h"
#include "hasp_drv_ft6336u.h"
#include "hasp_drv_ft6336u.h"
#define RST_PIN (TOUCH_RST) // -1 if pin is connected to VCC else set pin number
#define RST_PIN (TOUCH_RST) // -1 if pin is connected to VCC else set pin number
FT6336U * touchpanel;
FT6336U* touchpanel;
// Read touch points
bool FT6336U_getXY(int16_t * touchX, int16_t * touchY, bool debug)
HASP_ATTRIBUTE_FAST_MEM bool FT6336U_getXY(int16_t* touchX, int16_t* touchY, bool debug)
{
if(touchpanel->read_touch_number() != 1) return false;
@ -20,7 +20,7 @@ bool FT6336U_getXY(int16_t * touchX, int16_t * touchY, bool debug)
return true;
}
void scan(TwoWire & i2c)
void scan(TwoWire& i2c)
{
byte error, address;
int nDevices;

View File

@ -8,7 +8,7 @@
#include "hasp_debug.h" // for TAG_DRVR
bool FT6336U_getXY(int16_t* touchX, int16_t* touchY, bool debug);
HASP_ATTRIBUTE_FAST_MEM bool FT6336U_getXY(int16_t* touchX, int16_t* touchY, bool debug);
void FT6336U_init();
#endif

View File

@ -1,69 +1,71 @@
#if TOUCH_DRIVER == 610
#include <SPI.h>
#include "Adafruit_STMPE610.h"
#include "ArduinoLog.h"
#include "hasp_conf.h"
#include "hasp_drv_stmpe610.h"
#include <SPI.h>
#include "Adafruit_STMPE610.h"
#include "ArduinoLog.h"
#include "hasp_drv_stmpe610.h"
// This is calibration data for the raw touch data to the screen coordinates
#define TS_MINX 3800
#define TS_MAXX 100
#define TS_MINY 100
#define TS_MAXY 3750
#define TS_MINX 3800
#define TS_MAXX 100
#define TS_MINY 100
#define TS_MAXY 3750
static Adafruit_STMPE610 touch = Adafruit_STMPE610(STMPE_CS);
// Read touch points from global variable
bool IRAM_ATTR STMPE610_getXY(int16_t * touchX, int16_t * touchY, uint8_t touchRotation, bool debug)
HASP_ATTRIBUTE_FAST_MEM bool STMPE610_getXY(int16_t* touchX, int16_t* touchY, uint8_t touchRotation, bool debug)
{
uint16_t x, y;
uint8_t z;
if(! touch.touched()) return false;
if(!touch.touched()) return false;
while (! touch.bufferEmpty()) {
while(!touch.bufferEmpty()) {
touch.readData(&x, &y, &z);
if(debug) Log.trace(TAG_DRVR, F("STMPE610: x=%i y=%i z=%i r=%i"), x, y, z, touchRotation);
}
touch.writeRegister8(STMPE_INT_STA, 0xFF);
if (1 == touchRotation) {
#if HX8357D_DRIVER == 1
if(1 == touchRotation) {
#if HX8357D_DRIVER == 1
y = map(y, TS_MINX, TS_MAXX, 0, TFT_HEIGHT);
x = map(x, TS_MINY, TS_MAXY, TFT_WIDTH, 0);
#else
#else
x = map(x, TS_MAXX, TS_MINX, 0, TFT_WIDTH);
y = map(y, TS_MAXY, TS_MINY, 0, TFT_HEIGHT);
#endif
} else if (2 == touchRotation) {
#if HX8357D_DRIVER == 1
#endif
} else if(2 == touchRotation) {
#if HX8357D_DRIVER == 1
x = map(x, TS_MAXX, TS_MINX, TFT_WIDTH, 0);
y = map(y, TS_MAXY, TS_MINY, 0, TFT_HEIGHT);
#else
#else
x = map(x, TS_MAXX, TS_MINX, 0, TFT_WIDTH);
y = map(y, TS_MAXY, TS_MINY, 0, TFT_HEIGHT);
#endif
#endif
} else {
#if HX8357D_DRIVER == 1
#if HX8357D_DRIVER == 1
x = map(x, TS_MINX, TS_MAXX, TFT_WIDTH, 0);
y = map(y, TS_MINY, TS_MAXY, 0, TFT_HEIGHT);
#else
#else
x = map(x, TS_MINX, TS_MAXX, 0, TFT_WIDTH);
y = map(y, TS_MINY, TS_MAXY, 0, TFT_HEIGHT);
#endif
#endif
}
*touchX = x;
*touchY = y;
return true;
}
void STMPE610_init()
{
if (! touch.begin()) {
Log.trace(TAG_DRVR, F("STMPE610 not found!"));
LOG_INFO(TAG_DRVR, F("STMPE610 " D_SERVICE_STARTING));
if(!touch.begin()) {
LOG_ERROR(TAG_DRVR, F("STMPE610 " D_SERVICE_START_FAILED));
} else {
Log.trace(TAG_DRVR, F("STMPE610 touch driver started"));
LOG_INFO(TAG_DRVR, F("STMPE610 " D_SERVICE_STARTED));
}
}
#endif

View File

@ -6,9 +6,9 @@
#if TOUCH_DRIVER == 610
#include "hasp_debug.h" // for TAG_DRVR
#include "hasp_debug.h" // for TAG_DRVR
bool IRAM_ATTR STMPE610_getXY(int16_t * touchX, int16_t * touchY, uint8_t touchRotation, bool debug);
HASP_ATTRIBUTE_FAST_MEM bool STMPE610_getXY(int16_t* touchX, int16_t* touchY, uint8_t touchRotation, bool debug);
void STMPE610_init();
#endif

View File

@ -8,7 +8,6 @@
#if defined(TOUCH_CS)
#include "hal/hasp_hal.h" // for halGpioName()
#include "dev/device.h"
#include "drv/tft_driver.h"

View File

@ -99,22 +99,22 @@ void halRestartMcu(void)
} // halt
}
String halGetResetInfo()
{
#if defined(ARDUINO_ARCH_ESP32)
String resetReason((char*)0);
resetReason.reserve(128);
// String halGetResetInfo()
// {
// #if defined(ARDUINO_ARCH_ESP32)
// String resetReason((char*)0);
// resetReason.reserve(128);
resetReason += String(esp32ResetReason(0));
resetReason += F(" / ");
resetReason += String(esp32ResetReason(1));
return resetReason;
#elif defined(ARDUINO_ARCH_ESP8266)
return ESP.getResetInfo();
#else
return "";
#endif
}
// resetReason += String(esp32ResetReason(0));
// resetReason += F(" / ");
// resetReason += String(esp32ResetReason(1));
// return resetReason;
// #elif defined(ARDUINO_ARCH_ESP8266)
// return ESP.getResetInfo();
// #else
// return "";
// #endif
// }
// String halGetCoreVersion()
// {
@ -127,48 +127,48 @@ String halGetResetInfo()
// #endif
// }
String halGetChipModel()
{
String model((char*)0);
model.reserve(128);
// String halGetChipModel()
// {
// String model((char*)0);
// model.reserve(128);
#if defined(STM32F4xx)
model = F("STM32");
#endif
// #if defined(STM32F4xx)
// model = F("STM32");
// #endif
#if defined(STM32F4xx)
model = F("STM32F4xx");
// #if defined(STM32F4xx)
// model = F("STM32F4xx");
#elif defined(ARDUINO_ARCH_ESP8266)
model = F("ESP8266");
// #elif defined(ARDUINO_ARCH_ESP8266)
// model = F("ESP8266");
#elif defined(ARDUINO_ARCH_ESP32)
esp_chip_info_t chip_info;
esp_chip_info(&chip_info);
// #elif defined(ARDUINO_ARCH_ESP32)
// esp_chip_info_t chip_info;
// esp_chip_info(&chip_info);
model = chip_info.cores;
model += F("core ");
switch(chip_info.model) {
case CHIP_ESP32:
model += F("ESP32");
break;
#ifdef CHIP_ESP32S2
case CHIP_ESP32S2:
model += F("ESP32-S2");
break;
#endif
default:
model = F("Unknown ESP32");
}
model += F(" rev");
model += chip_info.revision;
// model = chip_info.cores;
// model += F("core ");
// switch(chip_info.model) {
// case CHIP_ESP32:
// model += F("ESP32");
// break;
// #ifdef CHIP_ESP32S2
// case CHIP_ESP32S2:
// model += F("ESP32-S2");
// break;
// #endif
// default:
// model = F("Unknown ESP32");
// }
// model += F(" rev");
// model += chip_info.revision;
#else
model = F("Unknown");
#endif
// #else
// model = F("Unknown");
// #endif
return model;
}
// return model;
// }
/*******************************/
/* Memory Management Functions */
@ -216,43 +216,43 @@ int getMemFree() { // returns the amount of free memory in bytes
return mi.fordblks + freeHighMemory();
} */
size_t halGetMaxFreeBlock()
{
#if defined(ARDUINO_ARCH_ESP32)
return ESP.getMaxAllocHeap();
#elif defined(ARDUINO_ARCH_ESP8266)
return ESP.getMaxFreeBlockSize();
#else
return freeHighMemory();
#endif
}
// size_t halGetMaxFreeBlock()
// {
// #if defined(ARDUINO_ARCH_ESP32)
// return ESP.getMaxAllocHeap();
// #elif defined(ARDUINO_ARCH_ESP8266)
// return ESP.getMaxFreeBlockSize();
// #else
// return freeHighMemory();
// #endif
// }
size_t halGetFreeHeap(void)
{
#if defined(ARDUINO_ARCH_ESP32)
return ESP.getFreeHeap();
#elif defined(ARDUINO_ARCH_ESP8266)
return ESP.getFreeHeap();
#else
struct mallinfo chuncks = mallinfo();
// size_t halGetFreeHeap(void)
// {
// #if defined(ARDUINO_ARCH_ESP32)
// return ESP.getFreeHeap();
// #elif defined(ARDUINO_ARCH_ESP8266)
// return ESP.getFreeHeap();
// #else
// struct mallinfo chuncks = mallinfo();
// fordblks
// This is the total size of memory occupied by free (not in use) chunks.
// // fordblks
// // This is the total size of memory occupied by free (not in use) chunks.
return chuncks.fordblks + freeHighMemory();
#endif
}
// return chuncks.fordblks + freeHighMemory();
// #endif
// }
uint8_t halGetHeapFragmentation()
{
#if defined(ARDUINO_ARCH_ESP32)
return (int8_t)(100.00f - (float)ESP.getMaxAllocHeap() * 100.00f / (float)ESP.getFreeHeap());
#elif defined(ARDUINO_ARCH_ESP8266)
return ESP.getHeapFragmentation();
#else
return (int8_t)(100.00f - (float)freeHighMemory() * 100.00f / (float)halGetFreeHeap());
#endif
}
// uint8_t halGetHeapFragmentation()
// {
// #if defined(ARDUINO_ARCH_ESP32)
// return (int8_t)(100.00f - (float)ESP.getMaxAllocHeap() * 100.00f / (float)ESP.getFreeHeap());
// #elif defined(ARDUINO_ARCH_ESP8266)
// return ESP.getHeapFragmentation();
// #else
// return (int8_t)(100.00f - (float)freeHighMemory() * 100.00f / (float)halGetFreeHeap());
// #endif
// }
String halGetMacAddress(int start, const char* seperator)
{
@ -284,14 +284,14 @@ String halGetMacAddress(int start, const char* seperator)
return cMac;
}
uint16_t halGetCpuFreqMHz()
{
#if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_32)
return ESP.getCpuFreqMHz();
#else
return (F_CPU / 1000 / 1000);
#endif
}
// uint16_t halGetCpuFreqMHz()
// {
// #if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_32)
// return ESP.getCpuFreqMHz();
// #else
// return (F_CPU / 1000 / 1000);
// #endif
// }
String halDisplayDriverName()
{

View File

@ -7,7 +7,7 @@
#include <Arduino.h>
// void halRestartMcu(void);
String halGetResetInfo(void);
// String halGetResetInfo(void);
// uint8_t halGetHeapFragmentation(void);
// size_t halGetMaxFreeBlock(void);
// size_t halGetFreeHeap(void);
@ -16,6 +16,6 @@ String halGetResetInfo(void);
String halGetMacAddress(int start, const char* seperator);
// uint16_t halGetCpuFreqMHz(void);
// String halDisplayDriverName(void);
String halGpioName(uint8_t gpio);
// String halGpioName(uint8_t gpio);
#endif

View File

@ -1,6 +1,9 @@
/* MIT License - Copyright (c) 2019-2021 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#include "hasplib.h"
#include "dev/device.h"
#ifdef ARDUINO
#include "ArduinoLog.h"
#endif
@ -11,15 +14,10 @@
#include <sstream>
#endif
#include "ArduinoJson.h"
#if HASP_USE_EEPROM > 0
#include "StreamUtils.h" // For EEPromStream
#endif
#include "lvgl.h"
#include "lv_conf.h"
#if HASP_USE_DEBUG > 0
#include "../hasp_debug.h"
#endif
@ -31,12 +29,6 @@
//#include "hasp_filesystem.h" included in hasp_conf.h
#endif
#include "hasplib.h"
#include "hasp.h"
#include "lv_theme_hasp.h"
#include "dev/device.h"
#if HASP_USE_EEPROM > 0
#include "EEPROM.h"
#endif
@ -110,30 +102,44 @@ lv_font_t* hasp_get_font(uint8_t fontid)
/**
* Check if sleep state needs to be updated
*/
bool hasp_update_sleep_state()
HASP_ATTRIBUTE_FAST_MEM bool hasp_update_sleep_state()
{
uint32_t idle = lv_disp_get_inactive_time(NULL);
if(sleepTimeLong > 0 && idle >= (sleepTimeShort + sleepTimeLong) * 1000U) {
if(hasp_sleep_state != HASP_SLEEP_LONG) {
dispatch_output_idle_state(HASP_SLEEP_LONG);
hasp_sleep_state = HASP_SLEEP_LONG;
dispatch_idle(NULL, NULL);
}
} else if(sleepTimeShort > 0 && idle >= sleepTimeShort * 1000U) {
if(hasp_sleep_state != HASP_SLEEP_SHORT) {
dispatch_output_idle_state(HASP_SLEEP_SHORT);
hasp_sleep_state = HASP_SLEEP_SHORT;
dispatch_idle(NULL, NULL);
}
} else {
if(hasp_sleep_state != HASP_SLEEP_OFF) {
dispatch_output_idle_state(HASP_SLEEP_OFF);
hasp_sleep_state = HASP_SLEEP_OFF;
dispatch_idle(NULL, NULL);
}
}
return (hasp_sleep_state != HASP_SLEEP_OFF);
}
void hasp_get_sleep_state(char* payload)
{
switch(hasp_sleep_state) {
case HASP_SLEEP_LONG:
memcpy_P(payload, PSTR("long"), 5);
break;
case HASP_SLEEP_SHORT:
memcpy_P(payload, PSTR("short"), 6);
break;
default:
memcpy_P(payload, PSTR("off"), 4);
}
}
void hasp_enable_wakeup_touch()
{
lv_obj_set_click(lv_disp_get_layer_sys(NULL), true); // enable first touch
@ -219,7 +225,7 @@ void haspReconnect()
void haspProgressVal(uint8_t val)
{
lv_obj_t* layer = lv_disp_get_layer_sys(NULL);
lv_obj_t* bar = hasp_find_obj_from_parent_id(haspPages.get_obj(255), (uint8_t)10);
lv_obj_t* bar = hasp_find_obj_from_page_id(255U, 10U);
if(layer && bar) {
if(val == 255) {
if(!lv_obj_get_hidden(bar)) {
@ -227,8 +233,8 @@ void haspProgressVal(uint8_t val)
lv_obj_set_style_local_bg_opa(layer, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_0);
// lv_obj_set_style_local_value_str(bar, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, "");
// lv_obj_set_value_str_txt(bar, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, NULL); //TODO: call our custom
// function to free the memory
// lv_obj_set_value_str_txt(bar, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, NULL);
// TODO: call our custom function to free the memory
#if defined(ARDUINO_ARCH_ESP32) || defined(ARDUINO_ARCH_ESP8266)
// progress_str.clear();
@ -248,9 +254,7 @@ void haspProgressVal(uint8_t val)
// Sets the value string of the global progress bar
void haspProgressMsg(const char* msg)
{
lv_obj_t* bar = hasp_find_obj_from_parent_id(haspPages.get_obj(255), (uint8_t)10);
if(bar) {
if(lv_obj_t* bar = hasp_find_obj_from_page_id(255U, 10U)) {
char value_str[10];
snprintf_P(value_str, sizeof(value_str), PSTR("value_str"));
hasp_process_obj_attribute(bar, value_str, msg, true);
@ -278,14 +282,17 @@ void haspProgressMsg(const __FlashStringHelper* msg)
/*Add a custom apply callback*/
static void custom_font_apply_cb(lv_theme_t* th, lv_obj_t* obj, lv_theme_style_t name)
{
lv_style_list_t* list;
/* lv_style_list_t* list;
switch(name) {
case LV_THEME_BTN:
list = lv_obj_get_style_list(obj, LV_BTN_PART_MAIN);
// _lv_style_list_add_style(list, &my_style);
break;
}
switch(name) {
case LV_THEME_BTN:
list = lv_obj_get_style_list(obj, LV_BTN_PART_MAIN);
// _lv_style_list_add_style(list, &my_style);
break;
default:
// nothing
;
} */
}
/**
@ -298,7 +305,7 @@ void haspSetup(void)
/******* File System Test ********************************************************************/
// lv_fs_file_t f;
// lv_fs_res_t res;
// res = lv_fs_open(&f, "E:/config.json", LV_FS_MODE_RD);
// res = lv_fs_open(&f, "L:/config.json", LV_FS_MODE_RD);
// if(res == LV_FS_RES_OK)
// LOG_VERBOSE(TAG_HASP, F("Opening config.json OK"));
// else
@ -337,7 +344,7 @@ void haspSetup(void)
// WARNING: hasp_font needs to be null !
if(lv_zifont_font_init(&hasp_font, haspZiFontPath, 32) != 0) {
LOG_ERROR(TAG_HASP, F("Failed to set font to %s"), haspZiFontPath);
if(strlen(haspZiFontPath) > 0) LOG_WARNING(TAG_HASP, F("Failed to set font to %s"), haspZiFontPath);
haspFonts[0] = LV_THEME_DEFAULT_FONT_SMALL;
} else {
// defaultFont = haspFonts[0];
@ -356,8 +363,8 @@ void haspSetup(void)
if(haspFonts[3] == nullptr) haspFonts[3] = LV_THEME_DEFAULT_FONT_TITLE;
// haspFonts[0] = lv_font_load("E:/font_1.fnt");
// haspFonts[2] = lv_font_load("E:/font_2.fnt");
// haspFonts[3] = lv_font_load("E:/font_3.fnt");
// haspFonts[2] = lv_font_load("E:/font_2.fnt");
// haspFonts[3] = lv_font_load("E:/font_3.fnt");
/* ********** Theme Initializations ********** */
if(haspThemeId == 8) haspThemeId = 1; // update old HASP id
@ -452,20 +459,30 @@ void haspSetup(void)
}
#endif
haspPages.init(haspStartPage);
haspPages.load_jsonl(haspPagesPath);
haspPages.set(haspStartPage, LV_SCR_LOAD_ANIM_NONE);
hasp_init();
hasp_load_json();
haspPages.set(haspStartPage, LV_SCR_LOAD_ANIM_FADE_ON);
}
/**********************
* STATIC FUNCTIONS
**********************/
void haspLoop(void)
IRAM_ATTR void haspLoop(void)
{
dispatchLoop();
}
void hasp_init(void)
{
haspPages.init(haspStartPage);
}
void hasp_load_json(void)
{
haspPages.load_jsonl(haspPagesPath);
}
/*
void hasp_background(uint16_t pageid, uint16_t imageid)
{
@ -517,10 +534,10 @@ void hasp_background(uint16_t pageid, uint16_t imageid)
///////////////////////////////////////////////////////////////////////////////////////////////////////////
void haspGetVersion(char* version, size_t len)
{
snprintf_P(version, len, PSTR("%u.%u.%u"), HASP_VER_MAJ, HASP_VER_MIN, HASP_VER_REV);
}
// void haspGetVersion(char* version, size_t len)
// {
// snprintf_P(version, len, PSTR("%u.%u.%u"), HASP_VER_MAJ, HASP_VER_MIN, HASP_VER_REV);
// }
void haspClearPage(uint16_t pageid)
{
@ -553,47 +570,80 @@ void haspSetPage(uint8_t pageid)
}
}
void haspLoadPage(const char* pagesfile)
void hasp_get_info(JsonDocument& doc)
{
#if HASP_USE_SPIFFS > 0 || HASP_USE_LITTLEFS > 0
if(pagesfile[0] == '\0') return;
std::string buffer;
buffer.reserve(64);
char size_buf[32];
JsonObject info = doc.createNestedObject(F(D_MANUFACTURER));
if(!filesystemSetup()) {
LOG_ERROR(TAG_HASP, F("FS not mounted. Failed to load %s"), pagesfile);
return;
info[F(D_INFO_VERSION)] = haspDevice.get_version();
buffer = __DATE__;
buffer += (" ");
buffer += __TIME__;
buffer += (" UTC"); // Github buildservers are in UTC
info[F(D_INFO_BUILD_DATETIME)] = buffer;
unsigned long time = millis() / 1000;
uint16_t day = time / 86400;
time = time % 86400;
uint8_t hour = time / 3600;
time = time % 3600;
uint8_t min = time / 60;
time = time % 60;
uint8_t sec = time;
buffer.clear();
if(day > 0) {
itoa(day, size_buf, DEC);
buffer += size_buf;
buffer += "d ";
}
if(!HASP_FS.exists(pagesfile)) {
LOG_ERROR(TAG_HASP, F("Non existing file %s"), pagesfile);
return;
if(day > 0 || hour > 0) {
itoa(hour, size_buf, DEC);
buffer += size_buf;
buffer += "h ";
}
if(day > 0 || hour > 0 || min > 0) {
itoa(min, size_buf, DEC);
buffer += size_buf;
buffer += "m ";
}
itoa(sec, size_buf, DEC);
buffer += size_buf;
buffer += "s";
info[F(D_INFO_UPTIME)] = buffer;
LOG_TRACE(TAG_HASP, F("Loading file %s"), pagesfile);
info = doc.createNestedObject(F(D_INFO_DEVICE_MEMORY));
Parser::format_bytes(haspDevice.get_free_heap(), size_buf, sizeof(size_buf));
info[F(D_INFO_FREE_HEAP)] = size_buf;
Parser::format_bytes(haspDevice.get_free_max_block(), size_buf, sizeof(size_buf));
info[F(D_INFO_FREE_BLOCK)] = size_buf;
info[F(D_INFO_FRAGMENTATION)] = haspDevice.get_heap_fragmentation();
File file = HASP_FS.open(pagesfile, "r");
dispatch_parse_jsonl(file);
file.close();
LOG_INFO(TAG_HASP, F("File %s loaded"), pagesfile);
#else
#if HASP_USE_EEPROM > 0
LOG_TRACE(TAG_HASP, F("Loading jsonl from EEPROM..."));
EepromStream eepromStream(4096, 1024);
dispatch_parse_jsonl(eepromStream);
LOG_INFO(TAG_HASP, F("Loaded jsonl from EEPROM"));
#if ARDUINO_ARCH_ESP32
if(psramFound()) {
Parser::format_bytes(ESP.getFreePsram(), size_buf, sizeof(size_buf));
info[F(D_INFO_PSRAM_FREE)] = size_buf;
Parser::format_bytes(ESP.getPsramSize(), size_buf, sizeof(size_buf));
info[F(D_INFO_PSRAM_SIZE)] = size_buf;
}
#endif
std::ifstream ifs("pages.json", std::ifstream::in);
if(ifs) {
LOG_TRACE(TAG_HASP, F("Loading file %s"), pagesfile);
dispatch_parse_jsonl(ifs);
LOG_INFO(TAG_HASP, F("File %s loaded"), pagesfile);
} else {
LOG_ERROR(TAG_HASP, F("Non existing file %s"), pagesfile);
}
info = doc.createNestedObject(F(D_INFO_LVGL_MEMORY));
lv_mem_monitor_t mem_mon;
lv_mem_monitor(&mem_mon);
Parser::format_bytes(mem_mon.total_size, size_buf, sizeof(size_buf));
info[F(D_INFO_TOTAL_MEMORY)] = size_buf;
Parser::format_bytes(mem_mon.free_size, size_buf, sizeof(size_buf));
info[F(D_INFO_FREE_MEMORY)] = size_buf;
info[F(D_INFO_FRAGMENTATION)] = mem_mon.frag_pct;
#endif
info = doc.createNestedObject(F("HASP State"));
hasp_get_sleep_state(size_buf);
info[F("Idle")] = size_buf;
info[F("Active Page")] = haspPages.get();
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

View File

@ -8,10 +8,7 @@
#include "Arduino.h"
#endif
#include "lvgl.h"
#include "hasp_conf.h"
#include "hasp_conf.h"
#include "hasplib.h"
#if HASP_USE_DEBUG > 0
#include "../hasp_debug.h"
@ -47,13 +44,12 @@ extern "C" {
* Create a hasp application
*/
void haspSetup(void);
void haspLoop(void);
IRAM_ATTR void haspLoop(void);
void haspEverySecond(void);
void haspReconnect(void);
void haspDisconnect(void);
void haspGetVersion(char* version, size_t len);
// void haspBackground(uint16_t pageid, uint16_t imageid);
// void haspNewObject(const JsonObject & config, uint8_t & saved_page_id);
@ -67,12 +63,18 @@ bool haspSetConfig(const JsonObject& settings);
lv_font_t* hasp_get_font(uint8_t fontid);
bool hasp_update_sleep_state();
HASP_ATTRIBUTE_FAST_MEM bool hasp_update_sleep_state();
void hasp_get_sleep_state(char* payload);
void hasp_get_sleep_time(uint16_t& short_time, uint16_t& long_time);
void hasp_set_sleep_time(uint16_t short_time, uint16_t long_time);
void hasp_enable_wakeup_touch();
void hasp_disable_wakeup_touch();
void hasp_init(void);
void hasp_load_json(void);
void hasp_get_info(JsonDocument& info);
/**********************
* MACROS
**********************/

File diff suppressed because it is too large Load Diff

View File

@ -4,27 +4,22 @@
#ifndef HASP_ATTR_SET_H
#define HASP_ATTR_SET_H
#include "lvgl.h"
#if LVGL_VERSION_MAJOR != 7
#include "../lv_components.h"
#endif
#include "hasp_conf.h"
#include "hasp.h"
#include "hasp_object.h"
#include "hasplib.h"
#ifdef __cplusplus
extern "C" {
#endif
lv_chart_series_t* my_chart_get_series(lv_obj_t* chart, uint8_t ser_num);
void my_obj_set_value_str_txt(lv_obj_t* obj, uint8_t part, lv_state_t state, const char* text);
void my_obj_set_value_str_text(lv_obj_t* obj, uint8_t part, lv_state_t state, const char* text);
void my_btnmatrix_map_clear(lv_obj_t* obj);
void my_msgbox_map_clear(lv_obj_t* obj);
void line_clear_points(lv_obj_t* obj);
void hasp_process_obj_attribute(lv_obj_t* obj, const char* attr_p, const char* payload, bool update);
bool hasp_process_obj_attribute_val(lv_obj_t* obj, const char* attr, int16_t intval, bool booval, bool update);
bool attribute_set_normalized_value(lv_obj_t* obj, hasp_update_value_t& value);
void attr_out_str(lv_obj_t* obj, const char* attribute, const char* data);
void attr_out_int(lv_obj_t* obj, const char* attribute, int32_t val);
@ -34,6 +29,106 @@ void attr_out_color(lv_obj_t* obj, const char* attribute, lv_color_t color);
} /* extern "C" */
#endif
typedef enum {
ATTR_RANGE_ERROR = -9,
ATTR_TYPE_METHOD_INVALID_FOR_PAGE = -8,
ATTR_TYPE_ALIGN_INVALID = -5,
ATTR_TYPE_COLOR_INVALID = -4,
ATTR_TYPE_STR_READONLY = -3,
ATTR_TYPE_BOOL_READONLY = -2,
ATTR_TYPE_INT_READONLY = -1,
ATTR_NOT_FOUND = 0,
ATTR_TYPE_INT,
ATTR_TYPE_BOOL,
ATTR_TYPE_STR,
ATTR_TYPE_COLOR,
ATTR_TYPE_ALIGN,
ATTR_TYPE_DIRECTION_XY,
ATTR_TYPE_DIRECTION_CLOCK,
ATTR_TYPE_METHOD_OK,
} hasp_attribute_type_t;
struct hasp_attr_update_bool_const_t
{
lv_hasp_obj_type_t obj_type;
uint16_t hash;
void (*set)(lv_obj_t*, bool);
bool (*get)(const lv_obj_t*);
};
struct hasp_attr_update_uint16_const_t
{
lv_hasp_obj_type_t obj_type;
uint16_t hash;
void (*set)(lv_obj_t*, uint16_t);
uint16_t (*get)(const lv_obj_t*);
};
struct hasp_attr_update_lv_anim_value_const_t
{
lv_hasp_obj_type_t obj_type;
uint16_t hash;
void (*set)(lv_obj_t*, lv_anim_value_t);
lv_anim_value_t (*get)(const lv_obj_t*);
};
struct hasp_attr_update_int16_const_t
{
lv_hasp_obj_type_t obj_type;
uint16_t hash;
void (*set)(lv_obj_t*, int16_t);
int16_t (*get)(const lv_obj_t*);
};
struct hasp_attr_update_uint8_const_t
{
lv_hasp_obj_type_t obj_type;
uint16_t hash;
void (*set)(lv_obj_t*, uint8_t);
uint8_t (*get)(const lv_obj_t*);
};
struct hasp_attr_update8_const_t
{
lv_hasp_obj_type_t obj_type;
uint16_t hash;
void (*set)(lv_obj_t*, uint8_t);
uint8_t (*get)(const lv_obj_t*);
};
struct hasp_attr_update_uint16_t
{
lv_hasp_obj_type_t obj_type;
uint16_t hash;
void (*set)(lv_obj_t*, uint16_t);
uint16_t (*get)(lv_obj_t*);
};
struct hasp_attr_update_bool_t
{
lv_hasp_obj_type_t obj_type;
uint16_t hash;
void (*set)(lv_obj_t*, bool);
bool (*get)(lv_obj_t*);
};
struct hasp_attr_update_lv_coord_t
{
lv_hasp_obj_type_t obj_type;
uint16_t hash;
void (*set)(lv_obj_t*, lv_coord_t);
lv_coord_t (*get)(lv_obj_t*);
};
struct hasp_attr_update_char_const_t
{
lv_hasp_obj_type_t obj_type;
uint16_t hash;
void (*set)(lv_obj_t*, const char*);
const char* (*get)(const lv_obj_t*);
};
#define _HASP_ATTRIBUTE(prop_name, func_name, value_type) \
static inline void attribute_##func_name(lv_obj_t* obj, uint8_t part, lv_state_t state, bool update, \
const char* attr, value_type val) \
@ -266,7 +361,6 @@ _HASP_ATTRIBUTE(SCALE_END_LINE_WIDTH, scale_end_line_width, lv_style_int_t)
#define ATTR_BACK 57799
/* Object Attributes */
#define ATTR_COMMENT 62559
#define ATTR_X 120
#define ATTR_Y 121
#define ATTR_W 119
@ -292,10 +386,15 @@ _HASP_ATTRIBUTE(SCALE_END_LINE_WIDTH, scale_end_line_width, lv_style_int_t)
#define ATTR_TEXT 53869
#define ATTR_SRC 4964
#define ATTR_ID 6715
#define ATTR_EXT_CLICK_H 46643
#define ATTR_EXT_CLICK_V 46657
#define ATTR_ANIM_TIME 59451
#define ATTR_ANIM_SPEED 281
#define ATTR_START_VALUE 11828
// methods
#define ATTR_DELETE 50027
#define ATTR_CLEAR 1069
#define ATTR_TO_FRONT 44741
#define ATTR_TO_BACK 24555
@ -326,6 +425,25 @@ _HASP_ATTRIBUTE(SCALE_END_LINE_WIDTH, scale_end_line_width, lv_style_int_t)
// Buttonmatrix
#define ATTR_ONE_CHECK 45935
// Tabview
#define ATTR_BTN_POS 35697
#define ATTR_COUNT 29103
// Msgbox
#define ATTR_MODAL 7405
#define ATTR_AUTO_CLOSE 7880
// Image
#define ATTR_OFFSET_X 65388
#define ATTR_OFFSET_Y 65389
#define ATTR_AUTO_SIZE 63729
// Spinner
#define ATTR_SPEED 14375
#define ATTR_THICKNESS 24180
//#define ATTR_ARC_LENGTH 755 - use ATTR_ANGLE
// #define ATTR_DIRECTION 32415 - see Dropdown
/* hasp user data */
#define ATTR_ACTION 42102
#define ATTR_TRANSITION 10933
@ -333,4 +451,11 @@ _HASP_ATTRIBUTE(SCALE_END_LINE_WIDTH, scale_end_line_width, lv_style_int_t)
#define ATTR_OBJID 41010
#define ATTR_OBJ 53623
#define ATTR_TEXT_MAC 38107
#define ATTR_TEXT_IP 41785
#define ATTR_TEXT_HOSTNAME 10125
#define ATTR_TEXT_MODEL 54561
#define ATTR_TEXT_VERSION 60178
#define ATTR_TEXT_SSID 62981
#endif

View File

@ -0,0 +1,532 @@
/* MIT License - Copyright (c) 2019-2021 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#include "hasplib.h"
const char* my_tabview_get_tab_name(const lv_obj_t* tabview, uint16_t id)
{
if(id >= lv_tabview_get_tab_count(tabview)) return NULL;
lv_tabview_ext_t* ext = (lv_tabview_ext_t*)lv_obj_get_ext_attr(tabview);
return ext->tab_name_ptr[id];
}
// OK - this function is missing in lvgl
static uint8_t my_roller_get_visible_row_count(const lv_obj_t* roller)
{
const lv_font_t* font = lv_obj_get_style_text_font(roller, LV_ROLLER_PART_BG);
lv_style_int_t line_space = lv_obj_get_style_text_line_space(roller, LV_ROLLER_PART_BG);
lv_coord_t h = lv_obj_get_height(roller);
if((lv_font_get_line_height(font) + line_space) != 0)
return (uint8_t)(h / (lv_font_get_line_height(font) + line_space));
else
return 0;
}
// OK - this function is not const in lvgl and doesn't return 0
static uint16_t my_msgbox_stop_auto_close(const lv_obj_t* obj)
{
lv_msgbox_stop_auto_close((lv_obj_t*)obj);
return 0;
}
// OK - this function is not const in lvgl
static bool my_arc_get_adjustable(const lv_obj_t* arc)
{
return lv_arc_get_adjustable((lv_obj_t*)arc);
}
// OK - we need to change the event handler too
static void my_arc_set_adjustable(lv_obj_t* arc, bool toggle)
{
lv_arc_set_adjustable(arc, toggle);
lv_obj_set_event_cb(arc, toggle ? slider_event_handler : generic_event_handler);
}
// OK - this function is missing in lvgl
static inline uint16_t my_arc_get_rotation(lv_obj_t* arc)
{
lv_arc_ext_t* ext = (lv_arc_ext_t*)lv_obj_get_ext_attr(arc);
return ext->rotation_angle;
}
// OK - this function is missing in lvgl
static inline int16_t my_chart_get_min_value(lv_obj_t* chart)
{
lv_chart_ext_t* ext = (lv_chart_ext_t*)lv_obj_get_ext_attr(chart);
return ext->ymin[LV_CHART_AXIS_PRIMARY_Y];
}
// OK - this function is missing in lvgl
static inline int16_t my_chart_get_max_value(lv_obj_t* chart)
{
lv_chart_ext_t* ext = (lv_chart_ext_t*)lv_obj_get_ext_attr(chart);
return ext->ymax[LV_CHART_AXIS_PRIMARY_Y];
}
lv_chart_series_t* my_chart_get_series(lv_obj_t* chart, uint8_t ser_num)
{
lv_chart_ext_t* ext = (lv_chart_ext_t*)lv_obj_get_ext_attr(chart);
lv_chart_series_t* ser = (lv_chart_series_t*)_lv_ll_get_tail(&ext->series_ll);
while(ser_num > 0 && ser) {
ser = (lv_chart_series_t*)_lv_ll_get_prev(&ext->series_ll, ser);
ser_num--;
}
return ser;
}
// OK
static inline lv_color_t haspLogColor(lv_color_t color)
{
// uint8_t r = (LV_COLOR_GET_R(color) * 263 + 7) >> 5;
// uint8_t g = (LV_COLOR_GET_G(color) * 259 + 3) >> 6;
// uint8_t b = (LV_COLOR_GET_B(color) * 263 + 7) >> 5;
// LOG_VERBOSE(TAG_ATTR,F("Color: R%u G%u B%u"), r, g, b);
return color;
}
void my_bar_set_start_value(lv_obj_t* bar, int16_t start_value)
{
lv_bar_set_start_value(bar, start_value, true);
}
void my_slider_set_left_value(lv_obj_t* bar, int16_t start_value)
{
lv_slider_set_left_value(bar, start_value, true);
}
lv_coord_t my_dropdown_get_max_height(lv_obj_t* obj)
{
return lv_dropdown_get_max_height(obj);
}
// OK
lv_obj_t* FindButtonLabel(lv_obj_t* btn)
{
if(btn) {
lv_obj_t* label = lv_obj_get_child_back(btn, NULL);
if(label) {
if(obj_check_type(label, LV_HASP_LABEL)) {
return label;
}
} else {
LOG_ERROR(TAG_ATTR, F("FindButtonLabel NULL Pointer encountered"));
}
} else {
LOG_WARNING(TAG_ATTR, F("Button not defined"));
}
return NULL;
}
// OK - lvgl does not return a const char *
static const char* my_label_get_text(const lv_obj_t* label)
{
return lv_label_get_text(label); // library does not return const
}
static void my_label_set_text(lv_obj_t* label, const char* text)
{
if(text[0] == '%') {
uint16_t hash = Parser::get_sdbm(text);
size_t len = strlen(text);
const char* static_text = NULL;
switch(hash) {
case ATTR_TEXT_MAC:
if(len == 4) break;
break;
#if HASP_USE_WIFI > 0
case ATTR_TEXT_SSID:
if(len == 6) static_text = wifi_get_ssid();
break;
case ATTR_TEXT_IP:
if(len == 4) static_text = wifi_get_ip_address();
break;
#endif
case ATTR_TEXT_HOSTNAME:
if(len == 10) static_text = haspDevice.get_hostname();
break;
case ATTR_TEXT_MODEL:
if(len == 7) static_text = haspDevice.get_model();
break;
case ATTR_TEXT_VERSION:
if(len == 9) static_text = haspDevice.get_version();
break;
}
if(static_text) {
lv_label_set_text_static(label, static_text);
return;
}
}
lv_label_set_text(label, text);
}
// OK
static const char* my_btn_get_text(const lv_obj_t* obj)
{
if(!obj) {
LOG_WARNING(TAG_ATTR, F("Button not defined"));
return NULL;
}
lv_obj_t* label = lv_obj_get_child_back(obj, NULL);
if(label) {
#if 1
if(obj_check_type(label, LV_HASP_LABEL)) return lv_label_get_text(label);
#else
lv_obj_type_t list;
lv_obj_get_type(label, &list);
if(obj_check_type(list.type[0], LV_HASP_LABEL)) {
text = lv_label_get_text(label);
return true;
}
#endif
} else {
LOG_WARNING(TAG_ATTR, F("my_btn_get_text NULL Pointer encountered"));
}
return NULL;
}
// OK
static inline void my_btn_set_text(lv_obj_t* obj, const char* value)
{
lv_obj_t* label = FindButtonLabel(obj);
if(label) {
my_label_set_text(label, value);
}
}
/**
* Set a new value_str for an object. Memory will be allocated to store the text by the object.
* @param obj pointer to a object
* @param text '\0' terminated character string. NULL to refresh with the current text.
*/
void my_obj_set_value_str_text(lv_obj_t* obj, uint8_t part, lv_state_t state, const char* text)
{
// LOG_VERBOSE(TAG_ATTR, F("%s %d"), __FILE__, __LINE__);
const void* value_str_p = lv_obj_get_style_value_str(obj, part);
lv_obj_invalidate(obj);
if(text == NULL || text[0] == 0) {
// LOG_VERBOSE(TAG_ATTR, F("%s %d"), __FILE__, __LINE__);
lv_obj_set_style_local_value_str(obj, part, state, NULL);
lv_mem_free(value_str_p);
// LOG_VERBOSE(TAG_ATTR, F("%s %d"), __FILE__, __LINE__);
return;
}
LV_ASSERT_STR(text);
if(value_str_p == NULL) {
/*Get the size of the text*/
size_t len = strlen(text) + 1;
/*Allocate space for the new text*/
// LOG_VERBOSE(TAG_ATTR, F("%s %d"), __FILE__, __LINE__);
value_str_p = (char*)lv_mem_alloc(len);
LV_ASSERT_MEM(value_str_p);
if(value_str_p == NULL) return;
// LOG_VERBOSE(TAG_ATTR, F("%s %d"), __FILE__, __LINE__);
strncpy((char*)value_str_p, text, len);
lv_obj_set_style_local_value_str(obj, part, state, (char*)value_str_p);
// LOG_VERBOSE(TAG_ATTR, F("%s %d"), __FILE__, __LINE__);
return;
}
// lv_obj_set_style_local_value_str(obj, part, state, str_p);
if(value_str_p == text) {
/*If set its own text then reallocate it (maybe its size changed)*/
LOG_DEBUG(TAG_ATTR, "%s %d", __FILE__, __LINE__);
return; // don't touch the data
// value_str_p = lv_mem_realloc(value_str_p, strlen(text) + 1);
// LV_ASSERT_MEM(value_str_p);
// if(value_str_p == NULL) return;
} else {
/*Free the old text*/
if(value_str_p != NULL) {
// LOG_DEBUG(TAG_ATTR, F("%s %d"), __FILE__, __LINE__);
lv_mem_free(value_str_p);
value_str_p = NULL;
// LOG_DEBUG(TAG_ATTR, F("%s %d"), __FILE__, __LINE__);
}
/*Get the size of the text*/
size_t len = strlen(text) + 1;
/*Allocate space for the new text*/
value_str_p = lv_mem_alloc(len);
LV_ASSERT_MEM(value_str_p);
if(value_str_p != NULL) strcpy((char*)value_str_p, text);
lv_obj_set_style_local_value_str(obj, part, state, (char*)value_str_p);
}
// LOG_VERBOSE(TAG_ATTR, F("%s %d"), __FILE__, __LINE__);
}
void my_tabview_set_text(lv_obj_t* obj, const char* payload)
{
uint16_t id = lv_tabview_get_tab_act(obj);
if(id < lv_tabview_get_tab_count(obj)) {
lv_tabview_set_tab_name(obj, id, (char*)payload);
}
}
const char* my_tabview_get_text(const lv_obj_t* obj)
{
uint16_t id = lv_tabview_get_tab_act(obj);
if(id < lv_tabview_get_tab_count(obj)) {
return my_tabview_get_tab_name(obj, id);
} else {
return NULL;
}
}
void my_tab_set_text(lv_obj_t* obj, const char* payload)
{
lv_obj_t* content = lv_obj_get_parent(obj->parent); // 2 levels up
if(!content) return LOG_WARNING(TAG_ATTR, F("content not found"));
lv_obj_t* tabview = lv_obj_get_parent(content); // 3rd level up
if(!tabview) return LOG_WARNING(TAG_ATTR, F("Tabview not found"));
if(!obj_check_type(tabview, LV_HASP_TABVIEW))
return LOG_WARNING(TAG_ATTR, F("LV_HASP_TABVIEW not found %d"), obj_get_type(tabview));
for(uint16_t id = 0; id < lv_tabview_get_tab_count(tabview); id++) {
if(obj == lv_tabview_get_tab(tabview, id)) {
lv_tabview_set_tab_name(tabview, id, (char*)payload);
return;
}
}
LOG_WARNING(TAG_ATTR, F("Tab not found"));
}
const char* my_tab_get_text(const lv_obj_t* obj)
{
lv_obj_t* content = lv_obj_get_parent(obj->parent); // 2 levels up
if(!content) {
LOG_WARNING(TAG_ATTR, F("content not found"));
return NULL;
}
lv_obj_t* tabview = lv_obj_get_parent(content); // 3rd level up
if(!tabview) {
LOG_WARNING(TAG_ATTR, F("Tabview not found"));
return NULL;
}
if(!obj_check_type(tabview, LV_HASP_TABVIEW)) {
LOG_WARNING(TAG_ATTR, F("LV_HASP_TABVIEW not found %d"), obj_get_type(tabview));
return NULL;
}
for(uint16_t id = 0; id < lv_tabview_get_tab_count(tabview); id++) {
if(obj == lv_tabview_get_tab(tabview, id)) {
return my_tabview_get_tab_name(tabview, id);
}
}
LOG_WARNING(TAG_ATTR, F("Tab not found"));
return NULL;
}
static void gauge_format_10(lv_obj_t* gauge, char* buf, int bufsize, int32_t value)
{
snprintf(buf, bufsize, PSTR("%d"), value / 10);
}
static void gauge_format_100(lv_obj_t* gauge, char* buf, int bufsize, int32_t value)
{
snprintf(buf, bufsize, PSTR("%d"), value / 100);
}
static void gauge_format_1k(lv_obj_t* gauge, char* buf, int bufsize, int32_t value)
{
snprintf(buf, bufsize, PSTR("%d"), value / 1000);
}
static void gauge_format_10k(lv_obj_t* gauge, char* buf, int bufsize, int32_t value)
{
snprintf(buf, bufsize, PSTR("%d"), value / 10000);
}
#if 0
static bool attribute_lookup_lv_property(uint16_t hash, uint8_t * prop)
{
struct prop_hash_map
{
uint16_t hash;
uint8_t prop;
};
/* in order of prevalence */
prop_hash_map props[] = {
{ATTR_PAD_TOP, LV_STYLE_PAD_TOP & LV_STYLE_PROP_ALL},
{ATTR_BORDER_WIDTH, LV_STYLE_BORDER_WIDTH & LV_STYLE_PROP_ALL},
{ATTR_OUTLINE_WIDTH, LV_STYLE_OUTLINE_WIDTH & LV_STYLE_PROP_ALL},
{ATTR_VALUE_LETTER_SPACE, LV_STYLE_VALUE_LETTER_SPACE & LV_STYLE_PROP_ALL},
{ATTR_TEXT_LETTER_SPACE, LV_STYLE_TEXT_LETTER_SPACE & LV_STYLE_PROP_ALL},
{ATTR_LINE_WIDTH, LV_STYLE_LINE_WIDTH & LV_STYLE_PROP_ALL},
{ATTR_TRANSITION_TIME, LV_STYLE_TRANSITION_TIME & LV_STYLE_PROP_ALL},
{ATTR_SCALE_WIDTH, LV_STYLE_SCALE_WIDTH & LV_STYLE_PROP_ALL},
{ATTR_RADIUS, LV_STYLE_RADIUS & LV_STYLE_PROP_ALL},
{ATTR_PAD_BOTTOM, LV_STYLE_PAD_BOTTOM & LV_STYLE_PROP_ALL},
{ATTR_BG_MAIN_STOP, LV_STYLE_BG_MAIN_STOP & LV_STYLE_PROP_ALL},
{ATTR_BORDER_SIDE, LV_STYLE_BORDER_SIDE & LV_STYLE_PROP_ALL},
{ATTR_OUTLINE_PAD, LV_STYLE_OUTLINE_PAD & LV_STYLE_PROP_ALL},
{ATTR_PATTERN_REPEAT, LV_STYLE_PATTERN_REPEAT & LV_STYLE_PROP_ALL},
{ATTR_VALUE_LINE_SPACE, LV_STYLE_VALUE_LINE_SPACE & LV_STYLE_PROP_ALL},
{ATTR_TEXT_LINE_SPACE, LV_STYLE_TEXT_LINE_SPACE & LV_STYLE_PROP_ALL},
{ATTR_TRANSITION_DELAY, LV_STYLE_TRANSITION_DELAY & LV_STYLE_PROP_ALL},
{ATTR_SCALE_BORDER_WIDTH, LV_STYLE_SCALE_BORDER_WIDTH & LV_STYLE_PROP_ALL},
{ATTR_CLIP_CORNER, LV_STYLE_CLIP_CORNER & LV_STYLE_PROP_ALL},
{ATTR_PAD_LEFT, LV_STYLE_PAD_LEFT & LV_STYLE_PROP_ALL},
{ATTR_BG_GRAD_STOP, LV_STYLE_BG_GRAD_STOP & LV_STYLE_PROP_ALL},
{ATTR_TEXT_DECOR, LV_STYLE_TEXT_DECOR & LV_STYLE_PROP_ALL},
{ATTR_LINE_DASH_WIDTH, LV_STYLE_LINE_DASH_WIDTH & LV_STYLE_PROP_ALL},
{ATTR_TRANSITION_PROP_1, LV_STYLE_TRANSITION_PROP_1 & LV_STYLE_PROP_ALL},
{ATTR_SCALE_END_BORDER_WIDTH, LV_STYLE_SCALE_END_BORDER_WIDTH & LV_STYLE_PROP_ALL},
{ATTR_SIZE, LV_STYLE_SIZE & LV_STYLE_PROP_ALL},
{ATTR_PAD_RIGHT, LV_STYLE_PAD_RIGHT & LV_STYLE_PROP_ALL},
{ATTR_BG_GRAD_DIR, LV_STYLE_BG_GRAD_DIR & LV_STYLE_PROP_ALL},
{ATTR_BORDER_POST, LV_STYLE_BORDER_POST & LV_STYLE_PROP_ALL},
{ATTR_VALUE_OFS_X, LV_STYLE_VALUE_OFS_X & LV_STYLE_PROP_ALL},
{ATTR_LINE_DASH_GAP, LV_STYLE_LINE_DASH_GAP & LV_STYLE_PROP_ALL},
{ATTR_TRANSITION_PROP_2, LV_STYLE_TRANSITION_PROP_2 & LV_STYLE_PROP_ALL},
{ATTR_SCALE_END_LINE_WIDTH, LV_STYLE_SCALE_END_LINE_WIDTH & LV_STYLE_PROP_ALL},
{ATTR_TRANSFORM_WIDTH, LV_STYLE_TRANSFORM_WIDTH & LV_STYLE_PROP_ALL},
{ATTR_PAD_INNER, LV_STYLE_PAD_INNER & LV_STYLE_PROP_ALL},
{ATTR_VALUE_OFS_Y, LV_STYLE_VALUE_OFS_Y & LV_STYLE_PROP_ALL},
{ATTR_LINE_ROUNDED, LV_STYLE_LINE_ROUNDED & LV_STYLE_PROP_ALL},
{ATTR_TRANSITION_PROP_3, LV_STYLE_TRANSITION_PROP_3 & LV_STYLE_PROP_ALL},
{ATTR_TRANSFORM_HEIGHT, LV_STYLE_TRANSFORM_HEIGHT & LV_STYLE_PROP_ALL},
// {ATTR_MARGIN_TOP, LV_STYLE_MARGIN_TOP & LV_STYLE_PROP_ALL},
{ATTR_VALUE_ALIGN, LV_STYLE_VALUE_ALIGN & LV_STYLE_PROP_ALL},
{ATTR_TRANSITION_PROP_4, LV_STYLE_TRANSITION_PROP_4 & LV_STYLE_PROP_ALL},
// {ATTR_TRANSFORM_ANGLE, LV_STYLE_TRANSFORM_ANGLE & LV_STYLE_PROP_ALL},
// {ATTR_MARGIN_BOTTOM, LV_STYLE_MARGIN_BOTTOM & LV_STYLE_PROP_ALL},
{ATTR_TRANSITION_PROP_5, LV_STYLE_TRANSITION_PROP_5 & LV_STYLE_PROP_ALL},
// {ATTR_TRANSFORM_ZOOM, LV_STYLE_TRANSFORM_ZOOM & LV_STYLE_PROP_ALL},
// {ATTR_MARGIN_LEFT, LV_STYLE_MARGIN_LEFT & LV_STYLE_PROP_ALL},
{ATTR_TRANSITION_PROP_6, LV_STYLE_TRANSITION_PROP_6 & LV_STYLE_PROP_ALL},
// {ATTR_MARGIN_RIGHT, LV_STYLE_MARGIN_RIGHT & LV_STYLE_PROP_ALL},
{ATTR_BG_COLOR, LV_STYLE_BG_COLOR & LV_STYLE_PROP_ALL},
{ATTR_BORDER_COLOR, LV_STYLE_BORDER_COLOR & LV_STYLE_PROP_ALL},
{ATTR_OUTLINE_COLOR, LV_STYLE_OUTLINE_COLOR & LV_STYLE_PROP_ALL},
{ATTR_PATTERN_RECOLOR, LV_STYLE_PATTERN_RECOLOR & LV_STYLE_PROP_ALL},
{ATTR_VALUE_COLOR, LV_STYLE_VALUE_COLOR & LV_STYLE_PROP_ALL},
{ATTR_TEXT_COLOR, LV_STYLE_TEXT_COLOR & LV_STYLE_PROP_ALL},
{ATTR_LINE_COLOR, LV_STYLE_LINE_COLOR & LV_STYLE_PROP_ALL},
{ATTR_IMAGE_RECOLOR, LV_STYLE_IMAGE_RECOLOR & LV_STYLE_PROP_ALL},
{ATTR_SCALE_GRAD_COLOR, LV_STYLE_SCALE_GRAD_COLOR & LV_STYLE_PROP_ALL},
{ATTR_BG_GRAD_COLOR, LV_STYLE_BG_GRAD_COLOR & LV_STYLE_PROP_ALL},
{ATTR_TEXT_SEL_COLOR, LV_STYLE_TEXT_SEL_COLOR & LV_STYLE_PROP_ALL},
{ATTR_SCALE_END_COLOR, LV_STYLE_SCALE_END_COLOR & LV_STYLE_PROP_ALL},
// {ATTR_TEXT_SEL_BG_COLOR, LV_STYLE_TEXT_SEL_BG_COLOR & LV_STYLE_PROP_ALL},
{ATTR_OPA_SCALE, LV_STYLE_OPA_SCALE & LV_STYLE_PROP_ALL},
{ATTR_BG_OPA, LV_STYLE_BG_OPA & LV_STYLE_PROP_ALL},
{ATTR_BORDER_OPA, LV_STYLE_BORDER_OPA & LV_STYLE_PROP_ALL},
{ATTR_OUTLINE_OPA, LV_STYLE_OUTLINE_OPA & LV_STYLE_PROP_ALL},
{ATTR_PATTERN_OPA, LV_STYLE_PATTERN_OPA & LV_STYLE_PROP_ALL},
{ATTR_VALUE_OPA, LV_STYLE_VALUE_OPA & LV_STYLE_PROP_ALL},
{ATTR_TEXT_OPA, LV_STYLE_TEXT_OPA & LV_STYLE_PROP_ALL},
{ATTR_LINE_OPA, LV_STYLE_LINE_OPA & LV_STYLE_PROP_ALL},
{ATTR_IMAGE_OPA, LV_STYLE_IMAGE_OPA & LV_STYLE_PROP_ALL},
{ATTR_PATTERN_RECOLOR_OPA, LV_STYLE_PATTERN_RECOLOR_OPA & LV_STYLE_PROP_ALL},
{ATTR_IMAGE_RECOLOR_OPA, LV_STYLE_IMAGE_RECOLOR_OPA & LV_STYLE_PROP_ALL},
{ATTR_PATTERN_IMAGE, LV_STYLE_PATTERN_IMAGE & LV_STYLE_PROP_ALL},
{ATTR_VALUE_FONT, LV_STYLE_VALUE_FONT & LV_STYLE_PROP_ALL},
{ATTR_TEXT_FONT, LV_STYLE_TEXT_FONT & LV_STYLE_PROP_ALL},
{ATTR_TRANSITION_PATH, LV_STYLE_TRANSITION_PATH & LV_STYLE_PROP_ALL},
{ATTR_VALUE_STR, LV_STYLE_VALUE_STR & LV_STYLE_PROP_ALL},
#if LV_USE_SHADOW
{ATTR_SHADOW_WIDTH, LV_STYLE_SHADOW_WIDTH & LV_STYLE_PROP_ALL},
{ATTR_SHADOW_OFS_X, LV_STYLE_SHADOW_OFS_X & LV_STYLE_PROP_ALL},
{ATTR_SHADOW_OFS_Y, LV_STYLE_SHADOW_OFS_Y & LV_STYLE_PROP_ALL},
{ATTR_SHADOW_SPREAD, LV_STYLE_SHADOW_SPREAD & LV_STYLE_PROP_ALL},
{ATTR_SHADOW_COLOR, LV_STYLE_SHADOW_COLOR & LV_STYLE_PROP_ALL},
{ATTR_SHADOW_OPA, LV_STYLE_SHADOW_OPA & LV_STYLE_PROP_ALL},
#endif
#if LV_USE_BLEND_MODES && LV_USE_SHADOW
{ATTR_SHADOW_BLEND_MODE, LV_STYLE_SHADOW_BLEND_MODE & LV_STYLE_PROP_ALL},
#endif
#if LV_USE_BLEND_MODES
{ATTR_BG_BLEND_MODE, LV_STYLE_BG_BLEND_MODE & LV_STYLE_PROP_ALL},
{ATTR_PATTERN_BLEND_MODE, LV_STYLE_PATTERN_BLEND_MODE & LV_STYLE_PROP_ALL},
{ATTR_IMAGE_BLEND_MODE, LV_STYLE_IMAGE_BLEND_MODE & LV_STYLE_PROP_ALL},
{ATTR_LINE_BLEND_MODE, LV_STYLE_LINE_BLEND_MODE & LV_STYLE_PROP_ALL},
{ATTR_BORDER_BLEND_MODE, LV_STYLE_BORDER_BLEND_MODE & LV_STYLE_PROP_ALL},
{ATTR_OUTLINE_BLEND_MODE, LV_STYLE_OUTLINE_BLEND_MODE & LV_STYLE_PROP_ALL},
{ATTR_VALUE_BLEND_MODE, LV_STYLE_VALUE_BLEND_MODE & LV_STYLE_PROP_ALL},
{ATTR_TEXT_BLEND_MODE, LV_STYLE_TEXT_BLEND_MODE & LV_STYLE_PROP_ALL},
#endif
};
for(uint32_t i = 0; i < sizeof(props) / sizeof(props[0]); i++) {
if(props[i].hash == hash) {
*prop = props[1].prop;
LOG_WARNING(TAG_ATTR, F("%d found and has propery %d"), hash, props[i].prop);
return true;
}
}
LOG_ERROR(TAG_ATTR, F("%d has no property id"), hash);
return false;
}
static bool attribute_get_lv_property()
{
lv_res_t res _lv_style_get_int(const lv_style_t * style, lv_style_property_t prop, void * res);
return res == LV_RES_OK
}
static bool attribute_set_lv_property()
{
lv_res_t res _lv_style_get_int(const lv_style_t * style, lv_style_property_t prop, void * res);
return res == LV_RES_OK
}
static bool attribute_update_lv_property(lv_obj_t * obj, const char * attr_p, uint16_t attr_hash, const char * payload,
bool update)
{
uint8_t prop;
uint8_t prop_type;
// convert sdbm hash to lv property number
if(!attribute_lookup_lv_property(attr_hash, &prop)) return false;
// find the parameter type for this property
prop_type = prop & 0xF;
if(prop_type < LV_STYLE_ID_COLOR) {
if(update) {
_lv_obj_set_style_local_int(obj, part, prop | (state << LV_STYLE_STATE_POS), atoi(payload))
} else {
attr_out_str(obj, attr_p, lv_obj_get_style_value_str(obj, part));
}
} else if(prop_type < LV_STYLE_ID_OPA) {
} else if(prop_type < LV_STYLE_ID_PTR) {
} else {
}
}
#endif

View File

@ -1,8 +1,6 @@
/* MIT License - Copyright (c) 2019-2021 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#include <stdint.h>
//#include "ArduinoLog.h"
#include "hasplib.h"
@ -38,20 +36,13 @@
#include "hasp_config.h"
#endif
extern uint8_t hasp_sleep_state;
dispatch_conf_t dispatch_setings = {.teleperiod = 300};
uint32_t dispatchLastMillis;
uint8_t nCommands = 0;
haspCommand_t commands[18];
uint32_t dispatchLastMillis = -3000000; // force discovery
uint8_t nCommands = 0;
haspCommand_t commands[20];
struct moodlight_t
{
uint8_t power;
uint8_t r, g, b;
};
moodlight_t moodlight;
moodlight_t moodlight = {.brightness = 255};
// static void dispatch_config(const char* topic, const char* payload);
// void dispatch_group_value(uint8_t groupid, int16_t state, lv_obj_t * obj);
@ -73,10 +64,10 @@ void dispatch_state_subtopic(const char* subtopic, const char* payload)
LOG_ERROR(TAG_MQTT_PUB, F(D_MQTT_FAILED " %s => %s"), subtopic, payload);
break;
case MQTT_ERR_NO_CONN:
LOG_ERROR(TAG_MQTT, F(D_MQTT_NOT_CONNECTED));
LOG_ERROR(TAG_MQTT, F(D_MQTT_NOT_CONNECTED " %s => %s"), subtopic, payload);
break;
default:
LOG_ERROR(TAG_MQTT, F(D_ERROR_UNKNOWN));
LOG_ERROR(TAG_MQTT, F(D_ERROR_UNKNOWN " %s => %s"), subtopic, payload);
}
#endif
@ -110,7 +101,7 @@ void dispatch_json_error(uint8_t tag, DeserializationError& jsonError)
}
// p[x].b[y].attr=value
static inline bool dispatch_parse_button_attribute(const char* topic_p, const char* payload)
static inline bool dispatch_parse_button_attribute(const char* topic_p, const char* payload, bool update)
{
long num;
char* pEnd;
@ -155,99 +146,83 @@ static inline bool dispatch_parse_button_attribute(const char* topic_p, const ch
if(*topic_p != '.') return false; // obligated seperator
topic_p++;
hasp_process_attribute(pageid, objid, topic_p, payload);
hasp_process_attribute(pageid, objid, topic_p, payload, update);
return true;
/*
if(sscanf(topic_p, HASP_OBJECT_NOTATION ".", &pageid, &objid) == 2) { // Literal String
// OK, continue below
} else if(sscanf(topic_p, "p[%u].b[%u].", &pageid, &objid) == 2) { // Literal String
// TODO: obsolete old syntax p[x].b[y].
// OK, continue below
while(*topic_p++ != '.') {
// strip to '.' character
}
} else {
return false;
}
while(*topic_p != '.') {
if(*topic_p == 0) return false; // strip to '.' character
topic_p++;
}
hasp_process_attribute((uint8_t)pageid, (uint8_t)objid, topic_p, payload);
return true; */
// String strPageId((char *)0);
// String strTemp((char *)0);
// strPageId = strTopic.substring(2, strTopic.indexOf("]"));
// strTemp = strTopic.substring(strTopic.indexOf("]") + 1, strTopic.length());
// if(strTemp.startsWith(".b[")) {
// String strObjId((char *)0);
// String strAttr((char *)0);
// strObjId = strTemp.substring(3, strTemp.indexOf("]"));
// strAttr = strTemp.substring(strTemp.indexOf("]") + 1, strTemp.length());
// // debugPrintln(strPageId + " && " + strObjId + " && " + strAttr);
// pageid = strPageId.toInt();
// objid = strObjId.toInt();
// if(pageid >= 0 && pageid <= 255 && objid >= 0 && objid <= 255) {
// hasp_process_attribute(pageid, objid, strAttr.c_str(), payload);
// } // valid page
// }
}
static void dispatch_gpio(const char* topic, const char* payload)
{
#if HASP_USE_GPIO > 0
int16_t val;
uint8_t pin;
if(topic == strstr_P(topic, PSTR("relay"))) {
topic += 5;
val = Parser::is_true(payload);
} else if(topic == strstr_P(topic, PSTR("led"))) {
topic += 3;
val = atoi(payload);
} else if(topic == strstr_P(topic, PSTR("pwm"))) {
topic += 3;
val = atoi(payload);
} else {
LOG_WARNING(TAG_MSGR, F("Invalid gpio %s"), topic);
if(!Parser::is_only_digits(topic)) {
LOG_WARNING(TAG_MSGR, F("Invalid pin %s"), topic);
return;
}
if(Parser::is_only_digits(topic)) {
pin = atoi(topic);
if(strlen(payload) > 0) {
gpio_set_value(pin, val);
uint8_t pin = atoi(topic);
if(strlen(payload) > 0) {
size_t maxsize = (128u * ((strlen(payload) / 128) + 1)) + 128;
DynamicJsonDocument json(maxsize);
// Note: Deserialization needs to be (const char *) so the objects WILL be copied
// this uses more memory but otherwise the mqtt receive buffer can get overwritten by the send buffer !!
DeserializationError jsonError = deserializeJson(json, payload);
json.shrinkToFit();
if(jsonError) { // Couldn't parse incoming JSON command
dispatch_json_error(TAG_MSGR, jsonError);
} else {
gpio_get_value(pin);
// Save the current state
int32_t state_value;
bool power_state;
bool updated = false;
if(!gpio_get_pin_state(pin, power_state, state_value)) {
LOG_WARNING(TAG_GPIO, F(D_BULLET "Pin %d can not be set"), pin);
return;
}
JsonVariant state = json[F("state")];
JsonVariant value = json[F("val")];
// Check if the state needs to change
if(!state.isNull() && power_state != state.as<bool>()) {
power_state = state.as<bool>();
updated = true;
}
if(!value.isNull() && state_value != value.as<int32_t>()) {
state_value = value.as<int32_t>();
updated = true;
}
// Set new state
if(updated && gpio_set_pin_state(pin, power_state, state_value)) {
return; // value was set and state output already
} else {
// output the new state to the log
}
}
} else {
LOG_WARNING(TAG_MSGR, F("Invalid pin %s"), topic);
}
// just output this pin
if(!gpio_output_pin_state(pin)) {
LOG_WARNING(TAG_GPIO, F(D_BULLET "Pin %d is not configured"), pin);
}
#endif
}
// objectattribute=value
void dispatch_command(const char* topic, const char* payload)
void dispatch_command(const char* topic, const char* payload, bool update)
{
/* ================================= Standard payload commands ======================================= */
if(dispatch_parse_button_attribute(topic, payload, update)) return; // matched pxby.attr, first for speed
// check and execute commands from commands array
for(int i = 0; i < nCommands; i++) {
if(!strcasecmp_P(topic, commands[i].p_cmdstr)) {
@ -259,16 +234,14 @@ void dispatch_command(const char* topic, const char* payload)
/* =============================== Not standard payload commands ===================================== */
if(topic == strstr_P(topic, PSTR("gpio/"))) {
// if(topic == strstr_P(topic, PSTR("gpio/"))) {
if(topic == strstr_P(topic, PSTR("output"))) {
dispatch_gpio(topic + 5, payload);
dispatch_gpio(topic + 6, payload);
// } else if(strcasecmp_P(topic, PSTR("screenshot")) == 0) {
// guiTakeScreenshot("/screenshot.bmp"); // Literal String
} else if((topic[0] == 'p' || topic[0] == 'P') && dispatch_parse_button_attribute(topic, payload)) {
return; // matched pxby.attr
#if HASP_USE_CONFIG > 0
#if HASP_USE_WIFI > 0
@ -292,7 +265,6 @@ void dispatch_command(const char* topic, const char* payload)
#endif // HASP_USE_MQTT
#endif // HASP_USE_CONFIG
} else {
if(strlen(payload) == 0) {
// dispatch_text_line(topic); // Could cause an infinite loop!
@ -302,30 +274,28 @@ void dispatch_command(const char* topic, const char* payload)
}
// Strip command/config prefix from the topic and process the payload
void dispatch_topic_payload(const char* topic, const char* payload)
void dispatch_topic_payload(const char* topic, const char* payload, bool update)
{
// LOG_VERBOSE(TAG_MSGR,F("TOPIC: short topic: %s"), topic);
if(!strcmp_P(topic, PSTR("command"))) {
if(!strcmp_P(topic, PSTR(MQTT_TOPIC_COMMAND))) {
dispatch_text_line((char*)payload);
return;
}
if(topic == strstr_P(topic, PSTR("command/"))) { // startsWith command/
if(topic == strstr_P(topic, PSTR(MQTT_TOPIC_COMMAND "/"))) { // startsWith command/
topic += 8u;
dispatch_command(topic, (char*)payload);
dispatch_command(topic, (char*)payload, update);
return;
}
#if HASP_USE_CONFIG > 0
if(topic == strstr_P(topic, PSTR("config/"))) { // startsWith command/
if(topic == strstr_P(topic, PSTR("config/"))) { // startsWith config/
topic += 7u;
dispatch_config(topic, (char*)payload);
return;
}
#endif
dispatch_command(topic, (char*)payload); // dispatch as is
dispatch_command(topic, (char*)payload, update); // dispatch as is
}
// Parse one line of text and execute the command
@ -334,14 +304,16 @@ void dispatch_text_line(const char* cmnd)
size_t pos1 = std::string(cmnd).find("=");
size_t pos2 = std::string(cmnd).find(" ");
size_t pos = 0;
bool update = false;
// Find what comes first, ' ' or '='
if(pos1 != std::string::npos) {
if(pos2 != std::string::npos) {
if(pos1 != std::string::npos) { // '=' found
if(pos2 != std::string::npos) { // ' ' found
pos = (pos1 < pos2 ? pos1 : pos2);
} else {
pos = pos1;
}
update = pos == pos1; // equal sign wins
} else {
pos = (pos2 != std::string::npos) ? pos2 : 0;
@ -356,40 +328,16 @@ void dispatch_text_line(const char* cmnd)
memcpy(topic, cmnd, sizeof(topic) - 1);
// topic is before '=', payload is after '=' position
LOG_TRACE(TAG_MSGR, F("%s=%s"), topic, cmnd + pos + 1);
dispatch_topic_payload(topic, cmnd + pos + 1);
update |= strlen(cmnd + pos + 1) > 0; // equal sign OR space with payload
LOG_TRACE(TAG_MSGR, update ? F("%s=%s") : F("%s%s"), topic, cmnd + pos + 1);
dispatch_topic_payload(topic, cmnd + pos + 1, update);
} else {
char empty_payload[1] = {0};
LOG_TRACE(TAG_MSGR, F("%s=%s"), cmnd, empty_payload);
dispatch_topic_payload(cmnd, empty_payload);
LOG_TRACE(TAG_MSGR, cmnd);
dispatch_topic_payload(cmnd, empty_payload, false);
}
}
void dispatch_get_idle_state(uint8_t state, char* payload)
{
switch(state) {
case HASP_SLEEP_LONG:
memcpy_P(payload, PSTR("long"), 5);
break;
case HASP_SLEEP_SHORT:
memcpy_P(payload, PSTR("short"), 6);
break;
default:
memcpy_P(payload, PSTR("off"), 4);
}
}
// send idle state to the client
void dispatch_output_idle_state(uint8_t state)
{
char topic[6];
char payload[6];
memcpy_P(topic, PSTR("idle"), 5);
dispatch_get_idle_state(state, payload);
dispatch_state_subtopic(topic, payload);
}
// void dispatch_output_group_state(uint8_t groupid, uint16_t state)
// {
// char payload[64];
@ -506,47 +454,20 @@ void dispatch_config(const char* topic, const char* payload)
#endif // HASP_USE_CONFIG
/********************************************** Output States ******************************************/
/*
static inline void dispatch_state_msg(const __FlashStringHelper* subtopic, const char* payload)
void dispatch_normalized_group_values(hasp_update_value_t& value)
{
if(value.group == 0) return;
}*/
// void dispatch_group_onoff(uint8_t groupid, uint16_t eventid, lv_obj_t * obj)
// {
// if((eventid == HASP_EVENT_LONG) || (eventid == HASP_EVENT_HOLD)) return; // don't send repeat events
// if(groupid >= 0) {
// bool state = Parser::get_event_state(eventid);
// gpio_set_group_onoff(groupid, state);
// object_set_normalized_group_value(groupid, eventid, obj);
// }
// char payload[8];
// Parser::get_event_name(eventid, payload, sizeof(payload));
// // dispatch_output_group_state(groupid, payload);
// }
// void dispatch_group_value(uint8_t groupid, int16_t state, lv_obj_t * obj)
// {
// if(groupid >= 0) {
// gpio_set_group_value(groupid, state);
// object_set_normalized_group_value(groupid, state, obj);
// }
// char payload[8];
// // dispatch_output_group_state(groupid, payload);
// }
void dispatch_normalized_group_value(uint8_t groupid, lv_obj_t* obj, int16_t val, int16_t min, int16_t max)
{
if(groupid == 0) return;
LOG_VERBOSE(TAG_MSGR, F("GROUP %d value %d (%d-%d)"), groupid, val, min, max);
#if HASP_USE_GPIO > 0
gpio_set_normalized_group_value(groupid, val, min, max); // Update GPIO states
gpio_set_normalized_group_values(value); // Update GPIO states first
#endif
object_set_normalized_group_values(value); // Update onsreen objects except originating obj
LOG_VERBOSE(TAG_MSGR, F("GROUP %d value %d (%d-%d)"), value.group, value.val, value.min, value.max);
#if HASP_USE_GPIO > 0
gpio_output_group_values(value.group); // Output new gpio values
#endif
object_set_normalized_group_value(groupid, obj, val, min, max); // Update onsreen objects
}
/********************************************** Native Commands ****************************************/
@ -560,7 +481,7 @@ void dispatch_screenshot(const char*, const char* filename)
memcpy_P(tempfile, PSTR("/screenshot.bmp"), sizeof(tempfile));
guiTakeScreenshot(tempfile);
} else if(strlen(filename) > 31 || filename[0] != '/') { // Invalid filename
LOG_WARNING(TAG_MSGR, "Invalid filename %s", filename);
LOG_WARNING(TAG_MSGR, F("D_FILE_SAVE_FAILED"), filename);
} else { // Valid filename
guiTakeScreenshot(filename);
}
@ -611,6 +532,9 @@ void dispatch_parse_json(const char*, const char* payload)
} else if(json.is<const char*>()) { // handle json as a single command
dispatch_text_line(json.as<const char*>());
// } else if(json.is<char*>()) { // handle json as a single command
// dispatch_text_line(json.as<char*>());
} else {
LOG_WARNING(TAG_MSGR, F(D_DISPATCH_COMMAND_NOT_FOUND), payload);
}
@ -623,7 +547,7 @@ void dispatch_parse_jsonl(std::istream& stream)
#endif
{
uint8_t savedPage = haspPages.get();
size_t line = 1;
uint16_t line = 1;
DynamicJsonDocument jsonl(MQTT_MAX_PACKET_SIZE / 2 + 128); // max ~256 characters per line
DeserializationError jsonError = deserializeJson(jsonl, stream);
@ -660,7 +584,7 @@ void dispatch_parse_jsonl(const char*, const char* payload)
#endif
}
void dispatch_output_current_page()
void dispatch_current_page()
{
char topic[8];
char payload[8];
@ -674,19 +598,19 @@ void dispatch_output_current_page()
void dispatch_page_next(lv_scr_load_anim_t animation)
{
haspPages.next(animation);
dispatch_output_current_page();
dispatch_current_page();
}
void dispatch_page_prev(lv_scr_load_anim_t animation)
{
haspPages.prev(animation);
dispatch_output_current_page();
dispatch_current_page();
}
void dispatch_page_back(lv_scr_load_anim_t animation)
{
haspPages.back(animation);
dispatch_output_current_page();
dispatch_current_page();
}
void dispatch_set_page(uint8_t pageid)
@ -697,13 +621,13 @@ void dispatch_set_page(uint8_t pageid)
void dispatch_set_page(uint8_t pageid, lv_scr_load_anim_t animation)
{
haspPages.set(pageid, animation);
dispatch_output_current_page();
dispatch_current_page();
}
void dispatch_page(const char*, const char* page)
{
if(strlen(page) == 0) {
dispatch_output_current_page(); // No payload, send current page
dispatch_current_page(); // No payload, send current page
return;
}
@ -756,7 +680,7 @@ void dispatch_moodlight(const char* topic, const char* payload)
// Set the current state
if(strlen(payload) != 0) {
size_t maxsize = (128u * ((strlen(payload) / 128) + 1)) + 512;
size_t maxsize = (128u * ((strlen(payload) / 128) + 1)) + 128;
DynamicJsonDocument json(maxsize);
// Note: Deserialization needs to be (const char *) so the objects WILL be copied
@ -771,19 +695,20 @@ void dispatch_moodlight(const char* topic, const char* payload)
if(!json[F("state")].isNull())
moodlight.power = Parser::is_true(json[F("state")].as<std::string>().c_str());
if(!json["r"].isNull()) moodlight.r = json["r"].as<uint8_t>();
if(!json["g"].isNull()) moodlight.g = json["g"].as<uint8_t>();
if(!json["b"].isNull()) moodlight.b = json["b"].as<uint8_t>();
if(!json["r"].isNull()) moodlight.rgbww[0] = json["r"].as<uint8_t>();
if(!json["g"].isNull()) moodlight.rgbww[1] = json["g"].as<uint8_t>();
if(!json["b"].isNull()) moodlight.rgbww[2] = json["b"].as<uint8_t>();
if(!json["brightness"].isNull()) moodlight.brightness = json["brightness"].as<uint8_t>();
if(!json[F("color")].isNull()) {
if(!json[F("color")]["r"].isNull()) {
moodlight.r = json[F("color")]["r"].as<uint8_t>();
moodlight.rgbww[0] = json[F("color")]["r"].as<uint8_t>();
}
if(!json[F("color")]["g"].isNull()) {
moodlight.g = json[F("color")]["g"].as<uint8_t>();
moodlight.rgbww[1] = json[F("color")]["g"].as<uint8_t>();
}
if(!json[F("color")]["b"].isNull()) {
moodlight.b = json[F("color")]["b"].as<uint8_t>();
moodlight.rgbww[2] = json[F("color")]["b"].as<uint8_t>();
}
// lv_color32_t color;
// if(Parser::haspPayloadToColor(json[F("color")].as<const char*>(), color)) {
@ -794,10 +719,7 @@ void dispatch_moodlight(const char* topic, const char* payload)
}
#if HASP_USE_GPIO > 0
if(moodlight.power)
gpio_set_moodlight(moodlight.r, moodlight.g, moodlight.b);
else
gpio_set_moodlight(0, 0, 0);
gpio_set_moodlight(moodlight);
#endif
}
}
@ -809,8 +731,9 @@ void dispatch_moodlight(const char* topic, const char* payload)
snprintf_P(
// buffer, sizeof(buffer),
// PSTR("{\"state\":\"%s\",\"color\":\"#%02x%02x%02x\",\"r\":%u,\"g\":%u,\"b\":%u}"),
buffer, sizeof(buffer), PSTR("{\"state\":\"%s\",\"color\":{\"r\":%u,\"g\":%u,\"b\":%u}}"),
moodlight.power ? "ON" : "OFF", moodlight.r, moodlight.g, moodlight.b);
buffer, sizeof(buffer), PSTR("{\"state\":\"%s\",\"color\":{\"r\":%u,\"g\":%u,\"b\":%u,\"brightness\":%u}}"),
moodlight.power ? "ON" : "OFF", moodlight.rgbww[0], moodlight.rgbww[1], moodlight.rgbww[2],
moodlight.brightness);
dispatch_state_subtopic(out_topic, buffer);
}
@ -873,32 +796,66 @@ void dispatch_reboot(bool saveConfig)
haspDevice.reboot();
}
void dispatch_current_state()
{
dispatch_output_statusupdate(NULL, NULL);
dispatch_output_idle_state(hasp_sleep_state);
dispatch_output_current_page();
}
/******************************************* Command Wrapper Functions *********************************/
// Periodically publish a JSON string indicating system status
void dispatch_output_statusupdate(const char*, const char*)
void dispatch_send_discovery(const char*, const char*)
{
#if HASP_USE_MQTT > 0
char data[512];
StaticJsonDocument<1024> doc;
doc[F("node")] = haspDevice.get_hostname();
doc[F("mdl")] = haspDevice.get_model();
doc[F("mf")] = F(D_MANUFACTURER);
doc[F("hwid")] = haspDevice.get_hardware_id();
doc[F("pages")] = haspPages.count();
doc[F("sw")] = haspDevice.get_version();
JsonObject input = doc.createNestedObject(F("input"));
JsonArray relay = doc.createNestedArray(F("power"));
JsonArray led = doc.createNestedArray(F("light"));
JsonArray dimmer = doc.createNestedArray(F("dim"));
#if HASP_USE_GPIO > 0
gpio_discovery(input, relay, led, dimmer);
#endif
char data[1024];
size_t len = serializeJson(doc, data);
switch(mqtt_send_discovery(data, len)) {
case MQTT_ERR_OK:
LOG_TRACE(TAG_MQTT_PUB, F(MQTT_TOPIC_DISCOVERY " => %s"), data);
break;
case MQTT_ERR_PUB_FAIL:
LOG_ERROR(TAG_MQTT_PUB, F(D_MQTT_FAILED " " MQTT_TOPIC_DISCOVERY " => %s"), data);
break;
case MQTT_ERR_NO_CONN:
LOG_ERROR(TAG_MQTT, F(D_MQTT_NOT_CONNECTED));
break;
default:
LOG_ERROR(TAG_MQTT, F(D_ERROR_UNKNOWN));
}
// dispatchLastMillis = millis();
#endif
}
// Periodically publish a JSON string indicating system status
void dispatch_statusupdate(const char*, const char*)
{
#if HASP_USE_MQTT > 0
char data[400];
char topic[16];
{
char buffer[128];
haspGetVersion(buffer, sizeof(buffer));
dispatch_get_idle_state(hasp_sleep_state, topic);
snprintf_P(data, sizeof(data),
PSTR("{\"node\":\"%s\",\"manufacturer\":\"" D_MANUFACTURER
"\",\"model\":\"%s\",\"idle\":\"%s\",\"version\":\"%s\",\"uptime\":%lu,"),
haspDevice.get_hostname(), haspDevice.get_model(), topic, buffer,
(unsigned long)(millis() / 1000)); // \"status\":\"available\",
hasp_get_sleep_state(topic);
snprintf_P(data, sizeof(data), PSTR("{\"node\":\"%s\",\"idle\":\"%s\",\"version\":\"%s\",\"uptime\":%lu,"),
haspDevice.get_hostname(), topic, haspDevice.get_version(),
long(millis() / 1000)); // \"status\":\"available\",
#if HASP_USE_WIFI > 0 || HASP_USE_ETHERNET > 0
network_get_statusupdate(buffer, sizeof(buffer));
@ -930,10 +887,25 @@ void dispatch_output_statusupdate(const char*, const char*)
dispatch_state_subtopic(topic, data);
dispatchLastMillis = millis();
/* if(updateEspAvailable) {
mqttStatusPayload += F("\"updateEspAvailable\":true,");
} else {
mqttStatusPayload += F("\"updateEspAvailable\":false,");
}
*/
#endif
}
void dispatch_calibrate(const char* topic = NULL, const char* payload = NULL)
void dispatch_current_state()
{
dispatch_statusupdate(NULL, NULL);
dispatch_idle(NULL, NULL);
dispatch_current_page();
dispatch_send_discovery(NULL, NULL);
}
void dispatch_calibrate(const char*, const char*)
{
guiCalibrate();
}
@ -949,6 +921,16 @@ void dispatch_sleep(const char*, const char*)
hasp_enable_wakeup_touch();
}
void dispatch_idle(const char*, const char*)
{
char topic[6];
char payload[6];
memcpy_P(topic, PSTR("idle"), 5);
hasp_get_sleep_state(payload);
dispatch_state_subtopic(topic, payload);
}
void dispatch_reboot(const char*, const char*)
{
dispatch_reboot(true);
@ -981,15 +963,18 @@ void dispatchSetup()
// In order of importance : commands are NOT case-sensitive
// The command.func() call will receive the full topic and payload parameters!
LOG_TRACE(TAG_MSGR, F(D_SERVICE_STARTING));
/* WARNING: remember to expand the commands array when adding new commands */
dispatch_add_command(PSTR("json"), dispatch_parse_json);
dispatch_add_command(PSTR("page"), dispatch_page);
dispatch_add_command(PSTR("wakeup"), dispatch_wakeup);
dispatch_add_command(PSTR("sleep"), dispatch_sleep);
dispatch_add_command(PSTR("statusupdate"), dispatch_output_statusupdate);
dispatch_add_command(PSTR("statusupdate"), dispatch_statusupdate);
dispatch_add_command(PSTR("clearpage"), dispatch_clear_page);
dispatch_add_command(PSTR("jsonl"), dispatch_parse_jsonl);
dispatch_add_command(PSTR("dim"), dispatch_dim);
dispatch_add_command(PSTR("idle"), dispatch_idle);
dispatch_add_command(PSTR("brightness"), dispatch_dim);
dispatch_add_command(PSTR("light"), dispatch_backlight);
dispatch_add_command(PSTR("moodlight"), dispatch_moodlight);
@ -998,24 +983,27 @@ void dispatchSetup()
dispatch_add_command(PSTR("reboot"), dispatch_reboot);
dispatch_add_command(PSTR("restart"), dispatch_reboot);
dispatch_add_command(PSTR("screenshot"), dispatch_screenshot);
dispatch_add_command(PSTR("discovery"), dispatch_send_discovery);
dispatch_add_command(PSTR("factoryreset"), dispatch_factory_reset);
#if HASP_USE_CONFIG > 0
dispatch_add_command(PSTR("setupap"), oobeFakeSetup);
#endif
/* WARNING: remember to expand the commands array when adding new commands */
LOG_INFO(TAG_MSGR, F(D_SERVICE_STARTED));
}
void dispatchLoop()
{
lv_task_handler(); // process animations
}
IRAM_ATTR void dispatchLoop()
{}
#if 1 || ARDUINO
void dispatchEverySecond()
{
if(dispatch_setings.teleperiod > 0 && (millis() - dispatchLastMillis) >= dispatch_setings.teleperiod * 1000) {
if(mqttIsConnected() && dispatch_setings.teleperiod > 0 &&
(millis() - dispatchLastMillis) >= dispatch_setings.teleperiod * 1000) {
dispatchLastMillis += dispatch_setings.teleperiod * 1000;
dispatch_output_statusupdate(NULL, NULL);
dispatch_statusupdate(NULL, NULL);
dispatch_send_discovery(NULL, NULL);
}
}
#else
@ -1029,7 +1017,7 @@ void everySecond()
if(elapsed.count() >= dispatch_setings.teleperiod) {
std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now();
dispatch_output_statusupdate(NULL, NULL);
dispatch_statusupdate(NULL, NULL);
}
}
}

View File

@ -4,14 +4,20 @@
#ifndef HASP_DISPATCH_H
#define HASP_DISPATCH_H
#include "ArduinoJson.h"
#include "lvgl.h"
#include "hasplib.h"
struct dispatch_conf_t
{
uint16_t teleperiod;
};
struct moodlight_t
{
uint8_t brightness;
uint8_t power;
uint8_t rgbww[5];
};
enum hasp_event_t { // even = released, odd = pressed
HASP_EVENT_OFF = 0,
HASP_EVENT_ON = 1,
@ -23,18 +29,24 @@ enum hasp_event_t { // even = released, odd = pressed
HASP_EVENT_LOST = 7,
HASP_EVENT_DOUBLE = 8,
HASP_EVENT_OPEN = 10,
HASP_EVENT_OPENING = 11,
HASP_EVENT_CLOSED = 12,
HASP_EVENT_CLOSING = 13,
HASP_EVENT_STOP = 14,
HASP_EVENT_CHANGED = 32
};
/* ===== Default Event Processors ===== */
void dispatchSetup(void);
void dispatchLoop(void);
IRAM_ATTR void dispatchLoop(void);
void dispatchEverySecond(void);
void dispatchStart(void);
void dispatchStop(void);
/* ===== Special Event Processors ===== */
void dispatch_topic_payload(const char* topic, const char* payload);
void dispatch_topic_payload(const char* topic, const char* payload, bool update);
void dispatch_text_line(const char* cmnd);
#ifdef ARDUINO
@ -46,28 +58,25 @@ void dispatch_parse_jsonl(std::istream& stream);
void dispatch_clear_page(const char* page);
void dispatch_json_error(uint8_t tag, DeserializationError& jsonError);
// void dispatch_set_page(uint8_t pageid);
void dispatch_set_page(uint8_t pageid, lv_scr_load_anim_t effectid);
void dispatch_page_next(lv_scr_load_anim_t effectid);
void dispatch_page_prev(lv_scr_load_anim_t effectid);
void dispatch_page_back(lv_scr_load_anim_t effectid);
void dispatch_dim(const char* level);
void dispatch_backlight(const char*, const char* payload);
void dispatch_web_update(const char*, const char* espOtaUrl);
void dispatch_reboot(bool saveConfig);
void dispatch_output_idle_state(uint8_t state);
void dispatch_output_statusupdate(const char*, const char*);
void dispatch_current_state();
void dispatch_output_current_page();
void dispatch_current_page();
void dispatch_backlight(const char*, const char* payload);
void dispatch_web_update(const char*, const char* espOtaUrl);
void dispatch_statusupdate(const char*, const char*);
void dispatch_send_discovery(const char*, const char*);
void dispatch_idle(const char*, const char*);
void dispatch_calibrate(const char*, const char*);
void dispatch_wakeup(const char*, const char*);
void dispatch_gpio_input_event(uint8_t pin, uint8_t group, uint8_t eventid);
void dispatch_object_value_changed(lv_obj_t* obj, int16_t state);
void dispatch_normalized_group_value(uint8_t groupid, lv_obj_t* obj, int16_t val, int16_t min, int16_t max);
void dispatch_normalized_group_values(hasp_update_value_t& value);
void dispatch_state_subtopic(const char* subtopic, const char* payload);

View File

@ -22,9 +22,13 @@
*
******************************************************************************************** */
#include "hasp_conf.h"
#include <time.h>
#include <sys/time.h>
#include "hasplib.h"
#include "lv_core/lv_obj.h" // for tabview ext
static lv_style_int_t last_value_sent;
static lv_color_t last_color_sent;
@ -36,23 +40,117 @@ void swipe_event_handler(lv_obj_t* obj, lv_event_t event);
*/
static void event_delete_object(lv_obj_t* obj)
{
switch(obj->user_data.objid) {
switch(obj_get_type(obj)) {
case LV_HASP_LINE:
line_clear_points(obj);
break;
case LV_HASP_BTNMATRIX:
my_btnmatrix_map_clear(obj);
_LV_WIN_PART_REAL_LAST;
_LV_WIN_PART_VIRTUAL_LAST;
break;
case LV_HASP_MSGBOX:
my_msgbox_map_clear(obj);
break;
case LV_HASP_IMAGE:
lv_img_cache_invalidate_src(NULL);
break;
case LV_HASP_GAUGE:
break;
default:
break;
}
// TODO: delete value_str data for ALL parts
my_obj_set_value_str_txt(obj, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, NULL);
my_obj_set_value_str_text(obj, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, NULL);
}
/* ============================== Timer Event ============================ */
void event_timer_calendar(lv_task_t* task)
{
hasp_task_user_data_t* data = (hasp_task_user_data_t*)task->user_data;
lv_obj_t* obj = NULL;
if(data) obj = hasp_find_obj_from_page_id(data->pageid, data->objid);
if(!obj || !data || !obj_check_type(obj, LV_HASP_CALENDER)) {
if(data) lv_mem_free(data); // the object that the user_data points to is gone
lv_task_del(task); // the calendar object for this task was deleted
LOG_WARNING(TAG_EVENT, "event_timer_calendar could not find the linked object");
return;
}
lv_calendar_date_t date;
timeval curTime;
int rslt = gettimeofday(&curTime, NULL);
time_t t = curTime.tv_sec;
tm* timeinfo = localtime(&t);
(void)rslt; // unused
if(timeinfo->tm_year < 120) {
lv_task_set_period(task, 60000); // try again in a minute
LOG_WARNING(TAG_EVENT, "event_timer_calendar could not sync the clock");
return;
} else {
uint32_t next_hour = (3600 - (t % 3600)) * 1000; // ms to next top of hour
// lv_task_set_period(task, next_hour + 128); // small offset so all tasks don't run at once
lv_task_set_period(task, data->interval);
}
date.day = timeinfo->tm_mday;
date.month = timeinfo->tm_mon + 1; // months since January 0-11
date.year = timeinfo->tm_year + 1900; // years since 1900
LOG_VERBOSE(TAG_EVENT, "event_timer_calendar called with user %d:%d:%d", timeinfo->tm_hour, timeinfo->tm_min,
timeinfo->tm_sec);
lv_calendar_set_today_date(obj, &date);
}
void event_timer_clock(lv_task_t* task)
{
hasp_task_user_data_t* data = (hasp_task_user_data_t*)task->user_data;
lv_obj_t* obj;
if(data) obj = hasp_find_obj_from_page_id(data->pageid, data->objid);
if(!obj || !data) {
if(data) lv_mem_free(data); // the object that the user_data points to is gone
lv_task_del(task); // the calendar object for this task was deleted
LOG_WARNING(TAG_EVENT, "event_timer_clock could not find the linked object");
return;
}
timeval curTime;
int rslt = gettimeofday(&curTime, NULL);
time_t seconds = curTime.tv_sec;
tm* timeinfo = localtime(&seconds);
(void)rslt; // unused
char buffer[24] = {0};
if(timeinfo->tm_year < 120) {
snprintf_P(buffer, sizeof(buffer), PSTR("%d"), seconds);
} else {
strftime(buffer, sizeof(buffer), D_TIMESTAMP, timeinfo); // Literal String
}
// LOG_VERBOSE(TAG_EVENT, "event_timer_clock called with user %d:%d:%d", timeinfo->tm_hour, timeinfo->tm_min,
// timeinfo->tm_sec);
lv_label_set_text(obj, buffer);
lv_task_set_period(task, data->interval);
}
/* ============================== Timer Event ============================ */
void event_timer_refresh(lv_task_t* task)
{
lv_obj_t* obj = (lv_obj_t*)task->user_data;
printf("event_timer_refresh called with user data\n");
if(!obj) return;
lv_obj_invalidate(obj);
}
/* ============================== Event Senders ============================ */
@ -104,7 +202,7 @@ static bool translate_event(lv_obj_t* obj, lv_event_t event, uint8_t& eventid)
// ##################### Value Senders ########################################################
void event_send_object_data(lv_obj_t* obj, const char* data)
static void event_send_object_data(lv_obj_t* obj, const char* data)
{
uint8_t pageid;
uint8_t objid;
@ -118,7 +216,7 @@ void event_send_object_data(lv_obj_t* obj, const char* data)
}
// Send out events with a val attribute
void event_object_val_event(lv_obj_t* obj, uint8_t eventid, int16_t val)
static void event_object_val_event(lv_obj_t* obj, uint8_t eventid, int16_t val)
{
char data[40];
char eventname[8];
@ -129,7 +227,7 @@ void event_object_val_event(lv_obj_t* obj, uint8_t eventid, int16_t val)
}
// Send out events with a val and text attribute
void event_object_selection_changed(lv_obj_t* obj, uint8_t eventid, int16_t val, const char* text)
static void event_object_selection_changed(lv_obj_t* obj, uint8_t eventid, int16_t val, const char* text)
{
char data[200];
char eventname[8];
@ -141,24 +239,32 @@ void event_object_selection_changed(lv_obj_t* obj, uint8_t eventid, int16_t val,
// ##################### Event Handlers ########################################################
#if HASP_USE_GPIO > 0
void event_gpio_input(uint8_t pin, uint8_t group, uint8_t eventid)
static inline void event_update_group(uint8_t group, lv_obj_t* obj, bool power, int32_t val, int32_t min, int32_t max)
{
char payload[64];
char topic[8];
hasp_update_value_t value = {.obj = obj, .group = group, .min = min, .max = max, .val = val, .power = power};
dispatch_normalized_group_values(value);
}
#if HASP_USE_GPIO > 0
void event_gpio_input(uint8_t pin, uint8_t eventid)
{
char payload[32];
char topic[10];
char eventname[8];
Parser::get_event_name(eventid, eventname, sizeof(eventname));
snprintf_P(payload, sizeof(payload), PSTR("{\"pin\":%d,\"group\":%d,\"event\":\"%s\"}"), pin, group, eventname);
memcpy_P(topic, PSTR("input"), 6);
snprintf_P(topic, sizeof(topic), PSTR("input%d"), pin);
if(eventid == HASP_EVENT_ON || eventid == HASP_EVENT_OFF) {
Parser::get_event_name(HASP_EVENT_CHANGED, eventname, sizeof(eventname));
snprintf_P(payload, sizeof(payload), PSTR("{\"event\":\"%s\",\"val\":%d}"), eventname, eventid);
} else {
Parser::get_event_name(eventid, eventname, sizeof(eventname));
snprintf_P(payload, sizeof(payload), PSTR("{\"event\":\"%s\"}"), eventname);
}
dispatch_state_subtopic(topic, payload);
// update outputstates
// dispatch_group_onoff(group, Parser::get_event_state(eventid), NULL);
}
#endif
void log_event(const char* name, lv_event_t event)
static void log_event(const char* name, lv_event_t event)
{
return;
@ -252,7 +358,7 @@ void swipe_event_handler(lv_obj_t* obj, lv_event_t event)
default:
return;
}
dispatch_output_current_page();
dispatch_current_page();
}
}
@ -338,7 +444,7 @@ void generic_event_handler(lv_obj_t* obj, lv_event_t event)
default:
haspPages.set(obj->user_data.actionid, transitionid);
}
dispatch_output_current_page();
dispatch_current_page();
}
} else {
char data[40];
@ -347,8 +453,12 @@ void generic_event_handler(lv_obj_t* obj, lv_event_t event)
snprintf_P(data, sizeof(data), PSTR("{\"event\":\"%s\"}"), eventname);
event_send_object_data(obj, data);
}
dispatch_normalized_group_value(obj->user_data.groupid, obj, Parser::get_event_state(last_value_sent),
HASP_EVENT_OFF, HASP_EVENT_ON);
// Update group objects and gpios on release
if(last_value_sent != LV_EVENT_LONG_PRESSED || last_value_sent != LV_EVENT_LONG_PRESSED_REPEAT) {
bool state = Parser::get_event_state(last_value_sent);
event_update_group(obj->user_data.groupid, obj, state, state, HASP_EVENT_OFF, HASP_EVENT_ON);
}
}
/**
@ -387,7 +497,12 @@ void toggle_event_handler(lv_obj_t* obj, lv_event_t event)
}
event_object_val_event(obj, hasp_event_id, last_value_sent);
dispatch_normalized_group_value(obj->user_data.groupid, obj, last_value_sent, HASP_EVENT_OFF, HASP_EVENT_ON);
// Update group objects and gpios on release
if(obj->user_data.groupid && hasp_event_id == HASP_EVENT_UP) {
event_update_group(obj->user_data.groupid, obj, last_value_sent, last_value_sent, HASP_EVENT_OFF,
HASP_EVENT_ON);
}
}
/**
@ -422,6 +537,15 @@ void selector_event_handler(lv_obj_t* obj, lv_event_t event)
lv_roller_get_selected_str(obj, buffer, sizeof(buffer));
break;
case LV_HASP_TABVIEW: {
val = lv_tabview_get_tab_act(obj);
max = lv_tabview_get_tab_count(obj) - 1;
lv_tabview_ext_t* ext = (lv_tabview_ext_t*)lv_obj_get_ext_attr(obj);
strcpy(buffer, ext->tab_name_ptr[val]);
break;
}
case LV_HASP_TABLE: {
uint16_t row;
uint16_t col;
@ -442,7 +566,11 @@ void selector_event_handler(lv_obj_t* obj, lv_event_t event)
if(hasp_event_id == HASP_EVENT_CHANGED && last_value_sent == val) return; // same value as before
last_value_sent = val;
event_object_selection_changed(obj, hasp_event_id, val, buffer);
// if(max > 0) dispatch_normalized_group_value(obj->user_data.groupid, obj, val, 0, max);
if(obj->user_data.groupid && max > 0) // max a cannot be 0, its the divider
if(hasp_event_id == HASP_EVENT_UP || hasp_event_id == LV_EVENT_VALUE_CHANGED) {
event_update_group(obj->user_data.groupid, obj, !!last_value_sent, last_value_sent, 0, max);
}
// set the property
// snprintf_P(property, sizeof(property), PSTR("val\":%d,\"text"), val);
@ -463,9 +591,7 @@ void btnmatrix_event_handler(lv_obj_t* obj, lv_event_t event)
/* Get the new value */
char buffer[128];
char property[36];
uint16_t val = 0;
uint16_t max = 0;
val = lv_btnmatrix_get_active_btn(obj);
if(val != LV_BTNMATRIX_BTN_NONE) {
@ -479,11 +605,43 @@ void btnmatrix_event_handler(lv_obj_t* obj, lv_event_t event)
last_value_sent = val;
event_object_selection_changed(obj, hasp_event_id, val, buffer);
// if(max > 0) dispatch_normalized_group_value(obj->user_data.groupid, obj, val, 0, max);
// set the property
// snprintf_P(property, sizeof(property), PSTR("val\":%d,\"text"), val);
// attr_out_str(obj, property, buffer);
// if(max > 0) // max a cannot be 0, its the divider
// if(hasp_event_id == HASP_EVENT_UP || hasp_event_id == LV_EVENT_VALUE_CHANGED) {
// event_update_group(obj->user_data.groupid, obj, last_value_sent, 0, max);
// }
}
/**
* Called when a msgbox value has changed
* @param obj pointer to a dropdown list or roller
* @param event type of event that occured
*/
void msgbox_event_handler(lv_obj_t* obj, lv_event_t event)
{
log_event("msgbox", event);
uint8_t hasp_event_id;
if(!translate_event(obj, event, hasp_event_id)) return; // Use LV_EVENT_VALUE_CHANGED
/* Get the new value */
char buffer[128];
uint16_t val = 0;
val = lv_msgbox_get_active_btn(obj);
if(val != LV_BTNMATRIX_BTN_NONE) {
const char* txt = lv_msgbox_get_active_btn_text(obj);
strncpy(buffer, txt, sizeof(buffer));
if(hasp_event_id == HASP_EVENT_UP || hasp_event_id == HASP_EVENT_RELEASE) lv_msgbox_start_auto_close(obj, 0);
} else {
buffer[0] = 0; // empty string
}
if(hasp_event_id == HASP_EVENT_CHANGED && last_value_sent == val) return; // same value as before
last_value_sent = val;
event_object_selection_changed(obj, hasp_event_id, val, buffer);
// if(max > 0) event_update_group(obj->user_data.groupid, obj, val, 0, max);
}
/**
@ -521,7 +679,9 @@ void slider_event_handler(lv_obj_t* obj, lv_event_t event)
last_value_sent = val;
event_object_val_event(obj, hasp_event_id, val);
dispatch_normalized_group_value(obj->user_data.groupid, obj, val, min, max);
if(obj->user_data.groupid && (hasp_event_id == HASP_EVENT_CHANGED || hasp_event_id == HASP_EVENT_UP) && min != max)
event_update_group(obj->user_data.groupid, obj, !!val, val, min, max);
}
/**
@ -553,16 +713,37 @@ void cpicker_event_handler(lv_obj_t* obj, lv_event_t event)
eventname, c32.ch.red, c32.ch.green, c32.ch.blue, c32.ch.red, c32.ch.green, c32.ch.blue);
event_send_object_data(obj, data);
// dispatch_normalized_group_value(obj->user_data.groupid, obj, val, min, max);
// event_update_group(obj->user_data.groupid, obj, val, min, max);
}
/**
* Called when an object is deleted
* @param obj pointer to a generic object
* @param event type of event that occured
*/
void deleted_event_handler(lv_obj_t* obj, lv_event_t event)
void calendar_event_handler(lv_obj_t* obj, lv_event_t event)
{
log_event("calendar", event);
uint8_t hasp_event_id;
translate_event(obj, event, hasp_event_id);
if(event != LV_EVENT_PRESSED && event != LV_EVENT_RELEASED && event != LV_EVENT_VALUE_CHANGED) return;
if(!translate_event(obj, event, hasp_event_id)) return; // Use LV_EVENT_VALUE_CHANGED
/* Get the new value */
lv_calendar_date_t* date;
if(hasp_event_id == HASP_EVENT_CHANGED)
date = lv_calendar_get_pressed_date(obj); // pressed date
else
date = lv_calendar_get_showed_date(obj); // current month
if(!date) return;
lv_style_int_t val = date->day + date->month * 31;
if(hasp_event_id == HASP_EVENT_CHANGED && last_value_sent == val) return; // same value as before
char data[100];
char eventname[8];
Parser::get_event_name(hasp_event_id, eventname, sizeof(eventname));
last_value_sent = val;
snprintf_P(data, sizeof(data), PSTR("{\"event\":\"%s\",\"val\":\"%d\",\"text\":\"%04d-%02d-%02dT00:00:00Z\"}"),
eventname, date->day, date->year, date->month, date->day);
event_send_object_data(obj, data);
// event_update_group(obj->user_data.groupid, obj, val, min, max);
}

View File

@ -11,17 +11,24 @@
#define HASP_NUM_PAGE_BACK (HASP_NUM_PAGES + 2)
#define HASP_NUM_PAGE_NEXT (HASP_NUM_PAGES + 3)
// Timer event Handlers
void event_timer_calendar(lv_task_t* task);
void event_timer_clock(lv_task_t* task);
// Object event Handlers
void wakeup_event_handler(lv_obj_t* obj, lv_event_t event);
void generic_event_handler(lv_obj_t* obj, lv_event_t event);
void toggle_event_handler(lv_obj_t* obj, lv_event_t event);
void slider_event_handler(lv_obj_t* obj, lv_event_t event);
void selector_event_handler(lv_obj_t* obj, lv_event_t event);
void btnmatrix_event_handler(lv_obj_t* obj, lv_event_t event);
void msgbox_event_handler(lv_obj_t* obj, lv_event_t event);
void cpicker_event_handler(lv_obj_t* obj, lv_event_t event);
void deleted_event_handler(lv_obj_t* obj, lv_event_t event);
void calendar_event_handler(lv_obj_t* obj, lv_event_t event);
#if HASP_USE_GPIO > 0
void event_gpio_input(uint8_t pin, uint8_t group, uint8_t eventid);
// GPIO event Handler
void event_gpio_input(uint8_t pin, uint8_t eventid);
#endif
#endif // HASP_EVENT_H

View File

@ -15,17 +15,14 @@
#include "ArduinoLog.h"
#endif
#include "lvgl.h"
#if LVGL_VERSION_MAJOR != 7
#include "../lv_components.h"
#endif
#include "hasplib.h"
const char** btnmatrix_default_map; // memory pointer to lvgl default btnmatrix map
const char** btnmatrix_default_map; // memory pointer to lvgl default btnmatrix map
const char* msgbox_default_map[] = {"OK", ""}; // memory pointer to hasp default msgbox map
// ##################### Object Finders ########################################################
// Return a child object from a parent with a specific objid
lv_obj_t* hasp_find_obj_from_parent_id(lv_obj_t* parent, uint8_t objid)
{
if(objid == 0 || parent == nullptr) return parent;
@ -41,7 +38,7 @@ lv_obj_t* hasp_find_obj_from_parent_id(lv_obj_t* parent, uint8_t objid)
if(grandchild) return grandchild; /* grandchild found, return it */
/* check tabs */
if(check_obj_type(child, LV_HASP_TABVIEW)) {
if(obj_check_type(child, LV_HASP_TABVIEW)) {
uint16_t tabcount = lv_tabview_get_tab_count(child);
for(uint16_t i = 0; i < tabcount; i++) {
lv_obj_t* tab = lv_tabview_get_tab(child, i);
@ -60,12 +57,14 @@ lv_obj_t* hasp_find_obj_from_parent_id(lv_obj_t* parent, uint8_t objid)
return NULL;
}
// lv_obj_t * hasp_find_obj_from_page_id(uint8_t pageid, uint8_t objid)
// {
// return hasp_find_obj_from_parent_id(get_page_obj(pageid), objid);
// }
// Return the object with a specific pageid and objid
lv_obj_t* hasp_find_obj_from_page_id(uint8_t pageid, uint8_t objid)
{
return hasp_find_obj_from_parent_id(haspPages.get_obj(pageid), objid);
}
bool hasp_find_id_from_obj(lv_obj_t* obj, uint8_t* pageid, uint8_t* objid)
// Return the pageid and objid of an object
bool hasp_find_id_from_obj(const lv_obj_t* obj, uint8_t* pageid, uint8_t* objid)
{
if(!obj || !haspPages.get_id(obj, pageid)) return false;
if(obj->user_data.id == 0 && obj != haspPages.get_obj(*pageid)) return false;
@ -73,122 +72,18 @@ bool hasp_find_id_from_obj(lv_obj_t* obj, uint8_t* pageid, uint8_t* objid)
return true;
}
/**
* Check if an lvgl object typename corresponds to a given HASP object ID
* @param lvobjtype a char* to a string
* @param haspobjtype the HASP object ID to check against
* @return true or false wether the types match
* @note
*/
// bool check_obj_type_str(const char * lvobjtype, lv_hasp_obj_type_t haspobjtype)
// {
// lvobjtype += 3; // skip "lv_"
// switch(haspobjtype) {
// case LV_HASP_BTNMATRIX:
// return (strcmp_P(lvobjtype, PSTR("btnmatrix")) == 0);
// case LV_HASP_TABLE:
// return (strcmp_P(lvobjtype, PSTR("table")) == 0);
// case LV_HASP_BUTTON:
// return (strcmp_P(lvobjtype, PSTR("btn")) == 0);
// case LV_HASP_LABEL:
// return (strcmp_P(lvobjtype, PSTR("label")) == 0);
// case LV_HASP_CHECKBOX:
// return (strcmp_P(lvobjtype, PSTR("checkbox")) == 0); // || (strcmp_P(lvobjtype, PSTR("lv_cb")) == 0);
// case LV_HASP_DROPDOWN:
// return (strcmp_P(lvobjtype, PSTR("dropdown")) == 0); // || (strcmp_P(lvobjtype, PSTR("lv_ddlist")) == 0);
// case LV_HASP_CPICKER:
// return (strcmp_P(lvobjtype, PSTR("cpicker")) == 0);
// case LV_HASP_SPINNER:
// return (strcmp_P(lvobjtype, PSTR("spinner")) == 0); // || (strcmp_P(lvobjtype, PSTR("lv_preload")) == 0);
// case LV_HASP_SLIDER:
// return (strcmp_P(lvobjtype, PSTR("slider")) == 0);
// case LV_HASP_GAUGE:
// return (strcmp_P(lvobjtype, PSTR("gauge")) == 0);
// case LV_HASP_ARC:
// return (strcmp_P(lvobjtype, PSTR("arc")) == 0);
// case LV_HASP_BAR:
// return (strcmp_P(lvobjtype, PSTR("bar")) == 0);
// case LV_HASP_LMETER:
// return (strcmp_P(lvobjtype, PSTR("linemeter")) == 0); // || (strcmp_P(lvobjtype, PSTR("lv_lmeter")) == 0)
// case LV_HASP_ROLLER:
// return (strcmp_P(lvobjtype, PSTR("roller")) == 0);
// case LV_HASP_SWITCH:
// return (strcmp_P(lvobjtype, PSTR("switch")) == 0); // || (strcmp_P(lvobjtype, PSTR("lv_sw")) == 0)
// case LV_HASP_LED:
// return (strcmp_P(lvobjtype, PSTR("led")) == 0);
// case LV_HASP_IMAGE:
// return (strcmp_P(lvobjtype, PSTR("img")) == 0);
// case LV_HASP_IMGBTN:
// return (strcmp_P(lvobjtype, PSTR("imgbtn")) == 0);
// case LV_HASP_CONTAINER:
// return (strcmp_P(lvobjtype, PSTR("container")) == 0); // || (strcmp_P(lvobjtype, PSTR("lv_cont")) == 0)
// case LV_HASP_OBJECT:
// return (strcmp_P(lvobjtype, PSTR("page")) == 0); // || (strcmp_P(lvobjtype, PSTR("lv_cont")) == 0)
// case LV_HASP_PAGE:
// return (strcmp_P(lvobjtype, PSTR("obj")) == 0); // || (strcmp_P(lvobjtype, PSTR("lv_cont")) == 0)
// case LV_HASP_TABVIEW:
// return (strcmp_P(lvobjtype, PSTR("tabview")) == 0);
// case LV_HASP_TILEVIEW:
// return (strcmp_P(lvobjtype, PSTR("tileview")) == 0);
// case LV_HASP_CHART:
// return (strcmp_P(lvobjtype, PSTR("chart")) == 0);
// case LV_HASP_CANVAS:
// return (strcmp_P(lvobjtype, PSTR("canvas")) == 0);
// case LV_HASP_CALENDER:
// return (strcmp_P(lvobjtype, PSTR("calender")) == 0);
// case LV_HASP_MSGBOX:
// return (strcmp_P(lvobjtype, PSTR("msgbox")) == 0);
// case LV_HASP_WINDOW:
// return (strcmp_P(lvobjtype, PSTR("win")) == 0);
// default:
// return false;
// }
// }
/**
* Get the object type name of an object
* @param obj an lv_obj_t* of the object to check its type
* @return name of the object type
* @note
*/
const char* get_obj_type_name(lv_obj_t* obj)
{
lv_obj_type_t list;
lv_obj_get_type(obj, &list);
const char* objtype = list.type[0];
return objtype + 3; // skip lv_
}
/**
* Check if an lvgl objecttype name corresponds to a given HASP object ID
* @param obj an lv_obj_t* of the object to check its type
* @param haspobjtype the HASP object ID to check against
* @return true or false wether the types match
* @note
*/
bool check_obj_type(lv_obj_t* obj, lv_hasp_obj_type_t haspobjtype)
{
#if 1
return obj->user_data.objid == (uint8_t)haspobjtype;
#else
lv_obj_type_t list;
lv_obj_get_type(obj, &list);
const char* objtype = list.type[0];
return check_obj_type(objtype, haspobjtype);
#endif
}
void hasp_object_tree(lv_obj_t* parent, uint8_t pageid, uint16_t level)
void hasp_object_tree(const lv_obj_t* parent, uint8_t pageid, uint16_t level)
{
if(parent == nullptr) return;
/* Output parent info */
lv_obj_type_t list;
lv_obj_get_type(parent, &list);
const char* objtype = list.type[0];
LOG_VERBOSE(TAG_HASP, F("[%d] " HASP_OBJECT_NOTATION " %s"), level, pageid, parent->user_data.id, objtype);
char indent[31];
memset(indent, 32, 31);
if(level < 15) indent[level * 2] = 0;
indent[30] = 0;
LOG_VERBOSE(TAG_HASP, F("%s- " HASP_OBJECT_NOTATION ": %s"), indent, pageid, parent->user_data.id,
obj_get_type_name(parent));
lv_obj_t* child;
child = lv_obj_get_child(parent, NULL);
@ -201,7 +96,7 @@ void hasp_object_tree(lv_obj_t* parent, uint8_t pageid, uint16_t level)
}
/* check tabs */
if(check_obj_type(parent, LV_HASP_TABVIEW)) {
if(obj_check_type(parent, LV_HASP_TABVIEW)) {
#if 1
uint16_t tabcount = lv_tabview_get_tab_count(parent);
for(uint16_t i = 0; i < tabcount; i++) {
@ -225,73 +120,53 @@ void object_dispatch_state(uint8_t pageid, uint8_t btnid, const char* payload)
// ##################### State Changers ########################################################
void object_set_group_value(lv_obj_t* parent, uint8_t groupid, int16_t intval)
// Recursive function that goes over all objects only ONCE
void object_set_group_values(lv_obj_t* parent, hasp_update_value_t& value)
{
if(groupid == 0 || parent == nullptr) return;
if(parent == nullptr) return;
lv_obj_t* child;
child = lv_obj_get_child(parent, NULL);
while(child) {
/* child found, update it */
if(groupid == child->user_data.groupid) hasp_process_obj_attribute_val(child, NULL, intval, intval, true);
// Update object if it's in the same group
if(value.group == parent->user_data.groupid && value.obj != parent) {
attribute_set_normalized_value(parent, value);
}
/* update grandchildren */
object_set_group_value(child, groupid, intval);
/* check tabs */
if(check_obj_type(child, LV_HASP_TABVIEW)) {
//#if LVGL_VERSION_MAJOR == 7
uint16_t tabcount = lv_tabview_get_tab_count(child);
for(uint16_t i = 0; i < tabcount; i++) {
lv_obj_t* tab = lv_tabview_get_tab(child, i);
LOG_VERBOSE(TAG_HASP, F("Found tab %i"), i);
if(tab->user_data.groupid && groupid == tab->user_data.groupid)
hasp_process_obj_attribute_val(tab, NULL, intval, intval, true); /* tab found, update it */
/* check grandchildren */
object_set_group_value(tab, groupid, intval);
}
//#endif
/* check tabs */
if(obj_get_type(parent) == LV_HASP_TABVIEW) {
uint16_t tabcount = lv_tabview_get_tab_count(parent);
for(uint16_t i = 0; i < tabcount; i++) {
lv_obj_t* tab = lv_tabview_get_tab(parent, i);
object_set_group_values(tab, value);
}
} else {
lv_obj_t* child;
child = lv_obj_get_child(parent, NULL);
while(child) {
object_set_group_values(child, value);
child = lv_obj_get_child(parent, child);
}
/* try next sibling */
child = lv_obj_get_child(parent, child);
}
}
// TODO make this a recursive function that goes over all objects only ONCE
void object_set_normalized_group_value(uint8_t groupid, lv_obj_t* src_obj, int16_t val, int16_t min, int16_t max)
// SHOULD only by called from DISPATCH
void object_set_normalized_group_values(hasp_update_value_t& value)
{
if(groupid == 0) return;
if(min == max) return;
if(value.group == 0 || value.min == value.max) return;
for(uint8_t page = 0; page < HASP_NUM_PAGES; page++) {
object_set_group_value(haspPages.get_obj(page), groupid, val);
// uint8_t startid = 1;
// for(uint8_t objid = startid; objid < 20; objid++) {
// lv_obj_t* obj = hasp_find_obj_from_parent_id(get_page_obj(page), objid);
// if(obj && obj != src_obj && obj->user_data.groupid == groupid) { // skip source object, if set
// LOG_VERBOSE(TAG_HASP, F("Found p%db%d in group %d"), page, objid, groupid);
// lv_obj_set_state(obj, val > 0 ? LV_STATE_PRESSED | LV_STATE_CHECKED : LV_STATE_DEFAULT);
// switch(obj->user_data.objid) {
// case HASP_OBJ_ARC:
// case HASP_OBJ_SLIDER:
// case HASP_OBJ_CHECKBOX:
// hasp_process_obj_attribute_val();
// default:
// }
// }
// }
uint8_t page = haspPages.get();
object_set_group_values(haspPages.get_obj(page), value); // Update visible objects first
for(uint8_t i = 0; i < HASP_NUM_PAGES; i++) {
if(i != page) object_set_group_values(haspPages.get_obj(i), value);
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// Used in the dispatcher & hasp_new_object
void hasp_process_attribute(uint8_t pageid, uint8_t objid, const char* attr, const char* payload)
void hasp_process_attribute(uint8_t pageid, uint8_t objid, const char* attr, const char* payload, bool update)
{
if(lv_obj_t* obj = hasp_find_obj_from_parent_id(haspPages.get_obj(pageid), objid)) {
hasp_process_obj_attribute(obj, attr, payload, strlen(payload) > 0);
if(lv_obj_t* obj = hasp_find_obj_from_page_id(pageid, objid)) {
hasp_process_obj_attribute(obj, attr, payload, update); // || strlen(payload) > 0);
} else {
LOG_WARNING(TAG_HASP, F(D_OBJECT_UNKNOWN " " HASP_OBJECT_NOTATION), pageid, objid);
}
@ -299,7 +174,8 @@ void hasp_process_attribute(uint8_t pageid, uint8_t objid, const char* attr, con
// ##################### Object Creator ########################################################
int hasp_parse_json_attributes(lv_obj_t* obj, const JsonObject& doc)
// Called from hasp_new_object only to process all attributes
static inline int hasp_parse_json_attributes(lv_obj_t* obj, const JsonObject& doc)
{
int i = 0;
#if defined(WINDOWS) || defined(POSIX)
@ -308,7 +184,8 @@ int hasp_parse_json_attributes(lv_obj_t* obj, const JsonObject& doc)
std::string v;
for(JsonPair keyValue : doc) {
LOG_VERBOSE(TAG_HASP, F(D_BULLET "%s=%s"), keyValue.key().c_str(), keyValue.value().as<std::string>().c_str());
// LOG_VERBOSE(TAG_HASP, F(D_BULLET "%s=%s"), keyValue.key().c_str(),
// keyValue.value().as<std::string>().c_str());
v = keyValue.value().as<std::string>();
hasp_process_obj_attribute(obj, keyValue.key().c_str(), keyValue.value().as<std::string>().c_str(), true);
i++;
@ -318,7 +195,7 @@ int hasp_parse_json_attributes(lv_obj_t* obj, const JsonObject& doc)
v.reserve(64);
for(JsonPair keyValue : doc) {
LOG_DEBUG(TAG_HASP, F(D_BULLET "%s=%s"), keyValue.key().c_str(), keyValue.value().as<String>().c_str());
// LOG_DEBUG(TAG_HASP, F(D_BULLET "%s=%s"), keyValue.key().c_str(), keyValue.value().as<String>().c_str());
v = keyValue.value().as<String>();
hasp_process_obj_attribute(obj, keyValue.key().c_str(), keyValue.value().as<String>().c_str(), true);
i++;
@ -328,6 +205,18 @@ int hasp_parse_json_attributes(lv_obj_t* obj, const JsonObject& doc)
return i;
}
static void object_add_task(lv_obj_t* obj, uint8_t pageid, uint8_t objid, lv_task_cb_t task_xcb, uint16_t interval)
{
hasp_task_user_data_t* user_data = (hasp_task_user_data_t*)lv_mem_alloc(sizeof(hasp_task_user_data_t));
if(!user_data) return;
user_data->pageid = pageid;
user_data->objid = objid;
user_data->interval = interval;
lv_task_t* task = lv_task_create(task_xcb, 25, LV_TASK_PRIO_LOWEST, (void*)user_data);
(void)task; // unused
}
/**
* Create a new object according to the json config
* @param config Json representation for this object
@ -365,9 +254,8 @@ void hasp_new_object(const JsonObject& config, uint8_t& saved_page_id)
config.remove(FPSTR(FP_PARENTID));
}
uint16_t sdbm = 0;
uint8_t groupid = config[FPSTR(FP_GROUPID)].as<uint8_t>();
uint8_t id = config[FPSTR(FP_ID)].as<uint8_t>();
uint16_t sdbm = 0;
uint8_t id = config[FPSTR(FP_ID)].as<uint8_t>();
config.remove(FPSTR(FP_ID));
/* Create the object if it does not exist */
@ -447,6 +335,8 @@ void hasp_new_object(const JsonObject& config, uint8_t& saved_page_id)
lv_label_set_recolor(obj, true);
lv_obj_set_event_cb(obj, generic_event_handler);
obj->user_data.objid = LV_HASP_LABEL;
// object_add_task(obj, pageid, id, event_timer_clock, 1000);
}
break;
@ -489,20 +379,16 @@ void hasp_new_object(const JsonObject& config, uint8_t& saved_page_id)
case LV_HASP_PAGE:
case HASP_OBJ_PAGE:
obj = lv_page_create(parent_obj, NULL);
if(obj) {
obj->user_data.objid = LV_HASP_PAGE;
lv_obj_set_event_cb(obj, deleted_event_handler); // Needed for memory dealocation
}
if(obj) obj->user_data.objid = LV_HASP_PAGE;
// No event handler for pages
break;
#if LV_USE_WIN && LVGL_VERSION_MAJOR == 7
case LV_HASP_WINDOW:
case HASP_OBJ_WIN:
obj = lv_win_create(parent_obj, NULL);
if(obj) {
obj->user_data.objid = LV_HASP_WINDOW;
lv_obj_set_event_cb(obj, deleted_event_handler); // Needed for memory dealocation
}
if(obj) obj->user_data.objid = LV_HASP_WINDOW;
// No event handler for pages
break;
#endif
@ -529,14 +415,7 @@ void hasp_new_object(const JsonObject& config, uint8_t& saved_page_id)
obj = lv_tabview_create(parent_obj, LV_DIR_TOP, 100);
// No event handler for tabs
if(obj) {
lv_obj_t* tab;
tab = lv_tabview_add_tab(obj, "tab 1");
// lv_obj_set_user_data(tab, id + 1);
tab = lv_tabview_add_tab(obj, "tab 2");
// lv_obj_set_user_data(tab, id + 2);
tab = lv_tabview_add_tab(obj, "tab 3");
// lv_obj_set_user_data(tab, id + 3);
lv_obj_set_event_cb(obj, selector_event_handler);
obj->user_data.objid = LV_HASP_TABVIEW;
}
break;
@ -554,30 +433,35 @@ void hasp_new_object(const JsonObject& config, uint8_t& saved_page_id)
case LV_HASP_TILEVIEW:
case HASP_OBJ_TILEVIEW:
obj = lv_tileview_create(parent_obj, NULL);
if(obj) {
obj->user_data.objid = LV_HASP_TILEVIEW;
lv_obj_set_event_cb(obj, deleted_event_handler); // Needed for memory dealocation
}
if(obj) obj->user_data.objid = LV_HASP_TILEVIEW;
// No event handler for tileviews
break;
case LV_HASP_TABVIEW:
case HASP_OBJ_TABVIEW:
obj = lv_tabview_create(parent_obj, NULL);
// No event handler for tabs
if(obj) {
lv_obj_set_event_cb(obj, deleted_event_handler); // Needed for memory dealocation
lv_obj_t* tab;
tab = lv_tabview_add_tab(obj, "tab 1");
// lv_obj_set_user_data(tab, id + 1);
tab = lv_tabview_add_tab(obj, "tab 2");
// lv_obj_set_user_data(tab, id + 2);
tab = lv_tabview_add_tab(obj, "tab 3");
// lv_obj_set_user_data(tab, id + 3);
lv_obj_set_event_cb(obj, selector_event_handler);
obj->user_data.objid = LV_HASP_TABVIEW;
}
break;
case LV_HASP_TAB:
case HASP_OBJ_TAB:
if(parent_obj && parent_obj->user_data.objid == LV_HASP_TABVIEW) {
obj = lv_tabview_add_tab(parent_obj, "Tab");
if(obj) {
lv_obj_set_event_cb(obj, generic_event_handler);
obj->user_data.objid = LV_HASP_TAB;
}
} else {
LOG_WARNING(TAG_HASP, F("Parent of a tab must be a tabview object"));
return;
}
break;
#endif
/* ----- Color Objects ------ */
case LV_HASP_CPICKER:
@ -595,11 +479,11 @@ void hasp_new_object(const JsonObject& config, uint8_t& saved_page_id)
obj = lv_spinner_create(parent_obj, NULL);
if(obj) {
obj->user_data.objid = LV_HASP_SPINNER;
lv_obj_set_event_cb(obj, deleted_event_handler); // Needed for memory dealocation
lv_obj_set_event_cb(obj, generic_event_handler);
}
break;
#endif
/* ----- Range Objects ------ */
case LV_HASP_SLIDER:
case HASP_OBJ_SLIDER:
@ -633,13 +517,14 @@ void hasp_new_object(const JsonObject& config, uint8_t& saved_page_id)
}
break;
case LV_HASP_LMETER:
case HASP_OBJ_LMETER:
case LV_HASP_LINEMETER:
case HASP_OBJ_LMETER: // obsolete
case HASP_OBJ_LINEMETER:
obj = lv_linemeter_create(parent_obj, NULL);
if(obj) {
lv_linemeter_set_range(obj, 0, 100);
lv_obj_set_event_cb(obj, generic_event_handler);
obj->user_data.objid = LV_HASP_LMETER;
obj->user_data.objid = LV_HASP_LINEMETER;
}
break;
@ -699,13 +584,27 @@ void hasp_new_object(const JsonObject& config, uint8_t& saved_page_id)
}
break;
case LV_HASP_MSGBOX:
case HASP_OBJ_MSGBOX:
obj = lv_msgbox_create(parent_obj, NULL);
if(obj) {
lv_obj_align(obj, NULL, LV_ALIGN_CENTER, 0, 0);
lv_obj_set_auto_realign(obj, true);
lv_obj_set_event_cb(obj, msgbox_event_handler);
if(msgbox_default_map) lv_msgbox_add_btns(obj, msgbox_default_map);
obj->user_data.objid = LV_HASP_MSGBOX;
}
break;
case LV_HASP_CALENDER:
case HASP_OBJ_CALENDAR:
obj = lv_calendar_create(parent_obj, NULL);
// lv_obj_align(obj, NULL, LV_ALIGN_IN_TOP_MID, 0, 20);
if(obj) {
lv_obj_set_event_cb(obj, selector_event_handler);
lv_obj_set_event_cb(obj, calendar_event_handler);
obj->user_data.objid = LV_HASP_CALENDER;
object_add_task(obj, pageid, id, event_timer_calendar, 5000);
}
break;
@ -726,30 +625,34 @@ void hasp_new_object(const JsonObject& config, uint8_t& saved_page_id)
lv_obj_set_gesture_parent(obj, false);
/* id tag the object */
// lv_obj_set_user_data(obj, id);
obj->user_data.id = id;
// obj->user_data.groupid = groupid; // get/set in atttr
uint8_t temp; // needed for debug tests
(void)temp;
#ifdef HASP_DEBUG
/** testing start **/
uint8_t temp;
if(!hasp_find_id_from_obj(obj, &pageid, &temp)) {
LOG_ERROR(TAG_HASP, F(D_OBJECT_LOST));
return;
}
#endif
#if HASP_LOG_LEVEL >= LOG_LEVEL_VERBOSE
/** verbose reporting **/
lv_obj_type_t list;
lv_obj_get_type(obj, &list);
LOG_VERBOSE(TAG_HASP, F(D_BULLET HASP_OBJECT_NOTATION " = %s"), pageid, temp, list.type[0]);
LOG_VERBOSE(TAG_HASP, F(D_BULLET HASP_OBJECT_NOTATION " = %s"), pageid, id, obj_get_type_name(obj));
#endif
#ifdef HASP_DEBUG
/* test double-check */
lv_obj_t* test = hasp_find_obj_from_parent_id(haspPages.get_obj(pageid), (uint8_t)temp);
if(test != obj) {
lv_obj_t* test = hasp_find_obj_from_page_id(pageid, (uint8_t)temp);
if(test != obj || temp != id) {
LOG_ERROR(TAG_HASP, F(D_OBJECT_MISMATCH));
return;
} else {
// object created successfully
}
#endif
} else {
// object already exists

View File

@ -4,8 +4,7 @@
#ifndef HASP_OBJECT_H
#define HASP_OBJECT_H
#include <ArduinoJson.h>
#include "lvgl.h"
#include "hasplib.h"
const char FP_PAGE[] PROGMEM = "page";
const char FP_ID[] PROGMEM = "id";
@ -14,68 +13,126 @@ const char FP_OBJID[] PROGMEM = "objid";
const char FP_PARENTID[] PROGMEM = "parentid";
const char FP_GROUPID[] PROGMEM = "groupid";
typedef struct
{
uint8_t pageid;
uint8_t objid;
uint16_t interval;
} hasp_task_user_data_t;
typedef struct
{
lv_obj_t* obj;
uint8_t group;
int32_t min;
int32_t max;
int32_t val;
bool power;
} hasp_update_value_t;
enum lv_hasp_obj_type_t {
/* Containers */
LV_HASP_SCREEN = 1,
LV_HASP_CONTAINER = 2,
LV_HASP_WINDOW = 3, // placeholder
LV_HASP_MSGBOX = 4, // placeholder
LV_HASP_TILEVIEW = 5, // placeholder
LV_HASP_TABVIEW = 6, // placeholder
LV_HASP_TAB = 7, // placeholder
LV_HASP_PAGE = 8, // Obsolete in v8
/* Controls */
LV_HASP_OBJECT = 91, // 10
LV_HASP_BUTTON = 10, // 12
LV_HASP_OBJECT = 11,
LV_HASP_BUTTON = 12,
LV_HASP_BTNMATRIX = 13,
LV_HASP_IMGBTN = 14, // placeholder
LV_HASP_CHECKBOX = 11, // 15
LV_HASP_SWITCH = 40, // 16
LV_HASP_SLIDER = 30, // 17
LV_HASP_CHECKBOX = 15,
LV_HASP_SWITCH = 16,
LV_HASP_SLIDER = 17,
LV_HASP_TEXTAREA = 18, // placeholder
LV_HASP_SPINBOX = 19, // placeholder
LV_HASP_CPICKER = 20,
/* Selectors */
LV_HASP_DROPDOWN = 50,
LV_HASP_ROLLER = 51,
LV_HASP_LIST = 52, // placeholder
LV_HASP_TABLE = 53,
LV_HASP_CALENDER = 54,
/* Containers */
LV_HASP_SCREEN = 1,
LV_HASP_CONTAINER = 70,
LV_HASP_WINDOW = 71, // placeholder
LV_HASP_MSGBOX = 72, // placeholder
LV_HASP_TILEVIEW = 73, // placeholder
LV_HASP_TABVIEW = 74, // placeholder
LV_HASP_TAB = 75, // placeholder
LV_HASP_PAGE = 79, // Obsolete in v8
/* Visualizers */
LV_HASP_LABEL = 12, // 30
LV_HASP_GAUGE = 31,
LV_HASP_BAR = 32,
LV_HASP_LMETER = 33,
LV_HASP_LED = 41, // 34
LV_HASP_ARC = 22, // 35
LV_HASP_SPINNER = 21, // 36
LV_HASP_CHART = 37,
LV_HASP_LABEL = 21,
LV_HASP_GAUGE = 22,
LV_HASP_BAR = 23,
LV_HASP_LINEMETER = 24,
LV_HASP_LED = 25,
LV_HASP_ARC = 26,
LV_HASP_SPINNER = 27,
LV_HASP_CHART = 28,
/* Selectors */
LV_HASP_DROPDOWN = 29,
LV_HASP_ROLLER = 30,
LV_HASP_LIST = 31, // placeholder
LV_HASP_TABLE = 32,
LV_HASP_CALENDER = 33,
/* Graphics */
LV_HASP_LINE = 60,
LV_HASP_IMAGE = 61, // placeholder
LV_HASP_CANVAS = 62, // placeholder
LV_HASP_MASK = 63, // placeholder
LV_HASP_LINE = 36,
LV_HASP_IMAGE = 37, // placeholder
LV_HASP_CANVAS = 38, // placeholder
LV_HASP_MASK = 39, // placeholder
};
void hasp_new_object(const JsonObject& config, uint8_t& saved_page_id);
lv_obj_t* hasp_find_obj_from_parent_id(lv_obj_t* parent, uint8_t objid);
// lv_obj_t * hasp_find_obj_from_page_id(uint8_t pageid, uint8_t objid);
bool hasp_find_id_from_obj(lv_obj_t* obj, uint8_t* pageid, uint8_t* objid);
// bool check_obj_type_str(const char * lvobjtype, lv_hasp_obj_type_t haspobjtype);
const char* get_obj_type_name(lv_obj_t* obj);
bool check_obj_type(lv_obj_t* obj, lv_hasp_obj_type_t haspobjtype);
void hasp_object_tree(lv_obj_t* parent, uint8_t pageid, uint16_t level);
lv_obj_t* hasp_find_obj_from_page_id(uint8_t pageid, uint8_t objid);
bool hasp_find_id_from_obj(const lv_obj_t* obj, uint8_t* pageid, uint8_t* objid);
void hasp_object_tree(const lv_obj_t* parent, uint8_t pageid, uint16_t level);
void object_dispatch_state(uint8_t pageid, uint8_t btnid, const char* payload);
void hasp_process_attribute(uint8_t pageid, uint8_t objid, const char* attr, const char* payload);
void hasp_process_attribute(uint8_t pageid, uint8_t objid, const char* attr, const char* payload, bool update);
void object_set_normalized_group_value(uint8_t groupid, lv_obj_t* src_obj, int16_t val, int16_t min, int16_t max);
void object_set_normalized_group_values(hasp_update_value_t& value);
/**
* Get the object type name of an object
* @param obj an lv_obj_t* of the object to check its type
* @return name of the object type
* @note
*/
inline const char* obj_get_type_name(const lv_obj_t* obj)
{
lv_obj_type_t list;
lv_obj_get_type(obj, &list);
const char* objtype = list.type[0];
return objtype + 3; // skip lv_
}
/**
* Get the hasp object type of a given LVGL object
* @param obj an lv_obj_t* of the object to check its type
* @return lv_hasp_obj_type_t
* @note
*/
inline lv_hasp_obj_type_t obj_get_type(const lv_obj_t* obj)
{
return (lv_hasp_obj_type_t)obj->user_data.objid;
}
/**
* Check if an lvgl objecttype name corresponds to a given HASP object ID
* @param obj an lv_obj_t* of the object to check its type
* @param haspobjtype the HASP object ID to check against
* @return true or false wether the types match
* @note
*/
inline bool obj_check_type(const lv_obj_t* obj, lv_hasp_obj_type_t haspobjtype)
{
#if 1
if(!obj) return false;
return obj->user_data.objid == (uint8_t)haspobjtype;
#else
lv_obj_type_t list;
lv_obj_get_type(obj, &list);
const char* objtype = list.type[0];
return obj_check_type(objtype, haspobjtype);
#endif
}
#define HASP_OBJ_BAR 1971
#define HASP_OBJ_BTN 3164
@ -109,7 +166,9 @@ void object_set_normalized_group_value(uint8_t groupid, lv_obj_t* src_obj, int16
#define HASP_OBJ_OBJ 53623
#define HASP_OBJ_OBJMASK 55395
#define HASP_OBJ_LMETER 62749
#define HASP_OBJ_LINEMETER 55189
#define HASP_OBJ_TABVIEW 63226
#define HASP_OBJ_TAB 7861
#define HASP_OBJ_ARC 64594
#endif

View File

@ -1,10 +1,8 @@
/* MIT License - Copyright (c) 2019-2021 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#include "hasp_conf.h"
#include "hasplib.h"
#include "hasp_page.h"
#include <fstream>
namespace hasp {
@ -21,14 +19,19 @@ Page::Page()
// LVGL is not yet initialized at construction time
}
size_t Page::count()
uint8_t Page::count()
{
return sizeof(_pages) / sizeof(*_pages);
return (uint8_t)(sizeof(_pages) / sizeof(*_pages));
}
void Page::init(uint8_t start_page)
{
lv_obj_t* scr_act = lv_scr_act();
lv_obj_clean(lv_layer_top());
for(int i = 0; i < count(); i++) {
lv_obj_t* prev_page_obj = _pages[i];
_pages[i] = lv_obj_create(NULL, NULL);
_pages[i]->user_data.objid = LV_HASP_SCREEN;
lv_obj_set_event_cb(_pages[i], generic_event_handler);
@ -40,6 +43,14 @@ void Page::init(uint8_t start_page)
_meta_data[i].prev = thispage == PAGE_START_INDEX ? HASP_NUM_PAGES : thispage - PAGE_START_INDEX;
_meta_data[i].next = thispage == HASP_NUM_PAGES ? PAGE_START_INDEX : thispage + PAGE_START_INDEX;
_meta_data[i].back = start_page;
if(prev_page_obj) {
if(scr_act == prev_page_obj) {
lv_scr_load_anim(_pages[i], LV_SCR_LOAD_ANIM_NONE, 500, 0, false); // update page screen obj
lv_obj_del_async(prev_page_obj);
} else
lv_obj_del(prev_page_obj);
}
}
}
@ -67,12 +78,12 @@ void Page::set(uint8_t pageid, lv_scr_load_anim_t animation)
} else if(!page) {
LOG_WARNING(TAG_HASP, F(D_HASP_INVALID_PAGE), pageid);
} else {
LOG_TRACE(TAG_HASP, F(D_HASP_CHANGE_PAGE), pageid);
if(_current_page != pageid) {
_current_page = pageid;
_current_page = pageid;
if(page != lv_scr_act()) {
LOG_TRACE(TAG_HASP, F(D_HASP_CHANGE_PAGE), pageid);
lv_scr_load_anim(page, animation, 500, 0, false);
hasp_object_tree(page, pageid, 0);
}
hasp_object_tree(page, pageid, 0);
}
}
@ -132,30 +143,66 @@ void Page::load_jsonl(const char* pagesfile)
if(pagesfile[0] == '\0') return;
if(!filesystemSetup()) {
LOG_ERROR(TAG_HASP, F("FS not mounted. Failed to load %s"), pagesfile);
LOG_ERROR(TAG_HASP, F("FS not mounted. " D_FILE_LOAD_FAILED), pagesfile);
return;
}
if(!HASP_FS.exists(pagesfile)) {
LOG_ERROR(TAG_HASP, F("Non existing file %s"), pagesfile);
LOG_ERROR(TAG_HASP, F(D_FILE_LOAD_FAILED), pagesfile);
return;
}
LOG_TRACE(TAG_HASP, F("Loading file %s"), pagesfile);
LOG_TRACE(TAG_HASP, F(D_FILE_LOADING), pagesfile);
File file = HASP_FS.open(pagesfile, "r");
dispatch_parse_jsonl(file);
file.close();
LOG_INFO(TAG_HASP, F("File %s loaded"), pagesfile);
#else
LOG_INFO(TAG_HASP, F(D_FILE_LOADED), pagesfile);
#if HASP_USE_EEPROM > 0
#elif HASP_USE_EEPROM > 0
LOG_TRACE(TAG_HASP, F("Loading jsonl from EEPROM..."));
EepromStream eepromStream(4096, 1024);
dispatch_parse_jsonl(eepromStream);
LOG_INFO(TAG_HASP, F("Loaded jsonl from EEPROM"));
#endif
#else
char path[strlen(pagesfile) + 4];
path[0] = '.';
path[1] = '\0';
strcat(path, pagesfile);
path[1] = '\\';
LOG_TRACE(TAG_HASP, F("Loading %s from disk..."), path);
std::ifstream f(path); // taking file as inputstream
if(f) {
dispatch_parse_jsonl(f);
}
f.close();
LOG_INFO(TAG_HASP, F("Loaded %s from disk"), path);
// char path[strlen(pagesfile) + 4];
// path[0] = '\0';
// strcat(path, "L:/");
// strcat(path, pagesfile);
// lv_fs_file_t file;
// lv_fs_res_t res;
// res = lv_fs_open(&file, path, LV_FS_MODE_RD);
// if(res == LV_FS_RES_OK) {
// LOG_VERBOSE(TAG_HASP, F("Opening %s"), path);
// } else {
// LOG_ERROR(TAG_HASP, F("TEST Opening %q from FS failed %d"), path, res);
// }
// dispatch_parse_jsonl(file);
// res = lv_fs_close(&file);
// if(res == LV_FS_RES_OK) {
// LOG_VERBOSE(TAG_HASP, F("Closing %s OK"), path);
// } else {
// LOG_ERROR(TAG_HASP, F("Closing %s on FS failed %d"), path, res);
// }
#endif
}
@ -168,7 +215,7 @@ lv_obj_t* Page::get_obj(uint8_t pageid)
return _pages[pageid - PAGE_START_INDEX];
}
bool Page::get_id(lv_obj_t* obj, uint8_t* pageid)
bool Page::get_id(const lv_obj_t* obj, uint8_t* pageid)
{
lv_obj_t* page = lv_obj_get_screen(obj);

View File

@ -4,7 +4,6 @@
#ifndef HASP_PAGES_H
#define HASP_PAGES_H
#include "hasp_conf.h"
#include "hasplib.h"
/*********************
@ -33,7 +32,7 @@ class Page {
public:
Page();
size_t count();
uint8_t count();
void init(uint8_t start_page);
void clear(uint8_t pageid);
// void set(uint8_t pageid);
@ -46,6 +45,7 @@ class Page {
uint8_t get_next(uint8_t pageid);
uint8_t get_prev(uint8_t pageid);
uint8_t get_back(uint8_t pageid);
void set_next(uint8_t pageid, uint8_t nextid);
void set_prev(uint8_t pageid, uint8_t previd);
void set_back(uint8_t pageid, uint8_t backid);
@ -53,7 +53,7 @@ class Page {
uint8_t get();
void load_jsonl(const char* pagesfile);
lv_obj_t* get_obj(uint8_t pageid);
bool get_id(lv_obj_t* obj, uint8_t* pageid);
bool get_id(const lv_obj_t* obj, uint8_t* pageid);
bool is_valid(uint8_t pageid);
};

View File

@ -1,17 +1,11 @@
/* MIT License - Copyright (c) 2019-2021 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#include <cstdlib>
#include <cctype>
#include <string>
#ifdef ARDUINO
#include "pgmspace.h"
#include "Arduino.h"
#endif
#include "lvgl.h"
#include "hasplib.h"
bool Parser::haspPayloadToColor(const char* payload, lv_color32_t& color)
@ -177,18 +171,20 @@ bool Parser::is_only_digits(const char* s)
int Parser::format_bytes(size_t filesize, char* buf, size_t len)
{
if(filesize < 1024) return snprintf_P(buf, len, PSTR("%d B"), filesize);
if(filesize < D_FILE_SIZE_DIVIDER) return snprintf_P(buf, len, PSTR("%d " D_FILE_SIZE_BYTES), filesize);
filesize = filesize * 10;
char labels[] = "kMGT";
filesize = filesize * 10 / 1024; // multiply by 10 for 1 decimal place
int unit = 0;
filesize = filesize / D_FILE_SIZE_DIVIDER; // multiply by 10 for 1 decimal place
if(filesize < D_FILE_SIZE_DIVIDER * 10)
return snprintf_P(buf, len, PSTR("%d" D_DECIMAL_POINT "%d " D_FILE_SIZE_KILOBYTES), filesize / 10,
filesize % 10);
while(filesize >= 10240 && unit < sizeof(labels) - 1) { // it is multiplied by 10
unit++;
filesize = filesize / 1024;
}
filesize = filesize / D_FILE_SIZE_DIVIDER; // multiply by 10 for 1 decimal place
if(filesize < D_FILE_SIZE_DIVIDER * 10)
return snprintf_P(buf, len, PSTR("%d" D_DECIMAL_POINT "%d " D_FILE_SIZE_MEGABYTES), filesize / 10,
filesize % 10);
return snprintf_P(buf, len, PSTR("%d.%d %ciB"), filesize / 10, filesize % 10, labels[unit]);
return snprintf_P(buf, len, PSTR("%d" D_DECIMAL_POINT "%d " D_FILE_SIZE_GIGABYTES), filesize / 10, filesize % 10);
}
uint8_t Parser::get_action_id(const char* action)

View File

@ -4,8 +4,7 @@
#ifndef HASP_PARSER_H
#define HASP_PARSER_H
#include "lvgl.h"
#include "hasp_conf.h"
#include "hasplib.h"
class Parser {

View File

@ -3,14 +3,12 @@
#if HASP_USE_CONFIG > 0
#include "ArduinoJson.h"
#include "StreamUtils.h" // For EEPromStream
#include "hasp_conf.h"
#include "hasplib.h"
#include "hasp_config.h"
#include "hasp_debug.h"
#include "hasp_gui.h"
#include "hal/hasp_hal.h"
//#include "hasp_ota.h" included in conf
//#include "hasp_filesystem.h" included in conf
@ -18,13 +16,13 @@
//#include "hasp_gpio.h" included in conf
//#include "hasp_eeprom.h"
#include "hasp/hasp.h"
#include "hasp/hasp_dispatch.h"
#if HASP_USE_EEPROM > 0
#include "EEPROM.h"
#endif
#include "StreamUtils.h" // For EEPromStream
extern uint16_t dispatchTelePeriod;
extern uint32_t dispatchLastMillis;
@ -76,24 +74,59 @@ bool configSet(uint16_t& value, const JsonVariant& setting, const __FlashStringH
return false;
}
void configStartDebug(bool setupdebug, String& configFile)
void configSetupDebug(JsonDocument& settings)
{
debugSetup(settings[FPSTR(FP_DEBUG)]);
debugStart(); // Debug started, now we can use it; HASP header sent
}
void configStorePasswords(JsonDocument& settings, String& wifiPass, String& mqttPass, String& httpPass)
{
const __FlashStringHelper* pass = F("pass");
wifiPass = settings[FPSTR(FP_WIFI)][pass].as<String>();
mqttPass = settings[FPSTR(FP_MQTT)][pass].as<String>();
httpPass = settings[FPSTR(FP_HTTP)][pass].as<String>();
}
void configRestorePasswords(JsonDocument& settings, String& wifiPass, String& mqttPass, String& httpPass)
{
const __FlashStringHelper* pass = F("pass");
if(!settings[FPSTR(FP_WIFI)][pass].isNull()) settings[FPSTR(FP_WIFI)][pass] = wifiPass;
if(!settings[FPSTR(FP_MQTT)][pass].isNull()) settings[FPSTR(FP_MQTT)][pass] = mqttPass;
if(!settings[FPSTR(FP_HTTP)][pass].isNull()) settings[FPSTR(FP_HTTP)][pass] = httpPass;
}
void configMaskPasswords(JsonDocument& settings)
{
String passmask = F(D_PASSWORD_MASK);
configRestorePasswords(settings, passmask, passmask, passmask);
}
DeserializationError configParseFile(String& configFile, JsonDocument& settings)
{
if(setupdebug) {
debugStart(); // Debug started, now we can use it; HASP header sent
#if HASP_USE_SPIFFS > 0 || HASP_USE_LITTLEFS > 0
LOG_INFO(TAG_CONF, F("SPI flash FS mounted"));
filesystemInfo();
filesystemList();
#endif
File file = HASP_FS.open(configFile, "r");
DeserializationError result;
if(file) {
size_t size = file.size();
if(size > 1024) {
LOG_ERROR(TAG_CONF, F("Config file size is too large"));
return DeserializationError::NoMemory;
}
result = deserializeJson(settings, file);
file.close();
return result;
}
#if HASP_USE_SPIFFS > 0 || HASP_USE_LITTLEFS > 0
LOG_TRACE(TAG_CONF, F(D_FILE_LOADING), configFile.c_str());
return DeserializationError::InvalidInput;
#else
LOG_TRACE(TAG_CONF, F(D_FILE_LOADING), "EEPROM");
return DeserializationError::InvalidInput;
#endif
}
void configRead(JsonDocument& settings, bool setupdebug = false)
DeserializationError configRead(JsonDocument& settings, bool setupdebug = false)
{
String configFile((char*)0);
configFile.reserve(32);
@ -101,40 +134,34 @@ void configRead(JsonDocument& settings, bool setupdebug = false)
DeserializationError error;
#if HASP_USE_SPIFFS > 0 || HASP_USE_LITTLEFS > 0
File file = HASP_FS.open(configFile, "r");
error = configParseFile(configFile, settings);
if(!error) {
String output, wifiPass, mqttPass, httpPass;
if(file) {
size_t size = file.size();
if(size > 1024) {
LOG_ERROR(TAG_CONF, F("Config file size is too large"));
return;
/* Load Debug params */
if(setupdebug) {
configSetupDebug(settings); // Now we can use log
LOG_INFO(TAG_CONF, F("SPI flash FS mounted"));
filesystemInfo();
filesystemList();
}
error = deserializeJson(settings, file);
file.close();
LOG_TRACE(TAG_CONF, F(D_FILE_LOADING), configFile.c_str());
configStorePasswords(settings, wifiPass, mqttPass, httpPass);
if(!error) {
/* Load Debug params */
if(setupdebug) {
debugPreSetup(settings[FPSTR(FP_DEBUG)]);
}
configStartDebug(setupdebug, configFile);
// Output settings in log with masked passwords
configMaskPasswords(settings);
serializeJson(settings, output);
LOG_VERBOSE(TAG_CONF, output.c_str());
// show settings in log
String output;
serializeJson(settings, output);
String passmask = F(D_PASSWORD_MASK);
const __FlashStringHelper* pass = F("pass");
output.replace(settings[FPSTR(FP_HTTP)][pass].as<String>(), passmask);
output.replace(settings[FPSTR(FP_MQTT)][pass].as<String>(), passmask);
output.replace(settings[FPSTR(FP_WIFI)][pass].as<String>(), passmask);
LOG_VERBOSE(TAG_CONF, output.c_str());
LOG_INFO(TAG_CONF, F(D_FILE_LOADED), configFile.c_str());
configRestorePasswords(settings, wifiPass, mqttPass, httpPass);
LOG_INFO(TAG_CONF, F(D_FILE_LOADED), configFile.c_str());
if(setupdebug) debugSetup();
return;
}
// if(setupdebug) debugSetup();
return error;
}
#else
#if HASP_USE_EEPROM > 0
@ -145,20 +172,18 @@ void configRead(JsonDocument& settings, bool setupdebug = false)
#endif
// File does not exist or error reading file
if(setupdebug) {
debugPreSetup(settings[FPSTR(FP_DEBUG)]);
}
configStartDebug(setupdebug, configFile);
if(setupdebug) configSetupDebug(settings); // Now we can use log
#if HASP_USE_SPIFFS > 0 || HASP_USE_LITTLEFS > 0
LOG_ERROR(TAG_CONF, F(D_FILE_LOAD_FAILED), configFile.c_str());
#endif
#if HASP_USE_CONFIG > 0 && defined(HASP_GPIO_TEMPLATE)
char json[96];
snprintf(json, sizeof(json), PSTR("{\"%s\":%s}"), (char*)(FPSTR(FP_GPIO_CONFIG)), (char*)(FPSTR(FP_GPIO_TEMPLATE)));
dispatch_config((char*)(FPSTR(FP_GPIO)), json);
#endif
configFile = F("EEPROM");
LOG_TRACE(TAG_CONF, F(D_FILE_LOADING), configFile.c_str());
LOG_INFO(TAG_CONF, F(D_FILE_LOADED), configFile.c_str());
return error;
}
/*
void configBackupToEeprom()
{
@ -314,7 +339,9 @@ void configWrite()
File file = HASP_FS.open(configFile, "w");
if(file) {
LOG_TRACE(TAG_CONF, F(D_FILE_SAVING), configFile.c_str());
size_t size = serializeJson(doc, file);
WriteBufferingStream bufferedFile(file, 256);
size_t size = serializeJson(doc, bufferedFile);
bufferedFile.flush();
file.close();
if(size > 0) {
LOG_INFO(TAG_CONF, F(D_FILE_SAVED), configFile.c_str());
@ -376,7 +403,7 @@ void configSetup()
#if HASP_USE_SPIFFS > 0 || HASP_USE_LITTLEFS > 0
if(!filesystemSetup()) {
LOG_ERROR(TAG_CONF, F("FILE: SPI flash init failed. Unable to mount FS: Using default settings..."));
return;
// return; // Keep going and initialize the console with default settings
}
#endif
configRead(settings, true);

View File

@ -6,8 +6,7 @@
#ifndef HASP_CONFIG_H
#define HASP_CONFIG_H
#include "hasp_conf.h"
#include "ArduinoJson.h"
#include "hasplib.h"
#include "hasp_debug.h" // for TAG_CONF
/* ===== Default Event Processors ===== */
@ -18,6 +17,8 @@ void configStart(void);
void configStop(void);
/* ===== Special Event Processors ===== */
DeserializationError configParseFile(String& configFile, JsonDocument& settings);
bool configRead(String configFile, JsonDocument& settings, bool setupdebug = false);
void configWrite(void);
void configOutput(const JsonObject& settings, uint8_t tag = TAG_CONF);
bool configClearEeprom(void);
@ -26,6 +27,7 @@ bool configClearEeprom(void);
bool configSet(int8_t& value, const JsonVariant& setting, const __FlashStringHelper* fstr_name);
bool configSet(uint8_t& value, const JsonVariant& setting, const __FlashStringHelper* fstr_name);
bool configSet(uint16_t& value, const JsonVariant& setting, const __FlashStringHelper* fstr_name);
void configMaskPasswords(JsonDocument& settings);
/* ===== Read/Write Configuration ===== */
void configSetConfig(JsonObject& settings);
@ -71,10 +73,6 @@ const char FP_HASP[] PROGMEM = "hasp";
const char FP_GUI[] PROGMEM = "gui";
const char FP_DEBUG[] PROGMEM = "debug";
#ifdef HASP_GPIO_TEMPLATE
const char FP_GPIO_TEMPLATE[] PROGMEM = HASP_GPIO_TEMPLATE;
#endif
#endif
#endif // HASP_USE_CONFIG

View File

@ -1,15 +1,12 @@
/* MIT License - Copyright (c) 2019-2021 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#include "ArduinoJson.h"
#include "lvgl.h"
#include "hasplib.h"
#include <sys/time.h>
#include "lang/lang.h"
#include "hasp_conf.h"
#include "hasp_debug.h"
#include "hasp_macro.h"
#include "hasp/hasp.h"
#if(!defined(WINDOWS)) && (!defined(POSIX))
#include "ArduinoLog.h"
@ -40,6 +37,7 @@ inline void debugSendAnsiCode(const __FlashStringHelper* code, Print* _logOutput
#endif
}
/*
void debug_timestamp()
{
timeval curTime;
@ -51,7 +49,7 @@ void debug_timestamp()
// strftime(currentTime, 80, "%Y-%m-%d %H:%M.%S", localtime(&t));
strftime(currentTime, 80, "%H:%M:%S", localtime(&t));
printf("[%s.%03d] ", currentTime, milli);
}
} */
static void debugPrintTimestamp(int level, Print* _logOutput)
{ /* Print Current Time */
@ -60,35 +58,34 @@ static void debugPrintTimestamp(int level, Print* _logOutput)
int rslt = gettimeofday(&curTime, NULL);
time_t t = curTime.tv_sec;
tm* timeinfo = localtime(&t);
int milli = curTime.tv_usec / 1000;
(void)rslt; // unused
debugSendAnsiCode(F(TERM_COLOR_CYAN), _logOutput);
if(timeinfo->tm_year >= 120) {
unsigned long int milli = curTime.tv_usec / 1000;
char buffer[24];
strftime(buffer, sizeof(buffer), "[%b %d %H:%M:%S", timeinfo); // Literal String
// strftime(buffer, sizeof(buffer), "[%H:%M:%S.", timeinfo); // Literal String
// strftime(buffer, sizeof(buffer), "[%b %d %H:%M:%S", timeinfo); // Literal String
strftime(buffer, sizeof(buffer), "[" D_TIMESTAMP, timeinfo); // Literal String
#ifdef ARDUINO
_logOutput->printf(PSTR("%s.%03lu]"), buffer, curTime.tv_usec / 1000);
_logOutput->printf(PSTR("%s.%03lu]"), buffer, milli);
#else
debug_print(_logOutput, PSTR("%s.%03lu]"), buffer, curTime.tv_usec / 1000);
debug_print(_logOutput, PSTR("%s.%03lu]"), buffer, milli);
#endif
} else {
uint32_t msecs = millis();
#ifdef ARDUINO
_logOutput->printf(PSTR("[%15d.%03d]"), msecs / 1000, msecs % 1000);
_logOutput->printf(PSTR("[" D_TIME_MILLIS ".%03d]"), msecs / 1000, msecs % 1000);
#else
debug_print(_logOutput, PSTR("[%15d.%03d]"), msecs / 1000, msecs % 1000);
debug_print(_logOutput, PSTR("[" D_TIME_MILLIS ".%03d]"), msecs / 1000, msecs % 1000);
#endif
}
}
/* ===== Default Event Processors ===== */
// void debugPreSetup(JsonObject settings);
// void debugSetup();
static inline void debug_flush()
{
@ -104,7 +101,7 @@ static inline void debug_flush()
void debugEverySecond()
{
// if(debugTelePeriod > 0 && (millis() - debugLastMillis) >= debugTelePeriod * 1000) {
// dispatch_output_statusupdate(NULL, NULL);
// dispatch_statusupdate(NULL, NULL);
// debugLastMillis = millis();
// }
// printLocalTime();
@ -123,7 +120,7 @@ void debugStart()
#endif
if(debugSerialStarted) {
debug_flush;
debug_flush();
// Serial.println();
// Serial.println(debugHaspHeader());
@ -180,22 +177,29 @@ void debugLvglLogEvent(lv_log_level_t level, const char* file, uint32_t line, co
// Send the HASP header and version to the output device specified
void debugPrintHaspHeader(Print* output)
{
// if(debugAnsiCodes) debug_print(output,TERM_COLOR_YELLOW);
// debug_newline(output);
// debug_print(output, F(""
// " _____ _____ _____ _____\r\n"
// " | | | _ | __| _ |\r\n"
// " | | |__ | __|\r\n"
// " |__|__|__|__|_____|__|\r\n"
// " Home Automation Switch Plate\r\n"
// " Open Hardware edition v"));
char buffer[32];
haspGetVersion(buffer, sizeof(buffer));
#ifdef ARDUINO
output->println(buffer);
if(debugAnsiCodes) output->print(TERM_COLOR_YELLOW);
output->println();
output->print(F("\r\n"
" open____ _____ _____ _____\r\n"
" | | | _ | __| _ |\r\n"
" | | |__ | __|\r\n"
" |__|__|__|__|_____|__|\r\n"
" Home Automation Switch Plate\r\n"
" Open Hardware edition v"));
output->println(haspDevice.get_version());
output->println();
#else
debug_print(output, buffer);
if(debugAnsiCodes) debug_print(output, TERM_COLOR_YELLOW);
debug_print(output, F("\r\n"
" open____ _____ _____ _____\r\n"
" | | | _ | __| _ |\r\n"
" | | |__ | __|\r\n"
" |__|__|__|__|_____|__|\r\n"
" Home Automation Switch Plate\r\n"
" Open Hardware edition v"));
debug_print(output, haspDevice.get_version());
debug_newline(output);
debug_newline(output);
#endif
}
@ -234,6 +238,9 @@ void debug_get_tag(uint8_t tag, char* buffer)
memcpy_P(buffer, PSTR("HAL "), 5);
break;
case TAG_CONS:
memcpy_P(buffer, PSTR("CONS"), 5);
break;
case TAG_DEBG:
memcpy_P(buffer, PSTR("DBUG"), 5);
break;
@ -338,8 +345,6 @@ static void debugPrintLvglMemory(int level, Print* _logOutput)
lv_mem_monitor_t mem_mon;
lv_mem_monitor(&mem_mon);
if(mem_mon.frag_pct > 20) lv_mem_defrag(); // prevents LED shadow crashing
/* Print LVGL Memory Info */
if(debugAnsiCodes) {
if(mem_mon.free_biggest_size > (1024u * 2) && (mem_mon.free_size > 1024u * 2.5) && (mem_mon.frag_pct <= 10))

View File

@ -14,8 +14,7 @@
#include "ArduinoLog.h"
/* ===== Default Event Processors ===== */
void debugPreSetup(JsonObject settings);
void debugSetup();
void debugSetup(JsonObject settings);
/* ===== Special Event Processors ===== */
@ -85,6 +84,46 @@ void debugStopSyslog(void);
std::cout << std::endl; \
fflush(stdout)
/* json keys used in the configfile */
// const char FP_CONFIG_STARTPAGE[] PROGMEM = "startpage";
// const char FP_CONFIG_STARTDIM[] PROGMEM = "startdim";
// const char FP_CONFIG_THEME[] PROGMEM = "theme";
// const char FP_CONFIG_HUE[] PROGMEM = "hue";
// const char FP_CONFIG_ZIFONT[] PROGMEM = "font";
// const char FP_CONFIG_PAGES[] PROGMEM = "pages";
// const char FP_CONFIG_ENABLE[] PROGMEM = "enable";
// const char FP_CONFIG_HOST[] PROGMEM = "host";
// const char FP_CONFIG_PORT[] PROGMEM = "port";
// const char FP_CONFIG_NAME[] PROGMEM = "name";
// const char FP_CONFIG_USER[] PROGMEM = "user";
// const char FP_CONFIG_PASS[] PROGMEM = "pass";
// const char FP_CONFIG_SSID[] PROGMEM = "ssid";
// const char FP_CONFIG_GROUP[] PROGMEM = "group";
// const char FP_CONFIG_BAUD[] PROGMEM = "baud";
// const char FP_CONFIG_LOG[] PROGMEM = "log";
// const char FP_CONFIG_PROTOCOL[] PROGMEM = "proto";
// const char FP_GUI_ROTATION[] PROGMEM = "rotate";
// const char FP_GUI_INVERT[] PROGMEM = "invert";
// const char FP_GUI_TICKPERIOD[] PROGMEM = "tick";
// const char FP_GUI_IDLEPERIOD1[] PROGMEM = "idle1";
// const char FP_GUI_IDLEPERIOD2[] PROGMEM = "idle2";
// const char FP_GUI_CALIBRATION[] PROGMEM = "calibration";
// const char FP_GUI_BACKLIGHTPIN[] PROGMEM = "bckl";
// const char FP_GUI_POINTER[] PROGMEM = "cursor";
// const char FP_DEBUG_TELEPERIOD[] PROGMEM = "tele";
// const char FP_GPIO_CONFIG[] PROGMEM = "config";
// const char FP_HASP_CONFIG_FILE[] PROGMEM = "/config.json";
// const char FP_WIFI[] PROGMEM = "wifi";
// const char FP_MQTT[] PROGMEM = "mqtt";
// const char FP_HTTP[] PROGMEM = "http";
// const char FP_GPIO[] PROGMEM = "gpio";
// const char FP_MDNS[] PROGMEM = "mdns";
// const char FP_HASP[] PROGMEM = "hasp";
// const char FP_GUI[] PROGMEM = "gui";
// const char FP_DEBUG[] PROGMEM = "debug";
#endif
#ifdef __cplusplus
@ -93,7 +132,7 @@ extern "C" {
// Functions used by ANDROID, WINDOWS and POSSIX
void debugLvglLogEvent(lv_log_level_t level, const char* file, uint32_t line, const char* funcname, const char* descr);
void debugLoop(void);
IRAM_ATTR void debugLoop(void);
void debugEverySecond(void);
void debugStart(void);
void debugStop(void);
@ -123,9 +162,10 @@ enum {
TAG_EVENT = 8,
TAG_DEBG = 10,
TAG_TELN = 11,
TAG_SYSL = 12,
TAG_TASM = 13,
TAG_CONS = 11,
TAG_TELN = 12,
TAG_SYSL = 13,
TAG_TASM = 14,
TAG_CONF = 20,
TAG_GUI = 21,

View File

@ -14,56 +14,14 @@
void filesystemInfo()
{ // Get all information of your SPIFFS
#if 0
#ifdef ESP8266
FSInfo fs_info;
SPIFFS.info(fs_info);
HASP_FS.info(fs_info);
Log.verbose(TAG_FILE, "Partition size: total: %d, used: %d", fs_info.totalBytes, fs_info.usedBytes);
#endif
Serial.println("File system info.");
Serial.print("Total space: ");
Serial.print(fs_info.totalBytes);
Serial.println("byte");
Serial.print("Total space used: ");
Serial.print(fs_info.usedBytes);
Serial.println("byte");
Serial.print("Block size: ");
Serial.print(fs_info.blockSize);
Serial.println("byte");
Serial.print("Page size: ");
Serial.print(fs_info.totalBytes);
Serial.println("byte");
Serial.print("Max open files: ");
Serial.println(fs_info.maxOpenFiles);
Serial.print("Max path lenght: ");
Serial.println(fs_info.maxPathLength);
Serial.println("File sistem info.");
Serial.print("Total space: ");
Serial.print(SPIFFS.totalBytes());
Serial.println("byte");
Serial.print("Total space used: ");
Serial.print(SPIFFS.usedBytes());
Serial.println("byte");
Serial.print("Block size: ");
// Serial.print(SPIFFS);
Serial.println("byte");
Serial.print("Page size: ");
Serial.print(SPIFFS.totalBytes());
Serial.println("byte");
Serial.print("Max open files: ");
// Serial.println(SPIFFS.maxOpenFiles());
Serial.print("Max path lenght: ");
// Serial.println(SPIFFS.maxPathLength());
#ifdef ESP32
Log.verbose(TAG_FILE, "Partition size: total: %d, used: %d", HASP_FS.totalBytes(), HASP_FS.usedBytes());
#endif
}
@ -71,9 +29,9 @@ void filesystemList()
{
#if HASP_USE_SPIFFS > 0
#if defined(ARDUINO_ARCH_ESP8266)
if(!SPIFFS.begin()) {
if(!HASP_FS.begin()) {
#else
if(!SPIFFS.begin(true)) {
if(!HASP_FS.begin(true)) { // default vfs path: /littlefs
#endif
LOG_ERROR(TAG_FILE, F("Flash file system not mouted."));
} else {
@ -81,7 +39,7 @@ void filesystemList()
LOG_VERBOSE(TAG_FILE, F("Listing files on the internal flash:"));
#if defined(ARDUINO_ARCH_ESP32)
File root = SPIFFS.open("/");
File root = HASP_FS.open("/");
File file = root.openNextFile();
while(file) {
LOG_VERBOSE(TAG_FILE, F(" * %s (%u bytes)"), file.name(), (uint32_t)file.size());
@ -89,7 +47,7 @@ void filesystemList()
}
#endif
#if defined(ARDUINO_ARCH_ESP8266)
Dir dir = SPIFFS.openDir("/");
Dir dir = HASP_FS.openDir("/");
while(dir.next()) {
LOG_VERBOSE(TAG_FILE, F(" * %s (%u bytes)"), dir.fileName().c_str(), (uint32_t)dir.fileSize());
}

View File

@ -1,10 +1,8 @@
/* MIT License - Copyright (c) 2019-2021 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#include "hasp_conf.h"
#include "hasplib.h"
#include "lv_conf.h"
#include "lvgl.h"
#include "lv_drv_conf.h"
// Filesystem Driver
@ -24,14 +22,12 @@
#include "hasp_gui.h"
#include "hasp_oobe.h"
#include "hasplib.h"
//#include "tpcal.h"
//#include "Ticker.h"
#if HASP_USE_PNGDECODE > 0
#include "png_decoder.h"
#include "lv_png.h"
#endif
#define BACKLIGHT_CHANNEL 0 // pwm channel 0-15
@ -52,7 +48,7 @@ File pFileOut;
#define INVERT_COLORS 0
#endif
// static void IRAM_ATTR lv_tick_handler(void);
// HASP_ATTRIBUTE_FAST_MEM static void lv_tick_handler(void);
gui_conf_t gui_settings = {.show_pointer = false,
.backlight_pin = TFT_BCKL,
@ -60,8 +56,8 @@ gui_conf_t gui_settings = {.show_pointer = false,
.invert_display = INVERT_COLORS,
.cal_data = {0, 65535, 0, 65535, 0}};
// static int8_t guiDimLevel = 100;
// bool guiBacklightIsOn;
uint16_t tft_width = TFT_WIDTH;
uint16_t tft_height = TFT_HEIGHT;
// #if defined(ARDUINO_ARCH_ESP32) || defined(ARDUINO_ARCH_ESP8266)
// static Ticker tick; /* timer for interrupt handler */
@ -76,7 +72,8 @@ gui_conf_t gui_settings = {.show_pointer = false,
// {
// lv_tick_inc(LVGL_TICK_PERIOD);
// }
void gui_flush_cb(lv_disp_drv_t* disp, const lv_area_t* area, lv_color_t* color_p)
IRAM_ATTR void gui_flush_cb(lv_disp_drv_t* disp, const lv_area_t* area, lv_color_t* color_p)
{
haspTft.flush_pixels(disp, area, color_p);
}
@ -98,20 +95,24 @@ void guiCalibrate(void)
#endif
}
void guiSetup(void)
void guiSetup()
{
// Register logger to capture lvgl_init output
LOG_TRACE(TAG_LVGL, F(D_SERVICE_STARTING));
#if LV_USE_LOG != 0
lv_log_register_print_cb(debugLvglLogEvent);
#endif
LOG_TRACE(TAG_TFT, F(D_SERVICE_STARTING));
// Initialize the TFT
haspTft.init(240, 320);
haspTft.init(tft_width, tft_height);
haspTft.set_rotation(gui_settings.rotation);
haspTft.set_invert(gui_settings.invert_display);
haspTft.show_info();
LOG_INFO(TAG_TFT, F(D_SERVICE_STARTED));
LOG_TRACE(TAG_LVGL, F(D_SERVICE_STARTING));
#if LV_USE_LOG != 0
lv_log_register_print_cb(debugLvglLogEvent);
#endif
/* Create the Virtual Device Buffers */
#if defined(ARDUINO_ARCH_ESP32)
@ -167,13 +168,16 @@ void guiSetup(void)
LOG_FATAL(TAG_GUI, F(D_ERROR_OUT_OF_MEMORY));
}
LOG_VERBOSE(TAG_LVGL, F("Version : %u.%u.%u %s"), LVGL_VERSION_MAJOR, LVGL_VERSION_MINOR, LVGL_VERSION_PATCH,
PSTR(LVGL_VERSION_INFO));
/* Initialize the display driver */
static lv_disp_drv_t disp_drv;
lv_disp_drv_init(&disp_drv);
disp_drv.buffer = &disp_buf;
disp_drv.flush_cb = gui_flush_cb;
disp_drv.hor_res = TFT_WIDTH;
disp_drv.ver_res = TFT_HEIGHT;
disp_drv.hor_res = tft_width;
disp_drv.ver_res = tft_height;
switch(gui_settings.rotation) {
case 1:
@ -181,43 +185,52 @@ void guiSetup(void)
case 5:
case 7:
// lv_disp_set_rotation(display, LV_DISP_ROT_90);
disp_drv.hor_res = TFT_HEIGHT;
disp_drv.ver_res = TFT_WIDTH;
disp_drv.hor_res = tft_height;
disp_drv.ver_res = tft_width;
break;
default:
// lv_disp_set_rotation(display, LV_DISP_ROT_NONE);
disp_drv.hor_res = TFT_WIDTH;
disp_drv.ver_res = TFT_HEIGHT;
disp_drv.hor_res = tft_width;
disp_drv.ver_res = tft_height;
}
lv_disp_t* display = lv_disp_drv_register(&disp_drv);
(void)display; // unused
/* Initialize Filesystems */
#if LV_USE_FS_IF != 0
// _lv_fs_init(); // lvgl File System -- not neaded, it done in lv_init() when LV_USE_FILESYSTEM is set
LOG_VERBOSE(TAG_LVGL, F("Filesystem : Enabled"));
//_lv_fs_init(); // lvgl File System -- not neaded, it done in lv_init() when LV_USE_FILESYSTEM is set
LOG_VERBOSE(TAG_LVGL, F("Filesystem : " D_SETTING_ENABLED));
lv_fs_if_init(); // auxilary file system drivers
filesystem_list_path("S:/fs/");
filesystem_list_path("L:/");
lv_fs_file_t f;
lv_fs_res_t res;
res = lv_fs_open(&f, "L:/config.json", LV_FS_MODE_RD);
if(res == LV_FS_RES_OK) {
LOG_VERBOSE(TAG_HASP, F("TEST Opening config.json OK"));
lv_fs_close(&f);
} else {
LOG_ERROR(TAG_HASP, F("TEST Opening config.json from FS failed %d"), res);
}
#else
LOG_VERBOSE(TAG_LVGL, F("Filesystem : Disabled"));
LOG_VERBOSE(TAG_LVGL, F("Filesystem : " D_SETTING_DISABLED));
#endif
/* Initialize PNG decoder */
#if HASP_USE_PNGDECODE > 0
png_decoder_init();
lv_png_init();
#endif
#ifdef USE_DMA_TO_TFT
LOG_VERBOSE(TAG_GUI, F("DMA : ENABLED"));
LOG_VERBOSE(TAG_GUI, F("DMA : " D_SETTING_ENABLED));
#else
LOG_VERBOSE(TAG_GUI, F("DMA : DISABLED"));
LOG_VERBOSE(TAG_GUI, F("DMA : " D_SETTING_DISABLED));
#endif
/* Setup Backlight Control Pin */
haspDevice.set_backlight_pin(gui_settings.backlight_pin);
LOG_VERBOSE(TAG_LVGL, F("Version : %u.%u.%u %s"), LVGL_VERSION_MAJOR, LVGL_VERSION_MINOR, LVGL_VERSION_PATCH,
PSTR(LVGL_VERSION_INFO));
#ifdef LV_MEM_SIZE
LOG_VERBOSE(TAG_LVGL, F("MEM size : %d"), LV_MEM_SIZE);
#endif
@ -280,10 +293,13 @@ void guiSetup(void)
lv_obj_set_style_local_bg_opa(lv_layer_sys(), LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_0);
// guiStart(); // Ticker
LOG_INFO(TAG_LVGL, F(D_SERVICE_STARTED));
}
void guiLoop(void)
IRAM_ATTR void guiLoop(void)
{
lv_task_handler(); // process animations
#if defined(STM32F4xx)
// tick.update();
#endif
@ -578,7 +594,7 @@ void guiTakeScreenshot(const char* pFileName)
pFileOut.close();
} else {
LOG_WARNING(TAG_GUI, F("%s cannot be opened"), pFileName);
LOG_WARNING(TAG_GUI, F(D_FILE_SAVE_FAILED), pFileName);
}
}
#endif

View File

@ -4,8 +4,7 @@
#ifndef HASP_GUI_H
#define HASP_GUI_H
#include "ArduinoJson.h"
#include "lvgl.h"
#include "hasplib.h"
struct gui_conf_t
{
@ -18,7 +17,7 @@ struct gui_conf_t
/* ===== Default Event Processors ===== */
void guiSetup(void);
void guiLoop(void);
IRAM_ATTR void guiLoop(void);
void guiEverySecond(void);
void guiStart(void);
void guiStop(void);

View File

@ -3,12 +3,7 @@
#if HASP_USE_CONFIG > 0
#include "hasp_conf.h"
#include "lvgl.h"
#if LVGL_VERSION_MAJOR != 7
#include "../lv_components.h"
#endif
#include "hasplib.h"
#include "hasp_gui.h"
#include "hasp_config.h"
@ -30,7 +25,7 @@ static lv_obj_t* oobepage[2];
static lv_obj_t* oobekb;
lv_obj_t* pwd_ta;
static inline void oobeSetPage(uint8_t pageid)
static void oobeSetPage(uint8_t pageid)
{
lv_scr_load(oobepage[pageid]);
lv_obj_invalidate(lv_disp_get_layer_sys(NULL));
@ -57,8 +52,8 @@ static void kb_event_cb(lv_obj_t* event_kb, lv_event_t event)
{
if(event == LV_EVENT_APPLY) {
StaticJsonDocument<256> settings;
char ssid[32] = "";
char pass[32] = "";
char ssid[64] = "";
char pass[64] = "";
lv_obj_t* obj;
obj = hasp_find_obj_from_parent_id(oobepage[1], (uint8_t)10);

43
src/hasp_png.cpp Normal file
View File

@ -0,0 +1,43 @@
/* MIT License - Copyright (c) 2019-2021 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifdef LODEPNG_NO_COMPILE_ALLOCATORS
#include <stdlib.h>
#include "hasplib.h"
#include "hasp_png.h"
void* lodepng_malloc(size_t size)
{
#ifdef LODEPNG_MAX_ALLOC
if(size > LODEPNG_MAX_ALLOC) return 0;
#endif
#ifdef ESP32
return psramFound() ? ps_malloc(size) : malloc(size);
#else
return malloc(size);
#endif
}
/* NOTE: when realloc returns NULL, it leaves the original memory untouched */
void* lodepng_realloc(void* ptr, size_t new_size)
{
#ifdef LODEPNG_MAX_ALLOC
if(new_size > LODEPNG_MAX_ALLOC) return 0;
#endif
#ifdef ESP32
return psramFound() ? ps_realloc(ptr, new_size) : realloc(ptr, new_size);
#else
return realloc(ptr, new_size);
#endif
}
void lodepng_free(void* ptr)
{
free(ptr);
}
#endif // LODEPNG_NO_COMPILE_ALLOCATORS

25
src/hasp_png.h Normal file
View File

@ -0,0 +1,25 @@
/* MIT License - Copyright (c) 2019-2021 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifndef HASP_PNG_H
#define HASP_PNG_H
#include <stdlib.h>
#ifdef LODEPNG_NO_COMPILE_ALLOCATORS
#ifdef __cplusplus
extern "C" {
#endif
void* lodepng_malloc(size_t size);
void* lodepng_realloc(void* ptr, size_t new_size);
void lodepng_free(void* ptr);
#ifdef __cplusplus
}
#endif
#endif // LODEPNG_NO_COMPILE_ALLOCATORS
#endif // HASP_PNG_H

View File

@ -1,5 +1,17 @@
#ifdef ARDUINO
#include <Arduino.h>
#endif
#include <cstdlib>
#include <cctype>
#include <string>
#include <stdint.h>
#include "hasp_conf.h"
#include "lv_conf.h"
#include "lvgl.h"
#include "hasp/hasp.h"
#include "hasp/hasp_attribute.h"
#include "hasp/hasp_dispatch.h"
@ -9,4 +21,6 @@
#include "hasp/hasp_parser.h"
#include "hasp/hasp_lvfs.h"
#include "hasp/lv_theme_hasp.h"
#include "hasp/lv_theme_hasp.h"
#include "ArduinoJson.h"

View File

@ -4,6 +4,8 @@
#define D_USERNAME "Username:"
#define D_PASSWORD "Password:"
#define D_SSID "Ssid:"
#define D_YES "Yes" // New
#define D_NO "No" // New
#define D_ERROR_OUT_OF_MEMORY "Out of memory"
#define D_ERROR_UNKNOWN "Unkown error"
@ -15,10 +17,16 @@
#define D_FILE_LOADING "Loading %s"
#define D_FILE_LOADED "Loaded %s"
#define D_FILE_LOAD_FAILED "Failed to load %s"
#define D_FILE_SAVING "Saving %s"
#define D_FILE_SAVED "Saved %s"
#define D_FILE_SAVE_FAILED "Failed to save %s"
#define D_FILE_NOT_FOUND "File not found" // new
#define D_FILE_SIZE_BYTES "bytes" // new
#define D_FILE_SIZE_KILOBYTES "KiB" // new
#define D_FILE_SIZE_MEGABYTES "MiB" // new
#define D_FILE_SIZE_GIGABYTES "GiB" // new
#define D_FILE_SIZE_DIVIDER 1024 // new, kibi or kilo bytes
#define D_DECIMAL_POINT "." // new, decimal comma or point
#define D_SERVICE_STARTING "Starting..."
#define D_SERVICE_STARTED "Started"
@ -28,6 +36,9 @@
#define D_SERVICE_CONNECTED "Connected"
#define D_SERVICE_DISCONNECTED "Disconnected"
#define D_SETTING_ENABLED "Enabled" // New
#define D_SETTING_DISABLED "Disabled" // New
#define D_NETWORK_IP_ADDRESS_RECEIVED "Received IP address %s"
#define D_NETWORK_ONLINE "online"
#define D_NETWORK_OFFLINE "offline"
@ -47,7 +58,7 @@
#define D_MQTT_SUBSCRIBED "Subscribed to %s"
#define D_MQTT_NOT_SUBSCRIBED "Failed to subscribe to %s"
#define D_MQTT_HA_AUTO_DISCOVERY "Register HA auto-discovery"
#define D_MQTT_PAYLOAD_TOO_LONG "Payload too long (%d bytes)"
#define D_MQTT_PAYLOAD_TOO_LONG "Payload too long (%u bytes)"
#define D_TELNET_CLOSING_CONNECTION "Closing session from %s"
#define D_TELNET_CLIENT_LOGIN_FROM "Client login from %s"
@ -58,7 +69,6 @@
#define D_TELNET_STARTED "Telnet console started"
#define D_TELNET_FAILED "Failed to start telnet console"
#define D_TELNET_CLIENT_CONNECTED "Client connected"
#define D_TELNET_CLIENT_NOT_CONNECTED "Client NOT connected"
#define D_TELNET_CLIENT_REJECTED "Client rejected"
#define D_HASP_INVALID_PAGE "Invalid page %u"
@ -70,13 +80,15 @@
#define D_OBJECT_UNKNOWN "Unknown object"
#define D_OBJECT_MISMATCH "Objects DO NOT match!"
#define D_OBJECT_LOST "Lost object!"
#define D_OBJECT_CREATE_FAILED "Object %u failed"
#define D_OBJECT_CREATE_FAILED "Failed to create object id %u"
#define D_OBJECT_PAGE_UNKNOWN "Page ID %u not defined"
#define D_OBJECT_EVENT_UNKNOWN "Unknown Event %d"
#define D_ATTRIBUTE_UNKNOWN "Unknown property %s"
#define D_ATTRIBUTE_READ_ONLY "%s is read-only"
#define D_ATTRIBUTE_PAGE_METHOD_INVALID "Unable to call %s on a page"
#define D_ATTRIBUTE_ALIGN_INVALID "Invalid align property: %s"
#define D_ATTRIBUTE_COLOR_INVALID "Invalid color property: %s"
#define D_OOBE_SSID_VALIDATED "SSID %s validated"
#define D_OOBE_AUTO_CALIBRATE "Auto calibrate enabled"
@ -87,7 +99,7 @@
#define D_DISPATCH_REBOOT "Rebooting the MCU now!"
#define D_JSON_FAILED "JSON parsing failed:"
#define D_JSONL_FAILED "JSONL parsing failed at line %d"
#define D_JSONL_FAILED "JSONL parsing failed at line %u"
#define D_JSONL_SUCCEEDED "Jsonl fully parsed"
#define D_OTA_CHECK_UPDATE "Checking updates URL: %s"
@ -97,6 +109,8 @@
#define D_OTA_UPDATE_COMPLETE "OTA Update complete"
#define D_OTA_UPDATE_APPLY "Applying Firmware & Reboot"
#define D_OTA_UPDATE_FAILED "OTA Update failed"
#define D_OTA_UPDATING_FIRMWARE "Updating firmware..."
#define D_OTA_UPDATING_FILESYSTEM "Updating filesystem..."
#define D_HTTP_HASP_DESIGN "HASP Design"
#define D_HTTP_INFORMATION "Information"
@ -118,18 +132,85 @@
#define D_HTTP_NEXT_PAGE "Next Page"
#define D_HTTP_CALIBRATE "Calibrate"
#define D_HTTP_SCREENSHOT "Screenshot"
#define D_HTTP_FILE_BROWSER "File Browser"
#define D_HTTP_FILE_BROWSER "File Editor"
#define D_HTTP_FIRMWARE_UPGRADE "Firmware Upgrade"
#define D_HTTP_UPDATE_FIRMWARE "Update Firmware"
#define D_HTTP_FACTORY_RESET "Factory Reset"
#define D_HTTP_MAIN_MENU "Main Menu"
#define D_HTTP_REBOOT "Restart"
#define D_HTTP_CONFIGURATION "Configuration"
#define D_HTTP_SENDING_PAGE "Sent %S page to %s" // New
#define D_HTTP_FOOTER "by Francis Van Roie"
#define D_INFO_VERSION "Version"
#define D_INFO_BUILD_DATETIME "Build DateTime"
#define D_INFO_UPTIME "Uptime"
#define D_INFO_FREE_HEAP "Free Heap"
#define D_INFO_FREE_BLOCK "Free Block"
#define D_INFO_DEVICE_MEMORY "Device Memory"
#define D_INFO_LVGL_MEMORY "LVGL Memory"
#define D_INFO_TOTAL_MEMORY "Total"
#define D_INFO_FREE_MEMORY "Free"
#define D_INFO_FRAGMENTATION "Fragmentation"
#define D_INFO_PSRAM_FREE "PSRam Free"
#define D_INFO_PSRAM_SIZE "PSRam Size"
#define D_INFO_FLASH_SIZE "Flash Size"
#define D_INFO_SKETCH_USED "Program Size Used"
#define D_INFO_SKETCH_FREE "Program Size Free"
#define D_INFO_MODULE "Module"
#define D_INFO_MODEL "Model"
#define D_INFO_FREQUENCY "Frequency"
#define D_INFO_CORE_VERSION "Core Version"
#define D_INFO_RESET_REASON "Reset Reason"
#define D_INFO_STATUS "Status"
#define D_INFO_SERVER "Server"
#define D_INFO_USERNAME "Username"
#define D_INFO_CLIENTID "Client ID"
#define D_INFO_CONNECTED "Connected"
#define D_INFO_DISCONNECTED "Disconnected"
#define D_INFO_RECEIVED "Received"
#define D_INFO_PUBLISHED "Published"
#define D_INFO_FAILED "Failed"
#define D_INFO_ETHERNET "Ethernet"
#define D_INFO_WIFI "Wifi"
#define D_INFO_LINK_SPEED "Link Speed"
#define D_INFO_FULL_DUPLEX "Full Duplex"
#define D_INFO_SSID "SSID"
#define D_INFO_RSSI "Signal Strength"
#define D_INFO_IP_ADDRESS "IP Address"
#define D_INFO_MAC_ADDRESS "MAC Address"
#define D_INFO_GATEWAY "Gateway"
#define D_INFO_DNS_SERVER "DNS Server"
#define D_OOBE_MSG "Tap the screen to setup WiFi or connect to this Access Point:"
#define D_OOBE_SCAN_TO_CONNECT "Scan to connect"
#define D_WIFI_CONNECTING_TO "Connecting to %s"
#define D_WIFI_CONNECTED_TO "Connected to %s, requesting IP..."
#define D_WIFI_RSSI_EXCELLENT "Excellent"
#define D_WIFI_RSSI_GOOD "Good"
#define D_WIFI_RSSI_FAIR "Fair"
#define D_WIFI_RSSI_WEAK "Weak"
#define D_WIFI_RSSI_BAD "Very bad"
// new
#define D_GPIO_SWITCH "Switch"
#define D_GPIO_BUTTON "Push Button"
#define D_GPIO_TOUCH "Capacitive Touch" // new
#define D_GPIO_LED "Led"
#define D_GPIO_LED_R "Mood Red"
#define D_GPIO_LED_G "Mood Green"
#define D_GPIO_LED_B "Mood Blue"
#define D_GPIO_POWER_RELAY "Power Relay" // new
#define D_GPIO_LIGHT_RELAY "Light Relay" // new
#define D_GPIO_PWM "PWM"
#define D_GPIO_DAC "DAC"
#define D_GPIO_SERIAL_DIMMER "Serial Dimmer"
#define D_GPIO_UNKNOWN "Unknown"
#define D_GPIO_PIN "Pin"
#define D_GPIO_GROUP "Group"
#define D_GPIO_GROUP_NONE "None"
#define D_GPIO_STATE_NORMAL "Normal" // new
#define D_GPIO_STATE_INVERTED "Inverted" // new
#endif

216
src/lang/es_ES.h Normal file
View File

@ -0,0 +1,216 @@
#ifndef HASP_LANG_ES_ES_H
#define HASP_LANG_ES_ES_H
#define D_USERNAME "Usuario:"
#define D_PASSWORD "Contraseña:"
#define D_SSID "Ssid:"
#define D_YES "Si" // New
#define D_NO "No" // New
#define D_ERROR_OUT_OF_MEMORY "Memory llena"
#define D_ERROR_UNKNOWN "Error desconocido"
#define D_CONFIG_NOT_CHANGED "No hay cambios en la configuración"
#define D_CONFIG_CHANGED "Configuración cambiada"
#define D_CONFIG_LOADED "Configuración cargada"
#define D_FILE_LOADING "Cargando %s"
#define D_FILE_LOADED "%s cargado"
#define D_FILE_LOAD_FAILED "No se pudo cargar %s"
#define D_FILE_SAVING "Guardando %s"
#define D_FILE_SAVED "%s guardado"
#define D_FILE_SAVE_FAILED "No se pudo guardar %s"
#define D_FILE_NOT_FOUND "Archivo no encontrado"
#define D_FILE_SIZE_BYTES "bytes" // new
#define D_FILE_SIZE_KILOBYTES "KiB" // new
#define D_FILE_SIZE_MEGABYTES "MiB" // new
#define D_FILE_SIZE_GIGABYTES "GiB" // new
#define D_FILE_SIZE_DIVIDER 1024 // new, kibi or kilo bytes
#define D_DECIMAL_POINT "," // new, decimal comma or point
#define D_SERVICE_STARTING "Inicializando..."
#define D_SERVICE_STARTED "Inicializado"
#define D_SERVICE_START_FAILED "No se pudo arrancar"
#define D_SERVICE_STOPPED "Parado"
#define D_SERVICE_DISABLED "Deshabilitado"
#define D_SERVICE_CONNECTED "Conectado"
#define D_SERVICE_DISCONNECTED "Desconectado"
#define D_SETTING_ENABLED "habilitado" // New
#define D_SETTING_DISABLED "Deshabilitado" // New
#define D_NETWORK_IP_ADDRESS_RECEIVED "Se recibió la dirección IP: %s"
#define D_NETWORK_ONLINE "en linea"
#define D_NETWORK_OFFLINE "fuera de línea"
#define D_NETWORK_CONNECTION_FAILED "Falló la conexión"
#define D_MQTT_DEFAULT_NAME "placa_%s"
#define D_MQTT_CONNECTING "Conectando..."
#define D_MQTT_CONNECTED "Conectado al Broker %s con el clientID %s"
#define D_MQTT_NOT_CONNECTED "No hay conexión ???"
#define D_MQTT_DISCONNECTING "Desconectando..."
#define D_MQTT_DISCONNECTED "Desconectado"
#define D_MQTT_RECONNECTING "Desconectado del broker, reconectando..."
#define D_MQTT_NOT_CONFIGURED "No se ha configurado el Broker"
#define D_MQTT_STARTED "Arrancando: %d bytes"
#define D_MQTT_FAILED "Falló:"
#define D_MQTT_INVALID_TOPIC "El mensaje tiene un tópico inválido"
#define D_MQTT_SUBSCRIBED "Subscrito a %s"
#define D_MQTT_NOT_SUBSCRIBED "No se pudo subscribir a %s"
#define D_MQTT_HA_AUTO_DISCOVERY "Registrando auto-descubrimiento en HA"
#define D_MQTT_PAYLOAD_TOO_LONG "Los datos enviados son demasiado largos(%u bytes)"
#define D_TELNET_CLOSING_CONNECTION "Cerrando sesión de %s"
#define D_TELNET_CLIENT_LOGIN_FROM "Se ha firmado el cliente %s"
#define D_TELNET_CLIENT_CONNECT_FROM "Se ha conectado el cliente %s"
#define D_TELNET_AUTHENTICATION_FAILED "Falló la autorización!"
#define D_TELNET_INCORRECT_LOGIN_ATTEMPT "Intento de conexión incorrecta desde %s"
#define D_TELNET_STARTED "Console Telnet arrancada"
#define D_TELNET_FAILED "Falló el arranque de la consola Telnet"
#define D_TELNET_CLIENT_CONNECTED "Cliente conectado"
#define D_TELNET_CLIENT_NOT_CONNECTED "Cliente NO conectado"
#define D_TELNET_CLIENT_REJECTED "Cliente rechazado"
#define D_HASP_INVALID_PAGE "Página inválida %u"
#define D_HASP_INVALID_LAYER "No se puede borrar una capa del sistema"
#define D_HASP_CHANGE_PAGE "Cambiando a página %u"
#define D_HASP_CLEAR_PAGE "Limpiando página %u"
#define D_OBJECT_DELETED "Objeto borrado"
#define D_OBJECT_UNKNOWN "Objeto desconocido"
#define D_OBJECT_MISMATCH "Los objetos NO SON IGUALES!"
#define D_OBJECT_LOST "Objeto perdido!"
#define D_OBJECT_CREATE_FAILED "No se pudo crear objeto %u"
#define D_OBJECT_PAGE_UNKNOWN "La página ID %u no está definida"
#define D_OBJECT_EVENT_UNKNOWN "NO se conoce el evento %d "
#define D_ATTRIBUTE_UNKNOWN "Propiedad %s desconocida"
#define D_ATTRIBUTE_READ_ONLY "%s es solo lectura"
#define D_ATTRIBUTE_PAGE_METHOD_INVALID "No se puede llamar %s en una página"
#define D_ATTRIBUTE_ALIGN_INVALID "Invalid align property: %s" // new
#define D_ATTRIBUTE_COLOR_INVALID "Invalid color property: %s" // new
#define D_OOBE_SSID_VALIDATED "SSID %s validado"
#define D_OOBE_AUTO_CALIBRATE "Auto calibración hablitada"
#define D_OOBE_CALIBRATED "Ya se ha calibrado"
#define D_DISPATCH_COMMAND_NOT_FOUND "No se encontró el comando '%s'"
#define D_DISPATCH_INVALID_PAGE "Página inválida %s"
#define D_DISPATCH_REBOOT "Reiniciando microprocesador!"
#define D_JSON_FAILED "No se pudo analizar JSON:"
#define D_JSONL_FAILED "El análisis del JSONL falló en la línea %u"
#define D_JSONL_SUCCEEDED "JSONL analizado"
#define D_OTA_CHECK_UPDATE "Buscando actualización en URL: %s"
#define D_OTA_CHECK_COMPLETE "Verificación de actualizacion completa"
#define D_OTA_CHECK_FAILED "Falló la verificación de actualización: %s"
#define D_OTA_UPDATE_FIRMWARE "Actualización de firmware OTA"
#define D_OTA_UPDATE_COMPLETE "Actualización OTA completada"
#define D_OTA_UPDATE_APPLY "Aplicando el nuevo firmware y reinicio"
#define D_OTA_UPDATE_FAILED "La actualización OTA falló"
#define D_OTA_UPDATING_FIRMWARE "Actualizando el firmware..."
#define D_OTA_UPDATING_FILESYSTEM "Actualizando el sistema de archivos..."
#define D_HTTP_HASP_DESIGN "Diseño de HASP"
#define D_HTTP_INFORMATION "Información"
#define D_HTTP_HTTP_SETTINGS "Ajustes HTTP"
#define D_HTTP_WIFI_SETTINGS "Ajustes Wifi"
#define D_HTTP_MQTT_SETTINGS "Ajustes MQTT"
#define D_HTTP_GPIO_SETTINGS "Ajustes GPIO"
#define D_HTTP_MDNS_SETTINGS "Ajustes mDNS"
#define D_HTTP_TELNET_SETTINGS "Ajustes Telnet"
#define D_HTTP_DEBUG_SETTINGS "Ajustes de depuración"
#define D_HTTP_GUI_SETTINGS "Ajustes de Pantalla"
#define D_HTTP_SAVE_SETTINGS "Guardar configuración"
#define D_HTTP_UPLOAD_FILE "Cargar archivo"
#define D_HTTP_ERASE_DEVICE "Borrar configuración"
#define D_HTTP_ADD_GPIO "Agragar un nuevo pin"
#define D_HTTP_BACK "Atrás"
#define D_HTTP_REFRESH "Refrescar"
#define D_HTTP_PREV_PAGE "Página Previa"
#define D_HTTP_NEXT_PAGE "Siguiente Página"
#define D_HTTP_CALIBRATE "Calibrar"
#define D_HTTP_SCREENSHOT "Imagen de Pantalla"
#define D_HTTP_FILE_BROWSER "Editor de Archivos"
#define D_HTTP_FIRMWARE_UPGRADE "Actualización de firmware"
#define D_HTTP_UPDATE_FIRMWARE "Actualizar firmware"
#define D_HTTP_FACTORY_RESET "Restaurar conf de fábrica"
#define D_HTTP_MAIN_MENU "Menú principal"
#define D_HTTP_REBOOT "Reiniciar"
#define D_HTTP_CONFIGURATION "Configuración"
#define D_HTTP_SENDING_PAGE "Se envió pagina %S a %s" // New
#define D_HTTP_FOOTER "por Francis Van Roie"
#define D_INFO_VERSION "Versión"
#define D_INFO_BUILD_DATETIME "Fecha de compilación"
#define D_INFO_UPTIME "Tiempo activo"
#define D_INFO_FREE_HEAP "Heap libre"
#define D_INFO_FREE_BLOCK "Bloques libres"
#define D_INFO_DEVICE_MEMORY "Memoria de dispositivo"
#define D_INFO_LVGL_MEMORY "Memoria LVGL"
#define D_INFO_TOTAL_MEMORY "Total"
#define D_INFO_FREE_MEMORY "Libre"
#define D_INFO_FRAGMENTATION "Fragmentación"
#define D_INFO_PSRAM_FREE "PSRam libre"
#define D_INFO_PSRAM_SIZE "Tamaño PSRam "
#define D_INFO_FLASH_SIZE "Tamaño Flash"
#define D_INFO_SKETCH_USED "Memoria programa usada"
#define D_INFO_SKETCH_FREE "Memoria Programa libre"
#define D_INFO_MODULE "Módulo"
#define D_INFO_MODEL "Modelo"
#define D_INFO_FREQUENCY "Frecuencia"
#define D_INFO_CORE_VERSION "Versión del núcleo"
#define D_INFO_RESET_REASON "Razón de ultimo Reset"
#define D_INFO_STATUS "Estado"
#define D_INFO_SERVER "Servidor"
#define D_INFO_USERNAME "Nombre de usuario"
#define D_INFO_CLIENTID "ID de Cliente"
#define D_INFO_CONNECTED "Connectado"
#define D_INFO_DISCONNECTED "Desconectado"
#define D_INFO_RECEIVED "Recivido"
#define D_INFO_PUBLISHED "Publicado"
#define D_INFO_FAILED "Fallado"
#define D_INFO_ETHERNET "Ethernet"
#define D_INFO_WIFI "Wifi"
#define D_INFO_LINK_SPEED "Velocidad de enlace"
#define D_INFO_FULL_DUPLEX "Full Duplex"
#define D_INFO_SSID "SSID"
#define D_INFO_RSSI "Potencia de señal"
#define D_INFO_IP_ADDRESS "Dirección IP"
#define D_INFO_MAC_ADDRESS "Dirección MAC"
#define D_INFO_GATEWAY "Gateway"
#define D_INFO_DNS_SERVER "Servidor DNS"
#define D_OOBE_MSG "Toque la pantalla para ajustar WiFi o conectarse a un punto de acceso"
#define D_OOBE_SCAN_TO_CONNECT "Scanee para conectar"
#define D_WIFI_CONNECTING_TO "Connectando a %s"
#define D_WIFI_CONNECTED_TO "Connectado a %s, pidiendo IP..."
#define D_WIFI_RSSI_EXCELLENT "Excellente"
#define D_WIFI_RSSI_GOOD "Buena"
#define D_WIFI_RSSI_FAIR "Pasable"
#define D_WIFI_RSSI_WEAK "Débil"
#define D_WIFI_RSSI_BAD "Muy baka"
// new
#define D_GPIO_SWITCH "Switch"
#define D_GPIO_BUTTON "Botón"
#define D_GPIO_TOUCH "Capacitive Touch" // new
#define D_GPIO_LED "DEL"
#define D_GPIO_LED_R "Ánimo Red"
#define D_GPIO_LED_G "Ánimo Green"
#define D_GPIO_LED_B "Ánimo Blue"
#define D_GPIO_POWER_RELAY "Power Relé" // new
#define D_GPIO_LIGHT_RELAY "Light Relé" // new
#define D_GPIO_PWM "PWM"
#define D_GPIO_DAC "DAC"
#define D_GPIO_SERIAL_DIMMER "Atenuador serial"
#define D_GPIO_UNKNOWN "Desconocido"
#define D_GPIO_PIN "Pin"
#define D_GPIO_GROUP "Grupo"
#define D_GPIO_GROUP_NONE "Ninguno"
#define D_GPIO_STATE_NORMAL "Normal" // new
#define D_GPIO_STATE_INVERTED "Inverted" // new
#endif

215
src/lang/fr_FR.h Normal file
View File

@ -0,0 +1,215 @@
#ifndef HASP_LANG_FR_FR_H
#define HASP_LANG_FR_FR_H
#define D_USERNAME "Utilisateur:"
#define D_PASSWORD "Mot de passe:"
#define D_SSID "Ssid:"
#define D_YES "Oui"
#define D_NO "Non"
#define D_ERROR_OUT_OF_MEMORY "Mémoire insuffisante "
#define D_ERROR_UNKNOWN "Erreur inconnue"
#define D_CONFIG_NOT_CHANGED "Paramètres pas modifiés"
#define D_CONFIG_CHANGED "Paramètres modifiés"
#define D_CONFIG_LOADED "Paramètres chargés"
#define D_FILE_LOADING "Charger %s"
#define D_FILE_LOADED "Chargé %s"
#define D_FILE_LOAD_FAILED "Échec du chargement %s"
#define D_FILE_SAVING "Enregistrer %s"
#define D_FILE_SAVED "Enregistré %s"
#define D_FILE_SAVE_FAILED "Échec de l'enregistrement %s"
#define D_FILE_NOT_FOUND "Fichier non trouvé"
#define D_FILE_SIZE_BYTES "octets"
#define D_FILE_SIZE_KILOBYTES "Kio"
#define D_FILE_SIZE_MEGABYTES "Mio"
#define D_FILE_SIZE_GIGABYTES "Gio"
#define D_FILE_SIZE_DIVIDER 1024 // new, kibi or kilo bytes
#define D_DECIMAL_POINT "," // new, decimal comma or point
#define D_SERVICE_STARTING "Démarer..."
#define D_SERVICE_STARTED "Démaré"
#define D_SERVICE_START_FAILED "Échec du démarrage"
#define D_SERVICE_STOPPED "Arrêté"
#define D_SERVICE_DISABLED "Désactivé"
#define D_SERVICE_CONNECTED "Connecté"
#define D_SERVICE_DISCONNECTED "Débranché"
#define D_SETTING_ENABLED "Activé"
#define D_SETTING_DISABLED "Désactivé"
#define D_NETWORK_IP_ADDRESS_RECEIVED "Adresse IP reçue %s"
#define D_NETWORK_ONLINE "en ligne"
#define D_NETWORK_OFFLINE "déconnecté"
#define D_NETWORK_CONNECTION_FAILED "Échec de la connexion "
#define D_MQTT_DEFAULT_NAME "plaque_%s"
#define D_MQTT_CONNECTING "Connexion..."
#define D_MQTT_CONNECTED "Connecté au broker %s avec ID client %s"
#define D_MQTT_NOT_CONNECTED "Pas connecté ???"
#define D_MQTT_DISCONNECTING "Déconnexion..."
#define D_MQTT_DISCONNECTED "Débranché"
#define D_MQTT_RECONNECTING "Déconnecté du broker, reconnexion..."
#define D_MQTT_NOT_CONFIGURED "Broker non configuré"
#define D_MQTT_STARTED "Démarré: %d octets "
#define D_MQTT_FAILED "Manqué:"
#define D_MQTT_INVALID_TOPIC "Message avec sujet non valide "
#define D_MQTT_SUBSCRIBED "Abonné à %s"
#define D_MQTT_NOT_SUBSCRIBED "Échec de s'abonner à %s"
#define D_MQTT_HA_AUTO_DISCOVERY "Enregistrer la détection automatique HA"
#define D_MQTT_PAYLOAD_TOO_LONG "Charge utile trop long (%u octets) "
#define D_TELNET_CLOSING_CONNECTION "Clôture de la session %s"
#define D_TELNET_CLIENT_LOGIN_FROM "Connexion client depuis %s"
#define D_TELNET_CLIENT_CONNECT_FROM "Client connecté depuis %s"
#define D_TELNET_CLIENT_NOT_CONNECTED "Client NON connecté"
#define D_TELNET_AUTHENTICATION_FAILED "Échec de l'autorisation!"
#define D_TELNET_INCORRECT_LOGIN_ATTEMPT "Tentative incorrecte de %s"
#define D_TELNET_STARTED "Console Telnet démarré"
#define D_TELNET_FAILED "Échec du démarrage de la console telnet"
#define D_TELNET_CLIENT_CONNECTED "Client connecté"
#define D_TELNET_CLIENT_REJECTED "Client rejeté"
#define D_HASP_INVALID_PAGE "Page non valide %u"
#define D_HASP_INVALID_LAYER "Impossible d'effacer la couche système"
#define D_HASP_CHANGE_PAGE "Changement de page %u"
#define D_HASP_CLEAR_PAGE "Effacement de la page %u"
#define D_OBJECT_DELETED "Objet supprimé"
#define D_OBJECT_UNKNOWN "Objet inconnu"
#define D_OBJECT_MISMATCH "Objets ne correspondent PAS!"
#define D_OBJECT_LOST "Objet perdu!"
#define D_OBJECT_CREATE_FAILED "Échec de la création d'objet %u"
#define D_OBJECT_PAGE_UNKNOWN "ID de page %u non défini"
#define D_OBJECT_EVENT_UNKNOWN "Inconnu Event %d"
#define D_ATTRIBUTE_UNKNOWN "Unknown property %s"
#define D_ATTRIBUTE_READ_ONLY "%s is read-only"
#define D_ATTRIBUTE_PAGE_METHOD_INVALID "Unable to call %s on a page"
#define D_ATTRIBUTE_ALIGN_INVALID "Invalid align property: %s" // new
#define D_ATTRIBUTE_COLOR_INVALID "Invalid color property: %s" // new
#define D_OOBE_SSID_VALIDATED "SSID %s validated"
#define D_OOBE_AUTO_CALIBRATE "Auto calibrate enabled"
#define D_OOBE_CALIBRATED "Already calibrated"
#define D_DISPATCH_COMMAND_NOT_FOUND "Command '%s' not found"
#define D_DISPATCH_INVALID_PAGE "Invalid page %s"
#define D_DISPATCH_REBOOT "Rebooting the MCU now!"
#define D_JSON_FAILED "JSON parsing failed:"
#define D_JSONL_FAILED "JSONL parsing failed at line %u"
#define D_JSONL_SUCCEEDED "Jsonl fully parsed"
#define D_OTA_CHECK_UPDATE "Checking updates URL: %s"
#define D_OTA_CHECK_COMPLETE "Update check complete"
#define D_OTA_CHECK_FAILED "Update check failed: %s"
#define D_OTA_UPDATE_FIRMWARE "OTA Firmware Update"
#define D_OTA_UPDATE_COMPLETE "OTA Update complete"
#define D_OTA_UPDATE_APPLY "Applying Firmware & Reboot"
#define D_OTA_UPDATE_FAILED "OTA Update failed"
#define D_OTA_UPDATING_FIRMWARE "Updating firmware..."
#define D_OTA_UPDATING_FILESYSTEM "Updating filesystem..."
#define D_HTTP_HASP_DESIGN "Conception HASP"
#define D_HTTP_INFORMATION "Information"
#define D_HTTP_HTTP_SETTINGS "Paramètres HTTP"
#define D_HTTP_WIFI_SETTINGS "Paramètres Wifi"
#define D_HTTP_MQTT_SETTINGS "Paramètres MQTT"
#define D_HTTP_GPIO_SETTINGS "Paramètres GPIO"
#define D_HTTP_MDNS_SETTINGS "Paramètres mDNS"
#define D_HTTP_TELNET_SETTINGS "Paramètres Telnet"
#define D_HTTP_DEBUG_SETTINGS "Paramètres de débogage"
#define D_HTTP_GUI_SETTINGS "Paramètres d'affichage"
#define D_HTTP_SAVE_SETTINGS "Enregistrer les paramètres"
#define D_HTTP_UPLOAD_FILE "Télécharger le fichier"
#define D_HTTP_ERASE_DEVICE "Réinitialiser tous les paramètres"
#define D_HTTP_ADD_GPIO "Ajouter une nouvelle épingles"
#define D_HTTP_BACK "Retour"
#define D_HTTP_REFRESH "Actualiser"
#define D_HTTP_PREV_PAGE "Page précédente"
#define D_HTTP_NEXT_PAGE "Page suivante"
#define D_HTTP_CALIBRATE "Calibrer"
#define D_HTTP_SCREENSHOT "Capture d'écran"
#define D_HTTP_FILE_BROWSER "Éditeur de fichiers"
#define D_HTTP_FIRMWARE_UPGRADE "Mise à jour du micrologiciel"
#define D_HTTP_UPDATE_FIRMWARE "Mettre à jour le micrologiciel"
#define D_HTTP_FACTORY_RESET "Paramètres d'usine"
#define D_HTTP_MAIN_MENU "Menu principal"
#define D_HTTP_REBOOT "Redémarrer"
#define D_HTTP_CONFIGURATION "Configuration"
#define D_HTTP_SENDING_PAGE "La page %S a été envoyée à %s"
#define D_HTTP_FOOTER "par Francis Van Roie"
#define D_INFO_VERSION "Version"
#define D_INFO_BUILD_DATETIME "Date/heure de compilation"
#define D_INFO_UPTIME "Disponibilité"
#define D_INFO_FREE_HEAP "Tas libre"
#define D_INFO_FREE_BLOCK "Blocage libre"
#define D_INFO_DEVICE_MEMORY "Mémoire de l&#39;appareil"
#define D_INFO_LVGL_MEMORY "Mémoire LVGL"
#define D_INFO_TOTAL_MEMORY "Total"
#define D_INFO_FREE_MEMORY "Libre"
#define D_INFO_FRAGMENTATION "Fragmentation"
#define D_INFO_PSRAM_FREE "PSRam libre"
#define D_INFO_PSRAM_SIZE "Taille PSRam"
#define D_INFO_FLASH_SIZE "Taille du flash"
#define D_INFO_SKETCH_USED "Taille utilisée du programme"
#define D_INFO_SKETCH_FREE "Taille libre du programme"
#define D_INFO_MODULE "Module"
#define D_INFO_MODEL "Modèle"
#define D_INFO_FREQUENCY "Fréquence"
#define D_INFO_CORE_VERSION "Version principale"
#define D_INFO_RESET_REASON "Raison de la réinitialisation"
#define D_INFO_STATUS "Statut"
#define D_INFO_SERVER "Serveur"
#define D_INFO_USERNAME "Nom d&#39;utilisateur"
#define D_INFO_CLIENTID "ID client"
#define D_INFO_CONNECTED "Connecté"
#define D_INFO_DISCONNECTED "Déconnecté"
#define D_INFO_RECEIVED "Reçu"
#define D_INFO_PUBLISHED "Publié"
#define D_INFO_FAILED "Échec"
#define D_INFO_ETHERNET "Ethernet"
#define D_INFO_WIFI "Wifi"
#define D_INFO_LINK_SPEED "Vitesse de liaison"
#define D_INFO_FULL_DUPLEX "Duplex intégral"
#define D_INFO_SSID "SSID"
#define D_INFO_RSSI "Force du signal"
#define D_INFO_IP_ADDRESS "Adresse IP"
#define D_INFO_MAC_ADDRESS "Adresse MAC"
#define D_INFO_GATEWAY "Passerelle"
#define D_INFO_DNS_SERVER "Serveur DNS"
#define D_OOBE_MSG "Touchez l'écran pour configurer le WiFi ou branchez ce point d'accès:"
#define D_OOBE_SCAN_TO_CONNECT "Scanner pour se connecter"
#define D_WIFI_CONNECTING_TO "Connexion à %s"
#define D_WIFI_CONNECTED_TO "Connecté à %s, demande d'IP..."
#define D_WIFI_RSSI_EXCELLENT "Excellent"
#define D_WIFI_RSSI_GOOD "Bon"
#define D_WIFI_RSSI_FAIR "Juste"
#define D_WIFI_RSSI_WEAK "Faible"
#define D_WIFI_RSSI_BAD "Très mauvais"
#define D_GPIO_SWITCH "Interrupteur"
#define D_GPIO_BUTTON "Bouton"
#define D_GPIO_TOUCH "Touche Capacitive"
#define D_GPIO_LED "Led"
#define D_GPIO_LED_R "Humeur Rouge"
#define D_GPIO_LED_G "Humeur Vert"
#define D_GPIO_LED_B "Humeur Bleu"
#define D_GPIO_POWER_RELAY "Relais Electrique"
#define D_GPIO_LIGHT_RELAY "Relais de Lumière"
#define D_GPIO_PWM "PWM"
#define D_GPIO_DAC "DAC"
#define D_GPIO_SERIAL_DIMMER "Gradateur Série"
#define D_GPIO_UNKNOWN "Inconnu"
#define D_GPIO_PIN "Pin"
#define D_GPIO_GROUP "Groupe"
#define D_GPIO_GROUP_NONE "Aucun"
#define D_GPIO_STATE_NORMAL "Normal"
#define D_GPIO_STATE_INVERTED "Inverse"
#endif

View File

@ -4,6 +4,8 @@
#define D_USERNAME "Felhasználónév:"
#define D_PASSWORD "Jelszó:"
#define D_SSID "SSID:"
#define D_YES "Igen"
#define D_NO "Nem"
#define D_ERROR_OUT_OF_MEMORY "Elfogyott a memória"
#define D_ERROR_UNKNOWN "Ismeretlen hiba"
@ -15,10 +17,16 @@
#define D_FILE_LOADING "%s betöltése"
#define D_FILE_LOADED "%s betöltve"
#define D_FILE_LOAD_FAILED "%s betöltése nem sikerült"
#define D_FILE_NOT_FOUND "File not found" // new
#define D_FILE_SAVING "%s mentése"
#define D_FILE_SAVED "%s mentve"
#define D_FILE_SAVE_FAILED "%s mentése meghiúsult"
#define D_FILE_SIZE_BYTES "bytes" // new
#define D_FILE_SIZE_KILOBYTES "KiB" // new
#define D_FILE_SIZE_MEGABYTES "MiB" // new
#define D_FILE_SIZE_GIGABYTES "GiB" // new
#define D_FILE_SIZE_DIVIDER 1024 // new, kibi or kilo bytes
#define D_DECIMAL_POINT "," // new, decimal comma or point
#define D_SERVICE_STARTING "Indítás..."
#define D_SERVICE_STARTED "Elindítva"
@ -28,6 +36,9 @@
#define D_SERVICE_CONNECTED "Csatlakoztatva"
#define D_SERVICE_DISCONNECTED "Szétkapcsolva"
#define D_SETTING_ENABLED "Engedélyezve"
#define D_SETTING_DISABLED "Letiltva"
#define D_NETWORK_IP_ADDRESS_RECEIVED "Beállított IP-cím: %s"
#define D_NETWORK_ONLINE "online"
#define D_NETWORK_OFFLINE "offline"
@ -47,7 +58,7 @@
#define D_MQTT_SUBSCRIBED "Feliratkozva: %s"
#define D_MQTT_NOT_SUBSCRIBED "Nem sikerült feliratkozni: %s"
#define D_MQTT_HA_AUTO_DISCOVERY "Regisztrálás HA automatikus felfedezésre"
#define D_MQTT_PAYLOAD_TOO_LONG "$$$Payload too long (%d bytes)"
#define D_MQTT_PAYLOAD_TOO_LONG "Túl hosszú payload (%u bájt)"
#define D_TELNET_CLOSING_CONNECTION "Munkamenet befejezése %s-el"
#define D_TELNET_CLIENT_LOGIN_FROM "Kliens bejelentkezés innen: %s"
@ -58,7 +69,6 @@
#define D_TELNET_STARTED "Telnet konzol elindítva"
#define D_TELNET_FAILED "Telnet konzol elindítása meghiúsult"
#define D_TELNET_CLIENT_CONNECTED "Kliens csatlakozva"
#define D_TELNET_CLIENT_NOT_CONNECTED "Kliens NEM csatlakozik"
#define D_TELNET_CLIENT_REJECTED "Kliens elutasítva"
#define D_HASP_INVALID_PAGE "Érvénytelen oldal: %u"
@ -77,6 +87,8 @@
#define D_ATTRIBUTE_UNKNOWN "Ismeretlen tulajdonság: %s"
#define D_ATTRIBUTE_READ_ONLY "%s csak olvasható"
#define D_ATTRIBUTE_PAGE_METHOD_INVALID "Nem lehet meghívni %s-t egy oldalon"
#define D_ATTRIBUTE_ALIGN_INVALID "Invalid align property: %s" // new
#define D_ATTRIBUTE_COLOR_INVALID "Invalid color property: %s" // new
#define D_OOBE_SSID_VALIDATED "%s SSID érvényes"
#define D_OOBE_AUTO_CALIBRATE "Automatikus kalibrálás engedélyezve"
@ -87,7 +99,7 @@
#define D_DISPATCH_REBOOT "Az MCU most újraindul!"
#define D_JSON_FAILED "JSON elemzése nem sikerült:"
#define D_JSONL_FAILED "JSONL elemzése meghiúsult a %d vonalnál"
#define D_JSONL_FAILED "JSONL elemzése meghiúsult a %u vonalnál"
#define D_JSONL_SUCCEEDED "JSONL teljes körűen elemezve"
#define D_OTA_CHECK_UPDATE "A frissítések ellenőrzése az URL-en: %s"
@ -97,6 +109,8 @@
#define D_OTA_UPDATE_COMPLETE "Az OTA frissítés elkészült"
#define D_OTA_UPDATE_APPLY "Firmware alkalmazása és újraindítás"
#define D_OTA_UPDATE_FAILED "Az OTA frissítés meghiúsult"
#define D_OTA_UPDATING_FIRMWARE "Firmware frissítés..."
#define D_OTA_UPDATING_FILESYSTEM "Fájlrendszer frissítés..."
#define D_HTTP_HASP_DESIGN "Képernyő dizájn"
#define D_HTTP_INFORMATION "Információk"
@ -118,18 +132,85 @@
#define D_HTTP_NEXT_PAGE "Következő oldal"
#define D_HTTP_CALIBRATE "Kalibrálás"
#define D_HTTP_SCREENSHOT "Képernyőkép"
#define D_HTTP_FILE_BROWSER "Fájl böngésző"
#define D_HTTP_FILE_BROWSER "Fájlkezelő"
#define D_HTTP_FIRMWARE_UPGRADE "Firmware frissítés"
#define D_HTTP_UPDATE_FIRMWARE "Firmware frissítése"
#define D_HTTP_FACTORY_RESET "Gyári beállítások visszaállítása"
#define D_HTTP_MAIN_MENU "Főmenü"
#define D_HTTP_REBOOT "Újraindítás"
#define D_HTTP_CONFIGURATION "Beállítások"
#define D_HTTP_SENDING_PAGE "%S oldal küldése %s-re"
#define D_HTTP_FOOTER "készítette: Francis Van Roie"
#define D_INFO_VERSION "Verziószám"
#define D_INFO_BUILD_DATETIME "Build időpontja"
#define D_INFO_UPTIME "Uptime"
#define D_INFO_FREE_HEAP "Szabad Heap"
#define D_INFO_FREE_BLOCK "Szabad Blokk"
#define D_INFO_DEVICE_MEMORY "Eszköz Memória"
#define D_INFO_LVGL_MEMORY "LVGL Memória"
#define D_INFO_TOTAL_MEMORY "Összesen"
#define D_INFO_FREE_MEMORY "Szabad"
#define D_INFO_FRAGMENTATION "Fragmentáció"
#define D_INFO_PSRAM_FREE "PSRam szabad"
#define D_INFO_PSRAM_SIZE "PSRam méret"
#define D_INFO_FLASH_SIZE "Flash méret"
#define D_INFO_SKETCH_USED "Program használatban"
#define D_INFO_SKETCH_FREE "Program szabad"
#define D_INFO_MODULE "Modul"
#define D_INFO_MODEL "Modell"
#define D_INFO_FREQUENCY "Frekvencia"
#define D_INFO_CORE_VERSION "Core Verzió"
#define D_INFO_RESET_REASON "Újraindulás oka"
#define D_INFO_STATUS "Státusz"
#define D_INFO_SERVER "Szerver"
#define D_INFO_USERNAME "Felhasználónév"
#define D_INFO_CLIENTID "Kliens ID"
#define D_INFO_CONNECTED "Csatlakoztatva"
#define D_INFO_DISCONNECTED "Szétkapcsolva"
#define D_INFO_RECEIVED "Fogadott"
#define D_INFO_PUBLISHED "Küldött"
#define D_INFO_FAILED "Sikertelen"
#define D_INFO_ETHERNET "Ethernet"
#define D_INFO_WIFI "WiFi"
#define D_INFO_LINK_SPEED "Linksebesség"
#define D_INFO_FULL_DUPLEX "Full Duplex" // new
#define D_INFO_SSID "SSID"
#define D_INFO_RSSI "Jelerősség"
#define D_INFO_IP_ADDRESS "IP cím"
#define D_INFO_MAC_ADDRESS "MAC cím"
#define D_INFO_GATEWAY "Átjáró"
#define D_INFO_DNS_SERVER "DNS szerver"
#define D_OOBE_MSG "Koppintson a képernyőre a WiFi beállításához, vagy csatlakozzon az alábbi Access Point-hoz:"
#define D_OOBE_SCAN_TO_CONNECT "Szkennelje le a csatlakozáshoz:"
#define D_WIFI_CONNECTING_TO "$$$Connecting to %s"
#define D_WIFI_CONNECTED_TO "$$$Connected to %s, requesting IP..."
#define D_WIFI_CONNECTING_TO "Csatlakozás %s-hez"
#define D_WIFI_CONNECTED_TO "Csatlakozva %s-hez, IP cím kérése..."
#define D_WIFI_RSSI_EXCELLENT "Kiváló"
#define D_WIFI_RSSI_GOOD "Jó"
#define D_WIFI_RSSI_FAIR "Elfogadható"
#define D_WIFI_RSSI_WEAK "Gyenge"
#define D_WIFI_RSSI_BAD "Rossz"
// new
#define D_GPIO_SWITCH "Switch"
#define D_GPIO_BUTTON "Button"
#define D_GPIO_TOUCH "Capacitive Touch" // new
#define D_GPIO_LED "Led"
#define D_GPIO_LED_R "Mood Red"
#define D_GPIO_LED_G "Mood Green"
#define D_GPIO_LED_B "Mood Blue"
#define D_GPIO_POWER_RELAY "Power Relay" // new
#define D_GPIO_LIGHT_RELAY "Light Relay" // new
#define D_GPIO_PWM "PWM"
#define D_GPIO_DAC "DAC"
#define D_GPIO_SERIAL_DIMMER "Serial Dimmer"
#define D_GPIO_UNKNOWN "Unknown"
#define D_GPIO_PIN "Pin"
#define D_GPIO_GROUP "Group"
#define D_GPIO_GROUP_NONE "None"
#define D_GPIO_STATE_NORMAL "Normal" // new
#define D_GPIO_STATE_INVERTED "Inverted" // new
#endif

View File

@ -2,17 +2,21 @@
#define HASP_LANG_H
#ifndef HASP_LANGUAGE
#include "en_US.h"
#include "en_US.h"
#else
#define QUOTEME(x) QUOTEME_1(x)
#define QUOTEME_1(x) #x
#define INCLUDE_FILE(x) QUOTEME(x.h)
#include INCLUDE_FILE(HASP_LANGUAGE)
#define QUOTEME(x) QUOTEME_1(x)
#define QUOTEME_1(x) #x
#define INCLUDE_FILE(x) QUOTEME(x.h)
#include INCLUDE_FILE(HASP_LANGUAGE)
#endif
// language independent defines
#define D_PASSWORD_MASK "********"
#define D_BULLET " * "
#define D_MANUFACTURER "openHASP"
#define D_BACK_ICON "&#8617; "
#define D_TIMESTAMP "%H:%M:%S" // Used when reference time is set from NTP
#define D_TIME_MILLIS "%8d" // Used when no reference clock could be set
#endif

View File

@ -1,9 +1,11 @@
#ifndef HASP_LANG_EN_US_H
#define HASP_LANG_EN_US_H
#ifndef HASP_LANG_NL_NL_H
#define HASP_LANG_NL_NL_H
#define D_USERNAME "Gebruikersnaam:"
#define D_PASSWORD "Wachtwoord:"
#define D_SSID "Ssid:"
#define D_YES "Ja"
#define D_NO "Nee"
#define D_ERROR_OUT_OF_MEMORY "Geen geheugen bechikbaar"
#define D_ERROR_UNKNOWN "Onbekende fout"
@ -15,10 +17,19 @@
#define D_FILE_LOADING "%s laden..."
#define D_FILE_LOADED "%s geladen"
#define D_FILE_LOAD_FAILED "%s laden mislukt"
#define D_FILE_SAVING "%s bewaren..."
#define D_FILE_SAVED "%s bewaard"
#define D_FILE_SAVE_FAILED "%s bewaren mislukt"
#define D_FILE_NOT_FOUND "Bestand niet gevonden"
#define D_FILE_SIZE_BYTES "bytes"
#define D_FILE_SIZE_KILOBYTES "KiB"
#define D_FILE_SIZE_MEGABYTES "MiB"
#define D_FILE_SIZE_GIGABYTES "GiB"
#define D_FILE_SIZE_DIVIDER 1024 // kibi or kilo bytes
#define D_DECIMAL_POINT "," // decimal comma or point
#define D_SETTING_ENABLED "Ingeschakeld"
#define D_SETTING_DISABLED "Uitgeschakeld"
#define D_SERVICE_STARTING "Starten..."
#define D_SERVICE_STARTED "Gestart"
@ -47,17 +58,17 @@
#define D_MQTT_SUBSCRIBED "Ingeschreven op %s"
#define D_MQTT_NOT_SUBSCRIBED "Inschrijving op %s mislukt"
#define D_MQTT_HA_AUTO_DISCOVERY "Registeren HA auto-configuratie"
#define D_MQTT_PAYLOAD_TOO_LONG "Payload is te lang (%d bytes)"
#define D_MQTT_PAYLOAD_TOO_LONG "Payload is te lang (%u bytes)"
#define D_TELNET_CLOSING_CONNECTION "Sessie sluiten van %s"
#define D_TELNET_CLIENT_LOGIN_FROM "Client aangemeld van %s"
#define D_TELNET_CLIENT_CONNECT_FROM "Client verbonden van %s"
#define D_TELNET_CLIENT_NOT_CONNECTED "Client NIET verbonden"
#define D_TELNET_AUTHENTICATION_FAILED "Autorisatie mislukt!"
#define D_TELNET_INCORRECT_LOGIN_ATTEMPT "Aanmelding van %s mislukt"
#define D_TELNET_STARTED "Telnet console gestart"
#define D_TELNET_FAILED "Telnet console starten is mislukt"
#define D_TELNET_CLIENT_CONNECTED "Client verbonden"
#define D_TELNET_CLIENT_NOT_CONNECTED "Client NIET verbonden"
#define D_TELNET_CLIENT_REJECTED "Client geweigerd"
#define D_HASP_INVALID_PAGE "Ongeldige pagina %u"
@ -69,13 +80,15 @@
#define D_OBJECT_UNKNOWN "Onbekend object"
#define D_OBJECT_MISMATCH "Objecten komen niet overeen!"
#define D_OBJECT_LOST "Object kwijt!"
#define D_OBJECT_CREATE_FAILED "Object %u mislukt"
#define D_OBJECT_CREATE_FAILED "Object id %u aanmaken mislukt"
#define D_OBJECT_PAGE_UNKNOWN "Paginga %u niet gedefinieerd"
#define D_OBJECT_EVENT_UNKNOWN "Onbekend Event %d"
#define D_ATTRIBUTE_UNKNOWN "Onbekend attribuut %s"
#define D_ATTRIBUTE_READ_ONLY "%s is alleen-lezen"
#define D_ATTRIBUTE_PAGE_METHOD_INVALID "%s is ongeldig voor een pagina"
#define D_ATTRIBUTE_ALIGN_INVALID "Ongeldig align attribuut: %s" // new
#define D_ATTRIBUTE_COLOR_INVALID "Ongeldige kleur: %s" // new
#define D_OOBE_SSID_VALIDATED "SSID %s gevalideerd"
#define D_OOBE_AUTO_CALIBRATE "Auto calibratie actief"
@ -86,7 +99,7 @@
#define D_DISPATCH_REBOOT "De MCU wordt herstart!"
#define D_JSON_FAILED "JSON verwerking mislukt:"
#define D_JSONL_FAILED "JSONL verwerking mislukt op lijn %d"
#define D_JSONL_FAILED "JSONL verwerking mislukt op lijn %u"
#define D_JSONL_SUCCEEDED "Jsonl volledig verwerkt"
#define D_OTA_CHECK_UPDATE "Controle update URL: %s"
@ -96,6 +109,8 @@
#define D_OTA_UPDATE_COMPLETE "OTA Firmware bijgewerkt"
#define D_OTA_UPDATE_APPLY "Firmware Schrijven & Herstart"
#define D_OTA_UPDATE_FAILED "OTA Update mislukt"
#define D_OTA_UPDATING_FIRMWARE "Firmware bijwerken..."
#define D_OTA_UPDATING_FILESYSTEM "Bestandsysteem bijwerken..."
#define D_HTTP_HASP_DESIGN "HASP Ontwerp"
#define D_HTTP_INFORMATION "Informatie"
@ -117,18 +132,84 @@
#define D_HTTP_NEXT_PAGE "Volgende Pagina"
#define D_HTTP_CALIBRATE "Calibratie"
#define D_HTTP_SCREENSHOT "Schermafbeelding"
#define D_HTTP_FILE_BROWSER "Bestandsverkenner"
#define D_HTTP_FILE_BROWSER "Bestandseditor"
#define D_HTTP_FIRMWARE_UPGRADE "Firmware Upgrade"
#define D_HTTP_UPDATE_FIRMWARE "Firmware Bijwerken"
#define D_HTTP_FACTORY_RESET "Fabrieksinstellingen"
#define D_HTTP_MAIN_MENU "Hoofdmenu"
#define D_HTTP_REBOOT "Herstarten"
#define D_HTTP_CONFIGURATION "Configuratie"
#define D_HTTP_SENDING_PAGE "Pagina %S verstuurd naar %s" // New
#define D_HTTP_FOOTER "door Francis Van Roie"
#define D_INFO_VERSION "Versie"
#define D_INFO_BUILD_DATETIME "Gecompileerd"
#define D_INFO_UPTIME "Opgestart"
#define D_INFO_FREE_HEAP "Vrije Heap"
#define D_INFO_FREE_BLOCK "Vrije Blok"
#define D_INFO_DEVICE_MEMORY "Algemeen Geheugen"
#define D_INFO_LVGL_MEMORY "LVGL Geheugen"
#define D_INFO_TOTAL_MEMORY "Totaal"
#define D_INFO_FREE_MEMORY "Vrij"
#define D_INFO_FRAGMENTATION "Fragmentatie"
#define D_INFO_PSRAM_FREE "PSRam Vrij"
#define D_INFO_PSRAM_SIZE "PSRam Grootte"
#define D_INFO_FLASH_SIZE "Flash Grootte"
#define D_INFO_SKETCH_USED "Programma Grootte"
#define D_INFO_SKETCH_FREE "Programma Vrij"
#define D_INFO_MODULE "Module"
#define D_INFO_MODEL "Model"
#define D_INFO_FREQUENCY "Frequentie"
#define D_INFO_CORE_VERSION "ESP-IDF Versie"
#define D_INFO_RESET_REASON "Reden Herstart"
#define D_INFO_STATUS "Status"
#define D_INFO_SERVER "Server"
#define D_INFO_USERNAME "Gerbuiker"
#define D_INFO_CLIENTID "Client ID"
#define D_INFO_CONNECTED "Verbonden"
#define D_INFO_DISCONNECTED "Verbroken"
#define D_INFO_RECEIVED "Ontvangen"
#define D_INFO_PUBLISHED "Gepubliceerd"
#define D_INFO_FAILED "Mislukt"
#define D_INFO_ETHERNET "Ethernet"
#define D_INFO_WIFI "Wifi"
#define D_INFO_LINK_SPEED "Snelheid"
#define D_INFO_FULL_DUPLEX "Full Duplex"
#define D_INFO_SSID "SSID"
#define D_INFO_RSSI "Signaalsterkte"
#define D_INFO_IP_ADDRESS "IP Adres"
#define D_INFO_MAC_ADDRESS "Fysiek adres (MAC)"
#define D_INFO_GATEWAY "Gateway"
#define D_INFO_DNS_SERVER "DNS Server"
#define D_OOBE_MSG "Raak het scherm aan om WiFi in te stellen of meld je aan op AP:"
#define D_OOBE_SCAN_TO_CONNECT "Scan code"
#define D_WIFI_CONNECTING_TO "Verbinden met %s"
#define D_WIFI_CONNECTED_TO "Verbonden met %s, IP aanvragen..."
#define D_WIFI_RSSI_EXCELLENT "Uitstekend"
#define D_WIFI_RSSI_GOOD "Goed"
#define D_WIFI_RSSI_FAIR "Redelijk"
#define D_WIFI_RSSI_WEAK "Zwak"
#define D_WIFI_RSSI_BAD "Zeer Slecht"
#define D_GPIO_SWITCH "Schakelaar"
#define D_GPIO_BUTTON "Drukknop"
#define D_GPIO_TOUCH "Aanraakknop"
#define D_GPIO_LED "Led"
#define D_GPIO_LED_R "Sfeer Rood"
#define D_GPIO_LED_G "Sfeer Groen"
#define D_GPIO_LED_B "Sfeer Blauw"
#define D_GPIO_POWER_RELAY "Stroomrelais"
#define D_GPIO_LIGHT_RELAY "Licht Relais"
#define D_GPIO_PWM "PWM"
#define D_GPIO_DAC "DAC"
#define D_GPIO_SERIAL_DIMMER "Seriële Dimmer"
#define D_GPIO_UNKNOWN "Onbekend"
#define D_GPIO_PIN "Pin"
#define D_GPIO_GROUP "Groep"
#define D_GPIO_GROUP_NONE "Geen"
#define D_GPIO_STATE_NORMAL "Normaal"
#define D_GPIO_STATE_INVERTED "Geïnverteerd"
#endif

16
src/lang/pt_BR.h Normal file
View File

@ -0,0 +1,16 @@
#ifndef HASP_LANG_PT_BR_H
#define HASP_LANG_PT_BR_H
#include "pt_PT.h" // Common language file
// Overrides
#undef D_USERNAME
#define D_USERNAME "Usuário:"
#undef D_PASSWORD
#define D_PASSWORD "Senha:"
#undef D_NETWORK_CONNECTION_FAILED
#define D_NETWORK_CONNECTION_FAILED "Falhou a conexão"
#endif

View File

@ -1,205 +1,216 @@
#ifndef HASP_LANG_PT_PT_H
#define HASP_LANG_PT_PT_H
#define D_USERNAME "Utilizador:"
#define D_PASSWORD "Palavra-passe:"
#define D_SSID "SSID:"
#define D_YES "Sim" // new
#define D_NO "Não" // new
#define D_ERROR_OUT_OF_MEMORY "Memória Cheia"
#define D_ERROR_UNKNOWN "Erro desconhecido"
#define D_CONFIG_NOT_CHANGED "Sem alterações na configuração"
#define D_CONFIG_CHANGED "Configuração alterada"
#define D_CONFIG_LOADED "Configuração carregada"
#define D_FILE_LOADING "A carregar %s"
#define D_FILE_LOADED "%s carregado"
#define D_FILE_LOAD_FAILED "Não foi possível carregar %s"
#define D_FILE_SAVING "A guardar %s"
#define D_FILE_SAVED "%s guardado"
#define D_FILE_SAVE_FAILED "Não foi possível guardar %s"
#define D_FILE_NOT_FOUND "Ficheiro não encontrado" // new
#define D_SERVICE_STARTING "A inicializar..."
#define D_SERVICE_STARTED "Iniciado"
#define D_SERVICE_START_FAILED "Não foi possível iniciar"
#define D_SERVICE_STOPPED "Parado"
#define D_SERVICE_DISABLED "Desativado"
#define D_SERVICE_CONNECTED "Ligado"
#define D_SERVICE_DISCONNECTED "Desligado"
#define D_SETTING_ENABLED "Ativado" // New
#define D_SETTING_DISABLED "Desativado" // New
#define D_NETWORK_IP_ADDRESS_RECEIVED "Foi atribuído endereço IP: %s"
#define D_NETWORK_ONLINE "Online"
#define D_NETWORK_OFFLINE "Offline"
#define D_NETWORK_CONNECTION_FAILED "Falhou a ligação"
#define D_MQTT_DEFAULT_NAME "placa_%s"
#define D_MQTT_CONNECTING "A ligar..."
#define D_MQTT_CONNECTED "Ligado ao broker %s com clientID %s"
#define D_MQTT_NOT_CONNECTED "Não há ligação ???"
#define D_MQTT_DISCONNECTING "A desligar..."
#define D_MQTT_DISCONNECTED "Desligado"
#define D_MQTT_RECONNECTING "Desligado do broker, a religar..."
#define D_MQTT_NOT_CONFIGURED "O Broker não foi configurado"
#define D_MQTT_STARTED "A iniciar: %d bytes"
#define D_MQTT_FAILED "Falhou:"
#define D_MQTT_INVALID_TOPIC "A mensagem tem um tópico inválido"
#define D_MQTT_SUBSCRIBED "Subscrito a %s"
#define D_MQTT_NOT_SUBSCRIBED "Não foi possível subscrever %s"
#define D_MQTT_HA_AUTO_DISCOVERY "A registar auto-descoberta no HA"
#define D_MQTT_PAYLOAD_TOO_LONG "Os dados são demasiado grandes(%u bytes)"
#define D_TELNET_CLOSING_CONNECTION "A fechar a ligação de %s"
#define D_TELNET_CLIENT_LOGIN_FROM "Foi feito login ao cliente %s"
#define D_TELNET_CLIENT_CONNECT_FROM "Foi conectado ao cliente %s"
#define D_TELNET_AUTHENTICATION_FAILED "Falhou a autorização!"
#define D_TELNET_INCORRECT_LOGIN_ATTEMPT "Tentativa de ligação incorreta desde %s"
#define D_TELNET_STARTED "Consola inicializada"
#define D_TELNET_FAILED "Falhou inicialização da consola"
#define D_TELNET_CLIENT_CONNECTED "Cliente ligado"
#define D_TELNET_CLIENT_NOT_CONNECTED "Cliente não ligado"
#define D_TELNET_CLIENT_REJECTED "Cliente rejeitado"
#define D_HASP_INVALID_PAGE "Página inválida %u"
#define D_HASP_INVALID_LAYER "Não foi possível eliminar a camada de sistema"
#define D_HASP_CHANGE_PAGE "A alterar a página %u"
#define D_HASP_CLEAR_PAGE "A limpar página %u"
#define D_OBJECT_DELETED "Objeto eliminado"
#define D_OBJECT_UNKNOWN "Objeto desconhecido"
#define D_OBJECT_MISMATCH "Os objetos não são iguais!"
#define D_OBJECT_LOST "Objeto perdido!"
#define D_OBJECT_CREATE_FAILED "Não foi possível criar o objeto %u"
#define D_OBJECT_PAGE_UNKNOWN "A página ID %u não está definida"
#define D_OBJECT_EVENT_UNKNOWN "Não se conhece o evento %d "
#define D_ATTRIBUTE_UNKNOWN "Propriedade %s desconhecida"
#define D_ATTRIBUTE_READ_ONLY "%s é de leitura apenas"
#define D_ATTRIBUTE_PAGE_METHOD_INVALID "Não foi possível chamar %s numa página"
#define D_OOBE_SSID_VALIDATED "SSID %s válido"
#define D_OOBE_AUTO_CALIBRATE "Auto calibração ativada"
#define D_OOBE_CALIBRATED "já foi calibrado"
#define D_DISPATCH_COMMAND_NOT_FOUND "Não se encontrou o comando '%s'"
#define D_DISPATCH_INVALID_PAGE "Página inválida %s"
#define D_DISPATCH_REBOOT "A reiniciar dispositivo!"
#define D_JSON_FAILED "Não foi possível analisar o JSON:"
#define D_JSONL_FAILED "A análise do JSONL falhou na linha %u"
#define D_JSONL_SUCCEEDED "JSONL analisado"
#define D_OTA_CHECK_UPDATE "A procurar por atualização no URL: %s"
#define D_OTA_CHECK_COMPLETE "Verificação da atualização completa"
#define D_OTA_CHECK_FAILED "Falhou a verificação da atualização: %s"
#define D_OTA_UPDATE_FIRMWARE "Atualização de firmware OTA"
#define D_OTA_UPDATE_COMPLETE "Atualização OTA completa"
#define D_OTA_UPDATE_APPLY "A aplicar o novo firmware e reiniciar"
#define D_OTA_UPDATE_FAILED "A atualização OTA falhou"
#define D_OTA_UPDATING_FIRMWARE "A atualizar o firmware..."
#define D_OTA_UPDATING_FILESYSTEM "A atualizar o sistema de ficheiros..."
#define D_HTTP_HASP_DESIGN "Design do HASP"
#define D_HTTP_INFORMATION "Informação"
#define D_HTTP_HTTP_SETTINGS "Configurar HTTP"
#define D_HTTP_WIFI_SETTINGS "Configurar Wifi"
#define D_HTTP_MQTT_SETTINGS "Configurar MQTT"
#define D_HTTP_GPIO_SETTINGS "Configurar GPIO"
#define D_HTTP_MDNS_SETTINGS "Configurar mDNS"
#define D_HTTP_TELNET_SETTINGS "Configurar Telnet"
#define D_HTTP_DEBUG_SETTINGS "Configurar debug"
#define D_HTTP_GUI_SETTINGS "Configurar GUI"
#define D_HTTP_SAVE_SETTINGS "Guardar Configuração"
#define D_HTTP_UPLOAD_FILE "Carregar ficheiro"
#define D_HTTP_ERASE_DEVICE "Eliminar Configuração"
#define D_HTTP_ADD_GPIO "Adicionar novo pino"
#define D_HTTP_BACK "Retroceder"
#define D_HTTP_REFRESH "Atualizar"
#define D_HTTP_PREV_PAGE "Página Anterior"
#define D_HTTP_NEXT_PAGE "Página Seguinte"
#define D_HTTP_CALIBRATE "Calibrar"
#define D_HTTP_SCREENSHOT "Screenshot"
#define D_HTTP_FILE_BROWSER "Editor de ficheiros"
#define D_HTTP_FIRMWARE_UPGRADE "Atualização do firmware"
#define D_HTTP_UPDATE_FIRMWARE "Atualizar o firmware"
#define D_HTTP_FACTORY_RESET "Repor configuração de fábrica"
#define D_HTTP_MAIN_MENU "Menu Principal"
#define D_HTTP_REBOOT "Reiniciar"
#define D_HTTP_CONFIGURATION "Configuração"
#define D_HTTP_SENDING_PAGE "Foi enviado página %S a %s" // New
#define D_HTTP_FOOTER "por Francis Van Roie"
#define D_INFO_VERSION "Versão"
#define D_INFO_BUILD_DATETIME "Compilado a"
#define D_INFO_UPTIME "Tempo ativo"
#define D_INFO_FREE_HEAP "Heap livre"
#define D_INFO_FREE_BLOCK "Blocos livres"
#define D_INFO_DEVICE_MEMORY "Memória do dispositivo"
#define D_INFO_LVGL_MEMORY "Memoria LVGL"
#define D_INFO_TOTAL_MEMORY "Total"
#define D_INFO_FREE_MEMORY "Livre"
#define D_INFO_FRAGMENTATION "Fragmentação"
#define D_INFO_PSRAM_FREE "PSRam livre"
#define D_INFO_PSRAM_SIZE "Tamanho PSRam "
#define D_INFO_FLASH_SIZE "Tamanho Flash"
#define D_INFO_SKETCH_USED "Memória programa usada"
#define D_INFO_SKETCH_FREE "Memória programa livre"
#define D_INFO_MODULE "Módulo"
#define D_INFO_MODEL "Modelo"
#define D_INFO_FREQUENCY "Frequência"
#define D_INFO_CORE_VERSION "Versão do core"
#define D_INFO_RESET_REASON "Razão do último Reset"
#define D_INFO_STATUS "Estado"
#define D_INFO_SERVER "Servidor"
#define D_INFO_USERNAME "Nome do utilizador"
#define D_INFO_CLIENTID "ID do Cliente"
#define D_INFO_CONNECTED "Ligado"
#define D_INFO_DISCONNECTED "Desligado"
#define D_INFO_RECEIVED "Recebido"
#define D_INFO_PUBLISHED "Publicado"
#define D_INFO_FAILED "Em falha"
#define D_INFO_ETHERNET "Ethernet"
#define D_INFO_WIFI "Wifi"
#define D_INFO_LINK_SPEED "Link Speed"
#define D_INFO_FULL_DUPLEX "Full Duplex"
#define D_INFO_SSID "SSID"
#define D_INFO_RSSI "Potência do sinal"
#define D_INFO_IP_ADDRESS "Endereço IP"
#define D_INFO_MAC_ADDRESS "Endereço MAC"
#define D_INFO_GATEWAY "Gateway"
#define D_INFO_DNS_SERVER "Servidor DNS"
#define D_OOBE_MSG "Toque no ecrã para configurar WiFi ou para se ligar a um access point"
#define D_OOBE_SCAN_TO_CONNECT "Procurar rede"
#define D_WIFI_CONNECTING_TO "A ligar a %s"
#define D_WIFI_CONNECTED_TO "Ligado a %s, a pedir IP..."
#define D_WIFI_RSSI_EXCELLENT "Excelente"
#define D_WIFI_RSSI_GOOD "Bom"
#define D_WIFI_RSSI_FAIR "Decente"
#define D_WIFI_RSSI_WEAK "Fraco"
#define D_WIFI_RSSI_BAD "Muito baixo"
// new
#define D_GPIO_SWITCH "Interruptor"
#define D_GPIO_BUTTON "Botão"
#define D_GPIO_LED "LED"
#define D_GPIO_LED_R "LED Red"
#define D_GPIO_LED_G "LED Green"
#define D_GPIO_LED_B "LED Blue"
#define D_GPIO_RELAY "Relé"
#define D_GPIO_PWM "PWM"
#define D_GPIO_DAC "DAC"
#define D_GPIO_SERIAL_DIMMER "Dimmer serial"
#define D_GPIO_UNKNOWN "Desconhecido"
#define D_GPIO_PIN "Pin"
#define D_GPIO_GROUP "Grupo"
#define D_GPIO_GROUP_NONE "Nenhum"
#endif
#ifndef HASP_LANG_PT_PT_H
#define HASP_LANG_PT_PT_H
#define D_USERNAME "Utilizador:"
#define D_PASSWORD "Palavra-passe:"
#define D_SSID "SSID:"
#define D_YES "Sim"
#define D_NO "Não"
#define D_ERROR_OUT_OF_MEMORY "Memória Cheia"
#define D_ERROR_UNKNOWN "Erro desconhecido"
#define D_CONFIG_NOT_CHANGED "Sem alterações na configuração"
#define D_CONFIG_CHANGED "Configuração alterada"
#define D_CONFIG_LOADED "Configuração carregada"
#define D_FILE_LOADING "A carregar %s"
#define D_FILE_LOADED "%s carregado"
#define D_FILE_LOAD_FAILED "Não foi possível carregar %s"
#define D_FILE_SAVING "A guardar %s"
#define D_FILE_SAVED "%s guardado"
#define D_FILE_SAVE_FAILED "Não foi possível guardar %s"
#define D_FILE_NOT_FOUND "Ficheiro não encontrado"
#define D_FILE_SIZE_BYTES "bytes" // new
#define D_FILE_SIZE_KILOBYTES "KiB" // new
#define D_FILE_SIZE_MEGABYTES "MiB" // new
#define D_FILE_SIZE_GIGABYTES "GiB" // new
#define D_FILE_SIZE_DIVIDER 1024 // new, kibi or kilo bytes
#define D_DECIMAL_POINT "." // new, decimal comma or point
#define D_SERVICE_STARTING "A inicializar..."
#define D_SERVICE_STARTED "Iniciado"
#define D_SERVICE_START_FAILED "Não foi possível iniciar"
#define D_SERVICE_STOPPED "Parado"
#define D_SERVICE_DISABLED "Desativado"
#define D_SERVICE_CONNECTED "Ligado"
#define D_SERVICE_DISCONNECTED "Desligado"
#define D_SETTING_ENABLED "Ativado"
#define D_SETTING_DISABLED "Desativado"
#define D_NETWORK_IP_ADDRESS_RECEIVED "Foi atribuído endereço IP: %s"
#define D_NETWORK_ONLINE "Online"
#define D_NETWORK_OFFLINE "Offline"
#define D_NETWORK_CONNECTION_FAILED "Falhou a ligação"
#define D_MQTT_DEFAULT_NAME "placa_%s"
#define D_MQTT_CONNECTING "A ligar..."
#define D_MQTT_CONNECTED "Ligado ao broker %s com clientID %s"
#define D_MQTT_NOT_CONNECTED "Não há ligação ???"
#define D_MQTT_DISCONNECTING "A desligar..."
#define D_MQTT_DISCONNECTED "Desligado"
#define D_MQTT_RECONNECTING "Desligado do broker, a religar..."
#define D_MQTT_NOT_CONFIGURED "O Broker não foi configurado"
#define D_MQTT_STARTED "A iniciar: %d bytes"
#define D_MQTT_FAILED "Falhou:"
#define D_MQTT_INVALID_TOPIC "A mensagem tem um tópico inválido"
#define D_MQTT_SUBSCRIBED "Subscrito a %s"
#define D_MQTT_NOT_SUBSCRIBED "Não foi possível subscrever %s"
#define D_MQTT_HA_AUTO_DISCOVERY "A registar auto-descoberta no HA"
#define D_MQTT_PAYLOAD_TOO_LONG "Os dados são demasiado grandes(%u bytes)"
#define D_TELNET_CLOSING_CONNECTION "A fechar a ligação de %s"
#define D_TELNET_CLIENT_LOGIN_FROM "Foi feito login ao cliente %s"
#define D_TELNET_CLIENT_CONNECT_FROM "Foi conectado ao cliente %s"
#define D_TELNET_AUTHENTICATION_FAILED "Falhou a autorização!"
#define D_TELNET_INCORRECT_LOGIN_ATTEMPT "Tentativa de ligação incorreta desde %s"
#define D_TELNET_STARTED "Consola inicializada"
#define D_TELNET_FAILED "Falhou inicialização da consola"
#define D_TELNET_CLIENT_CONNECTED "Cliente ligado"
#define D_TELNET_CLIENT_NOT_CONNECTED "Cliente não ligado"
#define D_TELNET_CLIENT_REJECTED "Cliente rejeitado"
#define D_HASP_INVALID_PAGE "Página inválida %u"
#define D_HASP_INVALID_LAYER "Não foi possível eliminar a camada de sistema"
#define D_HASP_CHANGE_PAGE "A alterar a página %u"
#define D_HASP_CLEAR_PAGE "A limpar página %u"
#define D_OBJECT_DELETED "Objeto eliminado"
#define D_OBJECT_UNKNOWN "Objeto desconhecido"
#define D_OBJECT_MISMATCH "Os objetos não são iguais!"
#define D_OBJECT_LOST "Objeto perdido!"
#define D_OBJECT_CREATE_FAILED "Não foi possível criar o objeto %u"
#define D_OBJECT_PAGE_UNKNOWN "A página ID %u não está definida"
#define D_OBJECT_EVENT_UNKNOWN "Não se conhece o evento %d "
#define D_ATTRIBUTE_UNKNOWN "Propriedade %s desconhecida"
#define D_ATTRIBUTE_READ_ONLY "%s é de leitura apenas"
#define D_ATTRIBUTE_PAGE_METHOD_INVALID "Não foi possível chamar %s numa página"
#define D_ATTRIBUTE_ALIGN_INVALID "Invalid align property: %s" // new
#define D_ATTRIBUTE_COLOR_INVALID "Invalid color property: %s" // new
#define D_OOBE_SSID_VALIDATED "SSID %s válido"
#define D_OOBE_AUTO_CALIBRATE "Auto calibração ativada"
#define D_OOBE_CALIBRATED "já foi calibrado"
#define D_DISPATCH_COMMAND_NOT_FOUND "Não se encontrou o comando '%s'"
#define D_DISPATCH_INVALID_PAGE "Página inválida %s"
#define D_DISPATCH_REBOOT "A reiniciar dispositivo!"
#define D_JSON_FAILED "Não foi possível analisar o JSON:"
#define D_JSONL_FAILED "A análise do JSONL falhou na linha %u"
#define D_JSONL_SUCCEEDED "JSONL analisado"
#define D_OTA_CHECK_UPDATE "A procurar por atualização no URL: %s"
#define D_OTA_CHECK_COMPLETE "Verificação da atualização completa"
#define D_OTA_CHECK_FAILED "Falhou a verificação da atualização: %s"
#define D_OTA_UPDATE_FIRMWARE "Atualização de firmware OTA"
#define D_OTA_UPDATE_COMPLETE "Atualização OTA completa"
#define D_OTA_UPDATE_APPLY "A aplicar o novo firmware e reiniciar"
#define D_OTA_UPDATE_FAILED "A atualização OTA falhou"
#define D_OTA_UPDATING_FIRMWARE "A atualizar o firmware..."
#define D_OTA_UPDATING_FILESYSTEM "A atualizar o sistema de ficheiros..."
#define D_HTTP_HASP_DESIGN "Design do HASP"
#define D_HTTP_INFORMATION "Informação"
#define D_HTTP_HTTP_SETTINGS "Configurar HTTP"
#define D_HTTP_WIFI_SETTINGS "Configurar Wifi"
#define D_HTTP_MQTT_SETTINGS "Configurar MQTT"
#define D_HTTP_GPIO_SETTINGS "Configurar GPIO"
#define D_HTTP_MDNS_SETTINGS "Configurar mDNS"
#define D_HTTP_TELNET_SETTINGS "Configurar Telnet"
#define D_HTTP_DEBUG_SETTINGS "Configurar debug"
#define D_HTTP_GUI_SETTINGS "Configurar GUI"
#define D_HTTP_SAVE_SETTINGS "Guardar Configuração"
#define D_HTTP_UPLOAD_FILE "Carregar ficheiro"
#define D_HTTP_ERASE_DEVICE "Eliminar Configuração"
#define D_HTTP_ADD_GPIO "Adicionar novo pino"
#define D_HTTP_BACK "Retroceder"
#define D_HTTP_REFRESH "Atualizar"
#define D_HTTP_PREV_PAGE "Página Anterior"
#define D_HTTP_NEXT_PAGE "Página Seguinte"
#define D_HTTP_CALIBRATE "Calibrar"
#define D_HTTP_SCREENSHOT "Screenshot"
#define D_HTTP_FILE_BROWSER "Editor de ficheiros"
#define D_HTTP_FIRMWARE_UPGRADE "Atualização do firmware"
#define D_HTTP_UPDATE_FIRMWARE "Atualizar o firmware"
#define D_HTTP_FACTORY_RESET "Repor configuração de fábrica"
#define D_HTTP_MAIN_MENU "Menu Principal"
#define D_HTTP_REBOOT "Reiniciar"
#define D_HTTP_CONFIGURATION "Configuração"
#define D_HTTP_SENDING_PAGE "Foi enviado página %S a %s"
#define D_HTTP_FOOTER "por Francis Van Roie"
#define D_INFO_VERSION "Versão"
#define D_INFO_BUILD_DATETIME "Compilado a"
#define D_INFO_UPTIME "Tempo ativo"
#define D_INFO_FREE_HEAP "Heap livre"
#define D_INFO_FREE_BLOCK "Blocos livres"
#define D_INFO_DEVICE_MEMORY "Memória do dispositivo"
#define D_INFO_LVGL_MEMORY "Memória LVGL"
#define D_INFO_TOTAL_MEMORY "Total"
#define D_INFO_FREE_MEMORY "Livre"
#define D_INFO_FRAGMENTATION "Fragmentação"
#define D_INFO_PSRAM_FREE "PSRam livre"
#define D_INFO_PSRAM_SIZE "Tamanho PSRam "
#define D_INFO_FLASH_SIZE "Tamanho Flash"
#define D_INFO_SKETCH_USED "Memória programa usada"
#define D_INFO_SKETCH_FREE "Memória programa livre"
#define D_INFO_MODULE "Módulo"
#define D_INFO_MODEL "Modelo"
#define D_INFO_FREQUENCY "Frequência"
#define D_INFO_CORE_VERSION "Versão do core"
#define D_INFO_RESET_REASON "Razão do último Reset"
#define D_INFO_STATUS "Estado"
#define D_INFO_SERVER "Servidor"
#define D_INFO_USERNAME "Nome do utilizador"
#define D_INFO_CLIENTID "ID do Cliente"
#define D_INFO_CONNECTED "Ligado"
#define D_INFO_DISCONNECTED "Desligado"
#define D_INFO_RECEIVED "Recebido"
#define D_INFO_PUBLISHED "Publicado"
#define D_INFO_FAILED "Em falha"
#define D_INFO_ETHERNET "Ethernet"
#define D_INFO_WIFI "Wifi"
#define D_INFO_LINK_SPEED "Link Speed"
#define D_INFO_FULL_DUPLEX "Full Duplex"
#define D_INFO_SSID "SSID"
#define D_INFO_RSSI "Potência do sinal"
#define D_INFO_IP_ADDRESS "Endereço IP"
#define D_INFO_MAC_ADDRESS "Endereço MAC"
#define D_INFO_GATEWAY "Gateway"
#define D_INFO_DNS_SERVER "Servidor DNS"
#define D_OOBE_MSG "Toque no ecrã para configurar WiFi ou para se ligar a um access point"
#define D_OOBE_SCAN_TO_CONNECT "Procurar rede"
#define D_WIFI_CONNECTING_TO "A ligar a %s"
#define D_WIFI_CONNECTED_TO "Ligado a %s, a pedir IP..."
#define D_WIFI_RSSI_EXCELLENT "Excelente"
#define D_WIFI_RSSI_GOOD "Bom"
#define D_WIFI_RSSI_FAIR "Decente"
#define D_WIFI_RSSI_WEAK "Fraco"
#define D_WIFI_RSSI_BAD "Muito baixo"
#define D_GPIO_SWITCH "Interruptor"
#define D_GPIO_BUTTON "Botão"
#define D_GPIO_TOUCH "Capacitive Touch" // new
#define D_GPIO_LED "LED"
#define D_GPIO_LED_R "LED Red"
#define D_GPIO_LED_G "LED Green"
#define D_GPIO_LED_B "LED Blue"
#define D_GPIO_POWER_RELAY "Power Relé" // new
#define D_GPIO_LIGHT_RELAY "Light Relé" // new
#define D_GPIO_PWM "PWM"
#define D_GPIO_DAC "DAC"
#define D_GPIO_SERIAL_DIMMER "Dimmer serial"
#define D_GPIO_UNKNOWN "Desconhecido"
#define D_GPIO_PIN "Pin"
#define D_GPIO_GROUP "Grupo"
#define D_GPIO_GROUP_NONE "Nenhum"
#define D_GPIO_STATE_NORMAL "Normal" // new
#define D_GPIO_STATE_INVERTED "Inverted" // new
#endif

View File

@ -4,6 +4,8 @@
#define D_USERNAME "Nume de utilizator:"
#define D_PASSWORD "Parola:"
#define D_SSID "SSID:"
#define D_YES "Da"
#define D_NO "Nu"
#define D_ERROR_OUT_OF_MEMORY "Memorie epuizată"
#define D_ERROR_UNKNOWN "Eroare necunoscută"
@ -15,10 +17,19 @@
#define D_FILE_LOADING "Se încarcă %s"
#define D_FILE_LOADED "S-a încărcat %s"
#define D_FILE_LOAD_FAILED "Încărcarea %s a eșuat"
#define D_FILE_SAVING "Se salvează %s"
#define D_FILE_SAVED "S-a salvat %s"
#define D_FILE_SAVE_FAILED "Salvarea %s a eșuat"
#define D_FILE_NOT_FOUND "File not found" // new
#define D_FILE_SIZE_BYTES "bytes" // new
#define D_FILE_SIZE_KILOBYTES "KiB" // new
#define D_FILE_SIZE_MEGABYTES "MiB" // new
#define D_FILE_SIZE_GIGABYTES "GiB" // new
#define D_FILE_SIZE_DIVIDER 1024 // new, kibi or kilo bytes
#define D_DECIMAL_POINT "," // new, decimal comma or point
#define D_SETTING_ENABLED "Activ"
#define D_SETTING_DISABLED "Inactiv"
#define D_SERVICE_STARTING "Pornire..."
#define D_SERVICE_STARTED "Pornit"
@ -47,7 +58,7 @@
#define D_MQTT_SUBSCRIBED "Abonat la %s"
#define D_MQTT_NOT_SUBSCRIBED "Abonarea la %s a eșuat"
#define D_MQTT_HA_AUTO_DISCOVERY "Înregistrare la auto-descoperire în HA"
#define D_MQTT_PAYLOAD_TOO_LONG "$$$Payload too long (%d bytes)"
#define D_MQTT_PAYLOAD_TOO_LONG "Payload prea lung (%u baiți)"
#define D_TELNET_CLOSING_CONNECTION "Terminarea sesiunii de la %s"
#define D_TELNET_CLIENT_LOGIN_FROM "Conectare client de la %s"
@ -58,7 +69,6 @@
#define D_TELNET_STARTED "Consola Telnet pornită"
#define D_TELNET_FAILED "Nu s-a putut porni consola Telnet"
#define D_TELNET_CLIENT_CONNECTED "Client conectat"
#define D_TELNET_CLIENT_NOT_CONNECTED "Client NU este conectat"
#define D_TELNET_CLIENT_REJECTED "Client respins"
#define D_HASP_INVALID_PAGE "Pagina invalidă: %u"
@ -77,6 +87,8 @@
#define D_ATTRIBUTE_UNKNOWN "Proprietate necunoscută: %s"
#define D_ATTRIBUTE_READ_ONLY "%s este numai în citire"
#define D_ATTRIBUTE_PAGE_METHOD_INVALID "Nu se poate apela %s pe o pagină"
#define D_ATTRIBUTE_ALIGN_INVALID "Invalid align property: %s" // new
#define D_ATTRIBUTE_COLOR_INVALID "Invalid color property: %s" // new
#define D_OOBE_SSID_VALIDATED "SSID %s validat"
#define D_OOBE_AUTO_CALIBRATE "Calibrarea automată este activă"
@ -87,7 +99,7 @@
#define D_DISPATCH_REBOOT "MCU-ul repornește acum!"
#define D_JSON_FAILED "Analiza JSON a eșuat:"
#define D_JSONL_FAILED "Analiza JSONL a eșuat la linia %d"
#define D_JSONL_FAILED "Analiza JSONL a eșuat la linia %u"
#define D_JSONL_SUCCEEDED "Analiza JSONL completă"
#define D_OTA_CHECK_UPDATE "Verificare la URL-ul actualizărilor: %s"
@ -97,6 +109,8 @@
#define D_OTA_UPDATE_COMPLETE "Actualizare prin OTA finalizată"
#define D_OTA_UPDATE_APPLY "Aplicarea firmware-ului și repornire"
#define D_OTA_UPDATE_FAILED "Actualizarea prin OTA a eșuat"
#define D_OTA_UPDATING_FIRMWARE "Actualizare firmware..."
#define D_OTA_UPDATING_FILESYSTEM "Actualizare sistem fișiere..."
#define D_HTTP_HASP_DESIGN "Desenul ecranului"
#define D_HTTP_INFORMATION "Informații"
@ -111,7 +125,7 @@
#define D_HTTP_SAVE_SETTINGS "Salvarea setărilor"
#define D_HTTP_UPLOAD_FILE "Încărcare fișier"
#define D_HTTP_ERASE_DEVICE "Resetarea tuturor setărilor"
#define D_HTTP_ADD_GPIO "Adăugați un pin nou"
#define D_HTTP_ADD_GPIO "Adăugare pin"
#define D_HTTP_BACK "Înapoi"
#define D_HTTP_REFRESH "Reîmprospătare"
#define D_HTTP_PREV_PAGE "Pagina anterioară"
@ -125,11 +139,78 @@
#define D_HTTP_MAIN_MENU "Meniu principal"
#define D_HTTP_REBOOT "Repornire"
#define D_HTTP_CONFIGURATION "Setări"
#define D_HTTP_SENDING_PAGE "Pagina %S trimisă la %s"
#define D_HTTP_FOOTER "de Francis Van Roie"
#define D_INFO_VERSION "Versiune"
#define D_INFO_BUILD_DATETIME "Data Build-ului"
#define D_INFO_UPTIME "Uptime"
#define D_INFO_FREE_HEAP "Heap liber"
#define D_INFO_FREE_BLOCK "Bloc liber"
#define D_INFO_DEVICE_MEMORY "Memorie dispozitiv"
#define D_INFO_LVGL_MEMORY "Memorie LVGL"
#define D_INFO_TOTAL_MEMORY "Total"
#define D_INFO_FREE_MEMORY "Liber"
#define D_INFO_FRAGMENTATION "Fragmentație"
#define D_INFO_PSRAM_FREE "PSRam liber"
#define D_INFO_PSRAM_SIZE "PSRam mărime"
#define D_INFO_FLASH_SIZE "Flash mărime"
#define D_INFO_SKETCH_USED "Mărime program folosită"
#define D_INFO_SKETCH_FREE "Mărime program liberă"
#define D_INFO_MODULE "Modul"
#define D_INFO_MODEL "Model"
#define D_INFO_FREQUENCY "Frecvență"
#define D_INFO_CORE_VERSION "Versiune Core"
#define D_INFO_RESET_REASON "Motiv reset"
#define D_INFO_STATUS "Stare"
#define D_INFO_SERVER "Server"
#define D_INFO_USERNAME "Utilizatur"
#define D_INFO_CLIENTID "ID Client"
#define D_INFO_CONNECTED "Conectat"
#define D_INFO_DISCONNECTED "Deconectat"
#define D_INFO_RECEIVED "Primite"
#define D_INFO_PUBLISHED "Trimise"
#define D_INFO_FAILED "Eșuate"
#define D_INFO_ETHERNET "Ethernet"
#define D_INFO_WIFI "WiFi"
#define D_INFO_LINK_SPEED "Viteză Link"
#define D_INFO_FULL_DUPLEX "Full Duplex" // new
#define D_INFO_SSID "SSID"
#define D_INFO_RSSI "Putere semnal"
#define D_INFO_IP_ADDRESS "Addresa IP"
#define D_INFO_MAC_ADDRESS "Addresa MAC"
#define D_INFO_GATEWAY "Gateway"
#define D_INFO_DNS_SERVER "Server DNS"
#define D_OOBE_MSG "Atingeți ecranul pentru a configura WiFi sau conectați-vă la acest punct de acces:"
#define D_OOBE_SCAN_TO_CONNECT "Scanați pentru a vă conecta:"
#define D_WIFI_CONNECTING_TO "$$$Connecting to %s"
#define D_WIFI_CONNECTED_TO "$$$Connected to %s, requesting IP..."
#define D_WIFI_CONNECTING_TO "Conectare la %s"
#define D_WIFI_CONNECTED_TO "Conectat la %s, cerere IP..."
#define D_WIFI_RSSI_EXCELLENT "Excelentă"
#define D_WIFI_RSSI_GOOD "Bună"
#define D_WIFI_RSSI_FAIR "Acceptabilă"
#define D_WIFI_RSSI_WEAK "Slabă"
#define D_WIFI_RSSI_BAD "Foarte slabă"
// new
#define D_GPIO_SWITCH "Switch"
#define D_GPIO_BUTTON "Button"
#define D_GPIO_TOUCH "Capacitive Touch" // new
#define D_GPIO_LED "Led"
#define D_GPIO_LED_R "Mood Red"
#define D_GPIO_LED_G "Mood Green"
#define D_GPIO_LED_B "Mood Blue"
#define D_GPIO_POWER_RELAY "Power Relay" // new
#define D_GPIO_LIGHT_RELAY "Light Relay" // new
#define D_GPIO_PWM "PWM"
#define D_GPIO_DAC "DAC"
#define D_GPIO_SERIAL_DIMMER "Serial Dimmer"
#define D_GPIO_UNKNOWN "Unknown"
#define D_GPIO_PIN "Pin"
#define D_GPIO_GROUP "Group"
#define D_GPIO_GROUP_NONE "None"
#define D_GPIO_STATE_NORMAL "Normal" // new
#define D_GPIO_STATE_INVERTED "Inverted" // new
#endif

View File

@ -39,10 +39,6 @@
#include "hasp/hasp_dispatch.h"
#include "hasp/hasp.h"
// #ifdef USE_CONFIG_OVERRIDE
// #include "user_config_override.h"
// #endif
#ifndef SERIAL_SPEED
#define SERIAL_SPEED 115200
#endif
@ -66,7 +62,6 @@
// static String debugOutput((char *)0);
// static StringStream debugStream((String &)debugOutput);
// extern char mqttNodeName[16];
// const char* syslogAppName = APP_NAME;
char debugSyslogHost[32] = SYSLOG_SERVER;
uint16_t debugSyslogPort = SYSLOG_PORT;
@ -92,9 +87,6 @@ uint16_t debugSerialBaud = SERIAL_SPEED / 10; // Multiplied by 10
extern bool debugSerialStarted;
extern bool debugAnsiCodes;
ConsoleInput debugConsole(&Serial, HASP_CONSOLE_BUFFER);
unsigned long debugLastMillis = 0;
extern dispatch_conf_t dispatch_setings;
// #if HASP_USE_SYSLOG > 0
@ -106,14 +98,6 @@ extern dispatch_conf_t dispatch_setings;
// }
// #endif
void debugSetup()
{
// memset(serialInputBuffer, 0, sizeof(serialInputBuffer));
// serialInputIndex = 0;
LOG_TRACE(TAG_DEBG, F(D_SERVICE_STARTING)); // Starting console
debugConsole.setLineCallback(dispatch_text_line);
}
void debugStartSyslog()
{
@ -293,13 +277,14 @@ void debugPrintSuffix(uint8_t tag, int level, Print* _logOutput)
_logOutput->println();
if(_logOutput == &Serial) {
debugConsole.update();
console_update_prompt();
} else {
_logOutput->print("hasp > ");
}
}
void debugPreSetup(JsonObject settings)
// Do NOT call Log function before debugSetup is called
void debugSetup(JsonObject settings)
{
Log.begin(LOG_LEVEL_WARNING, true);
Log.setPrefix(debugPrintPrefix); // Uncomment to get timestamps as prefix
@ -328,31 +313,13 @@ void debugPreSetup(JsonObject settings)
debugPrintHaspHeader(&Serial);
Serial.flush();
LOG_INFO(TAG_DEBG, F(D_SERVICE_STARTED " @ %u baud"), baudrate);
LOG_INFO(TAG_DEBG, F(D_SERVICE_STARTED " @ %u Bps"), baudrate);
LOG_INFO(TAG_DEBG, F("Environment: " PIOENV));
}
}
void debugLoop(void)
{
int16_t keypress;
do {
switch(keypress = debugConsole.readKey()) {
case ConsoleInput::KEY_PAGE_UP:
dispatch_page_next(LV_SCR_LOAD_ANIM_NONE);
break;
case ConsoleInput::KEY_PAGE_DOWN:
dispatch_page_prev(LV_SCR_LOAD_ANIM_NONE);
break;
case(ConsoleInput::KEY_FN)...(ConsoleInput::KEY_FN + 12):
dispatch_set_page(keypress - ConsoleInput::KEY_FN, LV_SCR_LOAD_ANIM_NONE);
break;
}
} while(keypress != 0);
}
IRAM_ATTR void debugLoop(void)
{}
void printLocalTime()
{
@ -386,7 +353,7 @@ void printLocalTime()
} else {
Serial.printf("%s ", sntp.toString().c_str());
}
Serial.printf("IPv6: %s Reachability: %o\n", sntp.isV6() ? "Yes" : "No", sntp_getreachability(i));
Serial.printf("IPv6: %s Reachability: %o\n", sntp.isV6() ? D_YES : D_NO, sntp_getreachability(i));
}
}
#endif

View File

@ -54,12 +54,11 @@ void setup()
* Read & Apply User Configuration
***************************/
#if HASP_USE_CONFIG > 0
configSetup(); // also runs debugPreSetup(), debugSetup() and debugStart()
configSetup(); // also runs debugSetup() and debugStart()
#endif
dispatchSetup();
guiSetup();
debugSetup(); // Init the console
#if HASP_USE_GPIO > 0
gpioSetup();
@ -105,7 +104,7 @@ void setup()
#endif
mainLastLoopTime = millis() - 1000; // reset loop counter
delay(250);
delay(20);
guiStart();
}

View File

@ -3,9 +3,12 @@
#if !(defined(WINDOWS) || defined(POSIX))
#include <Arduino.h>
#include "lvgl.h"
#include "hasp_conf.h" // load first
#include "hasplib.h"
#include "hasp_oobe.h"
#include "sys/net/hasp_network.h"
#include "dev/device.h"
#include "drv/hasp_drv_touch.h"
#include "ArduinoLog.h"
#if HASP_USE_CONFIG > 0
#include "hasp_debug.h"
@ -16,18 +19,10 @@
#include "hasp_gui.h"
#endif
#include "hasp_oobe.h"
#include "hasp/hasp_dispatch.h"
#include "hasp/hasp.h"
#include "sys/net/hasp_network.h"
#include "dev/device.h"
bool isConnected;
uint8_t mainLoopCounter = 0;
unsigned long mainLastLoopTime = 0;
uint8_t statLoopCounter = 0;
void setup()
{
@ -54,12 +49,11 @@ void setup()
* Read & Apply User Configuration
***************************/
#if HASP_USE_CONFIG > 0
configSetup(); // also runs debugPreSetup(), debugSetup() and debugStart()
configSetup(); // also runs debugSetup() and debugStart()
#endif
dispatchSetup(); // before hasp and oobe, asap after logging starts
guiSetup();
debugSetup(); // Init the console
dispatchSetup(); // for hasp and oobe
#if HASP_USE_CONFIG > 0
if(!oobeSetup())
@ -68,10 +62,6 @@ void setup()
haspSetup();
}
#if HASP_USE_GPIO > 0
gpioSetup();
#endif
/****************************
* Apply User Configuration
***************************/
@ -80,6 +70,10 @@ void setup()
mqttSetup(); // Load Hostname before starting WiFi
#endif
#if HASP_USE_GPIO > 0
gpioSetup();
#endif
#if HASP_USE_WIFI > 0 || HASP_USE_ETHERNET > 0
networkSetup();
#endif
@ -96,6 +90,10 @@ void setup()
httpSetup();
#endif
#if HASP_USE_CONSOLE > 0
consoleSetup();
#endif
#if HASP_USE_TELNET > 0
telnetSetup();
#endif
@ -104,15 +102,16 @@ void setup()
slaveSetup();
#endif
mainLastLoopTime = millis() - 1000; // reset loop counter
delay(250);
mainLastLoopTime = -1000; // reset loop counter
delay(20);
// guiStart();
}
void loop()
IRAM_ATTR void loop()
{
guiLoop();
haspLoop();
// haspLoop();
networkLoop();
#if HASP_USE_GPIO > 0
@ -123,48 +122,67 @@ void loop()
mqttLoop();
#endif // MQTT
debugLoop(); // Console
haspDevice.loop();
// haspDevice.loop();
#if HASP_USE_CONSOLE > 0
// debugLoop();
consoleLoop();
#endif
statLoopCounter++;
/* Timer Loop */
if(millis() - mainLastLoopTime >= 1000) {
mainLastLoopTime += 1000;
/* Runs Every Second */
haspEverySecond(); // sleep timer
debugEverySecond(); // statusupdate
haspEverySecond(); // sleep timer & statusupdate
/* Runs Every 5 Seconds */
if(mainLoopCounter == 0 || mainLoopCounter == 5) {
isConnected = networkEvery5Seconds(); // Check connection
#if HASP_USE_HTTP > 0
// httpEvery5Seconds();
#if HASP_USE_TELNET > 0
telnetEverySecond();
#endif
// debugEverySecond();
switch(++mainLoopCounter) {
case 1:
haspDevice.loop_5s();
break;
case 2:
#if HASP_USE_HTTP > 0
// httpEvery5Seconds();
#endif
break;
case 3:
#if HASP_USE_GPIO > 0
// gpioEvery5Seconds();
#endif
break;
case 4:
isConnected = networkEvery5Seconds(); // Check connection
#if HASP_USE_MQTT > 0
mqttEvery5Seconds(isConnected);
mqttEvery5Seconds(isConnected);
#endif
break;
#if HASP_USE_GPIO > 0
// gpioEvery5Seconds();
#endif
haspDevice.loop_5s();
case 5:
mainLoopCounter = 0;
// if(statLoopCounter)
// LOG_VERBOSE(TAG_MAIN, F("%d millis per loop, %d counted"), 5000 / statLoopCounter,
// statLoopCounter);
// statLoopCounter = 0;
break;
}
/* Reset loop counter every 10 seconds */
if(mainLoopCounter >= 9) {
mainLoopCounter = 0;
} else {
mainLoopCounter++;
}
mainLastLoopTime += 1000;
}
#ifdef ARDUINO_ARCH_ESP8266
delay(2);
delay(2); // ms
#else
delay(6);
delay(2); // ms
// delay((lv_task_get_idle() >> 5) + 3); // 2..5 ms
#endif
}

View File

@ -25,7 +25,7 @@
#include "hasp_conf.h"
#include "lvgl.h"
#include "app_hal.h"
// #include "app_hal.h"
#include "display/monitor.h"
#include "hasp_debug.h"
@ -42,6 +42,9 @@ bool isRunning = 1;
uint8_t mainLoopCounter = 0;
unsigned long mainLastLoopTime = 0;
extern uint16_t tft_width;
extern uint16_t tft_height;
#if defined(WINDOWS)
// https://gist.github.com/kingseva/a918ec66079a9475f19642ec31276a21
void BindStdHandlesToConsole()
@ -120,8 +123,6 @@ void setup()
// hal_setup();
guiSetup();
// debugSetup(); // Init the console
printf("%s %d\n", __FILE__, __LINE__);
dispatchSetup(); // for hasp and oobe
haspSetup();
@ -132,9 +133,14 @@ void setup()
mqttStart();
#endif
mainLastLoopTime = millis() - 1000; // reset loop counter
delay(250);
#if HASP_USE_GPIO > 0
printf("%s %d\n", __FILE__, __LINE__);
gpioSetup();
#endif
mainLastLoopTime = millis() - 1000; // reset loop counter
printf("%s %d\n", __FILE__, __LINE__);
// delay(250);
}
void loop()
@ -146,6 +152,10 @@ void loop()
haspDevice.loop();
guiLoop();
#if HASP_USE_GPIO > 0
gpioLoop();
#endif
/* Timer Loop */
if(millis() - mainLastLoopTime >= 1000) {
/* Runs Every Second */
@ -230,19 +240,27 @@ int main(int argc, char* argv[])
// Change to preferences dir
std::cout << "\nCommand-line arguments:\n";
for(count = 0; count < argc; count++)
std::cout << " argv[" << count << "] " << argv[count] << "\n" << std::endl << std::flush;
std::cout << " argv[" << count << "] " << argv[count] << std::endl << std::flush;
for(count = 0; count < argc; count++) {
if(argv[count][0] == '-') {
if(strncmp(argv[count], "--help", 6) == 0 || strncmp(argv[count], "-h", 2) == 0) {
std::cout << " argv[" << count << "] " << argv[count] << "\n" << std::endl << std::flush;
fflush(stdout);
exit(0);
showhelp = true;
}
if(strncmp(argv[count], "--name", 6) == 0) {
std::cout << " argv[" << count << "] " << argv[count] << "\n" << std::endl << std::flush;
if(strncmp(argv[count], "--width", 7) == 0 || strncmp(argv[count], "-x", 2) == 0) {
int w = atoi(argv[count + 1]);
if(w > 0) tft_width = w;
}
if(strncmp(argv[count], "--height", 8) == 0 || strncmp(argv[count], "-y", 2) == 0) {
int h = atoi(argv[count + 1]);
if(h > 0) tft_height = h;
}
if(strncmp(argv[count], "--name", 6) == 0 || strncmp(argv[count], "-n", 2) == 0) {
std::cout << " argv[" << count << "] " << argv[count] << std::endl << std::flush;
fflush(stdout);
if(count + 1 < argc) {
haspDevice.set_hostname(argv[count + 1]);
@ -257,24 +275,29 @@ int main(int argc, char* argv[])
usage("openHASP");
#if defined(WINDOWS)
WriteConsole(std_out, "bye", 3, NULL, NULL);
WriteConsole(std_out, "bye\n", 3, NULL, NULL);
std::cout << std::endl << std::flush;
fflush(stdout);
FreeConsole();
exit(0);
#endif
return 0;
}
// printf("%s %d\n", __FILE__, __LINE__);
// fflush(stdout);
printf("pre setup\n");
setup();
printf("to loop\n");
debugPrintHaspHeader(stdout);
LOG_NOTICE(TAG_MAIN, "resolution %d x %d", tft_width, tft_height);
LOG_NOTICE(TAG_MAIN, "pre setup");
setup();
LOG_TRACE(TAG_MAIN, "loop started");
while(isRunning) {
loop();
// std::cout << "HSetup OK\n";
}
printf("endrunning\n");
LOG_TRACE(TAG_MAIN, "main loop completed");
return 0;
}

View File

@ -5,9 +5,7 @@
#define HASP_MQTT_H
#include <stdint.h>
#include "ArduinoJson.h"
#include "hasp_conf.h"
#include "hasplib.h"
// #if defined(WINDOWS) || defined(POSIX)
// #define __FlashStringHelper char
@ -23,24 +21,67 @@ typedef enum {
} hasp_mqtt_error_t;
void mqttSetup();
void mqttLoop();
IRAM_ATTR void mqttLoop();
void mqttEvery5Seconds(bool wifiIsConnected);
void mqttStart();
void mqttStop();
int mqtt_send_object_state(uint8_t pageid, uint8_t btnid, const char* payload);
int mqtt_send_state(const char* subtopic, const char* payload);
int mqtt_send_discovery(const char* payload, size_t len);
int mqttPublish(const char* topic, const char* payload, size_t len, bool retain);
bool mqttIsConnected();
void mqtt_get_info(JsonDocument& doc);
#if HASP_USE_CONFIG > 0
bool mqttGetConfig(const JsonObject& settings);
bool mqttSetConfig(const JsonObject& settings);
#endif
// #ifndef WINDOWS
// String mqttGetNodename(void);
// #endif
#ifndef MQTT_PREFIX
#define MQTT_PREFIX "hasp"
#endif
#ifndef MQTT_TOPIC_STATE
#define MQTT_TOPIC_STATE "state"
#endif
#ifndef MQTT_TOPIC_COMMAND
#define MQTT_TOPIC_COMMAND "command"
#endif
#ifndef MQTT_TOPIC_DISCOVERY
#define MQTT_TOPIC_DISCOVERY "discovery"
#endif
#ifndef MQTT_TOPIC_BROADCAST
#define MQTT_TOPIC_BROADCAST "broadcast"
#endif
#define MQTT_TOPIC_LWT "LWT"
////////////////////////////////////////////////////////////////////////////////////////////////////
// These defaults may be overwritten with values saved by the web interface
#ifndef MQTT_GROUPNAME
#define MQTT_GROUPNAME "plates";
#endif
#ifndef MQTT_HOST
#define MQTT_HOST "";
#endif
#ifndef MQTT_PORT
#define MQTT_PORT 1883;
#endif
#ifndef MQTT_USER
#define MQTT_USER "";
#endif
#ifndef MQTT_PASSW
#define MQTT_PASSW "";
#endif
#endif // HASP_MQTT_H

View File

@ -17,8 +17,8 @@
#define RETAINED true
// extern char mqttNodeName[16];
extern char mqttNodeTopic[24];
extern char mqttGroupTopic[24];
extern std::string mqttNodeTopic;
extern std::string mqttGroupTopic;
extern bool mqttEnabled;
extern bool mqttHAautodiscover;
@ -75,10 +75,7 @@ void mqtt_ha_add_device_ids(JsonDocument& doc)
ids.add(haspDevice.get_hostname());
ids.add(HASP_MAC_ADDRESS_STR);
char buffer[32];
haspGetVersion(buffer, sizeof(buffer));
device[F("sw")] = buffer;
device[F("sw")] = haspDevice.get_version();
device[FPSTR(FP_MQTT_HA_NAME)] = haspDevice.get_hostname();
device[FPSTR(FP_MQTT_HA_MODEL)] = F(PIOENV);
device[FPSTR(FP_MQTT_HA_MANUFACTURER)] = F(D_MANUFACTURER);
@ -106,7 +103,7 @@ void mqtt_ha_register_button(uint8_t page, uint8_t id)
char buffer[128];
snprintf_P(buffer, sizeof(buffer), PSTR(HASP_OBJECT_NOTATION), page, id);
doc[F("stype")] = buffer; // subtype = "p0b0"
snprintf_P(buffer, sizeof(buffer), PSTR("~state/" HASP_OBJECT_NOTATION), page, id);
snprintf_P(buffer, sizeof(buffer), PSTR("~" MQTT_TOPIC_STATE "/" HASP_OBJECT_NOTATION), page, id);
doc[F("t")] = buffer; // topic
doc[F("atype")] = "trigger"; // automation_type
@ -148,7 +145,7 @@ void mqtt_ha_register_switch(uint8_t page, uint8_t id)
char buffer[128];
snprintf_P(buffer, sizeof(buffer), PSTR(HASP_OBJECT_NOTATION), page, id);
doc[F("stype")] = buffer; // subtype = "p0b0"
snprintf_P(buffer, sizeof(buffer), PSTR("~state/" HASP_OBJECT_NOTATION), page, id);
snprintf_P(buffer, sizeof(buffer), PSTR("~" MQTT_TOPIC_STATE "/" HASP_OBJECT_NOTATION), page, id);
doc[F("t")] = buffer; // topic
doc[F("atype")] = F("binary_sensor"); // automation_type
@ -169,7 +166,7 @@ void mqtt_ha_register_connectivity()
// start from static keys and values that do not change
deserializeJson(doc, F("{\"device_class\":\"connectivity\",\"stat_t\":\"~LWT\",\"pl_on\":\"online\",\"pl_off\":"
"\"offline\",\"json_attr_t\":\"~state/statusupdate\"}"));
"\"offline\",\"json_attr_t\":\"~" MQTT_TOPIC_STATE "/statusupdate\"}"));
mqtt_ha_add_device_ids(doc);
mqtt_ha_add_unique_id(doc, item);
@ -187,13 +184,13 @@ void mqtt_ha_register_backlight()
// start from static keys and values that do not change
deserializeJson(doc, F("{"
"\"cmd_t\":\"~command/light\","
"\"stat_t\":\"~state/light\","
"\"cmd_t\":\"~" MQTT_TOPIC_COMMAND "/light\","
"\"stat_t\":\"~" MQTT_TOPIC_STATE "/light\","
"\"pl_on\":\"on\","
"\"pl_off\":\"off\","
"\"avty_t\":\"~LWT\","
"\"bri_stat_t\":\"~state/dim\","
"\"bri_cmd_t\":\"~command/dim\","
"\"bri_stat_t\":\"~" MQTT_TOPIC_STATE "/dim\","
"\"bri_cmd_t\":\"~" MQTT_TOPIC_COMMAND "/dim\","
"\"bri_scl\":100}"));
mqtt_ha_add_device_ids(doc);
mqtt_ha_add_unique_id(doc, item);
@ -215,8 +212,8 @@ void mqtt_ha_register_moodlight()
// start from static keys and values that do not change
deserializeJson(doc, F("{"
"\"cmd_t\":\"~command/moodlight\","
"\"stat_t\":\"~state/moodlight\","
"\"cmd_t\":\"~" MQTT_TOPIC_COMMAND "/moodlight\","
"\"stat_t\":\"~" MQTT_TOPIC_STATE "/moodlight\","
"\"platform\":\"mqtt\","
"\"schema\":\"json\","
"\"rgb\":true,"
@ -225,12 +222,12 @@ void mqtt_ha_register_moodlight()
/* deserializeJson(doc, F("{"
"\"cmd_t\":\"~command/moodlight\","
// "\"stat_t\":\"~state/moodlight\","
// "\"stat_t\":\"~" MQTT_TOPIC_STATE "/moodlight\","
"\"avty_t\":\"~LWT\","
"\"bri_stat_t\":\"~state/moodlight/dim\","
"\"bri_stat_t\":\"~" MQTT_TOPIC_STATE "/moodlight/dim\","
"\"bri_cmd_t\":\"~command/moodlight/dim\","
"\"bri_scl\":100,"
"\"rgb_stat_t\":\"~state/moodlight/rgb\","
"\"rgb_stat_t\":\"~" MQTT_TOPIC_STATE "/moodlight/rgb\","
"\"rgb_cmd_t\":\"~command/moodlight/rgb\"}"));
*/
mqtt_ha_add_device_ids(doc);
@ -256,7 +253,8 @@ void mqtt_ha_register_idle()
snprintf_P(item, sizeof(item), PSTR("idle"));
// start from static keys and values that do not change
deserializeJson(doc, F("{\"stat_t\":\"~state/idle\",\"avty_t\":\"~LWT\",\"json_attr_t\":\"~state/statusupdate\"}"));
deserializeJson(doc, F("{\"stat_t\":\"~" MQTT_TOPIC_STATE
"/idle\",\"avty_t\":\"~LWT\",\"json_attr_t\":\"~" MQTT_TOPIC_STATE "/statusupdate\"}"));
mqtt_ha_add_device_ids(doc);
mqtt_ha_add_unique_id(doc, item);
@ -273,7 +271,8 @@ void mqtt_ha_register_activepage()
snprintf_P(item, sizeof(item), PSTR("page"));
// start from static keys and values that do not change
deserializeJson(doc, F("{\"cmd_t\":\"~command/page\",\"stat_t\":\"~state/page\",\"avty_t\":\"~LWT\"}"));
deserializeJson(doc, F("{\"cmd_t\":\"~" MQTT_TOPIC_COMMAND "/page\",\"stat_t\":\"~" MQTT_TOPIC_STATE
"/page\",\"avty_t\":\"~LWT\"}"));
mqtt_ha_add_device_ids(doc);
mqtt_ha_add_unique_id(doc, item);

View File

@ -63,36 +63,6 @@ const char* mqttGroupTopic = TOPIC;
bool mqttEnabled = false;
bool mqttHAautodiscover = true;
////////////////////////////////////////////////////////////////////////////////////////////////////
// These defaults may be overwritten with values saved by the web interface
#ifndef MQTT_HOST
#define MQTT_HOST "";
#endif
#ifndef MQTT_PORT
#define MQTT_PORT 1883;
#endif
#ifndef MQTT_USER
#define MQTT_USER "";
#endif
#ifndef MQTT_PASSW
#define MQTT_PASSW "";
#endif
#ifndef MQTT_NODENAME
#define MQTT_NODENAME "";
#endif
#ifndef MQTT_GROUPNAME
#define MQTT_GROUPNAME "";
#endif
#ifndef MQTT_PREFIX
#define MQTT_PREFIX "hasp"
#endif
#define LWT_TOPIC "LWT"
std::recursive_mutex dispatch_mtx;
std::recursive_mutex publish_mtx;
@ -123,10 +93,10 @@ void connlost(void* context, char* cause)
}
// Receive incoming messages
static void mqtt_message_cb(char* topic, char* payload, unsigned int length)
static void mqtt_message_cb(char* topic, char* payload, size_t length)
{ // Handle incoming commands from MQTT
if(length + 1 >= MQTT_MAX_PACKET_SIZE) {
LOG_ERROR(TAG_MQTT_RCV, F(D_MQTT_PAYLOAD_TOO_LONG), length);
LOG_ERROR(TAG_MQTT_RCV, F(D_MQTT_PAYLOAD_TOO_LONG), (uint32_t)length);
return;
} else {
payload[length] = '\0';
@ -164,12 +134,12 @@ static void mqtt_message_cb(char* topic, char* payload, unsigned int length)
}
// catch a dangling LWT from a previous connection if it appears
if(!strcmp_P(topic, PSTR(LWT_TOPIC))) { // endsWith LWT
if(!strcmp_P(topic, PSTR(MQTT_TOPIC_LWT))) { // endsWith LWT
if(!strcasecmp_P((char*)payload, PSTR("offline"))) {
{
char msg[8];
char tmp_topic[strlen(mqttNodeTopic) + 8];
snprintf_P(tmp_topic, sizeof(tmp_topic), PSTR("%s" LWT_TOPIC), mqttNodeTopic);
snprintf_P(tmp_topic, sizeof(tmp_topic), PSTR("%s" MQTT_TOPIC_LWT), mqttNodeTopic);
snprintf_P(msg, sizeof(msg), PSTR("online"));
// /*bool res =*/mqttClient.publish(tmp_topic, msg, true);
@ -254,12 +224,12 @@ void onConnect(void* context, MQTTAsync_successData* response)
printf("Successful connection\n");
mqtt_subscribe(context, TOPIC "command/#");
mqtt_subscribe(context, TOPIC "command");
mqtt_subscribe(context, TOPIC MQTT_TOPIC_COMMAND "/#");
mqtt_subscribe(context, TOPIC MQTT_TOPIC_COMMAND);
mqtt_subscribe(context, TOPIC "light");
mqtt_subscribe(context, TOPIC "dim");
mqttPublish(TOPIC LWT_TOPIC, "online", false);
mqttPublish(TOPIC MQTT_TOPIC_LWT, "online", false);
mqtt_send_object_state(0, 0, "connected");
std::cout << std::endl;
@ -340,15 +310,15 @@ bool mqttIsConnected()
void mqtt_send_state(const __FlashStringHelper* subtopic, const char* payload)
{
char tmp_topic[strlen(mqttNodeTopic) + 20];
printf(("%sstate/%s\n"), mqttNodeTopic, subtopic);
snprintf_P(tmp_topic, sizeof(tmp_topic), ("%sstate/%s"), mqttNodeTopic, subtopic);
printf(("%s" MQTT_TOPIC_STATE "/%s\n"), mqttNodeTopic, subtopic);
snprintf_P(tmp_topic, sizeof(tmp_topic), ("%s" MQTT_TOPIC_STATE "/%s"), mqttNodeTopic, subtopic);
mqttPublish(tmp_topic, payload, false);
}
void mqtt_send_object_state(uint8_t pageid, uint8_t btnid, const char* payload)
{
char tmp_topic[strlen(mqttNodeTopic) + 20];
snprintf_P(tmp_topic, sizeof(tmp_topic), PSTR("%sstate/p%ub%u"), mqttNodeTopic, pageid, btnid);
snprintf_P(tmp_topic, sizeof(tmp_topic), PSTR("%s" MQTT_TOPIC_STATE "/p%ub%u"), mqttNodeTopic, pageid, btnid);
mqttPublish(tmp_topic, payload, false);
}
@ -430,7 +400,7 @@ void mqttStop()
void mqttSetup(){};
void mqttLoop(){};
IRAM_ATTR void mqttLoop(){};
void mqttEvery5Seconds(bool wifiIsConnected){};

View File

@ -3,9 +3,7 @@
/* Single threaded synchronous paho client */
#include <stdint.h>
#include "hasp_conf.h"
#include "hasplib.h"
#if HASP_USE_MQTT > 0
#ifdef USE_PAHO
@ -50,55 +48,26 @@
#include <OsWrapper.h>
#endif
#define ADDRESS "10.1.0.208:1883"
#define CLIENTID "test1123"
#define TOPIC "hasp/plate35/"
// #define ADDRESS "10.1.0.208:1883"
// #define CLIENTID "test1123"
// #define TOPIC "hasp/plate35/"
#define QOS 1
#define TIMEOUT 1000L
char mqttNodeTopic[24] = "hasp/plate35/";
const char* mqttGroupTopic = "hasp/plates/";
// char mqttNodeTopic[24];
// char mqttGroupTopic[24];
std::string mqttNodeTopic;
std::string mqttGroupTopic;
std::string mqttLwtTopic;
bool mqttEnabled = false;
bool mqttHAautodiscover = true;
uint32_t mqttPublishCount;
uint32_t mqttReceiveCount;
uint32_t mqttFailedCount;
////////////////////////////////////////////////////////////////////////////////////////////////////
// These defaults may be overwritten with values saved by the web interface
#ifndef MQTT_HOST
#define MQTT_HOST "";
#endif
#ifndef MQTT_PORT
#define MQTT_PORT 1883;
#endif
#ifndef MQTT_USER
#define MQTT_USER "";
#endif
#ifndef MQTT_PASSW
#define MQTT_PASSW "";
#endif
#ifndef MQTT_NODENAME
#define MQTT_NODENAME "";
#endif
#ifndef MQTT_GROUPNAME
#define MQTT_GROUPNAME "";
#endif
#ifndef MQTT_PREFIX
#define MQTT_PREFIX "hasp"
#endif
#define LWT_TOPIC "LWT"
char mqttServer[16] = MQTT_HOST;
char mqttUser[23] = MQTT_USER;
char mqttPassword[32] = MQTT_PASSW;
// char mqttNodeName[16] = MQTT_NODENAME;
char mqttGroupName[16] = MQTT_GROUPNAME;
uint16_t mqttPort = MQTT_PORT;
std::string mqttServer = MQTT_HOST;
std::string mqttUser = MQTT_USER;
std::string mqttPassword = MQTT_PASSW;
std::string mqttGroupName = MQTT_GROUPNAME;
uint16_t mqttPort = MQTT_PORT;
MQTTClient mqtt_client;
@ -120,29 +89,41 @@ void connlost(void* context, char* cause)
}
// Receive incoming messages
static void mqtt_message_cb(char* topic, char* payload, unsigned int length)
static void mqtt_message_cb(char* topic, char* payload, size_t length)
{ // Handle incoming commands from MQTT
if(length + 1 >= MQTT_MAX_PACKET_SIZE) {
LOG_ERROR(TAG_MQTT_RCV, F(D_MQTT_PAYLOAD_TOO_LONG), length);
mqttFailedCount++;
LOG_ERROR(TAG_MQTT_RCV, F(D_MQTT_PAYLOAD_TOO_LONG), (uint32_t)length);
return;
} else {
mqttReceiveCount++;
payload[length] = '\0';
}
LOG_TRACE(TAG_MQTT_RCV, F("%s = %s"), topic, (char*)payload);
if(topic == strstr(topic, mqttNodeTopic)) { // startsWith mqttNodeTopic
if(topic == strstr(topic, mqttNodeTopic.c_str())) { // startsWith mqttNodeTopic
// Node topic
topic += strlen(mqttNodeTopic); // shorten topic
topic += mqttNodeTopic.length(); // shorten topic
} else if(topic == strstr(topic, mqttGroupTopic)) { // startsWith mqttGroupTopic
} else if(topic == strstr(topic, mqttGroupTopic.c_str())) { // startsWith mqttGroupTopic
// Group topic
topic += strlen(mqttGroupTopic); // shorten topic
dispatch_topic_payload(topic, (const char*)payload);
topic += mqttGroupTopic.length(); // shorten topic
dispatch_topic_payload(topic, (const char*)payload, length > 0);
return;
#ifdef HASP_USE_BROADCAST
} else if(topic == strstr_P(topic, PSTR(MQTT_PREFIX "/" MQTT_TOPIC_BROADCAST
"/"))) { // /" MQTT_TOPIC_BROADCAST "/ discovery topic
// /" MQTT_TOPIC_BROADCAST "/ topic
topic += strlen(MQTT_PREFIX "/" MQTT_TOPIC_BROADCAST "/"); // shorten topic
dispatch_topic_payload(topic, (const char*)payload, length > 0);
return;
#endif
#ifdef HASP_USE_HA
} else if(topic == strstr_P(topic, PSTR("homeassistant/status"))) { // HA discovery topic
if(mqttHAautodiscover && !strcasecmp_P((char*)payload, PSTR("online"))) {
@ -159,31 +140,24 @@ static void mqtt_message_cb(char* topic, char* payload, unsigned int length)
}
// catch a dangling LWT from a previous connection if it appears
if(!strcmp_P(topic, PSTR(LWT_TOPIC))) { // endsWith LWT
if(!strcmp_P(topic, PSTR(MQTT_TOPIC_LWT))) { // endsWith LWT
if(!strcasecmp_P((char*)payload, PSTR("offline"))) {
{
char msg[8];
char tmp_topic[strlen(mqttNodeTopic) + 8];
snprintf_P(tmp_topic, sizeof(tmp_topic), PSTR("%s" LWT_TOPIC), mqttNodeTopic);
snprintf_P(msg, sizeof(msg), PSTR("online"));
// /*bool res =*/mqttClient.publish(tmp_topic, msg, true);
mqttPublish(tmp_topic, msg, strlen(msg), true);
mqttPublish(mqttLwtTopic.c_str(), msg, strlen(msg), true);
}
} else {
// LOG_TRACE(TAG_MQTT, F("ignoring LWT = online"));
}
} else {
dispatch_topic_payload(topic, (const char*)payload);
dispatch_topic_payload(topic, (const char*)payload, length > 0);
}
}
int msgarrvd(void* context, char* topicName, int topicLen, MQTTClient_message* message)
int mqtt_message_arrived(void* context, char* topicName, int topicLen, MQTTClient_message* message)
{
// printf("MQT RCV >> ");
// printf("%s => %.*s (%d)\n", topicName, message->payloadlen, (char *)message->payload, message->payloadlen);
char msg[message->payloadlen + 1];
memcpy(msg, (char*)message->payload, message->payloadlen);
msg[message->payloadlen] = '\0';
@ -200,10 +174,10 @@ void mqtt_subscribe(void* context, const char* topic)
MQTTClient client = (MQTTClient)context;
int rc;
printf("Subscribing to topic %s\n", topic);
//\nfor client %s using QoS%d\n\n", topic, CLIENTID, QOS);
if((rc = MQTTClient_subscribe(client, topic, QOS)) != MQTTCLIENT_SUCCESS) {
printf("Failed to start subscribe, return code %d\n", rc);
LOG_WARNING(TAG_MQTT, D_BULLET D_MQTT_NOT_SUBSCRIBED, topic); // error code rc
} else {
LOG_VERBOSE(TAG_MQTT, D_BULLET D_MQTT_SUBSCRIBED, topic);
}
}
@ -211,7 +185,12 @@ void mqtt_subscribe(void* context, const char* topic)
int mqttPublish(const char* topic, const char* payload, size_t len, bool retain)
{
if(!mqttIsConnected()) return MQTT_ERR_NO_CONN;
if(!mqttEnabled) return MQTT_ERR_DISABLED;
if(!mqttIsConnected()) {
mqttFailedCount++;
return MQTT_ERR_NO_CONN;
}
MQTTClient_message pubmsg = MQTTClient_message_initializer;
MQTTClient_deliveryToken token;
@ -222,41 +201,46 @@ int mqttPublish(const char* topic, const char* payload, size_t len, bool retain)
pubmsg.retained = retain;
MQTTClient_publishMessage(mqtt_client, topic, &pubmsg, &token);
int rc = MQTTClient_waitForCompletion(mqtt_client, token, TIMEOUT);
int rc = MQTTClient_waitForCompletion(mqtt_client, token, TIMEOUT); // time to wait in milliseconds
if(rc != MQTTCLIENT_SUCCESS) {
mqttFailedCount++;
LOG_ERROR(TAG_MQTT_PUB, F(D_MQTT_FAILED " '%s' => %s"), topic, payload);
return MQTT_ERR_PUB_FAIL;
} else {
// LOG_TRACE(TAG_MQTT_PUB, F("'%s' => %s OK"), topic, payload);
mqttPublishCount++;
return MQTT_ERR_OK;
}
}
// static bool mqttPublish(const char* topic, const char* payload, bool retain)
// {
// return mqttPublish(topic, payload, strlen(payload), retain);
// }
/* ===== Public HASP MQTT functions ===== */
bool mqttIsConnected()
{
return connected == 1;
return MQTTClient_isConnected(mqtt_client);
}
int mqtt_send_state(const __FlashStringHelper* subtopic, const char* payload)
{
char tmp_topic[strlen(mqttNodeTopic) + 20];
// printf(("%sstate/%s\n"), mqttNodeTopic, subtopic);
snprintf_P(tmp_topic, sizeof(tmp_topic), ("%sstate/%s"), mqttNodeTopic, subtopic);
char tmp_topic[mqttNodeTopic.length() + 20];
// printf(("%s" MQTT_TOPIC_STATE "/%s\n"), mqttNodeTopic, subtopic);
snprintf_P(tmp_topic, sizeof(tmp_topic), ("%s" MQTT_TOPIC_STATE "/%s"), mqttNodeTopic.c_str(), subtopic);
return mqttPublish(tmp_topic, payload, strlen(payload), false);
}
int mqtt_send_discovery(const char* payload, size_t len)
{
char tmp_topic[20];
snprintf_P(tmp_topic, sizeof(tmp_topic), PSTR(MQTT_PREFIX "/" MQTT_TOPIC_DISCOVERY));
return mqttPublish(tmp_topic, payload, len, false);
}
int mqtt_send_object_state(uint8_t pageid, uint8_t btnid, const char* payload)
{
char tmp_topic[strlen(mqttNodeTopic) + 20];
snprintf_P(tmp_topic, sizeof(tmp_topic), PSTR("%sstate/p%ub%u"), mqttNodeTopic, pageid, btnid);
char tmp_topic[mqttNodeTopic.length() + 20];
snprintf_P(tmp_topic, sizeof(tmp_topic), PSTR("%s" MQTT_TOPIC_STATE "/p%ub%u"), mqttNodeTopic.c_str(), pageid,
btnid);
return mqttPublish(tmp_topic, payload, strlen(payload), false);
}
@ -264,35 +248,47 @@ static void onConnect(void* context)
{
MQTTClient client = (MQTTClient)context;
connected = 1;
std::string topic;
printf("Successful connection\n");
LOG_VERBOSE(TAG_MQTT, D_MQTT_CONNECTED, mqttServer.c_str(), haspDevice.get_hostname());
mqtt_subscribe(mqtt_client, TOPIC "command/#");
// mqtt_subscribe(mqtt_client, TOPIC "command");
mqtt_subscribe(mqtt_client, TOPIC "light/#");
mqtt_subscribe(mqtt_client, TOPIC "brightness/#");
mqtt_subscribe(mqtt_client, "hass/status");
topic = mqttGroupTopic + MQTT_TOPIC_COMMAND "/#";
mqtt_subscribe(mqtt_client, topic.c_str());
topic = mqttNodeTopic + MQTT_TOPIC_COMMAND "/#";
mqtt_subscribe(mqtt_client, topic.c_str());
topic = mqttGroupTopic + "config/#";
mqtt_subscribe(mqtt_client, topic.c_str());
topic = mqttNodeTopic + "config/#";
mqtt_subscribe(mqtt_client, topic.c_str());
#ifdef HASP_USE_BROADCAST
topic = MQTT_PREFIX "/" MQTT_TOPIC_BROADCAST "/" MQTT_TOPIC_COMMAND "/#";
mqtt_subscribe(mqtt_client, topic.c_str());
#endif
/* Home Assistant auto-configuration */
#ifdef HASP_USE_HA
if(mqttHAautodiscover) mqtt_subscribe(mqtt_client, "homeassistant/status");
topic = "homeassistant/status";
mqtt_subscribe(mqtt_client, topic.c_str());
#endif
mqttPublish(TOPIC LWT_TOPIC, "online", 6, true);
mqtt_send_object_state(0, 0, "connected");
std::cout << std::endl;
mqttPublish(mqttLwtTopic.c_str(), "online", 6, true);
}
void mqttStart()
{
printf("%s %d\n", __FILE__, __LINE__);
MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer;
MQTTClient_willOptions will_opts = MQTTClient_willOptions_initializer;
int rc;
int ch;
if((rc = MQTTClient_create(&mqtt_client, ADDRESS, CLIENTID, MQTTCLIENT_PERSISTENCE_NONE, NULL)) !=
MQTTCLIENT_SUCCESS) {
printf("%s %d\n", __FILE__, __LINE__);
if((rc = MQTTClient_create(&mqtt_client, mqttServer.c_str(), haspDevice.get_hostname(), MQTTCLIENT_PERSISTENCE_NONE,
NULL)) != MQTTCLIENT_SUCCESS) {
printf("Failed to create client, return code %d\n", rc);
rc = EXIT_FAILURE;
return;
@ -304,26 +300,39 @@ void mqttStart()
// return;
// }
conn_opts.will = &will_opts;
conn_opts.will->message = "offline";
conn_opts.will->qos = 1;
conn_opts.will->retained = 1;
conn_opts.will->topicName = "hasp/plate35/LWT";
printf("%s %d\n", __FILE__, __LINE__);
mqttEnabled = mqttServer.length() > 0 && mqttPort > 0;
conn_opts.keepAliveInterval = 20;
conn_opts.cleansession = 1;
if(mqttEnabled) {
conn_opts.will = &will_opts;
conn_opts.will->message = "offline";
conn_opts.will->qos = 1;
conn_opts.will->retained = 1;
conn_opts.will->topicName = mqttLwtTopic.c_str();
conn_opts.username = "hasp";
conn_opts.password = "hasp";
conn_opts.keepAliveInterval = 20;
conn_opts.cleansession = 1;
conn_opts.connectTimeout = 2; // seconds
conn_opts.retryInterval = 0; // no retry
if((rc = MQTTClient_connect(mqtt_client, &conn_opts)) != MQTTCLIENT_SUCCESS) {
printf("Failed to start connect, return code %d\n", rc);
rc = EXIT_FAILURE;
// goto destroy_exit;
conn_opts.username = mqttUser.c_str();
conn_opts.password = mqttPassword.c_str();
printf("%s %d\n", __FILE__, __LINE__);
if((rc = MQTTClient_connect(mqtt_client, &conn_opts)) != MQTTCLIENT_SUCCESS) {
printf("Failed to connect, return code %d\n", rc);
rc = EXIT_FAILURE;
// goto destroy_exit;
} else {
onConnect(&mqtt_client);
}
} else {
onConnect(&mqtt_client);
rc = EXIT_FAILURE;
printf("Mqtt server not configured\n");
}
printf("%s %d\n", __FILE__, __LINE__);
// while (!subscribed && !finished)
// #if defined(_WIN32)
// Sleep(100);
@ -342,7 +351,7 @@ void mqttStop()
// disc_opts.onSuccess = onDisconnect;
// disc_opts.onFailure = onDisconnectFailure;
if((rc = MQTTClient_disconnect(mqtt_client, 1000)) != MQTTCLIENT_SUCCESS) {
printf("Failed to start disconnect, return code %d\n", rc);
printf("Failed to disconnect, return code %d\n", rc);
rc = EXIT_FAILURE;
// goto destroy_exit;
}
@ -361,19 +370,59 @@ void mqttStop()
// return rc;
}
void mqttSetup(){};
char* topicName;
int topicLen;
MQTTClient_message* message;
void mqttLoop()
void mqttSetup()
{
printf("%s %d\n", __FILE__, __LINE__);
mqttNodeTopic = MQTT_PREFIX;
mqttNodeTopic += "/";
mqttNodeTopic += haspDevice.get_hostname();
mqttNodeTopic += "/";
printf("%s %d\n", __FILE__, __LINE__);
mqttGroupTopic = MQTT_PREFIX;
mqttGroupTopic += "/";
mqttGroupTopic += mqttGroupName;
mqttGroupTopic += "/";
printf("%s %d\n", __FILE__, __LINE__);
mqttLwtTopic = mqttNodeTopic;
mqttLwtTopic += MQTT_TOPIC_LWT;
printf("%s %d\n", __FILE__, __LINE__);
}
IRAM_ATTR void mqttLoop()
{
int topicLen;
char* topicName; // Freed by msgarrvd
MQTTClient_message* message; // Freed by msgarrvd
int rc = MQTTClient_receive(mqtt_client, &topicName, &topicLen, &message, 4);
if(rc == MQTTCLIENT_SUCCESS && message) msgarrvd(mqtt_client, topicName, topicLen, message);
if(rc == MQTTCLIENT_SUCCESS && message) mqtt_message_arrived(mqtt_client, topicName, topicLen, message);
};
void mqttEvery5Seconds(bool wifiIsConnected){};
void mqtt_get_info(JsonDocument& doc)
{
char mqttClientId[64];
JsonObject info = doc.createNestedObject(F("MQTT"));
info[F(D_INFO_SERVER)] = mqttServer;
info[F(D_INFO_USERNAME)] = mqttUser;
info[F(D_INFO_CLIENTID)] = haspDevice.get_hostname();
if(mqttIsConnected()) { // Check MQTT connection
info[F(D_INFO_STATUS)] = F(D_INFO_CONNECTED);
} else {
info[F(D_INFO_STATUS)] = F("<font color='red'><b>" D_INFO_DISCONNECTED "</b></font>, return code: ");
// +String(mqttClient.returnCode());
}
info[F(D_INFO_RECEIVED)] = mqttReceiveCount;
info[F(D_INFO_PUBLISHED)] = mqttPublishCount;
info[F(D_INFO_FAILED)] = mqttFailedCount;
}
#endif // USE_PAHO
#endif // USE_MQTT

View File

@ -50,60 +50,35 @@ char mqttNodeTopic[24];
char mqttGroupTopic[24];
bool mqttEnabled = false;
bool mqttHAautodiscover = true;
uint32_t mqttPublishCount;
uint32_t mqttReceiveCount;
uint32_t mqttFailedCount;
////////////////////////////////////////////////////////////////////////////////////////////////////
// These defaults may be overwritten with values saved by the web interface
#ifndef MQTT_HOST
#define MQTT_HOST "";
#endif
#ifndef MQTT_PORT
#define MQTT_PORT 1883;
#endif
#ifndef MQTT_USER
#define MQTT_USER "";
#endif
#ifndef MQTT_PASSW
#define MQTT_PASSW "";
#endif
#ifndef MQTT_NODENAME
#define MQTT_NODENAME "";
#endif
#ifndef MQTT_GROUPNAME
#define MQTT_GROUPNAME "";
#endif
#ifndef MQTT_PREFIX
#define MQTT_PREFIX "hasp"
#endif
#define LWT_TOPIC "LWT"
// char mqttServer[16] = MQTT_HOST;
// char mqttUser[23] = MQTT_USER;
// char mqttPassword[32] = MQTT_PASSW;
// char mqttGroupName[16] = MQTT_GROUPNAME;
std::string mqttServer = MQTT_HOST;
std::string mqttUser = MQTT_USER;
std::string mqttPassword = MQTT_PASSW;
std::string mqttGroupName = MQTT_GROUPNAME;
uint16_t mqttPort = MQTT_PORT;
char mqttServer[16] = MQTT_HOST;
char mqttUser[23] = MQTT_USER;
char mqttPassword[32] = MQTT_PASSW;
// char mqttNodeName[16] = MQTT_NODENAME;
char mqttGroupName[16] = MQTT_GROUPNAME;
uint16_t mqttPort = MQTT_PORT;
PubSubClient mqttClient(mqttNetworkClient);
int mqttPublish(const char* topic, const char* payload, size_t len, bool retain)
{
if(!mqttEnabled) return MQTT_ERR_DISABLED;
if(!mqttClient.connected()) return MQTT_ERR_NO_CONN;
if(!mqttClient.connected()) {
mqttFailedCount++;
return MQTT_ERR_NO_CONN;
}
if(mqttClient.beginPublish(topic, len, retain)) {
mqttPublishCount++;
mqttClient.write((uint8_t*)payload, len);
mqttClient.endPublish();
return MQTT_ERR_OK;
}
mqttFailedCount++;
return MQTT_ERR_PUB_FAIL;
}
@ -125,8 +100,8 @@ bool mqtt_send_lwt(bool online)
char tmp_payload[8];
char tmp_topic[strlen(mqttNodeTopic) + 4];
strncpy(tmp_topic, mqttNodeTopic, sizeof(tmp_topic));
strncat_P(tmp_topic, PSTR(LWT_TOPIC), sizeof(tmp_topic));
// snprintf_P(tmp_topic, sizeof(tmp_topic), PSTR("%s" LWT_TOPIC), mqttNodeTopic);
strncat_P(tmp_topic, PSTR(MQTT_TOPIC_LWT), sizeof(tmp_topic));
// snprintf_P(tmp_topic, sizeof(tmp_topic), PSTR("%s" MQTT_TOPIC_LWT), mqttNodeTopic);
size_t len = snprintf_P(tmp_payload, sizeof(tmp_payload), online ? PSTR("online") : PSTR("offline"));
bool res = mqttPublish(tmp_topic, tmp_payload, len, true);
@ -137,25 +112,35 @@ bool mqtt_send_lwt(bool online)
int mqtt_send_object_state(uint8_t pageid, uint8_t btnid, const char* payload)
{
char tmp_topic[strlen(mqttNodeTopic) + 16];
snprintf_P(tmp_topic, sizeof(tmp_topic), PSTR("%sstate/" HASP_OBJECT_NOTATION), mqttNodeTopic, pageid, btnid);
snprintf_P(tmp_topic, sizeof(tmp_topic), PSTR("%s" MQTT_TOPIC_STATE "/" HASP_OBJECT_NOTATION), mqttNodeTopic,
pageid, btnid);
return mqttPublish(tmp_topic, payload, false);
}
int mqtt_send_state(const char* subtopic, const char* payload)
{
char tmp_topic[strlen(mqttNodeTopic) + 20];
snprintf_P(tmp_topic, sizeof(tmp_topic), PSTR("%sstate/%s"), mqttNodeTopic, subtopic);
snprintf_P(tmp_topic, sizeof(tmp_topic), PSTR("%s" MQTT_TOPIC_STATE "/%s"), mqttNodeTopic, subtopic);
return mqttPublish(tmp_topic, payload, false);
}
int mqtt_send_discovery(const char* payload, size_t len)
{
char tmp_topic[20];
snprintf_P(tmp_topic, sizeof(tmp_topic), PSTR(MQTT_PREFIX "/" MQTT_TOPIC_DISCOVERY));
return mqttPublish(tmp_topic, payload, len, false);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// Receive incoming messages
static void mqtt_message_cb(char* topic, byte* payload, unsigned int length)
{ // Handle incoming commands from MQTT
if(length + 1 >= mqttClient.getBufferSize()) {
LOG_ERROR(TAG_MQTT_RCV, F(D_MQTT_PAYLOAD_TOO_LONG), length);
mqttFailedCount++;
LOG_ERROR(TAG_MQTT_RCV, F(D_MQTT_PAYLOAD_TOO_LONG), (uint32_t)length);
return;
} else {
mqttReceiveCount++;
payload[length] = '\0';
}
@ -170,9 +155,18 @@ static void mqtt_message_cb(char* topic, byte* payload, unsigned int length)
// Group topic
topic += strlen(mqttGroupTopic); // shorten topic
dispatch_topic_payload(topic, (const char*)payload);
dispatch_topic_payload(topic, (const char*)payload, length > 0);
return;
#ifdef HASP_USE_BROADCAST
} else if(topic == strstr_P(topic, PSTR(MQTT_PREFIX "/" MQTT_TOPIC_BROADCAST "/"))) { // broadcast topic
// Broadcast topic
topic += strlen_P(PSTR(MQTT_PREFIX "/" MQTT_TOPIC_BROADCAST "/")); // shorten topic
dispatch_topic_payload(topic, (const char*)payload, length > 0);
return;
#endif
#ifdef HASP_USE_HA
} else if(topic == strstr_P(topic, PSTR("homeassistant/status"))) { // HA discovery topic
if(mqttHAautodiscover && !strcasecmp_P((char*)payload, PSTR("online"))) {
@ -189,34 +183,36 @@ static void mqtt_message_cb(char* topic, byte* payload, unsigned int length)
}
// catch a dangling LWT from a previous connection if it appears
if(!strcmp_P(topic, PSTR(LWT_TOPIC))) { // endsWith LWT
if(!strcasecmp_P((char*)payload, PSTR("offline"))) {
{
char msg[8];
char tmp_topic[strlen(mqttNodeTopic) + 8];
snprintf_P(tmp_topic, sizeof(tmp_topic), PSTR("%s" LWT_TOPIC), mqttNodeTopic);
snprintf_P(msg, sizeof(msg), PSTR("online"));
/* if(!strcmp_P(topic, PSTR(MQTT_TOPIC_LWT))) { // endsWith LWT
if(!strcasecmp_P((char*)payload, PSTR("offline"))) {
{
char msg[8];
char tmp_topic[strlen(mqttNodeTopic) + 8];
snprintf_P(tmp_topic, sizeof(tmp_topic), PSTR("%s" MQTT_TOPIC_LWT), mqttNodeTopic);
snprintf_P(msg, sizeof(msg), PSTR("online"));
// /*bool res =*/mqttClient.publish(tmp_topic, msg, true);
mqttPublish(tmp_topic, msg, true);
}
} else {
// LOG_TRACE(TAG_MQTT, F("ignoring LWT = online"));
}
} else {
dispatch_topic_payload(topic, (const char*)payload);
// bool res =
mqttClient.publish(tmp_topic, msg, true);
mqttPublish(tmp_topic, msg, true);
}
}
else
{
// LOG_TRACE(TAG_MQTT, F("ignoring LWT = online"));
}
}
else */
{
dispatch_topic_payload(topic, (const char*)payload, length > 0);
}
}
static void mqttSubscribeTo(const __FlashStringHelper* format, const char* data)
static void mqttSubscribeTo(const char* topic)
{
char tmp_topic[strlen_P((PGM_P)format) + 2 + strlen(data)];
snprintf_P(tmp_topic, sizeof(tmp_topic), (PGM_P)format, data);
if(mqttClient.subscribe(tmp_topic)) {
LOG_VERBOSE(TAG_MQTT, F(D_BULLET D_MQTT_SUBSCRIBED), tmp_topic);
if(mqttClient.subscribe(topic)) {
LOG_VERBOSE(TAG_MQTT, F(D_BULLET D_MQTT_SUBSCRIBED), topic);
} else {
LOG_ERROR(TAG_MQTT, F(D_MQTT_NOT_SUBSCRIBED), tmp_topic);
LOG_ERROR(TAG_MQTT, F(D_MQTT_NOT_SUBSCRIBED), topic);
}
}
@ -228,7 +224,7 @@ void mqttStart()
static uint8_t mqttReconnectCount = 0;
// bool mqttFirstConnect = true;
mqttClient.setServer(mqttServer.c_str(), 1883);
mqttClient.setServer(mqttServer, 1883);
// mqttClient.setSocketTimeout(10); //in seconds
/* Construct unique Client ID*/
@ -241,13 +237,12 @@ void mqttStart()
}
// Attempt to connect and set LWT and Clean Session
snprintf_P(buffer, sizeof(buffer), PSTR("%s" LWT_TOPIC), mqttNodeTopic); // lastWillTopic
snprintf_P(lastWillPayload, sizeof(lastWillPayload), PSTR("offline")); // lastWillPayload
snprintf_P(buffer, sizeof(buffer), PSTR("%s" MQTT_TOPIC_LWT), mqttNodeTopic); // lastWillTopic
snprintf_P(lastWillPayload, sizeof(lastWillPayload), PSTR("offline")); // lastWillPayload
haspProgressMsg(F(D_MQTT_CONNECTING));
haspProgressVal(mqttReconnectCount * 5);
if(!mqttClient.connect(mqttClientId, mqttUser.c_str(), mqttPassword.c_str(), buffer, 0, true, lastWillPayload,
true)) {
if(!mqttClient.connect(mqttClientId, mqttUser, mqttPassword, buffer, 0, true, lastWillPayload, true)) {
// Retry until we give up and restart after connectTimeout seconds
mqttReconnectCount++;
@ -292,19 +287,22 @@ void mqttStart()
return;
}
LOG_INFO(TAG_MQTT, F(D_MQTT_CONNECTED), mqttServer.c_str(), mqttClientId);
LOG_INFO(TAG_MQTT, F(D_MQTT_CONNECTED), mqttServer, mqttClientId);
// Subscribe to our incoming topics
const __FlashStringHelper* F_topic;
F_topic = F("%scommand/#");
mqttSubscribeTo(F_topic, mqttGroupTopic);
mqttSubscribeTo(F_topic, mqttNodeTopic);
F_topic = F("%sconfig/#");
mqttSubscribeTo(F_topic, mqttGroupTopic);
mqttSubscribeTo(F_topic, mqttNodeTopic);
// mqttSubscribeTo(F("%slight/#"), mqttNodeTopic);
// mqttSubscribeTo(F("%sbrightness/#"), mqttNodeTopic);
// mqttSubscribeTo(F("%s"LWT_TOPIC), mqttNodeTopic);
char topic[64];
snprintf_P(topic, sizeof(topic), PSTR("%s" MQTT_TOPIC_COMMAND "/#"), mqttGroupTopic);
mqttSubscribeTo(topic);
snprintf_P(topic, sizeof(topic), PSTR("%s" MQTT_TOPIC_COMMAND "/#"), mqttNodeTopic);
mqttSubscribeTo(topic);
// F_topic = F("%sconfig/#");
// mqttSubscribeTo(F_topic, mqttGroupTopic);
// mqttSubscribeTo(F("%s"MQTT_TOPIC_LWT), mqttNodeTopic);
#ifdef HASP_USE_BROADCAST
snprintf_P(topic, sizeof(topic), PSTR(MQTT_PREFIX "/" MQTT_TOPIC_BROADCAST "/" MQTT_TOPIC_COMMAND "/#"));
mqttSubscribeTo(topic);
#endif
/* Home Assistant auto-configuration */
#ifdef HASP_USE_HA
@ -328,9 +326,9 @@ void mqttStart()
void mqttSetup()
{
mqttEnabled = mqttServer.length() > 0 && mqttPort > 0;
mqttEnabled = strlen(mqttServer) > 0 && mqttPort > 0;
if(mqttEnabled) {
mqttClient.setServer(mqttServer.c_str(), mqttPort);
mqttClient.setServer(mqttServer, mqttPort);
mqttClient.setCallback(mqtt_message_cb);
// if(!mqttClient.setBufferSize(1024)) {
// LOG_ERROR(TAG_MQTT, F("Buffer allocation failed"));
@ -342,9 +340,10 @@ void mqttSetup()
}
}
void mqttLoop(void)
IRAM_ATTR void mqttLoop(void)
{
if(mqttEnabled) mqttClient.loop();
// if(mqttEnabled)
mqttClient.loop();
}
void mqttEvery5Seconds(bool networkIsConnected)
@ -370,6 +369,33 @@ void mqttStop()
}
}
void mqtt_get_info(JsonDocument& doc)
{
char mqttClientId[64];
String mac((char*)0);
mac.reserve(64);
JsonObject info = doc.createNestedObject(F("MQTT"));
info[F(D_INFO_SERVER)] = mqttServer;
info[F(D_INFO_USERNAME)] = mqttUser;
mac = halGetMacAddress(3, "");
mac.toLowerCase();
snprintf_P(mqttClientId, sizeof(mqttClientId), PSTR("%s-%s"), haspDevice.get_hostname(), mac.c_str());
info[F(D_INFO_CLIENTID)] = mqttClientId;
if(mqttIsConnected()) { // Check MQTT connection
info[F(D_INFO_STATUS)] = F(D_INFO_CONNECTED);
} else {
info[F(D_INFO_STATUS)] = F("<font color='red'><b>" D_INFO_DISCONNECTED "</b></font>, return code: ");
// +String(mqttClient.returnCode());
}
info[F(D_INFO_RECEIVED)] = mqttReceiveCount;
info[F(D_INFO_PUBLISHED)] = mqttPublishCount;
info[F(D_INFO_FAILED)] = mqttFailedCount;
}
#if HASP_USE_CONFIG > 0
bool mqttGetConfig(const JsonObject& settings)
{
@ -378,19 +404,19 @@ bool mqttGetConfig(const JsonObject& settings)
if(strcmp(haspDevice.get_hostname(), settings[FPSTR(FP_CONFIG_NAME)].as<String>().c_str()) != 0) changed = true;
settings[FPSTR(FP_CONFIG_NAME)] = haspDevice.get_hostname();
if(mqttGroupName != settings[FPSTR(FP_CONFIG_GROUP)].as<std::string>()) changed = true;
if(strcmp(mqttGroupName, settings[FPSTR(FP_CONFIG_GROUP)].as<String>().c_str()) != 0) changed = true;
settings[FPSTR(FP_CONFIG_GROUP)] = mqttGroupName;
if(mqttServer != settings[FPSTR(FP_CONFIG_HOST)].as<std::string>()) changed = true;
if(strcmp(mqttServer, settings[FPSTR(FP_CONFIG_HOST)].as<String>().c_str()) != 0) changed = true;
settings[FPSTR(FP_CONFIG_HOST)] = mqttServer;
if(mqttPort != settings[FPSTR(FP_CONFIG_PORT)].as<uint16_t>()) changed = true;
settings[FPSTR(FP_CONFIG_PORT)] = mqttPort;
if(mqttUser != settings[FPSTR(FP_CONFIG_USER)].as<String>().c_str()) changed = true;
if(strcmp(mqttUser, settings[FPSTR(FP_CONFIG_USER)].as<String>().c_str()) != 0) changed = true;
settings[FPSTR(FP_CONFIG_USER)] = mqttUser;
if(mqttPassword != settings[FPSTR(FP_CONFIG_PASS)].as<String>().c_str()) changed = true;
if(strcmp(mqttPassword, settings[FPSTR(FP_CONFIG_PASS)].as<String>().c_str()) != 0) changed = true;
settings[FPSTR(FP_CONFIG_PASS)] = mqttPassword;
if(changed) configOutput(settings, TAG_MQTT);
@ -428,33 +454,33 @@ bool mqttSetConfig(const JsonObject& settings)
}
if(!settings[FPSTR(FP_CONFIG_GROUP)].isNull()) {
changed |= mqttGroupName != settings[FPSTR(FP_CONFIG_GROUP)].as<std::string>();
mqttGroupName = settings[FPSTR(FP_CONFIG_GROUP)].as<std::string>();
changed |= strcmp(mqttGroupName, settings[FPSTR(FP_CONFIG_GROUP)]) != 0;
strncpy(mqttGroupName, settings[FPSTR(FP_CONFIG_GROUP)], sizeof(mqttGroupName));
}
if(mqttGroupName.length() == 0) {
mqttGroupName = String(F("plates")).c_str();
changed = true;
if(strlen(mqttGroupName) == 0) {
strcpy_P(mqttGroupName, PSTR("plates"));
changed = true;
}
if(!settings[FPSTR(FP_CONFIG_HOST)].isNull()) {
changed |= mqttServer != settings[FPSTR(FP_CONFIG_HOST)].as<std::string>();
mqttServer = settings[FPSTR(FP_CONFIG_HOST)].as<std::string>();
changed |= strcmp(mqttServer, settings[FPSTR(FP_CONFIG_HOST)]) != 0;
strncpy(mqttServer, settings[FPSTR(FP_CONFIG_HOST)], sizeof(mqttServer));
}
if(!settings[FPSTR(FP_CONFIG_USER)].isNull()) {
changed |= mqttUser != settings[FPSTR(FP_CONFIG_USER)].as<std::string>();
mqttUser = settings[FPSTR(FP_CONFIG_USER)].as<std::string>();
changed |= strcmp(mqttUser, settings[FPSTR(FP_CONFIG_USER)]) != 0;
strncpy(mqttUser, settings[FPSTR(FP_CONFIG_USER)], sizeof(mqttUser));
}
if(!settings[FPSTR(FP_CONFIG_PASS)].isNull() &&
settings[FPSTR(FP_CONFIG_PASS)].as<String>() != String(FPSTR(D_PASSWORD_MASK))) {
changed |= mqttPassword != settings[FPSTR(FP_CONFIG_PASS)].as<std::string>();
mqttPassword = settings[FPSTR(FP_CONFIG_PASS)].as<std::string>();
changed |= strcmp(mqttPassword, settings[FPSTR(FP_CONFIG_PASS)]) != 0;
strncpy(mqttPassword, settings[FPSTR(FP_CONFIG_PASS)], sizeof(mqttPassword));
}
snprintf_P(mqttNodeTopic, sizeof(mqttNodeTopic), PSTR(MQTT_PREFIX "/%s/"), haspDevice.get_hostname());
snprintf_P(mqttGroupTopic, sizeof(mqttGroupTopic), PSTR(MQTT_PREFIX "/%s/"), mqttGroupName.c_str());
snprintf_P(mqttGroupTopic, sizeof(mqttGroupTopic), PSTR(MQTT_PREFIX "/%s/"), mqttGroupName);
return changed;
}

File diff suppressed because it is too large Load Diff

View File

@ -4,7 +4,12 @@
#ifndef HASP_GPIO_H
#define HASP_GPIO_H
#include "ArduinoJson.h"
#include "hasplib.h"
#ifdef ARDUINO
#include "AceButton.h"
using namespace ace_button;
#endif
#ifdef __cplusplus
extern "C" {
@ -12,27 +17,38 @@ extern "C" {
struct hasp_gpio_config_t
{
uint8_t pin; // pin number
uint8_t group; // groupid
uint8_t type; // switch, button, ...
uint8_t gpio_function; // INPUT, OUTPUT, PULLUP, etc
uint8_t pin : 8; // pin number
uint8_t group : 8; // groupid
uint8_t gpio_function : 7; // INPUT, OUTPUT, PULLUP, etc
uint8_t inverted : 1;
uint8_t channel : 4; // pwmchannel
uint8_t power : 1;
uint8_t type; // switch, button, ...
uint16_t val;
uint16_t max;
#ifdef ARDUINO
AceButton* btn;
#endif
};
void gpioSetup(void);
void gpioLoop(void);
IRAM_ATTR void gpioLoop(void);
void gpioEvery5Seconds(void);
// void gpio_set_group_onoff(uint8_t groupid, bool ison);
void gpio_set_normalized_group_value(uint8_t groupid, int16_t val, int16_t min, int16_t max);
// void gpio_set_gpio_state(uint8_t pin, uint16_t state);
void gpio_get_value(uint8_t pin);
void gpio_set_value(uint8_t pin, int16_t val);
void gpio_set_moodlight(uint8_t r, uint8_t g, uint8_t b);
void gpio_set_normalized_group_values(hasp_update_value_t& value);
void gpio_output_group_values(uint8_t group);
bool gpioSavePinConfig(uint8_t config_num, uint8_t pin, uint8_t type, uint8_t group, uint8_t pinfunc);
bool gpio_output_pin_state(uint8_t pin);
bool gpio_get_pin_state(uint8_t pin, bool& power, int32_t& val);
bool gpio_set_pin_state(uint8_t pin, bool power, int32_t val);
void gpio_set_moodlight(moodlight_t& moodlight);
void gpio_discovery(JsonObject& input, JsonArray& relay, JsonArray& light, JsonArray& dimmer);
bool gpioSavePinConfig(uint8_t config_num, uint8_t pin, uint8_t type, uint8_t group, uint8_t pinfunc, bool inverted);
bool gpioIsSystemPin(uint8_t gpio);
bool gpioInUse(uint8_t gpio);
bool gpioInUse(uint8_t pin);
bool gpioConfigInUse(uint8_t num);
int8_t gpioGetFreeConfigId();
hasp_gpio_config_t gpioGetPinConfig(uint8_t num);
@ -42,48 +58,89 @@ bool gpioGetConfig(const JsonObject& settings);
bool gpioSetConfig(const JsonObject& settings);
#endif
#define HASP_GPIO_FREE 0x00
#define HASP_GPIO_USED 0x01
#define HASP_GPIO_SWITCH 0x02 // User Inputs
#define HASP_GPIO_SWITCH_INVERTED 0x03
#define HASP_GPIO_BUTTON 0x04
#define HASP_GPIO_BUTTON_INVERTED 0x05
#define HASP_GPIO_TOUCH 0x06
#define HASP_GPIO_TOUCH_INVERTED 0x07
#define HASP_GPIO_COUNTER_RISE 0x10 // User Counters
#define HASP_GPIO_COUNTER_RISE_INVERTED 0x11
#define HASP_GPIO_COUNTER_FALL 0x12
#define HASP_GPIO_COUNTER_FALL_INVERTED 0x13
#define HASP_GPIO_COUNTER_BOTH 0x14
#define HASP_GPIO_COUNTER_BOTH_INVERTED 0x15
#define HASP_GPIO_RELAY 0x20 // User Outputs
#define HASP_GPIO_RELAY_INVERTED 0x21
#define HASP_GPIO_LED 0x22
#define HASP_GPIO_LED_INVERTED 0x23
#define HASP_GPIO_LED_R 0x24
#define HASP_GPIO_LED_R_INVERTED 0x25
#define HASP_GPIO_LED_G 0x26
#define HASP_GPIO_LED_G_INVERTED 0x27
#define HASP_GPIO_LED_B 0x28
#define HASP_GPIO_LED_B_INVERTED 0x29
#define HASP_GPIO_LED_W 0x2A
#define HASP_GPIO_LED_W_INVERTED 0x2B
#define HASP_GPIO_LED_WW 0x2C
#define HASP_GPIO_LED_WW_INVERTED 0x2D
#define HASP_GPIO_LED_CW 0x2E
#define HASP_GPIO_LED_CW_INVERTED 0x2F
#define HASP_GPIO_BUZZER 0x30
#define HASP_GPIO_BUZZER_INVERTED 0x31
#define HASP_GPIO_HAPTIC 0x32
#define HASP_GPIO_HAPTIC_INVERTED 0x33
#define HASP_GPIO_PWM 0x40
#define HASP_GPIO_PWM_INVERTED 0x41
#define HASP_GPIO_DAC 0x50
#define HASP_GPIO_DAC_INVERTED 0x51
#define HASP_GPIO_ADC 0x52
#define HASP_GPIO_ADC_INVERTED 0x53
#define HASP_GPIO_SERIAL_DIMMER 0x60
#define HASP_GPIO_USER 0xFF
enum hasp_gpio_function_t {
OUTPUT_PIN = 1,
INTERNAL_PULLUP = 2,
INTERNAL_PULLDOWN = 3,
EXTERNAL_PULLUP = 4,
EXTERNAL_PULLDOWN = 5
};
enum hasp_gpio_type_t {
FREE = 0x00,
USED = 0x01,
/* Outputs */
LED = 0x02,
LED_R = 0x03,
LED_G = 0x04,
LED_B = 0x05,
LED_CW = 0x06,
LED_WW = 0x07,
LED_W = 0x08,
LIGHT_RELAY = 0x0A,
POWER_RELAY = 0x0B,
SHUTTER_RELAY = 0x0C,
SHUTTER_OPEN = 0x1A,
SHUTTER_CLOSE = 0x1B,
BACKLIGHT = 0x20,
PWM = 0x21,
DAC = 0x22,
SERIAL_DIMMER = 0x30,
SERIAL_DIMMER_EU = 0x31,
SERIAL_DIMMER_AU = 0x32,
BUZZER = 0x40,
HAPTIC = 0x41,
/* Inputs */
SWITCH = 0xA0, // Binary Sensors
BATTERY = 0xA1,
BATTERY_CHARGING = 0xA2,
COLD = 0xA3,
CONNECTIVITY = 0xA4,
DOOR = 0xA5,
GARAGE_DOOR = 0xA6,
GAS = 0xA7,
HEAT = 0xA8,
LIGHT = 0xA9,
LOCK = 0xAA,
MOISTURE = 0xAB,
MOTION = 0xAC,
MOVING = 0xAD,
OCCUPANCY = 0xAE,
OPENING = 0xAF,
PLUG = 0xB0,
POWER = 0xB1,
PRESENCE = 0xB2,
PROBLEM = 0xB3,
SAFETY = 0xB4,
SMOKE = 0xB5,
SOUND = 0xB6,
VIBRATION = 0xB7,
WINDOW = 0xB8,
AWNING = 0xB9,
BLIND = 0xBA,
CURTAIN = 0xBB,
DAMPER = 0xBC,
GATE = 0xBD,
SHADE = 0xBE,
SHUTTER = 0xBF,
BUTTON = 0xF0,
BUTTON_TOGGLE_ON = 0xF1,
BUTTON_TOGGLE_OFF = 0xF2,
BUTTON_TOGGLE_BOTH = 0xF3,
TOUCH = 0xF4,
ADC = 0xF9,
COUNTER_RISE = 0xFA, // User Counters
COUNTER_FALL = 0xFB,
COUNTER_BOTH = 0xFC,
USER = 0xFF
};
#ifdef __cplusplus
} /* extern "C" */

View File

@ -25,13 +25,13 @@ void EthernetEvent(WiFiEvent_t event)
eth_connected = true;
break;
case SYSTEM_EVENT_ETH_GOT_IP:
LOG_TRACE(TAG_ETH, F("MAC Address %s"), ETH.macAddress().c_str());
LOG_TRACE(TAG_ETH, F(D_INFO_MAC_ADDRESS " %s"), ETH.macAddress().c_str());
ip = ETH.localIP();
LOG_TRACE(TAG_ETH, F("IPv4: %d.%d.%d.%d"), ip[0], ip[1], ip[2], ip[3]);
if(ETH.fullDuplex()) {
LOG_TRACE(TAG_ETH, F("FULL_DUPLEX"));
LOG_TRACE(TAG_ETH, F(D_INFO_FULL_DUPLEX));
}
LOG_TRACE(TAG_ETH, F("LINK_SPEED %d Mbps"), ETH.linkSpeed());
LOG_TRACE(TAG_ETH, F(D_INFO_LINK_SPEED " %d Mbps"), ETH.linkSpeed());
eth_connected = true;
networkStart(); // Start network services
break;
@ -55,7 +55,7 @@ void ethernetSetup()
ETH.begin(ETH_ADDR, ETH_POWER_PIN, ETH_MDC_PIN, ETH_MDIO_PIN, ETH_TYPE, ETH_CLKMODE);
}
void ethernetLoop(void)
IRAM_ATTR void ethernetLoop(void)
{}
bool ethernetEvery5Seconds()
@ -70,4 +70,25 @@ void ethernet_get_statusupdate(char* buffer, size_t len)
eth_connected ? F("on") : F("off"), ETH.linkSpeed(), ETH.localIP().toString().c_str());
}
void ethernet_get_info(JsonDocument& doc)
{
char size_buf[32];
String buffer((char*)0);
buffer.reserve(64);
JsonObject info = doc.createNestedObject(F(D_INFO_ETHERNET));
buffer = ETH.linkSpeed();
buffer += F(" Mbps");
if(ETH.fullDuplex()) {
buffer += F(" " D_INFO_FULL_DUPLEX);
}
info[F(D_INFO_LINK_SPEED)] = buffer;
info[F(D_INFO_IP_ADDRESS)] = ETH.localIP().toString();
info[F(D_INFO_GATEWAY)] = ETH.gatewayIP().toString();
info[F(D_INFO_DNS_SERVER)] = ETH.dnsIP().toString();
info[F(D_INFO_MAC_ADDRESS)] = ETH.macAddress();
}
#endif

View File

@ -4,13 +4,17 @@
#ifndef HASP_ETHERNET_ESP32_H
#define HASP_ETHERNET_ESP32_H
#include "ArduinoJson.h"
static bool eth_connected = false;
void ethernetSetup();
void ethernetLoop(void);
IRAM_ATTR void ethernetLoop(void);
bool ethernetEverySecond();
bool ethernetEvery5Seconds();
void ethernet_get_statusupdate(char* buffer, size_t len);
void ethernet_get_info(JsonDocument& doc);
#endif

View File

@ -4,6 +4,8 @@
#ifndef HASP_ETHERNET_STM32_H
#define HASP_ETHERNET_STM32_H
#include "ArduinoJson.h"
static bool eth_connected = false;
void ethernetSetup();
@ -13,4 +15,6 @@ bool ethernetEverySecond();
bool ethernetEvery5Seconds();
void ethernet_get_statusupdate(char* buffer, size_t len);
void ethernet_get_info(JsonDocument& doc);
#endif

View File

@ -3,9 +3,7 @@
#include <time.h>
#include <sys/time.h>
// #ifdef USE_CONFIG_OVERRIDE
// #include "user_config_override.h"
// #endif
#include <Arduino.h>
#include "ArduinoLog.h"
@ -29,7 +27,7 @@ void networkStart(void)
configTzTime(MYTZ, "pool.ntp.org", "time.nist.gov", NULL); // literal string
#endif
haspProgressVal(255); // hide
// haspProgressVal(255); // hide
haspReconnect();
debugStartSyslog();
// mqttStart();
@ -58,7 +56,7 @@ void networkSetup()
#endif
}
void networkLoop(void)
IRAM_ATTR void networkLoop(void)
{
#if HASP_USE_ETHERNET > 0
ethernetLoop();
@ -132,4 +130,15 @@ void network_get_statusupdate(char* buffer, size_t len)
#endif
}
void network_get_info(JsonDocument& doc)
{
#if HASP_USE_ETHERNET > 0
ethernet_get_info(doc);
#endif
#if HASP_USE_WIFI > 0
wifi_get_info(doc);
#endif
}
#endif

View File

@ -6,7 +6,7 @@
/* ===== Default Event Processors ===== */
void networkSetup();
void networkLoop(void);
IRAM_ATTR void networkLoop(void);
bool networkEvery5Seconds(void);
// bool networkEverySecond(void);
void networkStart(void);
@ -16,6 +16,7 @@ void networkStop(void);
/* ===== Getter and Setter Functions ===== */
void network_get_statusupdate(char* buffer, size_t len);
void network_get_info(JsonDocument& doc);
/* ===== Read/Write Configuration ===== */

View File

@ -48,6 +48,7 @@ char wifiPassword[64] = WIFI_PASSW;
#else
char wifiPassword[64] = "";
#endif
char wifiIpAddress[16] = "";
uint8_t wifiReconnectCounter = 0;
// const byte DNS_PORT = 53;
@ -60,10 +61,11 @@ static void wifiConnected(IPAddress ipaddress)
#if defined(STM32F4xx)
IPAddress ip;
ip = WiFi.localIP();
LOG_TRACE(TAG_WIFI, F("Received IP address %d.%d.%d.%d"), ip[0], ip[1], ip[2], ip[3]);
snprintf_P(wifiIpAddress, sizeof(wifiIpAddress), PSTR("%d.%d.%d.%d"), ip[0], ip[1], ip[2], ip[3]);
#else
LOG_TRACE(TAG_WIFI, F(D_NETWORK_IP_ADDRESS_RECEIVED), ipaddress.toString().c_str());
strncpy(wifiIpAddress, ipaddress.toString().c_str(), sizeof(wifiIpAddress));
#endif
LOG_TRACE(TAG_WIFI, F(D_NETWORK_IP_ADDRESS_RECEIVED), wifiIpAddress);
LOG_VERBOSE(TAG_WIFI, F("Connected = %s"),
WiFi.status() == WL_CONNECTED ? PSTR(D_NETWORK_ONLINE) : PSTR(D_NETWORK_OFFLINE));
@ -73,8 +75,9 @@ static void wifiConnected(IPAddress ipaddress)
static void wifiDisconnected(const char* ssid, uint8_t reason)
{
wifiReconnectCounter++;
char buffer[64];
haspProgressVal(wifiReconnectCounter * 3);
// haspProgressVal(wifiReconnectCounter * 3);
// networkStop();
if(wifiReconnectCounter > 33) {
@ -82,8 +85,6 @@ static void wifiDisconnected(const char* ssid, uint8_t reason)
dispatch_reboot(false);
}
char buffer[64];
switch(reason) {
#if defined(ARDUINO_ARCH_ESP8266)
case REASON_UNSPECIFIED:
@ -354,13 +355,13 @@ bool wifiShowAP(char* ssid, char* pass)
static void wifiReconnect(void)
{
#if defined(ARDUINO_ARCH_ESP8266)
WiFi.disconnect(true);
WiFi.disconnect();
WiFi.begin(wifiSsid, wifiPassword);
WiFi.hostname(haspDevice.get_hostname());
#elif defined(ARDUINO_ARCH_ESP32)
// https://github.com/espressif/arduino-esp32/issues/3438#issuecomment-721428310
WiFi.disconnect(true);
WiFi.disconnect();
WiFi.begin(wifiSsid, wifiPassword, WIFI_ALL_CHANNEL_SCAN);
// WiFi.config(INADDR_NONE, INADDR_NONE, INADDR_NONE); // causes 255.255.255.255 IP errors
WiFi.setHostname(haspDevice.get_hostname());
@ -446,11 +447,11 @@ bool wifiEvery5Seconds()
} else {
wifiReconnectCounter++;
if(wifiReconnectCounter > 45) {
LOG_ERROR(TAG_WIFI, F("Retries exceed %u: Rebooting..."), wifiReconnectCounter);
LOG_ERROR(TAG_WIFI, F("Retries exceeded %d: Rebooting..."), wifiReconnectCounter);
dispatch_reboot(false);
}
LOG_WARNING(TAG_WIFI, F("No Connection... retry %u"), wifiReconnectCounter);
if(wifiReconnectCounter % 6 == 0) {
LOG_WARNING(TAG_WIFI, F("No Connection... retry %d"), wifiReconnectCounter);
if(wifiReconnectCounter % 2 == 0) {
wifiReconnect();
}
return false;
@ -514,8 +515,61 @@ void wifi_get_statusupdate(char* buffer, size_t len)
snprintf_P(buffer, len, PSTR("\"ssid\":\"%s\",\"rssi\":%i,\"ip\":\"%d.%d.%d.%d\","), WiFi.SSID(), WiFi.RSSI(),
ip[0], ip[1], ip[2], ip[3]);
#else
strncpy(wifiIpAddress, WiFi.localIP().toString().c_str(), sizeof(wifiIpAddress));
snprintf_P(buffer, len, PSTR("\"ssid\":\"%s\",\"rssi\":%i,\"ip\":\"%s\","), WiFi.SSID().c_str(), WiFi.RSSI(),
WiFi.localIP().toString().c_str());
wifiIpAddress);
#endif
}
const char* wifi_get_ssid()
{
return wifiSsid;
}
const char* wifi_get_ip_address()
{
return wifiIpAddress;
}
void wifi_get_info(JsonDocument& doc)
{
String buffer((char*)0);
buffer.reserve(64);
JsonObject info = doc.createNestedObject(F(D_INFO_WIFI));
int8_t rssi = WiFi.RSSI();
buffer += String(rssi);
buffer += F("dBm (");
if(rssi >= -50) {
buffer += F(D_WIFI_RSSI_EXCELLENT ")");
} else if(rssi >= -59) {
buffer += F(D_WIFI_RSSI_GOOD ")");
} else if(rssi >= -68) {
buffer += F(D_WIFI_RSSI_FAIR ")");
} else if(rssi >= -77) {
buffer += F(D_WIFI_RSSI_WEAK ")");
} else {
buffer += F(D_WIFI_RSSI_BAD ")");
}
info[F(D_INFO_SSID)] = String(WiFi.SSID());
info[F(D_INFO_RSSI)] = buffer;
#if defined(STM32F4xx)
byte mac[6];
WiFi.macAddress(mac);
char macAddress[16];
snprintf_P(macAddress, sizeof(macAddress), PSTR("%02x%02x%02x"), mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
info[F(D_INFO_IP_ADDRESS)] = String(WiFi.localIP());
info[F(D_INFO_GATEWAY)] = String(WiFi.gatewayIP());
info[F(D_INFO_MAC_ADDRESS)] = String(macAddress);
#else
info[F(D_INFO_IP_ADDRESS)] = WiFi.localIP().toString();
info[F(D_INFO_GATEWAY)] = WiFi.gatewayIP().toString();
info[F(D_INFO_DNS_SERVER)] = WiFi.dnsIP().toString();
info[F(D_INFO_MAC_ADDRESS)] = WiFi.macAddress();
#endif
}

View File

@ -15,6 +15,10 @@ void wifiStop(void);
bool wifiValidateSsid(const char* ssid, const char* pass);
void wifi_get_statusupdate(char* buffer, size_t len);
void wifi_get_info(JsonDocument& doc);
const char* wifi_get_ssid();
const char* wifi_get_ip_address();
#if HASP_USE_CONFIG > 0
bool wifiGetConfig(const JsonObject& settings);
bool wifiSetConfig(const JsonObject& settings);

View File

@ -0,0 +1,78 @@
/* MIT License - Copyright (c) 2019-2021 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#include "hasplib.h"
#if HASP_USE_CONSOLE > 0
#include "ConsoleInput.h"
#include "hasp_debug.h"
#include "hasp_config.h"
#include "hasp_console.h"
#include "../../hasp/hasp_dispatch.h"
uint8_t consoleInputEnabled = true;
ConsoleInput debugConsole(&Serial, HASP_CONSOLE_BUFFER);
void console_update_prompt()
{
debugConsole.update();
}
void consoleSetup()
{
LOG_TRACE(TAG_MSGR, F(D_SERVICE_STARTING));
debugConsole.setLineCallback(dispatch_text_line);
LOG_INFO(TAG_CONS, F(D_SERVICE_STARTED));
}
IRAM_ATTR void consoleLoop()
{
if(!consoleInputEnabled) return;
int16_t keypress;
do {
switch(keypress = debugConsole.readKey()) {
case ConsoleInput::KEY_PAGE_UP:
dispatch_page_next(LV_SCR_LOAD_ANIM_NONE);
break;
case ConsoleInput::KEY_PAGE_DOWN:
dispatch_page_prev(LV_SCR_LOAD_ANIM_NONE);
break;
case(ConsoleInput::KEY_FN)...(ConsoleInput::KEY_FN + 12):
dispatch_set_page(keypress - ConsoleInput::KEY_FN, LV_SCR_LOAD_ANIM_NONE);
break;
}
} while(keypress != 0);
}
#if HASP_USE_CONFIG > 0
bool consoleGetConfig(const JsonObject& settings)
{
bool changed = false;
if(changed) configOutput(settings, TAG_CONS);
return changed;
}
/** Set console Configuration.
*
* Read the settings from json and sets the application variables.
*
* @param[in] settings JsonObject with the config settings.
**/
bool consoleSetConfig(const JsonObject& settings)
{
configOutput(settings, TAG_CONS);
bool changed = false;
return changed;
}
#endif // HASP_USE_CONFIG
#endif

View File

@ -0,0 +1,36 @@
/* MIT License - Copyright (c) 2019-2021 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifndef HASP_CONSOLE_H
#define HASP_CONSOLE_H
#if HASP_USE_CONSOLE > 0
#include "hasplib.h"
/* ===== Default Event Processors ===== */
void consoleSetup();
IRAM_ATTR void consoleLoop(void);
void consoleEvery5Seconds(void);
void consoleEverySecond(void);
void consoleStart(void);
void consoleStop(void);
/* ===== Special Event Processors ===== */
void console_update_prompt();
/* ===== Getter and Setter Functions ===== */
/* ===== Read/Write Configuration ===== */
#if HASP_USE_CONFIG > 0
bool consoleSetConfig(const JsonObject& settings);
bool consoleGetConfig(const JsonObject& settings);
#endif
#define CONSOLE_UNAUTHENTICATED 0
#define CONSOLE_USERNAME_OK 10
#define CONSOLE_USERNAME_NOK 99
#define CONSOLE_AUTHENTICATED 255
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@ -16,7 +16,7 @@ struct hasp_http_config_t
};
void httpSetup();
void httpLoop(void);
IRAM_ATTR void httpLoop(void);
void httpEvery5Seconds(void);
// void httpReconnect(void);
void httpStart(void);

View File

@ -60,8 +60,7 @@ void mdnsStart()
MDNS.addService(service, proto, 80);
strcpy_P(key, PSTR("app_version"));
haspGetVersion(value, sizeof(value));
MDNS.addServiceTxt(service, proto, key, value);
MDNS.addServiceTxt(service, proto, key, haspDevice.get_version());
strcpy_P(key, PSTR("app_name"));
strcpy_P(value, PSTR(D_MANUFACTURER));
@ -78,7 +77,7 @@ void mdnsStart()
}
}
void mdnsLoop(void)
IRAM_ATTR void mdnsLoop(void)
{
#if defined(ARDUINO_ARCH_ESP8266)
if(mdns_config.enable) {

View File

@ -13,7 +13,7 @@ struct hasp_mdns_config_t
/* ===== Default Event Processors ===== */
void mdnsSetup();
void mdnsLoop(void);
IRAM_ATTR void mdnsLoop(void);
void mdnsStart(void);
void mdnsStop(void);

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