diff --git a/src/WebAPIService.cpp b/src/WebAPIService.cpp index f25c7a19f..2fe2cc882 100644 --- a/src/WebAPIService.cpp +++ b/src/WebAPIService.cpp @@ -45,12 +45,6 @@ void WebAPIService::webAPIService(AsyncWebServerRequest * request) { // get cmd, we know we have one String cmd = request->getParam(F_(cmd))->value(); - // look up command in our list - if (Command::find_command(device_type, cmd.c_str()) == nullptr) { - request->send(400, "text/plain", F("Invalid cmd")); - return; - } - String data; if (request->hasParam(F_(data))) { data = request->getParam(F_(data))->value(); diff --git a/src/command.cpp b/src/command.cpp index 9e1510b59..2d8ec80dd 100644 --- a/src/command.cpp +++ b/src/command.cpp @@ -58,10 +58,6 @@ bool Command::call(const uint8_t device_type, const char * cmd, const char * val std::string dname = EMSdevice::device_type_2_device_name(device_type); auto cf = find_command(device_type, cmd); - if (cf == nullptr) { - LOG_WARNING(F("Command %s on %s not found"), cmd, dname.c_str()); - return false; // command not found or not json - } #ifdef EMSESP_DEBUG if (value == nullptr) { @@ -79,10 +75,17 @@ bool Command::call(const uint8_t device_type, const char * cmd, const char * val return false; } - if (!cf->cmdfunction_json_) { - return ((cf->cmdfunction_)(value, id)); - } else { + if (cf == nullptr) { + return EMSESP::get_device_value_info(json, cmd, device_type); + } + + if (cf->cmdfunction_json_) { return ((cf->cmdfunction_json_)(value, id, json)); + } else { + if (value == nullptr || strlen(value) == 0) { + return EMSESP::get_device_value_info(json, cmd, device_type); + } + return ((cf->cmdfunction_)(value, id)); } } diff --git a/src/console.cpp b/src/console.cpp index 00ec04d0c..821352617 100644 --- a/src/console.cpp +++ b/src/console.cpp @@ -349,11 +349,6 @@ void EMSESPShell::add_console_commands() { } const char * cmd = arguments[1].c_str(); - if (Command::find_command(device_type, cmd) == nullptr) { - shell.print(F("Unknown command. Available commands are: ")); - Command::show(shell, device_type); - return; - } DynamicJsonDocument doc(EMSESP_JSON_SIZE_XLARGE_DYN); JsonObject json = doc.to(); @@ -379,7 +374,10 @@ void EMSESPShell::add_console_commands() { doc.shrinkToFit(); serializeJsonPretty(doc, shell); shell.println(); + return; } + shell.print(F("Unknown command. Available commands are: ")); + Command::show(shell, device_type); }, [&](Shell & shell __attribute__((unused)), const std::vector & arguments) -> std::vector { if (arguments.size() == 0) { @@ -416,6 +414,7 @@ std::string EMSESPShell::hostname_text() { return console_hostname_; } +/* // remove commands from the current context to save memory before exiting bool EMSESPShell::exit_context() { unsigned int current_context = context(); @@ -429,7 +428,6 @@ bool EMSESPShell::exit_context() { return false; } -/* // enter a custom context (sub-menu) void Console::enter_custom_context(Shell & shell, unsigned int context) { // load_standard_commands(context); @@ -500,7 +498,8 @@ void Console::load_standard_commands(unsigned int context) { }); EMSESPShell::commands->add_command(context, CommandFlags::USER, flash_string_vector{F_(exit)}, [=](Shell & shell, const std::vector & arguments __attribute__((unused))) { - shell.exit_context(); + shell.stop(); + // shell.exit_context(); }); EMSESPShell::commands->add_command(context, CommandFlags::USER, flash_string_vector{F_(su)}, [=](Shell & shell, const std::vector & arguments __attribute__((unused))) { @@ -664,7 +663,7 @@ void Console::load_system_commands(unsigned int context) { } - +/* // prompt, change per context std::string EMSESPShell::context_text() { switch (static_cast(context())) { @@ -678,6 +677,7 @@ std::string EMSESPShell::context_text() { return std::string{}; } } +*/ // when in su (admin) show # as the prompt suffix std::string EMSESPShell::prompt_suffix() { diff --git a/src/console.h b/src/console.h index fd6c3e916..58c04e6e8 100644 --- a/src/console.h +++ b/src/console.h @@ -101,10 +101,10 @@ class EMSESPShell : virtual public uuid::console::Shell { void stopped() override; void display_banner() override; std::string hostname_text() override; - std::string context_text() override; + // std::string context_text() override; std::string prompt_suffix() override; void end_of_transmission() override; - bool exit_context() override; + // bool exit_context() override; private: void add_console_commands(); diff --git a/src/emsdevice.cpp b/src/emsdevice.cpp index ecf3ef464..a0c5e600d 100644 --- a/src/emsdevice.cpp +++ b/src/emsdevice.cpp @@ -613,6 +613,105 @@ bool EMSdevice::generate_values_json_web(JsonObject & json) { return (num_elements != 0); } +bool EMSdevice::get_value_info(JsonObject & root, const char * cmd) { + JsonObject json = root; + for (auto & dv : devicevalues_) { + if (strcmp(cmd, uuid::read_flash_string(dv.short_name).c_str()) == 0) { + uint8_t divider = (dv.options_size == 1) ? Helpers::atoint(uuid::read_flash_string(dv.options[0]).c_str()) : 0; + json["name"] = cmd; + switch (dv.type) { + case DeviceValueType::ENUM: + // json["value"] = dv.options[*(uint8_t *)(dv.value_p)]; // text + if (Helpers::hasValue((uint8_t)(*(uint8_t *)(dv.value_p)))) { + json["value"] = (uint8_t)(*(uint8_t *)(dv.value_p)); + } + json["type"] = "enum"; + json["min"] = 0; + json["max"] = dv.options_size - 1; + break; + case DeviceValueType::USHORT: + if (Helpers::hasValue(*(uint16_t *)(dv.value_p))) { + json["value"] = Helpers::round2(*(uint16_t *)(dv.value_p), divider); + } + json["type"] = "number"; + json["min"] = 0; + json["max"] = divider ? EMS_VALUE_USHORT_NOTSET / divider : EMS_VALUE_USHORT_NOTSET; + break; + case DeviceValueType::UINT: + if (Helpers::hasValue(*(uint8_t *)(dv.value_p))) { + json["value"] = Helpers::round2(*(uint8_t *)(dv.value_p), divider); + } + json["type"] = "number"; + json["min"] = 0; + if (dv.uom == DeviceValueUOM::PERCENT) { + json["max"] = 100; + } else { + json["max"] = divider ? EMS_VALUE_UINT_NOTSET / divider : EMS_VALUE_UINT_NOTSET; + } + break; + case DeviceValueType::SHORT: + if (Helpers::hasValue(*(int16_t *)(dv.value_p))) { + json["value"] = Helpers::round2(*(int16_t *)(dv.value_p), divider); + } + json["type"] = "number"; + json["min"] = divider ? -EMS_VALUE_SHORT_NOTSET / divider : -EMS_VALUE_SHORT_NOTSET; + json["max"] = divider ? EMS_VALUE_SHORT_NOTSET / divider : EMS_VALUE_SHORT_NOTSET; + break; + case DeviceValueType::INT: + if (Helpers::hasValue(*(int8_t *)(dv.value_p))) { + json["value"] = Helpers::round2(*(int8_t *)(dv.value_p), divider); + } + json["type"] = "number"; + if (dv.uom == DeviceValueUOM::PERCENT) { + json["min"] = -100; + json["max"] = 100; + } else { + json["min"] = divider ? -EMS_VALUE_INT_NOTSET / divider : -EMS_VALUE_INT_NOTSET; + json["max"] = divider ? EMS_VALUE_INT_NOTSET / divider : EMS_VALUE_INT_NOTSET; + } + break; + case DeviceValueType::ULONG: + if (Helpers::hasValue(*(uint32_t *)(dv.value_p))) { + json["value"] = Helpers::round2(*(uint32_t *)(dv.value_p), divider); + } + json["type"] = "number"; + json["min"] = 0; + json["max"] = divider ? EMS_VALUE_ULONG_NOTSET / divider : EMS_VALUE_ULONG_NOTSET; + break; + case DeviceValueType::BOOL: + if (Helpers::hasValue(*(uint8_t *)(dv.value_p), EMS_VALUE_BOOL)) { + json["value"] = (bool)(*(uint8_t *)(dv.value_p)) ? true : false; + } + json["type"] = "boolean"; + break; + case DeviceValueType::TIME: + if (Helpers::hasValue(*(uint32_t *)(dv.value_p))) { + json["value"] = (divider) ? *(uint32_t *)(dv.value_p) / divider : *(uint32_t *)(dv.value_p); + } + json["type"] = "number"; + json["min"] = 0; + json["max"] = divider ? EMS_VALUE_ULONG_NOTSET / divider : EMS_VALUE_ULONG_NOTSET; + break; + case DeviceValueType::TEXT: + if (Helpers::hasValue((char *)(dv.value_p))) { + json["value"] = (char *)(dv.value_p); + } + json["type"] = "text"; + break; + default: + json["type"] = "unknown"; + break; + } + if (dv.uom != DeviceValueUOM::NONE) { + json["unit"] = EMSdevice::uom_to_string(dv.uom); + } + json["writeable"] = dv.has_cmd; + return true; + } + } + return false; +} + // For each value in the device create the json object pair and add it to given json // return false if empty // this is used to create both the MQTT payloads and Console messages (console = true) @@ -778,7 +877,8 @@ void EMSdevice::publish_mqtt_ha_sensor() { void EMSdevice::ha_config_clear() { for (auto & dv : devicevalues_) { - dv.ha &= ~DeviceValueHA::HA_DONE; + // dv.ha &= ~DeviceValueHA::HA_DONE; // repubish all with values + dv.ha = DeviceValueHA::HA_NONE; // also wait for new value } ha_config_done(false); } diff --git a/src/emsdevice.h b/src/emsdevice.h index a7c446421..5ea14ab17 100644 --- a/src/emsdevice.h +++ b/src/emsdevice.h @@ -263,6 +263,7 @@ class EMSdevice { bool handle_telegram(std::shared_ptr telegram); std::string get_value_uom(const char * key); + bool get_value_info(JsonObject & root, const char * cmd); bool generate_values_json(JsonObject & json, const uint8_t tag_filter, const bool nested, const bool console = false); bool generate_values_json_web(JsonObject & json); diff --git a/src/emsesp.cpp b/src/emsesp.cpp index cf1cd49bf..a38f5ad59 100644 --- a/src/emsesp.cpp +++ b/src/emsesp.cpp @@ -547,6 +547,15 @@ void EMSESP::publish_response(std::shared_ptr telegram) { Mqtt::publish(F("response"), doc.as()); } +bool EMSESP::get_device_value_info(JsonObject & root, const char * cmd, uint8_t devicetype) { + for (const auto & emsdevice : emsdevices) { + if (emsdevice->device_type() == devicetype) { + return emsdevice->get_value_info(root, cmd); + } + } + return false; +} + // search for recognized device_ids : Me, All, otherwise print hex value std::string EMSESP::device_tostring(const uint8_t device_id) { if ((device_id & 0x7F) == rxservice_.ems_bus_id()) { diff --git a/src/emsesp.h b/src/emsesp.h index da3fee712..982c6b1af 100644 --- a/src/emsesp.h +++ b/src/emsesp.h @@ -106,6 +106,8 @@ class EMSESP { static void actual_master_thermostat(const uint8_t device_id); static uint8_t check_master_device(const uint8_t device_id, const uint16_t type_id, const bool read); + static bool get_device_value_info(JsonObject & root, const char * cmd, uint8_t devicetype); + static void show_device_values(uuid::console::Shell & shell); static void show_sensor_values(uuid::console::Shell & shell); diff --git a/src/mqtt.cpp b/src/mqtt.cpp index d72d9b2b5..f6294d3e2 100644 --- a/src/mqtt.cpp +++ b/src/mqtt.cpp @@ -313,6 +313,7 @@ void Mqtt::on_message(const char * fulltopic, const char * payload, size_t len) if (mf.mqtt_subfunction_) { if (!(mf.mqtt_subfunction_)(message)) { LOG_ERROR(F("MQTT error: invalid payload %s for this topic %s"), message, topic); + Mqtt::publish(F("response"), "invalid"); } return; } @@ -335,6 +336,7 @@ void Mqtt::on_message(const char * fulltopic, const char * payload, size_t len) // LOG_INFO(F("devicetype= %d, topic = %s, cmd = %s, message = %s, id = %d"), mf.device_type_, topic, cmd_only, message, id); if (!Command::call(mf.device_type_, cmd_only, message, id)) { LOG_ERROR(F("No matching cmd (%s) in topic %s, id %d, or invalid data"), cmd_only, topic, id); + Mqtt::publish(F("response"), "unknown"); } return; } @@ -379,11 +381,13 @@ void Mqtt::on_message(const char * fulltopic, const char * payload, size_t len) cmd_known = Command::call(mf.device_type_, command, "", n, json); if (cmd_known && json.size()) { Mqtt::publish(F("response"), resp.as()); - } + return; + } } if (!cmd_known) { LOG_ERROR(F("No matching cmd (%s) or invalid data"), command); + Mqtt::publish(F("response"), "unknown"); } return;