fix UOM not showing in console - and added new command 'system values'

This commit is contained in:
Proddy
2023-11-12 15:59:29 +01:00
parent ea38011085
commit 9993a7c739
8 changed files with 99 additions and 72 deletions

View File

@@ -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<Sensor> sensors_; // our list of sensors

View File

@@ -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

View File

@@ -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);
// 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,7 +214,8 @@ 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<const Telegram> telegram);
std::string get_value_uom(const char * key) const;
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);

View File

@@ -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<std::string>());
// 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);

View File

@@ -245,7 +245,6 @@ class EMSESP {
static void process_version(std::shared_ptr<const Telegram> telegram);
static void publish_response(std::shared_ptr<const Telegram> 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);

View File

@@ -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

View File

@@ -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

View File

@@ -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<Sensor> sensors_; // our list of active sensors