Merge pull request #369 from proddy/dev

optimized create/remove mqtt discovery topics
This commit is contained in:
MichaelDvP
2022-02-22 08:27:17 +01:00
committed by GitHub
13 changed files with 125 additions and 131 deletions

View File

@@ -8,8 +8,8 @@
"name": "EMS-ESP", "name": "EMS-ESP",
"version": "3.4.0", "version": "3.4.0",
"dependencies": { "dependencies": {
"@emotion/react": "^11.7.1", "@emotion/react": "^11.8.1",
"@emotion/styled": "^11.6.0", "@emotion/styled": "^11.8.1",
"@msgpack/msgpack": "^2.7.2", "@msgpack/msgpack": "^2.7.2",
"@mui/icons-material": "^5.4.2", "@mui/icons-material": "^5.4.2",
"@mui/material": "^5.4.2", "@mui/material": "^5.4.2",
@@ -1857,9 +1857,9 @@
"integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==" "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow=="
}, },
"node_modules/@emotion/is-prop-valid": { "node_modules/@emotion/is-prop-valid": {
"version": "1.1.1", "version": "1.1.2",
"resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.1.1.tgz", "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.1.2.tgz",
"integrity": "sha512-bW1Tos67CZkOURLc0OalnfxtSXQJMrAMV0jZTVGJUPSOd4qgjF3+tTD5CwJM13PHA8cltGW1WGbbvV9NpvUZPw==", "integrity": "sha512-3QnhqeL+WW88YjYbQL5gUIkthuMw7a0NGbZ7wfFVk2kg/CK5w8w5FFa0RzWjyY1+sujN0NWbtSHH6OJmWHtJpQ==",
"dependencies": { "dependencies": {
"@emotion/memoize": "^0.7.4" "@emotion/memoize": "^0.7.4"
} }
@@ -1870,15 +1870,16 @@
"integrity": "sha512-igX9a37DR2ZPGYtV6suZ6whr8pTFtyHL3K/oLUotxpSVO2ASaprmAe2Dkq7tBo7CRY7MMDrAa9nuQP9/YG8FxQ==" "integrity": "sha512-igX9a37DR2ZPGYtV6suZ6whr8pTFtyHL3K/oLUotxpSVO2ASaprmAe2Dkq7tBo7CRY7MMDrAa9nuQP9/YG8FxQ=="
}, },
"node_modules/@emotion/react": { "node_modules/@emotion/react": {
"version": "11.7.1", "version": "11.8.1",
"resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.7.1.tgz", "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.8.1.tgz",
"integrity": "sha512-DV2Xe3yhkF1yT4uAUoJcYL1AmrnO5SVsdfvu+fBuS7IbByDeTVx9+wFmvx9Idzv7/78+9Mgx2Hcmr7Fex3tIyw==", "integrity": "sha512-XGaie4nRxmtP1BZYBXqC5JGqMYF2KRKKI7vjqNvQxyRpekVAZhb6QqrElmZCAYXH1L90lAelADSVZC4PFsrJ8Q==",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.13.10", "@babel/runtime": "^7.13.10",
"@emotion/babel-plugin": "^11.7.1",
"@emotion/cache": "^11.7.1", "@emotion/cache": "^11.7.1",
"@emotion/serialize": "^1.0.2", "@emotion/serialize": "^1.0.2",
"@emotion/sheet": "^1.1.0", "@emotion/sheet": "^1.1.0",
"@emotion/utils": "^1.0.0", "@emotion/utils": "^1.1.0",
"@emotion/weak-memoize": "^0.2.5", "@emotion/weak-memoize": "^0.2.5",
"hoist-non-react-statics": "^3.3.1" "hoist-non-react-statics": "^3.3.1"
}, },
@@ -1913,15 +1914,15 @@
"integrity": "sha512-u0AX4aSo25sMAygCuQTzS+HsImZFuS8llY8O7b9MDRzbJM0kVJlAz6KNDqcG7pOuQZJmj/8X/rAW+66kMnMW+g==" "integrity": "sha512-u0AX4aSo25sMAygCuQTzS+HsImZFuS8llY8O7b9MDRzbJM0kVJlAz6KNDqcG7pOuQZJmj/8X/rAW+66kMnMW+g=="
}, },
"node_modules/@emotion/styled": { "node_modules/@emotion/styled": {
"version": "11.6.0", "version": "11.8.1",
"resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.6.0.tgz", "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.8.1.tgz",
"integrity": "sha512-mxVtVyIOTmCAkFbwIp+nCjTXJNgcz4VWkOYQro87jE2QBTydnkiYusMrRGFtzuruiGK4dDaNORk4gH049iiQuw==", "integrity": "sha512-OghEVAYBZMpEquHZwuelXcRjRJQOVayvbmNR0zr174NHdmMgrNkLC6TljKC5h9lZLkN5WGrdUcrKlOJ4phhoTQ==",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.13.10", "@babel/runtime": "^7.13.10",
"@emotion/babel-plugin": "^11.3.0", "@emotion/babel-plugin": "^11.7.1",
"@emotion/is-prop-valid": "^1.1.1", "@emotion/is-prop-valid": "^1.1.2",
"@emotion/serialize": "^1.0.2", "@emotion/serialize": "^1.0.2",
"@emotion/utils": "^1.0.0" "@emotion/utils": "^1.1.0"
}, },
"peerDependencies": { "peerDependencies": {
"@babel/core": "^7.0.0", "@babel/core": "^7.0.0",
@@ -1943,9 +1944,9 @@
"integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==" "integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg=="
}, },
"node_modules/@emotion/utils": { "node_modules/@emotion/utils": {
"version": "1.0.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.0.0.tgz", "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.1.0.tgz",
"integrity": "sha512-mQC2b3XLDs6QCW+pDQDiyO/EdGZYOygE8s5N5rrzjSI4M3IejPE/JPndCBwRT9z982aqQNi6beWs1UeayrQxxA==" "integrity": "sha512-iRLa/Y4Rs5H/f2nimczYmS5kFJEbpiVvgN3XVfZ022IYhuNA1IRSHEizcof88LtCTXtl9S2Cxt32KgaXEu72JQ=="
}, },
"node_modules/@emotion/weak-memoize": { "node_modules/@emotion/weak-memoize": {
"version": "0.2.5", "version": "0.2.5",
@@ -18714,9 +18715,9 @@
"integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==" "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow=="
}, },
"@emotion/is-prop-valid": { "@emotion/is-prop-valid": {
"version": "1.1.1", "version": "1.1.2",
"resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.1.1.tgz", "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.1.2.tgz",
"integrity": "sha512-bW1Tos67CZkOURLc0OalnfxtSXQJMrAMV0jZTVGJUPSOd4qgjF3+tTD5CwJM13PHA8cltGW1WGbbvV9NpvUZPw==", "integrity": "sha512-3QnhqeL+WW88YjYbQL5gUIkthuMw7a0NGbZ7wfFVk2kg/CK5w8w5FFa0RzWjyY1+sujN0NWbtSHH6OJmWHtJpQ==",
"requires": { "requires": {
"@emotion/memoize": "^0.7.4" "@emotion/memoize": "^0.7.4"
} }
@@ -18727,15 +18728,16 @@
"integrity": "sha512-igX9a37DR2ZPGYtV6suZ6whr8pTFtyHL3K/oLUotxpSVO2ASaprmAe2Dkq7tBo7CRY7MMDrAa9nuQP9/YG8FxQ==" "integrity": "sha512-igX9a37DR2ZPGYtV6suZ6whr8pTFtyHL3K/oLUotxpSVO2ASaprmAe2Dkq7tBo7CRY7MMDrAa9nuQP9/YG8FxQ=="
}, },
"@emotion/react": { "@emotion/react": {
"version": "11.7.1", "version": "11.8.1",
"resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.7.1.tgz", "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.8.1.tgz",
"integrity": "sha512-DV2Xe3yhkF1yT4uAUoJcYL1AmrnO5SVsdfvu+fBuS7IbByDeTVx9+wFmvx9Idzv7/78+9Mgx2Hcmr7Fex3tIyw==", "integrity": "sha512-XGaie4nRxmtP1BZYBXqC5JGqMYF2KRKKI7vjqNvQxyRpekVAZhb6QqrElmZCAYXH1L90lAelADSVZC4PFsrJ8Q==",
"requires": { "requires": {
"@babel/runtime": "^7.13.10", "@babel/runtime": "^7.13.10",
"@emotion/babel-plugin": "^11.7.1",
"@emotion/cache": "^11.7.1", "@emotion/cache": "^11.7.1",
"@emotion/serialize": "^1.0.2", "@emotion/serialize": "^1.0.2",
"@emotion/sheet": "^1.1.0", "@emotion/sheet": "^1.1.0",
"@emotion/utils": "^1.0.0", "@emotion/utils": "^1.1.0",
"@emotion/weak-memoize": "^0.2.5", "@emotion/weak-memoize": "^0.2.5",
"hoist-non-react-statics": "^3.3.1" "hoist-non-react-statics": "^3.3.1"
} }
@@ -18758,15 +18760,15 @@
"integrity": "sha512-u0AX4aSo25sMAygCuQTzS+HsImZFuS8llY8O7b9MDRzbJM0kVJlAz6KNDqcG7pOuQZJmj/8X/rAW+66kMnMW+g==" "integrity": "sha512-u0AX4aSo25sMAygCuQTzS+HsImZFuS8llY8O7b9MDRzbJM0kVJlAz6KNDqcG7pOuQZJmj/8X/rAW+66kMnMW+g=="
}, },
"@emotion/styled": { "@emotion/styled": {
"version": "11.6.0", "version": "11.8.1",
"resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.6.0.tgz", "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.8.1.tgz",
"integrity": "sha512-mxVtVyIOTmCAkFbwIp+nCjTXJNgcz4VWkOYQro87jE2QBTydnkiYusMrRGFtzuruiGK4dDaNORk4gH049iiQuw==", "integrity": "sha512-OghEVAYBZMpEquHZwuelXcRjRJQOVayvbmNR0zr174NHdmMgrNkLC6TljKC5h9lZLkN5WGrdUcrKlOJ4phhoTQ==",
"requires": { "requires": {
"@babel/runtime": "^7.13.10", "@babel/runtime": "^7.13.10",
"@emotion/babel-plugin": "^11.3.0", "@emotion/babel-plugin": "^11.7.1",
"@emotion/is-prop-valid": "^1.1.1", "@emotion/is-prop-valid": "^1.1.2",
"@emotion/serialize": "^1.0.2", "@emotion/serialize": "^1.0.2",
"@emotion/utils": "^1.0.0" "@emotion/utils": "^1.1.0"
} }
}, },
"@emotion/unitless": { "@emotion/unitless": {
@@ -18775,9 +18777,9 @@
"integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==" "integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg=="
}, },
"@emotion/utils": { "@emotion/utils": {
"version": "1.0.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.0.0.tgz", "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.1.0.tgz",
"integrity": "sha512-mQC2b3XLDs6QCW+pDQDiyO/EdGZYOygE8s5N5rrzjSI4M3IejPE/JPndCBwRT9z982aqQNi6beWs1UeayrQxxA==" "integrity": "sha512-iRLa/Y4Rs5H/f2nimczYmS5kFJEbpiVvgN3XVfZ022IYhuNA1IRSHEizcof88LtCTXtl9S2Cxt32KgaXEu72JQ=="
}, },
"@emotion/weak-memoize": { "@emotion/weak-memoize": {
"version": "0.2.5", "version": "0.2.5",

View File

@@ -4,8 +4,8 @@
"private": true, "private": true,
"proxy": "http://localhost:3080", "proxy": "http://localhost:3080",
"dependencies": { "dependencies": {
"@emotion/react": "^11.7.1", "@emotion/react": "^11.8.1",
"@emotion/styled": "^11.6.0", "@emotion/styled": "^11.8.1",
"@msgpack/msgpack": "^2.7.2", "@msgpack/msgpack": "^2.7.2",
"@mui/icons-material": "^5.4.2", "@mui/icons-material": "^5.4.2",
"@mui/material": "^5.4.2", "@mui/material": "^5.4.2",

View File

@@ -193,8 +193,10 @@ const MqttSettingsForm: FC = () => {
{data.publish_single && ( {data.publish_single && (
<Grid item> <Grid item>
<BlockFormControlLabel <BlockFormControlLabel
control={<Checkbox name="publish_single2cmd" checked={data.publish_single2cmd} onChange={updateFormValue} />} control={
label="publish to command topics (ioBroker)" <Checkbox name="publish_single2cmd" checked={data.publish_single2cmd} onChange={updateFormValue} />
}
label="Publish to command topics (ioBroker)"
/> />
</Grid> </Grid>
)} )}
@@ -203,14 +205,14 @@ const MqttSettingsForm: FC = () => {
<Grid item> <Grid item>
<BlockFormControlLabel <BlockFormControlLabel
control={<Checkbox name="ha_enabled" checked={data.ha_enabled} onChange={updateFormValue} />} control={<Checkbox name="ha_enabled" checked={data.ha_enabled} onChange={updateFormValue} />}
label="Enable MQTT Discovery (for Home Assistant, Domoticz)" label="Enable MQTT Discovery (Home Assistant, Domoticz)"
/> />
</Grid> </Grid>
{data.ha_enabled && ( {data.ha_enabled && (
<Grid item xs={6}> <Grid item xs={6}>
<ValidatedTextField <ValidatedTextField
name="discovery_prefix" name="discovery_prefix"
label="Prefix for the Discovery topic" label="Prefix for the Discovery topics"
fullWidth fullWidth
variant="outlined" variant="outlined"
value={data.discovery_prefix} value={data.discovery_prefix}

View File

@@ -834,7 +834,6 @@ const DashboardData: FC = () => {
InputProps={{ InputProps={{
startAdornment: <InputAdornment position="start">%</InputAdornment> startAdornment: <InputAdornment position="start">%</InputAdornment>
}} }}
/> />
</Grid> </Grid>
</> </>

View File

@@ -459,15 +459,7 @@ void Thermostat::publish_ha_config_hc(std::shared_ptr<Thermostat::HeatingCircuit
char topic[Mqtt::MQTT_TOPIC_MAX_SIZE]; char topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
snprintf(topic, sizeof(topic), "climate/%s/thermostat_hc%d/config", Mqtt::base().c_str(), hc_num); snprintf(topic, sizeof(topic), "climate/%s/thermostat_hc%d/config", Mqtt::base().c_str(), hc_num);
Mqtt::publish_ha(topic, doc.as<JsonObject>()); // publish the config payload with retain flag Mqtt::publish_ha(topic, doc.as<JsonObject>()); // publish the config payload with retain flag
/*
// enable the a special "thermostat_hc<n>" topic to take both mode strings and floats for each of the heating circuits
std::string topic2(Mqtt::MQTT_TOPIC_MAX_SIZE, '\0');
snprintf(&topic2[0], topic2.capacity() + 1, "thermostat_hc%d", hc_num);
Mqtt::subscribe(EMSdevice::DeviceType::THERMOSTAT, topic2, [=](const char * m) { return thermostat_ha_cmd(m, hc_num); });
*/
} }
// for HA specifically when receiving over MQTT in the thermostat topic // for HA specifically when receiving over MQTT in the thermostat topic
@@ -679,14 +671,22 @@ void Thermostat::process_RC10Monitor(std::shared_ptr<const Telegram> telegram) {
// add the HVAC/Climate HA component for the HC // add the HVAC/Climate HA component for the HC
void Thermostat::add_ha_climate(std::shared_ptr<HeatingCircuit> hc) { void Thermostat::add_ha_climate(std::shared_ptr<HeatingCircuit> hc) {
if (!Mqtt::ha_enabled() || (hc->ha_climate_created())) { if (!Mqtt::ha_enabled()) {
return; return;
} }
// only if it has a valid seltemp (roomtemp is optional) // note, this doesn't account for whether any of the device values have been excluded
if (Helpers::hasValue(hc->selTemp)) { if (hc->ha_climate_created()) {
// see if we've lost the selTemp (roomTemp/currTemp is optional and checked in the publish_ha_config_hc() function)
if (!Helpers::hasValue(hc->selTemp)) {
char topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
snprintf(topic, sizeof(topic), "climate/%s/thermostat_hc%d/config", Mqtt::base().c_str(), hc->hc_num());
Mqtt::publish_ha(topic);
}
} else {
// create the climate component, only once
publish_ha_config_hc(hc); publish_ha_config_hc(hc);
hc->ha_climate_created(true); // only create it once hc->ha_climate_created(true);
} }
} }

View File

@@ -779,7 +779,7 @@ void EMSdevice::exclude_entity(uint8_t id) {
for (auto & dv : devicevalues_) { for (auto & dv : devicevalues_) {
if (dv.id == id) { if (dv.id == id) {
#if defined(EMSESP_USE_SERIAL) #if defined(EMSESP_USE_SERIAL)
Serial.print("exclude_entity() Removing state for device value: "); Serial.print("exclude_entity() Removing Visible for device value: ");
Serial.println(read_flash_string(dv.full_name).c_str()); Serial.println(read_flash_string(dv.full_name).c_str());
#endif #endif
dv.remove_state(DeviceValueState::DV_VISIBLE); // this will remove from MQTT payloads and showing in web & console dv.remove_state(DeviceValueState::DV_VISIBLE); // this will remove from MQTT payloads and showing in web & console
@@ -1225,47 +1225,36 @@ bool EMSdevice::generate_values(JsonObject & output, const uint8_t tag_filter, c
return has_values; return has_values;
} }
// remove the Home Assistant configs for each device value/entity if its not visible or active
// 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_VISIBLE)) || (!dv.has_state(DeviceValueState::DV_ACTIVE)))) {
Mqtt::publish_ha_sensor_config(dv, "", "", true); // delete topic (remove = true)
dv.remove_state(DeviceValueState::DV_HA_CONFIG_CREATED);
}
}
}
// create the Home Assistant configs for each device value / entity // create the Home Assistant configs for each device value / entity
// this is called when an MQTT publish is done via an EMS Device in emsesp.cpp // this is called when an MQTT publish is done via an EMS Device in emsesp.cpp::publish_device_values()
void EMSdevice::publish_mqtt_ha_entity_config() { void EMSdevice::mqtt_ha_entity_config_create() {
// create the main device config if not already done, per device type bool create_device_config = !ha_config_done(); // do we need to create the main Discovery device config with this entity?
bool create_device_config = !ha_config_done();
// check the state of each of the device values // check the state of each of the device values
// create the discovery topic if if hasn't already been created, not a command (like reset) and is active and visible
for (auto & dv : devicevalues_) { for (auto & dv : devicevalues_) {
if (dv.has_state(DeviceValueState::DV_ACTIVE)) { if ((!dv.has_state(DeviceValueState::DV_HA_CONFIG_CREATED) && dv.type != DeviceValueType::CMD) && dv.has_state(DeviceValueState::DV_ACTIVE)
// entity has an active value (it means it contains a valid value) && dv.has_state(DeviceValueState::DV_VISIBLE)) {
// create_device_config is only done once for the EMS device. It can added to any entity, so we take the first
if (dv.has_state(DeviceValueState::DV_VISIBLE)) {
// visible
// if the HA config topic hasn't been created it, do it now (unless its a command like reset)
if (!dv.has_state(DeviceValueState::DV_HA_CONFIG_CREATED) && dv.type != DeviceValueType::CMD) {
Mqtt::publish_ha_sensor_config(dv, name(), brand_to_string(), false, create_device_config); Mqtt::publish_ha_sensor_config(dv, name(), brand_to_string(), false, create_device_config);
dv.add_state(DeviceValueState::DV_HA_CONFIG_CREATED); dv.add_state(DeviceValueState::DV_HA_CONFIG_CREATED);
if (create_device_config) { create_device_config = false; // only create the main config once
create_device_config = false;
}
}
} else {
// not visible. It must be on the entity exclusion list defined in the Customizations service
// if a HA config topic was created then remove it. This entity has become 'lost'
if (dv.has_state(DeviceValueState::DV_HA_CONFIG_CREATED)) {
Mqtt::publish_ha_sensor_config(dv, name(), brand_to_string(), true, create_device_config); // remove /config
dv.remove_state(DeviceValueState::DV_HA_CONFIG_CREATED);
}
}
} else {
// entity does not have an active value
// if a HA config topic was created then remove it. This entity has become 'lost'
// https://github.com/emsesp/EMS-ESP32/issues/196
if (dv.has_state(DeviceValueState::DV_HA_CONFIG_CREATED)) {
Mqtt::publish_ha_sensor_config(dv, name(), brand_to_string(), true, create_device_config); // remove /config
dv.remove_state(DeviceValueState::DV_HA_CONFIG_CREATED);
}
} }
} }
ha_config_done(true); // assume we've created the config ha_config_done(!create_device_config);
} }
// remove all config topics in HA // remove all config topics in HA

View File

@@ -245,7 +245,8 @@ class EMSdevice {
void publish_value(void * value); void publish_value(void * value);
void publish_all_values(); void publish_all_values();
void publish_mqtt_ha_entity_config(); void mqtt_ha_entity_config_create();
void mqtt_ha_entity_config_remove();
const std::string telegram_type_name(std::shared_ptr<const Telegram> telegram); const std::string telegram_type_name(std::shared_ptr<const Telegram> telegram);

View File

@@ -560,13 +560,18 @@ void EMSESP::publish_device_values(uint8_t device_type) {
// group by device type // group by device type
for (const auto & emsdevice : emsdevices) { for (const auto & emsdevice : emsdevices) {
if (emsdevice && (emsdevice->device_type() == device_type)) { if (emsdevice && (emsdevice->device_type() == device_type)) {
// specially for HA // specially for MQTT Discovery
// we may have some RETAINED /config topics that reference fields in the data payloads that no longer exist // 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 // remove them immediately to prevent HA from complaining
// we need to do this first before the data payload is published, and only done once! // we need to do this first before the data payload is published, and only done once!
if (Mqtt::ha_enabled() && emsdevice->ha_config_firstrun()) { if (Mqtt::ha_enabled()) {
if (emsdevice->ha_config_firstrun()) {
emsdevice->ha_config_clear(); emsdevice->ha_config_clear();
emsdevice->ha_config_firstrun(false); emsdevice->ha_config_firstrun(false);
} else {
// see if we need to delete and /config topics before adding the payloads
emsdevice->mqtt_ha_entity_config_remove();
}
} }
// if its a boiler, generate json for each group and publish it directly. not nested // if its a boiler, generate json for each group and publish it directly. not nested
@@ -629,7 +634,7 @@ void EMSESP::publish_device_values(uint8_t device_type) {
// we want to create the /config topic after the data payload to prevent HA from throwing up a warning // we want to create the /config topic after the data payload to prevent HA from throwing up a warning
if (Mqtt::ha_enabled()) { if (Mqtt::ha_enabled()) {
emsdevice->publish_mqtt_ha_entity_config(); emsdevice->mqtt_ha_entity_config_create();
} }
} }
} }

View File

@@ -892,19 +892,8 @@ void Mqtt::process_queue() {
mqtt_messages_.pop_front(); // remove the message from the queue mqtt_messages_.pop_front(); // remove the message from the queue
} }
// publish HA sensor for System using the heartbeat tag
void Mqtt::publish_system_ha_sensor_config(uint8_t type, const __FlashStringHelper * name, const __FlashStringHelper * entity, const uint8_t uom) {
StaticJsonDocument<EMSESP_JSON_SIZE_HA_CONFIG> doc;
JsonObject dev_json = doc.createNestedObject("dev");
JsonArray ids = dev_json.createNestedArray("ids");
ids.add("ems-esp");
publish_ha_sensor_config(type, DeviceValueTAG::TAG_HEARTBEAT, name, EMSdevice::DeviceType::SYSTEM, entity, uom, false, false, false, nullptr, 0, 0, 0, dev_json);
}
// create's a ha sensor config topic from a device value object // create's a ha sensor config topic from a device value object
// and also takes a flag to see whether it will also create the main HA device config // and also takes a flag (create_device_config) used to also create the main HA device config. This is only needed for one entity
void Mqtt::publish_ha_sensor_config(DeviceValue & dv, const std::string & model, const std::string & brand, const bool remove, const bool create_device_config) { void Mqtt::publish_ha_sensor_config(DeviceValue & dv, const std::string & model, const std::string & brand, const bool remove, const bool create_device_config) {
StaticJsonDocument<EMSESP_JSON_SIZE_HA_CONFIG> dev_json; StaticJsonDocument<EMSESP_JSON_SIZE_HA_CONFIG> dev_json;
@@ -934,7 +923,6 @@ void Mqtt::publish_ha_sensor_config(DeviceValue & dv, const std::string & model,
dv.short_name, dv.short_name,
dv.uom, dv.uom,
remove, remove,
create_device_config,
dv.has_cmd, dv.has_cmd,
dv.options, dv.options,
dv.options_size, dv.options_size,
@@ -943,6 +931,17 @@ void Mqtt::publish_ha_sensor_config(DeviceValue & dv, const std::string & model,
dev_json.as<JsonObject>()); dev_json.as<JsonObject>());
} }
// publish HA sensor for System using the heartbeat tag
void Mqtt::publish_system_ha_sensor_config(uint8_t type, const __FlashStringHelper * name, const __FlashStringHelper * entity, const uint8_t uom) {
StaticJsonDocument<EMSESP_JSON_SIZE_HA_CONFIG> doc;
JsonObject dev_json = doc.createNestedObject("dev");
JsonArray ids = dev_json.createNestedArray("ids");
ids.add("ems-esp");
publish_ha_sensor_config(type, DeviceValueTAG::TAG_HEARTBEAT, name, EMSdevice::DeviceType::SYSTEM, entity, uom, false, false, nullptr, 0, 0, 0, dev_json);
}
// MQTT discovery configs // MQTT discovery configs
// entity must match the key/value pair in the *_data topic // entity must match the key/value pair in the *_data topic
// note: some extra string copying done here, it looks messy but does help with heap fragmentation issues // note: some extra string copying done here, it looks messy but does help with heap fragmentation issues
@@ -953,7 +952,6 @@ void Mqtt::publish_ha_sensor_config(uint8_t type,
const __FlashStringHelper * entity, // shortname const __FlashStringHelper * entity, // shortname
const uint8_t uom, // EMSdevice::DeviceValueUOM (0=NONE) const uint8_t uom, // EMSdevice::DeviceValueUOM (0=NONE)
const bool remove, // true if we want to remove this topic const bool remove, // true if we want to remove this topic
const bool create_device_config, // true if need to create main device config
const bool has_cmd, const bool has_cmd,
const __FlashStringHelper * const * options, const __FlashStringHelper * const * options,
uint8_t options_size, uint8_t options_size,

View File

@@ -92,7 +92,6 @@ class Mqtt {
static void static void
publish_ha_sensor_config(DeviceValue & dv, const std::string & model, const std::string & brand, const bool remove, const bool create_device_config = false); publish_ha_sensor_config(DeviceValue & dv, const std::string & model, const std::string & brand, const bool remove, const bool create_device_config = false);
static void publish_ha_sensor_config(uint8_t type, static void publish_ha_sensor_config(uint8_t type,
uint8_t tag, uint8_t tag,
const __FlashStringHelper * name, const __FlashStringHelper * name,
@@ -100,7 +99,6 @@ class Mqtt {
const __FlashStringHelper * entity, const __FlashStringHelper * entity,
const uint8_t uom, const uint8_t uom,
const bool remove, const bool remove,
const bool create_device_config,
const bool has_cmd, const bool has_cmd,
const __FlashStringHelper * const * options, const __FlashStringHelper * const * options,
uint8_t options_size, uint8_t options_size,

View File

@@ -496,19 +496,19 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
if (command == "ha") { if (command == "ha") {
shell.printfln(F("Testing HA mqtt discovery")); shell.printfln(F("Testing HA mqtt discovery"));
// Mqtt::ha_enabled(true); Mqtt::ha_enabled(true);
Mqtt::ha_enabled(false); // Mqtt::ha_enabled(false);
// Mqtt::nested_format(1); // is nested Mqtt::nested_format(1); // is nested
Mqtt::nested_format(2); // not nested // Mqtt::nested_format(2); // not nested
// run_test("boiler"); run_test("boiler");
run_test("thermostat"); run_test("thermostat");
// run_test("solar"); run_test("solar");
// run_test("mixer"); run_test("mixer");
shell.invoke_command("call system publish"); shell.invoke_command("call system publish");
// shell.invoke_command("show mqtt"); shell.invoke_command("show mqtt");
// shell.invoke_command("call boiler fanwork"); // shell.invoke_command("call boiler fanwork");
// shell.invoke_command("call thermostat seltemp"); // sensor.thermostat_hc1_selected_room_temperature // shell.invoke_command("call thermostat seltemp"); // sensor.thermostat_hc1_selected_room_temperature

View File

@@ -35,8 +35,8 @@ namespace emsesp {
// #define EMSESP_DEBUG_DEFAULT "boiler" // #define EMSESP_DEBUG_DEFAULT "boiler"
// #define EMSESP_DEBUG_DEFAULT "mqtt2" // #define EMSESP_DEBUG_DEFAULT "mqtt2"
// #define EMSESP_DEBUG_DEFAULT "mqtt_nested" // #define EMSESP_DEBUG_DEFAULT "mqtt_nested"
// #define EMSESP_DEBUG_DEFAULT "ha" #define EMSESP_DEBUG_DEFAULT "ha"
#define EMSESP_DEBUG_DEFAULT "exclude" // #define EMSESP_DEBUG_DEFAULT "exclude"
// #define EMSESP_DEBUG_DEFAULT "board_profile" // #define EMSESP_DEBUG_DEFAULT "board_profile"
// #define EMSESP_DEBUG_DEFAULT "shower_alert" // #define EMSESP_DEBUG_DEFAULT "shower_alert"
// #define EMSESP_DEBUG_DEFAULT "310" // #define EMSESP_DEBUG_DEFAULT "310"

View File

@@ -1 +1 @@
#define EMSESP_APP_VERSION "3.4.0b6" #define EMSESP_APP_VERSION "3.4.0b7"