diff --git a/src/analogsensor.cpp b/src/analogsensor.cpp index 7a6856f53..8131754d6 100644 --- a/src/analogsensor.cpp +++ b/src/analogsensor.cpp @@ -435,15 +435,43 @@ void AnalogSensor::publish_values(const bool force) { // called from emsesp.cpp, similar to the emsdevice->get_value_info // searches by name bool AnalogSensor::get_value_info(JsonObject & output, const char * cmd, const int8_t id) const { + // make a copy of the string command for parsing + char command_s[30]; + strlcpy(command_s, cmd, sizeof(command_s)); + char * attribute_s = nullptr; + + // check specific attribute to fetch instead of the complete record + char * breakp = strchr(command_s, '/'); + if (breakp) { + *breakp = '\0'; + attribute_s = breakp + 1; + } + for (const auto & sensor : sensors_) { - if (strcmp(cmd, sensor.name().c_str()) == 0) { + if (strcmp(command_s, sensor.name().c_str()) == 0) { output["gpio"] = sensor.gpio(); output["name"] = sensor.name(); - output["type"] = sensor.type(); - output["uom"] = sensor.uom(); + output["type"] = F_(number); + output["analog"] = FL_(enum_sensortype)[sensor.type()]; + output["uom"] = EMSdevice::uom_to_string(sensor.uom()); output["offset"] = sensor.offset(); output["factor"] = sensor.factor(); output["value"] = sensor.value(); + // if we're filtering on an attribute, go find it + if (attribute_s) { + if (output.containsKey(attribute_s)) { + JsonVariant data = output[attribute_s]; + output.clear(); + output["api_data"] = data; + return true; + } else { + char error[100]; + snprintf(error, sizeof(error), "cannot find attribute %s in entity %s", attribute_s, command_s); + output.clear(); + output["message"] = error; + return false; + } + } return true; } } @@ -461,7 +489,8 @@ bool AnalogSensor::command_info(const char * value, const int8_t id, JsonObject if (id == -1) { // show number and id JsonObject dataSensor = output.createNestedObject(sensor.name()); dataSensor["gpio"] = sensor.gpio(); - dataSensor["type"] = FL_(enum_sensortype)[sensor.type()]; + dataSensor["type"] = F_(number); + dataSensor["analog"] = FL_(enum_sensortype)[sensor.type()]; if (sensor.type() == AnalogType::ADC) { dataSensor["uom"] = EMSdevice::uom_to_string(sensor.uom()); dataSensor["offset"] = sensor.offset(); diff --git a/src/command.cpp b/src/command.cpp index 1c3c54dc1..a169f87db 100644 --- a/src/command.cpp +++ b/src/command.cpp @@ -90,11 +90,16 @@ uint8_t Command::process(const char * path, const bool is_admin, const JsonObjec const char * command_p = nullptr; if (num_paths == 2) { command_p = p.paths()[1].c_str(); - } else if (num_paths >= 3) { + } else if (num_paths == 3) { // concatenate the path into one string as it could be in the format 'hc/XXX' char command[50]; snprintf(command, sizeof(command), "%s/%s", p.paths()[1].c_str(), p.paths()[2].c_str()); command_p = command; + } else if (num_paths > 3) { + // concatenate the path into one string as it could be in the format 'hc/XXX/attribute' + char command[50]; + snprintf(command, sizeof(command), "%s/%s/%s", p.paths()[1].c_str(), p.paths()[2].c_str(), p.paths()[3].c_str()); + command_p = command; } else { // take it from the JSON if (input.containsKey("entity")) { @@ -110,7 +115,7 @@ uint8_t Command::process(const char * path, const bool is_admin, const JsonObjec if (command_p == nullptr) { // handle dead endpoints like api/system or api/boiler // default to 'info' for SYSTEM, DALLASENSOR and ANALOGSENSOR, the other devices to 'values' for shortname version - if (num_paths < 3) { + if (num_paths < (id_n > 0 ? 4 : 3)) { if (device_type < EMSdevice::DeviceType::BOILER) { command_p = "info"; } else { @@ -188,37 +193,33 @@ const char * Command::parse_command_string(const char * command, int8_t & id) { return nullptr; } - // make a copy of the string command for parsing - char command_s[30]; - strlcpy(command_s, command, sizeof(command_s)); - - // look for a delimeter and split the string - char * p = command_s; - char * breakp = strchr(p, '.'); - if (!breakp) { - p = command_s; // reset and look for / - breakp = strchr(p, '/'); - if (!breakp) { - p = command_s; // reset and look for _ - breakp = strchr(p, '_'); - if (!breakp) { - return command; // no delimeter found, return the whole string - } - } + // check prefix and valid number range, also check 'id' + if (!strncmp(command, "hc", 2) && command[2] >= '1' && command[2] <= '8') { + id = command[2] - '0'; + command += 3; + } else if (!strncmp(command, "wwc", 3) && command[3] == '1' && command[4] == '0') { + id = 19; + command += 5; + } else if (!strncmp(command, "wwc", 3) && command[3] >= '1' && command[3] <= '9') { + id = command[3] - '0' + 8; + command += 4; + } else if (!strncmp(command, "id", 2) && command[2] == '1' && command[3] >= '0' && command[3] <= '9') { + id = command[3] - '0' + 10; + command += 4; + } else if (!strncmp(command, "id", 2) && command[2] >= '1' && command[2] <= '9') { + id = command[2] - '0'; + command += 3; + } + // remove separator + if (command[0] == '/' || command[0] == '.' || command[0] == '_') { + command++; + } + // return null for empty command + if (command[0] == '\0') { + return nullptr; } - // extract the hc or wwc number - uint8_t start_pos = breakp - p + 1; - if (!strncmp(command, "hc", 2) && start_pos == 4) { - id = command[start_pos - 2] - '0'; - } else if (!strncmp(command, "wwc", 3) && start_pos == 5) { - id = command[start_pos - 2] - '0' + 8; // wwc1 has id 9 - } else { - id = 0; // special case for extracting the attributes - return command; - } - - return (command + start_pos); + return command; } // calls a command directly diff --git a/src/dallassensor.cpp b/src/dallassensor.cpp index a66e070fd..58c15e123 100644 --- a/src/dallassensor.cpp +++ b/src/dallassensor.cpp @@ -375,8 +375,20 @@ bool DallasSensor::command_info(const char * value, const int8_t id, JsonObject // called from emsesp.cpp, similar to the emsdevice->get_value_info bool DallasSensor::get_value_info(JsonObject & output, const char * cmd, const int8_t id) { + // make a copy of the string command for parsing + char command_s[30]; + strlcpy(command_s, cmd, sizeof(command_s)); + char * attribute_s = nullptr; + + // check specific attribute to fetch instead of the complete record + char * breakp = strchr(command_s, '/'); + if (breakp) { + *breakp = '\0'; + attribute_s = breakp + 1; + } + for (const auto & sensor : sensors_) { - if (strcmp(cmd, sensor.name().c_str()) == 0) { + if (strcmp(command_s, sensor.name().c_str()) == 0) { output["id"] = sensor.id(); output["name"] = sensor.name(); if (Helpers::hasValue(sensor.temperature_c)) { @@ -385,8 +397,23 @@ bool DallasSensor::get_value_info(JsonObject & output, const char * cmd, const i output["type"] = F_(number); output["min"] = Helpers::round2(-55, 0, EMSESP::system_.fahrenheit() ? 2 : 0); output["max"] = Helpers::round2(125, 0, EMSESP::system_.fahrenheit() ? 2 : 0); - output["unit"] = EMSdevice::uom_to_string(DeviceValueUOM::DEGREES); + output["uom"] = EMSdevice::uom_to_string(DeviceValueUOM::DEGREES); output["writeable"] = false; + // if we're filtering on an attribute, go find it + if (attribute_s) { + if (output.containsKey(attribute_s)) { + JsonVariant data = output[attribute_s]; + output.clear(); + output["api_data"] = data; + return true; + } else { + char error[100]; + snprintf(error, sizeof(error), "cannot find attribute %s in entity %s", attribute_s, command_s); + output.clear(); + output["message"] = error; + return false; + } + } return true; } } diff --git a/src/emsdevice.cpp b/src/emsdevice.cpp index a1465ee47..29d2759a2 100644 --- a/src/emsdevice.cpp +++ b/src/emsdevice.cpp @@ -912,16 +912,13 @@ bool EMSdevice::get_value_info(JsonObject & output, const char * cmd, const int8 // make a copy of the string command for parsing char command_s[30]; strlcpy(command_s, cmd, sizeof(command_s)); - char * attribute_s = command_s; + char * attribute_s = nullptr; - // if id=0 then we have a specific attribute to fetch instead of the complete record - if (id == 0) { - char * p = command_s; - char * breakp = strchr(p, '/'); - if (breakp) { - *breakp = '\0'; - attribute_s = breakp + 1; - } + // check specific attribute to fetch instead of the complete record + char * breakp = strchr(command_s, '/'); + if (breakp) { + *breakp = '\0'; + attribute_s = breakp + 1; } // search device value with this tag @@ -1065,8 +1062,8 @@ bool EMSdevice::get_value_info(JsonObject & output, const char * cmd, const int8 json[value] = "not set"; } - // if id is 0 then we're filtering on an attribute, go find it - if (id == 0) { + // if we're filtering on an attribute, go find it + if (attribute_s) { #if defined(EMSESP_DEBUG) EMSESP::logger().debug(F("[DEBUG] Attribute '%s'"), attribute_s); #endif