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
- 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
- Don't create Home Assistant MQTT discovery entries for device values that don't exists (#756 on EMS-ESP repo)

View File

@@ -31,8 +31,11 @@ std::vector<Command::CmdFunction> Command::cmdfunctions_;
// 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) {
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_)) {
LOG_WARNING(F("Command %s on %s not found"), cmd, dname.c_str());
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
return ((cf->cmdfunction_)(value, id));
return ((cf->cmdfunction_)(value, id_new));
}
// calls a command. Takes a json object for output.
// id may be used to represent a heating circuit for example
// 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) {
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
std::string dname = EMSdevice::device_type_2_device_name(device_type);
if (value == nullptr) {
LOG_DEBUG(F("[DEBUG] Calling %s command %s"), dname.c_str(), cmd);
} 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) {
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_) {
return ((cf->cmdfunction_json_)(value, id, json));
return ((cf->cmdfunction_json_)(value, id_new, json));
} else {
if (value == nullptr || strlen(value) == 0) {
return EMSESP::get_device_value_info(json, cmd, device_type);
if (value == nullptr || strlen(value) == 0 || strcmp(value, "?") == 0 || strcmp(value, "*") == 0) {
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
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

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 show_all(uuid::console::Shell & shell);
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_devices(uuid::console::Shell & shell);

View File

@@ -620,12 +620,25 @@ bool EMSdevice::generate_values_json_web(JsonObject & json) {
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;
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_) {
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;
json["name"] = cmd;
json["name"] = dv.short_name;
if (dv.tag >= DeviceValueTAG::TAG_HC1) {
json["circuit"] = tag_to_string(dv.tag);
}
switch (dv.type) {
case DeviceValueType::ENUM: {
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);
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_web(JsonObject & json);

View File

@@ -440,7 +440,7 @@ void EMSESP::publish_device_values(uint8_t device_type) {
// group by device type
for (const auto & emsdevice : emsdevices) {
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()) {
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>());
}
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) {
if (emsdevice->device_type() == devicetype) {
return emsdevice->get_value_info(root, cmd);
return emsdevice->get_value_info(root, cmd, id);
}
}
return false;

View File

@@ -106,7 +106,7 @@ 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 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_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 /
int8_t id = -1;
// check for hcx/ prefix
if (cmd_only[0] == 'h' && cmd_only[1] == 'c' && cmd_only[3] == '/') {
id = cmd_only[2] - '0';
cmd_only += 4;
}
// check for hcx/ prefix, commented out, this is now in command::call
// if (cmd_only[0] == 'h' && cmd_only[1] == 'c' && cmd_only[3] == '/') {
// id = cmd_only[2] - '0';
// cmd_only += 4;
// }
// 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);