mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-07 08:19:52 +03:00
add state to dv, using DeviceValueState
This commit is contained in:
@@ -117,18 +117,18 @@ static const __FlashStringHelper * const DeviceValueTAG_mqtt[] PROGMEM = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const std::string EMSdevice::tag_to_string(uint8_t tag) {
|
const std::string EMSdevice::tag_to_string(uint8_t tag) {
|
||||||
return uuid::read_flash_string(DeviceValueTAG_s[tag]);
|
return read_flash_string(DeviceValueTAG_s[tag]);
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string EMSdevice::tag_to_mqtt(uint8_t tag) {
|
const std::string EMSdevice::tag_to_mqtt(uint8_t tag) {
|
||||||
return uuid::read_flash_string(DeviceValueTAG_mqtt[tag]);
|
return read_flash_string(DeviceValueTAG_mqtt[tag]);
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string EMSdevice::uom_to_string(uint8_t uom) {
|
const std::string EMSdevice::uom_to_string(uint8_t uom) {
|
||||||
if (uom == DeviceValueUOM::NONE) {
|
if (uom == DeviceValueUOM::NONE) {
|
||||||
return std::string{};
|
return std::string{};
|
||||||
}
|
}
|
||||||
return uuid::read_flash_string(DeviceValueUOM_s[uom - 1]); // offset by 1 to account for NONE
|
return read_flash_string(DeviceValueUOM_s[uom - 1]); // offset by 1 to account for NONE
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<EMSdevice::DeviceValue> EMSdevice::devicevalues() const {
|
const std::vector<EMSdevice::DeviceValue> EMSdevice::devicevalues() const {
|
||||||
@@ -374,13 +374,13 @@ bool EMSdevice::is_fetch(uint16_t telegram_id) {
|
|||||||
// list of registered device entries, adding the HA entity if it exists
|
// list of registered device entries, adding the HA entity if it exists
|
||||||
void EMSdevice::list_device_entries(JsonObject & output) {
|
void EMSdevice::list_device_entries(JsonObject & output) {
|
||||||
for (const auto & dv : devicevalues_) {
|
for (const auto & dv : devicevalues_) {
|
||||||
if (dv_is_visible(dv) && dv.type != DeviceValueType::CMD) {
|
if (dv.has_state(DeviceValueState::DV_VISIBLE) && dv.type != DeviceValueType::CMD) {
|
||||||
// if we have a tag prefix it
|
// if we have a tag prefix it
|
||||||
char key[50];
|
char key[50];
|
||||||
if (!EMSdevice::tag_to_string(dv.tag).empty()) {
|
if (!EMSdevice::tag_to_string(dv.tag).empty()) {
|
||||||
snprintf(key, 50, "%s.%s", EMSdevice::tag_to_string(dv.tag).c_str(), uuid::read_flash_string(dv.short_name).c_str());
|
snprintf(key, 50, "%s.%s", EMSdevice::tag_to_string(dv.tag).c_str(), read_flash_string(dv.short_name).c_str());
|
||||||
} else {
|
} else {
|
||||||
snprintf(key, 50, "%s", uuid::read_flash_string(dv.short_name).c_str());
|
snprintf(key, 50, "%s", read_flash_string(dv.short_name).c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonArray details = output.createNestedArray(key);
|
JsonArray details = output.createNestedArray(key);
|
||||||
@@ -405,14 +405,14 @@ void EMSdevice::list_device_entries(JsonObject & output) {
|
|||||||
const std::string EMSdevice::device_entity_ha(DeviceValue const & dv) {
|
const std::string EMSdevice::device_entity_ha(DeviceValue const & dv) {
|
||||||
std::string entity_name(50, '\0');
|
std::string entity_name(50, '\0');
|
||||||
if (EMSdevice::tag_to_string(dv.tag).empty()) {
|
if (EMSdevice::tag_to_string(dv.tag).empty()) {
|
||||||
snprintf(&entity_name[0], entity_name.capacity() + 1, "sensor.%s %s", this->device_type_name().c_str(), uuid::read_flash_string(dv.full_name).c_str());
|
snprintf(&entity_name[0], entity_name.capacity() + 1, "sensor.%s %s", this->device_type_name().c_str(), read_flash_string(dv.full_name).c_str());
|
||||||
} else {
|
} else {
|
||||||
snprintf(&entity_name[0],
|
snprintf(&entity_name[0],
|
||||||
entity_name.capacity() + 1,
|
entity_name.capacity() + 1,
|
||||||
"sensor.%s %s %s",
|
"sensor.%s %s %s",
|
||||||
this->device_type_name().c_str(),
|
this->device_type_name().c_str(),
|
||||||
EMSdevice::tag_to_string(dv.tag).c_str(),
|
EMSdevice::tag_to_string(dv.tag).c_str(),
|
||||||
uuid::read_flash_string(dv.full_name).c_str());
|
read_flash_string(dv.full_name).c_str());
|
||||||
}
|
}
|
||||||
std::replace(entity_name.begin(), entity_name.end(), ' ', '_');
|
std::replace(entity_name.begin(), entity_name.end(), ' ', '_');
|
||||||
return Helpers::toLower(entity_name);
|
return Helpers::toLower(entity_name);
|
||||||
@@ -512,7 +512,11 @@ void EMSdevice::register_device_value(uint8_t tag,
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
devicevalues_.emplace_back(device_type_, tag, value_p, type, options, options_size, short_name, full_name, uom, 0, has_cmd, min, max);
|
// set state
|
||||||
|
// if fullname is empty don't set the flag to visible (used for hamode and hatemp)
|
||||||
|
uint8_t state = (full_name) ? DeviceValueState::DV_VISIBLE : DeviceValueState::DV_DEFAULT;
|
||||||
|
|
||||||
|
devicevalues_.emplace_back(device_type_, tag, value_p, type, options, options_size, short_name, full_name, uom, 0, has_cmd, min, max, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
// function with min and max values
|
// function with min and max values
|
||||||
@@ -581,7 +585,7 @@ const std::string EMSdevice::get_value_uom(const char * key) {
|
|||||||
|
|
||||||
size_t sz = sizeof(DeviceValueTAG_s) / sizeof(__FlashStringHelper *);
|
size_t sz = sizeof(DeviceValueTAG_s) / sizeof(__FlashStringHelper *);
|
||||||
for (uint8_t i = 0; i < sz; i++) {
|
for (uint8_t i = 0; i < sz; i++) {
|
||||||
auto tag = uuid::read_flash_string(DeviceValueTAG_s[i]);
|
auto tag = read_flash_string(DeviceValueTAG_s[i]);
|
||||||
if (!tag.empty()) {
|
if (!tag.empty()) {
|
||||||
std::string key2 = key; // copy char to a std::string
|
std::string key2 = key; // copy char to a std::string
|
||||||
if ((key2.find(tag) != std::string::npos) && (key[tag.length()] == ' ')) {
|
if ((key2.find(tag) != std::string::npos) && (key[tag.length()] == ' ')) {
|
||||||
@@ -593,8 +597,8 @@ const std::string EMSdevice::get_value_uom(const char * key) {
|
|||||||
|
|
||||||
// look up key in our device value list
|
// look up key in our device value list
|
||||||
for (const auto & dv : devicevalues_) {
|
for (const auto & dv : devicevalues_) {
|
||||||
if (dv_is_visible(dv)) {
|
if (dv.has_state(DeviceValueState::DV_VISIBLE)) {
|
||||||
if (uuid::read_flash_string(dv.full_name) == key_p) {
|
if (read_flash_string(dv.full_name) == key_p) {
|
||||||
// ignore TIME since "minutes" is already added to the string value
|
// ignore TIME since "minutes" is already added to the string value
|
||||||
if ((dv.uom == DeviceValueUOM::NONE) || (dv.uom == DeviceValueUOM::MINUTES)) {
|
if ((dv.uom == DeviceValueUOM::NONE) || (dv.uom == DeviceValueUOM::MINUTES)) {
|
||||||
break;
|
break;
|
||||||
@@ -615,7 +619,7 @@ void EMSdevice::generate_values_json_web(JsonObject & output) {
|
|||||||
|
|
||||||
for (const auto & dv : devicevalues_) {
|
for (const auto & dv : devicevalues_) {
|
||||||
// ignore if full_name empty and also commands
|
// ignore if full_name empty and also commands
|
||||||
if (dv_is_visible(dv) && dv.type != DeviceValueType::CMD) {
|
if (dv.has_state(DeviceValueState::DV_VISIBLE) && dv.type != DeviceValueType::CMD) {
|
||||||
JsonObject obj; // create the object, if needed
|
JsonObject obj; // create the object, if needed
|
||||||
|
|
||||||
// handle Booleans (true, false)
|
// handle Booleans (true, false)
|
||||||
@@ -652,7 +656,7 @@ void EMSdevice::generate_values_json_web(JsonObject & output) {
|
|||||||
uint8_t divider = 0;
|
uint8_t divider = 0;
|
||||||
uint8_t factor = 1;
|
uint8_t factor = 1;
|
||||||
if (dv.options_size == 1) {
|
if (dv.options_size == 1) {
|
||||||
const char * s = uuid::read_flash_string(dv.options[0]).c_str();
|
const char * s = read_flash_string(dv.options[0]).c_str();
|
||||||
if (s[0] == '*') {
|
if (s[0] == '*') {
|
||||||
factor = Helpers::atoint(&s[1]);
|
factor = Helpers::atoint(&s[1]);
|
||||||
} else {
|
} else {
|
||||||
@@ -692,7 +696,7 @@ void EMSdevice::generate_values_json_web(JsonObject & output) {
|
|||||||
obj["n"] = dv.full_name;
|
obj["n"] = dv.full_name;
|
||||||
} else {
|
} else {
|
||||||
char name[50];
|
char name[50];
|
||||||
snprintf(name, sizeof(name), "%s %s", tag_to_string(dv.tag).c_str(), uuid::read_flash_string(dv.full_name).c_str());
|
snprintf(name, sizeof(name), "%s %s", tag_to_string(dv.tag).c_str(), read_flash_string(dv.full_name).c_str());
|
||||||
obj["n"] = name;
|
obj["n"] = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -700,7 +704,7 @@ void EMSdevice::generate_values_json_web(JsonObject & output) {
|
|||||||
if (dv.has_cmd) {
|
if (dv.has_cmd) {
|
||||||
// add the name of the Command function
|
// add the name of the Command function
|
||||||
if (dv.tag >= DeviceValueTAG::TAG_HC1) {
|
if (dv.tag >= DeviceValueTAG::TAG_HC1) {
|
||||||
obj["c"] = tag_to_string(dv.tag) + "/" + uuid::read_flash_string(dv.short_name);
|
obj["c"] = tag_to_string(dv.tag) + "/" + read_flash_string(dv.short_name);
|
||||||
} else {
|
} else {
|
||||||
obj["c"] = dv.short_name;
|
obj["c"] = dv.short_name;
|
||||||
}
|
}
|
||||||
@@ -708,8 +712,8 @@ void EMSdevice::generate_values_json_web(JsonObject & output) {
|
|||||||
if (dv.type == DeviceValueType::ENUM) {
|
if (dv.type == DeviceValueType::ENUM) {
|
||||||
JsonArray l = obj.createNestedArray("l");
|
JsonArray l = obj.createNestedArray("l");
|
||||||
for (uint8_t i = 0; i < dv.options_size; i++) {
|
for (uint8_t i = 0; i < dv.options_size; i++) {
|
||||||
if (!uuid::read_flash_string(dv.options[i]).empty()) {
|
if (!read_flash_string(dv.options[i]).empty()) {
|
||||||
l.add(uuid::read_flash_string(dv.options[i]));
|
l.add(read_flash_string(dv.options[i]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -746,11 +750,12 @@ bool EMSdevice::get_value_info(JsonObject & output, const char * cmd, const int8
|
|||||||
|
|
||||||
// search device value with this tag
|
// search device value with this tag
|
||||||
for (auto & dv : devicevalues_) {
|
for (auto & dv : devicevalues_) {
|
||||||
if (dv_is_visible(dv) && (strcmp(cmd, Helpers::toLower(uuid::read_flash_string(dv.short_name)).c_str()) == 0 && (tag <= 0 || tag == dv.tag))) {
|
if (dv.has_state(DeviceValueState::DV_VISIBLE)
|
||||||
|
&& (strcmp(cmd, Helpers::toLower(read_flash_string(dv.short_name)).c_str()) == 0 && (tag <= 0 || tag == dv.tag))) {
|
||||||
uint8_t divider = 0;
|
uint8_t divider = 0;
|
||||||
uint8_t factor = 1;
|
uint8_t factor = 1;
|
||||||
if (dv.options_size == 1) {
|
if (dv.options_size == 1) {
|
||||||
const char * s = uuid::read_flash_string(dv.options[0]).c_str();
|
const char * s = read_flash_string(dv.options[0]).c_str();
|
||||||
if (s[0] == '*') {
|
if (s[0] == '*') {
|
||||||
factor = Helpers::atoint(&s[1]);
|
factor = Helpers::atoint(&s[1]);
|
||||||
} else {
|
} else {
|
||||||
@@ -767,7 +772,7 @@ bool EMSdevice::get_value_info(JsonObject & output, const char * cmd, const int8
|
|||||||
if ((dv.tag == DeviceValueTAG::TAG_NONE) || tag_to_string(dv.tag).empty()) {
|
if ((dv.tag == DeviceValueTAG::TAG_NONE) || tag_to_string(dv.tag).empty()) {
|
||||||
json["fullname"] = dv.full_name;
|
json["fullname"] = dv.full_name;
|
||||||
} else {
|
} else {
|
||||||
json["fullname"] = tag_to_string(dv.tag) + " " + uuid::read_flash_string(dv.full_name);
|
json["fullname"] = tag_to_string(dv.tag) + " " + read_flash_string(dv.full_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!tag_to_mqtt(dv.tag).empty()) {
|
if (!tag_to_mqtt(dv.tag).empty()) {
|
||||||
@@ -784,7 +789,7 @@ bool EMSdevice::get_value_info(JsonObject & output, const char * cmd, const int8
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
json[type] = F_(enum);
|
json[type] = F_(enum);
|
||||||
// uint8_t min_ = (uuid::read_flash_string(dv.options[0]) == "") ? 1 : 0;
|
// uint8_t min_ = (read_flash_string(dv.options[0]) == "") ? 1 : 0;
|
||||||
// json[min] = min_;
|
// json[min] = min_;
|
||||||
// json[max] = dv.options_size - 1;
|
// json[max] = dv.options_size - 1;
|
||||||
JsonArray enum_ = json.createNestedArray(F_(enum));
|
JsonArray enum_ = json.createNestedArray(F_(enum));
|
||||||
@@ -800,7 +805,7 @@ bool EMSdevice::get_value_info(JsonObject & output, const char * cmd, const int8
|
|||||||
}
|
}
|
||||||
json[type] = F_(number);
|
json[type] = F_(number);
|
||||||
json[min] = 0;
|
json[min] = 0;
|
||||||
json[max] = divider ? EMS_VALUE_USHORT_NOTSET / divider : EMS_VALUE_USHORT_NOTSET;
|
json[max] = divider ? EMS_VALUE_USHORT_NOTSET / divider : EMS_VALUE_USHORT_NOTSET - 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DeviceValueType::UINT:
|
case DeviceValueType::UINT:
|
||||||
@@ -812,7 +817,7 @@ bool EMSdevice::get_value_info(JsonObject & output, const char * cmd, const int8
|
|||||||
if (dv.uom == DeviceValueUOM::PERCENT) {
|
if (dv.uom == DeviceValueUOM::PERCENT) {
|
||||||
json[max] = 100;
|
json[max] = 100;
|
||||||
} else {
|
} else {
|
||||||
json[max] = divider ? EMS_VALUE_UINT_NOTSET / divider : EMS_VALUE_UINT_NOTSET;
|
json[max] = divider ? EMS_VALUE_UINT_NOTSET / divider : EMS_VALUE_UINT_NOTSET - 1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -822,7 +827,7 @@ bool EMSdevice::get_value_info(JsonObject & output, const char * cmd, const int8
|
|||||||
}
|
}
|
||||||
json[type] = F_(number);
|
json[type] = F_(number);
|
||||||
json[min] = divider ? -EMS_VALUE_SHORT_NOTSET / divider : -EMS_VALUE_SHORT_NOTSET;
|
json[min] = divider ? -EMS_VALUE_SHORT_NOTSET / divider : -EMS_VALUE_SHORT_NOTSET;
|
||||||
json[max] = divider ? EMS_VALUE_SHORT_NOTSET / divider : EMS_VALUE_SHORT_NOTSET;
|
json[max] = divider ? EMS_VALUE_SHORT_NOTSET / divider : EMS_VALUE_SHORT_NOTSET - 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DeviceValueType::INT:
|
case DeviceValueType::INT:
|
||||||
@@ -835,7 +840,7 @@ bool EMSdevice::get_value_info(JsonObject & output, const char * cmd, const int8
|
|||||||
json[max] = 100;
|
json[max] = 100;
|
||||||
} else {
|
} else {
|
||||||
json[min] = divider ? -EMS_VALUE_INT_NOTSET / divider : -EMS_VALUE_INT_NOTSET;
|
json[min] = divider ? -EMS_VALUE_INT_NOTSET / divider : -EMS_VALUE_INT_NOTSET;
|
||||||
json[max] = divider ? EMS_VALUE_INT_NOTSET / divider : EMS_VALUE_INT_NOTSET;
|
json[max] = divider ? EMS_VALUE_INT_NOTSET / divider : EMS_VALUE_INT_NOTSET - 1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -932,42 +937,44 @@ bool EMSdevice::generate_values_json(JsonObject & output, const uint8_t tag_filt
|
|||||||
JsonObject json = output;
|
JsonObject json = output;
|
||||||
|
|
||||||
for (auto & dv : devicevalues_) {
|
for (auto & dv : devicevalues_) {
|
||||||
// conditions
|
// check conditions:
|
||||||
bool condition;
|
// 1. it must have a valid value
|
||||||
condition = (tag_filter == DeviceValueTAG::TAG_NONE) || (tag_filter == dv.tag); // tag must be either empty or match a tag passed to this function
|
// 2. it must be visible, unless our output destination is MQTT
|
||||||
|
// 3. it must match the given tag filter or have an empty tag
|
||||||
|
bool conditions = ((tag_filter == DeviceValueTAG::TAG_NONE) || (tag_filter == dv.tag)) && check_dv_hasvalue(dv);
|
||||||
if (output_target != OUTPUT_TARGET::MQTT) {
|
if (output_target != OUTPUT_TARGET::MQTT) {
|
||||||
condition &= dv_is_visible(dv); // value must be visible if outputting to API (web or console). This is for ID, hamode, hatemp etc
|
conditions &=
|
||||||
|
dv.has_state(DeviceValueState::DV_VISIBLE); // value must be visible if outputting to API (web or console). This is for ID, hamode, hatemp etc
|
||||||
}
|
}
|
||||||
|
|
||||||
bool has_value = false;
|
if (conditions) {
|
||||||
|
has_values = true; // we actually have data
|
||||||
|
|
||||||
if (condition) {
|
|
||||||
// we have a tag if it matches the filter given, and that the tag name is not empty/""
|
// we have a tag if it matches the filter given, and that the tag name is not empty/""
|
||||||
bool have_tag = ((dv.tag != tag_filter) && !tag_to_string(dv.tag).empty());
|
bool have_tag = ((dv.tag != tag_filter) && !tag_to_string(dv.tag).empty());
|
||||||
|
|
||||||
|
// create the name for the JSON key
|
||||||
char name[80];
|
char name[80];
|
||||||
if (output_target == OUTPUT_TARGET::API_VERBOSE) {
|
if (output_target == OUTPUT_TARGET::API_VERBOSE) {
|
||||||
// prefix the tag in brackets, unless it's Boiler because we're naughty and use tag for the MQTT topic
|
|
||||||
if (have_tag) {
|
if (have_tag) {
|
||||||
snprintf(name, 80, "%s %s", tag_to_string(dv.tag).c_str(), uuid::read_flash_string(dv.full_name).c_str());
|
snprintf(name, 80, "%s %s", tag_to_string(dv.tag).c_str(), read_flash_string(dv.full_name).c_str()); // prefix the tag
|
||||||
} else {
|
} else {
|
||||||
strcpy(name, uuid::read_flash_string(dv.full_name).c_str()); // use full name
|
strcpy(name, read_flash_string(dv.full_name).c_str()); // use full name
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
strcpy(name, uuid::read_flash_string(dv.short_name).c_str()); // use short name
|
strcpy(name, read_flash_string(dv.short_name).c_str()); // use short name
|
||||||
|
|
||||||
// if we have a tag, and its different to the last one create a nested object
|
// if we have a tag, and its different to the last one create a nested object. only for hc, wwc and hs
|
||||||
if (dv.tag != old_tag) {
|
if (dv.tag != old_tag) {
|
||||||
old_tag = dv.tag;
|
old_tag = dv.tag;
|
||||||
if (nested && have_tag && dv.tag >= DeviceValueTAG::TAG_HC1) { // no nests for boiler tags
|
if (nested && have_tag && dv.tag >= DeviceValueTAG::TAG_HC1) {
|
||||||
json = output.createNestedObject(tag_to_string(dv.tag));
|
json = output.createNestedObject(tag_to_string(dv.tag));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle Booleans (true, false)
|
// handle Booleans (true, false)
|
||||||
if ((dv.type == DeviceValueType::BOOL) && Helpers::hasValue(*(uint8_t *)(dv.value_p), EMS_VALUE_BOOL)) {
|
if (dv.type == DeviceValueType::BOOL) {
|
||||||
// see how to render the value depending on the setting
|
// see how to render the value depending on the setting
|
||||||
uint8_t bool_format = EMSESP::bool_format();
|
uint8_t bool_format = EMSESP::bool_format();
|
||||||
if (bool_format == BOOL_FORMAT_ONOFF) {
|
if (bool_format == BOOL_FORMAT_ONOFF) {
|
||||||
@@ -979,17 +986,15 @@ bool EMSdevice::generate_values_json(JsonObject & output, const uint8_t tag_filt
|
|||||||
} else {
|
} else {
|
||||||
json[name] = (uint8_t)(*(uint8_t *)(dv.value_p)) ? 1 : 0;
|
json[name] = (uint8_t)(*(uint8_t *)(dv.value_p)) ? 1 : 0;
|
||||||
}
|
}
|
||||||
has_value = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle TEXT strings
|
// handle TEXT strings
|
||||||
else if ((dv.type == DeviceValueType::STRING) && (Helpers::hasValue((char *)(dv.value_p)))) {
|
else if (dv.type == DeviceValueType::STRING) {
|
||||||
json[name] = (char *)(dv.value_p);
|
json[name] = (char *)(dv.value_p);
|
||||||
has_value = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle ENUMs
|
// handle ENUMs
|
||||||
else if ((dv.type == DeviceValueType::ENUM) && Helpers::hasValue(*(uint8_t *)(dv.value_p))) {
|
else if (dv.type == DeviceValueType::ENUM) {
|
||||||
if (*(uint8_t *)(dv.value_p) < dv.options_size) {
|
if (*(uint8_t *)(dv.value_p) < dv.options_size) {
|
||||||
// check for numeric enum-format, but "hamode" always as text
|
// check for numeric enum-format, but "hamode" always as text
|
||||||
if ((EMSESP::enum_format() == ENUM_FORMAT_NUMBER) && (dv.short_name != FL_(hamode)[0])) {
|
if ((EMSESP::enum_format() == ENUM_FORMAT_NUMBER) && (dv.short_name != FL_(hamode)[0])) {
|
||||||
@@ -997,19 +1002,18 @@ bool EMSdevice::generate_values_json(JsonObject & output, const uint8_t tag_filt
|
|||||||
} else {
|
} else {
|
||||||
json[name] = dv.options[*(uint8_t *)(dv.value_p)];
|
json[name] = dv.options[*(uint8_t *)(dv.value_p)];
|
||||||
}
|
}
|
||||||
has_value = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle Integers and Floats
|
// handle Integers and Floats
|
||||||
|
// If a divider is specified, do the division to 2 decimals places and send back as double/float
|
||||||
|
// otherwise force as a whole integer
|
||||||
|
// note: the strange nested if's is necessary due to the way the ArduinoJson templates are pre-processed by the compiler
|
||||||
else {
|
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 divider = 0;
|
||||||
uint8_t factor = 1;
|
uint8_t factor = 1;
|
||||||
if (dv.options_size == 1) {
|
if (dv.options_size == 1) {
|
||||||
const char * s = uuid::read_flash_string(dv.options[0]).c_str();
|
const char * s = read_flash_string(dv.options[0]).c_str();
|
||||||
if (s[0] == '*') {
|
if (s[0] == '*') {
|
||||||
factor = Helpers::atoint(&s[1]);
|
factor = Helpers::atoint(&s[1]);
|
||||||
} else {
|
} else {
|
||||||
@@ -1017,85 +1021,109 @@ bool EMSdevice::generate_values_json(JsonObject & output, const uint8_t tag_filt
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// always convert temperatures to floats
|
// always convert temperatures to floats with 1 decimal place
|
||||||
bool make_float = (divider || (dv.uom == DeviceValueUOM::DEGREES));
|
bool make_float = (divider || (dv.uom == DeviceValueUOM::DEGREES));
|
||||||
|
|
||||||
// INT
|
if (dv.type == DeviceValueType::INT) {
|
||||||
if ((dv.type == DeviceValueType::INT) && Helpers::hasValue(*(int8_t *)(dv.value_p))) {
|
|
||||||
if (make_float) {
|
if (make_float) {
|
||||||
json[name] = Helpers::round2(*(int8_t *)(dv.value_p), divider);
|
json[name] = Helpers::round2(*(int8_t *)(dv.value_p), divider);
|
||||||
} else {
|
} else {
|
||||||
json[name] = *(int8_t *)(dv.value_p) * factor;
|
json[name] = *(int8_t *)(dv.value_p) * factor;
|
||||||
}
|
}
|
||||||
has_value = true;
|
} else if (dv.type == DeviceValueType::UINT) {
|
||||||
} else if ((dv.type == DeviceValueType::UINT) && Helpers::hasValue(*(uint8_t *)(dv.value_p))) {
|
|
||||||
if (make_float) {
|
if (make_float) {
|
||||||
json[name] = Helpers::round2(*(uint8_t *)(dv.value_p), divider);
|
json[name] = Helpers::round2(*(uint8_t *)(dv.value_p), divider);
|
||||||
} else {
|
} else {
|
||||||
json[name] = *(uint8_t *)(dv.value_p) * factor;
|
json[name] = *(uint8_t *)(dv.value_p) * factor;
|
||||||
}
|
}
|
||||||
has_value = true;
|
} else if (dv.type == DeviceValueType::SHORT) {
|
||||||
} else if ((dv.type == DeviceValueType::SHORT) && Helpers::hasValue(*(int16_t *)(dv.value_p))) {
|
|
||||||
if (make_float) {
|
if (make_float) {
|
||||||
json[name] = Helpers::round2(*(int16_t *)(dv.value_p), divider);
|
json[name] = Helpers::round2(*(int16_t *)(dv.value_p), divider);
|
||||||
} else {
|
} else {
|
||||||
json[name] = *(int16_t *)(dv.value_p) * factor;
|
json[name] = *(int16_t *)(dv.value_p) * factor;
|
||||||
}
|
}
|
||||||
has_value = true;
|
} else if (dv.type == DeviceValueType::USHORT) {
|
||||||
} else if ((dv.type == DeviceValueType::USHORT) && Helpers::hasValue(*(uint16_t *)(dv.value_p))) {
|
|
||||||
if (make_float) {
|
if (make_float) {
|
||||||
json[name] = Helpers::round2(*(uint16_t *)(dv.value_p), divider);
|
json[name] = Helpers::round2(*(uint16_t *)(dv.value_p), divider);
|
||||||
} else {
|
} else {
|
||||||
json[name] = *(uint16_t *)(dv.value_p) * factor;
|
json[name] = *(uint16_t *)(dv.value_p) * factor;
|
||||||
}
|
}
|
||||||
has_value = true;
|
} else if (dv.type == DeviceValueType::ULONG) {
|
||||||
} else if ((dv.type == DeviceValueType::ULONG) && Helpers::hasValue(*(uint32_t *)(dv.value_p))) {
|
|
||||||
if (make_float) {
|
if (make_float) {
|
||||||
json[name] = Helpers::round2(*(uint32_t *)(dv.value_p), divider);
|
json[name] = Helpers::round2(*(uint32_t *)(dv.value_p), divider);
|
||||||
} else {
|
} else {
|
||||||
json[name] = *(uint32_t *)(dv.value_p) * factor;
|
json[name] = *(uint32_t *)(dv.value_p) * factor;
|
||||||
}
|
}
|
||||||
has_value = true;
|
} else if (dv.type == DeviceValueType::TIME) {
|
||||||
} else if ((dv.type == DeviceValueType::TIME) && Helpers::hasValue(*(uint32_t *)(dv.value_p))) {
|
|
||||||
uint32_t time_value = *(uint32_t *)(dv.value_p);
|
uint32_t time_value = *(uint32_t *)(dv.value_p);
|
||||||
time_value = (divider) ? time_value / divider : time_value * factor; // sometimes we need to divide by 60
|
time_value = (divider) ? time_value / divider : time_value * factor; // sometimes we need to divide by 60
|
||||||
if (output_target == EMSdevice::OUTPUT_TARGET::API_VERBOSE) {
|
if (output_target == EMSdevice::OUTPUT_TARGET::API_VERBOSE) {
|
||||||
char time_s[40];
|
char time_s[40];
|
||||||
snprintf(time_s, sizeof(time_s), "%d days %d hours %d minutes", (time_value / 1440), ((time_value % 1440) / 60), (time_value % 60));
|
snprintf(time_s,
|
||||||
|
sizeof(time_s),
|
||||||
|
"%d %s %d %s %d %s",
|
||||||
|
(time_value / 1440),
|
||||||
|
read_flash_string(F_(days)).c_str(),
|
||||||
|
((time_value % 1440) / 60),
|
||||||
|
read_flash_string(F_(hours)).c_str(),
|
||||||
|
(time_value % 60),
|
||||||
|
read_flash_string(F_(minutes)).c_str());
|
||||||
json[name] = time_s;
|
json[name] = time_s;
|
||||||
} else {
|
} else {
|
||||||
json[name] = time_value;
|
json[name] = time_value;
|
||||||
}
|
}
|
||||||
has_value = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dv.ha |= has_value ? DeviceValueHA::HA_VALUE : DeviceValueHA::HA_NONE;
|
|
||||||
has_values |= has_value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return has_values;
|
return has_values;
|
||||||
}
|
}
|
||||||
|
|
||||||
// create the Home Assistant configs for each value
|
// create the Home Assistant configs for each value
|
||||||
// this is called when an MQTT publish is done via an EMS Device
|
// this is called when an MQTT publish is done via an EMS Device in emsesp.cpp
|
||||||
void EMSdevice::publish_mqtt_ha_sensor() {
|
// if the main Device Entity config for the device hasn't been setup its also done here
|
||||||
for (auto & dv : devicevalues_) {
|
void EMSdevice::publish_mqtt_ha_entity_config() {
|
||||||
if (dv.ha == DeviceValueHA::HA_VALUE) {
|
// create the main device config if not doing already
|
||||||
Mqtt::publish_ha_sensor(dv.type, dv.tag, dv.full_name, dv.device_type, dv.short_name, dv.uom, dv.has_cmd);
|
if (!ha_config_done()) {
|
||||||
dv.ha |= DeviceValueHA::HA_DONE;
|
bool ok = publish_ha_device_config();
|
||||||
}
|
ha_config_done(ok); // see if it worked
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ha_config_done()) {
|
for (auto & dv : devicevalues_) {
|
||||||
bool ok = publish_ha_config();
|
#if defined(EMSESP_STANDALONE)
|
||||||
ha_config_done(ok); // see if it worked
|
// debug messages to go with the test called 'dv'
|
||||||
|
if (strcmp(read_flash_string(dv.short_name).c_str(), "wwseltemp") == 0) {
|
||||||
|
EMSESP::logger().warning(F("! init: wwseltemp state=%d, active=%d config_created=%d"),
|
||||||
|
dv.get_state(),
|
||||||
|
dv.has_state(DV_ACTIVE),
|
||||||
|
dv.has_state(DV_HA_CONFIG_CREATED));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// if the HA config has already been created and now the value has gone dormant, delete the config
|
||||||
|
// https://github.com/emsesp/EMS-ESP32/issues/196
|
||||||
|
if (dv.has_state(DV_ACTIVE)) {
|
||||||
|
if (!dv.has_state(DV_HA_CONFIG_CREATED)) {
|
||||||
|
// add it
|
||||||
|
Mqtt::publish_ha_sensor_config(dv.type, dv.tag, dv.full_name, dv.device_type, dv.short_name, dv.uom, false, dv.has_cmd);
|
||||||
|
dv.add_state(DV_HA_CONFIG_CREATED);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (dv.has_state(DV_HA_CONFIG_CREATED)) {
|
||||||
|
// remove it
|
||||||
|
Mqtt::publish_ha_sensor_config(dv.type, dv.tag, dv.full_name, dv.device_type, dv.short_name, dv.uom, true, dv.has_cmd);
|
||||||
|
dv.remove_state(DV_HA_CONFIG_CREATED);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// remove all config topics in HA
|
||||||
void EMSdevice::ha_config_clear() {
|
void EMSdevice::ha_config_clear() {
|
||||||
for (auto & dv : devicevalues_) {
|
for (auto & dv : devicevalues_) {
|
||||||
dv.ha = DeviceValueHA::HA_NONE; // also wait for new value
|
Mqtt::publish_ha_sensor_config(dv.type, dv.tag, dv.full_name, dv.device_type, dv.short_name, dv.uom, true, dv.has_cmd); // delete topic
|
||||||
|
dv.remove_state(DV_HA_CONFIG_CREATED);
|
||||||
}
|
}
|
||||||
ha_config_done(false);
|
ha_config_done(false);
|
||||||
}
|
}
|
||||||
@@ -1111,7 +1139,7 @@ const std::string EMSdevice::telegram_type_name(std::shared_ptr<const Telegram>
|
|||||||
|
|
||||||
for (const auto & tf : telegram_functions_) {
|
for (const auto & tf : telegram_functions_) {
|
||||||
if ((tf.telegram_type_id_ == telegram->type_id) && (telegram->type_id != 0xFF)) {
|
if ((tf.telegram_type_id_ == telegram->type_id) && (telegram->type_id != 0xFF)) {
|
||||||
return uuid::read_flash_string(tf.telegram_type_name_);
|
return read_flash_string(tf.telegram_type_name_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1126,7 +1154,7 @@ bool EMSdevice::handle_telegram(std::shared_ptr<const Telegram> telegram) {
|
|||||||
// if the data block is empty, assume that this telegram is not recognized by the bus master
|
// if the data block is empty, assume that this telegram is not recognized by the bus master
|
||||||
// so remove it from the automatic fetch list
|
// so remove it from the automatic fetch list
|
||||||
if (telegram->message_length == 0 && telegram->offset == 0) {
|
if (telegram->message_length == 0 && telegram->offset == 0) {
|
||||||
EMSESP::logger().debug(F("This telegram (%s) is not recognized by the EMS bus"), uuid::read_flash_string(tf.telegram_type_name_).c_str());
|
EMSESP::logger().debug(F("This telegram (%s) is not recognized by the EMS bus"), read_flash_string(tf.telegram_type_name_).c_str());
|
||||||
toggle_fetch(tf.telegram_type_id_, false);
|
toggle_fetch(tf.telegram_type_id_, false);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -1161,4 +1189,58 @@ void EMSdevice::read_command(const uint16_t type_id, const uint8_t offset, const
|
|||||||
EMSESP::send_read_request(type_id, device_id(), offset, length);
|
EMSESP::send_read_request(type_id, device_id(), offset, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// checks whether the device value has an actual value
|
||||||
|
// returns true if its valid
|
||||||
|
// state is stored in the dv object
|
||||||
|
bool EMSdevice::check_dv_hasvalue(DeviceValue & dv) {
|
||||||
|
bool has_value = false;
|
||||||
|
switch (dv.type) {
|
||||||
|
case DeviceValueType::BOOL:
|
||||||
|
has_value = Helpers::hasValue(*(uint8_t *)(dv.value_p), EMS_VALUE_BOOL);
|
||||||
|
break;
|
||||||
|
case DeviceValueType::STRING:
|
||||||
|
has_value = Helpers::hasValue((char *)(dv.value_p));
|
||||||
|
break;
|
||||||
|
case DeviceValueType::ENUM:
|
||||||
|
has_value = Helpers::hasValue(*(uint8_t *)(dv.value_p));
|
||||||
|
break;
|
||||||
|
case DeviceValueType::INT:
|
||||||
|
has_value = Helpers::hasValue(*(int8_t *)(dv.value_p));
|
||||||
|
break;
|
||||||
|
case DeviceValueType::UINT:
|
||||||
|
has_value = Helpers::hasValue(*(uint8_t *)(dv.value_p));
|
||||||
|
break;
|
||||||
|
case DeviceValueType::SHORT:
|
||||||
|
has_value = Helpers::hasValue(*(int16_t *)(dv.value_p));
|
||||||
|
break;
|
||||||
|
case DeviceValueType::USHORT:
|
||||||
|
has_value = Helpers::hasValue(*(uint16_t *)(dv.value_p));
|
||||||
|
break;
|
||||||
|
case DeviceValueType::ULONG:
|
||||||
|
has_value = Helpers::hasValue(*(uint32_t *)(dv.value_p));
|
||||||
|
break;
|
||||||
|
case DeviceValueType::TIME:
|
||||||
|
has_value = Helpers::hasValue(*(uint32_t *)(dv.value_p));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(EMSESP_DEBUG)
|
||||||
|
// https://github.com/emsesp/EMS-ESP32/issues/196
|
||||||
|
if (dv.has_state(DeviceValueState::DV_ACTIVE) && !has_value) {
|
||||||
|
EMSESP::logger().warning(F("[DEBUG] Lost device value %s"), dv.short_name);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// set the value state to active
|
||||||
|
if (has_value) {
|
||||||
|
dv.add_state(DeviceValueState::DV_ACTIVE);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
dv.remove_state(DeviceValueState::DV_ACTIVE);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace emsesp
|
} // namespace emsesp
|
||||||
|
|||||||
@@ -119,12 +119,14 @@ enum DeviceValueTAG : uint8_t {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// MQTT HA flags
|
// states of a device value
|
||||||
enum DeviceValueHA : uint8_t {
|
enum DeviceValueState : uint8_t {
|
||||||
|
|
||||||
|
DV_DEFAULT = 0, // 0 - does not yet have a value
|
||||||
|
DV_ACTIVE = (1 << 0), // 1 - has a value
|
||||||
|
DV_VISIBLE = (1 << 1), // 2 - shown on web and console
|
||||||
|
DV_HA_CONFIG_CREATED = (1 << 2) // 4 - set if the HA config has been created
|
||||||
|
|
||||||
HA_NONE = 0,
|
|
||||||
HA_VALUE,
|
|
||||||
HA_DONE
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class EMSdevice {
|
class EMSdevice {
|
||||||
@@ -134,7 +136,7 @@ class EMSdevice {
|
|||||||
static constexpr uint8_t EMS_DEVICES_MAX_TELEGRAMS = 20;
|
static constexpr uint8_t EMS_DEVICES_MAX_TELEGRAMS = 20;
|
||||||
|
|
||||||
// virtual functions overrules by derived classes
|
// virtual functions overrules by derived classes
|
||||||
virtual bool publish_ha_config() = 0;
|
virtual bool publish_ha_device_config() = 0;
|
||||||
|
|
||||||
// device_type defines which derived class to use, e.g. BOILER, THERMOSTAT etc..
|
// device_type defines which derived class to use, e.g. BOILER, THERMOSTAT etc..
|
||||||
EMSdevice(uint8_t device_type, uint8_t device_id, uint8_t product_id, const std::string & version, const std::string & name, uint8_t flags, uint8_t brand)
|
EMSdevice(uint8_t device_type, uint8_t device_id, uint8_t product_id, const std::string & version, const std::string & name, uint8_t flags, uint8_t brand)
|
||||||
@@ -291,7 +293,7 @@ class EMSdevice {
|
|||||||
|
|
||||||
void read_command(const uint16_t type_id, uint8_t offset = 0, uint8_t length = 0);
|
void read_command(const uint16_t type_id, uint8_t offset = 0, uint8_t length = 0);
|
||||||
|
|
||||||
void publish_mqtt_ha_sensor();
|
void publish_mqtt_ha_entity_config();
|
||||||
|
|
||||||
const std::string telegram_type_name(std::shared_ptr<const Telegram> telegram);
|
const std::string telegram_type_name(std::shared_ptr<const Telegram> telegram);
|
||||||
|
|
||||||
@@ -415,7 +417,6 @@ class EMSdevice {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// DeviceValue holds all the attributes for a device value (also a device parameter)
|
// DeviceValue holds all the attributes for a device value (also a device parameter)
|
||||||
struct DeviceValue {
|
struct DeviceValue {
|
||||||
uint8_t device_type; // EMSdevice::DeviceType
|
uint8_t device_type; // EMSdevice::DeviceType
|
||||||
@@ -431,6 +432,7 @@ class EMSdevice {
|
|||||||
bool has_cmd; // true if there is a Console/MQTT command which matches the short_name
|
bool has_cmd; // true if there is a Console/MQTT command which matches the short_name
|
||||||
int32_t min;
|
int32_t min;
|
||||||
uint32_t max;
|
uint32_t max;
|
||||||
|
uint8_t state; // DeviceValueState::*
|
||||||
|
|
||||||
DeviceValue(uint8_t device_type,
|
DeviceValue(uint8_t device_type,
|
||||||
uint8_t tag,
|
uint8_t tag,
|
||||||
@@ -444,7 +446,8 @@ class EMSdevice {
|
|||||||
uint8_t ha,
|
uint8_t ha,
|
||||||
bool has_cmd,
|
bool has_cmd,
|
||||||
int32_t min,
|
int32_t min,
|
||||||
uint32_t max)
|
uint32_t max,
|
||||||
|
uint8_t state)
|
||||||
: device_type(device_type)
|
: device_type(device_type)
|
||||||
, tag(tag)
|
, tag(tag)
|
||||||
, value_p(value_p)
|
, value_p(value_p)
|
||||||
@@ -457,7 +460,22 @@ class EMSdevice {
|
|||||||
, ha(ha)
|
, ha(ha)
|
||||||
, has_cmd(has_cmd)
|
, has_cmd(has_cmd)
|
||||||
, min(min)
|
, min(min)
|
||||||
, max(max) {
|
, max(max)
|
||||||
|
, state(state) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// state flags
|
||||||
|
inline void add_state(uint8_t s) {
|
||||||
|
state |= s;
|
||||||
|
}
|
||||||
|
inline bool has_state(uint8_t s) const {
|
||||||
|
return (state & s) == s;
|
||||||
|
}
|
||||||
|
inline void remove_state(uint8_t s) {
|
||||||
|
state &= ~s;
|
||||||
|
}
|
||||||
|
inline uint8_t get_state() const {
|
||||||
|
return state;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const std::vector<DeviceValue> devicevalues() const;
|
const std::vector<DeviceValue> devicevalues() const;
|
||||||
@@ -467,13 +485,11 @@ class EMSdevice {
|
|||||||
|
|
||||||
const std::string device_entity_ha(DeviceValue const & dv);
|
const std::string device_entity_ha(DeviceValue const & dv);
|
||||||
|
|
||||||
|
bool check_dv_hasvalue(DeviceValue & dv);
|
||||||
|
|
||||||
void init_devicevalues(uint8_t size) {
|
void init_devicevalues(uint8_t size) {
|
||||||
devicevalues_.reserve(size);
|
devicevalues_.reserve(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool dv_is_visible(DeviceValue dv) {
|
|
||||||
return (dv.full_name);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace emsesp
|
} // namespace emsesp
|
||||||
|
|||||||
Reference in New Issue
Block a user