id to value_info, alternative prefix to command/value

This commit is contained in:
MichaelDvP
2021-04-24 10:39:17 +02:00
parent c4e7747fd1
commit 70d8b6824c
8 changed files with 75 additions and 24 deletions

View File

@@ -4,6 +4,8 @@
- Mock API to simulate an ESP, for testing web - Mock API to simulate an ESP, for testing web
- Able to write values from the Web UI - Able to write values from the Web UI
- check values with `"cmd":<valuename>` and data empty or `?`
- set hc for values and commands by id or prefix `hc<x>`+separarator, separator can be any char
## Fixed ## Fixed
- Don't create Home Assistant MQTT discovery entries for device values that don't exists (#756 on EMS-ESP repo) - Don't create Home Assistant MQTT discovery entries for device values that don't exists (#756 on EMS-ESP repo)

View File

@@ -30,9 +30,12 @@ std::vector<Command::CmdFunction> Command::cmdfunctions_;
// id may be used to represent a heating circuit for example, it's optional // id may be used to represent a heating circuit for example, it's optional
// returns false if error or not found // returns false if error or not found
bool Command::call(const uint8_t device_type, const char * cmd, const char * value, const int8_t id) { bool Command::call(const uint8_t device_type, const char * cmd, const char * value, const int8_t id) {
std::string dname = EMSdevice::device_type_2_device_name(device_type); std::string dname = EMSdevice::device_type_2_device_name(device_type);
int8_t id_new = id;
char cmd_new[20];
auto cf = find_command(device_type, cmd); check_command(cmd_new, cmd, id_new);
auto cf = find_command(device_type, cmd_new);
if ((cf == nullptr) || (cf->cmdfunction_json_)) { if ((cf == nullptr) || (cf->cmdfunction_json_)) {
LOG_WARNING(F("Command %s on %s not found"), cmd, dname.c_str()); LOG_WARNING(F("Command %s on %s not found"), cmd, dname.c_str());
return false; // command not found, or requires a json return false; // command not found, or requires a json
@@ -48,18 +51,21 @@ bool Command::call(const uint8_t device_type, const char * cmd, const char * val
} }
#endif #endif
return ((cf->cmdfunction_)(value, id)); return ((cf->cmdfunction_)(value, id_new));
} }
// calls a command. Takes a json object for output. // calls a command. Takes a json object for output.
// id may be used to represent a heating circuit for example // id may be used to represent a heating circuit for example
// returns false if error or not found // returns false if error or not found
bool Command::call(const uint8_t device_type, const char * cmd, const char * value, const int8_t id, JsonObject & json) { bool Command::call(const uint8_t device_type, const char * cmd, const char * value, const int8_t id, JsonObject & json) {
std::string dname = EMSdevice::device_type_2_device_name(device_type); int8_t id_new = id;
char cmd_new[20];
auto cf = find_command(device_type, cmd); check_command(cmd_new, cmd, id_new);
auto cf = find_command(device_type, cmd_new);
#ifdef EMSESP_DEBUG #ifdef EMSESP_DEBUG
std::string dname = EMSdevice::device_type_2_device_name(device_type);
if (value == nullptr) { if (value == nullptr) {
LOG_DEBUG(F("[DEBUG] Calling %s command %s"), dname.c_str(), cmd); LOG_DEBUG(F("[DEBUG] Calling %s command %s"), dname.c_str(), cmd);
} else if (id == -1) { } else if (id == -1) {
@@ -76,19 +82,48 @@ bool Command::call(const uint8_t device_type, const char * cmd, const char * val
} }
if (cf == nullptr) { if (cf == nullptr) {
return EMSESP::get_device_value_info(json, cmd, device_type); return EMSESP::get_device_value_info(json, cmd_new, id_new, device_type);
} }
if (cf->cmdfunction_json_) { if (cf->cmdfunction_json_) {
return ((cf->cmdfunction_json_)(value, id, json)); return ((cf->cmdfunction_json_)(value, id_new, json));
} else { } else {
if (value == nullptr || strlen(value) == 0) { if (value == nullptr || strlen(value) == 0 || strcmp(value, "?") == 0 || strcmp(value, "*") == 0) {
return EMSESP::get_device_value_info(json, cmd, device_type); return EMSESP::get_device_value_info(json, cmd_new, id_new, device_type);
} }
return ((cf->cmdfunction_)(value, id)); return ((cf->cmdfunction_)(value, id_new));
} }
} }
char * Command::check_command(char * out, const char * cmd, int8_t & id) {
// convert cmd to lowercase
strlcpy(out, cmd, 20);
for (char * p = out; *p; p++) {
*p = tolower(*p);
}
//scan for prefix hc.
for (uint8_t i = DeviceValueTAG::TAG_HC1; i <= DeviceValueTAG::TAG_HC4; i++) {
if ((strncmp(out, EMSdevice::tag_to_string(i).c_str(), 3) == 0) && (strlen(out) > 4)) {
strcpy(out, &out[4]);
id = 1 + i - DeviceValueTAG::TAG_HC1;
break;
}
}
//scan for prefix wwc.
for (uint8_t i = DeviceValueTAG::TAG_WWC1; i <= DeviceValueTAG::TAG_WWC4; i++) {
if ((strncmp(out, EMSdevice::tag_to_string(i).c_str(), 4) == 0) && (strlen(out) > 5)) {
strcpy(out, &out[5]);
id = 8 + i - DeviceValueTAG::TAG_WWC1;
break;
}
}
return out;
}
// add a command to the list, which does not return json // add a command to the list, which does not return json
void Command::add(const uint8_t device_type, const __FlashStringHelper * cmd, cmdfunction_p cb, uint8_t flag) { void Command::add(const uint8_t device_type, const __FlashStringHelper * cmd, cmdfunction_p cb, uint8_t flag) {
// if the command already exists for that device type don't add it // if the command already exists for that device type don't add it

View File

@@ -65,6 +65,7 @@ class Command {
static void add_with_json(const uint8_t device_type, const __FlashStringHelper * cmd, cmdfunction_json_p cb); static void add_with_json(const uint8_t device_type, const __FlashStringHelper * cmd, cmdfunction_json_p cb);
static void show_all(uuid::console::Shell & shell); static void show_all(uuid::console::Shell & shell);
static Command::CmdFunction * find_command(const uint8_t device_type, const char * cmd); static Command::CmdFunction * find_command(const uint8_t device_type, const char * cmd);
static char * check_command(char * out, const char * cmd, int8_t & id);
static void show(uuid::console::Shell & shell, uint8_t device_type); static void show(uuid::console::Shell & shell, uint8_t device_type);
static void show_devices(uuid::console::Shell & shell); static void show_devices(uuid::console::Shell & shell);

View File

@@ -620,12 +620,25 @@ bool EMSdevice::generate_values_json_web(JsonObject & json) {
return (num_elements != 0); return (num_elements != 0);
} }
bool EMSdevice::get_value_info(JsonObject & root, const char * cmd) { bool EMSdevice::get_value_info(JsonObject & root, const char * cmd, const int8_t id) {
JsonObject json = root; JsonObject json = root;
int8_t tag = id;
// check if we have hc or wwc
if (id >= 1 && id <= 4) {
tag = DeviceValueTAG::TAG_HC1 + id - 1;
} else if (id >= 8 && id <= 11) {
tag = DeviceValueTAG::TAG_WWC1 + id - 8;
}
// search device value with this tag
for (auto & dv : devicevalues_) { for (auto & dv : devicevalues_) {
if (strcmp(cmd, uuid::read_flash_string(dv.short_name).c_str()) == 0) { if (strcmp(cmd, uuid::read_flash_string(dv.short_name).c_str()) == 0 && (tag <= 0 || tag == dv.tag)) {
uint8_t divider = (dv.options_size == 1) ? Helpers::atoint(uuid::read_flash_string(dv.options[0]).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; json["name"] = dv.short_name;
if (dv.tag >= DeviceValueTAG::TAG_HC1) {
json["circuit"] = tag_to_string(dv.tag);
}
switch (dv.type) { switch (dv.type) {
case DeviceValueType::ENUM: { case DeviceValueType::ENUM: {
if (Helpers::hasValue((uint8_t)(*(uint8_t *)(dv.value_p)))) { if (Helpers::hasValue((uint8_t)(*(uint8_t *)(dv.value_p)))) {

View File

@@ -263,7 +263,7 @@ class EMSdevice {
bool handle_telegram(std::shared_ptr<const Telegram> telegram); bool handle_telegram(std::shared_ptr<const Telegram> telegram);
std::string get_value_uom(const char * key); std::string get_value_uom(const char * key);
bool get_value_info(JsonObject & root, const char * cmd); bool get_value_info(JsonObject & root, const char * cmd, const int8_t id);
bool generate_values_json(JsonObject & json, const uint8_t tag_filter, const bool nested, const bool console = false); 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); bool generate_values_json_web(JsonObject & json);

View File

@@ -440,7 +440,7 @@ void EMSESP::publish_device_values(uint8_t device_type) {
// group by device type // group by device type
for (const auto & emsdevice : emsdevices) { for (const auto & emsdevice : emsdevices) {
if (emsdevice && (emsdevice->device_type() == device_type)) { if (emsdevice && (emsdevice->device_type() == device_type)) {
// if we're using HA, if done is checked for each sensor in devices // if we're using HA, done is checked for each sensor in devices
if (Mqtt::ha_enabled()) { if (Mqtt::ha_enabled()) {
emsdevice->publish_mqtt_ha_sensor(); // create the configs for each value as a sensor emsdevice->publish_mqtt_ha_sensor(); // create the configs for each value as a sensor
} }
@@ -547,10 +547,10 @@ void EMSESP::publish_response(std::shared_ptr<const Telegram> telegram) {
Mqtt::publish(F("response"), doc.as<JsonObject>()); Mqtt::publish(F("response"), doc.as<JsonObject>());
} }
bool EMSESP::get_device_value_info(JsonObject & root, const char * cmd, uint8_t devicetype) { bool EMSESP::get_device_value_info(JsonObject & root, const char * cmd, const int8_t id, const uint8_t devicetype) {
for (const auto & emsdevice : emsdevices) { for (const auto & emsdevice : emsdevices) {
if (emsdevice->device_type() == devicetype) { if (emsdevice->device_type() == devicetype) {
return emsdevice->get_value_info(root, cmd); return emsdevice->get_value_info(root, cmd, id);
} }
} }
return false; return false;

View File

@@ -106,7 +106,7 @@ class EMSESP {
static void actual_master_thermostat(const uint8_t device_id); 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 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 bool get_device_value_info(JsonObject & root, const char * cmd, const int8_t id, const uint8_t devicetype);
static void show_device_values(uuid::console::Shell & shell); static void show_device_values(uuid::console::Shell & shell);
static void show_sensor_values(uuid::console::Shell & shell); static void show_sensor_values(uuid::console::Shell & shell);

View File

@@ -328,11 +328,11 @@ void Mqtt::on_message(const char * fulltopic, const char * payload, size_t len)
} }
cmd_only++; // skip the / cmd_only++; // skip the /
int8_t id = -1; int8_t id = -1;
// check for hcx/ prefix // check for hcx/ prefix, commented out, this is now in command::call
if (cmd_only[0] == 'h' && cmd_only[1] == 'c' && cmd_only[3] == '/') { // if (cmd_only[0] == 'h' && cmd_only[1] == 'c' && cmd_only[3] == '/') {
id = cmd_only[2] - '0'; // id = cmd_only[2] - '0';
cmd_only += 4; // cmd_only += 4;
} // }
// LOG_INFO(F("devicetype= %d, topic = %s, cmd = %s, message = %s, id = %d"), mf.device_type_, topic, cmd_only, message, id); // 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)) { 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); LOG_ERROR(F("No matching cmd (%s) in topic %s, id %d, or invalid data"), cmd_only, topic, id);
@@ -382,7 +382,7 @@ void Mqtt::on_message(const char * fulltopic, const char * payload, size_t len)
if (cmd_known && json.size()) { if (cmd_known && json.size()) {
Mqtt::publish(F("response"), resp.as<JsonObject>()); Mqtt::publish(F("response"), resp.as<JsonObject>());
return; return;
} }
} }
if (!cmd_known) { if (!cmd_known) {