mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2026-10-28 11:14:58 +00:00
Merge pull request #3240 from proddy/dev
more memory debug, optimized http, better Eth error handling
This commit is contained in:
+1
-1
@@ -29,7 +29,7 @@ BreakBeforeBinaryOperators: NonAssignment
|
||||
BreakConstructorInitializersBeforeComma: true # Always break constructor initializers before commas and align the commas with the colon.
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||
MaxEmptyLinesToKeep: 4
|
||||
MaxEmptyLinesToKeep: 1
|
||||
PenaltyBreakBeforeFirstCallParameter: 200
|
||||
PenaltyExcessCharacter: 10
|
||||
PointerAlignment: Middle
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
{
|
||||
"name": "EMS-ESP Devcontainer",
|
||||
"image": "mcr.microsoft.com/devcontainers/typescript-node:1-22-bookworm",
|
||||
"image": "mcr.microsoft.com/devcontainers/typescript-node:5-26-bookworm",
|
||||
"features": {
|
||||
"ghcr.io/devcontainers/features/node:1": {},
|
||||
"ghcr.io/devcontainers/features/node:1": {
|
||||
"version": "26"
|
||||
},
|
||||
"ghcr.io/devcontainers-extra/features/pnpm:2": {},
|
||||
"ghcr.io/devcontainers/features/python:1": {},
|
||||
"ghcr.io/shyim/devcontainers-features/bun:0": {}
|
||||
|
||||
@@ -22,16 +22,16 @@ jobs:
|
||||
with:
|
||||
python-version: '3.13'
|
||||
|
||||
- name: Install Node.js 24
|
||||
- name: Install Node.js 26
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: 24
|
||||
node-version: 26
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Enable Corepack
|
||||
run: corepack enable pnpm
|
||||
- name: Install pnpm
|
||||
run: npm install -g pnpm
|
||||
|
||||
- name: Get the EMS-ESP version
|
||||
id: build_info
|
||||
|
||||
@@ -20,16 +20,16 @@ jobs:
|
||||
with:
|
||||
python-version: '3.13'
|
||||
|
||||
- name: Install Node.js 24
|
||||
- name: Install Node.js 26
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: 24
|
||||
node-version: 26
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Enable Corepack
|
||||
run: corepack enable pnpm
|
||||
- name: Install pnpm
|
||||
run: npm install -g pnpm
|
||||
|
||||
|
||||
- name: Get the EMS-ESP version
|
||||
|
||||
@@ -22,16 +22,16 @@ jobs:
|
||||
with:
|
||||
python-version: '3.13'
|
||||
|
||||
- name: Install Node.js 24
|
||||
- name: Install Node.js 26
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: 24
|
||||
node-version: 26
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Enable Corepack
|
||||
run: corepack enable pnpm
|
||||
- name: Install pnpm
|
||||
run: npm install -g pnpm
|
||||
|
||||
- name: Get the EMS-ESP version
|
||||
id: build_info
|
||||
|
||||
@@ -16,6 +16,8 @@ This release is based on the latest Espressif/Arduino core version 3. It brings
|
||||
- cleaner MD5 and firmware uploading in WebUI [#3222](https://github.com/emsesp/EMS-ESP32/issues/3222)
|
||||
- pc0Flow in l/min [#3224](https://github.com/emsesp/EMS-ESP32/issues/3224)
|
||||
- remove HA config for excluded entities [#3229](https://github.com/emsesp/EMS-ESP32/issues/3229)
|
||||
- `show system` reports the Ethernet status on boards with a PHY, so a failed initialisation or a link that never came up is visible instead of Ethernet being omitted completely. Also shows the loop task's lowest free stack, to help diagnose reboots
|
||||
- new Application Setting "Automatically check for firmware updates", off by default. When enabled EMS-ESP asks emsesp.org for the latest version once a day on its own, otherwise it only asks when the WebUI wants to show it, so an unattended system never contacts emsesp.org
|
||||
|
||||
## Fixed
|
||||
|
||||
@@ -28,6 +30,9 @@ This release is based on the latest Espressif/Arduino core version 3. It brings
|
||||
- HA Discovery warning on Uptime after EMS-ESP boot due to NTP not ready
|
||||
- hc/control setting for UI800 thermostats [#3181](https://github.com/emsesp/EMS-ESP32/discussions/3181)
|
||||
- solar module switches [#3223](https://github.com/emsesp/EMS-ESP32/issues/3223)
|
||||
- possible crash when the WebUI asked for version information while the versions.json refresh was rewriting the cache from the main loop task
|
||||
- HTTP client could write past a fixed 64 byte buffer when a URL had a hostname of 64 characters or more, could busy-spin for the whole read budget if the socket reported bytes it wouldn't return, and buffered responses without any size limit
|
||||
- the "Ethernet clock mode (GPIO16/17) conflicts with PSRAM" error was never logged because Ethernet had already been skipped by the time the check ran
|
||||
|
||||
## Changed
|
||||
|
||||
@@ -42,4 +47,6 @@ This release is based on the latest Espressif/Arduino core version 3. It brings
|
||||
- set `None` for undefined values in HA `val_tpl`
|
||||
- changes in WebUI - remove multiple calls systemInfo endpoint, Vewrsion pages checks for internet connection [#3195](https://github.com/emsesp/EMS-ESP32/pull/3195)
|
||||
- multiple optimization in network, power down WiFi when Ethernet and WiFi nosleep is instant when selected [#3213](https://github.com/emsesp/EMS-ESP32/pull/3213)
|
||||
- TLS buffers (~17KB per HTTPS request) are taken from PSRAM on boards that have it, instead of fragmenting the internal heap
|
||||
- failed versions.json fetches back off from 5 up to 160 minutes instead of retrying every 5 minutes, as each attempt blocks the main loop for as long as the DNS, connect and read timeouts allow
|
||||
|
||||
|
||||
+29
-188
@@ -1,7 +1,6 @@
|
||||
{
|
||||
"type": "systembackup",
|
||||
"version": "3.9.0",
|
||||
"date": "2026-06-14T10:59:16",
|
||||
"systembackup": [
|
||||
{
|
||||
"type": "settings",
|
||||
@@ -20,7 +19,7 @@
|
||||
"eth_10mbit": false
|
||||
},
|
||||
"AP": {
|
||||
"provision_mode": 2,
|
||||
"provision_mode": 1,
|
||||
"ssid": "ems-esp",
|
||||
"password": "ems-esp-neo",
|
||||
"channel": 1,
|
||||
@@ -33,13 +32,13 @@
|
||||
"MQTT": {
|
||||
"enableTLS": false,
|
||||
"rootCA": "",
|
||||
"enabled": true,
|
||||
"host": "192.168.1.2",
|
||||
"enabled": false,
|
||||
"host": "",
|
||||
"port": 1883,
|
||||
"base": "ems-esp",
|
||||
"username": "username",
|
||||
"password": "password",
|
||||
"client_id": "esp32",
|
||||
"username": "",
|
||||
"password": "",
|
||||
"client_id": "ems-esp",
|
||||
"keep_alive": 60,
|
||||
"clean_session": false,
|
||||
"entity_format": 1,
|
||||
@@ -53,20 +52,23 @@
|
||||
"publish_time_heartbeat": 60,
|
||||
"mqtt_qos": 0,
|
||||
"mqtt_retain": false,
|
||||
"ha_enabled": true,
|
||||
"ha_enabled": false,
|
||||
"nested_format": 1,
|
||||
"discovery_prefix": "homeassistant",
|
||||
"discovery_type": 0,
|
||||
"ha_number_mode": 1,
|
||||
"ha_number_mode": 0,
|
||||
"publish_single": false,
|
||||
"publish_single2cmd": false,
|
||||
"send_response": false
|
||||
},
|
||||
"NTP": {
|
||||
"enabled": true,
|
||||
"enabled": false,
|
||||
"server": "time.google.com",
|
||||
"tz_label": "Europe/Amsterdam",
|
||||
"tz_format": "CET-1CEST,M3.5.0,M10.5.0/3"
|
||||
"tz_format": "CET-1CEST,M3.5.0,M10.5.0/3",
|
||||
"thermostat_sync": 1,
|
||||
"tz_label_t": "Europe/Amsterdam",
|
||||
"tz_format_t": "CET-1CEST,M3.5.0,M10.5.0/3"
|
||||
},
|
||||
"Security": {
|
||||
"jwt_secret": "ems-esp-neo",
|
||||
@@ -87,9 +89,9 @@
|
||||
"version": "3.9.0",
|
||||
"board_profile": "E32V2_2",
|
||||
"platform": "ESP32",
|
||||
"system_name": "prod",
|
||||
"system_name": "",
|
||||
"locale": "en",
|
||||
"tx_mode": 1,
|
||||
"tx_mode": 5,
|
||||
"ems_bus_id": 73,
|
||||
"syslog_enabled": false,
|
||||
"syslog_level": 3,
|
||||
@@ -100,7 +102,7 @@
|
||||
"boiler_heatingoff": false,
|
||||
"remote_timeout": 24,
|
||||
"remote_timeout_en": false,
|
||||
"shower_timer": true,
|
||||
"shower_timer": false,
|
||||
"shower_alert": false,
|
||||
"shower_alert_coldshot": 10,
|
||||
"shower_alert_trigger": 7,
|
||||
@@ -110,7 +112,7 @@
|
||||
"dallas_gpio": 14,
|
||||
"dallas_parasite": false,
|
||||
"led_gpio": 32,
|
||||
"hide_led": true,
|
||||
"hide_led": false,
|
||||
"led_type": 1,
|
||||
"low_clock": false,
|
||||
"telnet_enabled": true,
|
||||
@@ -134,139 +136,43 @@
|
||||
"modbus_port": 502,
|
||||
"modbus_max_clients": 10,
|
||||
"modbus_timeout": 300,
|
||||
"developer_mode": true,
|
||||
"developer_mode": false,
|
||||
"disable_reset": false,
|
||||
"email_enabled": true,
|
||||
"email_enabled": false,
|
||||
"email_security": 2,
|
||||
"email_server": "smtp.gmail.com",
|
||||
"email_server": "smtp.example.net",
|
||||
"email_port": 587,
|
||||
"email_login": "test@emsesp.org",
|
||||
"email_pass": "password",
|
||||
"email_sender": "test@emsesp.org",
|
||||
"email_recp": "test@emsesp.org",
|
||||
"email_login": "",
|
||||
"email_pass": "",
|
||||
"email_sender": "ems-esp@example.net",
|
||||
"email_recp": "",
|
||||
"email_subject": "ems-esp notification"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "commands",
|
||||
"Commands": {
|
||||
"commands": [
|
||||
{
|
||||
"id": 1,
|
||||
"cmd": "{\"url\":\"https://api.pushover.net/1/messages.json\"}",
|
||||
"value": "{\"user\":\"userkey\", \"token\":\"tokenkey\", \"message\":\"custom/message2\"}",
|
||||
"name": "push_over"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"cmd": "system/message",
|
||||
"value": "hello",
|
||||
"name": "sendmessage"
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"cmd": "system/message",
|
||||
"value": "{\"url\":\"http://emsesp.org/versions.json\"}",
|
||||
"name": "sendversions"
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"cmd": "custom/message",
|
||||
"value": "{\"url\":\"http://emsesp.org/versions.json\"}",
|
||||
"name": "getversions"
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"cmd": "system/sendmail",
|
||||
"value": "\"test email with \" + custom/message2",
|
||||
"name": "sendmail"
|
||||
}
|
||||
]
|
||||
"commands": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "schedule",
|
||||
"Schedule": {
|
||||
"schedule": [
|
||||
{
|
||||
"id": 1,
|
||||
"flags": 128,
|
||||
"active": false,
|
||||
"time": "",
|
||||
"cmd_name": "sendmail",
|
||||
"name": "sendmailtest"
|
||||
}
|
||||
]
|
||||
"schedule": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "customizations",
|
||||
"Customizations": {
|
||||
"as": [
|
||||
{
|
||||
"gpio": 39,
|
||||
"name": "core_voltage",
|
||||
"offset": 0,
|
||||
"factor": 0.003771,
|
||||
"uom": 23,
|
||||
"type": 3,
|
||||
"is_system": true
|
||||
},
|
||||
{
|
||||
"gpio": 36,
|
||||
"name": "supply_voltage",
|
||||
"offset": 0,
|
||||
"factor": 0.017,
|
||||
"uom": 23,
|
||||
"type": 3,
|
||||
"is_system": true
|
||||
},
|
||||
{
|
||||
"gpio": 2,
|
||||
"name": "led",
|
||||
"offset": 0,
|
||||
"factor": 1,
|
||||
"uom": 0,
|
||||
"type": 6,
|
||||
"is_system": true
|
||||
}
|
||||
],
|
||||
"ts": [],
|
||||
"as": [],
|
||||
"masked_entities": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "entities",
|
||||
"Entities": {
|
||||
"entities": [
|
||||
{
|
||||
"id": 0,
|
||||
"ram": 1,
|
||||
"device_id": 0,
|
||||
"type_id": 0,
|
||||
"offset": 0,
|
||||
"factor": 1,
|
||||
"name": "message",
|
||||
"uom": 0,
|
||||
"value_type": 9,
|
||||
"writeable": true,
|
||||
"hide": false,
|
||||
"value": "{\"stable\":{\"version\":\"3.8.3\",\"date\":\"2026-08-01\"},\"dev\":{\"version\":\"3.9.0-dev.0\",\"date\":\"2026-08-01T09:55:29Z\"}}"
|
||||
},
|
||||
{
|
||||
"id": 1,
|
||||
"ram": 1,
|
||||
"device_id": 0,
|
||||
"type_id": 0,
|
||||
"offset": 0,
|
||||
"factor": 1,
|
||||
"name": "message2",
|
||||
"uom": 0,
|
||||
"value_type": 9,
|
||||
"writeable": true,
|
||||
"hide": false,
|
||||
"value": "testing"
|
||||
}
|
||||
]
|
||||
"entities": []
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -274,71 +180,6 @@
|
||||
"Modules": {
|
||||
"modules": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "nvs",
|
||||
"nvs": [
|
||||
{
|
||||
"type": 1,
|
||||
"key": "nompower",
|
||||
"value": 30
|
||||
},
|
||||
{
|
||||
"type": 33,
|
||||
"key": "boot",
|
||||
"value": "3.9.0"
|
||||
},
|
||||
{
|
||||
"type": 17,
|
||||
"key": "led",
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"type": 33,
|
||||
"key": "intTemp",
|
||||
"value": "28_1767_7B13_2502"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"key": "d_boot",
|
||||
"value": 1
|
||||
},
|
||||
{
|
||||
"type": 33,
|
||||
"key": "app1",
|
||||
"value": "3.9.0"
|
||||
},
|
||||
{
|
||||
"type": 33,
|
||||
"key": "app0",
|
||||
"value": "3.9.0"
|
||||
},
|
||||
{
|
||||
"type": 66,
|
||||
"key": "nrgheat",
|
||||
"value": 49355.29793
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"key": "d_app1",
|
||||
"value": 1781336521
|
||||
},
|
||||
{
|
||||
"type": 1,
|
||||
"key": "fresh_firmware",
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"key": "d_app0",
|
||||
"value": 1781363944
|
||||
},
|
||||
{
|
||||
"type": 66,
|
||||
"key": "nrgww",
|
||||
"value": 41852.79107
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -32,8 +32,8 @@
|
||||
"alova": "^3.5.5",
|
||||
"jwt-decode": "^4.0.0",
|
||||
"preact": "^10.29.8",
|
||||
"react": "^19.2.8",
|
||||
"react-dom": "^19.2.8",
|
||||
"react": "^19.3.0",
|
||||
"react-dom": "^19.3.0",
|
||||
"react-icons": "^5.7.0",
|
||||
"react-router": "^8.3.1",
|
||||
"typesafe-i18n": "^5.27.1"
|
||||
@@ -42,9 +42,9 @@
|
||||
"@eslint/js": "^10.0.1",
|
||||
"@preact/preset-vite": "^2.10.6",
|
||||
"@trivago/prettier-plugin-sort-imports": "^6.0.2",
|
||||
"@types/node": "^26.5.0",
|
||||
"@types/react": "^19.2.18",
|
||||
"@types/react-dom": "^19.2.7",
|
||||
"@types/node": "^26.5.1",
|
||||
"@types/react": "^19.3.0",
|
||||
"@types/react-dom": "^19.3.0",
|
||||
"concurrently": "^10.0.5",
|
||||
"eslint": "^10.10.0",
|
||||
"eslint-config-prettier": "^10.1.8",
|
||||
@@ -55,8 +55,8 @@
|
||||
"terser": "^5.51.2",
|
||||
"typescript": "^6.0.3",
|
||||
"typescript-eslint": "^8.70.0",
|
||||
"vite": "^8.2.2",
|
||||
"vite": "^8.3.0",
|
||||
"vite-plugin-imagemin": "^0.6.1"
|
||||
},
|
||||
"packageManager": "pnpm@12.3.4+sha512.961aa41fb077da3a04a441d9f8e15ebc0c96da8ef710b2eb67bf9ee7cb0610eabd48f1fd85f51cffe73846785fa0f87c56a3a872a1d893f8446741b5cce45457"
|
||||
"packageManager": "pnpm@12.4.1"
|
||||
}
|
||||
|
||||
Generated
+341
-280
File diff suppressed because it is too large
Load Diff
@@ -115,7 +115,6 @@ export const writeSchedule = (data: Schedule) =>
|
||||
// Commands
|
||||
export const readCommands = () =>
|
||||
alovaInstance.Get<CommandItem[]>('/rest/commands', {
|
||||
// @ts-expect-error - exactOptionalPropertyTypes compatibility issue
|
||||
transform(data) {
|
||||
const commands = (data as Commands).commands;
|
||||
return commands.map((ci) => ({
|
||||
|
||||
@@ -19,7 +19,6 @@ export const uploadFile = (file: File) => {
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
return alovaInstance.Post('/rest/uploadFile', formData, {
|
||||
timeout: UPLOAD_TIMEOUT,
|
||||
enableUpload: true
|
||||
timeout: UPLOAD_TIMEOUT
|
||||
});
|
||||
};
|
||||
|
||||
@@ -55,6 +55,7 @@ export interface Settings {
|
||||
email_subject: string;
|
||||
developer_mode: boolean;
|
||||
disable_reset: boolean;
|
||||
auto_fw_check: boolean;
|
||||
}
|
||||
|
||||
export enum busConnectionStatus {
|
||||
|
||||
@@ -512,6 +512,18 @@ const ApplicationSettings = () => {
|
||||
</Grid>
|
||||
</>
|
||||
)}
|
||||
<Typography color="secondary">Firmware</Typography>
|
||||
<BlockFormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
checked={data.auto_fw_check}
|
||||
onChange={updateFormValue}
|
||||
name="auto_fw_check"
|
||||
/>
|
||||
}
|
||||
label={LL.AUTO_FW_CHECK()}
|
||||
/>
|
||||
|
||||
<Typography sx={{ pb: 1, pt: 2 }} variant="h6" color="primary">
|
||||
{LL.SENSORS()}
|
||||
</Typography>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { memo, useContext, useEffect, useState } from 'react';
|
||||
import { memo, useContext, useEffect, useRef, useState } from 'react';
|
||||
import { Link } from 'react-router';
|
||||
|
||||
import CancelIcon from '@mui/icons-material/Cancel';
|
||||
@@ -52,6 +52,7 @@ const STABLE_RELNOTES_URL =
|
||||
const DEV_URL = 'https://github.com/emsesp/EMS-ESP32/releases/download/latest/';
|
||||
const DEV_RELNOTES_URL =
|
||||
'https://github.com/emsesp/EMS-ESP32/blob/dev/CHANGELOG_LATEST.md';
|
||||
const MAX_VERSION_POLLS = 5; // approx 15 seconds of waiting
|
||||
|
||||
// Types for better type safety
|
||||
interface PartitionData {
|
||||
@@ -440,12 +441,17 @@ const Version = () => {
|
||||
const stableUpgradeAvailable = versions?.stable?.upgradeable ?? false;
|
||||
const devUpgradeAvailable = versions?.dev?.upgradeable ?? false;
|
||||
const internetLive = Boolean(versions?.stable || versions?.dev);
|
||||
const versionPolls = useRef(0);
|
||||
|
||||
useEffect(() => {
|
||||
if (internetLive) {
|
||||
if (internetLive || versionPolls.current >= MAX_VERSION_POLLS) {
|
||||
return;
|
||||
}
|
||||
const interval = setInterval(() => {
|
||||
versionPolls.current += 1;
|
||||
if (versionPolls.current >= MAX_VERSION_POLLS) {
|
||||
clearInterval(interval);
|
||||
}
|
||||
void refreshVersions();
|
||||
}, 3000);
|
||||
return () => clearInterval(interval);
|
||||
|
||||
@@ -93,7 +93,7 @@ const SingleUpload = ({ doRestart, text }: SingleUploadProps) => {
|
||||
</>
|
||||
) : (
|
||||
<DragNdrop
|
||||
text={(md5 ? LL.UPLOAD_MD5_RECEIVED() : text) + '...'}
|
||||
text={md5 ? LL.UPLOAD_MD5_RECEIVED() : text}
|
||||
onFileSelected={setFile}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -321,6 +321,7 @@ const cs: Translation = {
|
||||
DASHBOARD: 'Dashboard',
|
||||
DEVELOPER_MODE: 'Režim vývojáře',
|
||||
DISABLE_RESET: 'Zakázat obnovení továrního nastavení',
|
||||
AUTO_FW_CHECK: 'Automaticky kontrolovat aktualizace firmwaru',
|
||||
BYTES: 'Bajty',
|
||||
BITMASK: 'Bit Mask',
|
||||
DUPLICATE: 'Duplikát',
|
||||
@@ -348,8 +349,8 @@ const cs: Translation = {
|
||||
COMMAND_EXECUTED: 'Příkaz úspěšně spuštěn',
|
||||
RUN: 'Spustit příkaz',
|
||||
INTERNET_CONNECTION_CHECK: 'Kontrola online pro dostupné verze',
|
||||
UPLOAD_BACKUP_TEXT: 'Klikněte, abyste vybrali nebo přetáhli a pustili soubor zálohy (.json) sem',
|
||||
UPLOAD_FIRMWARE_TEXT: 'Klikněte, abyste vybrali nebo přetáhli a pustili soubor firmware .bin/.md5 sem',
|
||||
UPLOAD_BACKUP_TEXT: 'Klikněte, abyste vybrali, nebo drop soubor zálohy (.json) sem',
|
||||
UPLOAD_FIRMWARE_TEXT: 'Klikněte, abyste vybrali, nebo drop soubor firmware .bin/.md5 sem',
|
||||
UPLOAD_MD5_RECEIVED: 'Digest přijat, nyní nahrajte firmware .bin',
|
||||
UPLOAD_MD5_MATCHED: 'MD5 souhlasí, firmware se instaluje...'
|
||||
};
|
||||
|
||||
@@ -321,6 +321,7 @@ const de: Translation = {
|
||||
DASHBOARD: 'Dashboard',
|
||||
DEVELOPER_MODE: 'Entwicklermodus',
|
||||
DISABLE_RESET: 'Werkseinstellungen deaktivieren',
|
||||
AUTO_FW_CHECK: 'Automatisch nach Firmware-Updates suchen',
|
||||
BYTES: 'Bytes',
|
||||
BITMASK: 'Bit Maske',
|
||||
DUPLICATE: 'Kopieren',
|
||||
@@ -348,8 +349,8 @@ const de: Translation = {
|
||||
COMMAND_EXECUTED: 'Befehl erfolgreich ausgeführt',
|
||||
RUN: 'Befehl ausführen',
|
||||
INTERNET_CONNECTION_CHECK: 'Online-Prüfung auf verfügbare Versionen',
|
||||
UPLOAD_BACKUP_TEXT: 'Klicken Sie, um eine Sicherungsdatei (.json) auszuwählen oder zu ziehen und abzulegen',
|
||||
UPLOAD_FIRMWARE_TEXT: 'Klicken Sie, um eine Firmware-Datei (.bin/.md5) auszuwählen oder zu ziehen und abzulegen',
|
||||
UPLOAD_BACKUP_TEXT: 'Klicken Sie, um eine Sicherungsdatei (.json) auszuwählen, oder drop ein',
|
||||
UPLOAD_FIRMWARE_TEXT: 'Klicken Sie, um eine Firmware-Datei (.bin/.md5) auszuwählen, oder drop ein',
|
||||
UPLOAD_MD5_RECEIVED: 'Prüfsumme empfangen, jetzt die Firmware-Datei (.bin) hochladen',
|
||||
UPLOAD_MD5_MATCHED: 'MD5 stimmt überein, Firmware wird installiert...'
|
||||
};
|
||||
|
||||
@@ -321,6 +321,7 @@ const en: Translation = {
|
||||
DASHBOARD: 'Dashboard',
|
||||
DEVELOPER_MODE: 'Developer Mode',
|
||||
DISABLE_RESET: 'Disable Factory Reset',
|
||||
AUTO_FW_CHECK: 'Automatically check for firmware updates',
|
||||
BYTES: 'Bytes',
|
||||
BITMASK: 'Bit Mask',
|
||||
DUPLICATE: 'Duplicate',
|
||||
@@ -348,8 +349,8 @@ const en: Translation = {
|
||||
COMMAND_EXECUTED: 'Command executed successfully',
|
||||
RUN: 'Run',
|
||||
INTERNET_CONNECTION_CHECK: 'Checking online for available versions',
|
||||
UPLOAD_BACKUP_TEXT: 'Click to select or Drag&Drop a backup file (.json) here',
|
||||
UPLOAD_FIRMWARE_TEXT: 'Click to select or Drag&Drop a firmware .bin/.md5 file',
|
||||
UPLOAD_BACKUP_TEXT: 'Click to select, or drop a backup file (.json) here',
|
||||
UPLOAD_FIRMWARE_TEXT: 'Click to select, or drop a firmware .bin/.md5 file here',
|
||||
UPLOAD_MD5_RECEIVED: 'Digest received, now upload the firmware .bin file',
|
||||
UPLOAD_MD5_MATCHED: 'MD5 matches, installing firmware...'
|
||||
};
|
||||
|
||||
@@ -321,6 +321,7 @@ const fr: Translation = {
|
||||
DASHBOARD: 'Tableau de bord',
|
||||
DEVELOPER_MODE: 'Mode développeur',
|
||||
DISABLE_RESET: 'Désactiver la réinitialisation de fabrique',
|
||||
AUTO_FW_CHECK: 'Vérifier automatiquement les mises à jour du firmware',
|
||||
BYTES: 'Octets',
|
||||
BITMASK: 'Masque de bits',
|
||||
DUPLICATE: 'Dupliquer',
|
||||
@@ -348,8 +349,8 @@ const fr: Translation = {
|
||||
COMMAND_EXECUTED: 'Commande exécutée avec succès',
|
||||
RUN: 'Exécuter une commande',
|
||||
INTERNET_CONNECTION_CHECK: 'Vérification en ligne pour les versions disponibles',
|
||||
UPLOAD_BACKUP_TEXT: 'Cliquez pour sélectionner ou faites glisser et déposez un fichier de sauvegarde (.json) ici',
|
||||
UPLOAD_FIRMWARE_TEXT: 'Cliquez pour sélectionner ou faites glisser et déposez un fichier firmware .bin/.md5 ici',
|
||||
UPLOAD_BACKUP_TEXT: 'Cliquez pour sélectionner, ou drop un fichier de sauvegarde (.json) ici',
|
||||
UPLOAD_FIRMWARE_TEXT: 'Cliquez pour sélectionner, ou drop un fichier firmware .bin/.md5 ici',
|
||||
UPLOAD_MD5_RECEIVED: 'Empreinte reçue, téléversez maintenant le fichier firmware .bin',
|
||||
UPLOAD_MD5_MATCHED: 'MD5 concordant, installation du firmware...'
|
||||
};
|
||||
|
||||
@@ -321,6 +321,7 @@ const it: Translation = {
|
||||
DASHBOARD: 'Pannello di controllo',
|
||||
DEVELOPER_MODE: 'Modalità sviluppatore',
|
||||
DISABLE_RESET: 'Disabilita la ripristino di fabbrica',
|
||||
AUTO_FW_CHECK: 'Controlla automaticamente gli aggiornamenti del firmware',
|
||||
BYTES: 'Byte',
|
||||
BITMASK: 'Bitmask',
|
||||
DUPLICATE: 'Duplicato',
|
||||
@@ -348,8 +349,8 @@ const it: Translation = {
|
||||
COMMAND_EXECUTED: 'Comando eseguito con successo',
|
||||
RUN: 'Esegui comando',
|
||||
INTERNET_CONNECTION_CHECK: 'Controllo online per le versioni disponibili',
|
||||
UPLOAD_BACKUP_TEXT: 'Klik per selezionare o trascinare e rilasciare un file di backup (.json) qui',
|
||||
UPLOAD_FIRMWARE_TEXT: 'Klik per selezionare o trascinare e rilasciare un file firmware .bin/.md5 qui',
|
||||
UPLOAD_BACKUP_TEXT: 'Klik per selezionare, o drop un file di backup (.json) qui',
|
||||
UPLOAD_FIRMWARE_TEXT: 'Klik per selezionare, o drop un file firmware .bin/.md5 qui',
|
||||
UPLOAD_MD5_RECEIVED: 'Digest ricevuto, ora caricare il file firmware .bin',
|
||||
UPLOAD_MD5_MATCHED: 'MD5 corrispondente, installazione firmware...'
|
||||
};
|
||||
|
||||
@@ -321,6 +321,7 @@ const nl: Translation = {
|
||||
DASHBOARD: 'Dashboard',
|
||||
DEVELOPER_MODE: 'Ontwikkelaarsmodus',
|
||||
DISABLE_RESET: 'Fabrieksinstellingen uitschakelen',
|
||||
AUTO_FW_CHECK: 'Automatisch controleren op firmware-updates',
|
||||
BYTES: 'Bytes',
|
||||
BITMASK: 'Bit Mask',
|
||||
DUPLICATE: 'Duplicaat',
|
||||
@@ -348,8 +349,8 @@ const nl: Translation = {
|
||||
COMMAND_EXECUTED: 'Commando uitgevoerd succesvol',
|
||||
RUN: 'Commando uitvoeren',
|
||||
INTERNET_CONNECTION_CHECK: 'Controleren op online beschikbare versies',
|
||||
UPLOAD_BACKUP_TEXT: 'Klik voor selecteren of sleep en drop een back-upbestand (.json) hier',
|
||||
UPLOAD_FIRMWARE_TEXT: 'Klik voor selecteren of sleep en drop een firmware .bin/.md5 bestand hier',
|
||||
UPLOAD_BACKUP_TEXT: 'Klik voor selecteren, of drop een back-upbestand (.json) hier',
|
||||
UPLOAD_FIRMWARE_TEXT: 'Klik voor selecteren, of drop een firmware .bin/.md5 bestand hier',
|
||||
UPLOAD_MD5_RECEIVED: 'Digest ontvangen, upload nu het firmware .bin-bestand',
|
||||
UPLOAD_MD5_MATCHED: 'MD5 komt overeen, firmware wordt geïnstalleerd...'
|
||||
};
|
||||
|
||||
@@ -321,6 +321,7 @@ const no: Translation = {
|
||||
DASHBOARD: 'Dashboard',
|
||||
DEVELOPER_MODE: 'Utvikler modus',
|
||||
DISABLE_RESET: 'Deaktiver fabrikkinnstillinger',
|
||||
AUTO_FW_CHECK: 'Se automatisk etter nye firmware versjoner',
|
||||
BYTES: 'Bytes',
|
||||
BITMASK: 'Bitmask',
|
||||
DUPLICATE: 'Duplikat',
|
||||
@@ -348,8 +349,8 @@ const no: Translation = {
|
||||
COMMAND_EXECUTED: 'Kommando kjørt lykkes',
|
||||
RUN: 'Kjør',
|
||||
INTERNET_CONNECTION_CHECK: 'Kontrollerer online for tilgjengelige versjoner',
|
||||
UPLOAD_BACKUP_TEXT: 'Klikk for å velge eller dra og slipp en sikkerhetskopi (.json) her',
|
||||
UPLOAD_FIRMWARE_TEXT: 'Klikk for å velge eller dra og slipp en firmware .bin/.md5 her',
|
||||
UPLOAD_BACKUP_TEXT: 'Klikk for å velge, eller drop en sikkerhetskopi (.json) her',
|
||||
UPLOAD_FIRMWARE_TEXT: 'Klikk for å velge, eller drop en firmware .bin/.md5 her',
|
||||
UPLOAD_MD5_RECEIVED: 'MD5 mottatt, last nå opp firmware .bin-filen',
|
||||
UPLOAD_MD5_MATCHED: 'MD5 stemmer, firmware installeres...'
|
||||
};
|
||||
|
||||
@@ -321,6 +321,7 @@ const pl: BaseTranslation = {
|
||||
DASHBOARD: 'Pulpit',
|
||||
DEVELOPER_MODE: 'Tryb programisty',
|
||||
DISABLE_RESET: 'Wyłącz reset fabryczny',
|
||||
AUTO_FW_CHECK: 'Automatycznie sprawdzaj aktualizacje firmware',
|
||||
BYTES: 'Bajty',
|
||||
BITMASK: 'Bit Mask',
|
||||
DUPLICATE: 'Duplicate',
|
||||
@@ -348,8 +349,8 @@ const pl: BaseTranslation = {
|
||||
COMMAND_EXECUTED: 'Komenda wykonana pomyślnie',
|
||||
RUN: 'Wykonaj',
|
||||
INTERNET_CONNECTION_CHECK: 'Sprawdzanie online dla dostępnych wersji',
|
||||
UPLOAD_BACKUP_TEXT: 'Kliknij, aby wybrać lub przeciągnij i upuść plik kopii zapasowej (.json) tutaj',
|
||||
UPLOAD_FIRMWARE_TEXT: 'Kliknij, aby wybrać lub przeciągnij i upuść plik firmware .bin/.md5',
|
||||
UPLOAD_BACKUP_TEXT: 'Kliknij, aby wybrać, lub drop plik kopii zapasowej (.json) tutaj',
|
||||
UPLOAD_FIRMWARE_TEXT: 'Kliknij, aby wybrać, lub drop plik firmware .bin/.md5 tutaj',
|
||||
UPLOAD_MD5_RECEIVED: 'Suma MD5 odebrana, teraz wgraj plik firmware .bin',
|
||||
UPLOAD_MD5_MATCHED: 'MD5 zgodne, instalowanie firmware...'
|
||||
};
|
||||
|
||||
@@ -321,6 +321,7 @@ const sk: Translation = {
|
||||
DASHBOARD: 'Panel',
|
||||
DEVELOPER_MODE: 'Režim vývojára',
|
||||
DISABLE_RESET: 'Zakázať továrenské nastavenia',
|
||||
AUTO_FW_CHECK: 'Automaticky kontrolovať aktualizácie firmvéru',
|
||||
BYTES: 'Bytov',
|
||||
BITMASK: 'Bitová maska',
|
||||
DUPLICATE: 'Duplicitné',
|
||||
@@ -348,8 +349,8 @@ const sk: Translation = {
|
||||
COMMAND_EXECUTED: 'Príkaz vykonaný úspešne',
|
||||
RUN: 'Volať príkaz',
|
||||
INTERNET_CONNECTION_CHECK: 'Kontrola online pre dostupné verzie',
|
||||
UPLOAD_BACKUP_TEXT: 'Kliknite, aby ste vybrali alebo presuňte a upustili súbor zálohy (.json) sem',
|
||||
UPLOAD_FIRMWARE_TEXT: 'Kliknite, aby ste vybrali alebo presuňte a upustili súbor firmware .bin/.md5',
|
||||
UPLOAD_BACKUP_TEXT: 'Kliknite, aby ste vybrali, alebo drop súbor zálohy (.json) sem',
|
||||
UPLOAD_FIRMWARE_TEXT: 'Kliknite, aby ste vybrali, alebo drop súbor firmware .bin/.md5 sem',
|
||||
UPLOAD_MD5_RECEIVED: 'Suma MD5 prijatá, teraz nahrajte firmware .bin',
|
||||
UPLOAD_MD5_MATCHED: 'MD5 súhlasí, firmvér sa inštaluje...'
|
||||
};
|
||||
|
||||
@@ -321,6 +321,7 @@ const sv: Translation = {
|
||||
DASHBOARD: 'Kontrollpanel',
|
||||
DEVELOPER_MODE: 'Utvecklarläge',
|
||||
DISABLE_RESET: 'Inaktivera fabriksåterställning',
|
||||
AUTO_FW_CHECK: 'Sök automatiskt efter nya firmwareversioner',
|
||||
BYTES: 'Bytes',
|
||||
BITMASK: 'Bitmask',
|
||||
DUPLICATE: 'Dublett',
|
||||
@@ -348,8 +349,8 @@ const sv: Translation = {
|
||||
COMMAND_EXECUTED: 'Kommando kört lyckades',
|
||||
RUN: 'Kör kommando',
|
||||
INTERNET_CONNECTION_CHECK: 'Kontrollerar online för tillgängliga versioner',
|
||||
UPLOAD_BACKUP_TEXT: 'Klicka för att välja eller dra och släpp en säkerhetskopia (.json) här',
|
||||
UPLOAD_FIRMWARE_TEXT: 'Klicka för att välja eller dra och släpp en firmware .bin/.md5 här',
|
||||
UPLOAD_BACKUP_TEXT: 'Klicka för att välja, eller drop en säkerhetskopia (.json) här',
|
||||
UPLOAD_FIRMWARE_TEXT: 'Klicka för att välja, eller drop en firmware .bin/.md5 här',
|
||||
UPLOAD_MD5_RECEIVED: 'MD5 mottagen, ladda nu upp firmware .bin-filen',
|
||||
UPLOAD_MD5_MATCHED: 'MD5 stämmer, firmware installeras...'
|
||||
};
|
||||
|
||||
@@ -321,6 +321,7 @@ const tr: Translation = {
|
||||
DASHBOARD: 'Kontrol Paneli',
|
||||
DEVELOPER_MODE: 'Geliştirici Modu',
|
||||
DISABLE_RESET: 'Fabrika ayarlarını devre dışı bırak',
|
||||
AUTO_FW_CHECK: 'Firmware güncellemelerini otomatik olarak denetle',
|
||||
BYTES: 'Bayt',
|
||||
BITMASK: 'Bit Maskesi',
|
||||
DUPLICATE: 'Çift',
|
||||
@@ -348,8 +349,8 @@ const tr: Translation = {
|
||||
COMMAND_EXECUTED: 'Komut başarıyla çalıştırıldı',
|
||||
RUN: 'Komutu çalıştır',
|
||||
INTERNET_CONNECTION_CHECK: 'Online bağlantısı kontrol ediliyor',
|
||||
UPLOAD_BACKUP_TEXT: 'Yeni bir firmware dosyası (.bin) veya yedek dosyası (.json) yükle',
|
||||
UPLOAD_FIRMWARE_TEXT: 'Bir firmware .bin dosyası veya buraya tıklayın',
|
||||
UPLOAD_BACKUP_TEXT: 'Bir yedek dosyası (.json), buraya drop yapın',
|
||||
UPLOAD_FIRMWARE_TEXT: 'Bir firmware .bin dosyası, buraya drop yapın',
|
||||
UPLOAD_MD5_RECEIVED: 'Özet alındı, şimdi firmware .bin dosyasını yükleyin',
|
||||
UPLOAD_MD5_MATCHED: 'MD5 eşleşti, firmware yükleniyor...'
|
||||
};
|
||||
|
||||
@@ -138,7 +138,7 @@ const runRule = async (
|
||||
|
||||
export default class Schema {
|
||||
private readonly rules: Rules;
|
||||
private requiredMessage?: string;
|
||||
private requiredMessage?: string | undefined;
|
||||
|
||||
constructor(descriptor: Rules) {
|
||||
this.rules = descriptor;
|
||||
|
||||
@@ -71,10 +71,13 @@ class Preferences {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool clear() {
|
||||
return true;
|
||||
}
|
||||
|
||||
// unused....
|
||||
|
||||
// void end();
|
||||
// bool clear();
|
||||
// size_t putShort(const char * key, int16_t value);
|
||||
// size_t putUShort(const char * key, uint16_t value);
|
||||
// size_t putInt(const char * key, int32_t value);
|
||||
|
||||
@@ -17,5 +17,5 @@
|
||||
"@trivago/prettier-plugin-sort-imports": "^6.0.2",
|
||||
"prettier": "^3.9.6"
|
||||
},
|
||||
"packageManager": "pnpm@12.3.4+sha512.961aa41fb077da3a04a441d9f8e15ebc0c96da8ef710b2eb67bf9ee7cb0610eabd48f1fd85f51cffe73846785fa0f87c56a3a872a1d893f8446741b5cce45457"
|
||||
"packageManager": "pnpm@12.4.1"
|
||||
}
|
||||
|
||||
Generated
+94
-37
@@ -7,96 +7,153 @@ importers:
|
||||
configDependencies: {}
|
||||
packageManagerDependencies:
|
||||
pnpm:
|
||||
specifier: 12.3.4
|
||||
version: 12.3.4
|
||||
specifier: 12.4.1
|
||||
version: 12.4.1
|
||||
|
||||
packages:
|
||||
|
||||
'@pnpm/exe.darwin-arm64@12.3.4':
|
||||
resolution: {integrity: sha512-PAyUol8T1+/+ViOiXAt51ECA+QnfXCqz6foL4bW+LsoX0NcVd5XVEM2mRQu+LV4oc7uRz9zf9U0P+XFfuQeDAw==}
|
||||
'@pnpm/exe.android-arm64@12.4.1':
|
||||
resolution: {integrity: sha512-/HwsqXMSmlOfgtV9+O0ratzjV6Vd/8n1hh4rGHpCGmDURvt52MwZxdbhyxP4K03ZfvgSDvotFPr8O+RzE5Eu8A==}
|
||||
cpu: [arm64]
|
||||
os: [android]
|
||||
|
||||
'@pnpm/exe.android-x64@12.4.1':
|
||||
resolution: {integrity: sha512-+l74Qb4c2YjOzNKHXJLg+1wr8xHM1ckkUhnU5KRUK9TJqiiczt6yeTZqqzHIlJ8i6pAoj5V0OJevDRwnQKLgrQ==}
|
||||
cpu: [x64]
|
||||
os: [android]
|
||||
|
||||
'@pnpm/exe.darwin-arm64@12.4.1':
|
||||
resolution: {integrity: sha512-6rkZkT3iGfaxknUdGHraqSWFvTa6N0ajAHluv9Ax0GRWs0sIcGNiFhDopv6xSZCsJZmG483aNS/b6UEDy3blfw==}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@pnpm/exe.darwin-x64@12.3.4':
|
||||
resolution: {integrity: sha512-fxP9JCk0Cdye+ePuj+GJJLMUMTqHGWRdb1dtv4How876uQ2ehxvenpgiYAir/ceO9PsYUZkFTtyZdx+rRu5QOA==}
|
||||
'@pnpm/exe.darwin-x64@12.4.1':
|
||||
resolution: {integrity: sha512-Vb1CHlR88HghC1qUxjxjs82zQSXnXacPD+btG2CmG8Q/hBU7Q0/b2YWJKSQqZXicunV5khFtfTlAwJddV9RkYA==}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@pnpm/exe.linux-arm64-musl@12.3.4':
|
||||
resolution: {integrity: sha512-FBOt0/7ye6O6q4AllVV5QMviB6qE6fqkeczV/+MDWQsmo+QJrlfsh6X7CpH/tClVpBZEyIbjpUoT8bNhCYBxEg==}
|
||||
'@pnpm/exe.freebsd-x64@12.4.1':
|
||||
resolution: {integrity: sha512-iT3iHz3Nl0Sxxj7UPOtZ/aQ81AFsQhjoeWMAlPkSRO04gsgDGAXv3UYxOFaesMWsfNxaGn0A+CITbuCHFF66FA==}
|
||||
cpu: [x64]
|
||||
os: [freebsd]
|
||||
|
||||
'@pnpm/exe.linux-arm64-musl@12.4.1':
|
||||
resolution: {integrity: sha512-aBooZfNXM5f+OGUgCAMFWpE/kAhsWfvmqIyMtHy6zl3aNxyInWrcY/Saln/UElzo7lZWMC0Yktroxd/2J26lNQ==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@pnpm/exe.linux-arm64@12.3.4':
|
||||
resolution: {integrity: sha512-t71AVA7LRqiKTyZ5xMYaZc2n5DfdpMbfokZuiIOXHBOM03ECnF0t4iYwaBDqJgVjlKYUOwaF/bRQajGNA4cJ4w==}
|
||||
'@pnpm/exe.linux-arm64@12.4.1':
|
||||
resolution: {integrity: sha512-TlOdacTTP09BgcMvwWBFRsu8VAjfwqwnslBj+XSq1JFM3ck4f3k+1O/747EuctxZxs3/o785b6Q3s7Pd92Ptsg==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@pnpm/exe.linux-x64-musl@12.3.4':
|
||||
resolution: {integrity: sha512-RPmk7Jb/aYaFvL2iyDN/AtMY+hUEsue732WmXpcuQ9tBpMnGyA5py7Z3+e+qmQaJ0zY/4ni9jJiyPBQHujmv6w==}
|
||||
'@pnpm/exe.linux-ppc64@12.4.1':
|
||||
resolution: {integrity: sha512-r/ab/MlIBo75oizUP5ITiziCCrnXz4SJwfErLQ+603AshB+Yq7xTMCoMtzTSCAMu6aaymIKkAFtZvd2J75Wq0w==}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@pnpm/exe.linux-riscv64@12.4.1':
|
||||
resolution: {integrity: sha512-C/D1QWdKMiB8+wv/spl1rGITFUuqC+aI/fb6h8NB5sqxsOaGXeYc/g891oCuzggHn6SODk9p+I09hI76x/cMNw==}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@pnpm/exe.linux-s390x@12.4.1':
|
||||
resolution: {integrity: sha512-nxz5zD4yXt94uzbStDk0QTPKW+aE92hH1b5tFXK9ctB1HE9Xcq1vjTiA2LsZMFC6p4gdu5OwQeFqYNAVGa6QlA==}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@pnpm/exe.linux-x64-musl@12.4.1':
|
||||
resolution: {integrity: sha512-5AwgFdGhVUg2kIweYGfxzSLEHiIG77PQhZAkXC3TwofQHsu1Wr+TrV5/rNX2PopFnHRzuE581zoB8F6Wle32yg==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@pnpm/exe.linux-x64@12.3.4':
|
||||
resolution: {integrity: sha512-2ZqOlSPkfwX1h5cR+FPiWf8+F+2hZT/3TvhUK5sigHqwaQCIiq8R7CGxhndKs63JtcLi2a1Qpo+wX/EoyfjyJQ==}
|
||||
'@pnpm/exe.linux-x64@12.4.1':
|
||||
resolution: {integrity: sha512-FJOZuuuQMhp0oLzBtcKkLXknBI92hfkmSnlKc47vfin4HrmfID5khY2lGekL9tCzk1cpR+HShEw/meFl+nHtzQ==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@pnpm/exe.win32-arm64@12.3.4':
|
||||
resolution: {integrity: sha512-ANyrHqyqco6SXBysUTRF74itDyyraea7IbFsKFdNXTjcFnfycTDx37EwuhdpPYFNSIh2JhUG4fByclsRfiHX7w==}
|
||||
'@pnpm/exe.win32-arm64@12.4.1':
|
||||
resolution: {integrity: sha512-OO7eKBL9S+xk5hRy+JUUZSNJknGuGe3GEUffsrlC2LbqKF02g+VX1anGIzSbJDvkkdnpJhSlxF5AUz2JzJu2Jw==}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
'@pnpm/exe.win32-x64@12.3.4':
|
||||
resolution: {integrity: sha512-WH/KqBPY/hq2Tb7SgQltEZytimcjgKRaCRL/aM9CI0c67iKc5TVmHUhIiL3Ux9FB4bWn36i6XewUcScQI+zG8w==}
|
||||
'@pnpm/exe.win32-x64@12.4.1':
|
||||
resolution: {integrity: sha512-x7gJHZgHo6hp354xCYA2NvoFzYJkHwovt2kVsUBK5EmXULLcP51JGMq09CX+5FRFJUZFKoXjLu3mZWmfP7o6PQ==}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
pnpm@12.3.4:
|
||||
resolution: {integrity: sha512-lhqkH7B32joEpEHZ+OFevAyW2o73ELLrZ7+e58sGEOq9SPH9hfUc/+c4RnhfoPh8VqOocqHYk/hEZ0G1zORUVw==}
|
||||
pnpm@12.4.1:
|
||||
resolution: {integrity: sha512-LoHjmdc/6DkNqyXgaqeIq3pZCCSNL1o3D4K0gRR6ano2e/gEj5pv22Rg8hpm8FQt7bi5TKLIcjWWdBkgsWVtTA==}
|
||||
engines: {node: '>=18.*'}
|
||||
hasBin: true
|
||||
|
||||
snapshots:
|
||||
|
||||
'@pnpm/exe.darwin-arm64@12.3.4':
|
||||
'@pnpm/exe.android-arm64@12.4.1':
|
||||
optional: true
|
||||
|
||||
'@pnpm/exe.darwin-x64@12.3.4':
|
||||
'@pnpm/exe.android-x64@12.4.1':
|
||||
optional: true
|
||||
|
||||
'@pnpm/exe.linux-arm64-musl@12.3.4':
|
||||
'@pnpm/exe.darwin-arm64@12.4.1':
|
||||
optional: true
|
||||
|
||||
'@pnpm/exe.linux-arm64@12.3.4':
|
||||
'@pnpm/exe.darwin-x64@12.4.1':
|
||||
optional: true
|
||||
|
||||
'@pnpm/exe.linux-x64-musl@12.3.4':
|
||||
'@pnpm/exe.freebsd-x64@12.4.1':
|
||||
optional: true
|
||||
|
||||
'@pnpm/exe.linux-x64@12.3.4':
|
||||
'@pnpm/exe.linux-arm64-musl@12.4.1':
|
||||
optional: true
|
||||
|
||||
'@pnpm/exe.win32-arm64@12.3.4':
|
||||
'@pnpm/exe.linux-arm64@12.4.1':
|
||||
optional: true
|
||||
|
||||
'@pnpm/exe.win32-x64@12.3.4':
|
||||
'@pnpm/exe.linux-ppc64@12.4.1':
|
||||
optional: true
|
||||
|
||||
pnpm@12.3.4:
|
||||
'@pnpm/exe.linux-riscv64@12.4.1':
|
||||
optional: true
|
||||
|
||||
'@pnpm/exe.linux-s390x@12.4.1':
|
||||
optional: true
|
||||
|
||||
'@pnpm/exe.linux-x64-musl@12.4.1':
|
||||
optional: true
|
||||
|
||||
'@pnpm/exe.linux-x64@12.4.1':
|
||||
optional: true
|
||||
|
||||
'@pnpm/exe.win32-arm64@12.4.1':
|
||||
optional: true
|
||||
|
||||
'@pnpm/exe.win32-x64@12.4.1':
|
||||
optional: true
|
||||
|
||||
pnpm@12.4.1:
|
||||
optionalDependencies:
|
||||
'@pnpm/exe.darwin-arm64': 12.3.4
|
||||
'@pnpm/exe.darwin-x64': 12.3.4
|
||||
'@pnpm/exe.linux-arm64': 12.3.4
|
||||
'@pnpm/exe.linux-arm64-musl': 12.3.4
|
||||
'@pnpm/exe.linux-x64': 12.3.4
|
||||
'@pnpm/exe.linux-x64-musl': 12.3.4
|
||||
'@pnpm/exe.win32-arm64': 12.3.4
|
||||
'@pnpm/exe.win32-x64': 12.3.4
|
||||
'@pnpm/exe.android-arm64': 12.4.1
|
||||
'@pnpm/exe.android-x64': 12.4.1
|
||||
'@pnpm/exe.darwin-arm64': 12.4.1
|
||||
'@pnpm/exe.darwin-x64': 12.4.1
|
||||
'@pnpm/exe.freebsd-x64': 12.4.1
|
||||
'@pnpm/exe.linux-arm64': 12.4.1
|
||||
'@pnpm/exe.linux-arm64-musl': 12.4.1
|
||||
'@pnpm/exe.linux-ppc64': 12.4.1
|
||||
'@pnpm/exe.linux-riscv64': 12.4.1
|
||||
'@pnpm/exe.linux-s390x': 12.4.1
|
||||
'@pnpm/exe.linux-x64': 12.4.1
|
||||
'@pnpm/exe.linux-x64-musl': 12.4.1
|
||||
'@pnpm/exe.win32-arm64': 12.4.1
|
||||
'@pnpm/exe.win32-x64': 12.4.1
|
||||
|
||||
---
|
||||
lockfileVersion: '9.0'
|
||||
|
||||
+16
-11
@@ -66,6 +66,7 @@ let settings = {
|
||||
modbus_timeout: 10000,
|
||||
developer_mode: true,
|
||||
disable_reset: false,
|
||||
auto_fw_check: false,
|
||||
email_enabled: false,
|
||||
email_security: 2,
|
||||
email_server: 'smtp.gmail.com',
|
||||
@@ -209,14 +210,16 @@ switch (emulate_esp) {
|
||||
// ESP32 4MB
|
||||
case 'ESP32':
|
||||
system_status.esp_platform = 'ESP32';
|
||||
system_status.cpu_type = 'ESP32';
|
||||
system_status.arduino_version = 'Tasmota Arduino v2.0.17';
|
||||
system_status.sdk_version = 'v4.4.7';
|
||||
system_status.psram = false;
|
||||
system_status.psram_size = 0;
|
||||
system_status.free_psram = 0;
|
||||
settings.board_profile = 'E32V2';
|
||||
settings.platform = 'ESP32';
|
||||
system_status.cpu_type = 'ESP32-D0WD-V3';
|
||||
system_status.arduino_version = 'Tasmota Arduino v3.3.8';
|
||||
system_status.sdk_version = '5.5.4.260407';
|
||||
system_status.psram = true;
|
||||
system_status.psram_size = 4096;
|
||||
system_status.free_psram = 4055;
|
||||
system_status.model = 'BBQKees Electronics E32V2.2 rev.2.2/2024073';
|
||||
system_status.board = 'E32V2_2';
|
||||
|
||||
settings.board_profile = 'E32V2_2';
|
||||
break;
|
||||
|
||||
// ESP32 S3
|
||||
@@ -224,13 +227,15 @@ switch (emulate_esp) {
|
||||
default:
|
||||
system_status.esp_platform = 'ESP32S3';
|
||||
system_status.cpu_type = 'ESP32-S3';
|
||||
system_status.arduino_version = 'ESP32 Arduino v2.0.18';
|
||||
system_status.sdk_version = 'v4.4.7';
|
||||
system_status.arduino_version = 'Tasmota Arduino v3.3.8';
|
||||
system_status.sdk_version = '5.5.4.260407';
|
||||
system_status.psram = true;
|
||||
system_status.psram_size = 8189;
|
||||
system_status.free_psram = 8166;
|
||||
system_status.model = 'BBQKees Electronics S32';
|
||||
system_status.board = 'S32S3';
|
||||
|
||||
settings.board_profile = 'S32S3';
|
||||
settings.platform = 'ESP32S3';
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
+4
-1
@@ -43,6 +43,9 @@ build_flags =
|
||||
; ESPAsyncWebServer
|
||||
; -D WS_MAX_QUEUED_MESSAGES=0 ; not used, default 8
|
||||
; -D SSE_MAX_QUEUED_MESSAGES=1 ; for log messages, default 32
|
||||
; ESP_SSLClient
|
||||
-D ENABLE_PSRAM ; take the ~17KB of TLS buffers from PSRAM instead of the internal heap. The library
|
||||
; needs BOARD_HAS_PSRAM too, so boards without PSRAM keep using the internal heap
|
||||
-D EMSESP_MQTT_RUNNING_CORE=1 ; default 1
|
||||
; -D EMSESP_MQTT_STACKSIZE=5120 ; default
|
||||
-D EMSESP_UART_RUNNING_CORE=1 ; default any core
|
||||
@@ -90,7 +93,7 @@ board_build.littlefs_version = 2.0
|
||||
lib_deps =
|
||||
bblanchon/ArduinoJson @ 7.4.3
|
||||
ESP32Async/AsyncTCP @ 3.5.0
|
||||
ESP32Async/ESPAsyncWebServer @ 3.12.0
|
||||
ESP32Async/ESPAsyncWebServer @ 3.12.1
|
||||
https://github.com/mobizt/ReadyMail.git @ 0.4.2
|
||||
https://github.com/mobizt/ESP_SSLClient.git @ 3.1.3
|
||||
; https://github.com/emsesp/EMS-ESP-Modules.git @ 1.0.8
|
||||
|
||||
+2
-1
@@ -1349,4 +1349,5 @@ wifioff
|
||||
autonegotiation
|
||||
Mbit
|
||||
WROVER
|
||||
OLIMEXPOEW
|
||||
OLIMEXPOEW
|
||||
arduinoespressif
|
||||
@@ -0,0 +1,80 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Builds a LittleFS image from the data/ folder without going through PlatformIO.
|
||||
# Mirrors build_fs_image() in the pioarduino espressif32 platform builder, so the
|
||||
# output is interchangeable with "platformio run --target buildfs".
|
||||
#
|
||||
# Needs littlefs-python, which is already installed in the PlatformIO venv:
|
||||
# ~/.platformio/penv/bin/python scripts/build_littlefs.py
|
||||
#
|
||||
# Defaults match the s_16M_P board (2MB spiffs partition, littlefs 2.0).
|
||||
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
|
||||
from littlefs import LittleFS
|
||||
|
||||
|
||||
def auto_int(value):
|
||||
return int(value, 0)
|
||||
|
||||
|
||||
def build(source_dir, target_file, fs_size, block_size, disk_version):
|
||||
fs = LittleFS(
|
||||
block_size=block_size,
|
||||
block_count=fs_size // block_size,
|
||||
read_size=1,
|
||||
prog_size=1,
|
||||
cache_size=block_size,
|
||||
lookahead_size=32,
|
||||
block_cycles=500,
|
||||
name_max=64, # ESP-IDF default filename length
|
||||
disk_version=disk_version,
|
||||
mount=False,
|
||||
)
|
||||
|
||||
# explicit format() + mount() on a fresh instance, see the platform builder
|
||||
# for why the constructor's auto-mount is avoided
|
||||
fs.format()
|
||||
fs.mount()
|
||||
|
||||
for item in sorted(source_dir.rglob("*")):
|
||||
rel_path = item.relative_to(source_dir)
|
||||
fs_path = rel_path.as_posix()
|
||||
|
||||
if item.is_dir():
|
||||
fs.makedirs(fs_path, exist_ok=True)
|
||||
else:
|
||||
if rel_path.parent != Path("."):
|
||||
fs.makedirs(rel_path.parent.as_posix(), exist_ok=True)
|
||||
with fs.open(fs_path, "wb") as dest:
|
||||
dest.write(item.read_bytes())
|
||||
print(f" {fs_path}")
|
||||
|
||||
# ESP-IDF compatible mtime attribute
|
||||
mtime = int(item.stat().st_mtime)
|
||||
fs.setattr(fs_path, "t", mtime.to_bytes(4, "little"))
|
||||
|
||||
target_file.parent.mkdir(parents=True, exist_ok=True)
|
||||
target_file.write_bytes(fs.context.buffer)
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Build a LittleFS image from a folder")
|
||||
parser.add_argument("source", nargs="?", default="data", type=Path)
|
||||
parser.add_argument("target", nargs="?", default=Path(".pio/build/s_16M_P/littlefs.bin"), type=Path)
|
||||
parser.add_argument("--size", default=0x200000, type=auto_int, help="partition size, default 0x200000")
|
||||
parser.add_argument("--block", default=0x1000, type=auto_int, help="block size, default 0x1000")
|
||||
parser.add_argument("--version", default="2.0", help="littlefs disk version, default 2.0")
|
||||
args = parser.parse_args()
|
||||
|
||||
major, _, minor = args.version.partition(".")
|
||||
disk_version = (int(major) << 16) | int(minor or 0)
|
||||
|
||||
print(f"Building {args.target} ({args.size // 1024} KB) from {args.source}/")
|
||||
build(args.source, args.target, args.size, args.block, disk_version)
|
||||
print(f"Wrote {args.target.stat().st_size} bytes")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Executable
+26
@@ -0,0 +1,26 @@
|
||||
|
||||
ESPTOOL=~/.platformio/penv/bin/esptool
|
||||
PORT=/dev/ttyUSB0
|
||||
BUILD=../.pio/build/s_16M_P
|
||||
BOOT_APP0=~/.platformio/packages/framework-arduinoespressif32/tools/partitions/boot_app0.bin
|
||||
|
||||
# erase
|
||||
$ESPTOOL --chip esp32 --port $PORT --after no-reset erase-flash
|
||||
|
||||
# create the filesystem
|
||||
~/.platformio/penv/bin/python build_littlefs.py data $BUILD/littlefs.bin
|
||||
|
||||
# upload filesystem (spiffs partition @ 0xdf0000), leave halted so it doesn't boot yet
|
||||
$ESPTOOL --chip esp32 --port $PORT --baud 460800 \
|
||||
--before default-reset --after no-reset \
|
||||
write-flash -z --flash-mode dio --flash-freq 80m --flash-size detect \
|
||||
0xdf0000 $BUILD/littlefs.bin
|
||||
|
||||
# flash bootloader + partition table + app (app0 @ 0x490000), then boot
|
||||
$ESPTOOL --chip esp32 --port $PORT --baud 460800 \
|
||||
--before default-reset --after hard-reset \
|
||||
write-flash -z --flash-mode dio --flash-freq 80m --flash-size detect \
|
||||
0x1000 $BUILD/bootloader.bin \
|
||||
0x8000 $BUILD/partitions.bin \
|
||||
0xe000 $BOOT_APP0 \
|
||||
0x490000 $BUILD/firmware.bin
|
||||
@@ -8,7 +8,7 @@ set -e
|
||||
|
||||
cd interface
|
||||
rm -rf node_modules
|
||||
corepack use pnpm@latest
|
||||
pnpm self-update
|
||||
pnpm update
|
||||
pnpm install
|
||||
pnpm format
|
||||
@@ -17,7 +17,7 @@ pnpm lint
|
||||
|
||||
cd ../mock-api
|
||||
rm -rf node_modules
|
||||
corepack use pnpm@latest
|
||||
pnpm self-update
|
||||
pnpm update
|
||||
pnpm install
|
||||
pnpm format
|
||||
|
||||
@@ -87,6 +87,7 @@ void AnalogSensor::start(const bool factory_settings) {
|
||||
|
||||
return StateUpdateResult::CHANGED; // persist the change
|
||||
});
|
||||
LOG_DEBUG("Adding system sensors for core_voltage, supply_voltage and led");
|
||||
}
|
||||
reload(true); // fetch the list of sensors from our customization service
|
||||
|
||||
|
||||
@@ -108,7 +108,6 @@ static void setup_commands(std::shared_ptr<Commands> const & commands) {
|
||||
return std::vector<std::string>{"system", "users", "devices", "log", "ems", "values", "mqtt", "commands"};
|
||||
});
|
||||
|
||||
|
||||
//
|
||||
// System commands
|
||||
//
|
||||
@@ -294,7 +293,6 @@ static void setup_commands(std::shared_ptr<Commands> const & commands) {
|
||||
EMSESP::network_.reconnect();
|
||||
});
|
||||
|
||||
|
||||
commands->add_command(ShellContext::MAIN,
|
||||
CommandFlags::ADMIN,
|
||||
string_vector{F_(set), F_(board_profile)},
|
||||
|
||||
@@ -121,6 +121,10 @@
|
||||
#define EMSESP_DEFAULT_TELNET_ENABLED true
|
||||
#endif
|
||||
|
||||
#ifndef EMSESP_DEFAULT_AUTO_FW_CHECK
|
||||
#define EMSESP_DEFAULT_AUTO_FW_CHECK false
|
||||
#endif
|
||||
|
||||
#ifndef EMSESP_DEFAULT_MODBUS_ENABLED
|
||||
#define EMSESP_DEFAULT_MODBUS_ENABLED false
|
||||
#endif
|
||||
|
||||
@@ -237,7 +237,6 @@ const char * const DeviceValue::DeviceValueTAG_mqtt[] = {
|
||||
FL_(tag_src15)[0], // "src15"
|
||||
FL_(tag_src16)[0] // "src16"
|
||||
|
||||
|
||||
};
|
||||
|
||||
// count #tags once at compile time
|
||||
|
||||
+42
-12
@@ -1696,7 +1696,6 @@ void EMSESP::scheduled_fetch_values() {
|
||||
}
|
||||
|
||||
// EMSESP main class
|
||||
|
||||
EMSESP::EMSESP()
|
||||
#ifndef EMSESP_STANDALONE
|
||||
: telnet_([this](Stream & stream, const IPAddress & addr, uint16_t port) -> std::shared_ptr<uuid::console::Shell> {
|
||||
@@ -1728,6 +1727,13 @@ void EMSESP::start() {
|
||||
LOG_ERROR("LittleFS Mount Failed");
|
||||
return;
|
||||
}
|
||||
// else {
|
||||
// output filesystem folders and files for debugging
|
||||
// #if defined(EMSESP_DEBUG)
|
||||
// LOG_DEBUG("Listing root directory before:");
|
||||
// system_.listDir("/", 3); // show the contents of the root directory
|
||||
// #endif
|
||||
// }
|
||||
#endif
|
||||
|
||||
// do a quick scan of the filesystem to see if we a settings file in the /config folder
|
||||
@@ -1748,7 +1754,7 @@ void EMSESP::start() {
|
||||
nvs_.begin("ems-esp", false, "nvs"); // fallback to small nvs
|
||||
}
|
||||
#else
|
||||
nvs_.begin("ems-esp", false, "nvs");
|
||||
nvs_.begin("ems-esp", false, "nvs");
|
||||
#endif
|
||||
|
||||
// set valid GPIOs list based on ESP32 chip/platform type
|
||||
@@ -1760,9 +1766,15 @@ void EMSESP::start() {
|
||||
// loads core system services settings (mqtt, ap, ntp etc)
|
||||
esp32React.begin();
|
||||
|
||||
// output filesystem folders and files for debugging
|
||||
// #if defined(EMSESP_DEBUG)
|
||||
// LOG_DEBUG("Listing root directory after:");
|
||||
// system_.listDir("/", 3); // show the contents of the root directory
|
||||
// #endif
|
||||
|
||||
#ifndef EMSESP_STANDALONE
|
||||
if (factory_settings) {
|
||||
LOG_WARNING("No settings found on filesystem. Using factory settings.");
|
||||
LOG_WARNING("No settings found on filesystem. Initialising with factory settings...");
|
||||
// make sure OTAdata is updated with core3 (v3.9.0) format
|
||||
esp_ota_set_boot_partition(esp_ota_get_running_partition());
|
||||
}
|
||||
@@ -1777,11 +1789,16 @@ void EMSESP::start() {
|
||||
|
||||
LOG_DEBUG("System is running in Debug mode");
|
||||
|
||||
bool check_internal_sensors = false; // true to check for internal sensors
|
||||
bool force_analog_sensors = false; // true to add core_voltage, supply_voltage and led
|
||||
bool force_temperature_sensors = false; // true to add gateway_temperature
|
||||
|
||||
// check if the firmware is fresh, i.e. a new install or a new version has been uploaded
|
||||
// this is set in UploadFileService::uploadComplete()
|
||||
// this is also set in UploadFileService::uploadComplete()
|
||||
// and reset in System::set_partition_install_date()
|
||||
if (EMSESP::nvs_.getBool(EMSESP_NVS_BOOT_NEW_FIRMWARE)) {
|
||||
LOG_DEBUG("Firmware is a new install");
|
||||
check_internal_sensors = true; // force check for internal sensors
|
||||
} else {
|
||||
// check if the firmware has been uploaded via Serial/USB
|
||||
#if defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
@@ -1809,10 +1826,11 @@ void EMSESP::start() {
|
||||
};
|
||||
#endif
|
||||
|
||||
LOG_DEBUG("eFuse device information: %s", system_.getBBQKeesGatewayDetails().isEmpty() ? "not set" : system_.getBBQKeesGatewayDetails().c_str());
|
||||
|
||||
webSettingsService.begin(); // load EMS-ESP Application settings
|
||||
|
||||
LOG_DEBUG("System name: %s", system_.system_name().c_str());
|
||||
LOG_DEBUG("eFuse BBQKees Gateway Model: %s", system_.getBBQKeesGatewayDetails().isEmpty() ? "not set" : system_.getBBQKeesGatewayDetails().c_str());
|
||||
|
||||
// start network services. This will initialise WiFi or Ethernet depending on the settings.
|
||||
network_.begin();
|
||||
|
||||
@@ -1823,12 +1841,24 @@ void EMSESP::start() {
|
||||
webCustomEntityService.begin(); // load the custom telegram reads
|
||||
webSchedulerService.begin(); // load the scheduler events
|
||||
|
||||
// perform any system upgrades
|
||||
// check for any changes to the settings. skipped if it's a fresh factory install
|
||||
if (!factory_settings) {
|
||||
// perform any system upgrades
|
||||
if (system_.check_upgrade()) {
|
||||
LOG_WARNING("System needs a restart to apply new settings. Please wait.");
|
||||
system_.system_restart();
|
||||
};
|
||||
|
||||
// if it's a new install and we have nothing in the analog or temperature customizations
|
||||
// then assume its a fresh install and add back the internal sensors
|
||||
// we could also check for core_voltage, supply_voltage, led and gateway_temperature and add them if they are not present
|
||||
if (check_internal_sensors) {
|
||||
auto check_empty_customizations = [&](const WebCustomization & settings) {
|
||||
force_analog_sensors = settings.analogCustomizations.empty();
|
||||
force_temperature_sensors = settings.sensorCustomizations.empty();
|
||||
};
|
||||
webCustomizationService.read(check_empty_customizations);
|
||||
}
|
||||
}
|
||||
|
||||
// Load our library of known devices into stack mem. Names are stored in Flash memory
|
||||
@@ -1848,11 +1878,11 @@ void EMSESP::start() {
|
||||
#endif
|
||||
}
|
||||
|
||||
mqtt_.start(); // mqtt init
|
||||
system_.start(); // starts commands, led, adc, button, network (sets hostname), syslog & uart
|
||||
shower_.start(); // initialize shower timer and shower alert
|
||||
temperaturesensor_.start(factory_settings); // Temperature external sensors
|
||||
analogsensor_.start(factory_settings); // Analog external sensors
|
||||
mqtt_.start(); // mqtt init
|
||||
system_.start(); // starts commands, led, adc, button, network (sets hostname), syslog & uart
|
||||
shower_.start(); // initialize shower timer and shower alert
|
||||
temperaturesensor_.start(factory_settings || force_temperature_sensors); // Temperature external sensors
|
||||
analogsensor_.start(factory_settings || force_analog_sensors); // Analog external sensors
|
||||
|
||||
// start web services
|
||||
LOG_INFO("Starting Web Server");
|
||||
|
||||
@@ -1042,5 +1042,4 @@ int16_t Helpers::calc_dew(int16_t temp, uint8_t humi) {
|
||||
return dt;
|
||||
}
|
||||
|
||||
|
||||
} // namespace emsesp
|
||||
|
||||
+37
-10
@@ -35,6 +35,31 @@ int HttpClient::request(std::string url, const std::string & method, const std::
|
||||
return 0; // unsupported scheme
|
||||
}
|
||||
|
||||
// split the host from the path before anything is allocated, so a bad URL costs nothing
|
||||
url.replace(0, is_https ? 8 : 7, "");
|
||||
std::string host = url;
|
||||
auto index = url.find_first_of('/');
|
||||
if (index != std::string::npos) {
|
||||
host = url.substr(0, index);
|
||||
url.replace(0, index, "");
|
||||
} else {
|
||||
url = "/";
|
||||
}
|
||||
|
||||
if (host.empty()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ESP_SSLClient keeps the host in a fixed char[64] and strcpy()s into it without a length
|
||||
// check, so a longer name would corrupt whatever follows it and crash somewhere unrelated
|
||||
if (host.length() > MAX_HOSTNAME_LENGTH) {
|
||||
EMSESP::logger().warning("%s hostname is too long (%u characters, max is %u)",
|
||||
is_https ? "HTTPS" : "HTTP",
|
||||
(unsigned)host.length(),
|
||||
(unsigned)MAX_HOSTNAME_LENGTH);
|
||||
return 0;
|
||||
}
|
||||
|
||||
WiFiClient * basic_client = new WiFiClient;
|
||||
ESP_SSLClient * ssl_client = new ESP_SSLClient;
|
||||
if (is_https) {
|
||||
@@ -50,16 +75,6 @@ int HttpClient::request(std::string url, const std::string & method, const std::
|
||||
ssl_client->setTimeout(5); // seconds, drives BearSSL only - unused on the plain HTTP path
|
||||
ssl_client->setClient(basic_client, is_https); // enableSSL = false for plain HTTP
|
||||
|
||||
url.replace(0, is_https ? 8 : 7, "");
|
||||
std::string host = url;
|
||||
auto index = url.find_first_of('/');
|
||||
if (index != std::string::npos) {
|
||||
host = url.substr(0, index);
|
||||
url.replace(0, index, "");
|
||||
} else {
|
||||
url = "/";
|
||||
}
|
||||
|
||||
const uint16_t port = is_https ? 443 : 80;
|
||||
if (ssl_client->connect(host.c_str(), port)) {
|
||||
bool content_set = false;
|
||||
@@ -97,16 +112,25 @@ int HttpClient::request(std::string url, const std::string & method, const std::
|
||||
// the stream goes idle, or the overall budget runs out
|
||||
const uint32_t started = millis();
|
||||
uint32_t last_data = started;
|
||||
bool truncated = false;
|
||||
while (millis() - started < TOTAL_TIMEOUT_MS) {
|
||||
const int avail = ssl_client->available();
|
||||
if (avail > 0) {
|
||||
if (result.length() >= MAX_RESPONSE_BYTES) {
|
||||
truncated = true;
|
||||
break;
|
||||
}
|
||||
uint8_t buf[128];
|
||||
const size_t want = (avail < (int)sizeof(buf)) ? (size_t)avail : sizeof(buf);
|
||||
const int len = ssl_client->read(buf, want);
|
||||
if (len > 0) {
|
||||
result.append(reinterpret_cast<const char *>(buf), len);
|
||||
last_data = millis();
|
||||
continue;
|
||||
}
|
||||
// available() reported bytes the client won't hand over. Yielding here keeps a
|
||||
// stale count from busy-spinning the whole read budget on this task's core
|
||||
delay(1);
|
||||
continue;
|
||||
}
|
||||
if (!ssl_client->connected()) {
|
||||
@@ -121,6 +145,9 @@ int HttpClient::request(std::string url, const std::string & method, const std::
|
||||
ssl_client->stop();
|
||||
|
||||
const auto received = result.length();
|
||||
if (truncated) {
|
||||
EMSESP::logger().warning("%s response from %s truncated at %u bytes", is_https ? "HTTPS" : "HTTP", host.c_str(), (unsigned)received);
|
||||
}
|
||||
|
||||
// parse the status line "HTTP/1.x <code> <reason>". stoi() would abort rather than throw on
|
||||
// a malformed response, since the firmware is built with -fno-exceptions
|
||||
|
||||
@@ -34,6 +34,12 @@ class HttpClient {
|
||||
static constexpr uint32_t FIRST_BYTE_TIMEOUT_MS = 8000; // how long the server may take to start replying
|
||||
static constexpr uint32_t IDLE_TIMEOUT_MS = 500; // gap in the stream that marks the end of a response
|
||||
static constexpr uint32_t TOTAL_TIMEOUT_MS = 10000; // ceiling for the whole read
|
||||
|
||||
// ceiling on the response we'll buffer. Without it a chatty or hijacked endpoint can grow the
|
||||
// result string until the heap runs out, which aborts the firmware since it's built -fno-exceptions
|
||||
static constexpr size_t MAX_RESPONSE_BYTES = 32 * 1024;
|
||||
|
||||
static constexpr size_t MAX_HOSTNAME_LENGTH = 63; // ESP_SSLClient stores the host in a char[64]
|
||||
};
|
||||
|
||||
} // namespace emsesp
|
||||
|
||||
@@ -238,7 +238,6 @@ ModbusMessage Modbus::handleRead(const ModbusMessage & request) {
|
||||
key,
|
||||
[](const EntityModbusInfo & a, const EntityModbusInfoKey & b) { return a.isLessThan(b); });
|
||||
|
||||
|
||||
if (modbusInfo == std::end(modbus_register_mappings) || !modbusInfo->equals(key)) {
|
||||
// combination of device_type/tag_type/register_offset does not exist
|
||||
LOG_ERROR("combination of device_type/tag_type/register_offset does not exist");
|
||||
@@ -324,7 +323,6 @@ ModbusMessage Modbus::handleWrite(const ModbusMessage & request) {
|
||||
|
||||
LOG_DEBUG("Tag %d, offset %d", tag, register_offset);
|
||||
|
||||
|
||||
// binary search in modbus infos
|
||||
auto key = EntityModbusInfoKey(device_type, tag_type, register_offset);
|
||||
auto modbusInfo = std::lower_bound(std::begin(modbus_register_mappings),
|
||||
|
||||
+44
-9
@@ -88,6 +88,11 @@ void Network::begin() {
|
||||
pinMode(eth_power_, OUTPUT);
|
||||
digitalWrite(eth_power_, LOW);
|
||||
}
|
||||
|
||||
// report it here rather than in startEthernet(), which is never reached because initialPhase() has already skipped Ethernet
|
||||
if (phy_type_ != PHY_type::PHY_TYPE_NONE && ethClockConflictsPsram()) {
|
||||
LOG_ERROR("Ethernet clock mode %d (GPIO16/17) conflicts with PSRAM - disabling Ethernet", eth_clock_mode_);
|
||||
}
|
||||
#endif
|
||||
|
||||
// avoid duplicate registration, so register the lambdas only once across the lifetime of this Network instance
|
||||
@@ -225,15 +230,22 @@ void Network::reconnect() {
|
||||
begin();
|
||||
}
|
||||
|
||||
// the RMII clock output on GPIO16/17 shares its pins with PSRAM, so Ethernet can't be used at all on
|
||||
// a board that has both. Ethernet is skipped for the whole boot when this is the case
|
||||
bool Network::ethClockConflictsPsram() const {
|
||||
#if CONFIG_IDF_TARGET_ESP32 && !defined(EMSESP_STANDALONE)
|
||||
return ESP.getPsramSize() && ((eth_clock_mode_t)eth_clock_mode_ == ETH_CLOCK_GPIO16_OUT || (eth_clock_mode_t)eth_clock_mode_ == ETH_CLOCK_GPIO17_OUT);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
// pick the first phase that has the hardware/config to even be attempted on this device.
|
||||
// boards without an Ethernet PHY skip straight to WIFI; without a configured SSID, straight to AP
|
||||
// (unless AP provision mode is Never — then stay on WIFI and keep waiting)
|
||||
NetPhase Network::initialPhase() const {
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
|
||||
bool eth_clock_conflicts_psram =
|
||||
ESP.getPsramSize() && ((eth_clock_mode_t)eth_clock_mode_ == ETH_CLOCK_GPIO16_OUT || (eth_clock_mode_t)eth_clock_mode_ == ETH_CLOCK_GPIO17_OUT);
|
||||
if (phy_type_ != PHY_type::PHY_TYPE_NONE && !eth_clock_conflicts_psram) {
|
||||
if (phy_type_ != PHY_type::PHY_TYPE_NONE && !ethClockConflictsPsram()) {
|
||||
return NetPhase::ETHERNET;
|
||||
}
|
||||
#endif
|
||||
@@ -605,11 +617,6 @@ void Network::startEthernet() {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ESP.getPsramSize() && ((eth_clock_mode_t)eth_clock_mode_ == ETH_CLOCK_GPIO16_OUT || (eth_clock_mode_t)eth_clock_mode_ == ETH_CLOCK_GPIO17_OUT)) {
|
||||
LOG_ERROR("Ethernet clock mode %d (GPIO16/17) conflicts with PSRAM - disabling Ethernet", eth_clock_mode_);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
// The Tasmota SDK is built with CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES=2, so the Ethernet MAC is derived as
|
||||
// a locally-administered address from base+1 instead of the universal base+3 that Arduino Core 2 used.
|
||||
@@ -656,9 +663,11 @@ void Network::startEthernet() {
|
||||
ETH.setFullDuplex(false);
|
||||
}
|
||||
|
||||
// start the Eth module
|
||||
if (ETH.begin(type, eth_phy_addr_, 23, 18, eth_power_, (eth_clock_mode_t)eth_clock_mode_)) {
|
||||
// LOG_DEBUG("Ethernet module found - initialising");
|
||||
ethernet_started_ = true;
|
||||
ethernet_init_failed_ = false;
|
||||
ethernet_connect_pending_ = true;
|
||||
|
||||
// check whether DHCP already announced us under lwIP's default hostname, before we correct it
|
||||
@@ -687,12 +696,38 @@ void Network::startEthernet() {
|
||||
ETH.config(localIP_, gatewayIP_, subnetMask_, dnsIP1_, dnsIP2_);
|
||||
}
|
||||
} else {
|
||||
ethernet_init_failed_ = true;
|
||||
LOG_ERROR("Failed to start Ethernet");
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
// Ethernet state as a printable string, for the console and the API
|
||||
// returns nullptr when this board has no Ethernet PHY configured, so callers can omit Ethernet completely
|
||||
const char * Network::ethernet_status() const {
|
||||
#if CONFIG_IDF_TARGET_ESP32 && !defined(EMSESP_STANDALONE)
|
||||
if (phy_type_ == PHY_type::PHY_TYPE_NONE) {
|
||||
return nullptr;
|
||||
}
|
||||
if (ethClockConflictsPsram()) {
|
||||
return "disabled - clock mode GPIO16/17 conflicts with PSRAM";
|
||||
}
|
||||
if (ethernet_connected()) {
|
||||
return "connected";
|
||||
}
|
||||
if (ethernet_init_failed_) {
|
||||
return "failed to initialize - no PHY found, check the board profile";
|
||||
}
|
||||
if (!ethernet_started_) {
|
||||
return "not started";
|
||||
}
|
||||
return ethernet_connect_pending_ ? "connecting" : "no connection";
|
||||
#else
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
// check if the network is connected and set network_ip_ / network_iface_ / has_ipv6_
|
||||
// Iterates over every esp-netif that exists, prioritizing Ethernet > WiFi > AP
|
||||
void Network::findNetworks() {
|
||||
|
||||
+6
-3
@@ -132,9 +132,10 @@ class Network {
|
||||
return reconnect_count_;
|
||||
}
|
||||
|
||||
std::string getLocalIP() const;
|
||||
std::string getMacAddress() const;
|
||||
uint8_t getStationNum() const;
|
||||
std::string getLocalIP() const;
|
||||
std::string getMacAddress() const;
|
||||
uint8_t getStationNum() const;
|
||||
const char * ethernet_status() const;
|
||||
|
||||
void reconnect();
|
||||
|
||||
@@ -192,6 +193,7 @@ class Network {
|
||||
const char * disconnectReason(uint8_t code);
|
||||
void stopAP();
|
||||
NetPhase initialPhase() const;
|
||||
bool ethClockConflictsPsram() const;
|
||||
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic push
|
||||
@@ -216,6 +218,7 @@ class Network {
|
||||
bool wifi_events_registered_ = false; // ensure WiFi.onEvent() handlers are registered only once across begin()/reconnect() cycles
|
||||
bool eth_hostname_handler_registered_ = false; // for the ETHERNET_EVENT_START hostname handler
|
||||
bool ethernet_started_ = false; // ETH.begin() succeeded; the driver runs for the lifetime of the boot
|
||||
bool ethernet_init_failed_ = false; // ETH.begin() failed, so the driver was never installed
|
||||
bool wifi_ever_connected_ = false; // set true once we've successfully obtained an IP
|
||||
bool ethernet_ever_connected_ = false; // set true once we've successfully obtained an IP
|
||||
bool wifi_radio_off_ = false; // STA powered down because Ethernet is carrying the traffic
|
||||
|
||||
+71
-5
@@ -460,6 +460,7 @@ void System::get_partition_info() {
|
||||
auto t = time(nullptr);
|
||||
// write timestamp always with new version, if clock is not set, this will be updated with ntp
|
||||
EMSESP::nvs_.putULong(c, t);
|
||||
LOG_DEBUG("Updated NVS partition due to version found");
|
||||
}
|
||||
|
||||
// Loop through all available partitions and update map with the version info pulled from NVS
|
||||
@@ -719,6 +720,7 @@ void System::store_settings(WebSettings & settings) {
|
||||
system_name_ = settings.system_name;
|
||||
developer_mode_ = settings.developer_mode;
|
||||
disable_reset_ = settings.disable_reset;
|
||||
auto_fw_check_ = settings.auto_fw_check;
|
||||
}
|
||||
|
||||
// Starts up core services
|
||||
@@ -867,7 +869,7 @@ bool System::loop() {
|
||||
void System::send_info_mqtt() {
|
||||
static uint8_t _connection = 0;
|
||||
uint8_t connection = (EMSESP::network_.ethernet_connected() ? 1 : 0) + (EMSESP::network_.wifi_connected() ? 2 : 0) + (ntp_connected_ ? 4 : 0)
|
||||
+ (EMSESP::network_.has_ipv6() ? 8 : 0);
|
||||
+ (EMSESP::network_.has_ipv6() ? 8 : 0);
|
||||
// check if connection status has changed
|
||||
if (!Mqtt::connected() || connection == _connection) {
|
||||
return;
|
||||
@@ -1092,7 +1094,7 @@ void System::show_system(uuid::console::Shell & shell) {
|
||||
shell.println();
|
||||
shell.println("System:");
|
||||
shell.printfln(" Version: %s", EMSESP_APP_VERSION);
|
||||
shell.printfln(" System name: %s", system_name_.c_str());
|
||||
shell.printfln(" System name: %s", system_name().c_str());
|
||||
#ifndef EMSESP_STANDALONE
|
||||
shell.printfln(" Platform: %s (%s)", EMSESP_PLATFORM, ESP.getChipModel());
|
||||
shell.printfln(" Model: %s", getBBQKeesGatewayDetails().c_str());
|
||||
@@ -1125,6 +1127,12 @@ void System::show_system(uuid::console::Shell & shell) {
|
||||
shell.printfln(" Internal heap free/largest block: %u KB / %u KB",
|
||||
heap_caps_get_free_size(MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT) / 1024,
|
||||
heap_caps_get_largest_free_block(MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT) / 1024);
|
||||
// Lowest the loop task's stack has ever been since boot. EMSESP::loop() runs the blocking HTTP
|
||||
// client and all the JSON work on this task, and a TLS handshake alone can want several KB
|
||||
TaskHandle_t loop_task = xTaskGetHandle("loopTask");
|
||||
if (loop_task != nullptr) {
|
||||
shell.printfln(" Loop task stack min free/total: %u / %u bytes", (unsigned)uxTaskGetStackHighWaterMark(loop_task), (unsigned)getArduinoLoopTaskStackSize());
|
||||
}
|
||||
#endif
|
||||
shell.printfln(" App used/free: %lu KB / %lu KB", appUsed(), appFree());
|
||||
uint32_t FSused = LittleFS.usedBytes() / 1024;
|
||||
@@ -1182,6 +1190,55 @@ void System::show_system(uuid::console::Shell & shell) {
|
||||
installed.c_str(),
|
||||
(strcmp(esp_ota_get_running_partition()->label, partition.first.c_str()) == 0) ? "** active **" : "");
|
||||
}
|
||||
// List all NVS values
|
||||
#ifndef EMSESP_STANDALONE
|
||||
shell.println(" NVS values:");
|
||||
const char * nvs_part = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, "nvs1") ? "nvs1" : "nvs"; // nvs1 is on 16MBs
|
||||
nvs_iterator_t it = nullptr;
|
||||
esp_err_t err = nvs_entry_find(nvs_part, "ems-esp", NVS_TYPE_ANY, &it);
|
||||
while (err == ESP_OK) {
|
||||
nvs_entry_info_t info;
|
||||
nvs_entry_info(it, &info);
|
||||
shell.printf(" %s", info.key);
|
||||
// also print the value depending on the type
|
||||
switch (info.type) {
|
||||
case NVS_TYPE_I8:
|
||||
shell.printfln(" = %d", (int)EMSESP::nvs_.getChar(info.key));
|
||||
break;
|
||||
case NVS_TYPE_U8:
|
||||
shell.printfln(" = %u", (unsigned int)EMSESP::nvs_.getUChar(info.key));
|
||||
break;
|
||||
case NVS_TYPE_I32:
|
||||
shell.printfln(" = %d", (int)EMSESP::nvs_.getInt(info.key));
|
||||
break;
|
||||
case NVS_TYPE_U32:
|
||||
shell.printfln(" = %u", (unsigned int)EMSESP::nvs_.getUInt(info.key));
|
||||
break;
|
||||
case NVS_TYPE_I64:
|
||||
shell.printfln(" = %lld", (long long)EMSESP::nvs_.getLong64(info.key));
|
||||
break;
|
||||
case NVS_TYPE_U64:
|
||||
shell.printfln(" = %llu", (unsigned long long)EMSESP::nvs_.getULong64(info.key));
|
||||
break;
|
||||
case NVS_TYPE_BLOB:
|
||||
shell.printfln(" = %f", EMSESP::nvs_.getDouble(info.key)); // bytes used for double values
|
||||
break;
|
||||
case NVS_TYPE_STR:
|
||||
shell.printfln(" = %s", EMSESP::nvs_.getString(info.key).c_str());
|
||||
break;
|
||||
default:
|
||||
shell.printfln(" = unknown");
|
||||
break;
|
||||
}
|
||||
err = nvs_entry_next(&it);
|
||||
}
|
||||
if (it != nullptr) {
|
||||
nvs_release_iterator(it); // just in case
|
||||
}
|
||||
if (err == ESP_OK) {
|
||||
shell.println();
|
||||
}
|
||||
#endif
|
||||
|
||||
shell.println();
|
||||
shell.println("Network:");
|
||||
@@ -1234,10 +1291,12 @@ void System::show_system(uuid::console::Shell & shell) {
|
||||
break;
|
||||
}
|
||||
|
||||
// show Ethernet if connected
|
||||
// show the Ethernet state, and the details when it's actually up
|
||||
const char * ethernet_status = EMSESP::network_.ethernet_status();
|
||||
if (ethernet_status != nullptr) {
|
||||
shell.printfln(" Ethernet Status: %s", ethernet_status);
|
||||
}
|
||||
if (EMSESP::network_.ethernet_connected()) {
|
||||
shell.println();
|
||||
shell.printfln(" Ethernet Status: connected");
|
||||
shell.printfln(" Ethernet MAC address: %s", ETH.macAddress().c_str());
|
||||
shell.printfln(" Hostname: %s", ETH.getHostname());
|
||||
shell.printfln(" IPv4 address: %s/%s", uuid::printable_to_string(ETH.localIP()).c_str(), uuid::printable_to_string(ETH.subnetMask()).c_str());
|
||||
@@ -2675,6 +2734,7 @@ bool System::command_info(const char * value, const int8_t id, JsonObject output
|
||||
node["forceHeatingOff"] = settings.boiler_heatingoff;
|
||||
node["developerMode"] = settings.developer_mode;
|
||||
node["disableReset"] = settings.disable_reset;
|
||||
node["autoFwCheck"] = settings.auto_fw_check;
|
||||
});
|
||||
|
||||
// Devices - show EMS devices if we have any
|
||||
@@ -2918,6 +2978,12 @@ bool System::command_format(const char * value, const int8_t id) {
|
||||
LOG_ERROR("Format command not available in standalone or test mode");
|
||||
#endif
|
||||
|
||||
// in debug we also remove all the NVS keys
|
||||
#ifdef EMSESP_DEBUG
|
||||
LOG_DEBUG("Setting NVS fresh firmware flag");
|
||||
EMSESP::nvs_.putBool(EMSESP_NVS_BOOT_NEW_FIRMWARE, true);
|
||||
#endif
|
||||
|
||||
// restart will be handled by the main loop
|
||||
EMSESP::system_.systemStatus(SYSTEM_STATUS::SYSTEM_STATUS_RESTART_REQUESTED);
|
||||
return true;
|
||||
|
||||
@@ -207,6 +207,14 @@ class System {
|
||||
disable_reset_ = disable_reset;
|
||||
}
|
||||
|
||||
bool auto_fw_check() {
|
||||
return auto_fw_check_;
|
||||
}
|
||||
|
||||
void auto_fw_check(bool auto_fw_check) {
|
||||
auto_fw_check_ = auto_fw_check;
|
||||
}
|
||||
|
||||
// Boolean Format API/MQTT
|
||||
uint8_t bool_format() {
|
||||
return bool_format_;
|
||||
@@ -447,6 +455,7 @@ class System {
|
||||
uint32_t modbus_timeout_;
|
||||
bool developer_mode_;
|
||||
bool disable_reset_;
|
||||
bool auto_fw_check_;
|
||||
uint32_t fstotal_;
|
||||
uint32_t psram_;
|
||||
uint32_t appused_;
|
||||
|
||||
@@ -213,7 +213,7 @@ void TemperatureSensor::loop() {
|
||||
if (!EMSESP::nvs_.isKey("intTemp")) {
|
||||
EMSESP::nvs_.putString("intTemp", s->id());
|
||||
}
|
||||
// LOG_NOTICE("Adding system sensor for gateway temperature %s", s->id().c_str());
|
||||
LOG_DEBUG("Adding system sensor for gateway_temperature");
|
||||
EMSESP::webCustomizationService.update([&](WebCustomization & settings) {
|
||||
auto newSensor = SensorCustomization();
|
||||
strlcpy(newSensor.id, s->id(), sizeof(newSensor.id));
|
||||
|
||||
@@ -1145,7 +1145,6 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const
|
||||
EMSESP::send_read_request(0xC2, device_id, 0, 20); // read last errorcode on start (not broadcasted)
|
||||
EMSESP::send_read_request(0xC6, device_id, 0, 21); // read last errorcode on start (not broadcasted)
|
||||
|
||||
|
||||
if (!isHeatPump() && model() != EMSdevice::EMS_DEVICE_FLAG_HIU) {
|
||||
register_telegram_type(0x04, "UBAFactory", true, MAKE_PF_CB(process_UBAFactory), 21);
|
||||
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &nomPower_, DeviceValueType::UINT8, FL_(nomPower), DeviceValueUOM::KW, MAKE_CF_CB(set_nomPower));
|
||||
@@ -2452,7 +2451,6 @@ bool Boiler::set_ww_temp(const char * value, const int8_t id) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Set the lower dhw temperature 0xEA
|
||||
bool Boiler::set_ww_temp_low(const char * value, const int8_t id) {
|
||||
int v;
|
||||
|
||||
@@ -66,7 +66,6 @@ Extension::Extension(uint8_t device_type, uint8_t device_id, uint8_t product_id,
|
||||
// register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &errorState_, DeviceValueType::BOOL, FL_(error), DeviceValueUOM::NONE);
|
||||
}
|
||||
|
||||
|
||||
// extension(0x15) -W-> Me(0x0B), EM100SetMessage(0x0935), data: 00 00 64 50 14
|
||||
// need to be fetched
|
||||
void Extension::process_EM100SetMessage(const std::shared_ptr<const Telegram> & telegram) {
|
||||
|
||||
@@ -40,7 +40,6 @@ class Extension : public EMSdevice {
|
||||
bool set_minT(const char * value, const int8_t id);
|
||||
bool set_maxT(const char * value, const int8_t id);
|
||||
|
||||
|
||||
int16_t headerTemp_; // T0
|
||||
uint8_t input_; // IO1
|
||||
// uint8_t errorState_; // OE1
|
||||
|
||||
@@ -81,7 +81,6 @@ class Heatsource : public EMSdevice {
|
||||
void process_amCommandMessage(const std::shared_ptr<const Telegram> & telegram);
|
||||
void process_amExtraMessage(const std::shared_ptr<const Telegram> & telegram);
|
||||
|
||||
|
||||
bool set_vr2Config(const char * value, const int8_t id); // pos 12: off(00)/Keelbypass(01)/(hc1pump(02) only standalone)
|
||||
bool set_ahsActivated(const char * value, const int8_t id); // pos 00: Alternate heat source activation: No(00),Yes(01)
|
||||
bool set_aPumpConfig(const char * value, const int8_t id); // pos 04: Buffer primary pump->Config pump: No(00),Yes(01)
|
||||
|
||||
@@ -115,7 +115,6 @@ class Solar : public EMSdevice {
|
||||
// telegram 0x361 Differential control
|
||||
uint8_t diffControl_; // is *10
|
||||
|
||||
|
||||
// telegram 0x380
|
||||
uint8_t climateZone_; // climate zone identifier
|
||||
uint16_t collector1Area_; // Area of collector field 1
|
||||
|
||||
@@ -3012,7 +3012,6 @@ bool Thermostat::set_R3000Holiday(const char * value, const int8_t id) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// set pause in hours
|
||||
bool Thermostat::set_pause(const char * value, const int8_t id) {
|
||||
auto hc = heating_circuit(id);
|
||||
@@ -3668,7 +3667,6 @@ bool Thermostat::set_reducemode(const char * value, const int8_t id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// sets the thermostat reducemode for RC35 vacations
|
||||
bool Thermostat::set_vacreducemode(const char * value, const int8_t id) {
|
||||
auto hc = heating_circuit(id);
|
||||
@@ -3983,7 +3981,6 @@ bool Thermostat::set_wwSwitchTime(const char * value, const int8_t id) {
|
||||
}
|
||||
char out[sizeof(dhw->wwSwitchTime_)] = {'\0'};
|
||||
|
||||
|
||||
if (set_switchtime(value, 0x38, out, sizeof(out))) {
|
||||
if (strlen(out)) {
|
||||
has_update(dhw->wwSwitchTime_, out, sizeof(dhw->wwSwitchTime_));
|
||||
|
||||
@@ -233,7 +233,6 @@ void Water::process_IPMParameterWW(const std::shared_ptr<const Telegram> & teleg
|
||||
// has_bitupdate(telegram, wwChargeType_, 10, 0); // 0 = charge pump, 0xff = 3-way valve
|
||||
}
|
||||
|
||||
|
||||
// 0x1E, only16 bit temperature
|
||||
// Mixer(0x41) -> Boiler(0x08), HydrTemp(0x1E), data: 01 D8
|
||||
void Water::process_IPMHydrTemp(const std::shared_ptr<const Telegram> & telegram) {
|
||||
@@ -399,7 +398,6 @@ bool Water::set_wwRequiredTemp(const char * value, const int8_t id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool Water::set_wwFlowTempOffset(const char * value, const int8_t id) {
|
||||
int n;
|
||||
if (!Helpers::value2number(value, n)) {
|
||||
|
||||
@@ -81,7 +81,6 @@ class Water : public EMSdevice {
|
||||
int8_t wwHystOff_; // Hyst off (default -1)
|
||||
uint8_t wwFlowTempOffset_; // default 40
|
||||
|
||||
|
||||
void process_SM100wwTemperature(const std::shared_ptr<const Telegram> & telegram);
|
||||
void process_SM100wwStatus(const std::shared_ptr<const Telegram> & telegram);
|
||||
void process_SM100wwStatus2(const std::shared_ptr<const Telegram> & telegram);
|
||||
@@ -100,7 +99,6 @@ class Water : public EMSdevice {
|
||||
void process_IPMHydrTemp(const std::shared_ptr<const Telegram> & telegram);
|
||||
void process_IPMParameterWW(const std::shared_ptr<const Telegram> & telegram);
|
||||
|
||||
|
||||
bool set_wwSelTemp(const char * value, const int8_t id);
|
||||
bool set_wwMaxTemp(const char * value, const int8_t id);
|
||||
bool set_wwRedTemp(const char * value, const int8_t id);
|
||||
|
||||
@@ -1 +1 @@
|
||||
#define EMSESP_APP_VERSION "3.9.0-dev.9"
|
||||
#define EMSESP_APP_VERSION "3.9.0-dev.10"
|
||||
|
||||
@@ -77,7 +77,6 @@ bool Test::test(const std::string & cmd, int8_t id1, int8_t id2) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// the tests take a lot of memory when built for the ESP32
|
||||
// so only including the full set in standalone, otherwise a limited selection of basic tests
|
||||
@@ -665,7 +664,6 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
|
||||
EMSESP::webAPIService.webAPIService(&request);
|
||||
Serial.println();
|
||||
|
||||
|
||||
request.url("/api/thermostat/hc2/entities");
|
||||
EMSESP::webAPIService.webAPIService(&request);
|
||||
Serial.println();
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* ESP32 UART port by @ArwedL and improved by @MichaelDvP. See https://github.com/emsesp/EMS-ESP/issues/380
|
||||
*/
|
||||
|
||||
@@ -57,7 +57,7 @@ void WebCustomization::read(WebCustomization & customizations, JsonObject root)
|
||||
sensorJson["id"] = (const char *)sensor.id; // ID of dallas temperature sensor chip
|
||||
sensorJson["name"] = (const char *)sensor.name; // n
|
||||
sensorJson["offset"] = sensor.offset; // o
|
||||
sensorJson["is_system"] = sensor.is_system; // s for gateway_temperature
|
||||
sensorJson["is_system"] = sensor.is_system; // s true for gateway_temperature
|
||||
}
|
||||
|
||||
// Analog Sensor customization
|
||||
@@ -70,7 +70,7 @@ void WebCustomization::read(WebCustomization & customizations, JsonObject root)
|
||||
sensorJson["factor"] = sensor.factor; // f
|
||||
sensorJson["uom"] = sensor.uom; // u
|
||||
sensorJson["type"] = sensor.type; // t
|
||||
sensorJson["is_system"] = sensor.is_system; // s for core_voltage, supply_voltage
|
||||
sensorJson["is_system"] = sensor.is_system; // s true for core_voltage, supply_voltage
|
||||
}
|
||||
|
||||
// Masked entities customization and custom device name (optional)
|
||||
|
||||
@@ -94,7 +94,7 @@ void WebLogService::show(Shell & shell) {
|
||||
}
|
||||
|
||||
shell.println();
|
||||
shell.printfln("Recent Log:");
|
||||
shell.printfln("Last %d messages:", log_messages_.size());
|
||||
shell.println();
|
||||
|
||||
for (const auto & message : log_messages_) {
|
||||
|
||||
@@ -85,6 +85,7 @@ void WebSettings::read(WebSettings & settings, JsonObject root) {
|
||||
root["modbus_timeout"] = settings.modbus_timeout;
|
||||
root["developer_mode"] = settings.developer_mode;
|
||||
root["disable_reset"] = settings.disable_reset;
|
||||
root["auto_fw_check"] = settings.auto_fw_check;
|
||||
root["email_enabled"] = settings.email_enabled;
|
||||
root["email_security"] = settings.email_security;
|
||||
root["email_server"] = settings.email_server;
|
||||
@@ -310,6 +311,12 @@ StateUpdateResult WebSettings::update(JsonObject root, WebSettings & settings) {
|
||||
settings.disable_reset = root["disable_reset"];
|
||||
EMSESP::system_.disable_reset(settings.disable_reset);
|
||||
|
||||
settings.auto_fw_check = root["auto_fw_check"] | EMSESP_DEFAULT_AUTO_FW_CHECK;
|
||||
EMSESP::system_.auto_fw_check(settings.auto_fw_check);
|
||||
if (settings.auto_fw_check && !original_settings.auto_fw_check) {
|
||||
EMSESP::webStatusService.schedule_versions_refresh(); // just switched on, so look straight away
|
||||
}
|
||||
|
||||
settings.bool_dashboard = root["bool_dashboard"] | EMSESP_DEFAULT_BOOL_FORMAT;
|
||||
EMSESP::system_.bool_dashboard(settings.bool_dashboard);
|
||||
|
||||
@@ -456,7 +463,7 @@ void WebSettings::set_board_profile(WebSettings & settings) {
|
||||
String bbq_board = EMSESP::system_.getBBQKeesGatewayDetails(FUSE_VALUE::BOARD);
|
||||
if (!bbq_board.isEmpty() && settings.board_profile != "CUSTOM") {
|
||||
#if defined(EMSESP_DEBUG)
|
||||
EMSESP::logger().info("Overriding board profile with fuse value %s", bbq_board.c_str());
|
||||
EMSESP::logger().info("Overriding board profile with eFuse value %s", bbq_board.c_str());
|
||||
#endif
|
||||
settings.board_profile = bbq_board;
|
||||
}
|
||||
|
||||
@@ -122,6 +122,7 @@ class WebSettings {
|
||||
|
||||
bool developer_mode; // developer mode
|
||||
bool disable_reset; // disable reset
|
||||
bool auto_fw_check; // periodically check emsesp.org for a newer firmware version
|
||||
|
||||
static void read(WebSettings & settings, JsonObject root);
|
||||
static StateUpdateResult update(JsonObject root, WebSettings & settings);
|
||||
|
||||
@@ -348,7 +348,20 @@ void WebStatusService::getVersions(JsonObject root) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!versions_cache_valid_) {
|
||||
// take a snapshot, since the loop task can be rewriting the cache while we run on AsyncTCP
|
||||
VersionInfo stable;
|
||||
VersionInfo dev;
|
||||
bool cache_valid;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock{versions_mutex_};
|
||||
cache_valid = versions_cache_valid_;
|
||||
stable = versions_stable_;
|
||||
dev = versions_dev_;
|
||||
}
|
||||
|
||||
versions_fetch_requested_ = true;
|
||||
|
||||
if (!cache_valid) {
|
||||
// no successful fetch yet (no network, fetch pending, or parse error)
|
||||
return;
|
||||
}
|
||||
@@ -364,8 +377,8 @@ void WebStatusService::getVersions(JsonObject root) {
|
||||
out["upgradeable"] = info.upgradeable;
|
||||
};
|
||||
|
||||
add_section("stable", versions_stable_);
|
||||
add_section("dev", versions_dev_);
|
||||
add_section("stable", stable);
|
||||
add_section("dev", dev);
|
||||
#else
|
||||
// standalone/test build: provide deterministic dummy data
|
||||
JsonObject stable_out = root["stable"].to<JsonObject>();
|
||||
@@ -383,17 +396,23 @@ void WebStatusService::getVersions(JsonObject root) {
|
||||
// schedule the next versions.json fetch a few seconds out so the network stack has time to settle
|
||||
// (DHCP completion, default-netif assignment and DNS server propagation through lwip)
|
||||
void WebStatusService::schedule_versions_refresh() {
|
||||
uint32_t next = uuid::get_uptime() + VERSIONS_INITIAL_FETCH_DELAY_MS;
|
||||
versions_failures_ = 0; // a fresh link is a fresh chance, so start again from the short retry delay
|
||||
uint32_t next = uuid::get_uptime() + VERSIONS_INITIAL_FETCH_DELAY_MS;
|
||||
if (next == 0) {
|
||||
next = 1; // 0 is the "idle" sentinel — never let the wrap land there
|
||||
}
|
||||
versions_next_fetch_ms_ = next;
|
||||
}
|
||||
|
||||
// periodic refresh (1 hour) of the cached versions.json
|
||||
// runs on the main loop task, which has a much bigger stack than AsyncTCP needed for https
|
||||
// refresh of the cached versions.json, at most once a day
|
||||
void WebStatusService::loop() {
|
||||
#ifndef EMSESP_STANDALONE
|
||||
// with auto_fw_check off we only reach out to emsesp.org when the WebUI asks for version
|
||||
// information, so an unattended system never contacts it at all
|
||||
if (!EMSESP::system_.auto_fw_check() && !versions_fetch_requested_) {
|
||||
return;
|
||||
}
|
||||
|
||||
// need a network
|
||||
if (!EMSESP::network_.network_connected()) {
|
||||
return;
|
||||
@@ -409,8 +428,20 @@ void WebStatusService::loop() {
|
||||
return;
|
||||
}
|
||||
|
||||
bool ok = refresh_versions_cache();
|
||||
uint32_t next = uuid::get_uptime() + (ok ? VERSIONS_REFRESH_INTERVAL_MS : VERSIONS_RETRY_INTERVAL_MS);
|
||||
versions_fetch_requested_ = false;
|
||||
|
||||
uint32_t interval;
|
||||
if (refresh_versions_cache()) {
|
||||
versions_failures_ = 0;
|
||||
interval = VERSIONS_REFRESH_INTERVAL_MS;
|
||||
} else {
|
||||
if (versions_failures_ < VERSIONS_MAX_BACKOFF_STEPS) {
|
||||
versions_failures_++;
|
||||
}
|
||||
interval = VERSIONS_RETRY_INTERVAL_MS << (versions_failures_ - 1);
|
||||
}
|
||||
|
||||
uint32_t next = uuid::get_uptime() + interval;
|
||||
if (next == 0) {
|
||||
next = 1;
|
||||
}
|
||||
@@ -451,16 +482,21 @@ bool WebStatusService::refresh_versions_cache() {
|
||||
out.upgradeable = !out.version.empty() && FirmwareVersion(out.version) > current_version;
|
||||
};
|
||||
|
||||
read_section("stable", versions_stable_);
|
||||
read_section("dev", versions_dev_);
|
||||
// parse into locals first, then publish in one go so the AsyncTCP task never sees a half-written cache
|
||||
VersionInfo stable;
|
||||
VersionInfo dev;
|
||||
read_section("stable", stable);
|
||||
read_section("dev", dev);
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock{versions_mutex_};
|
||||
versions_stable_ = stable;
|
||||
versions_dev_ = dev;
|
||||
versions_cache_valid_ = true;
|
||||
}
|
||||
|
||||
versions_cache_valid_ = true;
|
||||
#if defined(EMSESP_DEBUG)
|
||||
EMSESP::logger().debug("Fetched from %s: stable=%s, dev=%s, current=%s",
|
||||
VERSIONS_URL,
|
||||
versions_stable_.version.c_str(),
|
||||
versions_dev_.version.c_str(),
|
||||
current_version_s.c_str());
|
||||
EMSESP::logger().debug("Fetched from %s: stable=%s, dev=%s, current=%s", VERSIONS_URL, stable.version.c_str(), dev.version.c_str(), current_version_s.c_str());
|
||||
#endif
|
||||
return true;
|
||||
#endif
|
||||
@@ -468,11 +504,12 @@ bool WebStatusService::refresh_versions_cache() {
|
||||
|
||||
// returns if current dev/stable is upgradeable
|
||||
bool WebStatusService::current_upgradeable() const {
|
||||
FirmwareVersion current_version(current_version_s);
|
||||
bool is_dev = current_version.prerelease().find("dev") != std::string::npos;
|
||||
std::lock_guard<std::mutex> lock{versions_mutex_};
|
||||
if (!versions_cache_valid_) {
|
||||
return false;
|
||||
}
|
||||
FirmwareVersion current_version(current_version_s);
|
||||
bool is_dev = current_version.prerelease().find("dev") != std::string::npos;
|
||||
return is_dev ? versions_dev_.upgradeable : versions_stable_.upgradeable;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
#include "../core/firmwareVersion.h"
|
||||
#include "../emsesp_version.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
|
||||
namespace emsesp {
|
||||
|
||||
class WebStatusService {
|
||||
@@ -21,6 +24,7 @@ class WebStatusService {
|
||||
|
||||
// called from EMSESP::loop() to refresh the cached versions.json from emsesp.org
|
||||
// so that the web request handler never has to do blocking HTTPS on the small AsyncTCP stack
|
||||
// fetches on a daily schedule when auto_fw_check is on, otherwise only when getVersions asks
|
||||
void loop();
|
||||
|
||||
// true once we've had at least one successful versions.json fetch
|
||||
@@ -67,14 +71,28 @@ class WebStatusService {
|
||||
VersionInfo versions_dev_;
|
||||
bool versions_cache_valid_ = false; // true once we've had at least one successful fetch
|
||||
uint32_t versions_next_fetch_ms_ = 0; // uuid::get_uptime() of the next attempt; 0 = idle
|
||||
uint8_t versions_failures_ = 0; // consecutive failed fetches, drives the retry backoff
|
||||
|
||||
// set by getVersions() on the AsyncTCP task, consumed by the loop task, so that the WebUI still
|
||||
// gets version information when auto_fw_check is off
|
||||
std::atomic<bool> versions_fetch_requested_{false};
|
||||
|
||||
// the cache is written by the loop task in refresh_versions_cache() and read by the AsyncTCP
|
||||
// task in getVersions()/current_upgradeable(), so the std::strings need guarding - without it a
|
||||
// request landing mid-update reads a buffer that has just been freed
|
||||
mutable std::mutex versions_mutex_;
|
||||
|
||||
bool refresh_versions_cache(); // does the actual HTTPS fetch + parse, returns true on success
|
||||
|
||||
static constexpr const char * VERSIONS_URL = "http://emsesp.org/versions.json";
|
||||
|
||||
static constexpr uint32_t VERSIONS_REFRESH_INTERVAL_MS = 60UL * 60UL * 1000UL; // 1 hour on success
|
||||
static constexpr uint32_t VERSIONS_RETRY_INTERVAL_MS = 5UL * 60UL * 1000UL; // 5 min after failure
|
||||
static constexpr uint32_t VERSIONS_INITIAL_FETCH_DELAY_MS = 5UL * 1000UL; // 5 s after a link comes up
|
||||
static constexpr uint32_t VERSIONS_REFRESH_INTERVAL_MS = 24UL * 60UL * 60UL * 1000UL; // once a day on success
|
||||
static constexpr uint32_t VERSIONS_RETRY_INTERVAL_MS = 5UL * 60UL * 1000UL; // 5 min after the first failure
|
||||
static constexpr uint32_t VERSIONS_INITIAL_FETCH_DELAY_MS = 5UL * 1000UL; // 5 s after a link comes up
|
||||
|
||||
// each attempt blocks the loop task for as long as the DNS lookup, connect and read timeouts
|
||||
// allow, so double the retry delay per consecutive failure: 5, 10, 20, 40, 80, 160 minutes
|
||||
static constexpr uint8_t VERSIONS_MAX_BACKOFF_STEPS = 6;
|
||||
};
|
||||
|
||||
} // namespace emsesp
|
||||
|
||||
@@ -4,8 +4,7 @@
|
||||
# Command line test for the API
|
||||
#
|
||||
|
||||
# emsesp_url="http://ems-esp.local"
|
||||
emsesp_url="http://ems-espT.local"
|
||||
emsesp_url="http://ems-esp.local"
|
||||
|
||||
# get the token from the Security page. This is the token for the admin user, unless changed it'll always be the same
|
||||
emsesp_token="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiYWRtaW4iOnRydWV9.2bHpWya2C7Q12WjNUBD6_7N3RCD7CMl-EGhyQVzFdDg"
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,250 +0,0 @@
|
||||
{
|
||||
"type": "systembackup",
|
||||
"version": "3.9.0",
|
||||
"date": "2026-08-02T08:06:45",
|
||||
"systembackup": [
|
||||
{
|
||||
"type": "settings",
|
||||
"Network": {
|
||||
"ssid": "",
|
||||
"bssid": "",
|
||||
"password": "",
|
||||
"hostname": "ems-esp",
|
||||
"static_ip_config": false,
|
||||
"bandwidth20": false,
|
||||
"nosleep": true,
|
||||
"enableMDNS": true,
|
||||
"enableCORS": false,
|
||||
"CORSOrigin": "*",
|
||||
"tx_power": 0
|
||||
},
|
||||
"AP": {
|
||||
"provision_mode": 2,
|
||||
"ssid": "ems-esp",
|
||||
"password": "ems-esp-neo",
|
||||
"channel": 1,
|
||||
"ssid_hidden": false,
|
||||
"max_clients": 4,
|
||||
"local_ip": "192.168.X.X",
|
||||
"gateway_ip": "192.168.X.X",
|
||||
"subnet_mask": "255.255.255.0"
|
||||
},
|
||||
"MQTT": {
|
||||
"enableTLS": false,
|
||||
"rootCA": "",
|
||||
"enabled": true,
|
||||
"host": "192.168.X.X",
|
||||
"port": 1883,
|
||||
"base": "ems-esp",
|
||||
"username": "xxxx",
|
||||
"password": "xxxx",
|
||||
"client_id": "esp32-395c7bcc",
|
||||
"keep_alive": 60,
|
||||
"clean_session": false,
|
||||
"entity_format": 1,
|
||||
"publish_time_boiler": 60,
|
||||
"publish_time_thermostat": 60,
|
||||
"publish_time_solar": 60,
|
||||
"publish_time_mixer": 60,
|
||||
"publish_time_water": 60,
|
||||
"publish_time_other": 60,
|
||||
"publish_time_sensor": 60,
|
||||
"publish_time_heartbeat": 10,
|
||||
"mqtt_qos": 0,
|
||||
"mqtt_retain": false,
|
||||
"ha_enabled": true,
|
||||
"nested_format": 1,
|
||||
"discovery_prefix": "homeassistant",
|
||||
"discovery_type": 0,
|
||||
"ha_number_mode": 1,
|
||||
"publish_single": false,
|
||||
"publish_single2cmd": false,
|
||||
"send_response": false
|
||||
},
|
||||
"NTP": {
|
||||
"enabled": true,
|
||||
"server": "time.google.com",
|
||||
"tz_label": "Europe/Amsterdam",
|
||||
"tz_format": "CET-1CEST,M3.5.0,M10.5.0/3"
|
||||
},
|
||||
"Security": {
|
||||
"jwt_secret": "ems-esp-neo",
|
||||
"users": [
|
||||
{
|
||||
"username": "admin",
|
||||
"password": "admin",
|
||||
"admin": true
|
||||
},
|
||||
{
|
||||
"username": "guest",
|
||||
"password": "guest",
|
||||
"admin": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"Settings": {
|
||||
"version": "3.9.0",
|
||||
"board_profile": "E32V2",
|
||||
"platform": "ESP32",
|
||||
"locale": "en",
|
||||
"tx_mode": 1,
|
||||
"ems_bus_id": 11,
|
||||
"syslog_enabled": false,
|
||||
"syslog_level": 3,
|
||||
"trace_raw": false,
|
||||
"syslog_mark_interval": 0,
|
||||
"syslog_host": "",
|
||||
"syslog_port": 514,
|
||||
"boiler_heatingoff": false,
|
||||
"remote_timeout": 24,
|
||||
"remote_timeout_en": false,
|
||||
"shower_timer": true,
|
||||
"shower_alert": false,
|
||||
"shower_alert_coldshot": 10,
|
||||
"shower_alert_trigger": 7,
|
||||
"shower_min_duration": 180,
|
||||
"rx_gpio": 4,
|
||||
"tx_gpio": 5,
|
||||
"dallas_gpio": 14,
|
||||
"dallas_parasite": false,
|
||||
"led_gpio": 2,
|
||||
"hide_led": true,
|
||||
"led_type": 0,
|
||||
"low_clock": false,
|
||||
"telnet_enabled": true,
|
||||
"notoken_api": false,
|
||||
"readonly_mode": false,
|
||||
"analog_enabled": true,
|
||||
"pbutton_gpio": 34,
|
||||
"solar_maxflow": 30,
|
||||
"fahrenheit": false,
|
||||
"bool_format": 1,
|
||||
"bool_dashboard": 1,
|
||||
"enum_format": 1,
|
||||
"weblog_level": 6,
|
||||
"weblog_buffer": 75,
|
||||
"weblog_compact": true,
|
||||
"phy_type": 1,
|
||||
"eth_power": 15,
|
||||
"eth_phy_addr": 0,
|
||||
"eth_clock_mode": 1,
|
||||
"modbus_enabled": false,
|
||||
"modbus_port": 502,
|
||||
"modbus_max_clients": 10,
|
||||
"modbus_timeout": 300,
|
||||
"developer_mode": true,
|
||||
"disable_reset": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "schedule",
|
||||
"Schedule": {
|
||||
"schedule": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "customizations",
|
||||
"Customizations": {
|
||||
"ts": [],
|
||||
"as": [],
|
||||
"masked_entities": [
|
||||
{
|
||||
"product_id": 77,
|
||||
"device_id": 23,
|
||||
"custom_name": "",
|
||||
"custom_brand": "",
|
||||
"entity_ids": [
|
||||
"08datetime",
|
||||
"08hc1/seltemp|<30",
|
||||
"08hc1/currtemp",
|
||||
"08hc1/mode"
|
||||
]
|
||||
},
|
||||
{
|
||||
"product_id": 123,
|
||||
"device_id": 8,
|
||||
"custom_name": "",
|
||||
"custom_brand": "",
|
||||
"entity_ids": [
|
||||
"08heatingactive",
|
||||
"08burngas",
|
||||
"08fanwork",
|
||||
"08ignwork",
|
||||
"08burnmaxpower|>23<121",
|
||||
"08burnminperiod|<120",
|
||||
"08lastcode",
|
||||
"08servicecode"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "entities",
|
||||
"Entities": {
|
||||
"entities": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "modules",
|
||||
"Modules": {
|
||||
"modules": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "nvs",
|
||||
"nvs": [
|
||||
{
|
||||
"type": 1,
|
||||
"key": "nompower",
|
||||
"value": 30
|
||||
},
|
||||
{
|
||||
"type": 33,
|
||||
"key": "boot",
|
||||
"value": "3.8.1-dev.4"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"key": "d_boot",
|
||||
"value": 1767525325
|
||||
},
|
||||
{
|
||||
"type": 33,
|
||||
"key": "app1",
|
||||
"value": "3.8.2-dev.13"
|
||||
},
|
||||
{
|
||||
"type": 33,
|
||||
"key": "app0",
|
||||
"value": "3.8.1"
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"key": "d_app0",
|
||||
"value": 1774988066
|
||||
},
|
||||
{
|
||||
"type": 1,
|
||||
"key": "fresh_firmware",
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"key": "d_app1",
|
||||
"value": 1776194060
|
||||
},
|
||||
{
|
||||
"type": 66,
|
||||
"key": "nrgheat",
|
||||
"value": 485871.5481
|
||||
},
|
||||
{
|
||||
"type": 66,
|
||||
"key": "nrgww",
|
||||
"value": 101649.2176
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user