Merge pull request #798 from proddy/dev

minor updates and renaming system status entity in HA
This commit is contained in:
Proddy
2022-12-10 11:57:03 +01:00
committed by GitHub
12 changed files with 92 additions and 74 deletions

View File

@@ -5,6 +5,7 @@
## **IMPORTANT! BREAKING CHANGES** ## **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. - 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.
- Since 3.5.0b11 we have added support for multiple EMS-ESPs [#759] and also renamed the HA Entity IDs. For example what was previously `sensor.boiler_actual_boiler_temperature` is now using the shortname form `sensor.boiler_boiltemp` as opposed to the English description. Unfortunately this does means any HA dashboards, automation scripts and integrations (e.g. Grafana) need to be adjusted accordingly.
## Added ## Added

View File

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

View File

@@ -15,7 +15,7 @@
"@mui/material": "^5.10.17", "@mui/material": "^5.10.17",
"@table-library/react-table-library": "4.0.23", "@table-library/react-table-library": "4.0.23",
"@types/lodash": "^4.14.191", "@types/lodash": "^4.14.191",
"@types/node": "^18.11.11", "@types/node": "^18.11.12",
"@types/react": "^18.0.26", "@types/react": "^18.0.26",
"@types/react-dom": "^18.0.9", "@types/react-dom": "^18.0.9",
"@types/react-router-dom": "^5.3.3", "@types/react-router-dom": "^5.3.3",
@@ -31,11 +31,11 @@
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-dropzone": "^14.2.3", "react-dropzone": "^14.2.3",
"react-icons": "^4.7.1", "react-icons": "^4.7.1",
"react-router-dom": "^6.4.4", "react-router-dom": "^6.4.5",
"react-scripts": "5.0.1", "react-scripts": "5.0.1",
"sockette": "^2.0.6", "sockette": "^2.0.6",
"typesafe-i18n": "^5.17.1", "typesafe-i18n": "^5.17.1",
"typescript": "^4.9.3" "typescript": "^4.9.4"
}, },
"devDependencies": { "devDependencies": {
"nodemon": "^2.0.20", "nodemon": "^2.0.20",
@@ -3458,9 +3458,9 @@
} }
}, },
"node_modules/@remix-run/router": { "node_modules/@remix-run/router": {
"version": "1.0.4", "version": "1.0.5",
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.0.4.tgz", "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.0.5.tgz",
"integrity": "sha512-gTL8H5USTAKOyVA4xczzDJnC3HMssdFa3tRlwBicXynx9XfiXwneHnYQogwSKpdCkjXISrEKSTtX62rLpNEVQg==", "integrity": "sha512-my0Mycd+jruq/1lQuO5LBB6WTlL/e8DTCYWp44DfMTDcXz8DcTlgF0ISaLsGewt+ctHN+yA8xMq3q/N7uWJPug==",
"engines": { "engines": {
"node": ">=14" "node": ">=14"
} }
@@ -4017,9 +4017,9 @@
"integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==" "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA=="
}, },
"node_modules/@types/node": { "node_modules/@types/node": {
"version": "18.11.11", "version": "18.11.12",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.11.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.12.tgz",
"integrity": "sha512-KJ021B1nlQUBLopzZmPBVuGU9un7WJd/W4ya7Ih02B4Uwky5Nja0yGYav2EfYIk0RR2Q9oVhf60S2XR1BCWJ2g==" "integrity": "sha512-FgD3NtTAKvyMmD44T07zz2fEf+OKwutgBCEVM8GcvMGVGaDktiLNTDvPwC/LUe3PinMW+X6CuLOF2Ui1mAlSXg=="
}, },
"node_modules/@types/parse-json": { "node_modules/@types/parse-json": {
"version": "4.0.0", "version": "4.0.0",
@@ -14561,11 +14561,11 @@
} }
}, },
"node_modules/react-router": { "node_modules/react-router": {
"version": "6.4.4", "version": "6.4.5",
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.4.4.tgz", "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.4.5.tgz",
"integrity": "sha512-SA6tSrUCRfuLWeYsTJDuriRqfFIsrSvuH7SqAJHegx9ZgxadE119rU8oOX/rG5FYEthpdEaEljdjDlnBxvfr+Q==", "integrity": "sha512-1RQJ8bM70YEumHIlNUYc6mFfUDoWa5EgPDenK/fq0bxD8DYpQUi/S6Zoft+9DBrh2xmtg92N5HMAJgGWDhKJ5Q==",
"dependencies": { "dependencies": {
"@remix-run/router": "1.0.4" "@remix-run/router": "1.0.5"
}, },
"engines": { "engines": {
"node": ">=14" "node": ">=14"
@@ -14575,12 +14575,12 @@
} }
}, },
"node_modules/react-router-dom": { "node_modules/react-router-dom": {
"version": "6.4.4", "version": "6.4.5",
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.4.4.tgz", "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.4.5.tgz",
"integrity": "sha512-0Axverhw5d+4SBhLqLpzPhNkmv7gahUwlUVIOrRLGJ4/uwt30JVajVJXqv2Qr/LCwyvHhQc7YyK1Do8a9Jj7qA==", "integrity": "sha512-a7HsgikBR0wNfroBHcZUCd9+mLRqZS8R5U1Z1mzLWxFXEkUT3vR1XXmSIVoVpxVX8Bar0nQYYYc9Yipq8dWwAA==",
"dependencies": { "dependencies": {
"@remix-run/router": "1.0.4", "@remix-run/router": "1.0.5",
"react-router": "6.4.4" "react-router": "6.4.5"
}, },
"engines": { "engines": {
"node": ">=14" "node": ">=14"
@@ -16441,9 +16441,9 @@
} }
}, },
"node_modules/typescript": { "node_modules/typescript": {
"version": "4.9.3", "version": "4.9.4",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.3.tgz", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz",
"integrity": "sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA==", "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==",
"bin": { "bin": {
"tsc": "bin/tsc", "tsc": "bin/tsc",
"tsserver": "bin/tsserver" "tsserver": "bin/tsserver"
@@ -19818,9 +19818,9 @@
"integrity": "sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==" "integrity": "sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw=="
}, },
"@remix-run/router": { "@remix-run/router": {
"version": "1.0.4", "version": "1.0.5",
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.0.4.tgz", "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.0.5.tgz",
"integrity": "sha512-gTL8H5USTAKOyVA4xczzDJnC3HMssdFa3tRlwBicXynx9XfiXwneHnYQogwSKpdCkjXISrEKSTtX62rLpNEVQg==" "integrity": "sha512-my0Mycd+jruq/1lQuO5LBB6WTlL/e8DTCYWp44DfMTDcXz8DcTlgF0ISaLsGewt+ctHN+yA8xMq3q/N7uWJPug=="
}, },
"@rollup/plugin-babel": { "@rollup/plugin-babel": {
"version": "5.3.1", "version": "5.3.1",
@@ -20232,9 +20232,9 @@
"integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==" "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA=="
}, },
"@types/node": { "@types/node": {
"version": "18.11.11", "version": "18.11.12",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.11.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.12.tgz",
"integrity": "sha512-KJ021B1nlQUBLopzZmPBVuGU9un7WJd/W4ya7Ih02B4Uwky5Nja0yGYav2EfYIk0RR2Q9oVhf60S2XR1BCWJ2g==" "integrity": "sha512-FgD3NtTAKvyMmD44T07zz2fEf+OKwutgBCEVM8GcvMGVGaDktiLNTDvPwC/LUe3PinMW+X6CuLOF2Ui1mAlSXg=="
}, },
"@types/parse-json": { "@types/parse-json": {
"version": "4.0.0", "version": "4.0.0",
@@ -27723,20 +27723,20 @@
"integrity": "sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A==" "integrity": "sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A=="
}, },
"react-router": { "react-router": {
"version": "6.4.4", "version": "6.4.5",
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.4.4.tgz", "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.4.5.tgz",
"integrity": "sha512-SA6tSrUCRfuLWeYsTJDuriRqfFIsrSvuH7SqAJHegx9ZgxadE119rU8oOX/rG5FYEthpdEaEljdjDlnBxvfr+Q==", "integrity": "sha512-1RQJ8bM70YEumHIlNUYc6mFfUDoWa5EgPDenK/fq0bxD8DYpQUi/S6Zoft+9DBrh2xmtg92N5HMAJgGWDhKJ5Q==",
"requires": { "requires": {
"@remix-run/router": "1.0.4" "@remix-run/router": "1.0.5"
} }
}, },
"react-router-dom": { "react-router-dom": {
"version": "6.4.4", "version": "6.4.5",
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.4.4.tgz", "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.4.5.tgz",
"integrity": "sha512-0Axverhw5d+4SBhLqLpzPhNkmv7gahUwlUVIOrRLGJ4/uwt30JVajVJXqv2Qr/LCwyvHhQc7YyK1Do8a9Jj7qA==", "integrity": "sha512-a7HsgikBR0wNfroBHcZUCd9+mLRqZS8R5U1Z1mzLWxFXEkUT3vR1XXmSIVoVpxVX8Bar0nQYYYc9Yipq8dWwAA==",
"requires": { "requires": {
"@remix-run/router": "1.0.4", "@remix-run/router": "1.0.5",
"react-router": "6.4.4" "react-router": "6.4.5"
} }
}, },
"react-scripts": { "react-scripts": {
@@ -29117,9 +29117,9 @@
"requires": {} "requires": {}
}, },
"typescript": { "typescript": {
"version": "4.9.3", "version": "4.9.4",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.3.tgz", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz",
"integrity": "sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA==" "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg=="
}, },
"unbox-primitive": { "unbox-primitive": {
"version": "1.0.2", "version": "1.0.2",

View File

@@ -11,7 +11,7 @@
"@mui/material": "^5.10.17", "@mui/material": "^5.10.17",
"@table-library/react-table-library": "4.0.23", "@table-library/react-table-library": "4.0.23",
"@types/lodash": "^4.14.191", "@types/lodash": "^4.14.191",
"@types/node": "^18.11.11", "@types/node": "^18.11.12",
"@types/react": "^18.0.26", "@types/react": "^18.0.26",
"@types/react-dom": "^18.0.9", "@types/react-dom": "^18.0.9",
"@types/react-router-dom": "^5.3.3", "@types/react-router-dom": "^5.3.3",
@@ -27,11 +27,11 @@
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-dropzone": "^14.2.3", "react-dropzone": "^14.2.3",
"react-icons": "^4.7.1", "react-icons": "^4.7.1",
"react-router-dom": "^6.4.4", "react-router-dom": "^6.4.5",
"react-scripts": "5.0.1", "react-scripts": "5.0.1",
"sockette": "^2.0.6", "sockette": "^2.0.6",
"typesafe-i18n": "^5.17.1", "typesafe-i18n": "^5.17.1",
"typescript": "^4.9.3" "typescript": "^4.9.4"
}, },
"scripts": { "scripts": {
"start": "react-app-rewired start", "start": "react-app-rewired start",

View File

@@ -223,7 +223,13 @@ const MqttSettingsForm: FC = () => {
<> <>
<Grid item> <Grid item>
<BlockFormControlLabel <BlockFormControlLabel
control={<Checkbox name="multiple_instances" checked={data.multiple_instances} onChange={updateFormValue} />} control={
<Checkbox
name="multiple_instances"
checked={data.multiple_instances}
onChange={updateFormValue}
/>
}
label={LL.MQTT_MULTIPLE_INSTANCES()} label={LL.MQTT_MULTIPLE_INSTANCES()}
/> />
</Grid> </Grid>

View File

@@ -288,18 +288,18 @@ const WiFiSettingsForm: FC = () => {
</MessageBox> </MessageBox>
)} )}
{!restartNeeded && ( {!restartNeeded && (
<ButtonRow> <ButtonRow>
<Button <Button
startIcon={<SaveIcon />} startIcon={<SaveIcon />}
disabled={saving} disabled={saving}
variant="outlined" variant="outlined"
color="primary" color="primary"
type="submit" type="submit"
onClick={validateAndSubmit} onClick={validateAndSubmit}
> >
{LL.SAVE()} {LL.SAVE()}
</Button> </Button>
</ButtonRow> </ButtonRow>
)} )}
</> </>
); );

