mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2026-05-13 01:25:52 +00:00
Compare commits
111 Commits
cb3c9653ce
...
v3.8.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ee3a5d231a | ||
|
|
ddb2390bf7 | ||
|
|
91912cf5be | ||
|
|
4f9851a9fe | ||
|
|
a897afd4e6 | ||
|
|
344dcd0019 | ||
|
|
7854349dbe | ||
|
|
d1d046f3fd | ||
|
|
b988c67c8e | ||
|
|
37a94f8e0f | ||
|
|
017a7de639 | ||
|
|
7b61429a02 | ||
|
|
fed15f0f96 | ||
|
|
ad5d13168b | ||
|
|
ae5beccb9d | ||
|
|
764c660b14 | ||
|
|
ca0f32b087 | ||
|
|
8ad91de54a | ||
|
|
58da157272 | ||
|
|
b5014bf9ac | ||
|
|
14351436a7 | ||
|
|
469d412951 | ||
|
|
6edbac86e2 | ||
|
|
db2be70d66 | ||
|
|
c36f231990 | ||
|
|
26102121e1 | ||
|
|
8e64c6303e | ||
|
|
74c76eb90b | ||
|
|
daffdcf58e | ||
|
|
4bc4fa903f | ||
|
|
29380f0303 | ||
|
|
6b2370b79d | ||
|
|
dbc636c9bf | ||
|
|
0c0660c04b | ||
|
|
c9fd076394 | ||
|
|
35550553be | ||
|
|
06ff219385 | ||
|
|
e705a5629f | ||
|
|
a079169005 | ||
|
|
854f4d559a | ||
|
|
d9b6de0652 | ||
|
|
c54da18822 | ||
|
|
e8f57b6343 | ||
|
|
a1ab81de66 | ||
|
|
28135c225b | ||
|
|
eaa277fef0 | ||
|
|
e418b7d8e7 | ||
|
|
a4e3be6a69 | ||
|
|
a1bc5bb055 | ||
|
|
f444ca31e0 | ||
|
|
1b70b55989 | ||
|
|
1487f30c43 | ||
|
|
e00eb8e64f | ||
|
|
f41bb3671c | ||
|
|
22c75e6df3 | ||
|
|
5ab10b7aa6 | ||
|
|
ee5fd4d0eb | ||
|
|
46f35bc67c | ||
|
|
ec85a7ec24 | ||
|
|
02f2389587 | ||
|
|
7f140021aa | ||
|
|
6796962c1e | ||
|
|
df6de21cf4 | ||
|
|
df9f75a5c9 | ||
|
|
7bd8710eb6 | ||
|
|
32f2c6d341 | ||
|
|
86919c1684 | ||
|
|
86e29515e7 | ||
|
|
46eb4185d7 | ||
|
|
8da6761a48 | ||
|
|
9233f0dfcc | ||
|
|
292f743b14 | ||
|
|
dd6dfffd57 | ||
|
|
ec705a5307 | ||
|
|
f45f071710 | ||
|
|
f3858546de | ||
|
|
d0ac0b7804 | ||
|
|
d8284ec09f | ||
|
|
6e982acde8 | ||
|
|
8c94ce99b2 | ||
|
|
fc057d18c9 | ||
|
|
18e9b99413 | ||
|
|
a47e0e8266 | ||
|
|
f412ddc716 | ||
|
|
29110e96e5 | ||
|
|
b65866217a | ||
|
|
611e3b1243 | ||
|
|
2ca0a0c634 | ||
|
|
7eb1f061b7 | ||
|
|
50459a23fe | ||
|
|
5bf53c3389 | ||
|
|
4b7aa95be3 | ||
|
|
70943f5758 | ||
|
|
3bc280b817 | ||
|
|
62b15a5319 | ||
|
|
8dd18802d6 | ||
|
|
57a516a83a | ||
|
|
a57fdaa4b3 | ||
|
|
4841e42286 | ||
|
|
8c2d2b06ed | ||
|
|
38c8b1b7f0 | ||
|
|
6fb5933a02 | ||
|
|
c0944433be | ||
|
|
478e6362c9 | ||
|
|
4d6354db78 | ||
|
|
beab0f0c77 | ||
|
|
c17749bd22 | ||
|
|
2bad769c5c | ||
|
|
8ad89ca64b | ||
|
|
9244d8daec | ||
|
|
02d01334b2 |
39
CHANGELOG.md
39
CHANGELOG.md
@@ -5,6 +5,44 @@ All notable changes to this project will be documented in this file.
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [3.8.2] 12 May 2026
|
||||
|
||||
## Added
|
||||
|
||||
- comfortpoint for BC400 [#2935](https://github.com/emsesp/EMS-ESP32/issues/2935)
|
||||
- customize device brand [#2784](https://github.com/emsesp/EMS-ESP32/issues/2784)
|
||||
- set model for ems-esp devices temperature, analog, etc. [#2958](https://github.com/emsesp/EMS-ESP32/discussions/2958)
|
||||
- prometheus metrics for temperature/analog/scheduler/custom [#2962](https://github.com/emsesp/EMS-ESP32/issues/2962)
|
||||
- boiler pumpkick [#2965](https://github.com/emsesp/EMS-ESP32/discussions/2965)
|
||||
- heatpump reset [#2933](https://github.com/emsesp/EMS-ESP32/issues/2933)
|
||||
- 2.nd freshwater module (dhw4, dhw5) [#2991](https://github.com/emsesp/EMS-ESP32/issues/2991)
|
||||
- full system backup and restore
|
||||
- auto-logic to set ht3/ems+ tx-mode
|
||||
- polariity for digital_in sensors [#3070](https://github.com/emsesp/EMS-ESP32/discussions/3070)
|
||||
|
||||
## Fixed
|
||||
|
||||
- SRC climate creation [#2936](https://github.com/emsesp/EMS-ESP32/issues/2936) and [#2960](https://github.com/emsesp/EMS-ESP32/issues/2960)
|
||||
- missing translations [#3015](https://github.com/emsesp/EMS-ESP32/issues/3015)
|
||||
- custom entities check fetch length
|
||||
- modbus initialization [#3064](https://github.com/emsesp/EMS-ESP32/issues/3064)
|
||||
|
||||
## Changed
|
||||
|
||||
- weblogbuffer up to 1000 messages with PSRAM, mentioned in [#2933](https://github.com/emsesp/EMS-ESP32/issues/2933)
|
||||
- validate custom entity writes, [#2931](https://github.com/emsesp/EMS-ESP32/issues/2931)
|
||||
- remove wrong burnMinPower [#2918](https://github.com/emsesp/EMS-ESP32/issues/2918)
|
||||
- store scheduler active state to nvs [#2946](https://github.com/emsesp/EMS-ESP32/discussions/2946)
|
||||
- translated modes `heat` and `eco` for HA-climate mode-str-tpl
|
||||
- support `minflowtemp` and `baseflowtemp` [#2969](https://github.com/emsesp/EMS-ESP32/discussions/2969)
|
||||
- update version if it is 00.00 in first read [#2981](https://github.com/emsesp/EMS-ESP32/issues/2981)
|
||||
- device class for % values [#2980](https://github.com/emsesp/EMS-ESP32/issues/2980)
|
||||
- fetch telegrams: set length to fetch [#3017](https://github.com/emsesp/EMS-ESP32/issues/3017)
|
||||
- move http client from stack to heap
|
||||
- heap optimizations [#3021](https://github.com/emsesp/EMS-ESP32/discussions/3021)
|
||||
- check and read 0x470 as summer2_typeids[0] only if received [#2686](https://github.com/emsesp/EMS-ESP32/issues/2686), [#3055](https://github.com/emsesp/EMS-ESP32/issues/3055)
|
||||
- default bus-id: gateway1(0x49), tx-mode: auto
|
||||
|
||||
## [3.8.1] 11 January 2026
|
||||
|
||||
## Added
|
||||
@@ -33,7 +71,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- board profile `CUSTOM` can only be selected in developer mode
|
||||
- mqtt sends round values without decimals (`28` instead of `28.0`)
|
||||
|
||||
|
||||
## [3.8.0] 31 December 2025
|
||||
|
||||
## Added
|
||||
|
||||
@@ -2,34 +2,12 @@
|
||||
|
||||
For more details go to [emsesp.org](https://emsesp.org/).
|
||||
|
||||
## [3.8.2]
|
||||
## [3.8.3]
|
||||
|
||||
## Added
|
||||
|
||||
- comfortpoint for BC400 [#2935](https://github.com/emsesp/EMS-ESP32/issues/2935)
|
||||
- customize device brand [#2784](https://github.com/emsesp/EMS-ESP32/issues/2784)
|
||||
- set model for ems-esp devices temperature, analog, etc. [#2958](https://github.com/emsesp/EMS-ESP32/discussions/2958)
|
||||
- prometheus metrics for temperature/analog/scheduler/custom [#2962](https://github.com/emsesp/EMS-ESP32/issues/2962)
|
||||
- boiler pumpkick [#2965](https://github.com/emsesp/EMS-ESP32/discussions/2965)
|
||||
- heatpump reset [#2933](https://github.com/emsesp/EMS-ESP32/issues/2933)
|
||||
- 2.nd freshwater module (dhw4, dhw5) [#2991](https://github.com/emsesp/EMS-ESP32/issues/2991)
|
||||
- full system backup and restore
|
||||
|
||||
## Fixed
|
||||
|
||||
- SRC climate creation [#2936](https://github.com/emsesp/EMS-ESP32/issues/2936) and [#2960](https://github.com/emsesp/EMS-ESP32/issues/2960)
|
||||
- missing translations [#3015](https://github.com/emsesp/EMS-ESP32/issues/3015)
|
||||
|
||||
## Changed
|
||||
|
||||
- weblogbuffer up to 1000 messages with PSRAM, mentioned in [#2933](https://github.com/emsesp/EMS-ESP32/issues/2933)
|
||||
- validate custom entity writes, [#2931](https://github.com/emsesp/EMS-ESP32/issues/2931)
|
||||
- remove wrong burnMinPower [#2918](https://github.com/emsesp/EMS-ESP32/issues/2918)
|
||||
- store scheduler active state to nvs [#2946](https://github.com/emsesp/EMS-ESP32/discussions/2946)
|
||||
- translated modes `heat` and `eco` for HA-climate mode-str-tpl
|
||||
- support `minflowtemp` and `baseflowtemp` [#2969](https://github.com/emsesp/EMS-ESP32/discussions/2969)
|
||||
- update version if it is 00.00 in first read [#2981](https://github.com/emsesp/EMS-ESP32/issues/2981)
|
||||
- device class for % values [#2980](https://github.com/emsesp/EMS-ESP32/issues/2980)
|
||||
- fetch telegrams: set length to fetch [#3017](https://github.com/emsesp/EMS-ESP32/issues/3017)
|
||||
- move http client from stack to heap
|
||||
- heap optimizations [#3021](https://github.com/emsesp/EMS-ESP32/discussions/3021)
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
{
|
||||
"type": "systembackup",
|
||||
"version": "3.8.2",
|
||||
"date": "2026-03-29T13:28:15",
|
||||
"systembackup": [
|
||||
{
|
||||
"type": "settings",
|
||||
@@ -19,7 +18,7 @@
|
||||
"tx_power": 0
|
||||
},
|
||||
"AP": {
|
||||
"provision_mode": 2,
|
||||
"provision_mode": 1,
|
||||
"ssid": "ems-esp",
|
||||
"password": "ems-esp-neo",
|
||||
"channel": 1,
|
||||
@@ -62,7 +61,7 @@
|
||||
"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"
|
||||
@@ -83,12 +82,12 @@
|
||||
]
|
||||
},
|
||||
"Settings": {
|
||||
"version": "3.8.2",
|
||||
"version": "3.8.2-dev.22",
|
||||
"board_profile": "E32V2_2",
|
||||
"platform": "ESP32",
|
||||
"locale": "en",
|
||||
"tx_mode": 1,
|
||||
"ems_bus_id": 11,
|
||||
"tx_mode": 5,
|
||||
"ems_bus_id": 73,
|
||||
"syslog_enabled": false,
|
||||
"syslog_level": 3,
|
||||
"trace_raw": false,
|
||||
@@ -132,17 +131,7 @@
|
||||
"modbus_port": 502,
|
||||
"modbus_max_clients": 10,
|
||||
"modbus_timeout": 300,
|
||||
"developer_mode": true,
|
||||
"email_enabled": false,
|
||||
"email_ssl": false,
|
||||
"email_starttls": true,
|
||||
"email_server": "smtp.example.net",
|
||||
"email_port": 587,
|
||||
"email_login": "",
|
||||
"email_pass": "",
|
||||
"email_sender": "ems-esp@example.net",
|
||||
"email_recp": "",
|
||||
"email_subject": "ems-esp notification"
|
||||
"developer_mode": false
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -207,22 +196,14 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "customSupport",
|
||||
"Support": {
|
||||
"html": [
|
||||
"This product is installed and managed by:",
|
||||
"",
|
||||
"<b>Bosch Installer Example</b>",
|
||||
"",
|
||||
"Nefit Road 12",
|
||||
"1234 AB Amsterdam",
|
||||
"Phone: +31 123 456 789",
|
||||
"email: support@boschinstaller.nl",
|
||||
"",
|
||||
"For help and questions please <a target='_blank' href='https://emsesp.org'>contact</a> your installer."
|
||||
],
|
||||
"img_url": "https://emsesp.org/media/images/designer.png"
|
||||
}
|
||||
"type": "nvs",
|
||||
"nvs": [
|
||||
{
|
||||
"type": 1,
|
||||
"key": "fresh_firmware",
|
||||
"value": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -112,10 +112,10 @@ telegram_type_id,name,is_fetched
|
||||
0x02A0,RC300Curves,
|
||||
0x02A1,RC300Curves,
|
||||
0x02A2,RC300Curves,
|
||||
0x02A5,RC300Monitor,fetched
|
||||
0x02A6,CRFMonitor,
|
||||
0x02A5,RC300Monitor,
|
||||
0x02A6,RC300Monitor,
|
||||
0x02A7,RC300Monitor,
|
||||
0x02A8,CRFMonitor,
|
||||
0x02A8,RC300Monitor,
|
||||
0x02A9,RC300Monitor,
|
||||
0x02AA,RC300Monitor,
|
||||
0x02AB,RC300Monitor,
|
||||
@@ -171,6 +171,7 @@ telegram_type_id,name,is_fetched
|
||||
0x0468,HPSet,
|
||||
0x0469,HPSet,
|
||||
0x046A,HPSet,
|
||||
0x0470,RC300Summer2,fetched
|
||||
0x0471,RC300Summer2,
|
||||
0x0472,RC300Summer2,
|
||||
0x0473,RC300Summer2,
|
||||
|
||||
|
@@ -26,8 +26,8 @@
|
||||
"@alova/adapter-xhr": "2.3.1",
|
||||
"@emotion/react": "^11.14.0",
|
||||
"@emotion/styled": "^11.14.1",
|
||||
"@mui/icons-material": "^9.0.0",
|
||||
"@mui/material": "^9.0.0",
|
||||
"@mui/icons-material": "^9.0.1",
|
||||
"@mui/material": "^9.0.1",
|
||||
"@preact/compat": "^18.3.2",
|
||||
"@table-library/react-table-library": "4.1.15",
|
||||
"alova": "3.5.1",
|
||||
@@ -38,10 +38,10 @@
|
||||
"magic-string": "^0.30.21",
|
||||
"mime-types": "^3.0.2",
|
||||
"preact": "^10.29.1",
|
||||
"react": "^19.2.5",
|
||||
"react-dom": "^19.2.5",
|
||||
"react": "^19.2.6",
|
||||
"react-dom": "^19.2.6",
|
||||
"react-icons": "^5.6.0",
|
||||
"react-router": "^7.14.1",
|
||||
"react-router": "^7.15.0",
|
||||
"react-toastify": "^11.1.0",
|
||||
"typesafe-i18n": "^5.27.1",
|
||||
"typescript": "^6.0.3"
|
||||
@@ -52,20 +52,20 @@
|
||||
"@preact/compat": "^18.3.2",
|
||||
"@preact/preset-vite": "^2.10.5",
|
||||
"@trivago/prettier-plugin-sort-imports": "^6.0.2",
|
||||
"@types/node": "^25.6.0",
|
||||
"@types/node": "^25.7.0",
|
||||
"@types/react": "^19.2.14",
|
||||
"@types/react-dom": "^19.2.3",
|
||||
"axe-core": "^4.11.3",
|
||||
"axe-core": "^4.11.4",
|
||||
"concurrently": "^9.2.1",
|
||||
"eslint": "^10.2.1",
|
||||
"eslint": "^10.3.0",
|
||||
"eslint-config-prettier": "^10.1.8",
|
||||
"prettier": "^3.8.3",
|
||||
"rollup-plugin-visualizer": "^7.0.1",
|
||||
"terser": "^5.46.1",
|
||||
"typescript-eslint": "^8.58.2",
|
||||
"vite": "^8.0.9",
|
||||
"terser": "^5.47.1",
|
||||
"typescript-eslint": "^8.59.3",
|
||||
"vite": "^8.0.12",
|
||||
"vite-plugin-imagemin": "^0.6.1",
|
||||
"vite-tsconfig-paths": "^6.1.1"
|
||||
},
|
||||
"packageManager": "pnpm@10.33.0+sha512.10568bb4a6afb58c9eb3630da90cc9516417abebd3fabbe6739f0ae795728da1491e9db5a544c76ad8eb7570f5c4bb3d6c637b2cb41bfdcdb47fa823c8649319"
|
||||
"packageManager": "pnpm@10.33.4+sha512.1c67b3b359b2d408119ba1ed289f34b8fc3c6873412bec6fd264fbdc82489e510fcbecb9ce9d22dae7f3b76269d8441046014bdca53b9979cd7a561ad631b800"
|
||||
}
|
||||
|
||||
808
interface/pnpm-lock.yaml
generated
808
interface/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -18,7 +18,7 @@ import { PROJECT_NAME } from 'env';
|
||||
import { useI18nContext } from 'i18n/i18n-react';
|
||||
import type { SignInRequest } from 'types';
|
||||
import { onEnterCallback, updateValue } from 'utils';
|
||||
import { SIGN_IN_REQUEST_VALIDATOR, validate } from 'validators';
|
||||
import { SIGN_IN_REQUEST_VALIDATOR, ValidationError, validate } from 'validators';
|
||||
|
||||
const SignIn = memo(() => {
|
||||
const authenticationContext = useContext(AuthenticationContext);
|
||||
@@ -74,7 +74,7 @@ const SignIn = memo(() => {
|
||||
await validate(SIGN_IN_REQUEST_VALIDATOR, signInRequest);
|
||||
await signIn();
|
||||
} catch (error) {
|
||||
setFieldErrors(error as ValidateFieldsError);
|
||||
setFieldErrors((error as ValidationError).fieldErrors);
|
||||
setProcessing(false);
|
||||
}
|
||||
}, [signInRequest, signIn, LL]);
|
||||
|
||||
@@ -28,7 +28,7 @@ import type { ValidateFieldsError } from 'async-validator';
|
||||
import { BlockFormControlLabel, ValidatedTextField } from 'components';
|
||||
import { useI18nContext } from 'i18n/i18n-react';
|
||||
import { numberValue, updateValue } from 'utils';
|
||||
import { validate } from 'validators';
|
||||
import { ValidationError, validate } from 'validators';
|
||||
|
||||
import { DeviceValueType, DeviceValueTypeNames, DeviceValueUOM_s } from './types';
|
||||
import type { EntityItem } from './types';
|
||||
@@ -136,7 +136,7 @@ const CustomEntitiesDialog = ({
|
||||
}
|
||||
onSave(processedItem);
|
||||
} catch (error) {
|
||||
setFieldErrors(error as ValidateFieldsError);
|
||||
setFieldErrors((error as ValidationError).fieldErrors);
|
||||
}
|
||||
}, [validator, editItem, onSave]);
|
||||
|
||||
@@ -215,7 +215,7 @@ const CustomEntitiesDialog = ({
|
||||
name="value"
|
||||
label={LL.DEFAULT(0) + ' ' + LL.VALUE(0)}
|
||||
type="string"
|
||||
value={editItem.value as string}
|
||||
value={editItem.value}
|
||||
variant="outlined"
|
||||
onChange={updateFormValue}
|
||||
fullWidth
|
||||
@@ -260,7 +260,7 @@ const CustomEntitiesDialog = ({
|
||||
margin="normal"
|
||||
sx={{ width: '11ch' }}
|
||||
type="string"
|
||||
value={editItem.device_id as string}
|
||||
value={editItem.device_id}
|
||||
onChange={updateFormValue}
|
||||
slotProps={{
|
||||
input: {
|
||||
@@ -280,7 +280,7 @@ const CustomEntitiesDialog = ({
|
||||
margin="normal"
|
||||
sx={{ width: '11ch' }}
|
||||
type="string"
|
||||
value={editItem.type_id as string}
|
||||
value={editItem.type_id}
|
||||
onChange={updateFormValue}
|
||||
slotProps={{
|
||||
input: {
|
||||
@@ -381,7 +381,7 @@ const CustomEntitiesDialog = ({
|
||||
fieldErrors={fieldErrors || {}}
|
||||
name="factor"
|
||||
label={LL.BITMASK()}
|
||||
value={editItem.factor as string}
|
||||
value={editItem.factor}
|
||||
sx={{ width: '11ch' }}
|
||||
variant="outlined"
|
||||
onChange={updateFormValue}
|
||||
|
||||
@@ -24,7 +24,7 @@ import type { ValidateFieldsError } from 'async-validator';
|
||||
import { ValidatedTextField } from 'components';
|
||||
import { useI18nContext } from 'i18n/i18n-react';
|
||||
import { numberValue, updateValue } from 'utils';
|
||||
import { validate } from 'validators';
|
||||
import { ValidationError, validate } from 'validators';
|
||||
|
||||
import { DeviceValueUOM, DeviceValueUOM_s } from './types';
|
||||
import type { DeviceValue } from './types';
|
||||
@@ -67,7 +67,7 @@ const DevicesDialog = ({
|
||||
await validate(validator, editItem);
|
||||
onSave(editItem);
|
||||
} catch (error) {
|
||||
setFieldErrors(error as ValidateFieldsError);
|
||||
setFieldErrors((error as ValidationError).fieldErrors);
|
||||
}
|
||||
}, [validator, editItem, onSave]);
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ import type { ValidateFieldsError } from 'async-validator';
|
||||
import { BlockFormControlLabel, ValidatedTextField } from 'components';
|
||||
import { useI18nContext } from 'i18n/i18n-react';
|
||||
import { updateValue } from 'utils';
|
||||
import { validate } from 'validators';
|
||||
import { ValidationError, validate } from 'validators';
|
||||
|
||||
import { ScheduleFlag } from './types';
|
||||
import type { ScheduleItem } from './types';
|
||||
@@ -120,7 +120,7 @@ const SchedulerDialog = ({
|
||||
await validate(validator, itemToSave);
|
||||
onSave(itemToSave);
|
||||
} catch (error) {
|
||||
setFieldErrors(error as ValidateFieldsError);
|
||||
setFieldErrors((error as ValidationError).fieldErrors);
|
||||
}
|
||||
},
|
||||
[validator, onSave]
|
||||
|
||||
@@ -23,7 +23,7 @@ import type { ValidateFieldsError } from 'async-validator';
|
||||
import { ValidatedTextField } from 'components';
|
||||
import { useI18nContext } from 'i18n/i18n-react';
|
||||
import { numberValue, updateValue } from 'utils';
|
||||
import { validate } from 'validators';
|
||||
import { ValidationError, validate } from 'validators';
|
||||
|
||||
import { AnalogType, AnalogTypeNames, DeviceValueUOM_s } from './types';
|
||||
import type { AnalogSensor } from './types';
|
||||
@@ -172,7 +172,7 @@ const SensorsAnalogDialog = ({
|
||||
await validate(validator, editItem);
|
||||
onSave(editItem);
|
||||
} catch (error) {
|
||||
setFieldErrors(error as ValidateFieldsError);
|
||||
setFieldErrors((error as ValidationError).fieldErrors);
|
||||
}
|
||||
}, [validator, editItem, onSave]);
|
||||
|
||||
@@ -242,6 +242,23 @@ const SensorsAnalogDialog = ({
|
||||
</ValidatedTextField>
|
||||
</Grid>
|
||||
)}
|
||||
{editItem.t === AnalogType.DIGITAL_IN && (
|
||||
<Grid>
|
||||
<ValidatedTextField
|
||||
name="f"
|
||||
label={LL.POLARITY()}
|
||||
value={editItem.f}
|
||||
sx={{ width: '15ch' }}
|
||||
fullWidth
|
||||
select
|
||||
onChange={updateFormValue}
|
||||
disabled={editItem.s}
|
||||
>
|
||||
<MenuItem value={1}>{LL.ACTIVEHIGH()}</MenuItem>
|
||||
<MenuItem value={0}>{LL.ACTIVELOW()}</MenuItem>
|
||||
</ValidatedTextField>
|
||||
</Grid>
|
||||
)}
|
||||
{editItem.t === AnalogType.ADC && (
|
||||
<Grid>
|
||||
<ValidatedTextField
|
||||
@@ -447,7 +464,7 @@ const SensorsAnalogDialog = ({
|
||||
name="o"
|
||||
label={LL.POLARITY()}
|
||||
value={editItem.o}
|
||||
sx={{ width: '11ch' }}
|
||||
sx={{ width: '15ch' }}
|
||||
select
|
||||
onChange={updateFormValue}
|
||||
disabled={editItem.s}
|
||||
|
||||
@@ -21,7 +21,7 @@ import type { ValidateFieldsError } from 'async-validator';
|
||||
import { ValidatedTextField } from 'components';
|
||||
import { useI18nContext } from 'i18n/i18n-react';
|
||||
import { numberValue, updateValue } from 'utils';
|
||||
import { validate } from 'validators';
|
||||
import { ValidationError, validate } from 'validators';
|
||||
|
||||
import type { TemperatureSensor } from './types';
|
||||
|
||||
@@ -84,7 +84,7 @@ const SensorsTemperatureDialog = ({
|
||||
await validate(validator, editItem);
|
||||
onSave(editItem);
|
||||
} catch (error) {
|
||||
setFieldErrors(error as ValidateFieldsError);
|
||||
setFieldErrors((error as ValidationError).fieldErrors);
|
||||
}
|
||||
}, [validator, editItem, onSave]);
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ import { useI18nContext } from 'i18n/i18n-react';
|
||||
import type { APSettingsType } from 'types';
|
||||
import { APProvisionMode } from 'types';
|
||||
import { numberValue, updateValueDirty, useRest } from 'utils';
|
||||
import { createAPSettingsValidator, validate } from 'validators';
|
||||
import { ValidationError, createAPSettingsValidator, validate } from 'validators';
|
||||
|
||||
export const isAPEnabled = ({ provision_mode }: APSettingsType) =>
|
||||
provision_mode === APProvisionMode.AP_MODE_ALWAYS ||
|
||||
@@ -86,7 +86,7 @@ const APSettings = () => {
|
||||
await validate(createAPSettingsValidator(data), data);
|
||||
await saveData();
|
||||
} catch (error) {
|
||||
setFieldErrors(error as ValidateFieldsError);
|
||||
setFieldErrors((error as ValidationError).fieldErrors);
|
||||
}
|
||||
}, [data, saveData]);
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ import {
|
||||
} from 'components';
|
||||
import { useI18nContext } from 'i18n/i18n-react';
|
||||
import { numberValue, updateValueDirty, useRest } from 'utils';
|
||||
import { validate } from 'validators';
|
||||
import { ValidationError, validate } from 'validators';
|
||||
|
||||
import { API, getBoardProfile, readSettings, writeSettings } from '../../api/app';
|
||||
import { BOARD_PROFILES } from '../main/types';
|
||||
@@ -153,7 +153,7 @@ const ApplicationSettings = () => {
|
||||
setFieldErrors(undefined);
|
||||
await validate(createSettingsValidator(data), data);
|
||||
} catch (error) {
|
||||
setFieldErrors(error as ValidateFieldsError);
|
||||
setFieldErrors((error as ValidationError).fieldErrors);
|
||||
} finally {
|
||||
await saveData();
|
||||
}
|
||||
@@ -677,6 +677,7 @@ const ApplicationSettings = () => {
|
||||
<MenuItem value={2}>EMS+</MenuItem>
|
||||
<MenuItem value={3}>HT3</MenuItem>
|
||||
<MenuItem value={4}>{LL.HARDWARE()}</MenuItem>
|
||||
<MenuItem value={5}>Auto</MenuItem>
|
||||
</TextField>
|
||||
</Grid>
|
||||
<Grid>
|
||||
|
||||
@@ -31,7 +31,7 @@ import {
|
||||
import { useI18nContext } from 'i18n/i18n-react';
|
||||
import type { MqttSettingsType } from 'types';
|
||||
import { numberValue, updateValueDirty, useRest } from 'utils';
|
||||
import { createMqttSettingsValidator, validate } from 'validators';
|
||||
import { ValidationError, createMqttSettingsValidator, validate } from 'validators';
|
||||
|
||||
import { callAction } from '../../api/app';
|
||||
|
||||
@@ -94,7 +94,7 @@ const MqttSettings = () => {
|
||||
await validate(createMqttSettingsValidator(data), data);
|
||||
await saveData();
|
||||
} catch (error) {
|
||||
setFieldErrors(error as ValidateFieldsError);
|
||||
setFieldErrors((error as ValidationError).fieldErrors);
|
||||
}
|
||||
}, [data, saveData]);
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ import {
|
||||
import { useI18nContext } from 'i18n/i18n-react';
|
||||
import type { NTPSettingsType, Time } from 'types';
|
||||
import { formatLocalDateTime, updateValueDirty, useRest } from 'utils';
|
||||
import { validate } from 'validators';
|
||||
import { ValidationError, validate } from 'validators';
|
||||
import { NTP_SETTINGS_VALIDATOR } from 'validators/ntp';
|
||||
|
||||
import { TIME_ZONES, selectedTimeZone, useTimeZoneSelectItems } from './TZ';
|
||||
@@ -133,7 +133,7 @@ const NTPSettings = () => {
|
||||
await validate(NTP_SETTINGS_VALIDATOR, data);
|
||||
await saveData();
|
||||
} catch (error) {
|
||||
setFieldErrors(error as ValidateFieldsError);
|
||||
setFieldErrors((error as ValidationError).fieldErrors);
|
||||
}
|
||||
}, [data, saveData]);
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ import {
|
||||
import { useI18nContext } from 'i18n/i18n-react';
|
||||
import type { NetworkSettingsType } from 'types';
|
||||
import { updateValueDirty, useRest } from 'utils';
|
||||
import { validate } from 'validators';
|
||||
import { ValidationError, validate } from 'validators';
|
||||
import { createNetworkSettingsValidator } from 'validators/network';
|
||||
|
||||
import SystemMonitor from '../../status/SystemMonitor';
|
||||
@@ -116,7 +116,7 @@ const NetworkSettings = () => {
|
||||
await validate(createNetworkSettingsValidator(data), data);
|
||||
await saveData();
|
||||
} catch (error) {
|
||||
setFieldErrors(error as ValidateFieldsError);
|
||||
setFieldErrors((error as ValidationError).fieldErrors);
|
||||
}
|
||||
deselectNetwork();
|
||||
}, [data, saveData, deselectNetwork]);
|
||||
|
||||
@@ -19,7 +19,7 @@ import { AuthenticatedContext } from 'contexts/authentication';
|
||||
import { useI18nContext } from 'i18n/i18n-react';
|
||||
import type { SecuritySettingsType } from 'types';
|
||||
import { updateValueDirty, useRest } from 'utils';
|
||||
import { SECURITY_SETTINGS_VALIDATOR, validate } from 'validators';
|
||||
import { SECURITY_SETTINGS_VALIDATOR, ValidationError, validate } from 'validators';
|
||||
|
||||
const SecuritySettings = () => {
|
||||
const { LL } = useI18nContext();
|
||||
@@ -58,7 +58,7 @@ const SecuritySettings = () => {
|
||||
await saveData();
|
||||
await authenticatedContext.refresh();
|
||||
} catch (error) {
|
||||
setFieldErrors(error as ValidateFieldsError);
|
||||
setFieldErrors((error as ValidationError).fieldErrors);
|
||||
}
|
||||
}, [data, saveData, authenticatedContext]);
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ import {
|
||||
import { useI18nContext } from 'i18n/i18n-react';
|
||||
import type { UserType } from 'types';
|
||||
import { updateValue } from 'utils';
|
||||
import { validate } from 'validators';
|
||||
import { ValidationError, validate } from 'validators';
|
||||
|
||||
interface UserFormProps {
|
||||
creating: boolean;
|
||||
@@ -69,7 +69,7 @@ const User: FC<UserFormProps> = ({
|
||||
await validate(validator, user);
|
||||
onDoneEditing();
|
||||
} catch (error) {
|
||||
setFieldErrors(error as ValidateFieldsError);
|
||||
setFieldErrors((error as ValidationError).fieldErrors);
|
||||
}
|
||||
}
|
||||
}, [user, validator, onDoneEditing]);
|
||||
|
||||
@@ -187,7 +187,7 @@ const de: Translation = {
|
||||
COMPACT: 'Kompakte Darstellung',
|
||||
DOWNLOAD_SETTINGS_TEXT: 'Erstellen Sie eine Sicherung Ihrer Konfigurationen und Einstellungen',
|
||||
DOWNLOAD_SETTINGS_TEXT2: 'Exportiere alle Werte',
|
||||
DOWNLOAD_SYSTEM_BACKUP: 'System Sicherung',
|
||||
DOWNLOAD_SYSTEM_BACKUP: 'Systemsicherung',
|
||||
UPLOAD_TEXT: 'Laden Sie eine neue Firmware-Datei (.bin) oder eine Sicherungsdatei (.json) hoch',
|
||||
UPLOAD_DROP_TEXT: 'Legen Sie eine Firmware-Datei (.bin) ab oder klicken Sie hier',
|
||||
ERROR: 'Unerwarteter Fehler, bitte versuchen Sie es erneut.',
|
||||
@@ -362,9 +362,9 @@ const de: Translation = {
|
||||
STORED_VERSIONS: 'Gespeicherte Versionen',
|
||||
ONLINE_HELP: 'Online-Hilfe',
|
||||
UPGRADE_IMPORTANT_MESSAGES: 'Wichtige Nachrichten aktualisieren',
|
||||
UPGRADE_IMPORTANT_MESSAGES_1: 'Diese Aktualisierung erfordert eine Werkseinstellung. Stellen Sie sicher, dass Sie zuerst eine Systemsicherung herunterladen, bevor Sie fortfahren, und laden Sie diese Datei dann nach der Installation der neuen Version hoch.',
|
||||
UPGRADE_IMPORTANT_MESSAGES_1: 'Für diese Aktualisierung ist ein Werksreset erforderlich. Stellen Sie sicher, dass Sie zuerst eine Systemsicherung herunterladen, bevor Sie fortfahren, und laden Sie diese Datei dann nach der Installation der neuen Version hoch.',
|
||||
UPGRADE_IMPORTANT_MESSAGES_2: 'Sie aktualisieren auf eine neue Hauptversion. Stellen Sie sicher, dass Sie den ChangeLog für alle wichtigen Änderungen gelesen haben.',
|
||||
WARNING_SYSTEM_BACKUP: 'Dies wird eine Sicherung Ihrer vollständigen Systemkonfiguration und -einstellungen erstellen. Alle Passwörter werden im Sicherungsdatei lesbar sein. Seien Sie vorsichtig beim Teilen! Möchten Sie fortfahren?'
|
||||
WARNING_SYSTEM_BACKUP: 'Dies wird eine Sicherung Ihrer vollständigen Systemkonfiguration und Einstellungen erstellen. Alle Passwörter werden in dieser Sicherungsdatei lesbar sein. Seien Sie vorsichtig beim Teilen! Möchten Sie fortfahren?'
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -1,6 +1,20 @@
|
||||
import type { InternalRuleItem, ValidateOption } from 'async-validator';
|
||||
import type {
|
||||
InternalRuleItem,
|
||||
ValidateFieldsError,
|
||||
ValidateOption
|
||||
} from 'async-validator';
|
||||
import type Schema from 'async-validator';
|
||||
|
||||
export class ValidationError extends Error {
|
||||
readonly fieldErrors: ValidateFieldsError;
|
||||
|
||||
constructor(fieldErrors: ValidateFieldsError) {
|
||||
super('Validation failed');
|
||||
this.name = 'ValidationError';
|
||||
this.fieldErrors = fieldErrors;
|
||||
}
|
||||
}
|
||||
|
||||
export const validate = <T extends object>(
|
||||
validator: Schema,
|
||||
source: Partial<T>,
|
||||
@@ -8,7 +22,7 @@ export const validate = <T extends object>(
|
||||
): Promise<T> =>
|
||||
new Promise((resolve, reject) => {
|
||||
void validator.validate(source, options ?? {}, (errors, fieldErrors) => {
|
||||
errors ? reject(fieldErrors as Error) : resolve(source as T);
|
||||
errors ? reject(new ValidationError(fieldErrors)) : resolve(source as T);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -22,10 +22,11 @@
|
||||
#include "Arduino.h"
|
||||
|
||||
#define EMS_TXMODE_OFF 0
|
||||
#define EMS_TXMODE_DEFAULT 1
|
||||
#define EMS_TXMODE_EMS 1
|
||||
#define EMS_TXMODE_EMSPLUS 2
|
||||
#define EMS_TXMODE_HT3 3
|
||||
#define EMS_TXMODE_HW 4
|
||||
#define EMS_TXMODE_AUTO 5
|
||||
|
||||
namespace emsesp {
|
||||
|
||||
|
||||
@@ -15,5 +15,5 @@
|
||||
"itty-router": "^5.0.23",
|
||||
"prettier": "^3.8.3"
|
||||
},
|
||||
"packageManager": "pnpm@10.33.0+sha512.10568bb4a6afb58c9eb3630da90cc9516417abebd3fabbe6739f0ae795728da1491e9db5a544c76ad8eb7570f5c4bb3d6c637b2cb41bfdcdb47fa823c8649319"
|
||||
"packageManager": "pnpm@10.33.4+sha512.1c67b3b359b2d408119ba1ed289f34b8fc3c6873412bec6fd264fbdc82489e510fcbecb9ce9d22dae7f3b76269d8441046014bdca53b9979cd7a561ad631b800"
|
||||
}
|
||||
|
||||
14
mock-api/pnpm-lock.yaml
generated
14
mock-api/pnpm-lock.yaml
generated
@@ -46,8 +46,8 @@ packages:
|
||||
resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/parser@7.29.2':
|
||||
resolution: {integrity: sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==}
|
||||
'@babel/parser@7.29.3':
|
||||
resolution: {integrity: sha512-b3ctpQwp+PROvU/cttc4OYl4MzfJUWy6FZg+PMXfzmt/+39iHVF0sDfqay8TQM3JA2EUOyKcFZt75jWriQijsA==}
|
||||
engines: {node: '>=6.0.0'}
|
||||
hasBin: true
|
||||
|
||||
@@ -185,7 +185,7 @@ snapshots:
|
||||
|
||||
'@babel/generator@7.29.1':
|
||||
dependencies:
|
||||
'@babel/parser': 7.29.2
|
||||
'@babel/parser': 7.29.3
|
||||
'@babel/types': 7.29.0
|
||||
'@jridgewell/gen-mapping': 0.3.13
|
||||
'@jridgewell/trace-mapping': 0.3.31
|
||||
@@ -197,14 +197,14 @@ snapshots:
|
||||
|
||||
'@babel/helper-validator-identifier@7.28.5': {}
|
||||
|
||||
'@babel/parser@7.29.2':
|
||||
'@babel/parser@7.29.3':
|
||||
dependencies:
|
||||
'@babel/types': 7.29.0
|
||||
|
||||
'@babel/template@7.28.6':
|
||||
dependencies:
|
||||
'@babel/code-frame': 7.29.0
|
||||
'@babel/parser': 7.29.2
|
||||
'@babel/parser': 7.29.3
|
||||
'@babel/types': 7.29.0
|
||||
|
||||
'@babel/traverse@7.29.0':
|
||||
@@ -212,7 +212,7 @@ snapshots:
|
||||
'@babel/code-frame': 7.29.0
|
||||
'@babel/generator': 7.29.1
|
||||
'@babel/helper-globals': 7.28.0
|
||||
'@babel/parser': 7.29.2
|
||||
'@babel/parser': 7.29.3
|
||||
'@babel/template': 7.28.6
|
||||
'@babel/types': 7.29.0
|
||||
debug: 4.4.3
|
||||
@@ -249,7 +249,7 @@ snapshots:
|
||||
'@trivago/prettier-plugin-sort-imports@6.0.2(prettier@3.8.3)':
|
||||
dependencies:
|
||||
'@babel/generator': 7.29.1
|
||||
'@babel/parser': 7.29.2
|
||||
'@babel/parser': 7.29.3
|
||||
'@babel/traverse': 7.29.0
|
||||
'@babel/types': 7.29.0
|
||||
javascript-natural-sort: 0.7.1
|
||||
|
||||
@@ -59,7 +59,7 @@ framework = arduino
|
||||
board_build.partitions = partitions/esp32_partition_16M.csv
|
||||
board_upload.flash_size = 16MB
|
||||
board_build.app_partition_name = app0
|
||||
platform = espressif32@6.13.0 ; Arduino Core 2.0.17 / IDF 4.4.7
|
||||
platform = espressif32@7.0.0 ; Arduino Core 2.0.17 / IDF 4.4.7
|
||||
|
||||
; 32MB Flash variants
|
||||
[espressif32_base_32M]
|
||||
@@ -67,7 +67,7 @@ framework = arduino
|
||||
board_build.partitions = partitions/esp32_partition_32M.csv
|
||||
board_upload.flash_size = 32MB
|
||||
board_build.app_partition_name = app0
|
||||
platform = espressif32@6.13.0 ; Arduino Core 2.0.17 / IDF 4.4.7
|
||||
platform = espressif32@7.0.0 ; Arduino Core 2.0.17 / IDF 4.4.7
|
||||
|
||||
; use Tasmota's library for 4MB Flash variants.
|
||||
; Removes libs (like mbedtsl, so no WiFi_secure.h) to increase available heap
|
||||
@@ -105,7 +105,7 @@ board_build.filesystem = littlefs
|
||||
lib_deps =
|
||||
bblanchon/ArduinoJson @ 7.4.3
|
||||
ESP32Async/AsyncTCP @ 3.4.10
|
||||
ESP32Async/ESPAsyncWebServer @ 3.10.3
|
||||
ESP32Async/ESPAsyncWebServer @ 3.11.0
|
||||
; https://github.com/emsesp/EMS-ESP-Modules.git @ 1.0.8
|
||||
|
||||
; builds the web interface only, not the firmware
|
||||
|
||||
@@ -70,16 +70,12 @@ void ArduinoJsonJWT::parseJWT(String jwt, JsonDocument & jsonDocument) {
|
||||
*/
|
||||
String ArduinoJsonJWT::sign(String & payload) {
|
||||
std::array<unsigned char, 32> hmacResult{};
|
||||
{
|
||||
mbedtls_md_context_t ctx;
|
||||
mbedtls_md_type_t md_type = MBEDTLS_MD_SHA256;
|
||||
mbedtls_md_init(&ctx);
|
||||
mbedtls_md_setup(&ctx, mbedtls_md_info_from_type(md_type), 1);
|
||||
mbedtls_md_hmac_starts(&ctx, reinterpret_cast<const unsigned char *>(_secret.c_str()), _secret.length());
|
||||
mbedtls_md_hmac_update(&ctx, reinterpret_cast<const unsigned char *>(payload.c_str()), payload.length());
|
||||
mbedtls_md_hmac_finish(&ctx, hmacResult.data());
|
||||
mbedtls_md_free(&ctx);
|
||||
}
|
||||
mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256),
|
||||
reinterpret_cast<const unsigned char *>(_secret.c_str()),
|
||||
_secret.length(),
|
||||
reinterpret_cast<const unsigned char *>(payload.c_str()),
|
||||
payload.length(),
|
||||
hmacResult.data());
|
||||
return encode(reinterpret_cast<const char *>(hmacResult.data()), hmacResult.size());
|
||||
}
|
||||
|
||||
|
||||
@@ -185,10 +185,14 @@ bool MqttSettingsService::configureMqtt() {
|
||||
#ifndef TASMOTA_SDK
|
||||
if (_state.enableTLS) {
|
||||
if (_state.rootCA == "insecure") {
|
||||
#if defined(EMSESP_DEBUG)
|
||||
emsesp::EMSESP::logger().debug("Start insecure MQTT");
|
||||
#endif
|
||||
static_cast<espMqttClientSecure *>(_mqttClient)->setInsecure();
|
||||
} else {
|
||||
#if defined(EMSESP_DEBUG)
|
||||
emsesp::EMSESP::logger().debug("Start secure MQTT with rootCA");
|
||||
#endif
|
||||
String certificate = "-----BEGIN CERTIFICATE-----\n" + _state.rootCA + "\n-----END CERTIFICATE-----\n";
|
||||
static_cast<espMqttClientSecure *>(_mqttClient)->setCACert(certificate.c_str());
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include <esp_app_format.h>
|
||||
#include <esp_ota_ops.h>
|
||||
// #include <esp_partition.h>
|
||||
|
||||
static String getFilenameExtension(const String & filename) {
|
||||
const auto pos = filename.lastIndexOf('.');
|
||||
@@ -16,8 +17,8 @@ static String getFilenameExtension(const String & filename) {
|
||||
UploadFileService::UploadFileService(AsyncWebServer * server, SecurityManager * securityManager)
|
||||
: _securityManager(securityManager)
|
||||
, _is_firmware(false)
|
||||
, _is_filesystem(false)
|
||||
, _md5() {
|
||||
// upload a file via a form
|
||||
server->on(
|
||||
UPLOAD_FILE_PATH,
|
||||
HTTP_POST,
|
||||
@@ -41,8 +42,14 @@ void UploadFileService::handleUpload(AsyncWebServerRequest * request, const Stri
|
||||
const String extension = getFilenameExtension(filename);
|
||||
const std::size_t filesize = request->contentLength();
|
||||
|
||||
_is_firmware = false;
|
||||
if ((extension == "bin") && (filesize > 1000000)) {
|
||||
_is_firmware = false;
|
||||
_is_filesystem = false;
|
||||
|
||||
if (extension == "bin" && filename.endsWith("littlefs.bin")) {
|
||||
// LittleFS filesystem image
|
||||
_is_filesystem = true;
|
||||
_md5[0] = '\0'; // clear any stale md5 so Update.end() doesn't compare against it
|
||||
} else if ((extension == "bin") && (filesize > 2000000)) {
|
||||
_is_firmware = true;
|
||||
} else if (extension == "json") {
|
||||
_md5[0] = '\0'; // clear md5
|
||||
@@ -88,6 +95,7 @@ void UploadFileService::handleUpload(AsyncWebServerRequest * request, const Stri
|
||||
#endif
|
||||
// it's firmware - initialize the ArduinoOTA updater
|
||||
emsesp::EMSESP::logger().info("Uploading firmware file %s (size: %d KB). Please wait...", filename.c_str(), filesize / 1024);
|
||||
|
||||
// turn off UART to prevent interference with the upload
|
||||
emsesp::EMSuart::stop();
|
||||
|
||||
@@ -96,28 +104,55 @@ void UploadFileService::handleUpload(AsyncWebServerRequest * request, const Stri
|
||||
Update.setMD5(_md5.data());
|
||||
_md5.front() = '\0';
|
||||
}
|
||||
request->onDisconnect([this] { handleEarlyDisconnect(); }); // success, let's make sure we end the update if the client hangs up
|
||||
request->onDisconnect([this] { handleDisconnect(); }); // success, let's make sure we end the update if the client hangs up
|
||||
} else {
|
||||
handleError(request, 507); // failed to begin, send an error response Insufficient Storage
|
||||
return;
|
||||
}
|
||||
} else if (_is_filesystem) {
|
||||
// LittleFS filesystem image - flash directly to the spiffs/littlefs partition
|
||||
emsesp::EMSESP::logger().info("Uploading filesystem image %s (size: %u KB). Please wait...", filename.c_str(), static_cast<unsigned>(filesize / 1024));
|
||||
emsesp::EMSuart::stop();
|
||||
LittleFS.end(); // unmount LittleFS before we overwrite the partition under it
|
||||
|
||||
// request->contentLength() is the multipart HTTP body size, not the file size,
|
||||
// so it can exceed the partition by a few hundred bytes. Use UPDATE_SIZE_UNKNOWN
|
||||
// and let the Update library size against the whole partition.
|
||||
if (Update.begin(UPDATE_SIZE_UNKNOWN, U_SPIFFS)) {
|
||||
// emsesp::EMSESP::logger().info("Update.begin(U_SPIFFS) ok, partition size %u bytes", static_cast<unsigned>(Update.size()));
|
||||
request->onDisconnect([this] { handleDisconnect(); });
|
||||
} else {
|
||||
emsesp::EMSESP::logger().err("Update.begin(U_SPIFFS) failed: %s", Update.errorString());
|
||||
handleError(request, 507);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// its a normal file, open a new temp file to write the contents too
|
||||
request->_tempFile = LittleFS.open(TEMP_FILENAME_PATH, "w");
|
||||
}
|
||||
}
|
||||
|
||||
if (!_is_firmware) {
|
||||
if (len && len != request->_tempFile.write(data, len)) { // stream the incoming chunk to the opened file
|
||||
handleError(request, 507); // 507-Insufficient Storage
|
||||
}
|
||||
} else if (!request->_tempObject) { // if we haven't delt with an error, continue with the firmware update
|
||||
if (Update.write(data, len) != len) {
|
||||
handleError(request, 500); // internal error, failed
|
||||
return;
|
||||
}
|
||||
if (final && !Update.end(true)) {
|
||||
handleError(request, 500); // internal error, failed
|
||||
if (_is_firmware || _is_filesystem) {
|
||||
if (!request->_tempObject) { // if we haven't delt with an error, continue with the OTA update
|
||||
if (Update.write(data, len) != len) {
|
||||
emsesp::EMSESP::logger().err("Update.write failed at offset %u (chunk %u): %s",
|
||||
static_cast<unsigned>(Update.progress()),
|
||||
static_cast<unsigned>(len),
|
||||
Update.errorString());
|
||||
handleError(request, 500); // internal error, failed
|
||||
return;
|
||||
}
|
||||
if (final) {
|
||||
if (!Update.end(true)) {
|
||||
emsesp::EMSESP::logger().err("Update.end failed: %s", Update.errorString());
|
||||
handleError(request, 500);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (len && len != request->_tempFile.write(data, len)) { // stream the incoming chunk to the opened file
|
||||
handleError(request, 507); // 507-Insufficient Storage
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -135,11 +170,13 @@ void UploadFileService::uploadComplete(AsyncWebServerRequest * request) {
|
||||
return;
|
||||
}
|
||||
|
||||
// check if it was a firmware upgrade
|
||||
// if no error, send the success response as a JSON
|
||||
if (_is_firmware && !request->_tempObject) {
|
||||
// set NVS to tell EMS-ESP this is a new fresh firmware on next restart
|
||||
emsesp::EMSESP::nvs_.putBool(emsesp::EMSESP_NVS_BOOT_NEW_FIRMWARE, true);
|
||||
// check if it was a firmware or filesystem image upgrade
|
||||
// if no error, send the success response and request a restart
|
||||
if ((_is_firmware || _is_filesystem) && !request->_tempObject) {
|
||||
if (_is_firmware) {
|
||||
// set NVS to tell EMS-ESP this is a new fresh firmware on next restart
|
||||
emsesp::EMSESP::nvs_.putBool(emsesp::EMSESP_NVS_BOOT_NEW_FIRMWARE, true);
|
||||
}
|
||||
|
||||
AsyncWebServerResponse * response = request->beginResponse(200);
|
||||
request->send(response);
|
||||
@@ -178,15 +215,21 @@ void UploadFileService::handleError(AsyncWebServerRequest * request, int code) {
|
||||
// that is caught by the web code. Unfortunately the http error code is not sent to the client on fast network connections
|
||||
if (code == 406) {
|
||||
request->client()->close();
|
||||
_is_firmware = false;
|
||||
_is_firmware = false;
|
||||
_is_filesystem = false;
|
||||
Update.abort();
|
||||
}
|
||||
|
||||
// if we aborted a filesystem upload, remount LittleFS so the device keeps working
|
||||
if (_is_filesystem) {
|
||||
LittleFS.begin();
|
||||
}
|
||||
}
|
||||
|
||||
void UploadFileService::handleEarlyDisconnect() {
|
||||
void UploadFileService::handleDisconnect() {
|
||||
emsesp::EMSESP::logger().info("Upload finished");
|
||||
emsesp::EMSESP::system_.uart_init(); // re-enable UART
|
||||
|
||||
_is_firmware = false;
|
||||
Update.abort();
|
||||
_is_firmware = false;
|
||||
_is_filesystem = false;
|
||||
}
|
||||
|
||||
@@ -22,13 +22,14 @@ class UploadFileService {
|
||||
private:
|
||||
SecurityManager * _securityManager;
|
||||
bool _is_firmware;
|
||||
bool _is_filesystem;
|
||||
std::array<char, 33> _md5;
|
||||
|
||||
void handleUpload(AsyncWebServerRequest * request, const String & filename, size_t index, uint8_t * data, size_t len, bool final);
|
||||
void uploadComplete(AsyncWebServerRequest * request);
|
||||
void handleError(AsyncWebServerRequest * request, int code);
|
||||
|
||||
void handleEarlyDisconnect();
|
||||
void handleDisconnect();
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -69,7 +69,9 @@ class EMSESP_Version {
|
||||
return a.major_ < b.major_;
|
||||
if (a.minor_ != b.minor_)
|
||||
return a.minor_ < b.minor_;
|
||||
return a.patch_ < b.patch_;
|
||||
if (a.patch_ != b.patch_)
|
||||
return a.patch_ < b.patch_;
|
||||
return a.prerelease_ < b.prerelease_;
|
||||
}
|
||||
|
||||
friend bool operator>(const EMSESP_Version & a, const EMSESP_Version & b) {
|
||||
@@ -77,7 +79,7 @@ class EMSESP_Version {
|
||||
}
|
||||
|
||||
friend bool operator==(const EMSESP_Version & a, const EMSESP_Version & b) {
|
||||
return a.major_ == b.major_ && a.minor_ == b.minor_ && a.patch_ == b.patch_;
|
||||
return a.major_ == b.major_ && a.minor_ == b.minor_ && a.patch_ == b.patch_ && a.prerelease_ == b.prerelease_;
|
||||
}
|
||||
|
||||
friend bool operator!=(const EMSESP_Version & a, const EMSESP_Version & b) {
|
||||
|
||||
@@ -287,8 +287,8 @@ void AnalogSensor::reload(bool get_nvs) {
|
||||
#endif
|
||||
} else if (sensor.type() == AnalogType::DIGITAL_IN) {
|
||||
LOG_DEBUG("Digital Read on GPIO %02d", sensor.gpio());
|
||||
sensor.set_value(digitalRead(sensor.gpio())); // initial value
|
||||
sensor.set_uom(0); // no uom, just for safe measures
|
||||
sensor.set_value(sensor.factor() == 0 ? !digitalRead(sensor.gpio()) : digitalRead(sensor.gpio())); // initial value
|
||||
sensor.set_uom(0); // no uom, just for safe measures
|
||||
sensor.polltime_ = 0;
|
||||
sensor.poll_ = digitalRead(sensor.gpio());
|
||||
publish_sensor(sensor);
|
||||
@@ -465,7 +465,7 @@ void AnalogSensor::measure() {
|
||||
if (uuid::get_uptime() - sensor.polltime_ >= 15 && sensor.poll_ != sensor.last_reading_) {
|
||||
sensor.last_reading_ = sensor.poll_;
|
||||
if (sensor.type() == AnalogType::DIGITAL_IN) {
|
||||
sensor.set_value(sensor.poll_);
|
||||
sensor.set_value(sensor.factor() == 0 ? !sensor.poll_ : sensor.poll_);
|
||||
} else if (!sensor.poll_) { // falling edge
|
||||
if (sensor.type() == AnalogType::COUNTER) {
|
||||
sensor.set_value(old_value + sensor.factor());
|
||||
|
||||
@@ -26,11 +26,11 @@
|
||||
#endif
|
||||
|
||||
#ifndef EMSESP_DEFAULT_TX_MODE
|
||||
#define EMSESP_DEFAULT_TX_MODE 1 // EMS1.0
|
||||
#define EMSESP_DEFAULT_TX_MODE 5 // Auto
|
||||
#endif
|
||||
|
||||
#ifndef EMSESP_DEFAULT_EMS_BUS_ID
|
||||
#define EMSESP_DEFAULT_EMS_BUS_ID 0x0B // service key
|
||||
#define EMSESP_DEFAULT_EMS_BUS_ID 0x49 // gateway 2
|
||||
#endif
|
||||
|
||||
#ifndef EMSESP_DEFAULT_SYSLOG_ENABLED
|
||||
|
||||
@@ -387,10 +387,10 @@ void EMSdevice::toggle_fetch(uint16_t telegram_id, bool toggle) {
|
||||
}
|
||||
|
||||
// get status of automatic fetch for a telegramID
|
||||
bool EMSdevice::is_fetch(uint16_t telegram_id) const {
|
||||
bool EMSdevice::is_fetch(uint16_t telegram_id, uint8_t len) const {
|
||||
for (const auto & tf : telegram_functions_) {
|
||||
if (tf.telegram_type_id_ == telegram_id) {
|
||||
return tf.fetch_;
|
||||
return tf.fetch_ && tf.length_ >= len;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -362,7 +362,7 @@ class EMSdevice {
|
||||
const char * telegram_type_name(std::shared_ptr<const Telegram> telegram);
|
||||
void fetch_values();
|
||||
void toggle_fetch(uint16_t telegram_id, bool toggle);
|
||||
bool is_fetch(uint16_t telegram_id) const;
|
||||
bool is_fetch(uint16_t telegram_id, uint8_t len = 0) const;
|
||||
bool is_received(uint16_t telegram_id) const;
|
||||
bool has_telegram_id(uint16_t id) const;
|
||||
void ha_config_clear();
|
||||
@@ -448,6 +448,14 @@ class EMSdevice {
|
||||
static constexpr uint8_t EMS_DEVICE_ID_DHW2 = 0x29; // MM100 module as water station
|
||||
static constexpr uint8_t EMS_DEVICE_ID_DHW8 = 0x2F; // last DHW module id?
|
||||
static constexpr uint8_t EMS_DEVICE_ID_IPM_DHW = 0x41; // IPM module as water station
|
||||
static constexpr uint8_t EMS_DEVICE_ID_GATEWAY1 = 0x48; // KM200, MX300, MX400
|
||||
static constexpr uint8_t EMS_DEVICE_ID_GATEWAY2 = 0x49;
|
||||
static constexpr uint8_t EMS_DEVICE_ID_GATEWAY3 = 0x4A;
|
||||
static constexpr uint8_t EMS_DEVICE_ID_GATEWAY4 = 0x4B;
|
||||
static constexpr uint8_t EMS_DEVICE_ID_GATEWAY5 = 0x4C;
|
||||
static constexpr uint8_t EMS_DEVICE_ID_GATEWAY6 = 0x4D;
|
||||
static constexpr uint8_t EMS_DEVICE_ID_GATEWAY7 = 0x4E;
|
||||
static constexpr uint8_t EMS_DEVICE_ID_GATEWAY8 = 0x4F;
|
||||
|
||||
// generic type IDs
|
||||
static constexpr uint16_t EMS_TYPE_NAME = 0x01; // device config for ems devices, name ascii on offset 27ff for ems+
|
||||
|
||||
@@ -1710,6 +1710,11 @@ void EMSESP::start() {
|
||||
bool factory_settings = false;
|
||||
#endif
|
||||
|
||||
#if defined(EMSESP_DEBUG)
|
||||
// LOG_DEBUG("Listing root directory before:");
|
||||
// system_.listDir("/", 3); // show the contents of the root directory
|
||||
#endif
|
||||
|
||||
// start NVS storage
|
||||
if (!nvs_.begin("ems-esp", false, "nvs1")) { // try bigger nvs partition on 16M flash first
|
||||
nvs_.begin("ems-esp", false, "nvs"); // fallback to small nvs
|
||||
@@ -1724,6 +1729,11 @@ void EMSESP::start() {
|
||||
// loads core system services settings (network, mqtt, ap, ntp etc)
|
||||
esp32React.begin();
|
||||
|
||||
#if defined(EMSESP_DEBUG)
|
||||
// LOG_DEBUG("Listing root directory before:");
|
||||
// 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.");
|
||||
|
||||
@@ -526,6 +526,29 @@ void System::syslog_init() {
|
||||
#endif
|
||||
}
|
||||
|
||||
// start or reconfigure modbus
|
||||
void System::modbus_init() {
|
||||
EMSESP::webSettingsService.read([&](WebSettings & settings) {
|
||||
if (settings.modbus_enabled) {
|
||||
if (EMSESP::modbus_ == nullptr) {
|
||||
EMSESP::modbus_ = new Modbus;
|
||||
EMSESP::modbus_->start(1, settings.modbus_port, settings.modbus_max_clients, settings.modbus_timeout * 1000);
|
||||
} else if (settings.modbus_port != modbus_port_ || settings.modbus_max_clients != modbus_max_clients_ || settings.modbus_timeout != modbus_timeout_) {
|
||||
EMSESP::modbus_->stop();
|
||||
EMSESP::modbus_->start(1, settings.modbus_port, settings.modbus_max_clients, settings.modbus_timeout * 1000);
|
||||
}
|
||||
} else if (EMSESP::modbus_ != nullptr) {
|
||||
EMSESP::modbus_->stop();
|
||||
delete EMSESP::modbus_;
|
||||
EMSESP::modbus_ = nullptr;
|
||||
}
|
||||
modbus_enabled_ = settings.modbus_enabled;
|
||||
modbus_port_ = settings.modbus_port;
|
||||
modbus_max_clients_ = settings.modbus_max_clients;
|
||||
modbus_timeout_ = settings.modbus_timeout;
|
||||
});
|
||||
}
|
||||
|
||||
// read specific major system settings to store locally for faster access
|
||||
void System::store_settings(WebSettings & settings) {
|
||||
version_ = settings.version;
|
||||
@@ -563,25 +586,6 @@ void System::store_settings(WebSettings & settings) {
|
||||
|
||||
locale_ = settings.locale;
|
||||
developer_mode_ = settings.developer_mode;
|
||||
|
||||
// start services
|
||||
if (settings.modbus_enabled) {
|
||||
if (EMSESP::modbus_ == nullptr) {
|
||||
EMSESP::modbus_ = new Modbus;
|
||||
EMSESP::modbus_->start(1, settings.modbus_port, settings.modbus_max_clients, settings.modbus_timeout * 1000);
|
||||
} else if (settings.modbus_port != modbus_port_ || settings.modbus_max_clients != modbus_max_clients_ || settings.modbus_timeout != modbus_timeout_) {
|
||||
EMSESP::modbus_->stop();
|
||||
EMSESP::modbus_->start(1, settings.modbus_port, settings.modbus_max_clients, settings.modbus_timeout * 1000);
|
||||
}
|
||||
} else if (EMSESP::modbus_ != nullptr) {
|
||||
EMSESP::modbus_->stop();
|
||||
delete EMSESP::modbus_;
|
||||
EMSESP::modbus_ = nullptr;
|
||||
}
|
||||
modbus_enabled_ = settings.modbus_enabled;
|
||||
modbus_port_ = settings.modbus_port;
|
||||
modbus_max_clients_ = settings.modbus_max_clients;
|
||||
modbus_timeout_ = settings.modbus_timeout;
|
||||
}
|
||||
|
||||
// Starts up core services
|
||||
@@ -631,17 +635,16 @@ void System::start() {
|
||||
network_init(); // network
|
||||
uart_init(); // start UART
|
||||
syslog_init(); // start syslog
|
||||
modbus_init(); // start modbus
|
||||
}
|
||||
|
||||
// button single click
|
||||
void System::button_OnClick(PButton & b) {
|
||||
LOG_NOTICE("Button pressed - single click");
|
||||
|
||||
#if defined(EMSESP_TEST)
|
||||
#ifndef EMSESP_STANDALONE
|
||||
// show filesystem
|
||||
Test::listDir(LittleFS, "/", 3);
|
||||
#endif
|
||||
listDir("/", 3);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1713,7 +1716,7 @@ void System::exportSystemBackup(JsonObject output) {
|
||||
output["version"] = EMSESP_APP_VERSION; // add the version to the output
|
||||
|
||||
#ifndef EMSESP_STANDALONE
|
||||
// add date/time if NTP enabled and active
|
||||
// add date/time if NTP enabled and active
|
||||
if ((esp_sntp_enabled()) && (EMSESP::system_.ntp_connected())) {
|
||||
time_t now = time(nullptr);
|
||||
if (now > 1500000000L) {
|
||||
@@ -1767,7 +1770,7 @@ void System::exportSystemBackup(JsonObject output) {
|
||||
node = nodes.add<JsonObject>();
|
||||
node["type"] = "nvs";
|
||||
|
||||
const char * nvs_part = "nvs";
|
||||
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;
|
||||
#if ESP_IDF_VERSION_MAJOR < 5
|
||||
it = nvs_entry_find(nvs_part, "ems-esp", NVS_TYPE_ANY);
|
||||
@@ -3266,7 +3269,7 @@ void System::set_valid_system_gpios() {
|
||||
valid_system_gpios_ = string_range_to_vector("0-21", "2, 8, 12-17, 18-19");
|
||||
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
// https://docs.espressif.com/projects/esp-idf/en/stable/esp32s2/api-reference/peripherals/gpio.html
|
||||
// https://docs.espressif.com/projects/esp-idf/en/stable/esp32s2/api-reference/peripherals/gpio.html
|
||||
// excluded:
|
||||
// GPIO26 - GPIO32 = SPI flash and PSRAM
|
||||
// GPIO45 - GPIO46 = strapping pins
|
||||
@@ -3279,7 +3282,7 @@ void System::set_valid_system_gpios() {
|
||||
valid_system_gpios_ = string_range_to_vector("0-46", "19, 20, 26-32, 45-46, 39-42, 22-25");
|
||||
|
||||
#elif CONFIG_IDF_TARGET_ESP32S3
|
||||
// https://docs.espressif.com/projects/esp-idf/en/stable/esp32s3/api-reference/peripherals/gpio.html
|
||||
// https://docs.espressif.com/projects/esp-idf/en/stable/esp32s3/api-reference/peripherals/gpio.html
|
||||
// excluded:
|
||||
// GPIO3, GPIO45 - GPIO46 = strapping pins
|
||||
// GPIO26 - GPIO32 = SPI flash and PSRAM and not recommended
|
||||
@@ -3298,7 +3301,7 @@ void System::set_valid_system_gpios() {
|
||||
}
|
||||
|
||||
#elif CONFIG_IDF_TARGET_ESP32
|
||||
// https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/peripherals/gpio.html
|
||||
// https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/peripherals/gpio.html
|
||||
// excluded:
|
||||
// GPIO6 - GPIO11, GPIO16 - GPIO17 = used for SPI flash and PSRAM (dio mode only GPIO06-GPIO08, GPIO11)
|
||||
// GPIO20, GPIO24, GPIO28 - GPIO31 = don't exist
|
||||
@@ -3378,6 +3381,24 @@ void System::remove_gpio(uint8_t pin, bool also_system) {
|
||||
}
|
||||
}
|
||||
|
||||
// remove a gpio that has 0 for disable
|
||||
void System::remove_optional_gpio(uint8_t pin) {
|
||||
if (pin) {
|
||||
remove_gpio(pin, false);
|
||||
}
|
||||
}
|
||||
|
||||
// set unused gpios to default state input high-Z
|
||||
void System::reset_unused_gpios() {
|
||||
for (const auto & pin : valid_system_gpios_) {
|
||||
auto it = std::find_if(used_gpios_.begin(), used_gpios_.end(), [pin](const GpioUsage & usage) { return usage.pin == pin; });
|
||||
if (it == used_gpios_.end()) {
|
||||
LOG_DEBUG("reset pin %d", pin);
|
||||
pinMode(pin, INPUT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// return a list of GPIO's available for use
|
||||
std::vector<uint8_t> System::available_gpios() {
|
||||
std::vector<uint8_t> gpios;
|
||||
@@ -3412,4 +3433,39 @@ void System::restore_snapshot_gpios(std::vector<int8_t> & u_gpios, std::vector<i
|
||||
}
|
||||
}
|
||||
|
||||
// show the contents of a directory in the LittleFS filesystem
|
||||
void System::listDir(const char * dirname, uint8_t levels) {
|
||||
#if defined(EMSESP_DEBUG)
|
||||
#ifndef EMSESP_STANDALONE
|
||||
|
||||
File root = LittleFS.open(dirname);
|
||||
if (!root) {
|
||||
LOG_DEBUG("Failed to open directory %s", dirname);
|
||||
return;
|
||||
}
|
||||
if (!root.isDirectory()) {
|
||||
LOG_DEBUG("%s is not a directory", dirname);
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_DEBUG("(directory) %s", dirname);
|
||||
|
||||
File file = root.openNextFile();
|
||||
while (file) {
|
||||
if (file.isDirectory()) {
|
||||
std::string line = std::string(file.name()) + "/";
|
||||
if (levels) {
|
||||
// prefix a / to the name to make it a full path
|
||||
listDir(("/" + String(file.name())).c_str(), levels - 1);
|
||||
}
|
||||
} else {
|
||||
std::string line = " (file) " + std::string(file.name()) + " (" + std::to_string(file.size()) + " bytes)";
|
||||
LOG_DEBUG("%s", line.c_str());
|
||||
}
|
||||
file = root.openNextFile();
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace emsesp
|
||||
|
||||
@@ -109,6 +109,8 @@ class System {
|
||||
static void get_value_json(JsonObject output, const std::string & circuit, const std::string & name, JsonVariant val);
|
||||
static std::string get_metrics_prometheus();
|
||||
|
||||
static void listDir(const char * dirname, uint8_t levels);
|
||||
|
||||
#if defined(EMSESP_TEST)
|
||||
static bool command_test(const char * value, const int8_t id);
|
||||
#endif
|
||||
@@ -122,6 +124,7 @@ class System {
|
||||
void show_mem(const char * note);
|
||||
void store_settings(class WebSettings & settings);
|
||||
void syslog_init();
|
||||
void modbus_init();
|
||||
bool check_upgrade();
|
||||
bool check_restore();
|
||||
void heartbeat_json(JsonObject output);
|
||||
@@ -376,6 +379,8 @@ class System {
|
||||
#endif
|
||||
|
||||
static void remove_gpio(uint8_t pin, bool also_system = false); // remove a gpio from both valid (optional) and used lists
|
||||
static void remove_optional_gpio(uint8_t pin);
|
||||
static void reset_unused_gpios();
|
||||
|
||||
// Partition info map: partition name -> {version, size, install_date}
|
||||
std::map<std::string, PartitionInfo, std::less<>, AllocatorPSRAM<std::pair<const std::string, PartitionInfo>>> partition_info_;
|
||||
|
||||
@@ -43,6 +43,7 @@ uint8_t EMSbus::ems_mask_ = EMS_MASK_UNSET; // unset so its triggered
|
||||
uint8_t EMSbus::ems_bus_id_ = EMSESP_DEFAULT_EMS_BUS_ID;
|
||||
uint8_t EMSbus::tx_mode_ = EMSESP_DEFAULT_TX_MODE;
|
||||
uint8_t EMSbus::tx_state_ = Telegram::Operation::NONE;
|
||||
bool EMSbus::isEMS2_ = false;
|
||||
|
||||
uuid::log::Logger EMSbus::logger_{F_(telegram), uuid::log::Facility::CONSOLE};
|
||||
|
||||
@@ -206,7 +207,9 @@ void RxService::add(uint8_t * data, uint8_t length) {
|
||||
message_data = data + 6;
|
||||
message_length = length - 7;
|
||||
}
|
||||
|
||||
if (type_id > 0x0FF && message_length > 1) { // used for auto tx_mode
|
||||
set_ems2();
|
||||
}
|
||||
// if we're watching and "raw" print out actual telegram as bytes to the console
|
||||
// including the CRC at the end
|
||||
if (EMSESP::watch() == EMSESP::Watch::WATCH_RAW) {
|
||||
|
||||
@@ -168,6 +168,15 @@ class EMSbus {
|
||||
return (ems_mask_ == EMS_MASK_HT3);
|
||||
}
|
||||
|
||||
static bool is_ems2() {
|
||||
return isEMS2_;
|
||||
}
|
||||
|
||||
static void set_ems2() {
|
||||
isEMS2_ = true;
|
||||
;
|
||||
}
|
||||
|
||||
static uint8_t ems_mask() {
|
||||
return ems_mask_;
|
||||
}
|
||||
@@ -242,6 +251,7 @@ class EMSbus {
|
||||
static uint8_t ems_bus_id_; // the bus id, which configurable and stored in settings
|
||||
static uint8_t tx_mode_; // local copy of the tx mode
|
||||
static uint8_t tx_state_; // state of the Tx line (NONE or waiting on a TX_READ or TX_WRITE)
|
||||
static bool isEMS2_;
|
||||
};
|
||||
|
||||
class RxService : public EMSbus {
|
||||
|
||||
@@ -21,12 +21,6 @@
|
||||
#include "temperaturesensor.h"
|
||||
#include "emsesp.h"
|
||||
|
||||
#ifdef ESP32
|
||||
#define YIELD
|
||||
#else
|
||||
#define YIELD yield()
|
||||
#endif
|
||||
|
||||
namespace emsesp {
|
||||
|
||||
uuid::log::Logger TemperatureSensor::logger_{F_(temperaturesensor), uuid::log::Facility::DAEMON};
|
||||
@@ -81,7 +75,6 @@ void TemperatureSensor::loop() {
|
||||
LOG_DEBUG("Read sensor temperature");
|
||||
#endif
|
||||
if (bus_.reset() || parasite_) {
|
||||
YIELD;
|
||||
bus_.skip();
|
||||
bus_.write(CMD_CONVERT_TEMP, parasite_ ? 1 : 0);
|
||||
state_ = State::READING;
|
||||
@@ -260,19 +253,16 @@ int16_t TemperatureSensor::get_temperature_c(const uint8_t addr[]) {
|
||||
LOG_ERROR("Bus reset failed before reading scratchpad from %s", Sensor(addr).id());
|
||||
return EMS_VALUE_INT16_NOTSET;
|
||||
}
|
||||
YIELD;
|
||||
|
||||
uint8_t scratchpad[SCRATCHPAD_LEN] = {0};
|
||||
bus_.select(addr);
|
||||
bus_.write(CMD_READ_SCRATCHPAD);
|
||||
bus_.read_bytes(scratchpad, SCRATCHPAD_LEN);
|
||||
YIELD;
|
||||
|
||||
if (!bus_.reset()) {
|
||||
LOG_ERROR("Bus reset failed after reading scratchpad from %s", Sensor(addr).id());
|
||||
return EMS_VALUE_INT16_NOTSET;
|
||||
}
|
||||
YIELD;
|
||||
|
||||
if (bus_.crc8(scratchpad, SCRATCHPAD_LEN - 1) != scratchpad[SCRATCHPAD_LEN - 1]) {
|
||||
LOG_WARNING("Invalid scratchpad CRC: %02X%02X%02X%02X%02X%02X%02X%02X%02X from sensor %s",
|
||||
|
||||
@@ -39,11 +39,11 @@ Connect::Connect(uint8_t device_type, uint8_t device_id, uint8_t product_id, con
|
||||
DeviceValueUOM::DEGREES);
|
||||
// Roomthermostats
|
||||
for (uint8_t i = 0; i < 16; i++) {
|
||||
register_telegram_type(0x0BDD + i, "Room", false, MAKE_PF_CB(process_roomThermostat)); // broadcasted
|
||||
register_telegram_type(0x0B3D + i, "Roomname", false, MAKE_PF_CB(process_roomThermostatName), 100); // fetch for active circuits
|
||||
register_telegram_type(0x0BDD + i, "Room", false, MAKE_PF_CB(process_roomThermostat)); // broadcasted
|
||||
register_telegram_type(0x0B3D + i, "Roomname", false, MAKE_PF_CB(process_roomThermostatName), 100); // fetch for active circuits
|
||||
register_telegram_type(0x0BB5 + i, "Roomsettings", false, MAKE_PF_CB(process_roomThermostatSettings), 8); // fetch for active circuits
|
||||
register_telegram_type(0x1230 + i, "Roomparams", false, MAKE_PF_CB(process_roomThermostatParam)); // fetch for active circuits
|
||||
register_telegram_type(0x1244 + i, "Roomdata", false, MAKE_PF_CB(process_roomThermostatData)); // broadcasted
|
||||
register_telegram_type(0x1230 + i, "Roomparams", false, MAKE_PF_CB(process_roomThermostatParam)); // fetch for active circuits
|
||||
register_telegram_type(0x1244 + i, "Roomdata", false, MAKE_PF_CB(process_roomThermostatData)); // broadcasted
|
||||
}
|
||||
register_telegram_type(0xDB65, "Roomschedule", true, MAKE_PF_CB(process_roomSchedule));
|
||||
// 0x2040, broadcast 36 bytes:
|
||||
|
||||
@@ -173,7 +173,7 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i
|
||||
for (uint8_t i = 0; i < monitor_size; i++) {
|
||||
register_telegram_type(monitor_typeids[i], "RC300Monitor", false, MAKE_PF_CB(process_RC300Monitor), 33);
|
||||
register_telegram_type(set_typeids[i], "RC300Set", false, MAKE_PF_CB(process_RC300Set), 29);
|
||||
register_telegram_type(summer_typeids[i], "RC300Summer", false, MAKE_PF_CB(process_RC300Summer), 13);
|
||||
register_telegram_type(summer_typeids[i], "RC300Summer", false, MAKE_PF_CB(process_RC300Summer), 14);
|
||||
register_telegram_type(curve_typeids[i], "RC300Curves", false, MAKE_PF_CB(process_RC300Curve), 9);
|
||||
register_telegram_type(summer2_typeids[i], "RC300Summer2", false, MAKE_PF_CB(process_RC300Summer2), 8);
|
||||
}
|
||||
@@ -202,11 +202,12 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i
|
||||
if (model == EMSdevice::EMS_DEVICE_FLAG_RC100) {
|
||||
register_telegram_type(0x43F, "CRHolidays", true, MAKE_PF_CB(process_RC300Holiday), 6);
|
||||
} else {
|
||||
register_telegram_type(0x269, "RC300Holiday", true, MAKE_PF_CB(process_RC300Holiday), 6);
|
||||
register_telegram_type(0x269, "RC300Holiday", true, MAKE_PF_CB(process_RC300Holiday), 18);
|
||||
}
|
||||
register_telegram_type(0x16E, "Absent", true, MAKE_PF_CB(process_Absent), 1);
|
||||
register_telegram_type(0xBF, "ErrorMessage", false, MAKE_PF_CB(process_ErrorMessageBF));
|
||||
register_telegram_type(0xC0, "RCErrorMessage", false, MAKE_PF_CB(process_RCErrorMessage2));
|
||||
register_telegram_type(0x470, "RC300Summer2", true, MAKE_PF_CB(process_RC300Summer2), 8);
|
||||
EMSESP::send_read_request(0xC0, device_id, 0, 20); // read last errorcode on start (only published on errors)
|
||||
|
||||
// JUNKERS/HT3
|
||||
@@ -1268,7 +1269,13 @@ void Thermostat::process_RC300Summer(std::shared_ptr<const Telegram> telegram) {
|
||||
void Thermostat::process_RC300Summer2(std::shared_ptr<const Telegram> telegram) {
|
||||
auto hc = heating_circuit(telegram);
|
||||
if (hc == nullptr) {
|
||||
return;
|
||||
// telegram 0x470 see https://github.com/emsesp/EMS-ESP32/issues/2686
|
||||
if (telegram->type_id == 0x470 && telegram->message_length > 2) {
|
||||
hc = heating_circuit(1);
|
||||
summer2_typeids[0] = 0x470;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (hc->statusbyte & 1) {
|
||||
has_update(telegram, hc->summersetmode, 0);
|
||||
|
||||
@@ -1 +1 @@
|
||||
#define EMSESP_APP_VERSION "3.8.2-dev.16"
|
||||
#define EMSESP_APP_VERSION "3.8.2"
|
||||
|
||||
@@ -68,7 +68,7 @@ bool Test::test(const std::string & cmd, int8_t id1, int8_t id2) {
|
||||
uart_telegram({0x08, 0x98, 0x33, 0x00, 0x23, 0x24});
|
||||
|
||||
// Boiler -> Me, UBAParameterWW(0x33), telegram: 08 0B 33 00 08 FF 34 FB 00 28 00 00 46 00 FF FF 00 (#data=13)
|
||||
uart_telegram({0x08, 0x0B, 0x33, 0x00, 0x08, 0xFF, 0x34, 0xFB, 0x00, 0x28, 0x00, 0x00, 0x46, 0x00, 0xFF, 0xFF, 0x00});
|
||||
uart_telegram({0x08, 0x49, 0x33, 0x00, 0x08, 0xFF, 0x34, 0xFB, 0x00, 0x28, 0x00, 0x00, 0x46, 0x00, 0xFF, 0xFF, 0x00});
|
||||
|
||||
// Thermostat RCPLUSStatusMessage_HC1(0x01A5)
|
||||
uart_telegram({0x98, 0x00, 0xFF, 0x00, 0x01, 0xA5, 0x00, 0xCF, 0x21, 0x2E, 0x00, 0x00, 0x2E, 0x24,
|
||||
@@ -89,7 +89,7 @@ bool Test::test(const std::string & cmd, int8_t id1, int8_t id2) {
|
||||
|
||||
add_device(0x08, 219); // Greenstar HIU/Logamax kompakt WS170
|
||||
|
||||
// [emsesp] boiler(0x08) -W-> Me(0x0B), UBAMonitorFastPlus(0xE4), data: 00 01 35 00 00 00 00 00 00 00 00 80 00 00 00 00 00 00 00 80 00 (offset 6)
|
||||
// [emsesp] boiler(0x08) -W-> Me(0x49), UBAMonitorFastPlus(0xE4), data: 00 01 35 00 00 00 00 00 00 00 00 80 00 00 00 00 00 00 00 80 00 (offset 6)
|
||||
uart_telegram({0x08, 0x00, 0xE4, 0x00, //
|
||||
00, 01, 0x35, 00, 00, 00, 00, 00, 00, 00, 00, 0x80, 00, 00, 00, 00, 00, 00, 00, 0x80, 00});
|
||||
|
||||
@@ -112,7 +112,7 @@ bool Test::test(const std::string & cmd, int8_t id1, int8_t id2) {
|
||||
uart_telegram({0x08, 0x90, 0x33, 0x00, 0x23, 0x24});
|
||||
|
||||
// Boiler -> Me, UBAParameterWW(0x33), telegram: 08 0B 33 00 08 FF 34 FB 00 28 00 00 46 00 FF FF 00 (#data=13)
|
||||
uart_telegram({0x08, 0x0B, 0x33, 0x00, 0x08, 0xFF, 0x34, 0xFB, 0x00, 0x28, 0x00, 0x00, 0x46, 0x00, 0xFF, 0xFF, 0x00});
|
||||
uart_telegram({0x08, 0x49, 0x33, 0x00, 0x08, 0xFF, 0x34, 0xFB, 0x00, 0x28, 0x00, 0x00, 0x46, 0x00, 0xFF, 0xFF, 0x00});
|
||||
|
||||
// Thermostat 0x2A5 for HC1
|
||||
uart_telegram({0x10, 00, 0xFF, 00, 01, 0xA5, 0x80, 00, 01, 0x30, 0x28, 00, 0x30, 0x28, 01, 0x54,
|
||||
@@ -144,7 +144,7 @@ bool Test::test(const std::string & cmd, int8_t id1, int8_t id2) {
|
||||
uart_telegram({0x08, 0x90, 0x33, 0x00, 0x23, 0x24});
|
||||
|
||||
// Boiler -> Me, UBAParameterWW(0x33), telegram: 08 0B 33 00 08 FF 34 FB 00 28 00 00 46 00 FF FF 00 (#data=13)
|
||||
uart_telegram({0x08, 0x0B, 0x33, 0x00, 0x08, 0xFF, 0x34, 0xFB, 0x00, 0x28, 0x00, 0x00, 0x46, 0x00, 0xFF, 0xFF, 0x00});
|
||||
uart_telegram({0x08, 0x49, 0x33, 0x00, 0x08, 0xFF, 0x34, 0xFB, 0x00, 0x28, 0x00, 0x00, 0x46, 0x00, 0xFF, 0xFF, 0x00});
|
||||
|
||||
// Thermostat 0x2A5 for HC1
|
||||
uart_telegram({0x10, 00, 0xFF, 00, 01, 0xA5, 0x80, 00, 01, 0x30, 0x28, 00, 0x30, 0x28, 01, 0x54,
|
||||
@@ -160,7 +160,7 @@ bool Test::test(const std::string & cmd, int8_t id1, int8_t id2) {
|
||||
EMSESP::logger().notice("Adding a Gateway...");
|
||||
|
||||
// add 0x48 KM200, via a version command
|
||||
rx_telegram({0x48, 0x0B, 0x02, 0x00, 0xBD, 0x04, 0x06, 00, 00, 00, 00, 00, 00, 00});
|
||||
rx_telegram({0x48, 0x49, 0x02, 0x00, 0xBD, 0x04, 0x06, 00, 00, 00, 00, 00, 00, 00});
|
||||
|
||||
// Boiler(0x08) -> All(0x00), UBADevices(0x07), data: 09 01 00 00 00 00 00 00 01 00 00 00 00
|
||||
// check: make sure 0x48 is not detected again !
|
||||
@@ -203,14 +203,14 @@ bool Test::test(const std::string & cmd, int8_t id1, int8_t id2) {
|
||||
add_device(0x08, 123); // Nefit Trendline
|
||||
|
||||
// UBAuptime
|
||||
uart_telegram({0x08, 0x0B, 0x14, 00, 0x3C, 0x1F, 0xAC, 0x70});
|
||||
uart_telegram({0x08, 0x49, 0x14, 00, 0x3C, 0x1F, 0xAC, 0x70});
|
||||
|
||||
// Boiler -> Me, UBAMonitorFast(0x18), telegram: 08 00 18 00 00 02 5A 73 3D 0A 10 65 40 02 1A 80 00 01 E1 01 76 0E 3D 48 00 C9 44 02 00 (#data=25)
|
||||
uart_telegram({0x08, 0x00, 0x18, 0x00, 0x00, 0x02, 0x5A, 0x73, 0x3D, 0x0A, 0x10, 0x65, 0x40, 0x02, 0x1A,
|
||||
0x80, 0x00, 0x01, 0xE1, 0x01, 0x76, 0x0E, 0x3D, 0x48, 0x00, 0xC9, 0x44, 0x02, 0x00});
|
||||
|
||||
// Boiler -> Me, UBAParameterWW(0x33), telegram: 08 0B 33 00 08 FF 34 FB 00 28 00 00 46 00 FF FF 00 (#data=13)
|
||||
uart_telegram({0x08, 0x0B, 0x33, 0x00, 0x08, 0xFF, 0x34, 0xFB, 0x00, 0x28, 0x00, 0x00, 0x46, 0x00, 0xFF, 0xFF, 0x00});
|
||||
uart_telegram({0x08, 0x49, 0x33, 0x00, 0x08, 0xFF, 0x34, 0xFB, 0x00, 0x28, 0x00, 0x00, 0x46, 0x00, 0xFF, 0xFF, 0x00});
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -234,10 +234,10 @@ bool Test::test(const std::string & cmd, int8_t id1, int8_t id2) {
|
||||
add_device(0x30, 163); // SM100
|
||||
|
||||
// SM100Monitor - type 0x0362 EMS+ - for SM100 and SM200
|
||||
uart_telegram({0xB0, 0x0B, 0xFF, 00, 0x02, 0x62, 00, 0x44, 0x02, 0x7A, 0x80, 00, 0x80, 0x00, 0x80, 00,
|
||||
uart_telegram({0xB0, 0x49, 0xFF, 00, 0x02, 0x62, 00, 0x44, 0x02, 0x7A, 0x80, 00, 0x80, 0x00, 0x80, 00,
|
||||
0x80, 00, 0x80, 00, 0x80, 00, 00, 0x7C, 0x80, 00, 0x80, 00, 0x80, 00, 0x80});
|
||||
|
||||
uart_telegram({0xB0, 0x0B, 0xFF, 0x00, 0x02, 0x62, 0x01, 0x44, 0x03, 0x30, 0x80, 00, 0x80, 00, 0x80, 00,
|
||||
uart_telegram({0xB0, 0x49, 0xFF, 0x00, 0x02, 0x62, 0x01, 0x44, 0x03, 0x30, 0x80, 00, 0x80, 00, 0x80, 00,
|
||||
0x80, 00, 0x80, 00, 0x80, 00, 0x80, 00, 0x80, 00, 0x80, 00, 0x80, 00, 0x80, 0x33});
|
||||
|
||||
uart_telegram({0xB0, 00, 0xFF, 0x18, 02, 0x62, 0x80, 00, 0xB8});
|
||||
@@ -450,7 +450,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
|
||||
// THESE ONLY WORK WITH AN ESP32, not in standalone/native mode
|
||||
#ifndef EMSESP_STANDALONE
|
||||
if (command == "ls") {
|
||||
listDir(LittleFS, "/", 3);
|
||||
System::listDir("/", 3);
|
||||
ok = true;
|
||||
}
|
||||
|
||||
@@ -580,7 +580,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
|
||||
add_device(0x09, 206); // Nefit Excellent HR30 Controller
|
||||
|
||||
// UBAuptime
|
||||
uart_telegram({0x08, 0x0B, 0x14, 00, 0x3C, 0x1F, 0xAC, 0x70});
|
||||
uart_telegram({0x08, 0x49, 0x14, 00, 0x3C, 0x1F, 0xAC, 0x70});
|
||||
ok = true;
|
||||
}
|
||||
|
||||
@@ -588,10 +588,10 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
|
||||
EMSESP::logger().notice("Testing 620...");
|
||||
|
||||
// Version Controller
|
||||
uart_telegram({0x09, 0x0B, 0x02, 0x00, 0x5F, 0x06, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00});
|
||||
uart_telegram({0x09, 0x49, 0x02, 0x00, 0x5F, 0x06, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00});
|
||||
|
||||
// Version Boiler
|
||||
uart_telegram({0x08, 0x0B, 0x02, 0x00, 0x5F, 0x06, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00});
|
||||
uart_telegram({0x08, 0x49, 0x02, 0x00, 0x5F, 0x06, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00});
|
||||
ok = true;
|
||||
}
|
||||
|
||||
@@ -607,7 +607,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
|
||||
|
||||
// simulate getting version information back from an unknown device
|
||||
// note there is no brand (byte 9)
|
||||
rx_telegram({0x09, 0x0B, 0x02, 0x00, 0x59, 0x09, 0x0a});
|
||||
rx_telegram({0x09, 0x49, 0x02, 0x00, 0x59, 0x09, 0x0a});
|
||||
|
||||
shell.invoke_command("show devices");
|
||||
shell.invoke_command("call system report");
|
||||
@@ -618,7 +618,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
|
||||
shell.printfln("Testing unknown2...");
|
||||
|
||||
// simulate getting version information back from an unknown device
|
||||
rx_telegram({0x09, 0x0B, 0x02, 0x00, 0x5A, 0x01, 0x02}); // productID is 90 which doesn't exist
|
||||
rx_telegram({0x09, 0x49, 0x02, 0x00, 0x5A, 0x01, 0x02}); // productID is 90 which doesn't exist
|
||||
ok = true;
|
||||
}
|
||||
|
||||
@@ -815,9 +815,9 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
|
||||
// test("thermostat");
|
||||
|
||||
// 0xC2
|
||||
// [emsesp] Boiler(0x08) -> Me(0x0B), UBAErrorMessage3(0xC2), data: 08 AC 00 10 31 48 30 31 15 80 95 0B 0E 10 38 00 7F FF FF FF 08 AC 00 10 09 41 30
|
||||
// [emsesp] Boiler(0x08) -> Me(0x49), UBAErrorMessage3(0xC2), data: 08 AC 00 10 31 48 30 31 15 80 95 0B 0E 10 38 00 7F FF FF FF 08 AC 00 10 09 41 30
|
||||
uart_telegram(
|
||||
{0x08, 0x0B, 0xC2, 0, 0x08, 0xAC, 00, 0x10, 0x31, 0x48, 0x30, 0x31, 0x15, 0x80, 0x95, 0x0B, 0x0E, 0x10, 0x38, 00, 0x7F, 0xFF, 0xFF, 0xFF});
|
||||
{0x08, 0x49, 0xC2, 0, 0x08, 0xAC, 00, 0x10, 0x31, 0x48, 0x30, 0x31, 0x15, 0x80, 0x95, 0x0B, 0x0E, 0x10, 0x38, 00, 0x7F, 0xFF, 0xFF, 0xFF});
|
||||
|
||||
// shell.invoke_command("show values");
|
||||
|
||||
@@ -1042,7 +1042,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
|
||||
// Boiler -> Me, UBAParameterWW(0x33)
|
||||
// wwseltemp = goes from 52 degrees (0x34) to void (0xFF)
|
||||
// it should delete the HA config topic homeassistant/sensor/ems-esp/boiler_wwseltemp/config
|
||||
uart_telegram({0x08, 0x0B, 0x33, 0x00, 0x08, 0xFF, 0xFF, 0xFB, 0x00, 0x28, 0x00, 0x00, 0x46, 0x00, 0xFF, 0xFF, 0x00});
|
||||
uart_telegram({0x08, 0x49, 0x33, 0x00, 0x08, 0xFF, 0xFF, 0xFB, 0x00, 0x28, 0x00, 0x00, 0x46, 0x00, 0xFF, 0xFF, 0x00});
|
||||
|
||||
shell.invoke_command("call boiler wwseltemp");
|
||||
shell.invoke_command("call system publish");
|
||||
@@ -1795,7 +1795,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
|
||||
add_device(0x18, 202); // Bosch TC100 - https://github.com/emsesp/EMS-ESP/issues/474
|
||||
|
||||
// 0x0A
|
||||
uart_telegram({0x98, 0x0B, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
uart_telegram({0x98, 0x49, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00});
|
||||
ok = true;
|
||||
}
|
||||
@@ -1829,10 +1829,10 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
|
||||
|
||||
// SM100Monitor - type 0x0362 EMS+ - for SM100 and SM200
|
||||
// B0 0B FF 00 02 62 00 44 02 7A 80 00 80 00 80 00 80 00 80 00 80 00 00 7C 80 00 80 00 80 00 80
|
||||
rx_telegram({0xB0, 0x0B, 0xFF, 00, 0x02, 0x62, 00, 0x44, 0x02, 0x7A, 0x80, 00, 0x80, 0x00, 0x80, 00,
|
||||
rx_telegram({0xB0, 0x49, 0xFF, 00, 0x02, 0x62, 00, 0x44, 0x02, 0x7A, 0x80, 00, 0x80, 0x00, 0x80, 00,
|
||||
0x80, 00, 0x80, 00, 0x80, 00, 00, 0x7C, 0x80, 00, 0x80, 00, 0x80, 00, 0x80});
|
||||
|
||||
rx_telegram({0xB0, 0x0B, 0xFF, 0x00, 0x02, 0x62, 0x01, 0x44, 0x03, 0x30, 0x80, 00, 0x80, 00, 0x80, 00,
|
||||
rx_telegram({0xB0, 0x49, 0xFF, 0x00, 0x02, 0x62, 0x01, 0x44, 0x03, 0x30, 0x80, 00, 0x80, 00, 0x80, 00,
|
||||
0x80, 00, 0x80, 00, 0x80, 00, 0x80, 00, 0x80, 00, 0x80, 00, 0x80, 00, 0x80, 0x33});
|
||||
|
||||
rx_telegram({0xB0, 00, 0xFF, 0x18, 02, 0x62, 0x80, 00, 0xB8});
|
||||
@@ -1936,7 +1936,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
|
||||
if (command == "rx2") {
|
||||
shell.printfln("Testing Rx2...");
|
||||
for (uint8_t i = 0; i < 30; i++) {
|
||||
uart_telegram({0x08, 0x0B, 0x33, 0x00, 0x08, 0xFF, 0x34, 0xFB, 0x00, 0x28, 0x00, 0x00, 0x46, 0x00, 0xFF, 0xFF, 0x00});
|
||||
uart_telegram({0x08, 0x49, 0x33, 0x00, 0x08, 0xFF, 0x34, 0xFB, 0x00, 0x28, 0x00, 0x00, 0x46, 0x00, 0xFF, 0xFF, 0x00});
|
||||
ok = true;
|
||||
}
|
||||
}
|
||||
@@ -1953,23 +1953,23 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
|
||||
uart_telegram({0x08, 0x97, 0x33, 0x00, 0x23, 0x24});
|
||||
|
||||
// Boiler -> Me, UBAParameterWW(0x33), telegram: 08 0B 33 00 08 FF 34 FB 00 28 00 00 46 00 FF FF 00 (#data=13)
|
||||
uart_telegram({0x08, 0x0B, 0x33, 0x00, 0x08, 0xFF, 0x34, 0xFB, 0x00, 0x28, 0x00, 0x00, 0x46, 0x00, 0xFF, 0xFF, 0x00});
|
||||
uart_telegram({0x08, 0x49, 0x33, 0x00, 0x08, 0xFF, 0x34, 0xFB, 0x00, 0x28, 0x00, 0x00, 0x46, 0x00, 0xFF, 0xFF, 0x00});
|
||||
|
||||
// Thermostat -> Me, RC20StatusMessage(0x91), telegram: 17 0B 91 05 44 45 46 47 (#data=4)
|
||||
uart_telegram({0x17, 0x0B, 0x91, 0x05, 0x44, 0x45, 0x46, 0x47});
|
||||
uart_telegram({0x17, 0x49, 0x91, 0x05, 0x44, 0x45, 0x46, 0x47});
|
||||
|
||||
// bad CRC - corrupt telegram - CRC should be 0x8E
|
||||
uint8_t t5[] = {0x17, 0x0B, 0x91, 0x05, 0x44, 0x45, 0x46, 0x47, 0x99};
|
||||
uint8_t t5[] = {0x17, 0x49, 0x91, 0x05, 0x44, 0x45, 0x46, 0x47, 0x99};
|
||||
EMSESP::rxservice_.add(t5, sizeof(t5));
|
||||
|
||||
// simulating a Tx record
|
||||
uart_telegram({0x0B, 0x88, 0x07, 0x00, 0x20});
|
||||
uart_telegram({0x49, 0x88, 0x07, 0x00, 0x20});
|
||||
|
||||
// Version Boiler
|
||||
uart_telegram({0x08, 0x0B, 0x02, 0x00, 0x7B, 0x06, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04});
|
||||
uart_telegram({0x08, 0x49, 0x02, 0x00, 0x7B, 0x06, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04});
|
||||
|
||||
// Version Thermostat, device_id 0x11
|
||||
uart_telegram({0x11, 0x0B, 0x02, 0x00, 0x4D, 0x03, 0x03});
|
||||
uart_telegram({0x11, 0x49, 0x02, 0x00, 0x4D, 0x03, 0x03});
|
||||
|
||||
// Thermostat -> all, telegram: 10 00 FF 00 01 A5 00 D7 21 00 00 00 00 30 01 84 01 01 03 01 84 01 F1 00 00 11 01 00 08 63 00
|
||||
// 0x1A5 test ems+
|
||||
@@ -1987,7 +1987,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
|
||||
uart_telegram({0x17, 0x08, 0x1A, 0x00, 0x00, 0x00, 0x00, 0x00});
|
||||
|
||||
// Thermostat -> Me, RC20Set(0xA8), telegram: 17 0B A8 00 01 00 FF F6 01 06 00 01 0D 01 00 FF FF 01 02 02 02 00 00 05 1F 05 1F 02 0E 00 FF (#data=27)
|
||||
uart_telegram({0x17, 0x0B, 0xA8, 0x00, 0x01, 0x00, 0xFF, 0xF6, 0x01, 0x06, 0x00, 0x01, 0x0D, 0x01, 0x00, 0xFF,
|
||||
uart_telegram({0x17, 0x49, 0xA8, 0x00, 0x01, 0x00, 0xFF, 0xF6, 0x01, 0x06, 0x00, 0x01, 0x0D, 0x01, 0x00, 0xFF,
|
||||
0xFF, 0x01, 0x02, 0x02, 0x02, 0x00, 0x00, 0x05, 0x1F, 0x05, 0x1F, 0x02, 0x0E, 0x00, 0xFF});
|
||||
|
||||
// Boiler(0x08) -> All(0x00), UBAMonitorWW(0x34), data: 36 01 A5 80 00 21 00 00 01 00 01 3E 8D 03 77 91 00 80 00
|
||||
@@ -2021,7 +2021,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
|
||||
EMSESP::send_write_request(0x91, 0x17, 0x00, t18, sizeof(t18), 0x00);
|
||||
|
||||
// TX - send EMS+
|
||||
const uint8_t t13[] = {0x90, 0x0B, 0xFF, 00, 01, 0xBA, 00, 0x2E, 0x2A, 0x26, 0x1E, 0x03,
|
||||
const uint8_t t13[] = {0x90, 0x49, 0xFF, 00, 01, 0xBA, 00, 0x2E, 0x2A, 0x26, 0x1E, 0x03,
|
||||
00, 0xFF, 0xFF, 05, 0x2A, 01, 0xE1, 0x20, 0x01, 0x0F, 05, 0x2A};
|
||||
EMSESP::txservice_.add(Telegram::Operation::TX_RAW, t13, sizeof(t13), 0);
|
||||
|
||||
@@ -2145,7 +2145,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
|
||||
uart_telegram({0x08, 0x98, 0x33, 0x00, 0x23, 0x24});
|
||||
|
||||
// Boiler -> Me, UBAParameterWW(0x33), telegram: 08 0B 33 00 08 FF 34 FB 00 28 00 00 46 00 FF FF 00 (#data=13)
|
||||
uart_telegram({0x08, 0x0B, 0x33, 0x00, 0x08, 0xFF, 0x34, 0xFB, 0x00, 0x28, 0x00, 0x00, 0x46, 0x00, 0xFF, 0xFF, 0x00});
|
||||
uart_telegram({0x08, 0x49, 0x33, 0x00, 0x08, 0xFF, 0x34, 0xFB, 0x00, 0x28, 0x00, 0x00, 0x46, 0x00, 0xFF, 0xFF, 0x00});
|
||||
|
||||
// add a thermostat
|
||||
add_device(0x18, 157); // Bosch CR100
|
||||
@@ -2487,7 +2487,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
|
||||
if (command == "rx3") {
|
||||
shell.printfln("Testing rx3...");
|
||||
|
||||
uart_telegram({0x21, 0x0B, 0xFF, 0x00});
|
||||
uart_telegram({0x21, 0x49, 0xFF, 0x00});
|
||||
ok = true;
|
||||
}
|
||||
|
||||
@@ -2495,7 +2495,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
|
||||
if (command == "tx2") {
|
||||
shell.printfln("Testing tx2...");
|
||||
|
||||
uint8_t t[] = {0x0B, 0x88, 0x18, 0x00, 0x20, 0xD4}; // including CRC
|
||||
uint8_t t[] = {0x49, 0x88, 0x18, 0x00, 0x20, 0xD4}; // including CRC
|
||||
EMSuart::transmit(t, sizeof(t));
|
||||
ok = true;
|
||||
}
|
||||
@@ -2676,45 +2676,6 @@ void Test::add_device(uint8_t device_id, uint8_t product_id) {
|
||||
uart_telegram({device_id, EMSESP_DEFAULT_EMS_BUS_ID, EMSdevice::EMS_TYPE_VERSION, 0, product_id, 1, 0});
|
||||
}
|
||||
|
||||
#ifdef EMSESP_TEST
|
||||
#ifndef EMSESP_STANDALONE
|
||||
void Test::listDir(fs::FS & fs, const char * dirname, uint8_t levels) {
|
||||
Serial.println();
|
||||
Serial.printf("%s\r\n", dirname);
|
||||
|
||||
File root = fs.open(dirname);
|
||||
if (!root) {
|
||||
Serial.println("- failed to open directory");
|
||||
return;
|
||||
}
|
||||
if (!root.isDirectory()) {
|
||||
Serial.println(" - not a directory");
|
||||
return;
|
||||
}
|
||||
|
||||
File file = root.openNextFile();
|
||||
while (file) {
|
||||
if (file.isDirectory()) {
|
||||
Serial.print(file.name());
|
||||
Serial.println("/");
|
||||
if (levels) {
|
||||
// prefix a / to the name to make it a full path
|
||||
listDir(fs, ("/" + String(file.name())).c_str(), levels - 1);
|
||||
}
|
||||
Serial.println();
|
||||
} else {
|
||||
Serial.print(" ");
|
||||
Serial.print(file.name());
|
||||
Serial.print(" (");
|
||||
Serial.print(file.size());
|
||||
Serial.println(" bytes)");
|
||||
}
|
||||
file = root.openNextFile();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
} // namespace emsesp
|
||||
|
||||
#endif
|
||||
|
||||
@@ -80,7 +80,6 @@ class Test {
|
||||
static void uart_telegram_withCRC(const char * rx_data);
|
||||
static void add_device(uint8_t device_id, uint8_t product_id);
|
||||
static void refresh();
|
||||
static void listDir(fs::FS & fs, const char * dirname, uint8_t levels);
|
||||
};
|
||||
|
||||
} // namespace emsesp
|
||||
|
||||
@@ -149,8 +149,10 @@ uint8_t EMSuart::transmit(const uint8_t * buf, const uint8_t len) {
|
||||
return EMS_TX_STATUS_OK;
|
||||
}
|
||||
|
||||
auto tx_mode = tx_mode_ != EMS_TXMODE_AUTO ? tx_mode_ : EMSbus::is_ht3() ? EMS_TXMODE_HT3 : EMSbus::is_ems2() ? EMS_TXMODE_EMSPLUS : EMS_TXMODE_EMS;
|
||||
|
||||
// TXMODE is EMS+ with long delay
|
||||
if (tx_mode_ == EMS_TXMODE_EMSPLUS) {
|
||||
if (tx_mode == EMS_TXMODE_EMSPLUS) {
|
||||
for (uint8_t i = 0; i < len; i++) {
|
||||
uart_write_bytes(EMSUART_NUM, &buf[i], 1);
|
||||
delayMicroseconds(EMSUART_TX_WAIT_PLUS);
|
||||
@@ -160,7 +162,7 @@ uint8_t EMSuart::transmit(const uint8_t * buf, const uint8_t len) {
|
||||
}
|
||||
|
||||
// TXMODE is HT3 with 7 bittimes delay
|
||||
if (tx_mode_ == EMS_TXMODE_HT3) {
|
||||
if (tx_mode == EMS_TXMODE_HT3) {
|
||||
for (uint8_t i = 0; i < len; i++) {
|
||||
uart_write_bytes(EMSUART_NUM, &buf[i], 1);
|
||||
delayMicroseconds(EMSUART_TX_WAIT_HT3);
|
||||
|
||||
@@ -42,10 +42,11 @@
|
||||
|
||||
#define EMS_TXMODE_INIT 0xFF
|
||||
#define EMS_TXMODE_OFF 0
|
||||
#define EMS_TXMODE_DEFAULT 1
|
||||
#define EMS_TXMODE_EMS 1
|
||||
#define EMS_TXMODE_EMSPLUS 2
|
||||
#define EMS_TXMODE_HT3 3
|
||||
#define EMS_TXMODE_HW 4
|
||||
#define EMS_TXMODE_AUTO 5
|
||||
|
||||
// LEGACY
|
||||
#define EMSUART_TX_BIT_TIME 104 // bit time @9600 baud
|
||||
|
||||
@@ -166,7 +166,9 @@ StateUpdateResult WebCustomEntity::update(JsonObject root, WebCustomEntity & web
|
||||
bool WebCustomEntityService::command_setvalue(const char * value, const int8_t id, const char * name) {
|
||||
// don't write if there is no value, to prevent setting an empty value by mistake when parsing attributes
|
||||
if (!strlen(value)) {
|
||||
#if defined(EMSESP_DEBUG)
|
||||
EMSESP::logger().debug("can't set empty value!");
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -686,7 +688,7 @@ void WebCustomEntityService::fetch() {
|
||||
uint8_t stop = (entity.offset + len[entity.value_type]) % fetchblock;
|
||||
bool is_fetched = start < fetchblock && stop < fetchblock; // make sure the complete value is a a fetched block
|
||||
for (const auto & emsdevice : EMSESP::emsdevices) {
|
||||
if (emsdevice->is_device_id(entity.device_id) && emsdevice->is_fetch(entity.type_id)
|
||||
if (emsdevice->is_device_id(entity.device_id) && emsdevice->is_fetch(entity.type_id, entity.offset + len[entity.value_type])
|
||||
&& (is_fetched || entity.value_type == DeviceValueType::STRING)) {
|
||||
needFetch = false;
|
||||
break;
|
||||
|
||||
@@ -352,8 +352,8 @@ bool WebSchedulerService::command(const char * name, const std::string & command
|
||||
// parse json
|
||||
JsonDocument doc;
|
||||
if (deserializeJson(doc, cmd) == DeserializationError::Ok) {
|
||||
HTTPClient * http = new HTTPClient;
|
||||
std::string url = doc["url"] | "";
|
||||
HTTPClient * http = new HTTPClient;
|
||||
std::string url = doc["url"] | "";
|
||||
// for a GET with parameters replace commands with values
|
||||
// don't search the complete url, it may contain a devicename in path
|
||||
auto q = url.find_first_of('?');
|
||||
@@ -465,7 +465,9 @@ void WebSchedulerService::condition() {
|
||||
} else if (match.length() == 1 && match[0] == '0' && scheduleItem.retry_cnt == 1) {
|
||||
scheduleItem.retry_cnt = 0xFF;
|
||||
} else if (match.length() != 1) { // the match is not boolean
|
||||
#if defined(EMSESP_DEBUG)
|
||||
EMSESP::logger().debug("condition result: %s", match.c_str());
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
namespace emsesp {
|
||||
|
||||
uint8_t WebSettings::flags_ = 0;
|
||||
uint16_t WebSettings::flags_ = 0;
|
||||
|
||||
WebSettingsService::WebSettingsService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager)
|
||||
: _httpEndpoint(WebSettings::read, WebSettings::update, this, server, EMSESP_SETTINGS_SERVICE_PATH, securityManager)
|
||||
@@ -114,11 +114,11 @@ StateUpdateResult WebSettings::update(JsonObject root, WebSettings & settings) {
|
||||
reset_flags();
|
||||
|
||||
// before loading new board profile free old gpios from used list to allow remapping
|
||||
EMSESP::system_.remove_gpio(original_settings.led_gpio);
|
||||
EMSESP::system_.remove_gpio(original_settings.dallas_gpio);
|
||||
EMSESP::system_.remove_optional_gpio(original_settings.led_gpio);
|
||||
EMSESP::system_.remove_optional_gpio(original_settings.dallas_gpio);
|
||||
EMSESP::system_.remove_gpio(original_settings.pbutton_gpio);
|
||||
EMSESP::system_.remove_gpio(original_settings.rx_gpio);
|
||||
EMSESP::system_.remove_gpio(original_settings.tx_gpio);
|
||||
EMSESP::system_.remove_optional_gpio(original_settings.rx_gpio);
|
||||
EMSESP::system_.remove_optional_gpio(original_settings.tx_gpio);
|
||||
|
||||
// see if the user has changed the board profile
|
||||
// this will set: led_gpio, dallas_gpio, rx_gpio, tx_gpio, pbutton_gpio, phy_type, eth_power, eth_phy_addr, eth_clock_mode, led_type
|
||||
@@ -243,13 +243,13 @@ StateUpdateResult WebSettings::update(JsonObject root, WebSettings & settings) {
|
||||
|
||||
// Modbus settings
|
||||
settings.modbus_enabled = root["modbus_enabled"] | EMSESP_DEFAULT_MODBUS_ENABLED;
|
||||
check_flag(original_settings.modbus_enabled, settings.modbus_enabled, ChangeFlags::RESTART);
|
||||
check_flag(original_settings.modbus_enabled, settings.modbus_enabled, ChangeFlags::MODBUS);
|
||||
settings.modbus_port = root["modbus_port"] | EMSESP_DEFAULT_MODBUS_PORT;
|
||||
check_flag(original_settings.modbus_port, settings.modbus_port, ChangeFlags::RESTART);
|
||||
check_flag(original_settings.modbus_port, settings.modbus_port, ChangeFlags::MODBUS);
|
||||
settings.modbus_max_clients = root["modbus_max_clients"] | EMSESP_DEFAULT_MODBUS_MAX_CLIENTS;
|
||||
check_flag(original_settings.modbus_max_clients, settings.modbus_max_clients, ChangeFlags::RESTART);
|
||||
check_flag(original_settings.modbus_max_clients, settings.modbus_max_clients, ChangeFlags::MODBUS);
|
||||
settings.modbus_timeout = root["modbus_timeout"] | EMSESP_DEFAULT_MODBUS_TIMEOUT;
|
||||
check_flag(original_settings.modbus_timeout, settings.modbus_timeout, ChangeFlags::RESTART);
|
||||
check_flag(original_settings.modbus_timeout, settings.modbus_timeout, ChangeFlags::MODBUS);
|
||||
|
||||
//
|
||||
// these may need mqtt restart to rebuild HA discovery topics
|
||||
@@ -372,7 +372,11 @@ void WebSettingsService::onUpdate() {
|
||||
Mqtt::reset_mqtt(); // reload MQTT, init HA etc
|
||||
}
|
||||
|
||||
if (WebSettings::has_flags(WebSettings::ChangeFlags::MODBUS)) {
|
||||
EMSESP::system_.modbus_init();
|
||||
}
|
||||
WebSettings::reset_flags();
|
||||
EMSESP::system_.reset_unused_gpios();
|
||||
}
|
||||
|
||||
void WebSettingsService::begin() {
|
||||
@@ -523,7 +527,7 @@ void WebSettings::set_board_profile(WebSettings & settings) {
|
||||
}
|
||||
|
||||
// returns true if the value was changed
|
||||
bool WebSettings::check_flag(int prev_v, int new_v, uint8_t flag) {
|
||||
bool WebSettings::check_flag(int prev_v, int new_v, uint16_t flag) {
|
||||
if (prev_v != new_v) {
|
||||
add_flags(flag);
|
||||
#if defined(EMSESP_DEBUG)
|
||||
@@ -534,11 +538,11 @@ bool WebSettings::check_flag(int prev_v, int new_v, uint8_t flag) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void WebSettings::add_flags(uint8_t flags) {
|
||||
void WebSettings::add_flags(uint16_t flags) {
|
||||
flags_ |= flags;
|
||||
}
|
||||
|
||||
bool WebSettings::has_flags(uint8_t flags) {
|
||||
bool WebSettings::has_flags(uint16_t flags) {
|
||||
return (flags_ & flags) == flags;
|
||||
}
|
||||
|
||||
@@ -546,7 +550,7 @@ void WebSettings::reset_flags() {
|
||||
flags_ = ChangeFlags::NONE;
|
||||
}
|
||||
|
||||
uint8_t WebSettings::get_flags() {
|
||||
uint16_t WebSettings::get_flags() {
|
||||
return flags_;
|
||||
}
|
||||
|
||||
|
||||
@@ -88,7 +88,7 @@ class WebSettings {
|
||||
static void read(WebSettings & settings, JsonObject root);
|
||||
static StateUpdateResult update(JsonObject root, WebSettings & settings);
|
||||
|
||||
enum ChangeFlags : uint8_t {
|
||||
enum ChangeFlags : uint16_t {
|
||||
NONE = 0,
|
||||
UART = (1 << 0), // 1 - uart
|
||||
SYSLOG = (1 << 1), // 2 - syslog
|
||||
@@ -98,19 +98,20 @@ class WebSettings {
|
||||
LED = (1 << 5), // 32 - led
|
||||
BUTTON = (1 << 6), // 64 - button
|
||||
MQTT = (1 << 7), // 128 - mqtt
|
||||
RESTART = 0xFF // 255 - restart request (all changes)
|
||||
MODBUS = (1 << 8), // 256 - modbus
|
||||
RESTART = 0xFFFF // restart request (all changes)
|
||||
};
|
||||
|
||||
static bool check_flag(int prev_v, int new_v, uint8_t flag);
|
||||
static void add_flags(uint8_t flags);
|
||||
static bool has_flags(uint8_t flags);
|
||||
static void reset_flags();
|
||||
static uint8_t get_flags();
|
||||
static bool check_flag(int prev_v, int new_v, uint16_t flag);
|
||||
static void add_flags(uint16_t flags);
|
||||
static bool has_flags(uint16_t flags);
|
||||
static void reset_flags();
|
||||
static uint16_t get_flags();
|
||||
|
||||
private:
|
||||
static void set_board_profile(WebSettings & settings);
|
||||
|
||||
static uint8_t flags_;
|
||||
static uint16_t flags_;
|
||||
};
|
||||
|
||||
class WebSettingsService : public StatefulService<WebSettings> {
|
||||
|
||||
@@ -296,10 +296,6 @@ uint8_t WebStatusService::upgradeImportantMessages(std::string & version) {
|
||||
|
||||
version::EMSESP_Version current_version(current_version_s); // get current version
|
||||
|
||||
if (latest_version > current_version && current_version.minor() < latest_version.minor()) {
|
||||
return 0; // if it's just a minor version upgrade return 0
|
||||
}
|
||||
|
||||
if ((current_version.major() <= 3 && current_version.minor() <= 8) && (latest_version.major() == 3 && latest_version.minor() == 9)) {
|
||||
return 1; // if moving from below 3.8.x to 3.9.x return 1
|
||||
}
|
||||
@@ -308,6 +304,10 @@ uint8_t WebStatusService::upgradeImportantMessages(std::string & version) {
|
||||
return 2; // if it's a major version upgrade return 2
|
||||
}
|
||||
|
||||
if (latest_version > current_version && current_version.minor() < latest_version.minor()) {
|
||||
return 0; // if it's just a minor version upgrade return 0
|
||||
}
|
||||
|
||||
return 0; // if it's not a valid version upgrade return 0
|
||||
}
|
||||
|
||||
|
||||
@@ -132,7 +132,7 @@ void uart_telegram(const char * rx_data) {
|
||||
|
||||
// add an EMS device and register it
|
||||
void add_device(uint8_t device_id, uint8_t product_id) {
|
||||
uart_telegram({device_id, 0x0B, EMSdevice::EMS_TYPE_VERSION, 0, product_id, 1, 0});
|
||||
uart_telegram({device_id, 0x49, EMSdevice::EMS_TYPE_VERSION, 0, product_id, 1, 0});
|
||||
}
|
||||
|
||||
// add our EMS test devices
|
||||
@@ -143,14 +143,14 @@ void add_devices() {
|
||||
add_device(0x08, 123); // Nefit Trendline
|
||||
|
||||
// UBAuptime
|
||||
uart_telegram({0x08, 0x0B, 0x14, 00, 0x3C, 0x1F, 0xAC, 0x70});
|
||||
uart_telegram({0x08, 0x49, 0x14, 00, 0x3C, 0x1F, 0xAC, 0x70});
|
||||
|
||||
// Boiler -> Me, UBAMonitorFast(0x18), telegram: 08 00 18 00 00 02 5A 73 3D 0A 10 65 40 02 1A 80 00 01 E1 01 76 0E 3D 48 00 C9 44 02 00 (#data=25)
|
||||
uart_telegram({0x08, 0x00, 0x18, 0x00, 0x00, 0x02, 0x5A, 0x73, 0x3D, 0x0A, 0x10, 0x65, 0x40, 0x02, 0x1A,
|
||||
0x80, 0x00, 0x01, 0xE1, 0x01, 0x76, 0x0E, 0x3D, 0x48, 0x00, 0xC9, 0x44, 0x02, 0x00});
|
||||
|
||||
// Boiler -> Me, UBAParameterWW(0x33), telegram: 08 0B 33 00 08 FF 34 FB 00 28 00 00 46 00 FF FF 00 (#data=13)
|
||||
uart_telegram({0x08, 0x0B, 0x33, 0x00, 0x08, 0xFF, 0x34, 0xFB, 0x00, 0x28, 0x00, 0x00, 0x46, 0x00, 0xFF, 0xFF, 0x00});
|
||||
// Boiler -> Me, UBAParameterWW(0x33), telegram: 08 49 33 00 08 FF 34 FB 00 28 00 00 46 00 FF FF 00 (#data=13)
|
||||
uart_telegram({0x08, 0x49, 0x33, 0x00, 0x08, 0xFF, 0x34, 0xFB, 0x00, 0x28, 0x00, 0x00, 0x46, 0x00, 0xFF, 0xFF, 0x00});
|
||||
|
||||
//
|
||||
// thermostat
|
||||
|
||||
@@ -228,7 +228,7 @@ void test_23() {
|
||||
"\"temperatureSensorReads\":0,\"temperatureSensorFails\":0},\"analog\":{\"enabled\":true,\"analogSensors\":5,\"analogSensorReads\":0,"
|
||||
"\"analogSensorFails\":0},\"api\":{\"APICalls\":0,\"APIFails\":0},\"bus\":{\"busStatus\":\"connected\",\"busProtocol\":\"Buderus\","
|
||||
"\"busTelegramsReceived\":8,\"busReads\":0,\"busWrites\":0,\"busIncompleteTelegrams\":0,\"busReadsFailed\":0,\"busWritesFailed\":0,"
|
||||
"\"busRxLineQuality\":100,\"busTxLineQuality\":100},\"settings\":{\"boardProfile\":\"S32\",\"locale\":\"en\",\"txMode\":1,\"emsBusID\":11,"
|
||||
"\"busRxLineQuality\":100,\"busTxLineQuality\":100},\"settings\":{\"boardProfile\":\"S32\",\"locale\":\"en\",\"txMode\":5,\"emsBusID\":73,"
|
||||
"\"showerTimer\":false,\"showerMinDuration\":180,\"showerAlert\":false,\"hideLed\":false,\"noTokenApi\":false,\"readonlyMode\":false,\"fahrenheit\":"
|
||||
"false,\"dallasParasite\":false,\"boolFormat\":1,\"boolDashboard\":1,\"enumFormat\":1,\"analogEnabled\":true,\"telnetEnabled\":true,"
|
||||
"\"maxWebLogBuffer\":25,\"modbusEnabled\":false,\"forceHeatingOff\":false,\"developerMode\":false},\"devices\":[{\"type\":\"boiler\",\"name\":\"My "
|
||||
@@ -259,7 +259,7 @@ void test_24() {
|
||||
"\"temperatureSensorReads\":0,\"temperatureSensorFails\":0},\"analog\":{\"enabled\":true,\"analogSensors\":5,\"analogSensorReads\":0,"
|
||||
"\"analogSensorFails\":0},\"api\":{\"APICalls\":0,\"APIFails\":0},\"bus\":{\"busStatus\":\"connected\",\"busProtocol\":\"Buderus\","
|
||||
"\"busTelegramsReceived\":8,\"busReads\":0,\"busWrites\":0,\"busIncompleteTelegrams\":0,\"busReadsFailed\":0,\"busWritesFailed\":0,"
|
||||
"\"busRxLineQuality\":100,\"busTxLineQuality\":100},\"settings\":{\"boardProfile\":\"S32\",\"locale\":\"en\",\"txMode\":1,\"emsBusID\":11,"
|
||||
"\"busRxLineQuality\":100,\"busTxLineQuality\":100},\"settings\":{\"boardProfile\":\"S32\",\"locale\":\"en\",\"txMode\":5,\"emsBusID\":73,"
|
||||
"\"showerTimer\":false,\"showerMinDuration\":180,\"showerAlert\":false,\"hideLed\":false,\"noTokenApi\":false,\"readonlyMode\":false,\"fahrenheit\":"
|
||||
"false,\"dallasParasite\":false,\"boolFormat\":1,\"boolDashboard\":1,\"enumFormat\":1,\"analogEnabled\":true,\"telnetEnabled\":true,"
|
||||
"\"maxWebLogBuffer\":25,\"modbusEnabled\":false,\"forceHeatingOff\":false,\"developerMode\":false},\"devices\":[{\"type\":\"boiler\",\"name\":\"My "
|
||||
@@ -330,8 +330,8 @@ void test_25() {
|
||||
"gauge\\nemsesp_bus_buswritesfailed 0\\n# HELP emsesp_bus_busrxlinequality busRxLineQuality\\n# TYPE emsesp_bus_busrxlinequality "
|
||||
"gauge\\nemsesp_bus_busrxlinequality 100\\n# HELP emsesp_bus_bustxlinequality busTxLineQuality\\n# TYPE emsesp_bus_bustxlinequality "
|
||||
"gauge\\nemsesp_bus_bustxlinequality 100\\n# HELP emsesp_bus_info info\\n# TYPE emsesp_bus_info gauge\\nemsesp_bus_info{busstatus=\\\"connected\\\", "
|
||||
"busprotocol=\\\"Buderus\\\"} 1\\n# HELP emsesp_settings_txmode txMode\\n# TYPE emsesp_settings_txmode gauge\\nemsesp_settings_txmode 1\\n# HELP "
|
||||
"emsesp_settings_emsbusid emsBusID\\n# TYPE emsesp_settings_emsbusid gauge\\nemsesp_settings_emsbusid 11\\n# HELP emsesp_settings_showertimer "
|
||||
"busprotocol=\\\"Buderus\\\"} 1\\n# HELP emsesp_settings_txmode txMode\\n# TYPE emsesp_settings_txmode gauge\\nemsesp_settings_txmode 5\\n# HELP "
|
||||
"emsesp_settings_emsbusid emsBusID\\n# TYPE emsesp_settings_emsbusid gauge\\nemsesp_settings_emsbusid 73\\n# HELP emsesp_settings_showertimer "
|
||||
"showerTimer\\n# TYPE emsesp_settings_showertimer gauge\\nemsesp_settings_showertimer 0\\n# HELP emsesp_settings_showerminduration "
|
||||
"showerMinDuration\\n# TYPE emsesp_settings_showerminduration gauge\\nemsesp_settings_showerminduration 180\\n# HELP emsesp_settings_showeralert "
|
||||
"showerAlert\\n# TYPE emsesp_settings_showeralert gauge\\nemsesp_settings_showeralert 0\\n# HELP emsesp_settings_hideled hideLed\\n# TYPE "
|
||||
@@ -588,4 +588,4 @@ void run_tests() {
|
||||
RUN_TEST(test_57);
|
||||
}
|
||||
|
||||
// ---------- END - CUT HERE ----------
|
||||
// ---------- END - CUT HERE ----------
|
||||
Reference in New Issue
Block a user