36 Commits

Author SHA1 Message Date
Proddy
f3858546de Merge branch 'origin/dev' 2023-02-06 21:58:27 +01:00
Proddy
d0ac0b7804 update with version on dev 2022-10-30 16:58:37 +01:00
Proddy
d8284ec09f Merge pull request #705 from MichaelDvP/main
v3.4.4 Fix for new installations with filesystem not initializing
2022-10-29 10:46:41 +02:00
MichaelDvP
6e982acde8 v3.4.4 Fix for new installations with filesystem not initializing 2022-10-28 10:50:51 +02:00
Proddy
8c94ce99b2 quick fix for filesystem initialization 2022-10-08 09:23:00 +02:00
proddy
fc057d18c9 Merge remote-tracking branch 'origin/dev' 2022-09-18 14:33:23 +02:00
Proddy
18e9b99413 Merge remote-tracking branch 'origin/dev' into main 2022-05-29 16:16:38 +02:00
Proddy
a47e0e8266 update for 3.4.0 2022-05-23 21:20:45 +02:00
Proddy
f412ddc716 Merge remote-tracking branch 'origin/dev' into main 2022-05-23 21:20:36 +02:00
proddy
29110e96e5 Merge remote-tracking branch 'origin/dev' 2022-01-20 10:51:40 +01:00
proddy
b65866217a 3.4.0 2021-11-28 23:03:28 +01:00
proddy
611e3b1243 Merge remote-tracking branch 'origin/dev' 2021-11-28 23:03:15 +01:00
proddy
2ca0a0c634 v3.2.1 merged from dev 2021-08-08 14:46:14 +02:00
proddy
7eb1f061b7 Merge remote-tracking branch 'origin/dev' for 3.2.0 release 2021-08-06 12:06:08 +02:00
proddy
50459a23fe force v16 of nodejs 2021-06-26 11:13:07 +02:00
proddy
5bf53c3389 3.1.1 2021-06-26 11:03:03 +02:00
proddy
4b7aa95be3 Merge remote-tracking branch 'origin/dev' 2021-06-26 11:02:55 +02:00
Proddy
70943f5758 Update pre_release.yml 2021-05-16 15:52:09 +02:00
Proddy
3bc280b817 Delete check_code.yml 2021-05-16 15:51:56 +02:00
Proddy
62b15a5319 Update pre_release.yml 2021-05-16 15:35:06 +02:00
Proddy
8dd18802d6 Update tagged_release.yml 2021-05-16 15:34:45 +02:00
proddy
57a516a83a updated README and images 2021-05-09 15:13:16 +02:00
proddy
a57fdaa4b3 Merge remote-tracking branch 'origin/dev' into main 2021-05-04 12:21:51 +02:00
proddy
4841e42286 Merge remote-tracking branch 'origin/dev' into main 2021-03-30 16:35:18 +02:00
proddy
8c2d2b06ed cleaned up old changelog 2021-03-18 20:59:09 +01:00
proddy
38c8b1b7f0 3.0.0 2021-03-18 20:58:21 +01:00
proddy
6fb5933a02 Merge remote-tracking branch 'origin/dev' into main 2021-03-18 20:58:12 +01:00
proddy
c0944433be remove workspace.code-workspace 2021-03-16 17:41:42 +01:00
Proddy
478e6362c9 Merge pull request #27 from FauthD:main
Add global names to Dallas sensors to avoid ugly <unknown> and other …
2021-03-16 17:39:00 +01:00
fauthd
4d6354db78 Add stuff to gitignore, add vscode workspace 2021-03-16 16:47:09 +01:00
fauthd
beab0f0c77 Add global names to Dallas sensors to avoid ugly <unknown> and other issues in HA 2021-03-16 16:00:23 +01:00
Proddy
c17749bd22 Update README.md 2021-03-14 23:43:33 +01:00
proddy
2bad769c5c build: include assets 2021-03-14 21:20:51 +01:00
proddy
8ad89ca64b move repo 2021-03-14 21:05:15 +01:00
proddy
9244d8daec Semantic Commit Messages 2021-03-14 18:10:57 +01:00
proddy
02d01334b2 update new build 2021-03-14 17:37:18 +01:00
49 changed files with 748 additions and 14172 deletions

View File

