41 Commits

Author SHA1 Message Date
Proddy
9233f0dfcc v3.5.1 - merge with patch 2023-03-11 16:06:05 +01:00
Proddy
292f743b14 Update bug_report.md 2023-02-19 11:18:08 +01:00
Proddy
dd6dfffd57 Delete questions---troubleshooting.md 2023-02-19 10:49:52 +01:00
Proddy
ec705a5307 Delete feature_request.md 2023-02-19 10:49:45 +01:00
Proddy
f45f071710 Create config.yml 2023-02-19 10:49:32 +01:00
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
45 changed files with 1362 additions and 848 deletions

View File

@@ -1,35 +1,50 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: bug
assignees: ''
name: Problem Report
about: Create a Report to help us improve
---
*Before creating a new issue please check that you have:*
<!-- Thanks for reporting a problem for this project. READ THIS FIRST:
* *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 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
*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.*
Please take a few minutes to complete the requested information below.
*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.*
-->
**Bug description**
*A clear and concise description of what the bug is. Mention which EMS-ESP version you're using.*
### PROBLEM DESCRIPTION
**Steps to reproduce**
*Steps to reproduce the behavior.*
_A clear and concise description of what the problem is._
**Expected behavior**
*A clear and concise description of what you expected to happen.*
### REQUESTED INFORMATION
**Screenshots**
*If applicable, add screenshots to help explain your problem.*
_Make sure your have performed every step and checked the applicable boxes before submitting your issue. Thank you!_
**Device information**
*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 [issues](https://github.com/emsesp/EMS-ESP32/issues)
- [ ] Searched the problem in [discussions](https://github.com/emsesp/EMS-ESP32/discussions)
- [ ] 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 :
**Additional context**
*Add any other context about the problem here.*
```lua
System information output 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)**

11
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@@ -0,0 +1,11 @@
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

@@ -1,26 +0,0 @@
---
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

@@ -1,29 +0,0 @@
---
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
.directory
workspace.code-workspace
# build
build/

View File

@@ -5,6 +5,88 @@ 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.5.1] March 11 2023
## 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
# [3.5.0] February 6 2023
## **IMPORTANT! BREAKING CHANGES**
- When upgrading to v3.5 for the first time from v3.4 on a BBQKees Gateway board you will need to use the [EMS-EPS Flasher](https://github.com/emsesp/EMS-ESP-Flasher/releases) to correctly re-partition the flash. Make sure you backup the settings and customizations from the WebUI (System->Upload/Download) and restore after the upgrade.
- Support for multiple EMS-ESPs [#759] has been added as an optional setting for MQTT. When enabled, which is now the default, all MQTT Discovery Entity IDs will include the MQTT base name and the shortname of the EMS-ESP device entity. For example what was previously `sensor.boiler_actual_boiler_temperature` will now become `sensor.ems_esp_boiler_boiltemp`. If you still want to use the old format and retain the history and script compatibility in Home Assistant then set this back to the old format.
## Added
- Translations in Web UI and all device entity names (DE, NL, SV, PL, NO, FR) [#22](https://github.com/emsesp/EMS-ESP32/issues/22)
- Add support for Lolin C3 mini [#620](https://github.com/emsesp/EMS-ESP32/pull/620)
- Add support for ESP32-S2 [#667](https://github.com/emsesp/EMS-ESP32/pull/667)
- Add devices: Greenstar 30Ri boiler, Junkers FW500 thermostat, Buderus BC30 controller
- Add program memory info
- Add mqtt queue and connection infos
- Adapt min/max if ems-value is not in this range
- Add heat pump settings for inputs and limits [#600](https://github.com/emsesp/EMS-ESP32/issues/600)
- Add hybrid heatpump [#500](https://github.com/emsesp/EMS-ESP32/issues/500)
- Add translated tags
- Add min/max to customization table [#686](https://github.com/emsesp/EMS-ESP32/issues/686)
- Add MD5 check [#637](https://github.com/emsesp/EMS-ESP32/issues/637)
- Add more bus-ids [#673](https://github.com/emsesp/EMS-ESP32/issues/673)
- Use HA connectivity device class for Status, added boot time [#751](https://github.com/emsesp/EMS-ESP32/issues/751)
- Add commands for analog sensors outputs
- Support for multiple EMS-ESPs with MQTT and HA [[#759](https://github.com/emsesp/EMS-ESP32/issues/759)]
- Settings for heatpump silent mode and additional heater [[#802](https://github.com/emsesp/EMS-ESP32/issues/802)] [[#803](https://github.com/emsesp/EMS-ESP32/issues/803)]
- Zone module MZ100 [#826](https://github.com/emsesp/EMS-ESP32/issues/826)
- Default MQTT hostname is blank [#829](https://github.com/emsesp/EMS-ESP32/issues/829)
- wwCurFlow for ems+ devices [#829](https://github.com/emsesp/EMS-ESP32/issues/829)
- Add Rego 3000, TR120RF thermostats [#917](https://github.com/emsesp/EMS-ESP32/issues/917)
- Add config for ESP32-S3
- Add heatpump silent mode and other entities [#896](https://github.com/emsesp/EMS-ESP32/issues/896)
- Allow reboot to other partition (factory or asymetric OTA)
- Blacklist entities to remove from memory [#891](https://github.com/emsesp/EMS-ESP32/issues/891)
- Add boiler pump operating mode [#944](https://github.com/emsesp/EMS-ESP32/issues/944)
## Fixed
- Factory Reset not working [#628](https://github.com/emsesp/EMS-ESP32/issues/628)
- Valid 4 byte values [#820](https://github.com/emsesp/EMS-ESP32/issues/820)
- Commands for multiple thermostats [#826](https://github.com/emsesp/EMS-ESP32/issues/826)
- API queries for multiple devices [#865](https://github.com/emsesp/EMS-ESP32/issues/865)
- Console crash when using call with command `hcx` only. [#841](https://github.com/emsesp/EMS-ESP32/issues/841)
- `heatingPump2Mod` was wrong, changed to absBurnPow [[#908](https://github.com/emsesp/EMS-ESP32/issues/908)
- Rounding of web input values
- Analog sensor with single gpio number [#915](https://github.com/emsesp/EMS-ESP32/issues/915)
- HA dallas and analog configs: remove/rebuild on change [#888](https://github.com/emsesp/EMS-ESP32/issues/888)
- Modes and set seltemp for RC30 and RC20 [#932](https://github.com/emsesp/EMS-ESP32/issues/932)
## Changed
- Discovery in HomeAssistant don't work with custom base topic. [#596](https://github.com/emsesp/EMS-ESP32/issues/596) Base topic containing `/` are changed to `_`
- RF room temperature sensor are shown as thermostat
- Render mqtt float json values with trailing zero
- Removed flash strings, to increase available heap memory
- Reload page after restart button is pressed
- Analog/dallas values command as list like ems-devices
- Analog/dallas HA-entities based on id
- MQTT Base is a mandatory field. Removed MQTT topic length from settings
- 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)
# [3.4.2] September 18 2022
## Added
@@ -41,10 +123,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## 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
## Added

View File

@@ -1,63 +1,2 @@
# Changelog
# [3.5.0]
## **IMPORTANT! BREAKING CHANGES**
- When upgrading to v3.5 for the first time from v3.4 on a BBQKees Gateway board you will need to use the [EMS-EPS Flasher](https://github.com/emsesp/EMS-ESP-Flasher/releases) to correctly re-partition the flash. Make sure you backup the settings and customizations from the WebUI (System->Upload/Download) and restore after the upgrade.
- Support for multiple EMS-ESPs [#759] has been added as an optional setting for MQTT. When enabled, which is now the default, all MQTT Discovery Entity IDs will include the MQTT base name and the shortname of the EMS-ESP device entity. For example what was previously `sensor.boiler_actual_boiler_temperature` will now become `sensor.ems_esp_boiler_boiltemp`. If you still want to use the old format and retain the history and script compatibility in Home Assistant then set this back to the old format.
## Added
- Translations in Web UI and all device entity names (DE, NL, SV, PL, NO, FR) [#22](https://github.com/emsesp/EMS-ESP32/issues/22)
- Add support for Lolin C3 mini [#620](https://github.com/emsesp/EMS-ESP32/pull/620)
- Add support for ESP32-S2 [#667](https://github.com/emsesp/EMS-ESP32/pull/667)
- Add devices: Greenstar 30Ri boiler, Junkers FW500 thermostat, Buderus BC30 controller
- Add program memory info
- Add mqtt queue and connection infos
- Adapt min/max if ems-value is not in this range
- Add heat pump settings for inputs and limits [#600](https://github.com/emsesp/EMS-ESP32/issues/600)
- Add hybrid heatpump [#500](https://github.com/emsesp/EMS-ESP32/issues/500)
- Add translated tags
- Add min/max to customization table [#686](https://github.com/emsesp/EMS-ESP32/issues/686)
- Add MD5 check [#637](https://github.com/emsesp/EMS-ESP32/issues/637)
- Add more bus-ids [#673](https://github.com/emsesp/EMS-ESP32/issues/673)
- Use HA connectivity device class for Status, added boot time [#751](https://github.com/emsesp/EMS-ESP32/issues/751)
- Add commands for analog sensors outputs
- Support for multiple EMS-ESPs with MQTT and HA [[#759](https://github.com/emsesp/EMS-ESP32/issues/759)]
- Settings for heatpump silent mode and additional heater [[#802](https://github.com/emsesp/EMS-ESP32/issues/802)] [[#803](https://github.com/emsesp/EMS-ESP32/issues/803)]
- Zone module MZ100 [#826](https://github.com/emsesp/EMS-ESP32/issues/826)
- Default MQTT hostname is blank [#829](https://github.com/emsesp/EMS-ESP32/issues/829)
- wwCurFlow for ems+ devices [#829](https://github.com/emsesp/EMS-ESP32/issues/829)
- Add Rego 3000, TR120RF thermostats [#917](https://github.com/emsesp/EMS-ESP32/issues/917)
- Add config for ESP32-S3
- Add heatpump silent mode and other entities [#896](https://github.com/emsesp/EMS-ESP32/issues/896)
- Allow reboot to other partition (factory or asymetric OTA)
- Blacklist entities to remove from memory [#891](https://github.com/emsesp/EMS-ESP32/issues/891)
- Add boiler pump operating mode [#944](https://github.com/emsesp/EMS-ESP32/issues/944)
## Fixed
- Factory Reset not working [#628](https://github.com/emsesp/EMS-ESP32/issues/628)
- Valid 4 byte values [#820](https://github.com/emsesp/EMS-ESP32/issues/820)
- Commands for multiple thermostats [#826](https://github.com/emsesp/EMS-ESP32/issues/826)
- API queries for multiple devices [#865](https://github.com/emsesp/EMS-ESP32/issues/865)
- Console crash when using call with command `hcx` only. [#841](https://github.com/emsesp/EMS-ESP32/issues/841)
- `heatingPump2Mod` was wrong, changed to absBurnPow [[#908](https://github.com/emsesp/EMS-ESP32/issues/908)
- Rounding of web input values
- Analog sensor with single gpio number [#915](https://github.com/emsesp/EMS-ESP32/issues/915)
- HA dallas and analog configs: remove/rebuild on change [#888](https://github.com/emsesp/EMS-ESP32/issues/888)
- Modes and set seltemp for RC30 and RC20 [#932](https://github.com/emsesp/EMS-ESP32/issues/932)
## Changed
- Discovery in HomeAssistant don't work with custom base topic. [#596](https://github.com/emsesp/EMS-ESP32/issues/596) Base topic containing `/` are changed to `_`
- RF room temperature sensor are shown as thermostat
- Render mqtt float json values with trailing zero
- Removed flash strings, to increase available heap memory
- Reload page after restart button is pressed
- Analog/dallas values command as list like ems-devices
- Analog/dallas HA-entities based on id
- MQTT Base is a mandatory field. Removed MQTT topic length from settings
- 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)

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

@@ -127,6 +127,7 @@ const fr: Translation = {
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)',
UNDERCLOCK_CPU: 'Underclock du CPU',
HEATINGOFF: 'Start boiler with forced heating off',
ENABLE_SHOWER_TIMER: 'Activer la minuterie de la douche',
ENABLE_SHOWER_ALERT: 'Activer les alertes de durée de douche',
TRIGGER_TIME: 'Durée avant déclenchement',

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -408,6 +408,11 @@ const SettingsApplication: FC = () => {
label={LL.UNDERCLOCK_CPU()}
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">
<BlockFormControlLabel
control={<Checkbox checked={data.shower_timer} onChange={updateFormValue} name="shower_timer" />}

View File

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

View File

@@ -77,7 +77,7 @@ void UploadFileService::handleUpload(AsyncWebServerRequest * request, const Stri
}
#endif
// it's firmware - initialize the ArduinoOTA updater
if (Update.begin(fsize)) {
if (Update.begin()) {
if (strlen(md5) == 32) {
Update.setMD5(md5);
md5[0] = '\0';

View File

@@ -13,8 +13,8 @@
"compression": "^1.7.4",
"express": "^4.18.2",
"express-sse": "^0.5.3",
"nodemon": "^2.0.20",
"ws": "^8.12.0"
"nodemon": "^2.0.21",
"ws": "^8.13.0"
}
},
"node_modules/@msgpack/msgpack": {
@@ -643,9 +643,9 @@
}
},
"node_modules/nodemon": {
"version": "2.0.20",
"resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.20.tgz",
"integrity": "sha512-Km2mWHKKY5GzRg6i1j5OxOHQtuvVsgskLfigG25yTtbyfRGn/GNvIbRyOf1PSCKJ2aT/58TiuUsuOU5UToVViw==",
"version": "2.0.21",
"resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.21.tgz",
"integrity": "sha512-djN/n2549DUtY33S7o1djRCd7dEm0kBnj9c7S9XVXqRUbuggN1MZH/Nqa+5RFQr63Fbefq37nFXAE9VU86yL1A==",
"dependencies": {
"chokidar": "^3.5.2",
"debug": "^3.2.7",
@@ -1015,9 +1015,9 @@
}
},
"node_modules/ws": {
"version": "8.12.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.12.0.tgz",
"integrity": "sha512-kU62emKIdKVeEIOIKVegvqpXMSTAMLJozpHZaJNDYqBjzlSYXQGviYwN1osDLJ9av68qHd4a2oSjd7yD4pacig==",
"version": "8.13.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz",
"integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==",
"engines": {
"node": ">=10.0.0"
},

View File

@@ -15,7 +15,7 @@
"compression": "^1.7.4",
"express": "^4.18.2",
"express-sse": "^0.5.3",
"nodemon": "^2.0.20",
"ws": "^8.12.0"
"nodemon": "^2.0.21",
"ws": "^8.13.0"
}
}

View File

@@ -68,7 +68,7 @@ void AnalogSensor::reload() {
analog_enabled_ = true; // for local offline testing
#endif
for (auto sensor : sensors_) {
remove_ha_topic(sensor.gpio());
remove_ha_topic(sensor.type(), sensor.gpio());
sensor.ha_registered = false;
}
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 (found_sensor && Mqtt::ha_enabled()) {
remove_ha_topic(gpio); // the GPIO
remove_ha_topic(type, gpio); // the GPIO
}
// 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
void AnalogSensor::remove_ha_topic(const uint8_t gpio) const {
void AnalogSensor::remove_ha_topic(const int8_t type, const uint8_t gpio) const {
if (!Mqtt::ha_enabled()) {
return;
}
@@ -392,7 +392,21 @@ void AnalogSensor::remove_ha_topic(const uint8_t gpio) const {
LOG_DEBUG("Removing HA config for analog sensor GPIO %02d", gpio);
#endif
char topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
snprintf(topic, sizeof(topic), "sensor/%s/analogsensor_%02d/config", Mqtt::basename().c_str(), gpio);
#if CONFIG_IDF_TARGET_ESP32
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);
}
@@ -447,13 +461,16 @@ void AnalogSensor::publish_values(const bool force) {
snprintf(stat_t, sizeof(stat_t), "%s/analogsensor_data", Mqtt::base().c_str()); // use base path
config["stat_t"] = stat_t;
char str[50];
char val_obj[50];
char val_cond[65];
if (Mqtt::is_nested()) {
snprintf(str, sizeof(str), "{{value_json['%02d'].value}}", sensor.gpio());
snprintf(val_obj, sizeof(val_obj), "value_json['%02d'].value", sensor.gpio());
snprintf(val_cond, sizeof(val_cond), "value_json['%02d'] is defined", sensor.gpio());
} else {
snprintf(str, sizeof(str), "{{value_json['%s']}", sensor.name().c_str());
snprintf(val_obj, sizeof(val_obj), "value_json['%s']", sensor.name().c_str());
snprintf(val_cond, sizeof(val_cond), "%s is defined", val_obj);
}
config["val_tpl"] = str;
config["val_tpl"] = (std::string) "{{" + val_obj + " if " + val_cond + "}}";
char uniq_s[70];
if (Mqtt::entity_format() == 2) {
@@ -462,22 +479,76 @@ void AnalogSensor::publish_values(const bool force) {
snprintf(uniq_s, sizeof(uniq_s), "analogsensor_%02d", sensor.gpio());
}
config["object_id"] = uniq_s;
config["uniq_id"] = uniq_s; // same as object_id
config["obj_id"] = uniq_s;
config["uniq_id"] = uniq_s; // same as object_id
snprintf(str, sizeof(str), "%s", sensor.name().c_str());
config["name"] = str;
char name[50];
snprintf(name, sizeof(name), "%s", sensor.name().c_str());
config["name"] = name;
if (sensor.uom() != DeviceValueUOM::NONE) {
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");
JsonArray ids = dev.createNestedArray("ids");
ids.add("ems-esp");
char topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
snprintf(topic, sizeof(topic), "sensor/%s/analogsensor_%02d/config", Mqtt::basename().c_str(), sensor.gpio());
// add "availability" section
Mqtt::add_avty_to_doc(stat_t, config.as<JsonObject>(), val_cond);
Mqtt::publish_ha(topic, config.as<JsonObject>());

View File

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

View File

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

View File

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

View File

@@ -100,7 +100,12 @@ 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
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);
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, &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));
@@ -875,6 +880,11 @@ void Boiler::check_active(const bool force) {
Mqtt::publish(F_(tapwater_active), Helpers::render_boolean(s, b));
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
@@ -1075,6 +1085,11 @@ void Boiler::process_UBAMonitorSlow(std::shared_ptr<const Telegram> telegram) {
has_update(telegram, burn2WorkMin_, 16, 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
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);
}
}
/*
@@ -1105,6 +1120,11 @@ void Boiler::process_UBAMonitorSlowPlus(std::shared_ptr<const Telegram> telegram
has_update(telegram, heatStarts_, 22, 3); // force to 3 bytes
has_update(telegram, heatingPumpMod_, 25);
// 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);
}
}
/*
@@ -1711,7 +1731,9 @@ 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
// put it to end of tx-queue
if (v == selFlowTemp_) {
EMSESP::txservice_.add(Telegram::Operation::TX_WRITE, device_id(), EMS_TYPE_UBASetPoints, 0, (uint8_t *) &v, 1, 0, false);
return true;
}
@@ -2574,4 +2596,17 @@ bool Boiler::set_wwAltOpPrio(const char * value, const int8_t id) {
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

View File

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

View File

@@ -32,14 +32,25 @@ 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(0x9A0, "HPTemperature", false, MAKE_PF_CB(process_HPTemperature));
register_telegram_type(0x99B, "HPFlowTemp", false, MAKE_PF_CB(process_HPFlowTemp));
register_telegram_type(0x99C, "HPComp", false, MAKE_PF_CB(process_HPComp));
// device values
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, &flowTemp_, DeviceValueType::UINT, FL_(curFlowTemp), DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &retTemp_, DeviceValueType::UINT, FL_(retTemp), DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &sysRetTemp_, DeviceValueType::UINT, FL_(sysRetTemp), DeviceValueUOM::DEGREES);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
&flowTemp_,
DeviceValueType::SHORT,
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, &hpTr1_, DeviceValueType::SHORT, DeviceValueNumOp::DV_NUMOP_DIV10, FL_(hpTr1), DeviceValueUOM::DEGREES);
@@ -51,6 +62,9 @@ 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, &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,
&controlStrategy_,
DeviceValueType::ENUM,
@@ -177,6 +191,7 @@ void Heatpump::process_HPFlowTemp(std::shared_ptr<const Telegram> telegram) {
has_update(telegram, flowTemp_, 4);
has_update(telegram, retTemp_, 6);
has_update(telegram, sysRetTemp_, 14);
has_update(telegram, heatingPumpMod_, 19);
}
// 0x0998 HPSettings
@@ -193,6 +208,14 @@ void Heatpump::process_HPSettings(std::shared_ptr<const Telegram> telegram) {
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) {
has_update(telegram, airPurgeMode_, 0);
has_update(telegram, heatPumpOutput_, 2);

View File

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

View File

@@ -317,6 +317,7 @@ Solar::Solar(uint8_t device_type, uint8_t device_id, uint8_t product_id, const c
DeviceValueUOM::DEGREES);
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, &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, &collectorShutdown_, DeviceValueType::BOOL, FL_(collectorShutdown), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
@@ -820,6 +821,7 @@ 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)
*/
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, solarPump_, 10, 2); // on if bit 2 set
has_bitupdate(telegram, solarPump2_, 1, 2); // on if bit 2 set

View File

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

View File

@@ -1192,14 +1192,9 @@ 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
void Thermostat::process_RC35Monitor(std::shared_ptr<const Telegram> telegram) {
// exit if the 15th byte (second from last) is 0x00, which I think is calculated flow setpoint temperature
// with weather controlled RC35s this value is >=5, otherwise can be zero and our setpoint temps will be incorrect
// 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) {
// Check if heatingciruit is active, see https://github.com/emsesp/EMS-ESP32/issues/786
uint16_t active = 0;
if (!telegram->read_value(active, 3)) {
return;
}

View File

@@ -1642,22 +1642,6 @@ bool EMSdevice::generate_values(JsonObject & output, const uint8_t tag_filter, c
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
// 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() {
@@ -1686,6 +1670,9 @@ void EMSdevice::mqtt_ha_entity_config_create() {
dv.add_state(DeviceValueState::DV_HA_CONFIG_CREATED);
create_device_config = false; // only create the main config once
}
if (ESP.getFreeHeap() < (65 * 1024)) {
break;
}
}
ha_config_done(!create_device_config);
@@ -1694,7 +1681,6 @@ void EMSdevice::mqtt_ha_entity_config_create() {
// remove all config topics in HA
void EMSdevice::ha_config_clear() {
for (auto & dv : devicevalues_) {
Mqtt::publish_ha_sensor_config(dv, "", "", true); // delete topic (remove = true)
dv.remove_state(DeviceValueState::DV_HA_CONFIG_CREATED);
}

View File

@@ -289,7 +289,6 @@ class EMSdevice {
void publish_all_values();
void mqtt_ha_entity_config_create();
void mqtt_ha_entity_config_remove();
std::string telegram_type_name(std::shared_ptr<const Telegram> telegram) const;
@@ -306,13 +305,6 @@ class EMSdevice {
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 {
NO_BRAND = 0, // 0
BOSCH, // 1
@@ -366,6 +358,7 @@ class EMSdevice {
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_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
static constexpr uint16_t EMS_TYPE_VERSION = 0x02; // type ID for Version information. Generic across all EMS devices.
@@ -431,7 +424,6 @@ class EMSdevice {
bool ha_config_done_ = false;
bool has_update_ = false;
bool ha_config_firstrun_ = true; // this means a first setup of HA is needed after a restart
struct TelegramFunction {
uint16_t telegram_type_id_; // it's type_id

View File

@@ -535,24 +535,6 @@ void EMSESP::publish_device_values(uint8_t device_type) {
bool nested = (Mqtt::is_nested());
// 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++) {
JsonObject json_hc = json;
bool nest_created = false;
@@ -1057,7 +1039,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
name = "RF room temperature sensor";
device_type = DeviceType::THERMOSTAT;
} else if (device_id == EMSdevice::EMS_DEVICE_ID_ROOMTHERMOSTAT) {
} else if (device_id == EMSdevice::EMS_DEVICE_ID_ROOMTHERMOSTAT || device_id == EMSdevice::EMS_DEVICE_ID_TADO_OLD) {
name = "Generic thermostat";
device_type = DeviceType::THERMOSTAT;
flags = DeviceFlags::EMS_DEVICE_FLAG_RC10 | DeviceFlags::EMS_DEVICE_FLAG_NO_WRITE;

View File

@@ -269,6 +269,7 @@ MAKE_PSTR_LIST(cyl2, "cyl 2", "Zyl_2", "Cil 2", "Cyl 2", "cyl 2", "cyl 2", "cyl
// Entity translations
// 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(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")
@@ -683,6 +684,7 @@ 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(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(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(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")

View File

@@ -685,7 +685,7 @@ std::shared_ptr<const MqttMessage> Mqtt::queue_message(const uint8_t operation,
#endif
// if the queue is full, make room but removing the last one
if (mqtt_messages_.size() >= MAX_MQTT_MESSAGES) {
if (mqtt_messages_.size() >= MAX_MQTT_MESSAGES || ESP.getFreeHeap() < (60 * 1024)) {
mqtt_messages_.pop_front();
LOG_WARNING("Queue overflow, removing one message");
mqtt_publish_fails_++;
@@ -1074,6 +1074,8 @@ void Mqtt::publish_ha_sensor_config(uint8_t type, // EMSdev
const char * sc_ha = "stat_cla"; // state class
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
// 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
@@ -1093,6 +1095,7 @@ void Mqtt::publish_ha_sensor_config(uint8_t type, // EMSdev
for (uint8_t i = 0; i < options_size; 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) {
// Must be Numeric....
doc["mode"] = "box"; // auto, slider or box
@@ -1109,6 +1112,7 @@ void Mqtt::publish_ha_sensor_config(uint8_t type, // EMSdev
if (dv_set_min != 0 || dv_set_max != 0) {
doc["min"] = dv_set_min;
doc["max"] = dv_set_max;
snprintf(sample_val, sizeof(sample_val), "%i", dv_set_min);
}
// set icons
@@ -1146,17 +1150,15 @@ void Mqtt::publish_ha_sensor_config(uint8_t type, // EMSdev
// value template
// if its nested mqtt format then use the appended entity name, otherwise take the original name
char val_tpl[75];
if (is_nested()) {
if (tag >= DeviceValueTAG::TAG_HC1) {
snprintf(val_tpl, sizeof(val_tpl), "{{value_json.%s.%s}}", EMSdevice::tag_to_mqtt(tag).c_str(), entity);
} else {
snprintf(val_tpl, sizeof(val_tpl), "{{value_json.%s}}", entity);
}
char val_obj[100];
char val_cond[200];
if (is_nested() && tag >= DeviceValueTAG::TAG_HC1) {
snprintf(val_obj, sizeof(val_obj), "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);
snprintf(val_obj, sizeof(val_obj), "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
// applies to both Binary Sensor (read only) and a Switch (for a command)
@@ -1165,6 +1167,7 @@ void Mqtt::publish_ha_sensor_config(uint8_t type, // EMSdev
if (EMSESP::system_.bool_format() == BOOL_FORMAT_TRUEFALSE) {
doc["pl_on"] = true;
doc["pl_off"] = false;
snprintf(sample_val, sizeof(sample_val), "false");
} else if (EMSESP::system_.bool_format() == BOOL_FORMAT_10) {
doc["pl_on"] = 1;
doc["pl_off"] = 0;
@@ -1172,6 +1175,7 @@ void Mqtt::publish_ha_sensor_config(uint8_t type, // EMSdev
char result[12];
doc["pl_on"] = Helpers::render_boolean(result, true);
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???
} else {
@@ -1189,6 +1193,8 @@ 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
// used for Sensor and Binary Sensor Entities in HA
if (set_ha_classes) {
@@ -1284,6 +1290,9 @@ void Mqtt::publish_ha_sensor_config(uint8_t type, // EMSdev
// add the dev json object to the end
doc["dev"] = dev_json;
// add "availability" section
add_avty_to_doc(stat_t, doc.as<JsonObject>(), val_cond);
publish_ha(topic, doc.as<JsonObject>());
}
@@ -1295,6 +1304,9 @@ void Mqtt::publish_ha_climate_config(const uint8_t tag, const bool has_roomtemp,
char hc_mode_s[30];
char seltemp_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 name_s[10];
char uniq_id_s[60];
@@ -1312,24 +1324,31 @@ void Mqtt::publish_ha_climate_config(const uint8_t tag, const bool has_roomtemp,
if (Mqtt::is_nested()) {
// nested format
snprintf(hc_mode_s, sizeof(hc_mode_s), "value_json.hc%d.mode", hc_num);
snprintf(seltemp_s, sizeof(seltemp_s), "{{value_json.hc%d.seltemp}}", 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_cond, sizeof(seltemp_cond), "value_json.hc%d is defined and %s is defined", hc_num, seltemp_s);
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());
} else {
// single format
snprintf(hc_mode_s, sizeof(hc_mode_s), "value_json.mode");
snprintf(seltemp_s, sizeof(seltemp_s), "{{value_json.seltemp}}");
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_cond, sizeof(seltemp_cond), "%s is defined", seltemp_s);
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(mode_str_tpl,
sizeof(mode_str_tpl),
"{%%if %s=='manual'%%}heat{%%elif %s=='day'%%}heat{%%elif %s=='night'%%}off{%%elif %s=='off'%%}off{%%else%%}auto{%%endif%%}",
"{%%if %s%%}off{%%elif %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,
@@ -1346,7 +1365,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(mode_cmd_s, sizeof(temp_cmd_s), "~/thermostat/hc%d/mode", hc_num);
StaticJsonDocument<EMSESP_JSON_SIZE_HA_CONFIG> doc;
StaticJsonDocument<EMSESP_JSON_SIZE_HA_CONFIG + 512> doc;
doc["~"] = mqtt_base_;
doc["uniq_id"] = uniq_id_s;
@@ -1356,12 +1375,10 @@ void Mqtt::publish_ha_climate_config(const uint8_t tag, const bool has_roomtemp,
doc["mode_stat_tpl"] = mode_str_tpl;
doc["temp_cmd_t"] = temp_cmd_s;
doc["temp_stat_t"] = topic_t;
doc["temp_stat_tpl"] = seltemp_s;
doc["mode_cmd_t"] = mode_cmd_s;
doc["temp_stat_tpl"] = (std::string) "{{" + seltemp_s + " if " + seltemp_cond + " else 0}}";
if (has_roomtemp) {
doc["curr_temp_t"] = topic_t;
doc["curr_temp_tpl"] = currtemp_s;
doc["curr_temp_tpl"] = (std::string) "{{" + currtemp_s + " if " + currtemp_cond + " else 0}}";
}
doc["min_temp"] = Helpers::render_value(min_s, min, 0, EMSESP::system_.fahrenheit() ? 2 : 0);
@@ -1369,8 +1386,8 @@ void Mqtt::publish_ha_climate_config(const uint8_t tag, const bool has_roomtemp,
doc["temp_step"] = "0.5";
// the HA climate component only responds to auto, heat and off
JsonArray modes = doc.createNestedArray("modes");
doc["mode_cmd_t"] = mode_cmd_s;
JsonArray modes = doc.createNestedArray("modes");
modes.add("auto");
modes.add("heat");
modes.add("off");
@@ -1379,6 +1396,9 @@ void Mqtt::publish_ha_climate_config(const uint8_t tag, const bool has_roomtemp,
JsonArray ids = dev.createNestedArray("ids");
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
}
@@ -1401,4 +1421,41 @@ 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

View File

@@ -240,6 +240,9 @@ class Mqtt {
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 {
const uint32_t id_;
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;
if (EMSESP::system_.bool_format() == BOOL_FORMAT_TRUEFALSE) {
doc["pl_on"] = true;
doc["pl_off"] = false;
doc["pl_on"] = "true";
doc["pl_off"] = "false";
} else if (EMSESP::system_.bool_format() == BOOL_FORMAT_10) {
doc["pl_on"] = 1;
doc["pl_off"] = 0;
@@ -183,6 +183,9 @@ void Shower::set_shower_state(bool state, bool force) {
JsonArray ids = dev.createNestedArray("ids");
ids.add("ems-esp");
// add "availability" section
Mqtt::add_avty_to_doc(stat_t, doc.as<JsonObject>());
char topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
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

View File

@@ -1 +1 @@
#define EMSESP_APP_VERSION "3.5.0-dev.18"
#define EMSESP_APP_VERSION "3.5.1"

View File

@@ -136,7 +136,7 @@ void WebLogService::operator<<(std::shared_ptr<uuid::log::Message> message) {
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) {
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
void WebLogService::transmit(const QueuedLogMessage & message) {
auto jsonDocument = DynamicJsonDocument(EMSESP_JSON_SIZE_MEDIUM);
JsonObject logEvent = jsonDocument.to<JsonObject>();
char time_string[25];
StaticJsonDocument<EMSESP_JSON_SIZE_MEDIUM> jsonDocument;
JsonObject logEvent = jsonDocument.to<JsonObject>();
char time_string[25];
logEvent["t"] = messagetime(time_string, message.content_->uptime_ms, sizeof(time_string));
logEvent["l"] = message.content_->level;
@@ -212,34 +212,11 @@ void WebLogService::transmit(const QueuedLogMessage & message) {
// send the complete log buffer to the API, not filtering on log level
void WebLogService::fetchLog(AsyncWebServerRequest * request) {
// auto * response = new MsgpackAsyncJsonResponse(false, EMSESP_JSON_SIZE_LARGE_DYN + 192 * log_messages_.size());
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);
log_message_id_tail_ = 0;
request->send(200);
}
// sets the values like level after a POST
void WebLogService::setValues(AsyncWebServerRequest * request, JsonVariant & json) {
if (!json.is<JsonObject>()) {

View File

@@ -47,6 +47,7 @@ void WebSettings::read(WebSettings & settings, JsonObject & root) {
root["syslog_mark_interval"] = settings.syslog_mark_interval;
root["syslog_host"] = settings.syslog_host;
root["syslog_port"] = settings.syslog_port;
root["boiler_heatingoff"] = settings.boiler_heatingoff;
root["shower_timer"] = settings.shower_timer;
root["shower_alert"] = settings.shower_alert;
root["shower_alert_coldshot"] = settings.shower_alert_coldshot;
@@ -240,15 +241,6 @@ StateUpdateResult WebSettings::update(JsonObject & root, WebSettings & settings)
settings.low_clock = root["low_clock"] | false;
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
//
@@ -267,11 +259,15 @@ StateUpdateResult WebSettings::update(JsonObject & root, WebSettings & settings)
//
// without checks or necessary restarts...
//
settings.locale = root["locale"] | EMSESP_DEFAULT_LOCALE;
EMSESP::system_.locale(settings.locale);
settings.trace_raw = root["trace_raw"] | EMSESP_DEFAULT_TRACELOG_RAW;
EMSESP::trace_raw(settings.trace_raw);
settings.notoken_api = root["notoken_api"] | EMSESP_DEFAULT_NOTOKEN_API;
settings.solar_maxflow = root["solar_maxflow"] | EMSESP_DEFAULT_SOLAR_MAXFLOW;
settings.notoken_api = root["notoken_api"] | EMSESP_DEFAULT_NOTOKEN_API;
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;
EMSESP::system_.fahrenheit(settings.fahrenheit);

View File

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