diff --git a/src/emsdevice.cpp b/src/emsdevice.cpp index 6263554ee..c1d62e3c3 100644 --- a/src/emsdevice.cpp +++ b/src/emsdevice.cpp @@ -293,7 +293,7 @@ bool EMSdevice::is_fetch(uint16_t telegram_id) { // called from the command 'entities' void EMSdevice::list_device_entries(JsonObject & output) { for (const auto & dv : devicevalues_) { - if (dv.has_state(DeviceValueState::DV_VISIBLE) && dv.type != DeviceValueType::CMD) { + if (dv.has_state(DeviceValueState::DV_VISIBLE) && dv.type != DeviceValueType::CMD && dv.full_name) { // if we have a tag prefix it char key[50]; if (!EMSdevice::tag_to_mqtt(dv.tag).empty()) { @@ -445,23 +445,24 @@ void EMSdevice::register_device_value(uint8_t tag, // determine state uint8_t state = DeviceValueState::DV_VISIBLE; // default to visible - if (!full_name) { - state = DeviceValueState::DV_DEFAULT; // don't show if the full_name is empty - } else { - // scan through customizations to see if it's on the exclusion list by matching the productID and deviceID - EMSESP::webCustomizationService.read([&](WebCustomization & settings) { - for (EntityCustomization entityCustomization : settings.entityCustomizations) { - if ((entityCustomization.product_id == product_id()) && (entityCustomization.device_id == device_id())) { - for (uint8_t entity_id : entityCustomization.entity_ids) { - if (entity_id == dv_id) { - state = DeviceValueState::DV_DEFAULT; // it's on the exclude list, turn off active and visible flags - break; - } + + // if (!full_name) { + // state = DeviceValueState::DV_DEFAULT; // don't show if the full_name is empty + // } else { + // scan through customizations to see if it's on the exclusion list by matching the productID and deviceID + EMSESP::webCustomizationService.read([&](WebCustomization & settings) { + for (EntityCustomization entityCustomization : settings.entityCustomizations) { + if ((entityCustomization.product_id == product_id()) && (entityCustomization.device_id == device_id())) { + for (uint8_t entity_id : entityCustomization.entity_ids) { + if (entity_id == dv_id) { + state = DeviceValueState::DV_DEFAULT; // it's on the exclude list, turn off active and visible flags + break; } } } - }); - } + } + }); + // } // add the device devicevalues_.emplace_back(device_type_, tag, value_p, type, options, options_size, short_name, full_name, uom, 0, has_cmd, min, max, state, dv_id); @@ -526,9 +527,9 @@ void EMSdevice::register_device_value(uint8_t tag, // check if value is visible bool EMSdevice::is_visible(void * value_p) { - for (auto & dv : devicevalues_) { - if (dv.value_p == value_p && dv.has_state(DeviceValueState::DV_VISIBLE)) { - return true; + for (const auto & dv : devicevalues_) { + if (dv.value_p == value_p) { + return dv.has_state(DeviceValueState::DV_VISIBLE); } } return false; @@ -539,7 +540,7 @@ void EMSdevice::publish_value(void * value_p) { if (!Mqtt::publish_single() || value_p == nullptr) { return; } - for (auto & dv : devicevalues_) { + for (const auto & dv : devicevalues_) { if (dv.value_p == value_p && dv.has_state(DeviceValueState::DV_VISIBLE)) { char topic[Mqtt::MQTT_TOPIC_MAX_SIZE]; if (Mqtt::publish_single2cmd()) { @@ -640,7 +641,7 @@ const std::string EMSdevice::get_value_uom(const char * key) { // look up key in our device value list for (const auto & dv : devicevalues_) { - if (dv.has_state(DeviceValueState::DV_VISIBLE)) { + if (dv.has_state(DeviceValueState::DV_VISIBLE) && dv.full_name) { if (read_flash_string(dv.full_name) == key_p) { // ignore TIME since "minutes" is already added to the string value if ((dv.uom == DeviceValueUOM::NONE) || (dv.uom == DeviceValueUOM::MINUTES)) { @@ -667,7 +668,7 @@ void EMSdevice::generate_values_web(JsonObject & output) { // 1. full_name cannot be empty // 2. it must have a valid value, if it is not a command like 'reset' - if (dv.has_state(DeviceValueState::DV_VISIBLE) && (dv.hasValue() || (dv.type == DeviceValueType::CMD))) { + if (dv.has_state(DeviceValueState::DV_VISIBLE) && dv.full_name && (dv.hasValue() || (dv.type == DeviceValueType::CMD))) { JsonObject obj = data.createNestedObject(); // create the object, we know there is a value uint8_t fahrenheit = 0; @@ -694,11 +695,7 @@ void EMSdevice::generate_values_web(JsonObject & output) { obj["v"] = dv.options[*(uint8_t *)(dv.value_p)]; } - // handle commands without value - // else if (dv.type == DeviceValueType::CMD) { - // obj["v"] = "-"; - // } - + // handle numbers else { // If a divider is specified, do the division to 2 decimals places and send back as double/float // otherwise force as an integer whole @@ -801,69 +798,69 @@ void EMSdevice::exclude_entity(uint8_t id) { // as generate_values_web() but stripped down to only show all entities and their state void EMSdevice::generate_values_web_all(JsonArray & output) { for (auto & dv : devicevalues_) { - // ignore commands and entities that have an empty full name - if ((dv.type != DeviceValueType::CMD) && (dv.full_name)) { - JsonObject obj = output.createNestedObject(); + // also show commands and entities that have an empty full name + JsonObject obj = output.createNestedObject(); - // create the value - if (dv.hasValue()) { - // handle Booleans (true, false) - if (dv.type == DeviceValueType::BOOL) { - bool value_b = *(bool *)(dv.value_p); - if ((EMSESP::system_.bool_format() == BOOL_FORMAT_TRUEFALSE)) { - obj["v"] = value_b; - } else if ((EMSESP::system_.bool_format() == BOOL_FORMAT_10)) { - obj["v"] = value_b ? 1 : 0; - } else { - char s[7]; - obj["v"] = Helpers::render_boolean(s, value_b); - } - } - - // handle TEXT strings - else if (dv.type == DeviceValueType::STRING) { - obj["v"] = (char *)(dv.value_p); - } - - // handle ENUMs - else if ((dv.type == DeviceValueType::ENUM) && (*(uint8_t *)(dv.value_p) < dv.options_size)) { - obj["v"] = dv.options[*(uint8_t *)(dv.value_p)]; - } - - // handle Integers and Floats - else { - // If a divider is specified, do the division to 2 decimals places and send back as double/float - // otherwise force as an integer whole - // the nested if's is necessary due to the way the ArduinoJson templates are pre-processed by the compiler - uint8_t divider = 0; - uint8_t factor = 1; - if (dv.options_size == 1) { - const char * s = read_flash_string(dv.options[0]).c_str(); - if (s[0] == '*') { - factor = Helpers::atoint(&s[1]); - } else { - divider = Helpers::atoint(s); - } - } - - if (dv.type == DeviceValueType::INT) { - obj["v"] = (divider) ? Helpers::round2(*(int8_t *)(dv.value_p), divider) : *(int8_t *)(dv.value_p) * factor; - } else if (dv.type == DeviceValueType::UINT) { - obj["v"] = (divider) ? Helpers::round2(*(uint8_t *)(dv.value_p), divider) : *(uint8_t *)(dv.value_p) * factor; - } else if (dv.type == DeviceValueType::SHORT) { - obj["v"] = (divider) ? Helpers::round2(*(int16_t *)(dv.value_p), divider) : *(int16_t *)(dv.value_p) * factor; - } else if (dv.type == DeviceValueType::USHORT) { - obj["v"] = (divider) ? Helpers::round2(*(uint16_t *)(dv.value_p), divider) : *(uint16_t *)(dv.value_p) * factor; - } else if (dv.type == DeviceValueType::ULONG) { - obj["v"] = divider ? Helpers::round2(*(uint32_t *)(dv.value_p), divider) : *(uint32_t *)(dv.value_p) * factor; - } else if (dv.type == DeviceValueType::TIME) { - uint32_t time_value = *(uint32_t *)(dv.value_p); - obj["v"] = (divider > 0) ? time_value / divider : time_value * factor; // sometimes we need to divide by 60 - } + // create the value + if (dv.hasValue()) { + // handle Booleans (true, false) + if (dv.type == DeviceValueType::BOOL) { + bool value_b = *(bool *)(dv.value_p); + if ((EMSESP::system_.bool_format() == BOOL_FORMAT_TRUEFALSE)) { + obj["v"] = value_b; + } else if ((EMSESP::system_.bool_format() == BOOL_FORMAT_10)) { + obj["v"] = value_b ? 1 : 0; + } else { + char s[7]; + obj["v"] = Helpers::render_boolean(s, value_b); } } - // add name, prefixing the tag if it exists + // handle TEXT strings + else if (dv.type == DeviceValueType::STRING) { + obj["v"] = (char *)(dv.value_p); + } + + // handle ENUMs + else if ((dv.type == DeviceValueType::ENUM) && (*(uint8_t *)(dv.value_p) < dv.options_size)) { + obj["v"] = dv.options[*(uint8_t *)(dv.value_p)]; + } + + // handle Integers and Floats + else { + // If a divider is specified, do the division to 2 decimals places and send back as double/float + // otherwise force as an integer whole + // the nested if's is necessary due to the way the ArduinoJson templates are pre-processed by the compiler + uint8_t divider = 0; + uint8_t factor = 1; + if (dv.options_size == 1) { + const char * s = read_flash_string(dv.options[0]).c_str(); + if (s[0] == '*') { + factor = Helpers::atoint(&s[1]); + } else { + divider = Helpers::atoint(s); + } + } + + if (dv.type == DeviceValueType::INT) { + obj["v"] = (divider) ? Helpers::round2(*(int8_t *)(dv.value_p), divider) : *(int8_t *)(dv.value_p) * factor; + } else if (dv.type == DeviceValueType::UINT) { + obj["v"] = (divider) ? Helpers::round2(*(uint8_t *)(dv.value_p), divider) : *(uint8_t *)(dv.value_p) * factor; + } else if (dv.type == DeviceValueType::SHORT) { + obj["v"] = (divider) ? Helpers::round2(*(int16_t *)(dv.value_p), divider) : *(int16_t *)(dv.value_p) * factor; + } else if (dv.type == DeviceValueType::USHORT) { + obj["v"] = (divider) ? Helpers::round2(*(uint16_t *)(dv.value_p), divider) : *(uint16_t *)(dv.value_p) * factor; + } else if (dv.type == DeviceValueType::ULONG) { + obj["v"] = divider ? Helpers::round2(*(uint32_t *)(dv.value_p), divider) : *(uint32_t *)(dv.value_p) * factor; + } else if (dv.type == DeviceValueType::TIME) { + uint32_t time_value = *(uint32_t *)(dv.value_p); + obj["v"] = (divider > 0) ? time_value / divider : time_value * factor; // sometimes we need to divide by 60 + } + } + } + + // add name, prefixing the tag if it exists + if (dv.full_name) { if ((dv.tag == DeviceValueTAG::TAG_NONE) || tag_to_string(dv.tag).empty()) { obj["n"] = dv.full_name; } else { @@ -871,20 +868,21 @@ void EMSdevice::generate_values_web_all(JsonArray & output) { snprintf(name, sizeof(name), "%s %s", tag_to_string(dv.tag).c_str(), read_flash_string(dv.full_name).c_str()); obj["n"] = name; } - - // shortname - if (dv.tag >= DeviceValueTAG::TAG_HC1) { - obj["s"] = tag_to_string(dv.tag) + "/" + read_flash_string(dv.short_name); - } else { - obj["s"] = dv.short_name; - } - - // is it marked as excluded? - obj["x"] = !dv.has_state(DeviceValueState::DV_VISIBLE); - - // add the unique ID - obj["i"] = dv.id; + } else { + obj["n"] = "(hidden)"; } + // shortname + if (dv.tag >= DeviceValueTAG::TAG_HC1) { + obj["s"] = tag_to_string(dv.tag) + "/" + read_flash_string(dv.short_name); + } else { + obj["s"] = dv.short_name; + } + + // is it marked as excluded? + obj["x"] = !dv.has_state(DeviceValueState::DV_VISIBLE); + + // add the unique ID + obj["i"] = dv.id; } } @@ -1057,7 +1055,7 @@ bool EMSdevice::get_value_info(JsonObject & output, const char * cmd, const int8 // mqtt publish all single values from one device (used for time schedule) void EMSdevice::publish_all_values() { - for (auto & dv : devicevalues_) { + for (const auto & dv : devicevalues_) { publish_value(dv.value_p); } } @@ -1241,10 +1239,11 @@ 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); if (dv.short_name == FL_(climate)[0]) { Mqtt::publish_ha_climate_config(dv.tag, false, true); // delete topic (remove = true) + } else { + Mqtt::publish_ha_sensor_config(dv, "", "", true); // delete topic (remove = true) } } } @@ -1262,10 +1261,12 @@ void EMSdevice::mqtt_ha_entity_config_create() { if ((dv.short_name == FL_(climate)[0]) && dv.has_state(DeviceValueState::DV_VISIBLE) && dv.has_state(DeviceValueState::DV_ACTIVE)) { if (*(int8_t *)(dv.value_p) == 1 && (!dv.has_state(DeviceValueState::DV_HA_CONFIG_CREATED) || dv.has_state(DeviceValueState::DV_HA_CLIMATE_NO_RT))) { dv.remove_state(DeviceValueState::DV_HA_CLIMATE_NO_RT); + dv.add_state(DeviceValueState::DV_HA_CONFIG_CREATED); Mqtt::publish_ha_climate_config(dv.tag, true); } else if (*(int8_t *)(dv.value_p) == 0 && (!dv.has_state(DeviceValueState::DV_HA_CONFIG_CREATED) || !dv.has_state(DeviceValueState::DV_HA_CLIMATE_NO_RT))) { dv.add_state(DeviceValueState::DV_HA_CLIMATE_NO_RT); + dv.add_state(DeviceValueState::DV_HA_CONFIG_CREATED); Mqtt::publish_ha_climate_config(dv.tag, false); } } diff --git a/src/locale_DE.h b/src/locale_DE.h index 633c00a0b..26114d001 100644 --- a/src/locale_DE.h +++ b/src/locale_DE.h @@ -582,7 +582,7 @@ MAKE_PSTR_LIST(wwExtra2, F("wwextra2"), F("Kreis 2 Extra")) MAKE_PSTR_LIST(wwDailyHeating, F("wwdailyheating"), F("daily heating")) MAKE_PSTR_LIST(wwDailyHeatTime, F("wwdailyheattime"), F("daily heating time")) // thermostat hc -MAKE_PSTR_LIST(climate, F("climate"), F("Klima Anzeige")) +MAKE_PSTR_LIST(climate, F("climate")) MAKE_PSTR_LIST(selRoomTemp, F("seltemp"), F("Sollwert Raumtemperatur")) MAKE_PSTR_LIST(roomTemp, F("currtemp"), F("aktuelle Raumtemperatur")) MAKE_PSTR_LIST(mode, F("mode"), F("modus")) diff --git a/src/locale_EN.h b/src/locale_EN.h index 6146c4a83..00b02ad7c 100644 --- a/src/locale_EN.h +++ b/src/locale_EN.h @@ -583,7 +583,7 @@ MAKE_PSTR_LIST(wwExtra2, F("wwextra2"), F("circuit 2 extra")) MAKE_PSTR_LIST(wwDailyHeating, F("wwdailyheating"), F("daily heating")) MAKE_PSTR_LIST(wwDailyHeatTime, F("wwdailyheattime"), F("daily heating time")) // thermostat hc -MAKE_PSTR_LIST(climate, F("climate"), F("climate entity")) +MAKE_PSTR_LIST(climate, F("climate")) MAKE_PSTR_LIST(selRoomTemp, F("seltemp"), F("selected room temperature")) MAKE_PSTR_LIST(roomTemp, F("currtemp"), F("current room temperature")) MAKE_PSTR_LIST(mode, F("mode"), F("mode"))