From 9993a7c7397dc9797abb75731f14eda54509daaf Mon Sep 17 00:00:00 2001 From: Proddy Date: Sun, 12 Nov 2023 15:59:29 +0100 Subject: [PATCH] fix UOM not showing in console - and added new command 'system values' --- src/analogsensor.h | 4 ++- src/emsdevice.cpp | 61 ++++++++++++++++++++++++++--------------- src/emsdevice.h | 12 ++++---- src/emsesp.cpp | 56 ++++++++++--------------------------- src/emsesp.h | 1 - src/system.cpp | 32 +++++++++++++++++++++ src/system.h | 2 ++ src/temperaturesensor.h | 3 +- 8 files changed, 99 insertions(+), 72 deletions(-) diff --git a/src/analogsensor.h b/src/analogsensor.h index 132b20e50..b33fb1137 100644 --- a/src/analogsensor.h +++ b/src/analogsensor.h @@ -156,6 +156,9 @@ class AnalogSensor { bool get_value_info(JsonObject & output, const char * cmd, const int8_t id) const; void store_counters(); + bool command_info(const char * value, const int8_t id, JsonObject & output) const; + + #if defined(EMSESP_TEST) void test(); #endif @@ -169,7 +172,6 @@ class AnalogSensor { void remove_ha_topic(const int8_t type, const uint8_t id) const; bool command_setvalue(const char * value, const int8_t gpio); void measure(); - bool command_info(const char * value, const int8_t id, JsonObject & output) const; bool command_commands(const char * value, const int8_t id, JsonObject & output); std::vector sensors_; // our list of sensors diff --git a/src/emsdevice.cpp b/src/emsdevice.cpp index 7ce2b602f..ae80ffcb2 100644 --- a/src/emsdevice.cpp +++ b/src/emsdevice.cpp @@ -803,29 +803,9 @@ void EMSdevice::publish_value(void * value_p) const { } // looks up the UOM for a given key from the device value table -// key is the fullname -std::string EMSdevice::get_value_uom(const char * key) const { - // the key may have a TAG string prefixed at the beginning. If so, remove it - char new_key[80]; - strlcpy(new_key, key, sizeof(new_key)); - char * key_p = new_key; - - for (uint8_t i = 0; i < DeviceValue::NUM_TAGS; i++) { - auto tag = Helpers::translated_word(DeviceValue::DeviceValueTAG_s[i]); - if (tag) { - std::string key2 = key; // copy string to a std::string so we can use the find function - uint8_t length = strlen(tag); - if ((key2.find(tag) != std::string::npos) && (key[length] == ' ')) { - key_p += length + 1; // remove the tag - break; - } - } - } - - // look up key in our device value list +std::string EMSdevice::get_value_uom(const std::string & shortname) const { for (const auto & dv : devicevalues_) { - auto fullname = dv.get_fullname(); - if ((!dv.has_state(DeviceValueState::DV_WEB_EXCLUDE) && !fullname.empty()) && (fullname == key_p)) { + if ((!dv.has_state(DeviceValueState::DV_WEB_EXCLUDE)) && (dv.short_name == shortname)) { // ignore TIME since "minutes" is already added to the string value if ((dv.uom == DeviceValueUOM::NONE) || (dv.uom == DeviceValueUOM::MINUTES)) { break; @@ -837,6 +817,43 @@ std::string EMSdevice::get_value_uom(const char * key) const { return std::string{}; // not found } +bool EMSdevice::export_values(uint8_t device_type, JsonObject & output, const int8_t id, const uint8_t output_target) { + bool has_value = false; + uint8_t tag; + if (id >= 1 && id <= (1 + DeviceValueTAG::TAG_HS16 - DeviceValueTAG::TAG_HC1)) { + tag = DeviceValueTAG::TAG_HC1 + id - 1; // this sets also WWC and HS + } else if (id == -1 || id == 0) { + tag = DeviceValueTAG::TAG_NONE; + } else { + return false; + } + + if (id > 0 || output_target == EMSdevice::OUTPUT_TARGET::API_VERBOSE) { + for (const auto & emsdevice : EMSESP::emsdevices) { + if (emsdevice && (emsdevice->device_type() == device_type)) { + has_value |= emsdevice->generate_values(output, tag, (id < 1), output_target); // use nested for id -1 and 0 + } + } + return has_value; + } + + // for nested output add for each tag + for (tag = DeviceValueTAG::TAG_BOILER_DATA_WW; tag <= DeviceValueTAG::TAG_HS16; tag++) { + JsonObject output_hc = output; + bool nest_created = false; + for (const auto & emsdevice : EMSESP::emsdevices) { + if (emsdevice && (emsdevice->device_type() == device_type)) { + if (!nest_created && emsdevice->has_tags(tag)) { + output_hc = output.createNestedObject(EMSdevice::tag_to_mqtt(tag)); + nest_created = true; + } + has_value |= emsdevice->generate_values(output_hc, tag, true, output_target); // use nested for id -1 and 0 + } + } + } + return has_value; +} + // prepare array of device values used for the WebUI // this is loosely based of the function generate_values used for the MQTT and Console // except additional data is stored in the JSON document needed for the Web UI like the UOM and command diff --git a/src/emsdevice.h b/src/emsdevice.h index 62810471e..3a05ecb54 100644 --- a/src/emsdevice.h +++ b/src/emsdevice.h @@ -47,12 +47,13 @@ class EMSdevice { // static functions, used outside the class like in console.cpp, command.cpp, emsesp.cpp, mqtt.cpp static const char * device_type_2_device_name(const uint8_t device_type); static uint8_t device_name_2_device_type(const char * topic); - static const char * tag_to_string(uint8_t tag, const bool translate = true); static const char * uom_to_string(uint8_t uom); static const char * tag_to_mqtt(uint8_t tag); + static uint8_t decode_brand(uint8_t value); + static bool export_values(uint8_t device_type, JsonObject & output, const int8_t id, const uint8_t output_target); - static uint8_t decode_brand(uint8_t value); + // non static const char * device_type_name(); // returns short non-translated device type name const char * device_type_2_device_name_translated(); // returns translated device type name @@ -213,9 +214,10 @@ class EMSdevice { void register_telegram_type(const uint16_t telegram_type_id, const char * telegram_type_name, bool fetch, const process_function_p cb); bool handle_telegram(std::shared_ptr telegram); - std::string get_value_uom(const char * key) const; - bool get_value_info(JsonObject & root, const char * cmd, const int8_t id); - void get_dv_info(JsonObject & json); + std::string get_value_uom(const std::string & shortname) const; + + bool get_value_info(JsonObject & root, const char * cmd, const int8_t id); + void get_dv_info(JsonObject & json); enum OUTPUT_TARGET : uint8_t { API_VERBOSE, API_SHORTNAMES, MQTT, CONSOLE }; bool generate_values(JsonObject & output, const uint8_t tag_filter, const bool nested, const uint8_t output_target); diff --git a/src/emsesp.cpp b/src/emsesp.cpp index 3e2a8982d..21a8b19d5 100644 --- a/src/emsesp.cpp +++ b/src/emsesp.cpp @@ -386,13 +386,19 @@ void EMSESP::show_device_values(uuid::console::Shell & shell) { // print line for (JsonPair p : json) { - const char * key = p.key().c_str(); - shell.printf(" %s: ", key); + std::string key = p.key().c_str(); // this will be fullname and the shortname in brackets + shell.printf(" %s: ", key.c_str()); JsonVariant data = p.value(); shell.print(COLOR_BRIGHT_GREEN); shell.print(data.as()); + + // extract the shortname from the key, which is in brackets + std::size_t first_bracket = key.find_first_of('('); + std::size_t last_bracket = key.find_last_of(')'); + std::string shortname = key.substr(first_bracket + 1, last_bracket - first_bracket - 1); + // if there is a uom print it - std::string uom = emsdevice->get_value_uom(key); + std::string uom = emsdevice->get_value_uom(shortname); if (uom == "°C" && EMSESP::system_.fahrenheit()) { uom = "°F"; } @@ -1169,14 +1175,17 @@ bool EMSESP::add_device(const uint8_t device_id, const uint8_t product_id, const device_type, F_(info), [device_type](const char * value, const int8_t id, JsonObject & output) { - return command_info(device_type, output, id, EMSdevice::OUTPUT_TARGET::API_VERBOSE); + return EMSdevice::export_values(device_type, output, id, EMSdevice::OUTPUT_TARGET::API_VERBOSE); }, FL_(info_cmd)); Command::add( device_type, F_(values), [device_type](const char * value, const int8_t id, JsonObject & output) { - return command_info(device_type, output, id, EMSdevice::OUTPUT_TARGET::API_SHORTNAMES); // HIDDEN command showing short names, used in e.g. /api/boiler + return EMSdevice::export_values(device_type, + output, + id, + EMSdevice::OUTPUT_TARGET::API_SHORTNAMES); // HIDDEN command showing short names, used in e.g. /api/boiler }, nullptr, CommandFlag::HIDDEN); // this command is hidden @@ -1217,43 +1226,6 @@ bool EMSESP::command_commands(uint8_t device_type, JsonObject & output, const in return Command::list(device_type, output); } -// export all values for a specific device -bool EMSESP::command_info(uint8_t device_type, JsonObject & output, const int8_t id, const uint8_t output_target) { - bool has_value = false; - uint8_t tag; - if (id >= 1 && id <= (1 + DeviceValueTAG::TAG_HS16 - DeviceValueTAG::TAG_HC1)) { - tag = DeviceValueTAG::TAG_HC1 + id - 1; // this sets also WWC and HS - } else if (id == -1 || id == 0) { - tag = DeviceValueTAG::TAG_NONE; - } else { - return false; - } - - if (id > 0 || output_target == EMSdevice::OUTPUT_TARGET::API_VERBOSE) { - for (const auto & emsdevice : emsdevices) { - if (emsdevice && (emsdevice->device_type() == device_type)) { - has_value |= emsdevice->generate_values(output, tag, (id < 1), output_target); // use nested for id -1 and 0 - } - } - return has_value; - } - // for nested output add for each tag - for (tag = DeviceValueTAG::TAG_BOILER_DATA_WW; tag <= DeviceValueTAG::TAG_HS16; tag++) { - JsonObject output_hc = output; - bool nest_created = false; - for (const auto & emsdevice : emsdevices) { - if (emsdevice && (emsdevice->device_type() == device_type)) { - if (!nest_created && emsdevice->has_tags(tag)) { - output_hc = output.createNestedObject(EMSdevice::tag_to_mqtt(tag)); - nest_created = true; - } - has_value |= emsdevice->generate_values(output_hc, tag, true, output_target); // use nested for id -1 and 0 - } - } - } - return has_value; -} - // send a read request, passing it into to the Tx Service, with optional offset and length void EMSESP::send_read_request(const uint16_t type_id, const uint8_t dest, const uint8_t offset, const uint8_t length, const bool front) { txservice_.read_request(type_id, dest, offset, length, front); diff --git a/src/emsesp.h b/src/emsesp.h index 30634c103..e5d074460 100644 --- a/src/emsesp.h +++ b/src/emsesp.h @@ -245,7 +245,6 @@ class EMSESP { static void process_version(std::shared_ptr telegram); static void publish_response(std::shared_ptr telegram); static void publish_all_loop(); - static bool command_info(uint8_t device_type, JsonObject & output, const int8_t id, const uint8_t output_target); static bool command_commands(uint8_t device_type, JsonObject & output, const int8_t id); static bool command_entities(uint8_t device_type, JsonObject & output, const int8_t id); diff --git a/src/system.cpp b/src/system.cpp index be47f261a..f4cd90302 100644 --- a/src/system.cpp +++ b/src/system.cpp @@ -106,6 +106,35 @@ bool System::command_response(const char * value, const int8_t id, JsonObject & return true; } +// output all the EMS devices and their values, plus the sensors and any custom things +// basically dump everything we know about +bool System::command_values(const char * value, const int8_t id, JsonObject & output) { + DynamicJsonDocument doc(EMSESP_JSON_SIZE_XXXLARGE); + JsonObject device_output; + + for (const auto & device_class : EMSFactory::device_handlers()) { + for (const auto & emsdevice : EMSESP::emsdevices) { + if (emsdevice->device_type() == device_class.first) { + std::string title = emsdevice->device_type_2_device_name_translated() + std::string(" ") + emsdevice->to_string(); + device_output = output.createNestedObject(title); + emsesp::EMSdevice::export_values(emsdevice->device_type(), device_output, id, EMSdevice::OUTPUT_TARGET::API_VERBOSE); + } + } + } + + // Custom entities + device_output = output.createNestedObject("Custom Entities"); + EMSESP::webCustomEntityService.get_value_info(device_output, ""); + + // Sensors + device_output = output.createNestedObject("Analog Sensors"); + EMSESP::analogsensor_.command_info(nullptr, 0, device_output); + device_output = output.createNestedObject("Temperature Sensors"); + EMSESP::temperaturesensor_.command_info(nullptr, 0, device_output); + + return true; +} + // fetch device values bool System::command_fetch(const char * value, const int8_t id) { std::string value_s; @@ -756,6 +785,7 @@ void System::commands_init() { // restart and watch (and test) are also exposed as Console commands Command::add(EMSdevice::DeviceType::SYSTEM, F_(restart), System::command_restart, FL_(restart_cmd), CommandFlag::ADMIN_ONLY); Command::add(EMSdevice::DeviceType::SYSTEM, F_(watch), System::command_watch, FL_(watch_cmd)); + #if defined(EMSESP_TEST) Command::add(EMSdevice::DeviceType::SYSTEM, ("test"), System::command_test, FL_(test_cmd)); #endif @@ -764,6 +794,8 @@ void System::commands_init() { Command::add(EMSdevice::DeviceType::SYSTEM, F_(info), System::command_info, FL_(system_info_cmd)); Command::add(EMSdevice::DeviceType::SYSTEM, F_(commands), System::command_commands, FL_(commands_cmd)); Command::add(EMSdevice::DeviceType::SYSTEM, F("response"), System::command_response, FL_(commands_response)); + Command::add(EMSdevice::DeviceType::SYSTEM, F_(values), System::command_values, FL_(values_cmd)); + // MQTT subscribe "ems-esp/system/#" Mqtt::subscribe(EMSdevice::DeviceType::SYSTEM, "system/#", nullptr); // use empty function callback diff --git a/src/system.h b/src/system.h index a4cb6d5f6..d4826bb60 100644 --- a/src/system.h +++ b/src/system.h @@ -60,6 +60,8 @@ class System { static bool command_info(const char * value, const int8_t id, JsonObject & output); static bool command_commands(const char * value, const int8_t id, JsonObject & output); static bool command_response(const char * value, const int8_t id, JsonObject & output); + static bool command_values(const char * value, const int8_t id, JsonObject & output); + #if defined(EMSESP_TEST) static bool command_test(const char * value, const int8_t id); #endif diff --git a/src/temperaturesensor.h b/src/temperaturesensor.h index 353b8f8fa..3d7363054 100644 --- a/src/temperaturesensor.h +++ b/src/temperaturesensor.h @@ -111,6 +111,8 @@ class TemperatureSensor { bool update(const std::string & id, const std::string & name, int16_t offset); + bool command_info(const char * value, const int8_t id, JsonObject & output); + #if defined(EMSESP_TEST) void test(); #endif @@ -152,7 +154,6 @@ class TemperatureSensor { uint64_t get_id(const uint8_t addr[]); void remove_ha_topic(const std::string & id); - bool command_info(const char * value, const int8_t id, JsonObject & output); bool command_commands(const char * value, const int8_t id, JsonObject & output); std::vector sensors_; // our list of active sensors