View File

@@ -37,9 +37,9 @@ const DeviceIcon: FC<DeviceIconProps> = ({ type }) => {
case 'Gateway': case 'Gateway':
return <AiOutlineGateway />; return <AiOutlineGateway />;
case 'Alert': case 'Alert':
return <AiOutlineAlert />; return <AiOutlineAlert />;
case 'Pump': case 'Pump':
return <AiOutlineChrome />; return <AiOutlineChrome />;
default: default:
return null; return null;
} }

View File

@@ -440,7 +440,7 @@ void AnalogSensor::publish_values(const bool force) {
StaticJsonDocument<EMSESP_JSON_SIZE_MEDIUM> config; StaticJsonDocument<EMSESP_JSON_SIZE_MEDIUM> config;
char stat_t[50]; char stat_t[50];
snprintf(stat_t, sizeof(stat_t), "%s/analogsensor_data", Mqtt::base().c_str()); snprintf(stat_t, sizeof(stat_t), "%s/analogsensor_data", Mqtt::base().c_str()); // use base path
config["stat_t"] = stat_t; config["stat_t"] = stat_t;
char str[50]; char str[50];

View File

@@ -505,7 +505,7 @@ void DallasSensor::publish_values(const bool force) {
config["dev_cla"] = "temperature"; config["dev_cla"] = "temperature";
char stat_t[50]; char stat_t[50];
snprintf(stat_t, sizeof(stat_t), "%s/dallassensor_data", Mqtt::base().c_str()); snprintf(stat_t, sizeof(stat_t), "%s/dallassensor_data", Mqtt::base().c_str()); // use base path
config["stat_t"] = stat_t; config["stat_t"] = stat_t;
config["unit_of_meas"] = EMSdevice::uom_to_string(DeviceValueUOM::DEGREES); config["unit_of_meas"] = EMSdevice::uom_to_string(DeviceValueUOM::DEGREES);

View File

@@ -57,7 +57,7 @@ class DallasSensor {
std::string name() const; std::string name() const;
void set_name(const std::string & name) { void set_name(const std::string & name) {
name_ = name; name_ = name;
} }
bool apply_customization(); bool apply_customization();

View File

@@ -443,6 +443,7 @@ void Mqtt::load_settings() {
}); });
// create basename from base // create basename from base
// by taking the MQTT base path and replacing all / with underscores
mqtt_basename_ = mqtt_base_; mqtt_basename_ = mqtt_base_;
std::replace(mqtt_basename_.begin(), mqtt_basename_.end(), '/', '_'); std::replace(mqtt_basename_.begin(), mqtt_basename_.end(), '/', '_');
} }
@@ -608,19 +609,25 @@ void Mqtt::ha_status() {
StaticJsonDocument<EMSESP_JSON_SIZE_HA_CONFIG> doc; StaticJsonDocument<EMSESP_JSON_SIZE_HA_CONFIG> doc;
char uniq[70]; char uniq[70];
snprintf(uniq, sizeof(uniq), "%s_status", mqtt_basename_.c_str()); // always use basename if (Mqtt::multiple_instances()) {
snprintf(uniq, sizeof(uniq), "%s_system_status", mqtt_basename_.c_str());
} else {
strcpy(uniq, "system_status");
}
doc["uniq_id"] = uniq; doc["uniq_id"] = uniq;
doc["object_id"] = uniq; doc["object_id"] = uniq;
doc["~"] = mqtt_base_;
// doc["avty_t"] = "~/status"; // commented out, as it causes errors in HA sometimes doc["stat_t"] = mqtt_base_ + "/status";
// doc["json_attr_t"] = "~/heartbeat"; // store also as HA attributes
doc["stat_t"] = "~/status";
doc["name"] = "EMS-ESP status"; doc["name"] = "EMS-ESP status";
doc["payload_on"] = "online"; doc["payload_on"] = "online";
doc["payload_off"] = "offline"; doc["payload_off"] = "offline";
doc["state_class"] = "measurement"; doc["state_class"] = "measurement";
doc["device_class"] = "connectivity"; doc["device_class"] = "connectivity";
// doc["avty_t"] = "~/status"; // commented out, as it causes errors in HA sometimes
// doc["json_attr_t"] = "~/heartbeat"; // store also as HA attributes
JsonObject dev = doc.createNestedObject("dev"); JsonObject dev = doc.createNestedObject("dev");
dev["name"] = "EMS-ESP"; dev["name"] = "EMS-ESP";
dev["sw"] = "v" + std::string(EMSESP_APP_VERSION); dev["sw"] = "v" + std::string(EMSESP_APP_VERSION);
@@ -630,7 +637,7 @@ void Mqtt::ha_status() {
ids.add("ems-esp"); ids.add("ems-esp");
char topic[MQTT_TOPIC_MAX_SIZE]; char topic[MQTT_TOPIC_MAX_SIZE];
snprintf(topic, sizeof(topic), "binary_sensor/%s/status/config", mqtt_basename_.c_str()); snprintf(topic, sizeof(topic), "binary_sensor/%s/system_status/config", mqtt_basename_.c_str());
Mqtt::publish_ha(topic, doc.as<JsonObject>()); // publish the config payload with retain flag Mqtt::publish_ha(topic, doc.as<JsonObject>()); // publish the config payload with retain flag
// create the sensors - must match the MQTT payload keys // create the sensors - must match the MQTT payload keys
@@ -982,7 +989,7 @@ void Mqtt::publish_ha_sensor_config(uint8_t type, // EMSdev
// build unique identifier which will be used in the topic, also used as object_id // build unique identifier which will be used in the topic, also used as object_id
char uniq_id[70]; char uniq_id[70];
if (multiple_instances_) { if (Mqtt::multiple_instances()) {
// prefix base name to each uniq_id // prefix base name to each uniq_id
snprintf(uniq_id, sizeof(uniq_id), "%s_%s_%s", mqtt_basename_.c_str(), device_name, entity_with_tag); snprintf(uniq_id, sizeof(uniq_id), "%s_%s_%s", mqtt_basename_.c_str(), device_name, entity_with_tag);
} else { } else {

View File

@@ -151,13 +151,17 @@ void Shower::set_shower_state(bool state, bool force) {
ha_configdone_ = true; ha_configdone_ = true;
StaticJsonDocument<EMSESP_JSON_SIZE_HA_CONFIG> doc; StaticJsonDocument<EMSESP_JSON_SIZE_HA_CONFIG> doc;
doc["name"] = "Shower Active"; doc["name"] = "Shower Active";
char str[70]; char str[70];
snprintf(str, sizeof(str), "%s_shower_active", Mqtt::basename().c_str()); snprintf(str, sizeof(str), "%s_shower_active", Mqtt::basename().c_str());
doc["uniq_id"] = str; doc["uniq_id"] = str;
doc["object_id"] = str; doc["object_id"] = str;
doc["~"] = Mqtt::base();
doc["stat_t"] = "~/shower_active"; char stat_t[50];
snprintf(stat_t, sizeof(stat_t), "%s/shower_active", Mqtt::base().c_str()); // use base path
doc["stat_t"] = stat_t;
// always render boolean as strings for HA // always render boolean as strings for HA
char result[12]; char result[12];
@@ -169,7 +173,7 @@ void Shower::set_shower_state(bool state, bool force) {
ids.add("ems-esp"); ids.add("ems-esp");
char topic[Mqtt::MQTT_TOPIC_MAX_SIZE]; char topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
snprintf(topic, sizeof(topic), "binary_sensor/%s/shower_active/config", Mqtt::base().c_str()); snprintf(topic, sizeof(topic), "binary_sensor/%s/shower_active/config", Mqtt::basename().c_str());
Mqtt::publish_ha(topic, doc.as<JsonObject>()); // publish the config payload with retain flag Mqtt::publish_ha(topic, doc.as<JsonObject>()); // publish the config payload with retain flag
} }
} }