Merge pull request #2554 from MichaelDvP/dev

fixes and additions
This commit is contained in:
Proddy
2025-05-16 08:03:03 +02:00
committed by GitHub
33 changed files with 1358 additions and 369 deletions

View File

@@ -11,6 +11,9 @@ For more details go to [docs.emsesp.org](https://docs.emsesp.org/).
- boiler auxheatersource [#2489](https://github.com/emsesp/EMS-ESP32/discussions/2489) - boiler auxheatersource [#2489](https://github.com/emsesp/EMS-ESP32/discussions/2489)
- thermostat last error for RC100/300 [#2501](https://github.com/emsesp/EMS-ESP32/issues/2501) - thermostat last error for RC100/300 [#2501](https://github.com/emsesp/EMS-ESP32/issues/2501)
- boiler 0xC6 telegram [#1963](https://github.com/emsesp/EMS-ESP32/issues/1963) - boiler 0xC6 telegram [#1963](https://github.com/emsesp/EMS-ESP32/issues/1963)
- HA optimistic [#2551](https://github.com/emsesp/EMS-ESP32/issues/2551)
- CS6800i changes [#2448](https://github.com/emsesp/EMS-ESP32/issues/2448), [#2449](https://github.com/emsesp/EMS-ESP32/issues/2449)
- charging pump [#2544](https://github.com/emsesp/EMS-ESP32/issues/2544)
## Fixed ## Fixed
@@ -21,6 +24,7 @@ For more details go to [docs.emsesp.org](https://docs.emsesp.org/).
- also rebuild HA config on mqtt connect for scheduler, custom and shower - also rebuild HA config on mqtt connect for scheduler, custom and shower
- FB100 controls the hc, not the master [#2510](https://github.com/emsesp/EMS-ESP32/issues/2510) - FB100 controls the hc, not the master [#2510](https://github.com/emsesp/EMS-ESP32/issues/2510)
- IPM DHW module, [#2524](https://github.com/emsesp/EMS-ESP32/issues/2524) - IPM DHW module, [#2524](https://github.com/emsesp/EMS-ESP32/issues/2524)
- charge optimization [#2543](https://github.com/emsesp/EMS-ESP32/issues/2543)
## Changed ## Changed

View File

@@ -24,41 +24,41 @@
"@alova/adapter-xhr": "2.1.1", "@alova/adapter-xhr": "2.1.1",
"@emotion/react": "^11.14.0", "@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.0", "@emotion/styled": "^11.14.0",
"@mui/icons-material": "^7.0.2", "@mui/icons-material": "^7.1.0",
"@mui/material": "^7.0.2", "@mui/material": "^7.1.0",
"@table-library/react-table-library": "4.1.15", "@table-library/react-table-library": "4.1.15",
"formidable": "^3.5.4",
"alova": "3.2.10", "alova": "3.2.10",
"async-validator": "^4.2.5", "async-validator": "^4.2.5",
"formidable": "^3.5.4",
"jwt-decode": "^4.0.0", "jwt-decode": "^4.0.0",
"magic-string": "^0.30.17", "magic-string": "^0.30.17",
"mime-types": "^3.0.1", "mime-types": "^3.0.1",
"preact": "^10.26.5", "preact": "^10.26.6",
"react": "^19.1.0", "react": "^19.1.0",
"react-dom": "^19.1.0", "react-dom": "^19.1.0",
"react-icons": "^5.5.0", "react-icons": "^5.5.0",
"react-router": "^7.5.1", "react-router": "^7.6.0",
"react-toastify": "^11.0.5", "react-toastify": "^11.0.5",
"typesafe-i18n": "^5.26.2", "typesafe-i18n": "^5.26.2",
"typescript": "^5.8.3" "typescript": "^5.8.3"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.26.10", "@babel/core": "^7.27.1",
"@eslint/js": "^9.25.1", "@eslint/js": "^9.26.0",
"@preact/compat": "^18.3.1", "@preact/compat": "^18.3.1",
"@preact/preset-vite": "^2.10.1", "@preact/preset-vite": "^2.10.1",
"@trivago/prettier-plugin-sort-imports": "^5.2.2", "@trivago/prettier-plugin-sort-imports": "^5.2.2",
"@types/node": "^22.14.1", "@types/node": "^22.15.17",
"@types/react": "^19.1.2", "@types/react": "^19.1.3",
"@types/react-dom": "^19.1.2", "@types/react-dom": "^19.1.3",
"concurrently": "^9.1.2", "concurrently": "^9.1.2",
"eslint": "^9.25.1", "eslint": "^9.26.0",
"eslint-config-prettier": "^10.1.2", "eslint-config-prettier": "^10.1.5",
"prettier": "^3.5.3", "prettier": "^3.5.3",
"rollup-plugin-visualizer": "^5.14.0", "rollup-plugin-visualizer": "^5.14.0",
"terser": "^5.39.0", "terser": "^5.39.0",
"typescript-eslint": "8.31.0", "typescript-eslint": "8.32.0",
"vite": "^6.3.2", "vite": "^6.3.5",
"vite-plugin-imagemin": "^0.6.1", "vite-plugin-imagemin": "^0.6.1",
"vite-tsconfig-paths": "^5.1.4" "vite-tsconfig-paths": "^5.1.4"
}, },

View File

@@ -143,7 +143,8 @@ export const readCustomEntities = () =>
o_name: ei.name, o_name: ei.name,
o_writeable: ei.writeable, o_writeable: ei.writeable,
o_value: ei.value, o_value: ei.value,
o_deleted: ei.deleted o_deleted: ei.deleted,
o_hide: ei.hide
})); }));
} }
}); });

View File

@@ -76,6 +76,7 @@ const CustomEntities = () => {
ei.factor !== ei.o_factor || ei.factor !== ei.o_factor ||
ei.value_type !== ei.o_value_type || ei.value_type !== ei.o_value_type ||
ei.writeable !== ei.o_writeable || ei.writeable !== ei.o_writeable ||
ei.hide !== ei.o_hide ||
ei.deleted !== ei.o_deleted || ei.deleted !== ei.o_deleted ||
(ei.value || '') !== (ei.o_value || '') (ei.value || '') !== (ei.o_value || '')
); );
@@ -147,6 +148,7 @@ const CustomEntities = () => {
factor: condensed_ei.factor, factor: condensed_ei.factor,
uom: condensed_ei.uom, uom: condensed_ei.uom,
writeable: condensed_ei.writeable, writeable: condensed_ei.writeable,
hide: condensed_ei.hide,
value_type: condensed_ei.value_type, value_type: condensed_ei.value_type,
value: condensed_ei.value value: condensed_ei.value
})) }))
@@ -209,6 +211,7 @@ const CustomEntities = () => {
value_type: item.value_type, value_type: item.value_type,
writeable: item.writeable, writeable: item.writeable,
deleted: false, deleted: false,
hide: item.hide,
value: item.value value: item.value
}); });
setDialogOpen(true); setDialogOpen(true);

View File