@@ -1,50 +1,35 @@
--- ---
name: Problem Report name: Bug report
about: Create a Report to help us improve about: Create a report to help us improve
title: ''
labels: bug
assignees: ''
--- ---
<!-- Thanks for reporting a problem for this project. READ THIS FIRST: *Before creating a new issue please check that you have:*
Please DO NOT OPEN AN ISSUE if your EMS-ESP version is not the latest from the dev branch, please update your device before submitting your issue. Your problem might already be solved. The latest precompiled binaries of EMS-ESP can be downloaded from https://github.com/emsesp/EMS-ESP32/releases/tag/latest * *searched the existing [issues](https://github.com/emsesp/EMS-ESP32/issues) (both open and closed)*
* *searched the [documentation help section](https://emsesp.github.io/docs)*
Please take a few minutes to complete the requested information below. *Completing this template will help developers and contributors to address the issue. Try to be as specific and extensive as possible. If the information provided is not enough the issue will likely be closed.*
--> *You can now remove this line and the above ones. Text in italic is meant to be replaced by your own words. If any of the sections below are not relevant to the issue (for instance, the screenshots) then you can delete them.*
### PROBLEM DESCRIPTION **Bug description**
*A clear and concise description of what the bug is. Mention which EMS-ESP version you're using.*
_A clear and concise description of what the problem is._ **Steps to reproduce**
*Steps to reproduce the behavior.*
### REQUESTED INFORMATION **Expected behavior**
*A clear and concise description of what you expected to happen.*
_Make sure your have performed every step and checked the applicable boxes before submitting your issue. Thank you!_ **Screenshots**
*If applicable, add screenshots to help explain your problem.*
- [ ] Searched the problem in [issues](https://github.com/emsesp/EMS-ESP32/issues) **Device information**
- [ ] Searched the problem in [discussions](https://github.com/emsesp/EMS-ESP32/discussions) *Copy-paste here the information as it is outputted by the device. You can get this information by from http://ems-esp.local/api/system*
- [ ] Searched the problem in the [docs](https://emsesp.github.io/docs/Troubleshooting/)
- [ ] Searched the problem in the [chat](https://discord.gg/3J3GgnzpyT)
- [ ] Provide the output of http://ems-esp.local/api/system :
```lua **Additional context**
System information output here: *Add any other context about the problem here.*
```
### TO REPRODUCE
_Steps to reproduce the behavior:_
### EXPECTED BEHAVIOUR
_A clear and concise description of what you expected to happen._
### SCREENSHOTS
_If applicable, add screenshots to help explain your problem._
### ADDITIONAL CONTEXT
_Add any other context about the problem here._
**(Please, remember to close the issue when the problem has been addressed)**

View File

@@ -1,11 +0,0 @@
blank_issues_enabled: false
contact_links:
- name: EMS-ESP Docs
url: https://emsesp.github.io/docs/
about: All the information related to EMS-ESP.
- name: EMS-ESP Discussions and Support
url: https://github.com/emsesp/EMS-ESP32/discussions
about: EMS-ESP usage Questions, Feature Requests and Projects.
- name: EMS-ESP Users Chat
url: https://discord.gg/3J3GgnzpyT
about: Chat for feedback, questions and troubleshooting.

View File

@@ -0,0 +1,26 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: enhancement
assignees: ''
---
*Before creating a new feature request please check that you have searched the existing [issues](https://github.com/emsesp/EMS-ESP32/issues) (both open and closed)*
*Completing this template will help developers and contributors evaluating the feature. If the information provided is not enough the issue will likely be closed.*
*You can now remove this line and the above ones. Text in italic is meant to be replaced by your own words. If any of the sections below are not relevant to the request then you can delete them.*
**Is your feature request related to a problem? Please describe.**
*A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]*
**Describe the solution you'd like**
*A clear and concise description of what you want to happen.*
**Describe alternatives you've considered**
*A clear and concise description of any alternative solutions or features you've considered.*
**Additional context**
*Add any other context or screenshots about the feature request here.*

View File

@@ -0,0 +1,29 @@
---
name: Questions & Troubleshooting
about: Anything not a bug or feature request
title: ''
labels: question
assignees: ''
---
*Before creating a new issue please check that you have:*
* *searched the existing [issues](https://github.com/emsesp/EMS-ESP32/issues) (both open and closed)*
* *searched the [documentation help section](https://emsesp.github.io/docs)*
*Completing this template will help developers and contributors help you. Try to be as specific and extensive as possible. If the information provided is not enough the issue will likely be closed.*
*You can now remove this line and the above ones. Text in italic is meant to be replaced by your own words. If any of the sections below are not relevant to the issue (for instance, the screenshots) then you can delete them.*
**Question**
*A clear and concise description of what the problem/doubt is.*
**Screenshots**
*If applicable, add screenshots to help explain your problem.*
**Device information**
*Copy-paste here the information as it is outputted by the device. You can get this information from http://ems-esp.local/api/system*
**Additional context**
*Add any other context about the problem here.*

2
.gitignore vendored
View File

@@ -1,5 +1,7 @@
# vscode # vscode
.vscode .vscode
.directory
workspace.code-workspace
# build # build
build/ build/

View File

@@ -5,7 +5,7 @@ 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/), 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). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
# [3.5.0] February 6 2023 # [3.5.0]
## **IMPORTANT! BREAKING CHANGES** ## **IMPORTANT! BREAKING CHANGES**
@@ -67,7 +67,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- HA duration class for time entities [[#822](https://github.com/emsesp/EMS-ESP32/issues/822) - HA duration class for time entities [[#822](https://github.com/emsesp/EMS-ESP32/issues/822)
- AM200 alternative heatsource as class heatsource [[#857](https://github.com/emsesp/EMS-ESP32/issues/857) - AM200 alternative heatsource as class heatsource [[#857](https://github.com/emsesp/EMS-ESP32/issues/857)
# [3.4.2] September 18 2022 # [3.4.4]
## Fixed
- Fix for new installations with filesystem not initializing
# [3.4.3]
## Fixed
- Fix for new installations with filesystem not initializing
# [3.4.2]
## Added ## Added
@@ -103,10 +115,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## Changed ## Changed
- Controller data in web-ui only for IVT [#522](https://github.com/emsesp/EMS-ESP32/issues/522)
- Rename hidden `climate` to a more explaining name [#523](https://github.com/emsesp/EMS-ESP32/issues/523)
- Minor changes to the Customizations web page [#527](https://github.com/emsesp/EMS-ESP32/pull/527)
# [3.4.0] May 23 2022 # [3.4.0] May 23 2022
## Added ## Added

View File

@@ -1,20 +0,0 @@
# Changelog
# [3.5.1]
## Added
- Detect old Tado thermostat, device-id 0x19, no entities
- Some more HM200 entities [#500](https://github.com/emsesp/EMS-ESP32/issues/500)
- Add entity to force heating off (for systems without thermostat) [#951](https://github.com/emsesp/EMS-ESP32/issues/951)
## Fixed
- HA-discovery for analog sensor commands [#1035](https://github.com/emsesp/EMS-ESP32/issues/1035)
## Changed
- Use byte 0 for detection RC30 active heatingcircuit [#786](https://github.com/emsesp/EMS-ESP32/issues/786)
- Write repeated selflowtemp if tx-queue is empty without verify [#954](https://github.com/emsesp/EMS-ESP32/issues/954)
- HA discovery recreate after disconnect by device [#1067](https://github.com/emsesp/EMS-ESP32/issues/1067)
- File upload: check flash size (overflow) instead of filesize

View File

@@ -1,5 +1,5 @@
{ {
"adapter": "react", "adapter": "react",
"baseLocale": "pl", "baseLocale": "pl",
"$schema": "https://unpkg.com/typesafe-i18n@5.24.1/schema/typesafe-i18n.json" "$schema": "https://unpkg.com/typesafe-i18n@5.24.0/schema/typesafe-i18n.json"
} }

14188
interface/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -4,19 +4,19 @@
"private": true, "private": true,
"proxy": "http://localhost:3080", "proxy": "http://localhost:3080",
"dependencies": { "dependencies": {
"@emotion/react": "^11.10.6", "@emotion/react": "^11.10.5",
"@emotion/styled": "^11.10.6", "@emotion/styled": "^11.10.5",
"@msgpack/msgpack": "^2.8.0", "@msgpack/msgpack": "^2.8.0",
"@mui/icons-material": "^5.11.9", "@mui/icons-material": "^5.11.0",
"@mui/material": "^5.11.10", "@mui/material": "^5.11.7",
"@table-library/react-table-library": "4.0.26", "@table-library/react-table-library": "4.0.24",
"@types/lodash": "^4.14.191", "@types/lodash": "^4.14.191",
"@types/node": "^18.14.0", "@types/node": "^18.11.19",
"@types/react": "^18.0.28", "@types/react": "^18.0.27",
"@types/react-dom": "^18.0.11", "@types/react-dom": "^18.0.10",
"@types/react-router-dom": "^5.3.3", "@types/react-router-dom": "^5.3.3",
"async-validator": "^4.2.5", "async-validator": "^4.2.5",
"axios": "^1.3.4", "axios": "^1.3.2",
"jwt-decode": "^3.1.2", "jwt-decode": "^3.1.2",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"notistack": "^2.0.8", "notistack": "^2.0.8",
@@ -28,7 +28,7 @@
"react-router-dom": "^6.8.1", "react-router-dom": "^6.8.1",
"react-scripts": "5.0.1", "react-scripts": "5.0.1",
"sockette": "^2.0.6", "sockette": "^2.0.6",
"typesafe-i18n": "^5.24.1", "typesafe-i18n": "^5.24.0",
"typescript": "^4.9.5" "typescript": "^4.9.5"
}, },
"scripts": { "scripts": {

View File

@@ -73,6 +73,7 @@ const SystemLog: FC = () => {
}); });
const [errorMessage, setErrorMessage] = useState<string>(); const [errorMessage, setErrorMessage] = useState<string>();
const [reconnectTimeout, setReconnectTimeout] = useState<NodeJS.Timeout>();
const [logEntries, setLogEntries] = useState<LogEntries>({ events: [] }); const [logEntries, setLogEntries] = useState<LogEntries>({ events: [] });
const [lastIndex, setLastIndex] = useState<number>(0); const [lastIndex, setLastIndex] = useState<number>(0);
@@ -161,7 +162,7 @@ const SystemLog: FC = () => {
const fetchLog = useCallback(async () => { const fetchLog = useCallback(async () => {
try { try {
await SystemApi.readLogEntries(); setLogEntries((await SystemApi.readLogEntries()).data);
} catch (error) { } catch (error) {
setErrorMessage(extractErrorMessage(error, LL.PROBLEM_LOADING())); setErrorMessage(extractErrorMessage(error, LL.PROBLEM_LOADING()));
} }
@@ -175,14 +176,20 @@ const SystemLog: FC = () => {
const es = new EventSource(addAccessTokenParameter(LOG_EVENTSOURCE_URL)); const es = new EventSource(addAccessTokenParameter(LOG_EVENTSOURCE_URL));
es.onmessage = onMessage; es.onmessage = onMessage;
es.onerror = () => { es.onerror = () => {
es.close(); if (reconnectTimeout) {
reloadPage(); es.close();
setReconnectTimeout(setTimeout(reloadPage, 1000));
}
}; };
return () => { return () => {
es.close(); es.close();
if (reconnectTimeout) {
clearTimeout(reconnectTimeout);
}
}; };
// eslint-disable-next-line // eslint-disable-next-line
}, []); }, [reconnectTimeout]);
const content = () => { const content = () => {
if (!data) { if (!data) {

View File

@@ -127,7 +127,6 @@ const de: Translation = {
BYPASS_TOKEN: 'Zugriffstoken-Autorisierung bei API-Aufrufen umgehen', BYPASS_TOKEN: 'Zugriffstoken-Autorisierung bei API-Aufrufen umgehen',
READONLY: 'Nur-Lese-Modus aktivieren (blockiert alle ausgehenden EMS Tx Write-Befehle)', READONLY: 'Nur-Lese-Modus aktivieren (blockiert alle ausgehenden EMS Tx Write-Befehle)',
UNDERCLOCK_CPU: 'CPU-Geschwindigkeit untertakten', UNDERCLOCK_CPU: 'CPU-Geschwindigkeit untertakten',
HEATINGOFF: 'Boiler Start mit Heizung ausgeschaltet',
ENABLE_SHOWER_TIMER: 'Duschtimer aktivieren', ENABLE_SHOWER_TIMER: 'Duschtimer aktivieren',
ENABLE_SHOWER_ALERT: 'Duschalarm aktivieren', ENABLE_SHOWER_ALERT: 'Duschalarm aktivieren',
TRIGGER_TIME: 'Auslösezeit', TRIGGER_TIME: 'Auslösezeit',

View File

@@ -127,7 +127,6 @@ const en: Translation = {
BYPASS_TOKEN: 'Bypass Access Token authorization on API calls', BYPASS_TOKEN: 'Bypass Access Token authorization on API calls',
READONLY: 'Enable read-only mode (blocks all outgoing EMS Tx Write commands)', READONLY: 'Enable read-only mode (blocks all outgoing EMS Tx Write commands)',
UNDERCLOCK_CPU: 'Underclock CPU speed', UNDERCLOCK_CPU: 'Underclock CPU speed',
HEATINGOFF: 'Start boiler with forced heating off',
ENABLE_SHOWER_TIMER: 'Enable Shower Timer', ENABLE_SHOWER_TIMER: 'Enable Shower Timer',
ENABLE_SHOWER_ALERT: 'Enable Shower Alert', ENABLE_SHOWER_ALERT: 'Enable Shower Alert',
TRIGGER_TIME: 'Trigger Time', TRIGGER_TIME: 'Trigger Time',

View File

@@ -127,7 +127,6 @@ const fr: Translation = {
BYPASS_TOKEN: 'Contourner l\'autorisation du jeton d\'accès sur les appels API', BYPASS_TOKEN: 'Contourner l\'autorisation du jeton d\'accès sur les appels API',
READONLY: 'Activer le mode lecture uniquement (bloque toutes les commandes EMS sortantes en écriture Tx)', READONLY: 'Activer le mode lecture uniquement (bloque toutes les commandes EMS sortantes en écriture Tx)',
UNDERCLOCK_CPU: 'Underclock du CPU', UNDERCLOCK_CPU: 'Underclock du CPU',
HEATINGOFF: 'Start boiler with forced heating off',
ENABLE_SHOWER_TIMER: 'Activer la minuterie de la douche', ENABLE_SHOWER_TIMER: 'Activer la minuterie de la douche',
ENABLE_SHOWER_ALERT: 'Activer les alertes de durée de douche', ENABLE_SHOWER_ALERT: 'Activer les alertes de durée de douche',
TRIGGER_TIME: 'Durée avant déclenchement', TRIGGER_TIME: 'Durée avant déclenchement',

View File

@@ -127,7 +127,6 @@ const nl: Translation = {
BYPASS_TOKEN: 'API Access Token authenticatie uitschakelen', BYPASS_TOKEN: 'API Access Token authenticatie uitschakelen',
READONLY: 'Activeer read-only modus (blokkeert alle outgaande EMS Tx schrijf commandos)', READONLY: 'Activeer read-only modus (blokkeert alle outgaande EMS Tx schrijf commandos)',
UNDERCLOCK_CPU: 'Underclock CPU snelheid', UNDERCLOCK_CPU: 'Underclock CPU snelheid',
HEATINGOFF: 'Start boiler with forced heating off',
ENABLE_SHOWER_TIMER: 'Activeer Douche Timer (tijdmeting)', ENABLE_SHOWER_TIMER: 'Activeer Douche Timer (tijdmeting)',
ENABLE_SHOWER_ALERT: 'Activeer Douchemelding', ENABLE_SHOWER_ALERT: 'Activeer Douchemelding',
TRIGGER_TIME: 'Trigger tijd', TRIGGER_TIME: 'Trigger tijd',

View File

@@ -127,7 +127,6 @@ const no: Translation = {
BYPASS_TOKEN: 'Utelat Aksess Token authorisering av API kall', BYPASS_TOKEN: 'Utelat Aksess Token authorisering av API kall',
READONLY: 'Aktiver read-only modus (blokker all EMS Tx Skriving)', READONLY: 'Aktiver read-only modus (blokker all EMS Tx Skriving)',
UNDERCLOCK_CPU: 'Underklokking av prosessorhastighet', UNDERCLOCK_CPU: 'Underklokking av prosessorhastighet',
HEATINGOFF: 'Start boiler with forced heating off',
ENABLE_SHOWER_TIMER: 'Aktiver Dusjtimer', ENABLE_SHOWER_TIMER: 'Aktiver Dusjtimer',
ENABLE_SHOWER_ALERT: 'Aktiver Dusj-varsling', ENABLE_SHOWER_ALERT: 'Aktiver Dusj-varsling',
TRIGGER_TIME: 'Aktiveringstid', TRIGGER_TIME: 'Aktiveringstid',

View File

@@ -127,7 +127,6 @@ const pl: BaseTranslation = {
BYPASS_TOKEN: 'Pomiń autoryzację tokenem w wywołaniach API', BYPASS_TOKEN: 'Pomiń autoryzację tokenem w wywołaniach API',
READONLY: 'Tryb pracy "tylko do odczytu" (blokuje wszystkie komendy zapisu na magistralę EMS)', READONLY: 'Tryb pracy "tylko do odczytu" (blokuje wszystkie komendy zapisu na magistralę EMS)',
UNDERCLOCK_CPU: 'Obniż taktowanie CPU', UNDERCLOCK_CPU: 'Obniż taktowanie CPU',
HEATINGOFF: 'Start boiler with forced heating off',
ENABLE_SHOWER_TIMER: 'Aktywuj minutnik prysznica', ENABLE_SHOWER_TIMER: 'Aktywuj minutnik prysznica',
ENABLE_SHOWER_ALERT: 'Aktywuj alarm prysznica', ENABLE_SHOWER_ALERT: 'Aktywuj alarm prysznica',
TRIGGER_TIME: 'Wyzwalaj po czasie', TRIGGER_TIME: 'Wyzwalaj po czasie',
@@ -158,7 +157,7 @@ const pl: BaseTranslation = {
CUSTOMIZATIONS_HELP_3: 'zablokuj akcje zapisu', CUSTOMIZATIONS_HELP_3: 'zablokuj akcje zapisu',
CUSTOMIZATIONS_HELP_4: 'wyklucz z MQTT i API', CUSTOMIZATIONS_HELP_4: 'wyklucz z MQTT i API',
CUSTOMIZATIONS_HELP_5: 'ukryj na pulpicie', CUSTOMIZATIONS_HELP_5: 'ukryj na pulpicie',
CUSTOMIZATIONS_HELP_6: 'usuń z pamięci', CUSTOMIZATIONS_HELP_6: 'remove from memory',
SELECT_DEVICE: 'wybierz urządzenie', SELECT_DEVICE: 'wybierz urządzenie',
SET_ALL: 'Ustaw wszystko jako', SET_ALL: 'Ustaw wszystko jako',
OPTIONS: 'Opcje', OPTIONS: 'Opcje',
@@ -203,7 +202,7 @@ const pl: BaseTranslation = {
CPU_FREQ: 'Taktowanie CPU', CPU_FREQ: 'Taktowanie CPU',
HEAP: 'HEAP (wolne / maksymalny przydział)', HEAP: 'HEAP (wolne / maksymalny przydział)',
PSRAM: 'PSRAM (rozmiar / wolne)', PSRAM: 'PSRAM (rozmiar / wolne)',
FLASH: 'FLASH (rozmiar / taktowanie)', FLASH: 'Flash (rozmiar / taktowanie)',
APPSIZE: 'Aplikacja (wykorzystane / wolne)', APPSIZE: 'Aplikacja (wykorzystane / wolne)',
FILESYSTEM: 'System plików (wykorzystane / wolne)', FILESYSTEM: 'System plików (wykorzystane / wolne)',
BUFFER_SIZE: 'Maksymalna pojemność bufora (ilość wpisów)', BUFFER_SIZE: 'Maksymalna pojemność bufora (ilość wpisów)',

View File

@@ -127,7 +127,6 @@ const sv: Translation = {
BYPASS_TOKEN: 'Inaktivera Token-autensiering för API-anrop', BYPASS_TOKEN: 'Inaktivera Token-autensiering för API-anrop',
READONLY: 'Aktivera read-only (blockerar alla utgående skrivkommandon mot EMS-bussen)', READONLY: 'Aktivera read-only (blockerar alla utgående skrivkommandon mot EMS-bussen)',
UNDERCLOCK_CPU: 'Nedklocka Processorhastighet', UNDERCLOCK_CPU: 'Nedklocka Processorhastighet',
HEATINGOFF: 'Start boiler with forced heating off',
ENABLE_SHOWER_TIMER: 'Aktivera Dusch-timer', ENABLE_SHOWER_TIMER: 'Aktivera Dusch-timer',
ENABLE_SHOWER_ALERT: 'Aktivera Dusch-varning', ENABLE_SHOWER_ALERT: 'Aktivera Dusch-varning',
TRIGGER_TIME: 'Aktiveringstid', TRIGGER_TIME: 'Aktiveringstid',

View File

@@ -650,7 +650,7 @@ const DashboardData: FC = () => {
<DialogContent dividers> <DialogContent dividers>
<List dense={true}> <List dense={true}>
<ListItem> <ListItem>
<ListItemText primary={LL.TYPE()} secondary={coreData.devices[deviceDialog].tn} /> <ListItemText primary={LL.TYPE()} secondary={coreData.devices[deviceDialog].t} />
</ListItem> </ListItem>
<ListItem> <ListItem>
<ListItemText primary={LL.NAME(0)} secondary={coreData.devices[deviceDialog].n} /> <ListItemText primary={LL.NAME(0)} secondary={coreData.devices[deviceDialog].n} />

View File

@@ -408,11 +408,6 @@ const SettingsApplication: FC = () => {
label={LL.UNDERCLOCK_CPU()} label={LL.UNDERCLOCK_CPU()}
disabled={saving} disabled={saving}
/> />
<BlockFormControlLabel
control={<Checkbox checked={data.boiler_heatingoff} onChange={updateFormValue} name="boiler_heatingoff" />}
label={LL.HEATINGOFF()}
disabled={saving}
/>
<Grid container spacing={0} direction="row" justifyContent="flex-start" alignItems="flex-start"> <Grid container spacing={0} direction="row" justifyContent="flex-start" alignItems="flex-start">
<BlockFormControlLabel <BlockFormControlLabel
control={<Checkbox checked={data.shower_timer} onChange={updateFormValue} name="shower_timer" />} control={<Checkbox checked={data.shower_timer} onChange={updateFormValue} name="shower_timer" />}

View File

@@ -7,7 +7,6 @@ export interface Settings {
syslog_mark_interval: number; syslog_mark_interval: number;
syslog_host: string; syslog_host: string;
syslog_port: number; syslog_port: number;
boiler_heatingoff: boolean;
shower_timer: boolean; shower_timer: boolean;
shower_alert: boolean; shower_alert: boolean;
shower_alert_coldshot: number; shower_alert_coldshot: number;

View File

@@ -71,13 +71,13 @@ void UploadFileService::handleUpload(AsyncWebServerRequest * request, const Stri
return; return;
} }
#elif CONFIG_IDF_TARGET_ESP32S3 #elif CONFIG_IDF_TARGET_ESP32S3
if (len > 12 && (data[0] != 0xE9 || data[12] != 9)) { if (len > 12 && (data[0] != 0xE9 || data[12] != 3)) {
handleError(request, 503); // service unavailable handleError(request, 503); // service unavailable
return; return;
} }
#endif #endif
// it's firmware - initialize the ArduinoOTA updater // it's firmware - initialize the ArduinoOTA updater
if (Update.begin()) { if (Update.begin(fsize)) {
if (strlen(md5) == 32) { if (strlen(md5) == 32) {
Update.setMD5(md5); Update.setMD5(md5);
md5[0] = '\0'; md5[0] = '\0';

View File

@@ -14,7 +14,7 @@
"express": "^4.18.2", "express": "^4.18.2",
"express-sse": "^0.5.3", "express-sse": "^0.5.3",
"nodemon": "^2.0.20", "nodemon": "^2.0.20",
"ws": "^8.12.1" "ws": "^8.12.0"
} }
}, },
"node_modules/@msgpack/msgpack": { "node_modules/@msgpack/msgpack": {
@@ -1015,9 +1015,9 @@
} }
}, },
"node_modules/ws": { "node_modules/ws": {
"version": "8.12.1", "version": "8.12.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.12.1.tgz", "resolved": "https://registry.npmjs.org/ws/-/ws-8.12.0.tgz",
"integrity": "sha512-1qo+M9Ba+xNhPB+YTWUlK6M17brTut5EXbcBaMRN5pH5dFrXz7lzz1ChFSUq3bOUl8yEvSenhHmYUNJxFzdJew==", "integrity": "sha512-kU62emKIdKVeEIOIKVegvqpXMSTAMLJozpHZaJNDYqBjzlSYXQGviYwN1osDLJ9av68qHd4a2oSjd7yD4pacig==",
"engines": { "engines": {
"node": ">=10.0.0" "node": ">=10.0.0"
}, },

View File

@@ -16,6 +16,6 @@
"express": "^4.18.2", "express": "^4.18.2",
"express-sse": "^0.5.3", "express-sse": "^0.5.3",
"nodemon": "^2.0.20", "nodemon": "^2.0.20",
"ws": "^8.12.1" "ws": "^8.12.0"
} }
} }

View File

@@ -68,7 +68,7 @@ void AnalogSensor::reload() {
analog_enabled_ = true; // for local offline testing analog_enabled_ = true; // for local offline testing
#endif #endif
for (auto sensor : sensors_) { for (auto sensor : sensors_) {
remove_ha_topic(sensor.type(), sensor.gpio()); remove_ha_topic(sensor.gpio());
sensor.ha_registered = false; sensor.ha_registered = false;
} }
if (!analog_enabled_) { if (!analog_enabled_) {
@@ -333,7 +333,7 @@ bool AnalogSensor::update(uint8_t gpio, const std::string & name, double offset,
// if the sensor exists and we're using HA, delete the old HA record // if the sensor exists and we're using HA, delete the old HA record
if (found_sensor && Mqtt::ha_enabled()) { if (found_sensor && Mqtt::ha_enabled()) {
remove_ha_topic(type, gpio); // the GPIO remove_ha_topic(gpio); // the GPIO
} }
// we didn't find it, it's new, so create and store it // we didn't find it, it's new, so create and store it
@@ -384,7 +384,7 @@ void AnalogSensor::publish_sensor(const Sensor & sensor) const {
} }
// send empty config topic to remove the entry from HA // send empty config topic to remove the entry from HA
void AnalogSensor::remove_ha_topic(const int8_t type, const uint8_t gpio) const { void AnalogSensor::remove_ha_topic(const uint8_t gpio) const {
if (!Mqtt::ha_enabled()) { if (!Mqtt::ha_enabled()) {
return; return;
} }
@@ -392,21 +392,7 @@ void AnalogSensor::remove_ha_topic(const int8_t type, const uint8_t gpio) const
LOG_DEBUG("Removing HA config for analog sensor GPIO %02d", gpio); LOG_DEBUG("Removing HA config for analog sensor GPIO %02d", gpio);
#endif #endif
char topic[Mqtt::MQTT_TOPIC_MAX_SIZE]; char topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
#if CONFIG_IDF_TARGET_ESP32 snprintf(topic, sizeof(topic), "sensor/%s/analogsensor_%02d/config", Mqtt::basename().c_str(), gpio);
if (type == AnalogType::DIGITAL_OUT && gpio != 25 && gpio != 26) {
#else
if (type == AnalogType::DIGITAL_OUT)
#endif
snprintf(topic, sizeof(topic), "switch/%s/analogsensor_%02d/config", Mqtt::basename().c_str(), gpio);
} else if (type == AnalogType::DIGITAL_OUT) { // DAC
snprintf(topic, sizeof(topic), "number/%s/analogsensor_%02d/config", Mqtt::basename().c_str(), gpio);
} else if (type >= AnalogType::PWM_0) {
snprintf(topic, sizeof(topic), "number/%s/analogsensor_%02d/config", Mqtt::basename().c_str(), gpio);
} else if (type == AnalogType::DIGITAL_IN) {
snprintf(topic, sizeof(topic), "binary_sensor/%s/analogsensor_%02d/config", Mqtt::basename().c_str(), gpio);
} else {
snprintf(topic, sizeof(topic), "sensor/%s/analogsensor_%02d/config", Mqtt::basename().c_str(), gpio);
}
Mqtt::publish_ha(topic); Mqtt::publish_ha(topic);
} }
@@ -461,16 +447,13 @@ void AnalogSensor::publish_values(const bool force) {
snprintf(stat_t, sizeof(stat_t), "%s/analogsensor_data", Mqtt::base().c_str()); // use base path snprintf(stat_t, sizeof(stat_t), "%s/analogsensor_data", Mqtt::base().c_str()); // use base path
config["stat_t"] = stat_t; config["stat_t"] = stat_t;
char val_obj[50]; char str[50];
char val_cond[65];
if (Mqtt::is_nested()) { if (Mqtt::is_nested()) {
snprintf(val_obj, sizeof(val_obj), "value_json['%02d'].value", sensor.gpio()); snprintf(str, sizeof(str), "{{value_json['%02d'].value}}", sensor.gpio());
snprintf(val_cond, sizeof(val_cond), "value_json['%02d'] is defined", sensor.gpio());
} else { } else {
snprintf(val_obj, sizeof(val_obj), "value_json['%s']", sensor.name().c_str()); snprintf(str, sizeof(str), "{{value_json['%s']}", sensor.name().c_str());
snprintf(val_cond, sizeof(val_cond), "%s is defined", val_obj);
} }
config["val_tpl"] = (std::string) "{{" + val_obj + " if " + val_cond + "}}"; config["val_tpl"] = str;
char uniq_s[70]; char uniq_s[70];
if (Mqtt::entity_format() == 2) { if (Mqtt::entity_format() == 2) {
@@ -479,76 +462,22 @@ void AnalogSensor::publish_values(const bool force) {
snprintf(uniq_s, sizeof(uniq_s), "analogsensor_%02d", sensor.gpio()); snprintf(uniq_s, sizeof(uniq_s), "analogsensor_%02d", sensor.gpio());
} }
config["obj_id"] = uniq_s; config["object_id"] = uniq_s;
config["uniq_id"] = uniq_s; // same as object_id config["uniq_id"] = uniq_s; // same as object_id
char name[50]; snprintf(str, sizeof(str), "%s", sensor.name().c_str());
snprintf(name, sizeof(name), "%s", sensor.name().c_str()); config["name"] = str;
config["name"] = name;
if (sensor.uom() != DeviceValueUOM::NONE) { if (sensor.uom() != DeviceValueUOM::NONE) {
config["unit_of_meas"] = EMSdevice::uom_to_string(sensor.uom()); config["unit_of_meas"] = EMSdevice::uom_to_string(sensor.uom());
} }
char topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
// Set commands for some analog types
char command_topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
#if CONFIG_IDF_TARGET_ESP32
if (sensor.type() == AnalogType::DIGITAL_OUT && sensor.gpio() != 25 && sensor.gpio() != 26) {
#else
if (sensor.type() == AnalogType::DIGITAL_OUT)
#endif
snprintf(topic, sizeof(topic), "switch/%s/analogsensor_%02d/config", Mqtt::basename().c_str(), sensor.gpio());
snprintf(command_topic, sizeof(command_topic), "%s/analogsensor/%s", Mqtt::basename().c_str(), sensor.name().c_str());
config["cmd_t"] = command_topic;
if (EMSESP::system_.bool_format() == BOOL_FORMAT_TRUEFALSE) {
config["pl_on"] = true;
config["pl_off"] = false;
} else if (EMSESP::system_.bool_format() == BOOL_FORMAT_10) {
config["pl_on"] = 1;
config["pl_off"] = 0;
} else {
char result[12];
config["pl_on"] = Helpers::render_boolean(result, true);
config["pl_off"] = Helpers::render_boolean(result, false);
}
} else if (sensor.type() == AnalogType::DIGITAL_OUT) { // DAC
snprintf(topic, sizeof(topic), "number/%s/analogsensor_%02d/config", Mqtt::basename().c_str(), sensor.gpio());
snprintf(command_topic, sizeof(command_topic), "%s/analogsensor/%s", Mqtt::basename().c_str(), sensor.name().c_str());
config["cmd_t"] = command_topic;
config["min"] = 0;
config["max"] = 255;
config["mode"] = "box"; // auto, slider or box
config["step"] = 1;
} else if (sensor.type() >= AnalogType::PWM_0) {
snprintf(topic, sizeof(topic), "number/%s/analogsensor_%02d/config", Mqtt::basename().c_str(), sensor.gpio());
snprintf(command_topic, sizeof(command_topic), "%s/analogsensor/%s", Mqtt::basename().c_str(), sensor.name().c_str());
config["cmd_t"] = command_topic;
config["min"] = 0;
config["max"] = 100;
config["mode"] = "box"; // auto, slider or box
config["step"] = 0.1;
} else if (sensor.type() == AnalogType::COUNTER) {
snprintf(topic, sizeof(topic), "sensor/%s/analogsensor_%02d/config", Mqtt::basename().c_str(), sensor.gpio());
snprintf(command_topic, sizeof(command_topic), "%s/analogsensor/%s", Mqtt::basename().c_str(), sensor.name().c_str());
config["cmd_t"] = command_topic;
config["stat_cla"] = "total_increasing";
// config["mode"] = "box"; // auto, slider or box
// config["step"] = sensor.factor();
} else if (sensor.type() == AnalogType::DIGITAL_IN) {
snprintf(topic, sizeof(topic), "binary_sensor/%s/analogsensor_%02d/config", Mqtt::basename().c_str(), sensor.gpio());
} else {
snprintf(topic, sizeof(topic), "sensor/%s/analogsensor_%02d/config", Mqtt::basename().c_str(), sensor.gpio());
config["stat_cla"] = "measurement";
}
JsonObject dev = config.createNestedObject("dev"); JsonObject dev = config.createNestedObject("dev");
JsonArray ids = dev.createNestedArray("ids"); JsonArray ids = dev.createNestedArray("ids");
ids.add("ems-esp"); ids.add("ems-esp");
// add "availability" section char topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
Mqtt::add_avty_to_doc(stat_t, config.as<JsonObject>(), val_cond); snprintf(topic, sizeof(topic), "sensor/%s/analogsensor_%02d/config", Mqtt::basename().c_str(), sensor.gpio());
Mqtt::publish_ha(topic, config.as<JsonObject>()); Mqtt::publish_ha(topic, config.as<JsonObject>());

View File

@@ -170,7 +170,7 @@ class AnalogSensor {
static uuid::log::Logger logger_; static uuid::log::Logger logger_;
void remove_ha_topic(const int8_t type, const uint8_t id) const; void remove_ha_topic(const uint8_t id) const;
bool command_setvalue(const char * value, const int8_t gpio); bool command_setvalue(const char * value, const int8_t gpio);
void measure(); void measure();
bool command_info(const char * value, const int8_t id, JsonObject & output) const; bool command_info(const char * value, const int8_t id, JsonObject & output) const;

View File

@@ -514,16 +514,13 @@ void DallasSensor::publish_values(const bool force) {
config["unit_of_meas"] = EMSdevice::uom_to_string(DeviceValueUOM::DEGREES); config["unit_of_meas"] = EMSdevice::uom_to_string(DeviceValueUOM::DEGREES);
char val_obj[50]; char str[50];
char val_cond[65];
if (Mqtt::is_nested()) { if (Mqtt::is_nested()) {
snprintf(val_obj, sizeof(val_obj), "value_json['%s'].temp", sensor.id().c_str()); snprintf(str, sizeof(str), "{{value_json['%s'].temp}}", sensor.id().c_str());
snprintf(val_cond, sizeof(val_cond), "value_json['%s'] is defined", sensor.id().c_str());
} else { } else {
snprintf(val_obj, sizeof(val_obj), "value_json['%s']", sensor.name().c_str()); snprintf(str, sizeof(str), "{{value_json['%s']}}", sensor.name().c_str());
snprintf(val_cond, sizeof(val_cond), "%s is defined", val_obj);
} }
config["val_tpl"] = (std::string) "{{" + val_obj + " if " + val_cond + "}}"; config["val_tpl"] = str;
char uniq_s[70]; char uniq_s[70];
if (Mqtt::entity_format() == 2) { if (Mqtt::entity_format() == 2) {
@@ -532,20 +529,16 @@ void DallasSensor::publish_values(const bool force) {
snprintf(uniq_s, sizeof(uniq_s), "dallassensor_%s", sensor.id().c_str()); snprintf(uniq_s, sizeof(uniq_s), "dallassensor_%s", sensor.id().c_str());
} }
config["obj_id"] = uniq_s; config["object_id"] = uniq_s;
config["uniq_id"] = uniq_s; // same as object_id config["uniq_id"] = uniq_s; // same as object_id
char name[50]; snprintf(str, sizeof(str), "%s", sensor.name().c_str());
snprintf(name, sizeof(name), "%s", sensor.name().c_str()); config["name"] = str;
config["name"] = name;
JsonObject dev = config.createNestedObject("dev"); JsonObject dev = config.createNestedObject("dev");
JsonArray ids = dev.createNestedArray("ids"); JsonArray ids = dev.createNestedArray("ids");
ids.add("ems-esp"); ids.add("ems-esp");
// add "availability" section
Mqtt::add_avty_to_doc(stat_t, config.as<JsonObject>(), val_cond);
char topic[Mqtt::MQTT_TOPIC_MAX_SIZE]; char topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
// use '_' as HA doesn't like '-' in the topic name // use '_' as HA doesn't like '-' in the topic name
std::string sensorid = sensor.id(); std::string sensorid = sensor.id();
@@ -637,4 +630,4 @@ void DallasSensor::test() {
} }
#endif #endif
} // namespace emsesp } // namespace emsesp

View File

@@ -61,10 +61,6 @@
#define EMSESP_DEFAULT_TRACELOG_RAW false #define EMSESP_DEFAULT_TRACELOG_RAW false
#endif #endif
#ifndef EMSESP_DEFAULT_BOILER_HEATINGOFF
#define EMSESP_DEFAULT_BOILER_HEATINGOFF false
#endif
#ifndef EMSESP_DEFAULT_SHOWER_TIMER #ifndef EMSESP_DEFAULT_SHOWER_TIMER
#define EMSESP_DEFAULT_SHOWER_TIMER false #define EMSESP_DEFAULT_SHOWER_TIMER false
#endif #endif

View File

@@ -48,7 +48,6 @@
{208, DeviceType::BOILER, "Logamax Plus/GB192/Condens GC9000/Greenstar ErP", DeviceFlags::EMS_DEVICE_FLAG_NONE}, {208, DeviceType::BOILER, "Logamax Plus/GB192/Condens GC9000/Greenstar ErP", DeviceFlags::EMS_DEVICE_FLAG_NONE},
{210, DeviceType::BOILER, "Cascade MC400", DeviceFlags::EMS_DEVICE_FLAG_NONE}, {210, DeviceType::BOILER, "Cascade MC400", DeviceFlags::EMS_DEVICE_FLAG_NONE},
{211, DeviceType::BOILER, "EasyControl Adapter", DeviceFlags::EMS_DEVICE_FLAG_NONE}, {211, DeviceType::BOILER, "EasyControl Adapter", DeviceFlags::EMS_DEVICE_FLAG_NONE},
{219, DeviceType::BOILER, "Greenstar HIU", DeviceFlags::EMS_DEVICE_FLAG_NONE},
{234, DeviceType::BOILER, "Logamax Plus GB122/Condense 2300", DeviceFlags::EMS_DEVICE_FLAG_NONE}, {234, DeviceType::BOILER, "Logamax Plus GB122/Condense 2300", DeviceFlags::EMS_DEVICE_FLAG_NONE},
// Controllers - 0x09 / 0x10 / 0x50 // Controllers - 0x09 / 0x10 / 0x50

View File

@@ -100,12 +100,7 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const
// reset is a command uses a dummy variable which is always zero, shown as blank, but provides command enum options // reset is a command uses a dummy variable which is always zero, shown as blank, but provides command enum options
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &reset_, DeviceValueType::CMD, FL_(enum_reset), FL_(reset), DeviceValueUOM::NONE, MAKE_CF_CB(set_reset)); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &reset_, DeviceValueType::CMD, FL_(enum_reset), FL_(reset), DeviceValueUOM::NONE, MAKE_CF_CB(set_reset));
has_update(reset_, 0); has_update(reset_, 0);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
&forceHeatingOff_,
DeviceValueType::BOOL,
FL_(forceHeatingOff),
DeviceValueUOM::NONE,
MAKE_CF_CB(set_forceHeatingOff));
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &heatingActive_, DeviceValueType::BOOL, FL_(heatingActive), DeviceValueUOM::NONE); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &heatingActive_, DeviceValueType::BOOL, FL_(heatingActive), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &tapwaterActive_, DeviceValueType::BOOL, FL_(tapwaterActive), DeviceValueUOM::NONE); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &tapwaterActive_, DeviceValueType::BOOL, FL_(tapwaterActive), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &selFlowTemp_, DeviceValueType::UINT, FL_(selFlowTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_flow_temp)); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &selFlowTemp_, DeviceValueType::UINT, FL_(selFlowTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_flow_temp));
@@ -880,11 +875,6 @@ void Boiler::check_active(const bool force) {
Mqtt::publish(F_(tapwater_active), Helpers::render_boolean(s, b)); Mqtt::publish(F_(tapwater_active), Helpers::render_boolean(s, b));
EMSESP::tap_water_active(b); // let EMS-ESP know, used in the Shower class EMSESP::tap_water_active(b); // let EMS-ESP know, used in the Shower class
} }
if (!Helpers::hasValue(forceHeatingOff_, EMS_VALUE_BOOL)) {
EMSESP::webSettingsService.read([&](WebSettings & settings) { forceHeatingOff_ = (settings.boiler_heatingoff || selFlowTemp_ == 0) ? 1 : 0; });
has_update(&forceHeatingOff_);
}
} }
// 0x18 // 0x18
@@ -1085,11 +1075,6 @@ void Boiler::process_UBAMonitorSlow(std::shared_ptr<const Telegram> telegram) {
has_update(telegram, burn2WorkMin_, 16, 3); // force to 3 bytes has_update(telegram, burn2WorkMin_, 16, 3); // force to 3 bytes
has_update(telegram, heatWorkMin_, 19, 3); // force to 3 bytes has_update(telegram, heatWorkMin_, 19, 3); // force to 3 bytes
has_update(telegram, heatStarts_, 22, 3); // force to 3 bytes has_update(telegram, heatStarts_, 22, 3); // force to 3 bytes
if (forceHeatingOff_ == EMS_VALUE_BOOL_ON && telegram->dest == 0) {
uint8_t data[] = {0, 0, 0, 0};
write_command(EMS_TYPE_UBASetPoints, 0, data, sizeof(data), 0);
}
} }
/* /*
@@ -1120,11 +1105,6 @@ void Boiler::process_UBAMonitorSlowPlus(std::shared_ptr<const Telegram> telegram
has_update(telegram, heatStarts_, 22, 3); // force to 3 bytes has_update(telegram, heatStarts_, 22, 3); // force to 3 bytes
has_update(telegram, heatingPumpMod_, 25); has_update(telegram, heatingPumpMod_, 25);
// temperature measurements at 4, see #620 // temperature measurements at 4, see #620
if (forceHeatingOff_ == EMS_VALUE_BOOL_ON && telegram->dest == 0) {
uint8_t data[] = {0, 0, 0, 0};
write_command(EMS_TYPE_UBASetPoints, 0, data, sizeof(data), 0);
}
} }
/* /*
@@ -1731,9 +1711,7 @@ bool Boiler::set_flow_temp(const char * value, const int8_t id) {
} }
// no write/verify if there is no change, see https://github.com/emsesp/EMS-ESP32/issues/654 // no write/verify if there is no change, see https://github.com/emsesp/EMS-ESP32/issues/654
// put it to end of tx-queue
if (v == selFlowTemp_) { if (v == selFlowTemp_) {
EMSESP::txservice_.add(Telegram::Operation::TX_WRITE, device_id(), EMS_TYPE_UBASetPoints, 0, (uint8_t *) &v, 1, 0, false);
return true; return true;
} }
@@ -2596,17 +2574,4 @@ bool Boiler::set_wwAltOpPrio(const char * value, const int8_t id) {
return false; return false;
} }
bool Boiler::set_forceHeatingOff(const char * value, const int8_t id) {
bool v;
if (Helpers::value2bool(value, v)) {
has_update(forceHeatingOff_, v);
if (!v && Helpers::hasValue(heatingTemp_)) {
uint8_t data[] = {heatingTemp_, (Helpers::hasValue(burnMaxPower_) ? burnMaxPower_ : (uint8_t)100), (Helpers::hasValue(pumpModMax_) ? pumpModMax_ : (uint8_t)0), 0};
write_command(EMS_TYPE_UBASetPoints, 0, data, sizeof(data), 0);
}
return true;
}
return false;
}
} // namespace emsesp } // namespace emsesp

View File

@@ -87,6 +87,7 @@ class Boiler : public EMSdevice {
uint32_t wwWorkM_; // DHW minutes uint32_t wwWorkM_; // DHW minutes
int8_t wwHystOn_; int8_t wwHystOn_;
int8_t wwHystOff_; int8_t wwHystOff_;
uint8_t wwTapActivated_; // maintenance-mode to switch DHW off
uint16_t wwMixerTemp_; // mixing temperature uint16_t wwMixerTemp_; // mixing temperature
uint16_t wwCylMiddleTemp_; // Cyl middle temperature (TS3) uint16_t wwCylMiddleTemp_; // Cyl middle temperature (TS3)
uint16_t wwSolarTemp_; uint16_t wwSolarTemp_;
@@ -94,11 +95,6 @@ class Boiler : public EMSdevice {
uint8_t wwAltOpPrioHeat_; // alternating operation, prioritise heat time uint8_t wwAltOpPrioHeat_; // alternating operation, prioritise heat time
uint8_t wwAltOpPrioWw_; // alternating operation, prioritise dhw time uint8_t wwAltOpPrioWw_; // alternating operation, prioritise dhw time
// special function
uint8_t forceHeatingOff_;
uint8_t wwTapActivated_; // maintenance-mode to switch DHW off
// main // main
uint8_t reset_; // for reset command uint8_t reset_; // for reset command
uint8_t heatingActive_; // Central heating is on/off uint8_t heatingActive_; // Central heating is on/off
@@ -451,8 +447,6 @@ class Boiler : public EMSdevice {
inline bool set_wwAltOpPrioWw(const char * value, const int8_t id) { inline bool set_wwAltOpPrioWw(const char * value, const int8_t id) {
return set_wwAltOpPrio(value, 3); return set_wwAltOpPrio(value, 3);
} }
bool set_forceHeatingOff(const char * value, const int8_t id);
/* /*
bool set_hybridStrategy(const char * value, const int8_t id); bool set_hybridStrategy(const char * value, const int8_t id);
bool set_switchOverTemp(const char * value, const int8_t id); bool set_switchOverTemp(const char * value, const int8_t id);

View File

@@ -32,25 +32,14 @@ Heatpump::Heatpump(uint8_t device_type, uint8_t device_id, uint8_t product_id, c
register_telegram_type(0x999, "HPFunctionTest", true, MAKE_PF_CB(process_HPFunctionTest)); register_telegram_type(0x999, "HPFunctionTest", true, MAKE_PF_CB(process_HPFunctionTest));
register_telegram_type(0x9A0, "HPTemperature", false, MAKE_PF_CB(process_HPTemperature)); register_telegram_type(0x9A0, "HPTemperature", false, MAKE_PF_CB(process_HPTemperature));
register_telegram_type(0x99B, "HPFlowTemp", false, MAKE_PF_CB(process_HPFlowTemp)); register_telegram_type(0x99B, "HPFlowTemp", false, MAKE_PF_CB(process_HPFlowTemp));
register_telegram_type(0x99C, "HPComp", false, MAKE_PF_CB(process_HPComp));
// device values // device values
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &airHumidity_, DeviceValueType::UINT, FL_(airHumidity), DeviceValueUOM::PERCENT); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &airHumidity_, DeviceValueType::UINT, FL_(airHumidity), DeviceValueUOM::PERCENT);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &dewTemperature_, DeviceValueType::UINT, FL_(dewTemperature), DeviceValueUOM::DEGREES); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &dewTemperature_, DeviceValueType::UINT, FL_(dewTemperature), DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &flowTemp_, DeviceValueType::UINT, FL_(curFlowTemp), DeviceValueUOM::DEGREES);
&flowTemp_, register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &retTemp_, DeviceValueType::UINT, FL_(retTemp), DeviceValueUOM::DEGREES);
DeviceValueType::SHORT, register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &sysRetTemp_, DeviceValueType::UINT, FL_(sysRetTemp), DeviceValueUOM::DEGREES);
DeviceValueNumOp::DV_NUMOP_DIV10,
FL_(curFlowTemp),
DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &retTemp_, DeviceValueType::SHORT, DeviceValueNumOp::DV_NUMOP_DIV10, FL_(retTemp), DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
&sysRetTemp_,
DeviceValueType::SHORT,
DeviceValueNumOp::DV_NUMOP_DIV10,
FL_(sysRetTemp),
DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpTa4_, DeviceValueType::SHORT, DeviceValueNumOp::DV_NUMOP_DIV10, FL_(hpTa4), DeviceValueUOM::DEGREES); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpTa4_, DeviceValueType::SHORT, DeviceValueNumOp::DV_NUMOP_DIV10, FL_(hpTa4), DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpTr1_, DeviceValueType::SHORT, DeviceValueNumOp::DV_NUMOP_DIV10, FL_(hpTr1), DeviceValueUOM::DEGREES); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpTr1_, DeviceValueType::SHORT, DeviceValueNumOp::DV_NUMOP_DIV10, FL_(hpTr1), DeviceValueUOM::DEGREES);
@@ -62,9 +51,6 @@ Heatpump::Heatpump(uint8_t device_type, uint8_t device_id, uint8_t product_id, c
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpJr0_, DeviceValueType::SHORT, DeviceValueNumOp::DV_NUMOP_DIV10, FL_(hpPl1), DeviceValueUOM::DEGREES); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpJr0_, DeviceValueType::SHORT, DeviceValueNumOp::DV_NUMOP_DIV10, FL_(hpPl1), DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpJr1_, DeviceValueType::SHORT, DeviceValueNumOp::DV_NUMOP_DIV10, FL_(hpPh1), DeviceValueUOM::DEGREES); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpJr1_, DeviceValueType::SHORT, DeviceValueNumOp::DV_NUMOP_DIV10, FL_(hpPh1), DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &heatingPumpMod_, DeviceValueType::UINT, FL_(heatingPumpMod), DeviceValueUOM::PERCENT);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpCompSpd_, DeviceValueType::UINT, FL_(hpCompSpd), DeviceValueUOM::PERCENT);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
&controlStrategy_, &controlStrategy_,
DeviceValueType::ENUM, DeviceValueType::ENUM,
@@ -191,7 +177,6 @@ void Heatpump::process_HPFlowTemp(std::shared_ptr<const Telegram> telegram) {
has_update(telegram, flowTemp_, 4); has_update(telegram, flowTemp_, 4);
has_update(telegram, retTemp_, 6); has_update(telegram, retTemp_, 6);
has_update(telegram, sysRetTemp_, 14); has_update(telegram, sysRetTemp_, 14);
has_update(telegram, heatingPumpMod_, 19);
} }
// 0x0998 HPSettings // 0x0998 HPSettings
@@ -208,14 +193,6 @@ void Heatpump::process_HPSettings(std::shared_ptr<const Telegram> telegram) {
has_update(telegram, switchOverTemp_, 14); has_update(telegram, switchOverTemp_, 14);
} }
// 0x099C HPComp
// Broadcast (0x099C), data: 00 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 76 00 00
// data: 00 2B 00 03 04 13 00 00 00 00 00 02 02 02 (offset 24)
void Heatpump::process_HPComp(std::shared_ptr<const Telegram> telegram) {
has_update(telegram, hpCompSpd_, 51);
}
// 0x999 HPFunctionTest
void Heatpump::process_HPFunctionTest(std::shared_ptr<const Telegram> telegram) { void Heatpump::process_HPFunctionTest(std::shared_ptr<const Telegram> telegram) {
has_update(telegram, airPurgeMode_, 0); has_update(telegram, airPurgeMode_, 0);
has_update(telegram, heatPumpOutput_, 2); has_update(telegram, heatPumpOutput_, 2);

View File

@@ -41,8 +41,6 @@ class Heatpump : public EMSdevice {
uint8_t energyPriceEl_; uint8_t energyPriceEl_;
uint8_t energyPricePV_; uint8_t energyPricePV_;
int8_t switchOverTemp_; int8_t switchOverTemp_;
uint8_t heatingPumpMod_;
uint8_t hpCompSpd_;
// Function test // Function test
uint8_t airPurgeMode_; uint8_t airPurgeMode_;
@@ -53,19 +51,19 @@ class Heatpump : public EMSdevice {
uint8_t heatCable_; uint8_t heatCable_;
// HM200 temperature // HM200 temperature
int16_t flowTemp_; // TH1 int16_t flowTemp_;
int16_t retTemp_; // TH2 int16_t retTemp_;
int16_t sysRetTemp_; // TH3 int16_t sysRetTemp_;
int16_t hpTc3_; // condenser temp. int16_t hpTc3_; // condenser temp.
int16_t hpTr1_; // compressor temp. int16_t hpTr1_; // compressor temp.
int16_t hpTr3_; // cond. temp. heating int16_t hpTr3_; // cond. temp. heating
int16_t hpTr4_; // cond. temp. clg int16_t hpTr4_; // cond. temp. clg
int16_t hpTr5_; // suction line temp. int16_t hpTr5_; // suction line temp.
int16_t hpTr6_; // hot gas temp. int16_t hpTr6_; // hot gas temp.
int16_t hpTl2_; // inlet air temperature int16_t hpTl2_; // inlet air temperature
int16_t hpTa4_; // drain pan temp. int16_t hpTa4_; // drain pan temp.
int16_t hpJr0_; // low pressure sensor int16_t hpJr0_; // low pressure sensor
int16_t hpJr1_; // high pressure sensor int16_t hpJr1_; // high pressure sensor
void process_HPMonitor1(std::shared_ptr<const Telegram> telegram); void process_HPMonitor1(std::shared_ptr<const Telegram> telegram);
void process_HPMonitor2(std::shared_ptr<const Telegram> telegram); void process_HPMonitor2(std::shared_ptr<const Telegram> telegram);
@@ -73,8 +71,6 @@ class Heatpump : public EMSdevice {
void process_HPFunctionTest(std::shared_ptr<const Telegram> telegram); void process_HPFunctionTest(std::shared_ptr<const Telegram> telegram);
void process_HPTemperature(std::shared_ptr<const Telegram> telegram); void process_HPTemperature(std::shared_ptr<const Telegram> telegram);
void process_HPFlowTemp(std::shared_ptr<const Telegram> telegram); void process_HPFlowTemp(std::shared_ptr<const Telegram> telegram);
void process_HPComp(std::shared_ptr<const Telegram> telegram);
bool set_controlStrategy(const char * value, const int8_t id); bool set_controlStrategy(const char * value, const int8_t id);
bool set_lowNoiseMode(const char * value, const int8_t id); bool set_lowNoiseMode(const char * value, const int8_t id);
bool set_lowNoiseStart(const char * value, const int8_t id); bool set_lowNoiseStart(const char * value, const int8_t id);

View File

@@ -317,7 +317,6 @@ Solar::Solar(uint8_t device_type, uint8_t device_id, uint8_t product_id, const c
DeviceValueUOM::DEGREES); DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &cylPumpMod_, DeviceValueType::UINT, FL_(cylPumpMod), DeviceValueUOM::PERCENT); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &cylPumpMod_, DeviceValueType::UINT, FL_(cylPumpMod), DeviceValueUOM::PERCENT);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &valveStatus_, DeviceValueType::BOOL, FL_(valveStatus), DeviceValueUOM::NONE); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &valveStatus_, DeviceValueType::BOOL, FL_(valveStatus), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &vs1Status_, DeviceValueType::BOOL, FL_(vs1Status), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &cylHeated_, DeviceValueType::BOOL, FL_(cylHeated), DeviceValueUOM::NONE); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &cylHeated_, DeviceValueType::BOOL, FL_(cylHeated), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &collectorShutdown_, DeviceValueType::BOOL, FL_(collectorShutdown), DeviceValueUOM::NONE); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &collectorShutdown_, DeviceValueType::BOOL, FL_(collectorShutdown), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
@@ -821,7 +820,6 @@ void Solar::process_SM100Status(std::shared_ptr<const Telegram> telegram) {
* byte 10 = PS1 Solar circuit pump for collector array 1: test=b0001(1), on=b0100(4) and off=b0011(3) * byte 10 = PS1 Solar circuit pump for collector array 1: test=b0001(1), on=b0100(4) and off=b0011(3)
*/ */
void Solar::process_SM100Status2(std::shared_ptr<const Telegram> telegram) { void Solar::process_SM100Status2(std::shared_ptr<const Telegram> telegram) {
has_bitupdate(telegram, vs1Status_, 0, 2); // on if bit 2 set
has_bitupdate(telegram, valveStatus_, 4, 2); // on if bit 2 set has_bitupdate(telegram, valveStatus_, 4, 2); // on if bit 2 set
has_bitupdate(telegram, solarPump_, 10, 2); // on if bit 2 set has_bitupdate(telegram, solarPump_, 10, 2); // on if bit 2 set
has_bitupdate(telegram, solarPump2_, 1, 2); // on if bit 2 set has_bitupdate(telegram, solarPump2_, 1, 2); // on if bit 2 set

View File

@@ -45,7 +45,6 @@ class Solar : public EMSdevice {
uint8_t solarPump2Mod_; // PS4: modulation solar pump uint8_t solarPump2Mod_; // PS4: modulation solar pump
uint8_t m1Valve_; // M1: heat assistance valve uint8_t m1Valve_; // M1: heat assistance valve
uint8_t m1Power_; // M1: heat assistance valve uint8_t m1Power_; // M1: heat assistance valve
uint8_t vs1Status_; // VS1: status
// 0x363 heat counter // 0x363 heat counter
uint16_t heatCntFlowTemp_; uint16_t heatCntFlowTemp_;

View File

@@ -1192,9 +1192,14 @@ void Thermostat::process_RC30Temp(std::shared_ptr<const Telegram> telegram) {
// type 0x3E (HC1), 0x48 (HC2), 0x52 (HC3), 0x5C (HC4) - data from the RC35 thermostat (0x10) - 16 bytes // type 0x3E (HC1), 0x48 (HC2), 0x52 (HC3), 0x5C (HC4) - data from the RC35 thermostat (0x10) - 16 bytes
void Thermostat::process_RC35Monitor(std::shared_ptr<const Telegram> telegram) { void Thermostat::process_RC35Monitor(std::shared_ptr<const Telegram> telegram) {
// Check if heatingciruit is active, see https://github.com/emsesp/EMS-ESP32/issues/786 // exit if the 15th byte (second from last) is 0x00, which I think is calculated flow setpoint temperature
uint16_t active = 0; // with weather controlled RC35s this value is >=5, otherwise can be zero and our setpoint temps will be incorrect
if (!telegram->read_value(active, 3)) { // see https://github.com/emsesp/EMS-ESP/issues/373#issuecomment-627907301
if (telegram->offset > 0 || telegram->message_length < 15) {
return;
}
if (telegram->message_data[14] == 0x00) {
return; return;
} }

View File

@@ -1642,6 +1642,22 @@ bool EMSdevice::generate_values(JsonObject & output, const uint8_t tag_filter, c
return has_values; return has_values;
} }
// remove the Home Assistant configs for each device value/entity if its not visible or active or marked as read-only
// this is called when an MQTT publish is done via an EMS Device in emsesp.cpp::publish_device_values()
void EMSdevice::mqtt_ha_entity_config_remove() {
for (auto & dv : devicevalues_) {
if (dv.has_state(DeviceValueState::DV_HA_CONFIG_CREATED)
&& ((dv.has_state(DeviceValueState::DV_API_MQTT_EXCLUDE)) || (!dv.has_state(DeviceValueState::DV_ACTIVE)))) {
dv.remove_state(DeviceValueState::DV_HA_CONFIG_CREATED);
if (dv.short_name == FL_(climate)[0]) {
Mqtt::publish_ha_climate_config(dv.tag, false, true); // delete topic (remove = true)
} else {
Mqtt::publish_ha_sensor_config(dv, "", "", true); // delete topic (remove = true)
}
}
}
}
// create the Home Assistant configs for each device value / entity // create the Home Assistant configs for each device value / entity
// this is called when an MQTT publish is done via an EMS Device in emsesp.cpp::publish_device_values() // this is called when an MQTT publish is done via an EMS Device in emsesp.cpp::publish_device_values()
void EMSdevice::mqtt_ha_entity_config_create() { void EMSdevice::mqtt_ha_entity_config_create() {
@@ -1670,9 +1686,6 @@ void EMSdevice::mqtt_ha_entity_config_create() {
dv.add_state(DeviceValueState::DV_HA_CONFIG_CREATED); dv.add_state(DeviceValueState::DV_HA_CONFIG_CREATED);
create_device_config = false; // only create the main config once create_device_config = false; // only create the main config once
} }
if (ESP.getFreeHeap() < (65 * 1024)) {
break;
}
} }
ha_config_done(!create_device_config); ha_config_done(!create_device_config);
@@ -1681,6 +1694,7 @@ void EMSdevice::mqtt_ha_entity_config_create() {
// remove all config topics in HA // remove all config topics in HA
void EMSdevice::ha_config_clear() { void EMSdevice::ha_config_clear() {
for (auto & dv : devicevalues_) { for (auto & dv : devicevalues_) {
Mqtt::publish_ha_sensor_config(dv, "", "", true); // delete topic (remove = true)
dv.remove_state(DeviceValueState::DV_HA_CONFIG_CREATED); dv.remove_state(DeviceValueState::DV_HA_CONFIG_CREATED);
} }

View File

@@ -289,6 +289,7 @@ class EMSdevice {
void publish_all_values(); void publish_all_values();
void mqtt_ha_entity_config_create(); void mqtt_ha_entity_config_create();
void mqtt_ha_entity_config_remove();
std::string telegram_type_name(std::shared_ptr<const Telegram> telegram) const; std::string telegram_type_name(std::shared_ptr<const Telegram> telegram) const;
@@ -305,6 +306,13 @@ class EMSdevice {
ha_config_done_ = v; ha_config_done_ = v;
} }
bool ha_config_firstrun() const {
return ha_config_firstrun_;
}
void ha_config_firstrun(const bool v) {
ha_config_firstrun_ = v;
}
enum Brand : uint8_t { enum Brand : uint8_t {
NO_BRAND = 0, // 0 NO_BRAND = 0, // 0
BOSCH, // 1 BOSCH, // 1
@@ -358,7 +366,6 @@ class EMSdevice {
static constexpr uint8_t EMS_DEVICE_ID_RFSENSOR = 0x40; // RF sensor only sending, no reply static constexpr uint8_t EMS_DEVICE_ID_RFSENSOR = 0x40; // RF sensor only sending, no reply
static constexpr uint8_t EMS_DEVICE_ID_RFBASE = 0x50; static constexpr uint8_t EMS_DEVICE_ID_RFBASE = 0x50;
static constexpr uint8_t EMS_DEVICE_ID_ROOMTHERMOSTAT = 0x17; // TADO using this with no version reply static constexpr uint8_t EMS_DEVICE_ID_ROOMTHERMOSTAT = 0x17; // TADO using this with no version reply
static constexpr uint8_t EMS_DEVICE_ID_TADO_OLD = 0x19; // TADO using this with no broadcast and version
// generic type IDs // generic type IDs
static constexpr uint16_t EMS_TYPE_VERSION = 0x02; // type ID for Version information. Generic across all EMS devices. static constexpr uint16_t EMS_TYPE_VERSION = 0x02; // type ID for Version information. Generic across all EMS devices.
@@ -424,6 +431,7 @@ class EMSdevice {
bool ha_config_done_ = false; bool ha_config_done_ = false;
bool has_update_ = false; bool has_update_ = false;
bool ha_config_firstrun_ = true; // this means a first setup of HA is needed after a restart
struct TelegramFunction { struct TelegramFunction {
uint16_t telegram_type_id_; // it's type_id uint16_t telegram_type_id_; // it's type_id

View File

@@ -535,6 +535,24 @@ void EMSESP::publish_device_values(uint8_t device_type) {
bool nested = (Mqtt::is_nested()); bool nested = (Mqtt::is_nested());
// group by device type // group by device type
if (Mqtt::ha_enabled()) {
for (const auto & emsdevice : emsdevices) {
if (emsdevice && (emsdevice->device_type() == device_type)) {
// specially for MQTT Discovery
// we may have some RETAINED /config topics that reference fields in the data payloads that no longer exist
// remove them immediately to prevent HA from complaining
// we need to do this first before the data payload is published, and only done once!
if (emsdevice->ha_config_firstrun()) {
emsdevice->ha_config_clear();
emsdevice->ha_config_firstrun(false);
return;
} else {
// see if we need to delete and /config topics before adding the payloads
emsdevice->mqtt_ha_entity_config_remove();
}
}
}
}
for (uint8_t tag = DeviceValueTAG::TAG_BOILER_DATA_WW; tag <= DeviceValueTAG::TAG_HS16; tag++) { for (uint8_t tag = DeviceValueTAG::TAG_BOILER_DATA_WW; tag <= DeviceValueTAG::TAG_HS16; tag++) {
JsonObject json_hc = json; JsonObject json_hc = json;
bool nest_created = false; bool nest_created = false;
@@ -1039,7 +1057,7 @@ bool EMSESP::add_device(const uint8_t device_id, const uint8_t product_id, const
// see: https://github.com/emsesp/EMS-ESP32/issues/103#issuecomment-911717342 and https://github.com/emsesp/EMS-ESP32/issues/624 // see: https://github.com/emsesp/EMS-ESP32/issues/103#issuecomment-911717342 and https://github.com/emsesp/EMS-ESP32/issues/624
name = "RF room temperature sensor"; name = "RF room temperature sensor";
device_type = DeviceType::THERMOSTAT; device_type = DeviceType::THERMOSTAT;
} else if (device_id == EMSdevice::EMS_DEVICE_ID_ROOMTHERMOSTAT || device_id == EMSdevice::EMS_DEVICE_ID_TADO_OLD) { } else if (device_id == EMSdevice::EMS_DEVICE_ID_ROOMTHERMOSTAT) {
name = "Generic thermostat"; name = "Generic thermostat";
device_type = DeviceType::THERMOSTAT; device_type = DeviceType::THERMOSTAT;
flags = DeviceFlags::EMS_DEVICE_FLAG_RC10 | DeviceFlags::EMS_DEVICE_FLAG_NO_WRITE; flags = DeviceFlags::EMS_DEVICE_FLAG_RC10 | DeviceFlags::EMS_DEVICE_FLAG_NO_WRITE;

View File

@@ -291,7 +291,7 @@ MAKE_PSTR_ENUM(enum_modetype5, FL_(off), FL_(on))
MAKE_PSTR_ENUM(enum_reducemode, FL_(nofrost), FL_(reduce), FL_(room), FL_(outdoor)) MAKE_PSTR_ENUM(enum_reducemode, FL_(nofrost), FL_(reduce), FL_(room), FL_(outdoor))
MAKE_PSTR_ENUM(enum_reducemode1, FL_(outdoor), FL_(room), FL_(reduce)) // RC310 values: 1-3 MAKE_PSTR_ENUM(enum_reducemode1, FL_(outdoor), FL_(room), FL_(reduce)) // RC310 values: 1-3
MAKE_PSTR_ENUM(enum_nofrostmode, FL_(off), FL_(outdoor), FL_(room)) MAKE_PSTR_ENUM(enum_nofrostmode, FL_(off), FL_(room), FL_(outdoor))
MAKE_PSTR_ENUM(enum_nofrostmode1, FL_(room), FL_(outdoor), FL_(room_outdoor)) MAKE_PSTR_ENUM(enum_nofrostmode1, FL_(room), FL_(outdoor), FL_(room_outdoor))
MAKE_PSTR_ENUM(enum_controlmode, FL_(off), FL_(optimized), FL_(simple), FL_(mpc), FL_(room), FL_(power), FL_(constant)) MAKE_PSTR_ENUM(enum_controlmode, FL_(off), FL_(optimized), FL_(simple), FL_(mpc), FL_(room), FL_(power), FL_(constant))

View File

@@ -269,7 +269,6 @@ MAKE_PSTR_LIST(cyl2, "cyl 2", "Zyl_2", "Cil 2", "Cyl 2", "cyl 2", "cyl 2", "cyl
// Entity translations // Entity translations
// Boiler // Boiler
MAKE_PSTR_LIST(forceHeatingOff, "heatingoff", "force heating off", "Heizen abschalten", "", "", "", "", "")
MAKE_PSTR_LIST(wwtapactivated, "wwtapactivated", "turn on/off", "Durchlauferhitzer aktiv", "zet aan/uit", "på/av", "system przygotowywania", "slå på/av", "ecs activée") MAKE_PSTR_LIST(wwtapactivated, "wwtapactivated", "turn on/off", "Durchlauferhitzer aktiv", "zet aan/uit", "på/av", "system przygotowywania", "slå på/av", "ecs activée")
MAKE_PSTR_LIST(reset, "reset", "Reset", "Reset", "Reset", "Nollställ", "kasowanie komunikatu", "nullstill", "reset") MAKE_PSTR_LIST(reset, "reset", "Reset", "Reset", "Reset", "Nollställ", "kasowanie komunikatu", "nullstill", "reset")
MAKE_PSTR_LIST(oilPreHeat, "oilpreheat", "oil preheating", "Ölvorwärmung", "Olie voorverwarming", "Förvärmning olja", "podgrzewanie oleju", "oljeforvarming", "préchauffage de l'huile") MAKE_PSTR_LIST(oilPreHeat, "oilpreheat", "oil preheating", "Ölvorwärmung", "Olie voorverwarming", "Förvärmning olja", "podgrzewanie oleju", "oljeforvarming", "préchauffage de l'huile")
@@ -684,7 +683,6 @@ MAKE_PSTR_LIST(solarPump, "solarpump", "pump (PS1)", "Pumpe (PS1)", "Pomp (PS1)"
MAKE_PSTR_LIST(solarPump2, "solarpump2", "pump 2 (PS4)", "Pumpe 2 (PS4)", "Pomp 2 (PS4)", "Pump 2 (PS4)", "pompa solarna 2 (PS4)", "solpumpe 2 (PS4)", "pompe 2 (PS4)") MAKE_PSTR_LIST(solarPump2, "solarpump2", "pump 2 (PS4)", "Pumpe 2 (PS4)", "Pomp 2 (PS4)", "Pump 2 (PS4)", "pompa solarna 2 (PS4)", "solpumpe 2 (PS4)", "pompe 2 (PS4)")
MAKE_PSTR_LIST(solarPump2Mod, "solarpump2mod", "pump 2 modulation (PS4)", "Pumpe 2 Modulation (PS4)", "Modulatie pomp 2 (PS4)", "Pump 2 Modulering (PS4)", "modulacja pompy solarnej 2 (PS4)", "solpumpe2modulering (PS4)", "modulation pompe solaire 2 (PS4)") MAKE_PSTR_LIST(solarPump2Mod, "solarpump2mod", "pump 2 modulation (PS4)", "Pumpe 2 Modulation (PS4)", "Modulatie pomp 2 (PS4)", "Pump 2 Modulering (PS4)", "modulacja pompy solarnej 2 (PS4)", "solpumpe2modulering (PS4)", "modulation pompe solaire 2 (PS4)")
MAKE_PSTR_LIST(valveStatus, "valvestatus", "valve status", "Ventilstatus", "Klepstatus", "Ventilstatus", "stan zaworu", "ventilstatus", "statut valve") MAKE_PSTR_LIST(valveStatus, "valvestatus", "valve status", "Ventilstatus", "Klepstatus", "Ventilstatus", "stan zaworu", "ventilstatus", "statut valve")
MAKE_PSTR_LIST(vs1Status, "vs1status", "valve status VS1", "Ventilstatus VS1", "Klepstatus VS1", "Ventilstatus VS1", "stan zaworu VS1", "ventilstatus VS1", "statut valve VS1")
MAKE_PSTR_LIST(cylHeated, "cylheated", "cyl heated", "Speichertemperatur erreicht", "Boilertemperatuur behaald", "Värmepanna Uppvärmd", "zasobnik został nagrzany", "bereder oppvarmt", "cylindre chauffé") MAKE_PSTR_LIST(cylHeated, "cylheated", "cyl heated", "Speichertemperatur erreicht", "Boilertemperatuur behaald", "Värmepanna Uppvärmd", "zasobnik został nagrzany", "bereder oppvarmt", "cylindre chauffé")
MAKE_PSTR_LIST(collectorShutdown, "collectorshutdown", "collector shutdown", "Kollektorabschaltung", "Collector afschakeling", "Kollektor Avstängning", "wyłączenie kolektora", "kollektor stengt", "arrêt collecteur") MAKE_PSTR_LIST(collectorShutdown, "collectorshutdown", "collector shutdown", "Kollektorabschaltung", "Collector afschakeling", "Kollektor Avstängning", "wyłączenie kolektora", "kollektor stengt", "arrêt collecteur")
MAKE_PSTR_LIST(pumpWorkTime, "pumpworktime", "pump working time", "Pumpenlaufzeit", "Pomplooptijd", "Pump Drifttid", "czas pracy pompy", "driftstid pumpe", "durée fonctionnement pompe") MAKE_PSTR_LIST(pumpWorkTime, "pumpworktime", "pump working time", "Pumpenlaufzeit", "Pomplooptijd", "Pump Drifttid", "czas pracy pompy", "driftstid pumpe", "durée fonctionnement pompe")

View File

@@ -685,7 +685,7 @@ std::shared_ptr<const MqttMessage> Mqtt::queue_message(const uint8_t operation,
#endif #endif
// if the queue is full, make room but removing the last one // if the queue is full, make room but removing the last one
if (mqtt_messages_.size() >= MAX_MQTT_MESSAGES || ESP.getFreeHeap() < (60 * 1024)) { if (mqtt_messages_.size() >= MAX_MQTT_MESSAGES) {
mqtt_messages_.pop_front(); mqtt_messages_.pop_front();
LOG_WARNING("Queue overflow, removing one message"); LOG_WARNING("Queue overflow, removing one message");
mqtt_publish_fails_++; mqtt_publish_fails_++;
@@ -815,8 +815,8 @@ void Mqtt::process_queue() {
#if defined(EMSESP_DEBUG) #if defined(EMSESP_DEBUG)
LOG_DEBUG("[DEBUG] Waiting for QOS-ACK"); LOG_DEBUG("[DEBUG] Waiting for QOS-ACK");
#endif #endif
// if we don't get the ack within 10 seconds, republish with new packet_id // if we don't get the ack within 10 minutes, republish with new packet_id
if (uuid::get_uptime_sec() - last_publish_queue_ < 10) { if (uuid::get_uptime_sec() - last_publish_queue_ < 600) {
return; return;
} }
} }
@@ -1074,8 +1074,6 @@ void Mqtt::publish_ha_sensor_config(uint8_t type, // EMSdev
const char * sc_ha = "stat_cla"; // state class const char * sc_ha = "stat_cla"; // state class
const char * uom_ha = "unit_of_meas"; // unit of measure const char * uom_ha = "unit_of_meas"; // unit of measure
char sample_val[30] = "0"; // sample, correct(!) entity value, used only to prevent warning/error in HA if real value is not published yet
// handle commands, which are device entities that are writable // handle commands, which are device entities that are writable
// we add the command topic parameter // we add the command topic parameter
// note: there is no way to handle strings in HA so datetimes (e.g. set_datetime, set_holiday, set_wwswitchtime etc) are excluded // note: there is no way to handle strings in HA so datetimes (e.g. set_datetime, set_holiday, set_wwswitchtime etc) are excluded
@@ -1095,7 +1093,6 @@ void Mqtt::publish_ha_sensor_config(uint8_t type, // EMSdev
for (uint8_t i = 0; i < options_size; i++) { for (uint8_t i = 0; i < options_size; i++) {
option_list.add(Helpers::translated_word(options[i])); option_list.add(Helpers::translated_word(options[i]));
} }
snprintf(sample_val, sizeof(sample_val), "'%s'", Helpers::translated_word(options[0]));
} else if (type != DeviceValueType::STRING && type != DeviceValueType::BOOL) { } else if (type != DeviceValueType::STRING && type != DeviceValueType::BOOL) {
// Must be Numeric.... // Must be Numeric....
doc["mode"] = "box"; // auto, slider or box doc["mode"] = "box"; // auto, slider or box
@@ -1112,7 +1109,6 @@ void Mqtt::publish_ha_sensor_config(uint8_t type, // EMSdev
if (dv_set_min != 0 || dv_set_max != 0) { if (dv_set_min != 0 || dv_set_max != 0) {
doc["min"] = dv_set_min; doc["min"] = dv_set_min;
doc["max"] = dv_set_max; doc["max"] = dv_set_max;
snprintf(sample_val, sizeof(sample_val), "%i", dv_set_min);
} }
// set icons // set icons
@@ -1150,15 +1146,17 @@ void Mqtt::publish_ha_sensor_config(uint8_t type, // EMSdev
// value template // value template
// if its nested mqtt format then use the appended entity name, otherwise take the original name // if its nested mqtt format then use the appended entity name, otherwise take the original name
char val_obj[100]; char val_tpl[75];
char val_cond[200]; if (is_nested()) {
if (is_nested() && tag >= DeviceValueTAG::TAG_HC1) { if (tag >= DeviceValueTAG::TAG_HC1) {
snprintf(val_obj, sizeof(val_obj), "value_json.%s.%s", EMSdevice::tag_to_mqtt(tag).c_str(), entity); snprintf(val_tpl, sizeof(val_tpl), "{{value_json.%s.%s}}", EMSdevice::tag_to_mqtt(tag).c_str(), entity);
snprintf(val_cond, sizeof(val_cond), "value_json.%s is defined and %s is defined", EMSdevice::tag_to_mqtt(tag).c_str(), val_obj); } else {
snprintf(val_tpl, sizeof(val_tpl), "{{value_json.%s}}", entity);
}
} else { } else {
snprintf(val_obj, sizeof(val_obj), "value_json.%s", entity); snprintf(val_tpl, sizeof(val_tpl), "{{value_json.%s}}", entity);
snprintf(val_cond, sizeof(val_cond), "%s is defined", val_obj);
} }
doc["val_tpl"] = val_tpl;
// special case to handle booleans // special case to handle booleans
// applies to both Binary Sensor (read only) and a Switch (for a command) // applies to both Binary Sensor (read only) and a Switch (for a command)
@@ -1167,7 +1165,6 @@ void Mqtt::publish_ha_sensor_config(uint8_t type, // EMSdev
if (EMSESP::system_.bool_format() == BOOL_FORMAT_TRUEFALSE) { if (EMSESP::system_.bool_format() == BOOL_FORMAT_TRUEFALSE) {
doc["pl_on"] = true; doc["pl_on"] = true;
doc["pl_off"] = false; doc["pl_off"] = false;
snprintf(sample_val, sizeof(sample_val), "false");
} else if (EMSESP::system_.bool_format() == BOOL_FORMAT_10) { } else if (EMSESP::system_.bool_format() == BOOL_FORMAT_10) {
doc["pl_on"] = 1; doc["pl_on"] = 1;
doc["pl_off"] = 0; doc["pl_off"] = 0;
@@ -1175,7 +1172,6 @@ void Mqtt::publish_ha_sensor_config(uint8_t type, // EMSdev
char result[12]; char result[12];
doc["pl_on"] = Helpers::render_boolean(result, true); doc["pl_on"] = Helpers::render_boolean(result, true);
doc["pl_off"] = Helpers::render_boolean(result, false); doc["pl_off"] = Helpers::render_boolean(result, false);
snprintf(sample_val, sizeof(sample_val), "'%s'", Helpers::render_boolean(result, false));
} }
doc[sc_ha] = F_(measurement); //do we want this??? doc[sc_ha] = F_(measurement); //do we want this???
} else { } else {
@@ -1193,8 +1189,6 @@ void Mqtt::publish_ha_sensor_config(uint8_t type, // EMSdev
} }
} }
doc["val_tpl"] = (std::string) "{{" + val_obj + " if " + val_cond + " else " + sample_val + "}}";
// this next section is adding the state class, device class and sometimes the icon // this next section is adding the state class, device class and sometimes the icon
// used for Sensor and Binary Sensor Entities in HA // used for Sensor and Binary Sensor Entities in HA
if (set_ha_classes) { if (set_ha_classes) {
@@ -1290,9 +1284,6 @@ void Mqtt::publish_ha_sensor_config(uint8_t type, // EMSdev
// add the dev json object to the end // add the dev json object to the end
doc["dev"] = dev_json; doc["dev"] = dev_json;
// add "availability" section
add_avty_to_doc(stat_t, doc.as<JsonObject>(), val_cond);
publish_ha(topic, doc.as<JsonObject>()); publish_ha(topic, doc.as<JsonObject>());
} }
@@ -1304,9 +1295,6 @@ void Mqtt::publish_ha_climate_config(const uint8_t tag, const bool has_roomtemp,
char hc_mode_s[30]; char hc_mode_s[30];
char seltemp_s[30]; char seltemp_s[30];
char currtemp_s[30]; char currtemp_s[30];
char hc_mode_cond[80];
char seltemp_cond[80];
char currtemp_cond[170];
char mode_str_tpl[400]; char mode_str_tpl[400];
char name_s[10]; char name_s[10];
char uniq_id_s[60]; char uniq_id_s[60];
@@ -1324,31 +1312,24 @@ void Mqtt::publish_ha_climate_config(const uint8_t tag, const bool has_roomtemp,
if (Mqtt::is_nested()) { if (Mqtt::is_nested()) {
// nested format // nested format
snprintf(hc_mode_s, sizeof(hc_mode_s), "value_json.hc%d.mode", hc_num); snprintf(hc_mode_s, sizeof(hc_mode_s), "value_json.hc%d.mode", hc_num);
snprintf(hc_mode_cond, sizeof(hc_mode_cond), "value_json.hc%d is undefined or %s is undefined", hc_num, hc_mode_s); snprintf(seltemp_s, sizeof(seltemp_s), "{{value_json.hc%d.seltemp}}", hc_num);
snprintf(seltemp_s, sizeof(seltemp_s), "value_json.hc%d.seltemp", hc_num);
snprintf(seltemp_cond, sizeof(seltemp_cond), "value_json.hc%d is defined and %s is defined", hc_num, seltemp_s);
if (has_roomtemp) { if (has_roomtemp) {
snprintf(currtemp_s, sizeof(currtemp_s), "value_json.hc%d.currtemp", hc_num); snprintf(currtemp_s, sizeof(currtemp_s), "{{value_json.hc%d.currtemp}}", hc_num);
snprintf(currtemp_cond, sizeof(currtemp_cond), "value_json.hc%d is defined and %s is defined", hc_num, currtemp_s);
} }
snprintf(topic_t, sizeof(topic_t), "~/%s", Mqtt::tag_to_topic(EMSdevice::DeviceType::THERMOSTAT, DeviceValueTAG::TAG_NONE).c_str()); snprintf(topic_t, sizeof(topic_t), "~/%s", Mqtt::tag_to_topic(EMSdevice::DeviceType::THERMOSTAT, DeviceValueTAG::TAG_NONE).c_str());
} else { } else {
// single format // single format
snprintf(hc_mode_s, sizeof(hc_mode_s), "value_json.mode"); snprintf(hc_mode_s, sizeof(hc_mode_s), "value_json.mode");
snprintf(hc_mode_cond, sizeof(hc_mode_cond), "%s is undefined", hc_mode_s); snprintf(seltemp_s, sizeof(seltemp_s), "{{value_json.seltemp}}");
snprintf(seltemp_s, sizeof(seltemp_s), "value_json.seltemp");
snprintf(seltemp_cond, sizeof(seltemp_cond), "%s is defined", seltemp_s);
if (has_roomtemp) { if (has_roomtemp) {
snprintf(currtemp_s, sizeof(currtemp_s), "value_json.currtemp"); snprintf(currtemp_s, sizeof(currtemp_s), "{{value_json.currtemp}}");
snprintf(currtemp_cond, sizeof(currtemp_cond), "%s is defined", currtemp_s);
} }
snprintf(topic_t, sizeof(topic_t), "~/%s", Mqtt::tag_to_topic(EMSdevice::DeviceType::THERMOSTAT, DeviceValueTAG::TAG_HC1 + hc_num - 1).c_str()); snprintf(topic_t, sizeof(topic_t), "~/%s", Mqtt::tag_to_topic(EMSdevice::DeviceType::THERMOSTAT, DeviceValueTAG::TAG_HC1 + hc_num - 1).c_str());
} }
snprintf(mode_str_tpl, snprintf(mode_str_tpl,
sizeof(mode_str_tpl), sizeof(mode_str_tpl),
"{%%if %s%%}off{%%elif %s=='manual'%%}heat{%%elif %s=='day'%%}heat{%%elif %s=='night'%%}off{%%elif %s=='off'%%}off{%%else%%}auto{%%endif%%}", "{%%if %s=='manual'%%}heat{%%elif %s=='day'%%}heat{%%elif %s=='night'%%}off{%%elif %s=='off'%%}off{%%else%%}auto{%%endif%%}",
hc_mode_cond,
hc_mode_s, hc_mode_s,
hc_mode_s, hc_mode_s,
hc_mode_s, hc_mode_s,
@@ -1365,7 +1346,7 @@ void Mqtt::publish_ha_climate_config(const uint8_t tag, const bool has_roomtemp,
snprintf(temp_cmd_s, sizeof(temp_cmd_s), "~/thermostat/hc%d/seltemp", hc_num); snprintf(temp_cmd_s, sizeof(temp_cmd_s), "~/thermostat/hc%d/seltemp", hc_num);
snprintf(mode_cmd_s, sizeof(temp_cmd_s), "~/thermostat/hc%d/mode", hc_num); snprintf(mode_cmd_s, sizeof(temp_cmd_s), "~/thermostat/hc%d/mode", hc_num);
StaticJsonDocument<EMSESP_JSON_SIZE_HA_CONFIG + 512> doc; StaticJsonDocument<EMSESP_JSON_SIZE_HA_CONFIG> doc;
doc["~"] = mqtt_base_; doc["~"] = mqtt_base_;
doc["uniq_id"] = uniq_id_s; doc["uniq_id"] = uniq_id_s;
@@ -1375,10 +1356,12 @@ void Mqtt::publish_ha_climate_config(const uint8_t tag, const bool has_roomtemp,
doc["mode_stat_tpl"] = mode_str_tpl; doc["mode_stat_tpl"] = mode_str_tpl;
doc["temp_cmd_t"] = temp_cmd_s; doc["temp_cmd_t"] = temp_cmd_s;
doc["temp_stat_t"] = topic_t; doc["temp_stat_t"] = topic_t;
doc["temp_stat_tpl"] = (std::string) "{{" + seltemp_s + " if " + seltemp_cond + " else 0}}"; doc["temp_stat_tpl"] = seltemp_s;
doc["mode_cmd_t"] = mode_cmd_s;
if (has_roomtemp) { if (has_roomtemp) {
doc["curr_temp_t"] = topic_t; doc["curr_temp_t"] = topic_t;
doc["curr_temp_tpl"] = (std::string) "{{" + currtemp_s + " if " + currtemp_cond + " else 0}}"; doc["curr_temp_tpl"] = currtemp_s;
} }
doc["min_temp"] = Helpers::render_value(min_s, min, 0, EMSESP::system_.fahrenheit() ? 2 : 0); doc["min_temp"] = Helpers::render_value(min_s, min, 0, EMSESP::system_.fahrenheit() ? 2 : 0);
@@ -1386,8 +1369,8 @@ void Mqtt::publish_ha_climate_config(const uint8_t tag, const bool has_roomtemp,
doc["temp_step"] = "0.5"; doc["temp_step"] = "0.5";
// the HA climate component only responds to auto, heat and off // the HA climate component only responds to auto, heat and off
doc["mode_cmd_t"] = mode_cmd_s; JsonArray modes = doc.createNestedArray("modes");
JsonArray modes = doc.createNestedArray("modes");
modes.add("auto"); modes.add("auto");
modes.add("heat"); modes.add("heat");
modes.add("off"); modes.add("off");
@@ -1396,9 +1379,6 @@ void Mqtt::publish_ha_climate_config(const uint8_t tag, const bool has_roomtemp,
JsonArray ids = dev.createNestedArray("ids"); JsonArray ids = dev.createNestedArray("ids");
ids.add("ems-esp-thermostat"); ids.add("ems-esp-thermostat");
// add "availability" section
add_avty_to_doc(topic_t, doc.as<JsonObject>(), seltemp_cond, has_roomtemp ? currtemp_cond : nullptr, hc_mode_cond);
publish_ha(topic, doc.as<JsonObject>()); // publish the config payload with retain flag publish_ha(topic, doc.as<JsonObject>()); // publish the config payload with retain flag
} }
@@ -1421,41 +1401,4 @@ std::string Mqtt::tag_to_topic(uint8_t device_type, uint8_t tag) {
} }
} }
// adds "availability" section to HA Discovery config
void Mqtt::add_avty_to_doc(const char * state_t, const JsonObject & doc, const char * cond1, const char * cond2, const char * negcond) {
const char * tpl_draft = "{{'online' if %s else 'offline'}}";
char tpl[150];
JsonArray avty = doc.createNestedArray("avty");
StaticJsonDocument<512> avty_json;
snprintf(tpl, sizeof(tpl), "%s/status", mqtt_base_.c_str());
avty_json["t"] = tpl;
snprintf(tpl, sizeof(tpl), tpl_draft, "value == 'online'");
avty_json["val_tpl"] = tpl;
avty.add(avty_json);
avty_json.clear();
avty_json["t"] = state_t;
snprintf(tpl, sizeof(tpl), tpl_draft, cond1 == nullptr ? "value is defined" : cond1);
avty_json["val_tpl"] = tpl;
avty.add(avty_json);
if (cond2 != nullptr) {
avty_json.clear();
avty_json["t"] = state_t;
snprintf(tpl, sizeof(tpl), tpl_draft, cond2);
avty_json["val_tpl"] = tpl;
avty.add(avty_json);
}
if (negcond != nullptr) {
avty_json.clear();
avty_json["t"] = state_t;
snprintf(tpl, sizeof(tpl), "{{'offline' if %s else 'online'}}", negcond);
avty_json["val_tpl"] = tpl;
avty.add(avty_json);
}
doc["avty_mode"] = "all";
}
} // namespace emsesp } // namespace emsesp

View File

@@ -240,9 +240,6 @@ class Mqtt {
static std::string tag_to_topic(uint8_t device_type, uint8_t tag); static std::string tag_to_topic(uint8_t device_type, uint8_t tag);
static void
add_avty_to_doc(const char * state_t, const JsonObject & doc, const char * cond1 = nullptr, const char * cond2 = nullptr, const char * negcond = nullptr);
struct QueuedMqttMessage { struct QueuedMqttMessage {
const uint32_t id_; const uint32_t id_;
const std::shared_ptr<const MqttMessage> content_; const std::shared_ptr<const MqttMessage> content_;

View File

@@ -168,8 +168,8 @@ void Shower::set_shower_state(bool state, bool force) {
doc["stat_t"] = stat_t; doc["stat_t"] = stat_t;
if (EMSESP::system_.bool_format() == BOOL_FORMAT_TRUEFALSE) { if (EMSESP::system_.bool_format() == BOOL_FORMAT_TRUEFALSE) {
doc["pl_on"] = "true"; doc["pl_on"] = true;
doc["pl_off"] = "false"; doc["pl_off"] = false;
} else if (EMSESP::system_.bool_format() == BOOL_FORMAT_10) { } else if (EMSESP::system_.bool_format() == BOOL_FORMAT_10) {
doc["pl_on"] = 1; doc["pl_on"] = 1;
doc["pl_off"] = 0; doc["pl_off"] = 0;
@@ -183,9 +183,6 @@ void Shower::set_shower_state(bool state, bool force) {
JsonArray ids = dev.createNestedArray("ids"); JsonArray ids = dev.createNestedArray("ids");
ids.add("ems-esp"); ids.add("ems-esp");
// add "availability" section
Mqtt::add_avty_to_doc(stat_t, doc.as<JsonObject>());
char topic[Mqtt::MQTT_TOPIC_MAX_SIZE]; char topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
snprintf(topic, sizeof(topic), "binary_sensor/%s/shower_active/config", Mqtt::basename().c_str()); snprintf(topic, sizeof(topic), "binary_sensor/%s/shower_active/config", Mqtt::basename().c_str());
Mqtt::publish_ha(topic, doc.as<JsonObject>()); // publish the config payload with retain flag Mqtt::publish_ha(topic, doc.as<JsonObject>()); // publish the config payload with retain flag

View File

@@ -659,6 +659,7 @@ void System::network_init(bool refresh) {
} }
last_system_check_ = 0; // force the LED to go from fast flash to pulse last_system_check_ = 0; // force the LED to go from fast flash to pulse
send_heartbeat();
if (phy_type_ == PHY_type::PHY_TYPE_NONE) { if (phy_type_ == PHY_type::PHY_TYPE_NONE) {
return; return;
@@ -714,6 +715,7 @@ void System::system_check() {
digitalWrite(led_gpio_, hide_led_ ? !LED_ON : LED_ON); digitalWrite(led_gpio_, hide_led_ ? !LED_ON : LED_ON);
#endif #endif
} }
send_heartbeat();
} else { } else {
// turn off LED so we're ready to the flashes // turn off LED so we're ready to the flashes
if (led_gpio_) { if (led_gpio_) {

View File

@@ -1 +1 @@
#define EMSESP_APP_VERSION "3.5.2-patch.0" #define EMSESP_APP_VERSION "3.5.0"

View File

@@ -136,7 +136,7 @@ void WebLogService::operator<<(std::shared_ptr<uuid::log::Message> message) {
log_messages_.pop_front(); log_messages_.pop_front();
} }
log_messages_.emplace_back(++log_message_id_, std::move(message)); log_messages_.emplace_back(log_message_id_++, std::move(message));
EMSESP::esp8266React.getNTPSettingsService()->read([&](NTPSettings & settings) { EMSESP::esp8266React.getNTPSettingsService()->read([&](NTPSettings & settings) {
if (!settings.enabled || (time(nullptr) < 1500000000L)) { if (!settings.enabled || (time(nullptr) < 1500000000L)) {
@@ -191,9 +191,9 @@ char * WebLogService::messagetime(char * out, const uint64_t t, const size_t buf
// send to web eventsource // send to web eventsource
void WebLogService::transmit(const QueuedLogMessage & message) { void WebLogService::transmit(const QueuedLogMessage & message) {
StaticJsonDocument<EMSESP_JSON_SIZE_MEDIUM> jsonDocument; auto jsonDocument = DynamicJsonDocument(EMSESP_JSON_SIZE_MEDIUM);
JsonObject logEvent = jsonDocument.to<JsonObject>(); JsonObject logEvent = jsonDocument.to<JsonObject>();
char time_string[25]; char time_string[25];
logEvent["t"] = messagetime(time_string, message.content_->uptime_ms, sizeof(time_string)); logEvent["t"] = messagetime(time_string, message.content_->uptime_ms, sizeof(time_string));
logEvent["l"] = message.content_->level; logEvent["l"] = message.content_->level;
@@ -212,10 +212,33 @@ void WebLogService::transmit(const QueuedLogMessage & message) {
// send the complete log buffer to the API, not filtering on log level // send the complete log buffer to the API, not filtering on log level
void WebLogService::fetchLog(AsyncWebServerRequest * request) { void WebLogService::fetchLog(AsyncWebServerRequest * request) {
log_message_id_tail_ = 0; // auto * response = new MsgpackAsyncJsonResponse(false, EMSESP_JSON_SIZE_LARGE_DYN + 192 * log_messages_.size());
request->send(200); size_t buffer = EMSESP_JSON_SIZE_XLARGE_DYN + 192 * log_messages_.size();
} auto * response = new MsgpackAsyncJsonResponse(false, buffer);
while (!response->getSize()) {
delete response;
buffer -= 1024;
response = new MsgpackAsyncJsonResponse(false, buffer);
}
JsonObject root = response->getRoot();
JsonArray log = root.createNestedArray("events");
log_message_id_tail_ = log_messages_.back().id_;
last_transmit_ = uuid::get_uptime_ms();
for (const auto & message : log_messages_) {
JsonObject logEvent = log.createNestedObject();
char time_string[25];
logEvent["t"] = messagetime(time_string, message.content_->uptime_ms, sizeof(time_string));
logEvent["l"] = message.content_->level;
logEvent["i"] = message.id_;
logEvent["n"] = message.content_->name;
logEvent["m"] = message.content_->text;
}
log_message_id_tail_ = log_messages_.back().id_;
response->setLength();
request->send(response);
}
// sets the values like level after a POST // sets the values like level after a POST
void WebLogService::setValues(AsyncWebServerRequest * request, JsonVariant & json) { void WebLogService::setValues(AsyncWebServerRequest * request, JsonVariant & json) {

View File

@@ -47,7 +47,6 @@ void WebSettings::read(WebSettings & settings, JsonObject & root) {
root["syslog_mark_interval"] = settings.syslog_mark_interval; root["syslog_mark_interval"] = settings.syslog_mark_interval;
root["syslog_host"] = settings.syslog_host; root["syslog_host"] = settings.syslog_host;
root["syslog_port"] = settings.syslog_port; root["syslog_port"] = settings.syslog_port;
root["boiler_heatingoff"] = settings.boiler_heatingoff;
root["shower_timer"] = settings.shower_timer; root["shower_timer"] = settings.shower_timer;
root["shower_alert"] = settings.shower_alert; root["shower_alert"] = settings.shower_alert;
root["shower_alert_coldshot"] = settings.shower_alert_coldshot; root["shower_alert_coldshot"] = settings.shower_alert_coldshot;
@@ -241,40 +240,38 @@ StateUpdateResult WebSettings::update(JsonObject & root, WebSettings & settings)
settings.low_clock = root["low_clock"] | false; settings.low_clock = root["low_clock"] | false;
check_flag(prev, settings.low_clock, ChangeFlags::RESTART); check_flag(prev, settings.low_clock, ChangeFlags::RESTART);
String old_local = settings.locale;
settings.locale = root["locale"] | EMSESP_DEFAULT_LOCALE;
EMSESP::system_.locale(settings.locale);
#ifndef EMSESP_STANDALONE
if (!old_local.equals(settings.locale)) {
add_flags(ChangeFlags::RESTART); // force restart
}
#endif
// //
// these may need mqtt restart to rebuild HA discovery topics // these may need mqtt restart to rebuild HA discovery topics
// //
prev = settings.bool_format; prev = settings.bool_format;
settings.bool_format = root["bool_format"] | EMSESP_DEFAULT_BOOL_FORMAT; settings.bool_format = root["bool_format"] | EMSESP_DEFAULT_BOOL_FORMAT;
EMSESP::system_.bool_format(settings.bool_format); EMSESP::system_.bool_format(settings.bool_format);
if (Mqtt::ha_enabled()) { if (Mqtt::ha_enabled())
check_flag(prev, settings.bool_format, ChangeFlags::MQTT); check_flag(prev, settings.bool_format, ChangeFlags::MQTT);
}
prev = settings.enum_format; prev = settings.enum_format;
settings.enum_format = root["enum_format"] | EMSESP_DEFAULT_ENUM_FORMAT; settings.enum_format = root["enum_format"] | EMSESP_DEFAULT_ENUM_FORMAT;
EMSESP::system_.enum_format(settings.enum_format); EMSESP::system_.enum_format(settings.enum_format);
if (Mqtt::ha_enabled()) { if (Mqtt::ha_enabled())
check_flag(prev, settings.enum_format, ChangeFlags::MQTT); check_flag(prev, settings.enum_format, ChangeFlags::MQTT);
}
String old_locale = settings.locale;
settings.locale = root["locale"] | EMSESP_DEFAULT_LOCALE;
EMSESP::system_.locale(settings.locale);
if (Mqtt::ha_enabled() && !old_locale.equals(settings.locale)) {
add_flags(ChangeFlags::MQTT);
}
// //
// without checks or necessary restarts... // without checks or necessary restarts...
// //
settings.trace_raw = root["trace_raw"] | EMSESP_DEFAULT_TRACELOG_RAW; settings.trace_raw = root["trace_raw"] | EMSESP_DEFAULT_TRACELOG_RAW;
EMSESP::trace_raw(settings.trace_raw); EMSESP::trace_raw(settings.trace_raw);
settings.notoken_api = root["notoken_api"] | EMSESP_DEFAULT_NOTOKEN_API; settings.notoken_api = root["notoken_api"] | EMSESP_DEFAULT_NOTOKEN_API;
settings.solar_maxflow = root["solar_maxflow"] | EMSESP_DEFAULT_SOLAR_MAXFLOW; settings.solar_maxflow = root["solar_maxflow"] | EMSESP_DEFAULT_SOLAR_MAXFLOW;
settings.boiler_heatingoff = root["boiler_heatingoff"] | EMSESP_DEFAULT_BOILER_HEATINGOFF;
settings.fahrenheit = root["fahrenheit"] | false; settings.fahrenheit = root["fahrenheit"] | false;
EMSESP::system_.fahrenheit(settings.fahrenheit); EMSESP::system_.fahrenheit(settings.fahrenheit);

View File

@@ -33,7 +33,6 @@ class WebSettings {
String locale; String locale;
uint8_t tx_mode; uint8_t tx_mode;
uint8_t ems_bus_id; uint8_t ems_bus_id;
bool boiler_heatingoff;
bool shower_timer; bool shower_timer;
bool shower_alert; bool shower_alert;
uint8_t shower_alert_trigger; uint8_t shower_alert_trigger;