mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-10 01:39:54 +03:00
Merge branch 'dev' of https://github.com/emsesp/EMS-ESP32 into dev
This commit is contained in:
60
interface/package-lock.json
generated
60
interface/package-lock.json
generated
@@ -12,7 +12,7 @@
|
||||
"@emotion/styled": "^11.10.5",
|
||||
"@msgpack/msgpack": "^2.8.0",
|
||||
"@mui/icons-material": "^5.11.0",
|
||||
"@mui/material": "^5.11.5",
|
||||
"@mui/material": "^5.11.6",
|
||||
"@table-library/react-table-library": "4.0.23",
|
||||
"@types/lodash": "^4.14.191",
|
||||
"@types/node": "^18.11.18",
|
||||
@@ -20,8 +20,7 @@
|
||||
"@types/react-dom": "^18.0.10",
|
||||
"@types/react-router-dom": "^5.3.3",
|
||||
"async-validator": "^4.2.5",
|
||||
"axios": "^1.2.3",
|
||||
"http-proxy-middleware": "^2.0.6",
|
||||
"axios": "^1.2.6",
|
||||
"jwt-decode": "^3.1.2",
|
||||
"lodash": "^4.17.21",
|
||||
"notistack": "^2.0.8",
|
||||
@@ -30,13 +29,14 @@
|
||||
"react-dom": "^18.2.0",
|
||||
"react-dropzone": "^14.2.3",
|
||||
"react-icons": "^4.7.1",
|
||||
"react-router-dom": "^6.7.0",
|
||||
"react-router-dom": "^6.8.0",
|
||||
"react-scripts": "5.0.1",
|
||||
"sockette": "^2.0.6",
|
||||
"typesafe-i18n": "^5.20.0",
|
||||
"typescript": "^4.9.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"http-proxy-middleware": "^2.0.6",
|
||||
"nodemon": "^2.0.20",
|
||||
"npm-run-all": "^4.1.5"
|
||||
}
|
||||
@@ -3082,9 +3082,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@mui/base": {
|
||||
"version": "5.0.0-alpha.114",
|
||||
"resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-alpha.114.tgz",
|
||||
"integrity": "sha512-ZpsG2I+zTOAnVTj3Un7TxD2zKRA2OhEPGMcWs/9ylPlS6VuGQSXowPooZiqarjT7TZ0+1bOe8titk/t8dLFiGw==",
|
||||
"version": "5.0.0-alpha.115",
|
||||
"resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-alpha.115.tgz",
|
||||
"integrity": "sha512-OGQ84whT/yNYd6xKCGGS6MxqEfjVjk5esXM7HP6bB2Rim7QICUapxZt4nm8q39fpT08rNDkv3xPVqDDwRdRg1g==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.7",
|
||||
"@emotion/is-prop-valid": "^1.2.0",
|
||||
@@ -3114,9 +3114,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@mui/core-downloads-tracker": {
|
||||
"version": "5.11.5",
|
||||
"resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.11.5.tgz",
|
||||
"integrity": "sha512-MIuWGjitOsugpRhp64CQY3ZEVMIu9M/L9ioql6QLSkz73+bGIlC9FEhfi670/GZ8pQIIGmtiGGwofYzlwEWjig==",
|
||||
"version": "5.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.11.6.tgz",
|
||||
"integrity": "sha512-lbD3qdafBOf2dlqKhOcVRxaPAujX+9UlPC6v8iMugMeAXe0TCgU3QbGXY3zrJsu6ex64WYDpH4y1+WOOBmWMuA==",
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/mui"
|
||||
@@ -3148,13 +3148,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@mui/material": {
|
||||
"version": "5.11.5",
|
||||
"resolved": "https://registry.npmjs.org/@mui/material/-/material-5.11.5.tgz",
|
||||
"integrity": "sha512-5fzjBbRYaB5MoEpvA32oalAWltOZ3/kSyuovuVmPc6UF6AG42lTtbdMLpdCygurFSGUMZYTg4Cjij52fKlDDgg==",
|
||||
"version": "5.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@mui/material/-/material-5.11.6.tgz",
|
||||
"integrity": "sha512-MzkkL5KC2PCkFiv8cLpkzgLUPXSrAtnvJBR0emV7mLVWbkwV3n5832vjBx154B6R032fHjFTziTh7YEb50nK6Q==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.7",
|
||||
"@mui/base": "5.0.0-alpha.114",
|
||||
"@mui/core-downloads-tracker": "^5.11.5",
|
||||
"@mui/base": "5.0.0-alpha.115",
|
||||
"@mui/core-downloads-tracker": "^5.11.6",
|
||||
"@mui/system": "^5.11.5",
|
||||
"@mui/types": "^7.2.3",
|
||||
"@mui/utils": "^5.11.2",
|
||||
@@ -3449,9 +3449,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@remix-run/router": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.3.0.tgz",
|
||||
"integrity": "sha512-nwQoYb3m4DDpHTeOwpJEuDt8lWVcujhYYSFGLluC+9es2PyLjm+jjq3IeRBQbwBtPLJE/lkuHuGHr8uQLgmJRA==",
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.3.1.tgz",
|
||||
"integrity": "sha512-+eun1Wtf72RNRSqgU7qM2AMX/oHp+dnx7BHk1qhK5ZHzdHTUU4LA1mGG1vT+jMc8sbhG3orvsfOmryjzx2PzQw==",
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
}
|
||||
@@ -5076,9 +5076,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/axios": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.2.3.tgz",
|
||||
"integrity": "sha512-pdDkMYJeuXLZ6Xj/Q5J3Phpe+jbGdsSzlQaFVkMQzRUL05+6+tetX8TV3p4HrU4kzuO9bt+io/yGQxuyxA/xcw==",
|
||||
"version": "1.2.6",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.2.6.tgz",
|
||||
"integrity": "sha512-rC/7F08XxZwjMV4iuWv+JpD3E0Ksqg9nac4IIg6RwNuF0JTeWoCo/mBNG54+tNhhI11G3/VDRbdDQTs9hGp4pQ==",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.15.0",
|
||||
"form-data": "^4.0.0",
|
||||
@@ -14884,11 +14884,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/react-router": {
|
||||
"version": "6.7.0",
|
||||
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.7.0.tgz",
|
||||
"integrity": "sha512-KNWlG622ddq29MAM159uUsNMdbX8USruoKnwMMQcs/QWZgFUayICSn2oB7reHce1zPj6CG18kfkZIunSSRyGHg==",
|
||||
"version": "6.8.0",
|
||||
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.8.0.tgz",
|
||||
"integrity": "sha512-760bk7y3QwabduExtudhWbd88IBbuD1YfwzpuDUAlJUJ7laIIcqhMvdhSVh1Fur1PE8cGl84L0dxhR3/gvHF7A==",
|
||||
"dependencies": {
|
||||
"@remix-run/router": "1.3.0"
|
||||
"@remix-run/router": "1.3.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
@@ -14898,12 +14898,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/react-router-dom": {
|
||||
"version": "6.7.0",
|
||||
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.7.0.tgz",
|
||||
"integrity": "sha512-jQtXUJyhso3kFw430+0SPCbmCmY1/kJv8iRffGHwHy3CkoomGxeYzMkmeSPYo6Egzh3FKJZRAL22yg5p2tXtfg==",
|
||||
"version": "6.8.0",
|
||||
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.8.0.tgz",
|
||||
"integrity": "sha512-hQouduSTywGJndE86CXJ2h7YEy4HYC6C/uh19etM+79FfQ6cFFFHnHyDlzO4Pq0eBUI96E4qVE5yUjA00yJZGQ==",
|
||||
"dependencies": {
|
||||
"@remix-run/router": "1.3.0",
|
||||
"react-router": "6.7.0"
|
||||
"@remix-run/router": "1.3.1",
|
||||
"react-router": "6.8.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"@emotion/styled": "^11.10.5",
|
||||
"@msgpack/msgpack": "^2.8.0",
|
||||
"@mui/icons-material": "^5.11.0",
|
||||
"@mui/material": "^5.11.5",
|
||||
"@mui/material": "^5.11.6",
|
||||
"@table-library/react-table-library": "4.0.23",
|
||||
"@types/lodash": "^4.14.191",
|
||||
"@types/node": "^18.11.18",
|
||||
@@ -16,8 +16,7 @@
|
||||
"@types/react-dom": "^18.0.10",
|
||||
"@types/react-router-dom": "^5.3.3",
|
||||
"async-validator": "^4.2.5",
|
||||
"axios": "^1.2.3",
|
||||
"http-proxy-middleware": "^2.0.6",
|
||||
"axios": "^1.2.6",
|
||||
"jwt-decode": "^3.1.2",
|
||||
"lodash": "^4.17.21",
|
||||
"notistack": "^2.0.8",
|
||||
@@ -26,7 +25,7 @@
|
||||
"react-dom": "^18.2.0",
|
||||
"react-dropzone": "^14.2.3",
|
||||
"react-icons": "^4.7.1",
|
||||
"react-router-dom": "^6.7.0",
|
||||
"react-router-dom": "^6.8.0",
|
||||
"react-scripts": "5.0.1",
|
||||
"sockette": "^2.0.6",
|
||||
"typesafe-i18n": "^5.20.0",
|
||||
@@ -99,6 +98,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"nodemon": "^2.0.20",
|
||||
"npm-run-all": "^4.1.5"
|
||||
"npm-run-all": "^4.1.5",
|
||||
"http-proxy-middleware": "^2.0.6"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1130,7 +1130,7 @@ void EMSdevice::dump_value_info() {
|
||||
if (dv.fullname != nullptr) {
|
||||
Serial.print(name_);
|
||||
Serial.print(',');
|
||||
Serial.print(device_type_name().c_str());
|
||||
Serial.print(device_type_name());
|
||||
Serial.print(',');
|
||||
|
||||
Serial.print(product_id_);
|
||||
@@ -1546,10 +1546,7 @@ bool EMSdevice::generate_values(JsonObject & output, const uint8_t tag_filter, c
|
||||
if (dv.type == DeviceValueType::BOOL && Helpers::hasValue(*(uint8_t *)(dv.value_p), EMS_VALUE_BOOL)) {
|
||||
// see how to render the value depending on the setting
|
||||
auto value_b = (bool)*(uint8_t *)(dv.value_p);
|
||||
if (Mqtt::ha_enabled() && (output_target == OUTPUT_TARGET::MQTT)) {
|
||||
char s[12];
|
||||
json[name] = Helpers::render_boolean(s, value_b); // for HA always render as string
|
||||
} else if (output_target == OUTPUT_TARGET::CONSOLE) {
|
||||
if (output_target == OUTPUT_TARGET::CONSOLE) {
|
||||
char s[12];
|
||||
json[name] = Helpers::render_boolean(s, value_b, true); // console use web settings
|
||||
} else if (EMSESP::system_.bool_format() == BOOL_FORMAT_TRUEFALSE) {
|
||||
|
||||
37
src/mqtt.cpp
37
src/mqtt.cpp
@@ -611,14 +611,14 @@ void Mqtt::ha_status() {
|
||||
}
|
||||
|
||||
doc["uniq_id"] = uniq;
|
||||
doc["object_id"] = uniq;
|
||||
doc["obj_id"] = uniq;
|
||||
|
||||
doc["stat_t"] = mqtt_base_ + "/status";
|
||||
doc["name"] = "EMS-ESP status";
|
||||
doc["payload_on"] = "online";
|
||||
doc["payload_off"] = "offline";
|
||||
doc["state_class"] = "measurement";
|
||||
doc["device_class"] = "connectivity";
|
||||
doc["pl_on"] = "online";
|
||||
doc["pl_off"] = "offline";
|
||||
doc["stat_cla"] = "measurement";
|
||||
doc["dev_cla"] = "connectivity";
|
||||
|
||||
// doc["avty_t"] = "~/status"; // commented out, as it causes errors in HA sometimes
|
||||
// doc["json_attr_t"] = "~/heartbeat"; // store also as HA attributes
|
||||
@@ -643,7 +643,7 @@ void Mqtt::ha_status() {
|
||||
}
|
||||
|
||||
publish_system_ha_sensor_config(DeviceValueType::STRING, "EMS Bus", "bus_status", DeviceValueUOM::NONE);
|
||||
publish_system_ha_sensor_config(DeviceValueType::INT, "Uptime", "uptime", DeviceValueUOM::NONE);
|
||||
publish_system_ha_sensor_config(DeviceValueType::STRING, "Uptime", "uptime", DeviceValueUOM::NONE);
|
||||
publish_system_ha_sensor_config(DeviceValueType::INT, "Uptime (sec)", "uptime_sec", DeviceValueUOM::SECONDS);
|
||||
publish_system_ha_sensor_config(DeviceValueType::BOOL, "NTP status", "ntp_status", DeviceValueUOM::CONNECTIVITY);
|
||||
publish_system_ha_sensor_config(DeviceValueType::INT, "Free memory", "freemem", DeviceValueUOM::KB);
|
||||
@@ -1063,7 +1063,7 @@ void Mqtt::publish_ha_sensor_config(uint8_t type, // EMSdev
|
||||
// build the payload
|
||||
DynamicJsonDocument doc(EMSESP_JSON_SIZE_HA_CONFIG);
|
||||
doc["uniq_id"] = uniq_id;
|
||||
doc["object_id"] = uniq_id; // same as unique_id
|
||||
doc["obj_id"] = uniq_id; // same as unique_id
|
||||
|
||||
const char * ic_ha = "ic"; // icon - only set this if there is no device class
|
||||
const char * sc_ha = "state_class"; // state class
|
||||
@@ -1080,7 +1080,7 @@ void Mqtt::publish_ha_sensor_config(uint8_t type, // EMSdev
|
||||
} else {
|
||||
snprintf(command_topic, sizeof(command_topic), "%s/%s/%s", mqtt_basename_.c_str(), device_name, entity);
|
||||
}
|
||||
doc["command_topic"] = command_topic;
|
||||
doc["cmd_t"] = command_topic;
|
||||
|
||||
// for enums, add options
|
||||
if (type == DeviceValueType::ENUM) {
|
||||
@@ -1088,7 +1088,7 @@ void Mqtt::publish_ha_sensor_config(uint8_t type, // EMSdev
|
||||
for (uint8_t i = 0; i < options_size; i++) {
|
||||
option_list.add(Helpers::translated_word(options[i]));
|
||||
}
|
||||
} else if (type != DeviceValueType::STRING) {
|
||||
} else if (type != DeviceValueType::STRING && type != DeviceValueType::BOOL) {
|
||||
// Must be Numeric....
|
||||
doc["mode"] = "box"; // auto, slider or box
|
||||
if (num_op > 0) {
|
||||
@@ -1155,13 +1155,20 @@ void Mqtt::publish_ha_sensor_config(uint8_t type, // EMSdev
|
||||
|
||||
// special case to handle booleans
|
||||
// applies to both Binary Sensor (read only) and a Switch (for a command)
|
||||
// always render boolean as strings true & false
|
||||
// and has no unit of measure or icon
|
||||
// has no unit of measure or icon
|
||||
if (type == DeviceValueType::BOOL) {
|
||||
if (EMSESP::system_.bool_format() == BOOL_FORMAT_TRUEFALSE) {
|
||||
doc["pl_on"] = true;
|
||||
doc["pl_off"] = false;
|
||||
} else if (EMSESP::system_.bool_format() == BOOL_FORMAT_10) {
|
||||
doc["pl_on"] = 1;
|
||||
doc["pl_off"] = 0;
|
||||
} else {
|
||||
char result[12];
|
||||
doc["payload_on"] = Helpers::render_boolean(result, true);
|
||||
doc["payload_off"] = Helpers::render_boolean(result, false);
|
||||
doc[sc_ha] = F_(measurement);
|
||||
doc["pl_on"] = Helpers::render_boolean(result, true);
|
||||
doc["pl_off"] = Helpers::render_boolean(result, false);
|
||||
}
|
||||
doc[sc_ha] = F_(measurement); //do we want this???
|
||||
} else {
|
||||
// always set the uom, using the standards except for hours/minutes/seconds
|
||||
// using HA specific codes from https://github.com/home-assistant/core/blob/dev/homeassistant/const.py
|
||||
@@ -1333,7 +1340,7 @@ void Mqtt::publish_ha_climate_config(const uint8_t tag, const bool has_roomtemp,
|
||||
|
||||
doc["~"] = mqtt_base_;
|
||||
doc["uniq_id"] = uniq_id_s;
|
||||
doc["object_id"] = uniq_id_s; // same as uniq_id
|
||||
doc["obj_id"] = uniq_id_s; // same as uniq_id
|
||||
doc["name"] = name_s;
|
||||
doc["mode_stat_t"] = topic_t;
|
||||
doc["mode_stat_tpl"] = mode_str_tpl;
|
||||
|
||||
@@ -167,10 +167,17 @@ void Shower::set_shower_state(bool state, bool force) {
|
||||
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
|
||||
if (EMSESP::system_.bool_format() == BOOL_FORMAT_TRUEFALSE) {
|
||||
doc["pl_on"] = true;
|
||||
doc["pl_off"] = false;
|
||||
} else if (EMSESP::system_.bool_format() == BOOL_FORMAT_10) {
|
||||
doc["pl_on"] = 1;
|
||||
doc["pl_off"] = 0;
|
||||
} else {
|
||||
char result[12];
|
||||
doc[("payload_on")] = Helpers::render_boolean(result, true);
|
||||
doc[("payload_off")] = Helpers::render_boolean(result, false);
|
||||
doc["pl_on"] = Helpers::render_boolean(result, true);
|
||||
doc["pl_off"] = Helpers::render_boolean(result, false);
|
||||
}
|
||||
|
||||
JsonObject dev = doc.createNestedObject("dev");
|
||||
JsonArray ids = dev.createNestedArray("ids");
|
||||
|
||||
@@ -249,6 +249,21 @@ StateUpdateResult WebSettings::update(JsonObject & root, WebSettings & settings)
|
||||
}
|
||||
#endif
|
||||
|
||||
//
|
||||
// these may need mqtt restart to rebuild HA discovery topics
|
||||
//
|
||||
prev = settings.bool_format;
|
||||
settings.bool_format = root["bool_format"] | EMSESP_DEFAULT_BOOL_FORMAT;
|
||||
EMSESP::system_.bool_format(settings.bool_format);
|
||||
if (Mqtt::ha_enabled())
|
||||
check_flag(prev, settings.bool_format, ChangeFlags::MQTT);
|
||||
|
||||
prev = settings.enum_format;
|
||||
settings.enum_format = root["enum_format"] | EMSESP_DEFAULT_ENUM_FORMAT;
|
||||
EMSESP::system_.enum_format(settings.enum_format);
|
||||
if (Mqtt::ha_enabled())
|
||||
check_flag(prev, settings.enum_format, ChangeFlags::MQTT);
|
||||
|
||||
//
|
||||
// without checks or necessary restarts...
|
||||
//
|
||||
@@ -264,15 +279,9 @@ StateUpdateResult WebSettings::update(JsonObject & root, WebSettings & settings)
|
||||
settings.readonly_mode = root["readonly_mode"] | false;
|
||||
EMSESP::system_.readonly_mode(settings.readonly_mode);
|
||||
|
||||
settings.bool_format = root["bool_format"] | EMSESP_DEFAULT_BOOL_FORMAT;
|
||||
EMSESP::system_.bool_format(settings.bool_format);
|
||||
|
||||
settings.bool_dashboard = root["bool_dashboard"] | EMSESP_DEFAULT_BOOL_FORMAT;
|
||||
EMSESP::system_.bool_dashboard(settings.bool_dashboard);
|
||||
|
||||
settings.enum_format = root["enum_format"] | EMSESP_DEFAULT_ENUM_FORMAT;
|
||||
EMSESP::system_.enum_format(settings.enum_format);
|
||||
|
||||
settings.weblog_level = root["weblog_level"] | EMSESP_DEFAULT_WEBLOG_LEVEL;
|
||||
settings.weblog_buffer = root["weblog_buffer"] | EMSESP_DEFAULT_WEBLOG_BUFFER;
|
||||
settings.weblog_compact = root["weblog_compact"] | EMSESP_DEFAULT_WEBLOG_COMPACT;
|
||||
|
||||
Reference in New Issue
Block a user