@@ -2,7 +2,11 @@ import { useEffect, useState } from 'react';
import AddIcon from '@mui/icons-material/Add'; import AddIcon from '@mui/icons-material/Add';
import CancelIcon from '@mui/icons-material/Cancel'; import CancelIcon from '@mui/icons-material/Cancel';
import CommentsDisabledOutlinedIcon from '@mui/icons-material/CommentsDisabledOutlined';
import DoneIcon from '@mui/icons-material/Done'; import DoneIcon from '@mui/icons-material/Done';
import EditOffOutlinedIcon from '@mui/icons-material/EditOffOutlined';
import EditOutlinedIcon from '@mui/icons-material/EditOutlined';
import InsertCommentOutlinedIcon from '@mui/icons-material/InsertCommentOutlined';
import RemoveIcon from '@mui/icons-material/RemoveCircleOutline'; import RemoveIcon from '@mui/icons-material/RemoveCircleOutline';
import { import {
Box, Box,
@@ -128,6 +132,20 @@ const CustomEntitiesDialog = ({
onChange={updateFormValue} onChange={updateFormValue}
/> />
</Grid> </Grid>
<Grid mt={3}>
<BlockFormControlLabel
control={
<Checkbox
icon={<InsertCommentOutlinedIcon htmlColor="white" />}
checkedIcon={<CommentsDisabledOutlinedIcon color="primary" />}
checked={editItem.hide}
onChange={updateFormValue}
name="hide"
/>
}
label="API/Mqtt"
/>
</Grid>
<Grid> <Grid>
<TextField <TextField
name="ram" name="ram"
@@ -177,10 +195,12 @@ const CustomEntitiesDialog = ({
)} )}
{editItem.ram === 0 && ( {editItem.ram === 0 && (
<> <>
<Grid mt={3} size={9}> <Grid mt={3}>
<BlockFormControlLabel <BlockFormControlLabel
control={ control={
<Checkbox <Checkbox
icon={<EditOffOutlinedIcon color="primary" />}
checkedIcon={<EditOutlinedIcon htmlColor="white" />}
checked={editItem.writeable} checked={editItem.writeable}
onChange={updateFormValue} onChange={updateFormValue}
name="writeable" name="writeable"

View File

@@ -306,7 +306,7 @@ const Customizations = () => {
const filter_entity = (de: DeviceEntity) => const filter_entity = (de: DeviceEntity) =>
(de.m & selectedFilters || !selectedFilters) && (de.m & selectedFilters || !selectedFilters) &&
formatName(de, true).includes(search); formatName(de, true).toLowerCase().includes(search.toLowerCase());
const maskDisabled = (set: boolean) => { const maskDisabled = (set: boolean) => {
setDeviceEntities( setDeviceEntities(

View File

@@ -600,9 +600,11 @@ const Devices = () => {
? deviceData.nodes.filter( ? deviceData.nodes.filter(
(dv) => (dv) =>
hasMask(dv.id, DeviceEntityMask.DV_FAVORITE) && hasMask(dv.id, DeviceEntityMask.DV_FAVORITE) &&
dv.id.slice(2).includes(search) dv.id.slice(2).toLowerCase().includes(search.toLowerCase())
) )
: deviceData.nodes.filter((dv) => dv.id.slice(2).includes(search)); : deviceData.nodes.filter((dv) =>
dv.id.slice(2).toLowerCase().includes(search.toLowerCase())
);
const deviceIndex = coreData.devices.findIndex( const deviceIndex = coreData.devices.findIndex(
(d) => d.id === device_select.state.id (d) => d.id === device_select.state.id

View File

@@ -384,6 +384,7 @@ export interface EntityItem {
value_type: number; value_type: number;
value?: unknown; value?: unknown;
writeable: boolean; writeable: boolean;
hide: boolean;
deleted?: boolean; deleted?: boolean;
o_id?: number; o_id?: number;
o_ram?: number; o_ram?: number;
@@ -397,6 +398,7 @@ export interface EntityItem {
o_deleted?: boolean; o_deleted?: boolean;
o_writeable?: boolean; o_writeable?: boolean;
o_value?: unknown; o_value?: unknown;
o_hide?: boolean;
} }
export interface Entities { export interface Entities {

View File

@@ -254,102 +254,112 @@ const MqttSettings = () => {
} }
label={LL.MQTT_RESPONSE()} label={LL.MQTT_RESPONSE()}
/> />
{!data.ha_enabled && ( <Grid container spacing={2} rowSpacing={0}>
<Grid container spacing={2} rowSpacing={0}> <Grid>
<BlockFormControlLabel
control={
<Checkbox
name="publish_single"
checked={data.publish_single}
onChange={updateFormValue}
disabled={data.ha_enabled}
/>
}
label={LL.MQTT_PUBLISH_TEXT_1()}
/>
</Grid>
{data.publish_single && (
<Grid> <Grid>
<BlockFormControlLabel <BlockFormControlLabel
control={ control={
<Checkbox <Checkbox
name="publish_single" name="publish_single2cmd"
checked={data.publish_single} checked={data.publish_single2cmd}
onChange={updateFormValue} onChange={updateFormValue}
/> />
} }
label={LL.MQTT_PUBLISH_TEXT_1()} label={LL.MQTT_PUBLISH_TEXT_2()}
/> />
</Grid> </Grid>
{data.publish_single && ( )}
</Grid>
<Grid container spacing={2} rowSpacing={0}>
<Grid>
<BlockFormControlLabel
control={
<Checkbox
name="ha_enabled"
checked={data.ha_enabled}
onChange={updateFormValue}
disabled={data.publish_single}
/>
}
label={LL.MQTT_PUBLISH_TEXT_3()}
/>
{data.ha_enabled && data.discovery_type === 0 && (
<BlockFormControlLabel
control={
<Checkbox
name="ha_optimistic"
checked={data.ha_optimistic}
onChange={updateFormValue}
/>
}
label="Optimistic"
/>
)}
</Grid>
{data.ha_enabled && (
<Grid container spacing={2} rowSpacing={0}>
<Grid> <Grid>
<BlockFormControlLabel <TextField
control={ name="discovery_type"
<Checkbox label={LL.MQTT_PUBLISH_TEXT_5()}
name="publish_single2cmd" value={data.discovery_type}
checked={data.publish_single2cmd} variant="outlined"
onChange={updateFormValue} onChange={updateFormValue}
/> margin="normal"
} select
label={LL.MQTT_PUBLISH_TEXT_2()} >
<MenuItem value={0}>Home Assistant</MenuItem>
<MenuItem value={1}>Domoticz</MenuItem>
<MenuItem value={2}>Domoticz (latest)</MenuItem>
</TextField>
</Grid>
<Grid>
<TextField
name="discovery_prefix"
label={LL.MQTT_PUBLISH_TEXT_4()}
variant="outlined"
value={data.discovery_prefix}
onChange={updateFormValue}
margin="normal"
/> />
</Grid> </Grid>
)} <Grid>
</Grid> <TextField
)} name="entity_format"
{!data.publish_single && ( label={LL.MQTT_ENTITY_FORMAT()}
<Grid container spacing={2} rowSpacing={0}> value={data.entity_format}
<Grid> variant="outlined"
<BlockFormControlLabel onChange={updateFormValue}
control={ margin="normal"
<Checkbox select
name="ha_enabled" >
checked={data.ha_enabled} <MenuItem value={0}>{LL.MQTT_ENTITY_FORMAT_0()}</MenuItem>
onChange={updateFormValue} <MenuItem value={3}>
/> {LL.MQTT_ENTITY_FORMAT_1()}&nbsp;(v3.6)
} </MenuItem>
label={LL.MQTT_PUBLISH_TEXT_3()} <MenuItem value={4}>
/> {LL.MQTT_ENTITY_FORMAT_2()}&nbsp;(v3.6)
</Grid> </MenuItem>
{data.ha_enabled && ( <MenuItem value={1}>{LL.MQTT_ENTITY_FORMAT_1()}</MenuItem>
<Grid container spacing={2} rowSpacing={0}> <MenuItem value={2}>{LL.MQTT_ENTITY_FORMAT_2()}</MenuItem>
<Grid> </TextField>
<TextField
name="discovery_type"
label={LL.MQTT_PUBLISH_TEXT_5()}
value={data.discovery_type}
variant="outlined"
onChange={updateFormValue}
margin="normal"
select
>
<MenuItem value={0}>Home Assistant</MenuItem>
<MenuItem value={1}>Domoticz</MenuItem>
<MenuItem value={2}>Domoticz (latest)</MenuItem>
</TextField>
</Grid>
<Grid>
<TextField
name="discovery_prefix"
label={LL.MQTT_PUBLISH_TEXT_4()}
variant="outlined"
value={data.discovery_prefix}
onChange={updateFormValue}
margin="normal"
/>
</Grid>
<Grid>
<TextField
name="entity_format"
label={LL.MQTT_ENTITY_FORMAT()}
value={data.entity_format}
variant="outlined"
onChange={updateFormValue}
margin="normal"
select
>
<MenuItem value={0}>{LL.MQTT_ENTITY_FORMAT_0()}</MenuItem>
<MenuItem value={3}>
{LL.MQTT_ENTITY_FORMAT_1()}&nbsp;(v3.6)
</MenuItem>
<MenuItem value={4}>
{LL.MQTT_ENTITY_FORMAT_2()}&nbsp;(v3.6)
</MenuItem>
<MenuItem value={1}>{LL.MQTT_ENTITY_FORMAT_1()}</MenuItem>
<MenuItem value={2}>{LL.MQTT_ENTITY_FORMAT_2()}</MenuItem>
</TextField>
</Grid>
</Grid> </Grid>
)} </Grid>
</Grid> )}
)} </Grid>
<Typography sx={{ pt: 2 }} variant="h6" color="primary"> <Typography sx={{ pt: 2 }} variant="h6" color="primary">
{LL.MQTT_PUBLISH_INTERVALS()}&nbsp;(0=auto) {LL.MQTT_PUBLISH_INTERVALS()}&nbsp;(0=auto)
</Typography> </Typography>
@@ -442,7 +452,7 @@ const MqttSettings = () => {
<Grid> <Grid>
<TextField <TextField
name="publish_time_sensor" name="publish_time_sensor"
label={LL.TEMP_SENSORS()} label={LL.SENSORS()}
variant="outlined" variant="outlined"
value={numberValue(data.publish_time_sensor)} value={numberValue(data.publish_time_sensor)}
type="number" type="number"

View File

@@ -43,6 +43,7 @@ export interface MqttSettingsType {
mqtt_qos: number; mqtt_qos: number;
mqtt_retain: boolean; mqtt_retain: boolean;
ha_enabled: boolean; ha_enabled: boolean;
ha_optimistic: boolean;
nested_format: number; nested_format: number;
send_response: boolean; send_response: boolean;
publish_single: boolean; publish_single: boolean;

File diff suppressed because it is too large Load Diff

View File

@@ -36,6 +36,7 @@ class DummySettings {
String discovery_prefix = "homeassistant"; String discovery_prefix = "homeassistant";
uint8_t discovery_type = 0; // HA uint8_t discovery_type = 0; // HA
bool ha_enabled = true; bool ha_enabled = true;
bool ha_optimistic = false;
String base = "ems-esp"; String base = "ems-esp";
bool publish_single = false; bool publish_single = false;
bool publish_single2cmd = false; bool publish_single2cmd = false;

View File

@@ -567,6 +567,7 @@ let mqtt_settings = {
rootCA: '', rootCA: '',
mqtt_retain: false, mqtt_retain: false,
ha_enabled: true, ha_enabled: true,
ha_optimistic: false,
nested_format: 1, nested_format: 1,
discovery_type: 0, discovery_type: 0,
discovery_prefix: 'homeassistant', discovery_prefix: 'homeassistant',

View File

@@ -244,6 +244,7 @@ void MqttSettings::read(MqttSettings & settings, JsonObject root) {
root["mqtt_qos"] = settings.mqtt_qos; root["mqtt_qos"] = settings.mqtt_qos;
root["mqtt_retain"] = settings.mqtt_retain; root["mqtt_retain"] = settings.mqtt_retain;
root["ha_enabled"] = settings.ha_enabled; root["ha_enabled"] = settings.ha_enabled;
root["ha_optimistic"] = settings.ha_optimistic;
root["nested_format"] = settings.nested_format; root["nested_format"] = settings.nested_format;
root["discovery_prefix"] = settings.discovery_prefix; root["discovery_prefix"] = settings.discovery_prefix;
root["discovery_type"] = settings.discovery_type; root["discovery_type"] = settings.discovery_type;
@@ -284,6 +285,7 @@ StateUpdateResult MqttSettings::update(JsonObject root, MqttSettings & settings)
newSettings.publish_time_heartbeat = static_cast<uint16_t>(root["publish_time_heartbeat"] | EMSESP_DEFAULT_PUBLISH_HEARTBEAT); newSettings.publish_time_heartbeat = static_cast<uint16_t>(root["publish_time_heartbeat"] | EMSESP_DEFAULT_PUBLISH_HEARTBEAT);
newSettings.ha_enabled = root["ha_enabled"] | EMSESP_DEFAULT_HA_ENABLED; newSettings.ha_enabled = root["ha_enabled"] | EMSESP_DEFAULT_HA_ENABLED;
newSettings.ha_optimistic = root["ha_optimistic"] | EMSESP_DEFAULT_HA_OPTIMISTIC;
newSettings.nested_format = static_cast<uint8_t>(root["nested_format"] | EMSESP_DEFAULT_NESTED_FORMAT); newSettings.nested_format = static_cast<uint8_t>(root["nested_format"] | EMSESP_DEFAULT_NESTED_FORMAT);
newSettings.discovery_prefix = root["discovery_prefix"] | EMSESP_DEFAULT_DISCOVERY_PREFIX; newSettings.discovery_prefix = root["discovery_prefix"] | EMSESP_DEFAULT_DISCOVERY_PREFIX;
newSettings.discovery_type = static_cast<uint8_t>(root["discovery_type"] | EMSESP_DEFAULT_DISCOVERY_TYPE); newSettings.discovery_type = static_cast<uint8_t>(root["discovery_type"] | EMSESP_DEFAULT_DISCOVERY_TYPE);
@@ -345,6 +347,14 @@ StateUpdateResult MqttSettings::update(JsonObject root, MqttSettings & settings)
changed = true; changed = true;
} }
if (newSettings.discovery_type != 0) {
newSettings.ha_optimistic = false;
}
if (newSettings.ha_optimistic != settings.ha_optimistic) {
emsesp::EMSESP::mqtt_.ha_optimistic(newSettings.ha_optimistic);
changed = true;
}
if (newSettings.mqtt_retain != settings.mqtt_retain) { if (newSettings.mqtt_retain != settings.mqtt_retain) {
emsesp::EMSESP::mqtt_.set_retain(newSettings.mqtt_retain); emsesp::EMSESP::mqtt_.set_retain(newSettings.mqtt_retain);
changed = true; changed = true;

View File

@@ -76,6 +76,7 @@ class MqttSettings {
uint8_t mqtt_qos; uint8_t mqtt_qos;
bool mqtt_retain; bool mqtt_retain;
bool ha_enabled; bool ha_enabled;
bool ha_optimistic;
uint8_t nested_format; uint8_t nested_format;
String discovery_prefix; String discovery_prefix;
uint8_t discovery_type; uint8_t discovery_type;

View File

@@ -682,6 +682,9 @@ void AnalogSensor::publish_values(const bool force) {
Mqtt::add_ha_sections_to_doc("analog", stat_t, config, !is_ha_device_created, val_cond); Mqtt::add_ha_sections_to_doc("analog", stat_t, config, !is_ha_device_created, val_cond);
if (Mqtt::ha_optimistic() && config["cmd_t"].is<const char*>()) {
config["optimistic"] = true;
}
sensor.ha_registered = Mqtt::queue_ha(topic, config.as<JsonObject>()); sensor.ha_registered = Mqtt::queue_ha(topic, config.as<JsonObject>());
} }
} }

View File

@@ -185,6 +185,10 @@
#define EMSESP_DEFAULT_HA_ENABLED false #define EMSESP_DEFAULT_HA_ENABLED false
#endif #endif
#ifndef EMSESP_DEFAULT_HA_OPTIMISTIC
#define EMSESP_DEFAULT_HA_OPTIMISTIC false
#endif
#ifndef EMSESP_DEFAULT_PUBLISH_TIME #ifndef EMSESP_DEFAULT_PUBLISH_TIME
#define EMSESP_DEFAULT_PUBLISH_TIME 10 #define EMSESP_DEFAULT_PUBLISH_TIME 10
#endif #endif

View File

@@ -24,7 +24,7 @@
*/ */
// Boilers - 0x08 // Boilers - 0x08
{ 8, DeviceType::BOILER, "CS*800i, Logatherm WLW*", DeviceFlags::EMS_DEVICE_FLAG_HEATPUMP}, { 8, DeviceType::BOILER, "CS5800i, CS6800i, WLW176i, WLW186i", DeviceFlags::EMS_DEVICE_FLAG_CS6800},
{ 12, DeviceType::BOILER, "C1200W", DeviceFlags::EMS_DEVICE_FLAG_NONE}, { 12, DeviceType::BOILER, "C1200W", DeviceFlags::EMS_DEVICE_FLAG_NONE},
{ 64, DeviceType::BOILER, "BK13/BK15, Smartline, GB1*2", DeviceFlags::EMS_DEVICE_FLAG_NONE}, { 64, DeviceType::BOILER, "BK13/BK15, Smartline, GB1*2", DeviceFlags::EMS_DEVICE_FLAG_NONE},
{ 72, DeviceType::BOILER, "Logano GB1*5, Logamatic MC10", DeviceFlags::EMS_DEVICE_FLAG_EMS}, { 72, DeviceType::BOILER, "Logano GB1*5, Logamatic MC10", DeviceFlags::EMS_DEVICE_FLAG_EMS},

View File

@@ -197,6 +197,19 @@ class EMSdevice {
} }
} }
void has_enumupdate(std::shared_ptr<const Telegram> telegram,
uint8_t & value,
const uint8_t index,
const std::vector<uint8_t> & maskIn,
const std::vector<uint8_t> & maskOut) {
uint8_t val = value < maskIn.size() ? maskIn[value] : EMS_VALUE_UINT8_NOTSET;
if (telegram->read_value(val, index)) {
value = val < maskOut.size() ? maskOut[val] : EMS_VALUE_UINT8_NOTSET;
has_update_ = true;
publish_value((void *)&value);
}
}
template <typename Value> template <typename Value>
void has_update(std::shared_ptr<const Telegram> telegram, Value & value, const uint8_t index, uint8_t s = 0) { void has_update(std::shared_ptr<const Telegram> telegram, Value & value, const uint8_t index, uint8_t s = 0) {
if (telegram->read_value(value, index, s)) { if (telegram->read_value(value, index, s)) {
@@ -434,9 +447,10 @@ class EMSdevice {
static constexpr uint8_t EMS_DEVICE_FLAG_EMS = 1; static constexpr uint8_t EMS_DEVICE_FLAG_EMS = 1;
static constexpr uint8_t EMS_DEVICE_FLAG_EMSPLUS = 2; static constexpr uint8_t EMS_DEVICE_FLAG_EMSPLUS = 2;
static constexpr uint8_t EMS_DEVICE_FLAG_HT3 = 3; static constexpr uint8_t EMS_DEVICE_FLAG_HT3 = 3;
static constexpr uint8_t EMS_DEVICE_FLAG_HEATPUMP = 4; static constexpr uint8_t EMS_DEVICE_FLAG_HYBRID = 4;
static constexpr uint8_t EMS_DEVICE_FLAG_HYBRID = 5; static constexpr uint8_t EMS_DEVICE_FLAG_HIU = 5;
static constexpr uint8_t EMS_DEVICE_FLAG_HIU = 6; static constexpr uint8_t EMS_DEVICE_FLAG_HEATPUMP = 8; // use bit for subtypes
static constexpr uint8_t EMS_DEVICE_FLAG_CS6800 = 9; // subtype of heatpump
// Solar Module // Solar Module
static constexpr uint8_t EMS_DEVICE_FLAG_SM10 = 1; static constexpr uint8_t EMS_DEVICE_FLAG_SM10 = 1;

View File

@@ -627,10 +627,18 @@ bool Helpers::value2enum(const char * value, uint8_t & value_ui, const char * co
} }
} }
value_ui = 0; value_ui = 0;
return false; return false;
} }
bool Helpers::value2enum(const char * value, uint8_t & value_ui, const char * const ** strs, const std::vector<uint8_t> & mask) {
uint8_t v = value_ui;
if (!value2enum(value, v, strs) || v >= mask.size()) {
return false;
}
value_ui = mask[v];
return true;
}
// finds the string (value) of a list vector (strs) // finds the string (value) of a list vector (strs)
// returns true if found, and sets the value_ui to the index, else false // returns true if found, and sets the value_ui to the index, else false
// also allow true/false for on/off // also allow true/false for on/off
@@ -658,6 +666,15 @@ bool Helpers::value2enum(const char * value, uint8_t & value_ui, const char * co
return false; return false;
} }
bool Helpers::value2enum(const char * value, uint8_t & value_ui, const char * const * strs, const std::vector<uint8_t> & mask) {
uint8_t v = value_ui;
if (!value2enum(value, v, strs) || v >= mask.size()) {
return false;
}
value_ui = mask[v];
return true;
}
// https://stackoverflow.com/questions/313970/how-to-convert-stdstring-to-lower-case // https://stackoverflow.com/questions/313970/how-to-convert-stdstring-to-lower-case
std::string Helpers::toLower(std::string const & s) { std::string Helpers::toLower(std::string const & s) {
std::string lc = s; std::string lc = s;

View File

@@ -72,7 +72,9 @@ class Helpers {
static bool value2bool(const char * value, bool & value_b); static bool value2bool(const char * value, bool & value_b);
static bool value2string(const char * value, std::string & value_s); static bool value2string(const char * value, std::string & value_s);
static bool value2enum(const char * value, uint8_t & value_ui, const char * const ** strs); static bool value2enum(const char * value, uint8_t & value_ui, const char * const ** strs);
static bool value2enum(const char * value, uint8_t & value_ui, const char * const ** strs, const std::vector<uint8_t> & mask);
static bool value2enum(const char * value, uint8_t & value_ui, const char * const * strs); static bool value2enum(const char * value, uint8_t & value_ui, const char * const * strs);
static bool value2enum(const char * value, uint8_t & value_ui, const char * const * strs, const std::vector<uint8_t> & mask);
static bool value2temperature(const char * value, float & value_f, bool relative = false); static bool value2temperature(const char * value, float & value_f, bool relative = false);
static bool value2temperature(const char * value, int & value_i, const bool relative = false, const int min = -2147483648, const int max = 2147483647); static bool value2temperature(const char * value, int & value_i, const bool relative = false, const int min = -2147483648, const int max = 2147483647);

View File

@@ -298,6 +298,8 @@ MAKE_ENUM(enum_comfort2, FL_(eco), FL_(high_comfort))
MAKE_ENUM(enum_flow, FL_(off), FL_(flow), FL_(bufferedflow), FL_(buffer), FL_(layeredbuffer)) MAKE_ENUM(enum_flow, FL_(off), FL_(flow), FL_(bufferedflow), FL_(buffer), FL_(layeredbuffer))
MAKE_ENUM(enum_reset, FL_(dash), FL_(maintenance), FL_(error), FL_(history), FL_(message)) MAKE_ENUM(enum_reset, FL_(dash), FL_(maintenance), FL_(error), FL_(history), FL_(message))
MAKE_ENUM(enum_maxHeat, FL_(0kW), FL_(2kW), FL_(3kW), FL_(4kW), FL_(6kW), FL_(9kW)) MAKE_ENUM(enum_maxHeat, FL_(0kW), FL_(2kW), FL_(3kW), FL_(4kW), FL_(6kW), FL_(9kW))
MAKE_ENUM(enum_maxHeat1, FL_(0kW), FL_(3kW), FL_(6kW), FL_(9kW))
MAKE_ENUM(enum_maxHeat2, FL_(3kW), FL_(6kW), FL_(9kW))
MAKE_ENUM(enum_pumpMode, FL_(proportional), FL_(deltaP1), FL_(deltaP2), FL_(deltaP3), FL_(deltaP4)) MAKE_ENUM(enum_pumpMode, FL_(proportional), FL_(deltaP1), FL_(deltaP2), FL_(deltaP3), FL_(deltaP4))
MAKE_ENUM(enum_pumpCharacter, FL_(proportional), FL_(pressure1), FL_(pressure2), FL_(pressure3), FL_(pressure4), FL_(pressure5), FL_(pressure6)) MAKE_ENUM(enum_pumpCharacter, FL_(proportional), FL_(pressure1), FL_(pressure2), FL_(pressure3), FL_(pressure4), FL_(pressure5), FL_(pressure6))
MAKE_ENUM(enum_hpPumpMode, FL_(auto), FL_(continuous)) MAKE_ENUM(enum_hpPumpMode, FL_(auto), FL_(continuous))

View File

@@ -636,6 +636,7 @@ MAKE_TRANSLATION(wwStorageTemp2, "storagetemp2", "storage extern temperature", "
MAKE_TRANSLATION(wwActivated, "activated", "activated", "aktiviert", "geactiveerd", "Aktiverad", "system przygotowywania c.w.u.", "aktivert", "activé", "devreye girdi", "attivato", "aktivovaný", "aktivováno") MAKE_TRANSLATION(wwActivated, "activated", "activated", "aktiviert", "geactiveerd", "Aktiverad", "system przygotowywania c.w.u.", "aktivert", "activé", "devreye girdi", "attivato", "aktivovaný", "aktivováno")
MAKE_TRANSLATION(wwDisinfecting, "disinfecting", "disinfecting", "Desinfizieren", "Desinfectie", "Desinficerar", "dezynfekcja termiczna", "desinfiserer", "désinfection", "dezenfekte ediliyor", "disinfezione", "dezinfekcia", "dezinfekce") MAKE_TRANSLATION(wwDisinfecting, "disinfecting", "disinfecting", "Desinfizieren", "Desinfectie", "Desinficerar", "dezynfekcja termiczna", "desinfiserer", "désinfection", "dezenfekte ediliyor", "disinfezione", "dezinfekcia", "dezinfekce")
MAKE_TRANSLATION(wwDisinfectionTemp, "disinfectiontemp", "disinfection temperature", "Desinfektionstemperatur", "Desinfectietemperatuur", "Desinfektionstemperatur", "temperatura dezynfekcji termicznej", "desinfeksjonstemperatur", "température désinfection", "dezenfeksiyon sıcaklığı", "temperatura disinfezione", "teplota dezinfekcie", "dezinfekční teplota") MAKE_TRANSLATION(wwDisinfectionTemp, "disinfectiontemp", "disinfection temperature", "Desinfektionstemperatur", "Desinfectietemperatuur", "Desinfektionstemperatur", "temperatura dezynfekcji termicznej", "desinfeksjonstemperatur", "température désinfection", "dezenfeksiyon sıcaklığı", "temperatura disinfezione", "teplota dezinfekcie", "dezinfekční teplota")
MAKE_TRANSLATION(wwChargePump, "chargepump", "charge pump", "Ladepumpe", "", "", "", "", "", "", "", "", "") // TODO Translate
MAKE_TRANSLATION(wwCharging, "charging", "charging", "Laden", "Laden", "Värmer", "grzanie", "varmer", "chargement", "dolduruluyor", "caricamento", "nabíjanie", "nabíjení") MAKE_TRANSLATION(wwCharging, "charging", "charging", "Laden", "Laden", "Värmer", "grzanie", "varmer", "chargement", "dolduruluyor", "caricamento", "nabíjanie", "nabíjení")
MAKE_TRANSLATION(wwChargeOptimization, "chargeoptimization", "charge optimization", "Ladungsoptimierung", "laadoptimalisatie", "Laddningsoptimering", "optymalizacja grzania", "oppvarmingsoptimalisering", "optimisation charge", "dolum optimizasyonu", "ottimizzazione carica", "optimalizácia poplatkov", "optimalizace nabíjení") MAKE_TRANSLATION(wwChargeOptimization, "chargeoptimization", "charge optimization", "Ladungsoptimierung", "laadoptimalisatie", "Laddningsoptimering", "optymalizacja grzania", "oppvarmingsoptimalisering", "optimisation charge", "dolum optimizasyonu", "ottimizzazione carica", "optimalizácia poplatkov", "optimalizace nabíjení")
MAKE_TRANSLATION(wwRecharging, "recharging", "recharging", "Nachladen", "herladen", "Laddar om", "ponowne grzanie", "varm på nytt", "en recharge", "tekrar dolduruluyor", "in ricarica", "nabíjanie", "dobíjení") MAKE_TRANSLATION(wwRecharging, "recharging", "recharging", "Nachladen", "herladen", "Laddar om", "ponowne grzanie", "varm på nytt", "en recharge", "tekrar dolduruluyor", "in ricarica", "nabíjanie", "dobíjení")

View File

@@ -40,6 +40,7 @@ uint32_t Mqtt::publish_time_heartbeat_;
bool Mqtt::mqtt_enabled_; bool Mqtt::mqtt_enabled_;
uint8_t Mqtt::entity_format_; uint8_t Mqtt::entity_format_;
bool Mqtt::ha_enabled_; bool Mqtt::ha_enabled_;
bool Mqtt::ha_optimistic_;
uint8_t Mqtt::nested_format_; uint8_t Mqtt::nested_format_;
std::string Mqtt::discovery_prefix_; std::string Mqtt::discovery_prefix_;
uint8_t Mqtt::discovery_type_; uint8_t Mqtt::discovery_type_;
@@ -340,6 +341,7 @@ void Mqtt::load_settings() {
mqtt_retain_ = mqttSettings.mqtt_retain; mqtt_retain_ = mqttSettings.mqtt_retain;
mqtt_enabled_ = mqttSettings.enabled; mqtt_enabled_ = mqttSettings.enabled;
ha_enabled_ = mqttSettings.ha_enabled; ha_enabled_ = mqttSettings.ha_enabled;
ha_optimistic_ = mqttSettings.ha_optimistic;
nested_format_ = mqttSettings.nested_format; nested_format_ = mqttSettings.nested_format;
publish_single_ = mqttSettings.publish_single; publish_single_ = mqttSettings.publish_single;
publish_single2cmd_ = mqttSettings.publish_single2cmd; publish_single2cmd_ = mqttSettings.publish_single2cmd;
@@ -1114,6 +1116,9 @@ bool Mqtt::publish_ha_sensor_config(uint8_t type, // EMSdev
doc["dev"] = dev_json; doc["dev"] = dev_json;
if (ha_optimistic_ && has_cmd) {
doc["optimistic"] = true;
}
return queue_ha(topic, doc.as<JsonObject>()); return queue_ha(topic, doc.as<JsonObject>());
} }
@@ -1343,6 +1348,9 @@ bool Mqtt::publish_ha_climate_config(const int8_t tag, const bool has_roomtemp,
// device name must be different to the entity name, take the ids value we just created // device name must be different to the entity name, take the ids value we just created
add_ha_sections_to_doc("thermostat", topic_t, doc, false, seltemp_cond, has_roomtemp ? currtemp_cond : nullptr, hc_mode_cond); add_ha_sections_to_doc("thermostat", topic_t, doc, false, seltemp_cond, has_roomtemp ? currtemp_cond : nullptr, hc_mode_cond);
if (ha_optimistic_) {
doc["optimistic"] = true;
}
return queue_ha(topic, doc.as<JsonObject>()); // publish the config payload with retain flag return queue_ha(topic, doc.as<JsonObject>()); // publish the config payload with retain flag
} }
@@ -1398,7 +1406,7 @@ void Mqtt::add_ha_sections_to_doc(const char * name,
// make local copy of state, as the pointer will get derefenced // make local copy of state, as the pointer will get derefenced
char state[50]; char state[50];
strcpy(state, state_t); strlcpy(state, state_t, sizeof(state));
// skip conditional Jinja2 templates if not home assistant // skip conditional Jinja2 templates if not home assistant
if (discovery_type() == discoveryType::HOMEASSISTANT) { if (discovery_type() == discoveryType::HOMEASSISTANT) {

View File

@@ -206,6 +206,14 @@ class Mqtt {
ha_enabled_ = ha_enabled; ha_enabled_ = ha_enabled;
} }
static bool ha_optimistic() {
return ha_optimistic_;
}
static void ha_optimistic(bool ha_optimistic) {
ha_optimistic_ = ha_optimistic;
}
static bool ha_climate_reset() { static bool ha_climate_reset() {
return ha_climate_reset_; return ha_climate_reset_;
} }
@@ -309,6 +317,7 @@ class Mqtt {
static uint32_t publish_time_heartbeat_; static uint32_t publish_time_heartbeat_;
static bool mqtt_enabled_; static bool mqtt_enabled_;
static bool ha_enabled_; static bool ha_enabled_;
static bool ha_optimistic_;
static uint8_t nested_format_; static uint8_t nested_format_;
static uint8_t entity_format_; static uint8_t entity_format_;
static std::string discovery_prefix_; static std::string discovery_prefix_;

View File

@@ -2001,8 +2001,12 @@ std::string System::reset_reason(uint8_t cpu) const {
// set NTP status // set NTP status
void System::ntp_connected(bool b) { void System::ntp_connected(bool b) {
if (b != ntp_connected_ && !b) { if (b != ntp_connected_) {
LOG_WARNING("NTP disconnected"); // if turned off report it if (b) {
LOG_INFO("NTP connected");
} else {
LOG_WARNING("NTP disconnected"); // if turned off report it
}
} }
ntp_connected_ = b; ntp_connected_ = b;

View File

@@ -68,7 +68,7 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const
register_telegram_type(0x28, "WeatherComp", true, MAKE_PF_CB(process_WeatherComp)); register_telegram_type(0x28, "WeatherComp", true, MAKE_PF_CB(process_WeatherComp));
} }
if (model() == EMSdevice::EMS_DEVICE_FLAG_HEATPUMP) { if (isHeatPump()) {
register_telegram_type(0x494, "UBAEnergySupplied", false, MAKE_PF_CB(process_UBAEnergySupplied)); register_telegram_type(0x494, "UBAEnergySupplied", false, MAKE_PF_CB(process_UBAEnergySupplied));
register_telegram_type(0x495, "UBAInformation", false, MAKE_PF_CB(process_UBAInformation)); register_telegram_type(0x495, "UBAInformation", false, MAKE_PF_CB(process_UBAInformation));
register_telegram_type(0x48D, "HpPower", true, MAKE_PF_CB(process_HpPower)); register_telegram_type(0x48D, "HpPower", true, MAKE_PF_CB(process_HpPower));
@@ -96,7 +96,7 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const
} }
// some gas boilers, see #1701 // some gas boilers, see #1701
if (model() != EMSdevice::EMS_DEVICE_FLAG_HEATPUMP) { if (!isHeatPump()) {
register_telegram_type(0x2E, "Meters", false, MAKE_PF_CB(process_Meters)); register_telegram_type(0x2E, "Meters", false, MAKE_PF_CB(process_Meters));
register_telegram_type(0x3B, "Energy", false, MAKE_PF_CB(process_Energy)); register_telegram_type(0x3B, "Energy", false, MAKE_PF_CB(process_Energy));
} }
@@ -187,7 +187,7 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const
DeviceValueUOM::DEGREES); DeviceValueUOM::DEGREES);
// exclude burner related entities from heatpump and HIU // exclude burner related entities from heatpump and HIU
if (model() != EMSdevice::EMS_DEVICE_FLAG_HEATPUMP && model() != EMSdevice::EMS_DEVICE_FLAG_HIU) { if (!isHeatPump() && model() != EMSdevice::EMS_DEVICE_FLAG_HIU) {
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
&exhaustTemp_, &exhaustTemp_,
DeviceValueType::UINT16, DeviceValueType::UINT16,
@@ -411,7 +411,7 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const
99); 99);
} }
*/ */
if (model() != EMSdevice::EMS_DEVICE_FLAG_HEATPUMP) { if (!isHeatPump()) {
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
&meterHeat_, &meterHeat_,
DeviceValueType::UINT24, DeviceValueType::UINT24,
@@ -436,7 +436,7 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const
} }
// heatpump info // heatpump info
if (model() == EMSdevice::EMS_DEVICE_FLAG_HEATPUMP) { if (isHeatPump()) {
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
&nrgTotal_, &nrgTotal_,
DeviceValueType::UINT24, DeviceValueType::UINT24,
@@ -655,27 +655,51 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const
FL_(hpIn4Opt), FL_(hpIn4Opt),
DeviceValueUOM::NONE, DeviceValueUOM::NONE,
MAKE_CF_CB(set_HpIn4Logic)); MAKE_CF_CB(set_HpIn4Logic));
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, if (model() == EMSdevice::EMS_DEVICE_FLAG_CS6800) {
&maxHeatComp_, register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
DeviceValueType::ENUM, &maxHeatComp_,
FL_(enum_maxHeat), DeviceValueType::ENUM,
FL_(maxHeatComp), FL_(enum_maxHeat1),
DeviceValueUOM::NONE, FL_(maxHeatComp),
MAKE_CF_CB(set_maxHeatComp)); DeviceValueUOM::NONE,
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, MAKE_CF_CB(set_maxHeatComp));
&maxHeatHeat_, register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
DeviceValueType::ENUM, &maxHeatHeat_,
FL_(enum_maxHeat), DeviceValueType::ENUM,
FL_(maxHeatHeat), FL_(enum_maxHeat2),
DeviceValueUOM::NONE, FL_(maxHeatHeat),
MAKE_CF_CB(set_maxHeatHeat)); DeviceValueUOM::NONE,
register_device_value(DeviceValueTAG::TAG_DHW1, MAKE_CF_CB(set_maxHeatHeat));
&maxHeatDhw_, register_device_value(DeviceValueTAG::TAG_DHW1,
DeviceValueType::ENUM, &maxHeatDhw_,
FL_(enum_maxHeat), DeviceValueType::ENUM,
FL_(maxHeatDhw), FL_(enum_maxHeat2),
DeviceValueUOM::NONE, FL_(maxHeatDhw),
MAKE_CF_CB(set_maxHeatDhw)); DeviceValueUOM::NONE,
MAKE_CF_CB(set_maxHeatDhw));
} else {
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
&maxHeatComp_,
DeviceValueType::ENUM,
FL_(enum_maxHeat),
FL_(maxHeatComp),
DeviceValueUOM::NONE,
MAKE_CF_CB(set_maxHeatComp));
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
&maxHeatHeat_,
DeviceValueType::ENUM,
FL_(enum_maxHeat),
FL_(maxHeatHeat),
DeviceValueUOM::NONE,
MAKE_CF_CB(set_maxHeatHeat));
register_device_value(DeviceValueTAG::TAG_DHW1,
&maxHeatDhw_,
DeviceValueType::ENUM,
FL_(enum_maxHeat),
FL_(maxHeatDhw),
DeviceValueUOM::NONE,
MAKE_CF_CB(set_maxHeatDhw));
}
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
&auxHeaterSource_, &auxHeaterSource_,
DeviceValueType::ENUM, DeviceValueType::ENUM,
@@ -1043,6 +1067,7 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const
register_device_value(DeviceValueTAG::TAG_DHW1, &wwTempOK_, DeviceValueType::BOOL, FL_(wwTempOK), DeviceValueUOM::NONE); register_device_value(DeviceValueTAG::TAG_DHW1, &wwTempOK_, DeviceValueType::BOOL, FL_(wwTempOK), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_DHW1, &wwActive_, DeviceValueType::BOOL, FL_(wwActive), DeviceValueUOM::NONE); register_device_value(DeviceValueTAG::TAG_DHW1, &wwActive_, DeviceValueType::BOOL, FL_(wwActive), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_DHW1, &ww3wayValve_, DeviceValueType::BOOL, FL_(ww3wayValve), DeviceValueUOM::NONE); register_device_value(DeviceValueTAG::TAG_DHW1, &ww3wayValve_, DeviceValueType::BOOL, FL_(ww3wayValve), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_DHW1, &wwChargePump_, DeviceValueType::BOOL, FL_(wwChargePump), DeviceValueUOM::NONE);
register_device_value(DeviceValueTAG::TAG_DHW1, register_device_value(DeviceValueTAG::TAG_DHW1,
&wwMixerTemp_, &wwMixerTemp_,
DeviceValueType::UINT16, DeviceValueType::UINT16,
@@ -1067,7 +1092,7 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const
EMSESP::send_read_request(0xC6, device_id, 0, 21); // read last errorcode on start (not broadcasted) EMSESP::send_read_request(0xC6, device_id, 0, 21); // read last errorcode on start (not broadcasted)
if (model() != EMSdevice::EMS_DEVICE_FLAG_HEATPUMP && model() != EMSdevice::EMS_DEVICE_FLAG_HIU) { if (!isHeatPump() && model() != EMSdevice::EMS_DEVICE_FLAG_HIU) {
register_telegram_type(0x04, "UBAFactory", true, MAKE_PF_CB(process_UBAFactory)); register_telegram_type(0x04, "UBAFactory", true, MAKE_PF_CB(process_UBAFactory));
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &nomPower_, DeviceValueType::UINT8, FL_(nomPower), DeviceValueUOM::KW, MAKE_CF_CB(set_nomPower)); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &nomPower_, DeviceValueType::UINT8, FL_(nomPower), DeviceValueUOM::KW, MAKE_CF_CB(set_nomPower));
register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, register_device_value(DeviceValueTAG::TAG_DEVICE_DATA,
@@ -1188,7 +1213,7 @@ void Boiler::check_active() {
} }
// calculate energy for boiler 0x08 from stored modulation an time in units of 0.01 Wh // calculate energy for boiler 0x08 from stored modulation an time in units of 0.01 Wh
if (model() != EMSdevice::EMS_DEVICE_FLAG_HEATPUMP && model() != EMSdevice::EMS_DEVICE_FLAG_HIU) { if (!isHeatPump() && model() != EMSdevice::EMS_DEVICE_FLAG_HIU) {
// remember values from last call // remember values from last call
static uint32_t powLastReadTime_ = uuid::get_uptime(); static uint32_t powLastReadTime_ = uuid::get_uptime();
static uint8_t heatBurnPow = 0; static uint8_t heatBurnPow = 0;
@@ -1297,6 +1322,7 @@ void Boiler::process_UBAMonitorFast(std::shared_ptr<const Telegram> telegram) {
has_update(curBurnPow_, curBurnPow); has_update(curBurnPow_, curBurnPow);
check_active(); // do a quick check to see if the hot water or heating is active check_active(); // do a quick check to see if the hot water or heating is active
has_bitupdate(telegram, wwChargePump_, 23, 0);
} }
} }
@@ -1348,11 +1374,11 @@ void Boiler::process_UBAParameterWW(std::shared_ptr<const Telegram> telegram) {
// has_bitupdate(telegram, wwEquipt_,0,3); // 8=boiler has ww // has_bitupdate(telegram, wwEquipt_,0,3); // 8=boiler has ww
has_update(telegram, wwActivated_, 1); // 0xFF means on has_update(telegram, wwActivated_, 1); // 0xFF means on
has_update(telegram, wwSelTemp_, 2); has_update(telegram, wwSelTemp_, 2);
has_update(telegram, wwHystOn_, 3); // Hyst on (default -5) has_update(telegram, wwHystOn_, 3); // Hyst on (default -5)
has_update(telegram, wwHystOff_, 4); // Hyst off (default -1) has_update(telegram, wwChargeOptimization_, 4); // bool
has_update(telegram, wwFlowTempOffset_, 5); // default 40 has_update(telegram, wwFlowTempOffset_, 5); // default 40
has_update(telegram, wwCircPump_, 6); // 0xFF means on has_update(telegram, wwCircPump_, 6); // 0xFF means on
has_update(telegram, wwCircMode_, 7); // 0=off, 1=1x3min 6=6x3min 7=continuous has_update(telegram, wwCircMode_, 7); // 0=off, 1=1x3min 6=6x3min 7=continuous
has_update(telegram, wwDisinfectionTemp_, 8); has_update(telegram, wwDisinfectionTemp_, 8);
has_bitupdate(telegram, wwChargeType_, 10, 0); // 0 = charge pump, 0xff = 3-way valve has_bitupdate(telegram, wwChargeType_, 10, 0); // 0 = charge pump, 0xff = 3-way valve
@@ -1451,7 +1477,7 @@ void Boiler::process_UBAMonitorFastPlus(std::shared_ptr<const Telegram> telegram
// at this point do a quick check to see if the hot water or heating is active // at this point do a quick check to see if the hot water or heating is active
uint8_t state = EMS_VALUE_UINT8_NOTSET; uint8_t state = EMS_VALUE_UINT8_NOTSET;
if (telegram->read_value(state, 11) && model() != EMSdevice::EMS_DEVICE_FLAG_HIU && model() != EMSdevice::EMS_DEVICE_FLAG_HEATPUMP) { if (telegram->read_value(state, 11) && model() != EMSdevice::EMS_DEVICE_FLAG_HIU && !isHeatPump()) {
boilerState_ = state & 0x01 ? 0x08 : 0; // burnGas boilerState_ = state & 0x01 ? 0x08 : 0; // burnGas
boilerState_ |= state & 0x02 ? 0x01 : 0; // heatingPump boilerState_ |= state & 0x02 ? 0x01 : 0; // heatingPump
boilerState_ |= state & 0x04 ? 0x02 : 0; // 3-way-valve boilerState_ |= state & 0x04 ? 0x02 : 0; // 3-way-valve
@@ -1778,6 +1804,12 @@ void Boiler::process_HpCooling(std::shared_ptr<const Telegram> telegram) {
// Boiler(0x08) -W-> Me(0x0B), HpHeaterConfig(0x0492), data: 03 00 00 04 00 // Boiler(0x08) -W-> Me(0x0B), HpHeaterConfig(0x0492), data: 03 00 00 04 00
void Boiler::process_HpHeaterConfig(std::shared_ptr<const Telegram> telegram) { void Boiler::process_HpHeaterConfig(std::shared_ptr<const Telegram> telegram) {
if (model() == EMSdevice::EMS_DEVICE_FLAG_CS6800) {
has_enumupdate(telegram, maxHeatComp_, 2, {0, 2, 4, 5}, {0, 0, 1, 0, 2, 3});
has_enumupdate(telegram, maxHeatHeat_, 3, {2, 4, 5}, {0, 0, 0, 0, 1, 2});
has_enumupdate(telegram, maxHeatDhw_, 4, {2, 4, 5}, {0, 0, 0, 0, 1, 2});
return;
}
has_update(telegram, maxHeatComp_, 2); has_update(telegram, maxHeatComp_, 2);
has_update(telegram, maxHeatHeat_, 3); has_update(telegram, maxHeatHeat_, 3);
has_update(telegram, maxHeatDhw_, 4); has_update(telegram, maxHeatDhw_, 4);
@@ -2078,7 +2110,7 @@ void Boiler::process_HpPump2(std::shared_ptr<const Telegram> telegram) {
// Boiler(0x08) -> All(0x00), ?(0x0491), data: 03 01 00 00 00 02 64 00 00 14 01 2C 00 0A 00 1E 00 1E 00 00 1E 0A 1E 05 05 // Boiler(0x08) -> All(0x00), ?(0x0491), data: 03 01 00 00 00 02 64 00 00 14 01 2C 00 0A 00 1E 00 1E 00 00 1E 0A 1E 05 05
void Boiler::process_HpAdditionalHeater(std::shared_ptr<const Telegram> telegram) { void Boiler::process_HpAdditionalHeater(std::shared_ptr<const Telegram> telegram) {
has_update(telegram, auxHeaterSource_, 0); // https://github.com/emsesp/EMS-ESP32/discussions/2489 has_update(telegram, auxHeaterSource_, 0); // https://github.com/emsesp/EMS-ESP32/discussions/2489
has_update(telegram, auxHeaterOnly_, 1); has_update(telegram, auxHeaterOnly_, model() == EMSdevice::EMS_DEVICE_FLAG_CS6800 ? 3 : 1);
has_update(telegram, auxHeaterOff_, 2); has_update(telegram, auxHeaterOff_, 2);
has_update(telegram, auxHeatMode_, 4); // eco/comfort has_update(telegram, auxHeatMode_, 4); // eco/comfort
has_update(telegram, tempParMode_, 5); has_update(telegram, tempParMode_, 5);
@@ -2532,6 +2564,8 @@ bool Boiler::set_ww_chargeOptimization(const char * value, const int8_t id) {
if (is_received(EMS_TYPE_UBAParameterWWPlus)) { if (is_received(EMS_TYPE_UBAParameterWWPlus)) {
write_command(EMS_TYPE_UBAParameterWWPlus, 25, v ? 1 : 0, EMS_TYPE_UBAParameterWWPlus); write_command(EMS_TYPE_UBAParameterWWPlus, 25, v ? 1 : 0, EMS_TYPE_UBAParameterWWPlus);
} else {
write_command(EMS_TYPE_UBAParameterWW, 4, v ? 0xFF : 0, EMS_TYPE_UBAParameterWW);
} }
return true; return true;
@@ -3059,8 +3093,20 @@ bool Boiler::set_HpInLogic(const char * value, const int8_t id) {
bool Boiler::set_maxHeat(const char * value, const int8_t id) { bool Boiler::set_maxHeat(const char * value, const int8_t id) {
uint8_t v; uint8_t v;
if (!Helpers::value2enum(value, v, FL_(enum_maxHeat))) { if (model() == EMSdevice::EMS_DEVICE_FLAG_CS6800) {
return false; if (id == 0) {
if (!Helpers::value2enum(value, v, FL_(enum_maxHeat1), {0, 2, 4, 5})) {
return false;
}
} else {
if (!Helpers::value2enum(value, v, FL_(enum_maxHeat2), {2, 4, 5})) {
return false;
}
}
} else {
if (!Helpers::value2enum(value, v, FL_(enum_maxHeat))) {
return false;
}
} }
write_command(0x492, id, v, 0x492); write_command(0x492, id, v, 0x492);
return true; return true;
@@ -3105,7 +3151,7 @@ bool Boiler::set_minTempSilent(const char * value, const int8_t id) {
bool Boiler::set_additionalHeaterOnly(const char * value, const int8_t id) { bool Boiler::set_additionalHeaterOnly(const char * value, const int8_t id) {
bool v; bool v;
if (Helpers::value2bool(value, v)) { if (Helpers::value2bool(value, v)) {
write_command(0x491, 1, v ? 1 : 0, 0x491); write_command(0x491, model() == EMSdevice::EMS_DEVICE_FLAG_CS6800 ? 3 : 1, v ? 1 : 0, 0x491);
return true; return true;
} }
return false; return false;

View File

@@ -34,6 +34,9 @@ class Boiler : public EMSdevice {
inline uint8_t model() const { inline uint8_t model() const {
return (flags() & 0x0F); return (flags() & 0x0F);
} }
inline bool isHeatPump() const {
return flags() & 0x08;
}
void check_active(); void check_active();
void store_energy(); void store_energy();
@@ -45,6 +48,7 @@ class Boiler : public EMSdevice {
static constexpr uint8_t EMS_TYPE_UBAFunctionTest = 0x1D; static constexpr uint8_t EMS_TYPE_UBAFunctionTest = 0x1D;
static constexpr uint8_t EMS_TYPE_UBAFlags = 0x35; static constexpr uint8_t EMS_TYPE_UBAFlags = 0x35;
static constexpr uint8_t EMS_TYPE_UBASetPoints = 0x1A; static constexpr uint8_t EMS_TYPE_UBASetPoints = 0x1A;
static constexpr uint16_t EMS_TYPE_UBASetPoints2 = 0x2E0;
static constexpr uint8_t EMS_TYPE_UBAParameters = 0x16; static constexpr uint8_t EMS_TYPE_UBAParameters = 0x16;
static constexpr uint8_t EMS_TYPE_UBAParametersPlus = 0xE6; static constexpr uint8_t EMS_TYPE_UBAParametersPlus = 0xE6;
static constexpr uint8_t EMS_TYPE_UBAParameterWWPlus = 0xEA; static constexpr uint8_t EMS_TYPE_UBAParameterWWPlus = 0xEA;
@@ -81,12 +85,13 @@ class Boiler : public EMSdevice {
uint8_t wwTempOK_; // DHW temperature ok on/off uint8_t wwTempOK_; // DHW temperature ok on/off
uint8_t wwActive_; // uint8_t wwActive_; //
uint8_t ww3wayValve_; // 3-way valve on WW uint8_t ww3wayValve_; // 3-way valve on WW
uint8_t wwFlowTempOffset_; // Boiler offset for ww heating uint8_t wwChargePump_;
uint8_t wwMaxPower_; // DHW maximum power uint8_t wwFlowTempOffset_; // Boiler offset for ww heating
uint8_t wwMaxTemp_; // DHW maximum temperature uint8_t wwMaxPower_; // DHW maximum power
uint32_t wwStarts_; // DHW starts uint8_t wwMaxTemp_; // DHW maximum temperature
uint32_t wwStartsHp_; // DHW starts Heatpump uint32_t wwStarts_; // DHW starts
uint32_t wwWorkM_; // DHW minutes uint32_t wwStartsHp_; // DHW starts Heatpump
uint32_t wwWorkM_; // DHW minutes
int8_t wwHystOn_; int8_t wwHystOn_;
int8_t wwHystOff_; int8_t wwHystOff_;
uint16_t wwMixerTemp_; // mixing temperature uint16_t wwMixerTemp_; // mixing temperature

View File

@@ -1275,30 +1275,14 @@ void Thermostat::process_RC300WWmode(std::shared_ptr<const Telegram> telegram) {
has_update(telegram, dhw->wwCircPump_, 1); // FF=off, 0=on ? has_update(telegram, dhw->wwCircPump_, 1); // FF=off, 0=on ?
if (model() == EMSdevice::EMS_DEVICE_FLAG_BC400 || model() == EMSdevice::EMS_DEVICE_FLAG_HMC310) { if (model() == EMSdevice::EMS_DEVICE_FLAG_BC400 || model() == EMSdevice::EMS_DEVICE_FLAG_HMC310) {
const uint8_t modes[] = {0, 5, 1, 2, 4}; // off, eco+, eco, comfort, auto has_enumupdate(telegram, dhw->wwMode_, 2, {0, 5, 1, 2, 4}, {0, 2, 3, 0, 4, 1});
uint8_t wwmode = dhw->wwMode_ < sizeof(modes) ? modes[dhw->wwMode_] : EMS_VALUE_UINT8_NOTSET;
telegram->read_value(wwmode, 2);
const uint8_t modes1[] = {0, 2, 3, 0, 4, 1};
has_update(dhw->wwMode_, wwmode < sizeof(modes1) ? modes1[wwmode] : EMS_VALUE_UINT8_NOTSET);
} else if (model() == EMSdevice::EMS_DEVICE_FLAG_R3000) { } else if (model() == EMSdevice::EMS_DEVICE_FLAG_R3000) {
// https://github.com/emsesp/EMS-ESP32/pull/1722#discussion_r1582823521 // https://github.com/emsesp/EMS-ESP32/pull/1722#discussion_r1582823521
const uint8_t modes[] = {1, 2, 5}; // normal, comfort, eco+ has_enumupdate(telegram, dhw->wwMode_, 2, {1, 2, 5}, {0, 0, 1, 0, 0, 2}); // normal, comfort, eco+
uint8_t wwmode = dhw->wwMode_ < sizeof(modes) ? modes[dhw->wwMode_] : EMS_VALUE_UINT8_NOTSET;
telegram->read_value(wwmode, 2);
const uint8_t modes1[] = {0, 0, 1, 0, 0, 2}; // 0=normal (1), 1=comfort(2), 2=eco+(5)
has_update(dhw->wwMode_, wwmode < sizeof(modes1) ? modes1[wwmode] : EMS_VALUE_UINT8_NOTSET);
} else if (model() == EMSdevice::EMS_DEVICE_FLAG_CR120) { } else if (model() == EMSdevice::EMS_DEVICE_FLAG_CR120) {
const uint8_t modes[] = {1, 2, 4}; //// 0=normal (1), 1=comfort(2), 2=auto(4) has_enumupdate(telegram, dhw->wwMode_, 2, {1, 2, 4}, {0, 0, 1, 0, 2, 0}); // normal, comfort, auto
uint8_t wwmode = dhw->wwMode_ < sizeof(modes) ? modes[dhw->wwMode_] : EMS_VALUE_UINT8_NOTSET;
telegram->read_value(wwmode, 2);
const uint8_t modes1[] = {0, 0, 1, 0, 2, 0};
has_update(dhw->wwMode_, wwmode < sizeof(modes1) ? modes1[wwmode] : EMS_VALUE_UINT8_NOTSET);
} else if (model() == EMSdevice::EMS_DEVICE_FLAG_RC100) { } else if (model() == EMSdevice::EMS_DEVICE_FLAG_RC100) {
const uint8_t modes[] = {0, 2, 3}; //// 0=off(0), 1=on(2), 2=auto(3) has_enumupdate(telegram, dhw->wwMode_, 2, {0, 2, 3}, {0, 0, 1, 2, 0, 0}); // normal, on, auto
uint8_t wwmode = dhw->wwMode_ < sizeof(modes) ? modes[dhw->wwMode_] : EMS_VALUE_UINT8_NOTSET;
telegram->read_value(wwmode, 2);
const uint8_t modes1[] = {0, 0, 1, 2, 0, 0};
has_update(dhw->wwMode_, wwmode < sizeof(modes1) ? modes1[wwmode] : EMS_VALUE_UINT8_NOTSET);
} else { } else {
has_update(telegram, dhw->wwMode_, 2); // 0=off, 1=low, 2=high, 3=auto, 4=own prog has_update(telegram, dhw->wwMode_, 2); // 0=off, 1=low, 2=high, 3=auto, 4=own prog
} }
@@ -2294,29 +2278,25 @@ bool Thermostat::set_wwmode(const char * value, const int8_t id) {
} }
write_command(0xB0, 2, set, 0xB0); write_command(0xB0, 2, set, 0xB0);
} else if (model() == EMSdevice::EMS_DEVICE_FLAG_BC400 || model() == EMSdevice::EMS_DEVICE_FLAG_HMC310) { } else if (model() == EMSdevice::EMS_DEVICE_FLAG_BC400 || model() == EMSdevice::EMS_DEVICE_FLAG_HMC310) {
if (!Helpers::value2enum(value, set, FL_(enum_wwMode4))) { // off, eco+, eco, comfort, auto if (!Helpers::value2enum(value, set, FL_(enum_wwMode4), {0, 5, 1, 2, 4})) { // off, eco+, eco, comfort, auto
return false; return false;
} }
const uint8_t modes[] = {0, 5, 1, 2, 4}; write_command(0x02F5 + dhw->offset(), 2, set, 0x02F5 + dhw->offset());
write_command(0x02F5 + dhw->offset(), 2, modes[set], 0x02F5 + dhw->offset());
} else if (model() == EMSdevice::EMS_DEVICE_FLAG_CR120) { } else if (model() == EMSdevice::EMS_DEVICE_FLAG_CR120) {
if (!Helpers::value2enum(value, set, FL_(enum_wwMode6))) { // normal, comfort, auto if (!Helpers::value2enum(value, set, FL_(enum_wwMode6), {0, 2, 4})) { // normal, comfort, auto
return false; return false;
} }
const uint8_t modes[] = {0, 2, 4}; write_command(0x02F5 + dhw->offset(), 2, set, 0x02F5 + dhw->offset());
write_command(0x02F5 + dhw->offset(), 2, modes[set], 0x02F5 + dhw->offset());
} else if (model() == EMSdevice::EMS_DEVICE_FLAG_RC100) { } else if (model() == EMSdevice::EMS_DEVICE_FLAG_RC100) {
if (!Helpers::value2enum(value, set, FL_(enum_wwMode2))) { // off, on, auto if (!Helpers::value2enum(value, set, FL_(enum_wwMode2), {0, 2, 3})) { // off, on, auto
return false; return false;
} }
const uint8_t modes[] = {0, 2, 3}; write_command(0x02F5 + dhw->offset(), 2, set, 0x02F5 + dhw->offset());
write_command(0x02F5 + dhw->offset(), 2, modes[set], 0x02F5 + dhw->offset());
} else if (model() == EMSdevice::EMS_DEVICE_FLAG_R3000) { // Rego3000 - https://github.com/emsesp/EMS-ESP32/issues/1692 } else if (model() == EMSdevice::EMS_DEVICE_FLAG_R3000) { // Rego3000 - https://github.com/emsesp/EMS-ESP32/issues/1692
if (!Helpers::value2enum(value, set, FL_(enum_wwMode5))) { if (!Helpers::value2enum(value, set, FL_(enum_wwMode5), {1, 2, 5})) {
return false; return false;
} }
const uint8_t modes[] = {1, 2, 5}; write_command(0x02F5 + dhw->offset(), 2, set, 0x02F5 + dhw->offset());
write_command(0x02F5 + dhw->offset(), 2, modes[set], 0x02F5 + dhw->offset());
} else if (model() == EMSdevice::EMS_DEVICE_FLAG_RC300) { } else if (model() == EMSdevice::EMS_DEVICE_FLAG_RC300) {
if (!Helpers::value2enum(value, set, FL_(enum_wwMode))) { if (!Helpers::value2enum(value, set, FL_(enum_wwMode))) {
return false; return false;

View File

@@ -1 +1 @@
#define EMSESP_APP_VERSION "3.7.3-dev.10" #define EMSESP_APP_VERSION "3.7.3-dev.11"

View File

@@ -59,6 +59,7 @@ void WebCustomEntity::read(WebCustomEntity & webEntity, JsonObject root) {
ei["uom"] = entityItem.value_type == DeviceValueType::BOOL ? 0 : entityItem.uom; ei["uom"] = entityItem.value_type == DeviceValueType::BOOL ? 0 : entityItem.uom;
ei["value_type"] = entityItem.value_type; ei["value_type"] = entityItem.value_type;
ei["writeable"] = entityItem.writeable; ei["writeable"] = entityItem.writeable;
ei["hide"] = entityItem.hide;
EMSESP::webCustomEntityService.render_value(ei, entityItem, true, true); EMSESP::webCustomEntityService.render_value(ei, entityItem, true, true);
} }
} }
@@ -94,6 +95,7 @@ StateUpdateResult WebCustomEntity::update(JsonObject root, WebCustomEntity & web
entityItem.uom = ei["uom"]; entityItem.uom = ei["uom"];
entityItem.value_type = ei["value_type"]; entityItem.value_type = ei["value_type"];
entityItem.writeable = ei["writeable"]; entityItem.writeable = ei["writeable"];
entityItem.hide = ei["hide"] | false;
entityItem.data = ei["value"].as<std::string>(); entityItem.data = ei["value"].as<std::string>();
if (entityItem.ram == 1) { if (entityItem.ram == 1) {
entityItem.device_id = 0; entityItem.device_id = 0;
@@ -295,7 +297,9 @@ bool WebCustomEntityService::get_value_info(JsonObject output, const char * cmd)
if (!strlen(cmd) || !strcmp(cmd, F_(values)) || !strcmp(cmd, F_(info))) { if (!strlen(cmd) || !strcmp(cmd, F_(values)) || !strcmp(cmd, F_(info))) {
// list all names // list all names
for (CustomEntityItem & entity : *customEntityItems_) { for (CustomEntityItem & entity : *customEntityItems_) {
render_value(output, entity); if (!entity.hide) {
render_value(output, entity);
}
} }
return true; return true;
} }
@@ -346,7 +350,7 @@ void WebCustomEntityService::get_value_json(JsonObject output, CustomEntityItem
// publish single value // publish single value
void WebCustomEntityService::publish_single(CustomEntityItem & entity) { void WebCustomEntityService::publish_single(CustomEntityItem & entity) {
if (!Mqtt::enabled() || !Mqtt::publish_single()) { if (!Mqtt::enabled() || !Mqtt::publish_single() || entity.hide) {
return; return;
} }
@@ -387,6 +391,9 @@ void WebCustomEntityService::publish(const bool force) {
bool ha_created = ha_registered_; bool ha_created = ha_registered_;
for (CustomEntityItem & entityItem : *customEntityItems_) { for (CustomEntityItem & entityItem : *customEntityItems_) {
if (entityItem.hide) {
continue;
}
render_value(output, entityItem); render_value(output, entityItem);
// create HA config // create HA config
if (Mqtt::ha_enabled() && !ha_registered_) { if (Mqtt::ha_enabled() && !ha_registered_) {
@@ -445,6 +452,9 @@ void WebCustomEntityService::publish(const bool force) {
Mqtt::add_ha_sections_to_doc(F_(custom), stat_t, config, !ha_created, val_cond); Mqtt::add_ha_sections_to_doc(F_(custom), stat_t, config, !ha_created, val_cond);
if (Mqtt::ha_optimistic() && (entityItem.writeable || entityItem.ram > 0)) {
config["optimistic"] = true;
}
ha_created |= Mqtt::queue_ha(topic, config.as<JsonObject>()); ha_created |= Mqtt::queue_ha(topic, config.as<JsonObject>());
} }
} }
@@ -470,7 +480,7 @@ uint8_t WebCustomEntityService::count_entities() {
for (CustomEntityItem & entity : *customEntityItems_) { for (CustomEntityItem & entity : *customEntityItems_) {
render_value(output, entity); render_value(output, entity);
if (output[entity.name].is<JsonVariantConst>() || entity.writeable) { if (!entity.hide && (output[entity.name].is<JsonVariantConst>() || entity.writeable)) {
count++; count++;
} }
} }
@@ -484,6 +494,9 @@ void WebCustomEntityService::generate_value_web(JsonObject output, const bool is
uint8_t index = 0; uint8_t index = 0;
for (const CustomEntityItem & entity : *customEntityItems_) { for (const CustomEntityItem & entity : *customEntityItems_) {
if (entity.hide) {
continue;
}
bool include = false; bool include = false;
JsonObject root_obj = nodes.add<JsonObject>(); // create the object, we know there is a value JsonObject root_obj = nodes.add<JsonObject>(); // create the object, we know there is a value

View File

@@ -40,6 +40,7 @@ class CustomEntityItem {
std::string data; std::string data;
uint8_t ram; uint8_t ram;
uint8_t * raw; uint8_t * raw;
bool hide;
}; };
class WebCustomEntity { class WebCustomEntity {

View File

@@ -154,8 +154,6 @@ bool WebSchedulerService::get_value_info(JsonObject output, const char * cmd) {
return true; return true;
} }
const char * attribute_s = Command::get_attribute(cmd);
if (!strcmp(cmd, F_(entities))) { if (!strcmp(cmd, F_(entities))) {
uint8_t i = 0; uint8_t i = 0;
char name[30]; char name[30];
@@ -166,6 +164,7 @@ bool WebSchedulerService::get_value_info(JsonObject output, const char * cmd) {
return true; return true;
} }
const char * attribute_s = Command::get_attribute(cmd);
for (const ScheduleItem & scheduleItem : *scheduleItems_) { for (const ScheduleItem & scheduleItem : *scheduleItems_) {
if (Helpers::toLower(scheduleItem.name) == cmd) { if (Helpers::toLower(scheduleItem.name) == cmd) {
get_value_json(output, scheduleItem); get_value_json(output, scheduleItem);
@@ -291,6 +290,9 @@ void WebSchedulerService::publish(const bool force) {
Mqtt::add_ha_bool(config); Mqtt::add_ha_bool(config);
Mqtt::add_ha_sections_to_doc(F_(scheduler), stat_t, config, !ha_created, val_cond); Mqtt::add_ha_sections_to_doc(F_(scheduler), stat_t, config, !ha_created, val_cond);
if (Mqtt::ha_optimistic()) {
config["optimistic"] = true;
}
ha_created |= Mqtt::queue_ha(topic, config.as<JsonObject>()); ha_created |= Mqtt::queue_ha(topic, config.as<JsonObject>());
} }
} }