mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-06 07:49:52 +03:00
refactor common commands #1897
This commit is contained in:
@@ -33,6 +33,7 @@
|
|||||||
- scheduler can use web get/post for values and commands [#1806](https://github.com/emsesp/EMS-ESP32/issues/1806)
|
- scheduler can use web get/post for values and commands [#1806](https://github.com/emsesp/EMS-ESP32/issues/1806)
|
||||||
- RT800 remote emulation [#1867](https://github.com/emsesp/EMS-ESP32/issues/1867)
|
- RT800 remote emulation [#1867](https://github.com/emsesp/EMS-ESP32/issues/1867)
|
||||||
- RC310 cooling parameters [#1857](https://github.com/emsesp/EMS-ESP32/issues/1857)
|
- RC310 cooling parameters [#1857](https://github.com/emsesp/EMS-ESP32/issues/1857)
|
||||||
|
- command `api/device/entities` [#1897](https://github.com/emsesp/EMS-ESP32/issues/1897)
|
||||||
|
|
||||||
## Fixed
|
## Fixed
|
||||||
|
|
||||||
|
|||||||
@@ -648,78 +648,39 @@ void AnalogSensor::publish_values(const bool force) {
|
|||||||
// called from emsesp.cpp for commands
|
// called from emsesp.cpp for commands
|
||||||
// searches sensor by name
|
// searches sensor by name
|
||||||
bool AnalogSensor::get_value_info(JsonObject output, const char * cmd, const int8_t id) {
|
bool AnalogSensor::get_value_info(JsonObject output, const char * cmd, const int8_t id) {
|
||||||
// check of it a 'commands' command
|
|
||||||
if (Helpers::toLower(cmd) == F_(commands)) {
|
|
||||||
return Command::list(EMSdevice::DeviceType::ANALOGSENSOR, output);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sensors_.empty()) {
|
if (sensors_.empty()) {
|
||||||
return true; // no sensors, return true
|
return true; // no sensors, return true
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t show_all = 0;
|
if (!strcmp(cmd, F_(info)) || !strcmp(cmd, F_(values))) {
|
||||||
if (Helpers::hasValue(cmd)) {
|
for (const auto & sensor : sensors_) {
|
||||||
show_all = (strncmp(cmd, F_(info), 4) == 0) ? 1 : (strncmp(cmd, F_(values), 6) == 0) ? 2 : 0;
|
output[sensor.name()] = sensor.value();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// see if we're showing all sensors
|
if (!strcmp(cmd, F_(entities))) {
|
||||||
if (show_all) {
|
|
||||||
for (const auto & sensor : sensors_) {
|
for (const auto & sensor : sensors_) {
|
||||||
if (show_all == 1) {
|
get_value_json(output[sensor.name()].to<JsonObject>(), sensor);
|
||||||
// info
|
|
||||||
JsonObject dataSensor = output[sensor.name()].to<JsonObject>();
|
|
||||||
addSensorJson(dataSensor, sensor);
|
|
||||||
} else {
|
|
||||||
// values, shortname version. Also used in 'system allvalues'
|
|
||||||
output[sensor.name()] = sensor.value();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// this is for a specific sensor
|
// this is for a specific sensor
|
||||||
// make a copy of the string command for parsing, and lowercase it
|
const char * attribute_s = Command::get_attribute(cmd);
|
||||||
char sensor_name[COMMAND_MAX_LENGTH] = {'\0'};
|
|
||||||
char * attribute_s = nullptr;
|
|
||||||
strlcpy(sensor_name, Helpers::toLower(cmd).c_str(), sizeof(sensor_name));
|
|
||||||
|
|
||||||
// check specific attribute to fetch instead of the complete record
|
|
||||||
char * breakp = strchr(sensor_name, '/');
|
|
||||||
if (breakp) {
|
|
||||||
*breakp = '\0';
|
|
||||||
attribute_s = breakp + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto & sensor : sensors_) {
|
for (const auto & sensor : sensors_) {
|
||||||
if (sensor_name == Helpers::toLower(sensor.name()) || Helpers::atoint(sensor_name) == sensor.gpio()) {
|
// match custom name or sensor GPIO
|
||||||
// add the details
|
if (cmd == Helpers::toLower(sensor.name()) || Helpers::atoint(cmd) == sensor.gpio()) {
|
||||||
addSensorJson(output, sensor);
|
get_value_json(output, sensor);
|
||||||
|
return Command::set_attirbute(output, cmd, attribute_s);
|
||||||
/*
|
|
||||||
// if someone wants gpio numbers
|
|
||||||
char gpio_str[9];
|
|
||||||
snprintf(gpio_str, sizeof(gpio_str), "gpio_%02d", sensor.gpio());
|
|
||||||
output[gpio_str] = sensor.value();
|
|
||||||
*/
|
|
||||||
|
|
||||||
// if we're filtering on an attribute, go find it
|
|
||||||
if (attribute_s) {
|
|
||||||
if (output.containsKey(attribute_s)) {
|
|
||||||
std::string data = output[attribute_s].as<std::string>();
|
|
||||||
output.clear();
|
|
||||||
output["api_data"] = data; // always as a string
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return EMSESP::return_not_found(output, attribute_s, sensor_name); // not found
|
|
||||||
}
|
|
||||||
return true; // found a match, exit
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false; // not found
|
return false; // not found
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnalogSensor::addSensorJson(JsonObject output, const Sensor & sensor) {
|
void AnalogSensor::get_value_json(JsonObject output, const Sensor & sensor) {
|
||||||
output["gpio"] = sensor.gpio();
|
output["gpio"] = sensor.gpio();
|
||||||
output["type"] = F_(number);
|
output["type"] = F_(number);
|
||||||
output["analog"] = FL_(list_sensortype)[sensor.type()];
|
output["analog"] = FL_(list_sensortype)[sensor.type()];
|
||||||
|
|||||||
@@ -171,6 +171,7 @@ class AnalogSensor {
|
|||||||
bool command_setvalue(const char * value, const int8_t gpio);
|
bool command_setvalue(const char * value, const int8_t gpio);
|
||||||
void measure();
|
void measure();
|
||||||
void addSensorJson(JsonObject output, const Sensor & sensor);
|
void addSensorJson(JsonObject output, const Sensor & sensor);
|
||||||
|
void get_value_json(JsonObject output, const Sensor & sensor);
|
||||||
|
|
||||||
std::vector<Sensor> sensors_; // our list of sensors
|
std::vector<Sensor> sensors_; // our list of sensors
|
||||||
|
|
||||||
|
|||||||
@@ -284,6 +284,29 @@ const char * Command::parse_command_string(const char * command, int8_t & id) {
|
|||||||
return command;
|
return command;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check if command contains an attribute
|
||||||
|
const char * Command::get_attribute(const char * cmd) {
|
||||||
|
char * breakp = strchr(cmd, '/');
|
||||||
|
if (breakp) {
|
||||||
|
*breakp = '\0';
|
||||||
|
return breakp + 1;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Command::set_attirbute(JsonObject output, const char * cmd, const char * attribute) {
|
||||||
|
if (attribute == nullptr) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (output.containsKey(attribute)) {
|
||||||
|
std::string data = output[attribute].as<std::string>();
|
||||||
|
output.clear();
|
||||||
|
output["api_data"] = data; // always as a string
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return EMSESP::return_not_found(output, attribute, cmd); // not found
|
||||||
|
}
|
||||||
|
|
||||||
// calls a command directly
|
// calls a command directly
|
||||||
uint8_t Command::call(const uint8_t device_type, const char * cmd, const char * value, const int8_t id) {
|
uint8_t Command::call(const uint8_t device_type, const char * cmd, const char * value, const int8_t id) {
|
||||||
// create a temporary buffer
|
// create a temporary buffer
|
||||||
@@ -297,10 +320,12 @@ uint8_t Command::call(const uint8_t device_type, const char * cmd, const char *
|
|||||||
// 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 0 if the command errored, 1 (TRUE) if ok, 2 if not found, 3 if error or 4 if not allowed
|
// returns 0 if the command errored, 1 (TRUE) if ok, 2 if not found, 3 if error or 4 if not allowed
|
||||||
uint8_t Command::call(const uint8_t device_type, const char * cmd, const char * value, const bool is_admin, const int8_t id, JsonObject output) {
|
uint8_t Command::call(const uint8_t device_type, const char * command, const char * value, const bool is_admin, const int8_t id, JsonObject output) {
|
||||||
if (cmd == nullptr) {
|
if (command == nullptr) {
|
||||||
return CommandRet::NOT_FOUND;
|
return CommandRet::NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
char cmd[COMMAND_MAX_LENGTH];
|
||||||
|
strcpy(cmd, Helpers::toLower(command).c_str());
|
||||||
|
|
||||||
auto dname = EMSdevice::device_type_2_device_name(device_type); // device name, not translated
|
auto dname = EMSdevice::device_type_2_device_name(device_type); // device name, not translated
|
||||||
|
|
||||||
@@ -309,6 +334,9 @@ uint8_t Command::call(const uint8_t device_type, const char * cmd, const char *
|
|||||||
// or a special command like 'info', 'values', 'commands', 'entities' etc
|
// or a special command like 'info', 'values', 'commands', 'entities' etc
|
||||||
bool single_command = (!value || !strlen(value));
|
bool single_command = (!value || !strlen(value));
|
||||||
if (single_command) {
|
if (single_command) {
|
||||||
|
if (!strcmp(cmd, F_(commands))) {
|
||||||
|
return Command::list(device_type, output);
|
||||||
|
}
|
||||||
if (EMSESP::get_device_value_info(output, cmd, id, device_type)) { // entity = cmd
|
if (EMSESP::get_device_value_info(output, cmd, id, device_type)) { // entity = cmd
|
||||||
LOG_DEBUG("Fetched device entity/attributes for %s/%s", dname, cmd);
|
LOG_DEBUG("Fetched device entity/attributes for %s/%s", dname, cmd);
|
||||||
return CommandRet::OK;
|
return CommandRet::OK;
|
||||||
@@ -319,17 +347,14 @@ uint8_t Command::call(const uint8_t device_type, const char * cmd, const char *
|
|||||||
|
|
||||||
// determine flags based on id (which is the tag)
|
// determine flags based on id (which is the tag)
|
||||||
uint8_t flag = CommandFlag::CMD_FLAG_DEFAULT;
|
uint8_t flag = CommandFlag::CMD_FLAG_DEFAULT;
|
||||||
// info and values works with all tags, keep it default
|
if (id >= DeviceValueTAG::TAG_HC1 && id <= DeviceValueTAG::TAG_HC8) {
|
||||||
if (std::string(cmd) != F_(values) && std::string(cmd) != F_(info)) {
|
flag = CommandFlag::CMD_FLAG_HC;
|
||||||
if (id >= DeviceValueTAG::TAG_HC1 && id <= DeviceValueTAG::TAG_HC8) {
|
} else if (id >= DeviceValueTAG::TAG_DHW1 && id <= DeviceValueTAG::TAG_DHW10) {
|
||||||
flag = CommandFlag::CMD_FLAG_HC;
|
flag = CommandFlag::CMD_FLAG_DHW;
|
||||||
} else if (id >= DeviceValueTAG::TAG_DHW1 && id <= DeviceValueTAG::TAG_DHW10) {
|
} else if (id >= DeviceValueTAG::TAG_HS1 && id <= DeviceValueTAG::TAG_HS16) {
|
||||||
flag = CommandFlag::CMD_FLAG_DHW;
|
flag = CommandFlag::CMD_FLAG_HS;
|
||||||
} else if (id >= DeviceValueTAG::TAG_HS1 && id <= DeviceValueTAG::TAG_HS16) {
|
} else if (id >= DeviceValueTAG::TAG_AHS1 && id <= DeviceValueTAG::TAG_AHS1) {
|
||||||
flag = CommandFlag::CMD_FLAG_HS;
|
flag = CommandFlag::CMD_FLAG_AHS;
|
||||||
} else if (id >= DeviceValueTAG::TAG_AHS1 && id <= DeviceValueTAG::TAG_AHS1) {
|
|
||||||
flag = CommandFlag::CMD_FLAG_AHS;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// see if there is a command registered and it's valid
|
// see if there is a command registered and it's valid
|
||||||
@@ -500,15 +525,11 @@ std::string Command::tagged_cmd(const std::string & cmd, const uint8_t flag) {
|
|||||||
|
|
||||||
// list all commands for a specific device, output as json
|
// list all commands for a specific device, output as json
|
||||||
bool Command::list(const uint8_t device_type, JsonObject output) {
|
bool Command::list(const uint8_t device_type, JsonObject output) {
|
||||||
// check of it a 'commands' command
|
// common commands
|
||||||
if (device_type == EMSdevice::DeviceType::TEMPERATURESENSOR || device_type == EMSdevice::DeviceType::ANALOGSENSOR) {
|
output[F_(info)] = Helpers::translated_word(FL_(info_cmd));
|
||||||
output[F_(info)] = Helpers::translated_word(FL_(info_cmd));
|
output[F_(values)] = Helpers::translated_word(FL_(values_cmd));
|
||||||
output[F_(commands)] = Helpers::translated_word(FL_(commands_cmd));
|
output[F_(commands)] = Helpers::translated_word(FL_(commands_cmd));
|
||||||
output[F_(values)] = Helpers::translated_word(FL_(values_cmd));
|
output[F_(entities)] = Helpers::translated_word(FL_(entities_cmd));
|
||||||
} else if (cmdfunctions_.empty()) {
|
|
||||||
output["message"] = "no commands available";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// create a list of commands we have registered, and sort them
|
// create a list of commands we have registered, and sort them
|
||||||
std::list<std::string> sorted_cmds;
|
std::list<std::string> sorted_cmds;
|
||||||
|
|||||||
@@ -135,6 +135,8 @@ class Command {
|
|||||||
static uint8_t process(const char * path, const bool is_admin, const JsonObject input, JsonObject output);
|
static uint8_t process(const char * path, const bool is_admin, const JsonObject input, JsonObject output);
|
||||||
|
|
||||||
static const char * parse_command_string(const char * command, int8_t & id);
|
static const char * parse_command_string(const char * command, int8_t & id);
|
||||||
|
static const char * get_attribute(const char * cmd);
|
||||||
|
static bool set_attirbute(JsonObject output, const char * cmd, const char * attirbute);
|
||||||
|
|
||||||
static const char * return_code_string(const uint8_t return_code);
|
static const char * return_code_string(const uint8_t return_code);
|
||||||
|
|
||||||
|
|||||||
@@ -389,6 +389,7 @@ bool EMSdevice::has_cmd(const char * cmd, const int8_t id) const {
|
|||||||
|
|
||||||
// list of registered device entries
|
// list of registered device entries
|
||||||
// called from the command 'entities'
|
// called from the command 'entities'
|
||||||
|
/*
|
||||||
void EMSdevice::list_device_entries(JsonObject output) const {
|
void EMSdevice::list_device_entries(JsonObject output) const {
|
||||||
for (const auto & dv : devicevalues_) {
|
for (const auto & dv : devicevalues_) {
|
||||||
auto fullname = dv.get_fullname();
|
auto fullname = dv.get_fullname();
|
||||||
@@ -414,6 +415,7 @@ void EMSdevice::list_device_entries(JsonObject output) const {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
// list all the telegram type IDs for this device
|
// list all the telegram type IDs for this device
|
||||||
void EMSdevice::show_telegram_handlers(uuid::console::Shell & shell) const {
|
void EMSdevice::show_telegram_handlers(uuid::console::Shell & shell) const {
|
||||||
@@ -1435,187 +1437,182 @@ void EMSdevice::dump_telegram_info(std::vector<TelegramFunctionDump> & telegram_
|
|||||||
// cmd is the endpoint or name of the device entity
|
// cmd is the endpoint or name of the device entity
|
||||||
// returns false if failed, otherwise true
|
// returns false if failed, otherwise true
|
||||||
bool EMSdevice::get_value_info(JsonObject output, const char * cmd, const int8_t tag) {
|
bool EMSdevice::get_value_info(JsonObject output, const char * cmd, const int8_t tag) {
|
||||||
JsonObject json = output;
|
if (!strcmp(cmd, F_(info))) {
|
||||||
|
return export_values(device_type(), output, tag, EMSdevice::OUTPUT_TARGET::API_VERBOSE);
|
||||||
// make a copy of the string command for parsing
|
}
|
||||||
char command_s[30];
|
if (!strcmp(cmd, F_(values))) {
|
||||||
strlcpy(command_s, cmd, sizeof(command_s));
|
return export_values(device_type(), output, tag, EMSdevice::OUTPUT_TARGET::API_SHORTNAMES);
|
||||||
char * attribute_s = nullptr;
|
}
|
||||||
|
if (!strcmp(cmd, F_(entities))) {
|
||||||
// check specific attribute to fetch instead of the complete record
|
char name[30];
|
||||||
char * breakp = strchr(command_s, '/');
|
for (auto & dv : devicevalues_) {
|
||||||
if (breakp) {
|
if (tag < 0 || tag == dv.tag) {
|
||||||
*breakp = '\0';
|
strlcpy(name, tag < 0 ? tag_to_mqtt(dv.tag) : "", sizeof(name));
|
||||||
attribute_s = breakp + 1;
|
strlcat(name, tag < 0 && dv.tag > 0 ? "." : "", sizeof(name));
|
||||||
|
strlcat(name, dv.short_name, sizeof(name));
|
||||||
|
get_value_json(output[name].to<JsonObject>(), dv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// search device value with this tag
|
// search device value with this tag
|
||||||
|
const char * attribute_s = Command::get_attribute(cmd);
|
||||||
for (auto & dv : devicevalues_) {
|
for (auto & dv : devicevalues_) {
|
||||||
if (Helpers::toLower(command_s) == Helpers::toLower(dv.short_name) && (tag <= 0 || tag == dv.tag)) {
|
if (cmd == Helpers::toLower(dv.short_name) && (tag <= 0 || tag == dv.tag)) {
|
||||||
uint8_t fahrenheit = !EMSESP::system_.fahrenheit() ? 0 : (dv.uom == DeviceValueUOM::DEGREES) ? 2 : (dv.uom == DeviceValueUOM::DEGREES_R) ? 1 : 0;
|
get_value_json(output, dv);
|
||||||
|
|
||||||
const char * type = "type";
|
|
||||||
const char * value = "value";
|
|
||||||
|
|
||||||
json["name"] = dv.short_name;
|
|
||||||
|
|
||||||
auto fullname = dv.get_fullname();
|
|
||||||
if (!fullname.empty()) {
|
|
||||||
json["fullname"] = dv.has_tag() ? fullname + " " + tag_to_string(dv.tag) : fullname; // suffix tag
|
|
||||||
|
|
||||||
// TAG https://github.com/emsesp/EMS-ESP32/issues/1338
|
|
||||||
json["fullname"] = dv.has_tag() ? std::string(tag_to_string(dv.tag)) + " " + fullname.c_str() : fullname; // prefix tag
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dv.tag != DeviceValueTAG::TAG_NONE) {
|
|
||||||
json["circuit"] = tag_to_mqtt(dv.tag);
|
|
||||||
}
|
|
||||||
|
|
||||||
char val[10];
|
|
||||||
switch (dv.type) {
|
|
||||||
case DeviceValueType::ENUM: {
|
|
||||||
if (*(uint8_t *)(dv.value_p) < dv.options_size) {
|
|
||||||
if (EMSESP::system_.enum_format() == ENUM_FORMAT_INDEX) {
|
|
||||||
json[value] = (uint8_t)(*(uint8_t *)(dv.value_p));
|
|
||||||
} else {
|
|
||||||
json[value] = Helpers::translated_word(dv.options[*(uint8_t *)(dv.value_p)]); // text
|
|
||||||
}
|
|
||||||
}
|
|
||||||
json[type] = F_(enum);
|
|
||||||
JsonArray enum_ = json[F_(enum)].to<JsonArray>();
|
|
||||||
for (uint8_t i = 0; i < dv.options_size; i++) {
|
|
||||||
enum_.add(Helpers::translated_word(dv.options[i]));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case DeviceValueType::UINT16:
|
|
||||||
if (Helpers::hasValue(*(uint16_t *)(dv.value_p))) {
|
|
||||||
json[value] = serialized(Helpers::render_value(val, *(uint16_t *)(dv.value_p), dv.numeric_operator, fahrenheit));
|
|
||||||
}
|
|
||||||
json[type] = F_(number);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DeviceValueType::UINT8:
|
|
||||||
if (Helpers::hasValue(*(uint8_t *)(dv.value_p))) {
|
|
||||||
json[value] = serialized(Helpers::render_value(val, *(uint8_t *)(dv.value_p), dv.numeric_operator, fahrenheit));
|
|
||||||
}
|
|
||||||
json[type] = F_(number);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DeviceValueType::INT16:
|
|
||||||
if (Helpers::hasValue(*(int16_t *)(dv.value_p))) {
|
|
||||||
json[value] = serialized(Helpers::render_value(val, *(int16_t *)(dv.value_p), dv.numeric_operator, fahrenheit));
|
|
||||||
}
|
|
||||||
json[type] = F_(number);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DeviceValueType::INT8:
|
|
||||||
if (Helpers::hasValue(*(int8_t *)(dv.value_p))) {
|
|
||||||
json[value] = serialized(Helpers::render_value(val, *(int8_t *)(dv.value_p), dv.numeric_operator, fahrenheit));
|
|
||||||
}
|
|
||||||
json[type] = F_(number);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DeviceValueType::UINT24:
|
|
||||||
case DeviceValueType::UINT32:
|
|
||||||
if (Helpers::hasValue(*(uint32_t *)(dv.value_p))) {
|
|
||||||
json[value] = serialized(Helpers::render_value(val, *(uint32_t *)(dv.value_p), dv.numeric_operator));
|
|
||||||
}
|
|
||||||
json[type] = F_(number);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DeviceValueType::BOOL:
|
|
||||||
if (Helpers::hasValue(*(uint8_t *)(dv.value_p), EMS_VALUE_BOOL)) {
|
|
||||||
auto value_b = (bool)*(uint8_t *)(dv.value_p);
|
|
||||||
if (EMSESP::system_.bool_format() == BOOL_FORMAT_TRUEFALSE) {
|
|
||||||
json[value] = value_b;
|
|
||||||
} else if (EMSESP::system_.bool_format() == BOOL_FORMAT_10) {
|
|
||||||
json[value] = value_b ? 1 : 0;
|
|
||||||
} else {
|
|
||||||
char s[12];
|
|
||||||
json[value] = Helpers::render_boolean(s, value_b);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
json[type] = ("boolean");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DeviceValueType::TIME:
|
|
||||||
if (Helpers::hasValue(*(uint32_t *)(dv.value_p))) {
|
|
||||||
json[value] = serialized(Helpers::render_value(val, *(uint32_t *)(dv.value_p), dv.numeric_operator));
|
|
||||||
}
|
|
||||||
json[type] = F_(number);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DeviceValueType::STRING:
|
|
||||||
if (Helpers::hasValue((char *)(dv.value_p))) {
|
|
||||||
json[value] = (char *)(dv.value_p);
|
|
||||||
}
|
|
||||||
json[type] = ("string");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DeviceValueType::CMD:
|
|
||||||
if (dv.options_size > 1) {
|
|
||||||
json[type] = F_(enum);
|
|
||||||
JsonArray enum_ = json[F_(enum)].to<JsonArray>();
|
|
||||||
for (uint8_t i = 0; i < dv.options_size; i++) {
|
|
||||||
enum_.add(Helpers::translated_word(dv.options[i]));
|
|
||||||
}
|
|
||||||
} else if (dv.uom != DeviceValueUOM::NONE) {
|
|
||||||
json[type] = F_(number);
|
|
||||||
} else {
|
|
||||||
json[type] = F_(command);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
json[type] = Helpers::translated_word(FL_(unknown));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// set the min and max only for commands
|
|
||||||
if (dv.has_cmd) {
|
|
||||||
int16_t dv_set_min;
|
|
||||||
uint32_t dv_set_max;
|
|
||||||
if (dv.get_min_max(dv_set_min, dv_set_max)) {
|
|
||||||
json["min"] = dv_set_min;
|
|
||||||
json["max"] = dv_set_max;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// add uom if it's not a " " (single space)
|
|
||||||
if (dv.uom != DeviceValueUOM::NONE) {
|
|
||||||
json["uom"] = uom_to_string(dv.uom);
|
|
||||||
}
|
|
||||||
|
|
||||||
json["readable"] = !dv.has_state(DeviceValueState::DV_API_MQTT_EXCLUDE);
|
|
||||||
json["writeable"] = dv.has_cmd && !dv.has_state(DeviceValueState::DV_READONLY);
|
|
||||||
json["visible"] = !dv.has_state(DeviceValueState::DV_WEB_EXCLUDE);
|
|
||||||
|
|
||||||
// TODO refactor to remove containsKey as it's costly and not advisable to use it
|
|
||||||
// https://arduinojson.org/v7/api/jsonobject/containskey/#avoid
|
|
||||||
|
|
||||||
// commented out, leads to issues if type is set to number
|
|
||||||
// if there is no value, mention it
|
|
||||||
// if (!json.containsKey(value)) {
|
|
||||||
// json[value] = "not set";
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if we're filtering on an attribute, go find it
|
// if we're filtering on an attribute, go find it
|
||||||
if (attribute_s) {
|
return Command::set_attirbute(output, cmd, attribute_s);
|
||||||
if (json.containsKey(attribute_s)) {
|
}
|
||||||
std::string data = json[attribute_s].as<std::string>();
|
}
|
||||||
output.clear();
|
return false; // not found, but don't return a message error yet
|
||||||
output["api_data"] = data; // always as string
|
}
|
||||||
return true;
|
|
||||||
}
|
// build the json for a specific entity
|
||||||
return EMSESP::return_not_found(output, attribute_s, command_s); // not found
|
void EMSdevice::get_value_json(JsonObject json, DeviceValue & dv) {
|
||||||
|
uint8_t fahrenheit = !EMSESP::system_.fahrenheit() ? 0 : (dv.uom == DeviceValueUOM::DEGREES) ? 2 : (dv.uom == DeviceValueUOM::DEGREES_R) ? 1 : 0;
|
||||||
|
|
||||||
|
const char * type = "type";
|
||||||
|
const char * value = "value";
|
||||||
|
|
||||||
|
json["name"] = dv.short_name;
|
||||||
|
|
||||||
|
auto fullname = dv.get_fullname();
|
||||||
|
if (!fullname.empty()) {
|
||||||
|
json["fullname"] = dv.has_tag() ? fullname + " " + tag_to_string(dv.tag) : fullname; // suffix tag
|
||||||
|
|
||||||
|
// TAG https://github.com/emsesp/EMS-ESP32/issues/1338
|
||||||
|
json["fullname"] = dv.has_tag() ? std::string(tag_to_string(dv.tag)) + " " + fullname.c_str() : fullname; // prefix tag
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dv.tag != DeviceValueTAG::TAG_NONE) {
|
||||||
|
json["circuit"] = tag_to_mqtt(dv.tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
char val[10];
|
||||||
|
switch (dv.type) {
|
||||||
|
case DeviceValueType::ENUM: {
|
||||||
|
if (*(uint8_t *)(dv.value_p) < dv.options_size) {
|
||||||
|
json["index"] = (uint8_t)(*(uint8_t *)(dv.value_p));
|
||||||
|
json["enum"] = Helpers::translated_word(dv.options[*(uint8_t *)(dv.value_p)]); // text
|
||||||
|
if (EMSESP::system_.enum_format() == ENUM_FORMAT_INDEX) {
|
||||||
|
json[value] = (uint8_t)(*(uint8_t *)(dv.value_p));
|
||||||
|
} else {
|
||||||
|
json[value] = Helpers::translated_word(dv.options[*(uint8_t *)(dv.value_p)]); // text
|
||||||
}
|
}
|
||||||
return true;
|
}
|
||||||
|
json[type] = F_(enum);
|
||||||
|
JsonArray enum_ = json[F_(enum)].to<JsonArray>();
|
||||||
|
for (uint8_t i = 0; i < dv.options_size; i++) {
|
||||||
|
enum_.add(Helpers::translated_word(dv.options[i]));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case DeviceValueType::UINT16:
|
||||||
|
if (Helpers::hasValue(*(uint16_t *)(dv.value_p))) {
|
||||||
|
json[value] = serialized(Helpers::render_value(val, *(uint16_t *)(dv.value_p), dv.numeric_operator, fahrenheit));
|
||||||
|
}
|
||||||
|
json[type] = F_(number);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DeviceValueType::UINT8:
|
||||||
|
if (Helpers::hasValue(*(uint8_t *)(dv.value_p))) {
|
||||||
|
json[value] = serialized(Helpers::render_value(val, *(uint8_t *)(dv.value_p), dv.numeric_operator, fahrenheit));
|
||||||
|
}
|
||||||
|
json[type] = F_(number);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DeviceValueType::INT16:
|
||||||
|
if (Helpers::hasValue(*(int16_t *)(dv.value_p))) {
|
||||||
|
json[value] = serialized(Helpers::render_value(val, *(int16_t *)(dv.value_p), dv.numeric_operator, fahrenheit));
|
||||||
|
}
|
||||||
|
json[type] = F_(number);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DeviceValueType::INT8:
|
||||||
|
if (Helpers::hasValue(*(int8_t *)(dv.value_p))) {
|
||||||
|
json[value] = serialized(Helpers::render_value(val, *(int8_t *)(dv.value_p), dv.numeric_operator, fahrenheit));
|
||||||
|
}
|
||||||
|
json[type] = F_(number);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DeviceValueType::UINT24:
|
||||||
|
case DeviceValueType::UINT32:
|
||||||
|
if (Helpers::hasValue(*(uint32_t *)(dv.value_p))) {
|
||||||
|
json[value] = serialized(Helpers::render_value(val, *(uint32_t *)(dv.value_p), dv.numeric_operator));
|
||||||
|
}
|
||||||
|
json[type] = F_(number);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DeviceValueType::BOOL:
|
||||||
|
if (Helpers::hasValue(*(uint8_t *)(dv.value_p), EMS_VALUE_BOOL)) {
|
||||||
|
auto value_b = (bool)*(uint8_t *)(dv.value_p);
|
||||||
|
json["bool"] = value_b;
|
||||||
|
json["index"] = value_b ? 1 : 0;
|
||||||
|
if (EMSESP::system_.bool_format() == BOOL_FORMAT_TRUEFALSE) {
|
||||||
|
json[value] = value_b;
|
||||||
|
} else if (EMSESP::system_.bool_format() == BOOL_FORMAT_10) {
|
||||||
|
json[value] = value_b ? 1 : 0;
|
||||||
|
} else {
|
||||||
|
char s[12];
|
||||||
|
json[value] = Helpers::render_boolean(s, value_b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
json[type] = ("boolean");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DeviceValueType::TIME:
|
||||||
|
if (Helpers::hasValue(*(uint32_t *)(dv.value_p))) {
|
||||||
|
json[value] = serialized(Helpers::render_value(val, *(uint32_t *)(dv.value_p), dv.numeric_operator));
|
||||||
|
}
|
||||||
|
json[type] = F_(number);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DeviceValueType::STRING:
|
||||||
|
if (Helpers::hasValue((char *)(dv.value_p))) {
|
||||||
|
json[value] = (char *)(dv.value_p);
|
||||||
|
}
|
||||||
|
json[type] = ("string");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DeviceValueType::CMD:
|
||||||
|
if (dv.options_size > 1) {
|
||||||
|
json[type] = F_(enum);
|
||||||
|
JsonArray enum_ = json[F_(enum)].to<JsonArray>();
|
||||||
|
for (uint8_t i = 0; i < dv.options_size; i++) {
|
||||||
|
enum_.add(Helpers::translated_word(dv.options[i]));
|
||||||
|
}
|
||||||
|
} else if (dv.uom != DeviceValueUOM::NONE) {
|
||||||
|
json[type] = F_(number);
|
||||||
|
} else {
|
||||||
|
json[type] = F_(command);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
json[type] = Helpers::translated_word(FL_(unknown));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set the min and max only for commands
|
||||||
|
if (dv.has_cmd) {
|
||||||
|
int16_t dv_set_min;
|
||||||
|
uint32_t dv_set_max;
|
||||||
|
if (dv.get_min_max(dv_set_min, dv_set_max)) {
|
||||||
|
json["min"] = dv_set_min;
|
||||||
|
json["max"] = dv_set_max;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false; // not found, but don't return a message error yet
|
// add uom if it's not a " " (single space)
|
||||||
|
if (dv.uom != DeviceValueUOM::NONE) {
|
||||||
|
json["uom"] = uom_to_string(dv.uom);
|
||||||
|
}
|
||||||
|
|
||||||
|
json["readable"] = !dv.has_state(DeviceValueState::DV_API_MQTT_EXCLUDE);
|
||||||
|
json["writeable"] = dv.has_cmd && !dv.has_state(DeviceValueState::DV_READONLY);
|
||||||
|
json["visible"] = !dv.has_state(DeviceValueState::DV_WEB_EXCLUDE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// mqtt publish all single values from one device (used for time schedule)
|
// mqtt publish all single values from one device (used for time schedule)
|
||||||
|
|||||||
@@ -214,7 +214,7 @@ class EMSdevice {
|
|||||||
void show_telegram_handlers(uuid::console::Shell & shell) const;
|
void show_telegram_handlers(uuid::console::Shell & shell) const;
|
||||||
char * show_telegram_handlers(char * result, const size_t len, const uint8_t handlers);
|
char * show_telegram_handlers(char * result, const size_t len, const uint8_t handlers);
|
||||||
void show_mqtt_handlers(uuid::console::Shell & shell) const;
|
void show_mqtt_handlers(uuid::console::Shell & shell) const;
|
||||||
void list_device_entries(JsonObject output) const;
|
// void list_device_entries(JsonObject output) const;
|
||||||
void add_handlers_ignored(const uint16_t handler);
|
void add_handlers_ignored(const uint16_t handler);
|
||||||
|
|
||||||
void set_climate_minmax(int8_t tag, int16_t min, uint32_t max);
|
void set_climate_minmax(int8_t tag, int16_t min, uint32_t max);
|
||||||
@@ -227,6 +227,7 @@ class EMSdevice {
|
|||||||
std::string get_value_uom(const std::string & shortname) const;
|
std::string get_value_uom(const std::string & shortname) const;
|
||||||
|
|
||||||
bool get_value_info(JsonObject root, const char * cmd, const int8_t id);
|
bool get_value_info(JsonObject root, const char * cmd, const int8_t id);
|
||||||
|
void get_value_json(JsonObject output, DeviceValue & dv);
|
||||||
void get_dv_info(JsonObject json);
|
void get_dv_info(JsonObject json);
|
||||||
|
|
||||||
enum OUTPUT_TARGET : uint8_t { API_VERBOSE, API_SHORTNAMES, MQTT, CONSOLE };
|
enum OUTPUT_TARGET : uint8_t { API_VERBOSE, API_SHORTNAMES, MQTT, CONSOLE };
|
||||||
@@ -353,8 +354,7 @@ class EMSdevice {
|
|||||||
ANALOGSENSOR, // for internal analog sensors
|
ANALOGSENSOR, // for internal analog sensors
|
||||||
SCHEDULER, // for internal schedule
|
SCHEDULER, // for internal schedule
|
||||||
CUSTOM, // for user defined entities
|
CUSTOM, // for user defined entities
|
||||||
|
BOILER, // frome here on enum the ems-devices
|
||||||
BOILER,
|
|
||||||
THERMOSTAT,
|
THERMOSTAT,
|
||||||
MIXER,
|
MIXER,
|
||||||
SOLAR,
|
SOLAR,
|
||||||
|
|||||||
@@ -1343,38 +1343,12 @@ bool EMSESP::add_device(const uint8_t device_id, const uint8_t product_id, const
|
|||||||
// Print to LOG showing we've added a new device
|
// Print to LOG showing we've added a new device
|
||||||
LOG_INFO("Recognized new %s with deviceID 0x%02X", EMSdevice::device_type_2_device_name(device_type), device_id);
|
LOG_INFO("Recognized new %s with deviceID 0x%02X", EMSdevice::device_type_2_device_name(device_type), device_id);
|
||||||
|
|
||||||
// add commands 'info', 'commands', 'values', 'entities' for all EMS devices
|
// register the MQTT subscribe topic for this device
|
||||||
// and register the MQTT subscribe topic for this device
|
|
||||||
// except for connect, controller and gateway
|
// except for connect, controller and gateway
|
||||||
if ((device_type == DeviceType::CONNECT) || (device_type == DeviceType::CONTROLLER) || (device_type == DeviceType::GATEWAY)) {
|
if ((device_type == DeviceType::CONNECT) || (device_type == DeviceType::CONTROLLER) || (device_type == DeviceType::GATEWAY)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Command::add(
|
|
||||||
device_type,
|
|
||||||
F_(info),
|
|
||||||
[device_type](const char * value, const int8_t id, JsonObject output) {
|
|
||||||
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 EMSdevice::export_values(device_type, output, id, EMSdevice::OUTPUT_TARGET::API_SHORTNAMES);
|
|
||||||
},
|
|
||||||
FL_(values_cmd));
|
|
||||||
Command::add(
|
|
||||||
device_type,
|
|
||||||
F_(commands),
|
|
||||||
[device_type](const char * value, const int8_t id, JsonObject output) { return command_commands(device_type, output, id); },
|
|
||||||
FL_(commands_cmd));
|
|
||||||
Command::add(
|
|
||||||
device_type,
|
|
||||||
F_(entities),
|
|
||||||
[device_type](const char * value, const int8_t id, JsonObject output) { return command_entities(device_type, output, id); },
|
|
||||||
FL_(entities_cmd));
|
|
||||||
|
|
||||||
// MQTT subscribe to the device e.g. "ems-esp/boiler/#"
|
// MQTT subscribe to the device e.g. "ems-esp/boiler/#"
|
||||||
auto topic = std::string(EMSdevice::device_type_2_device_name(device_type)) + "/#";
|
auto topic = std::string(EMSdevice::device_type_2_device_name(device_type)) + "/#";
|
||||||
Mqtt::subscribe(device_type, topic, nullptr);
|
Mqtt::subscribe(device_type, topic, nullptr);
|
||||||
@@ -1382,25 +1356,6 @@ bool EMSESP::add_device(const uint8_t device_id, const uint8_t product_id, const
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// list device entities
|
|
||||||
bool EMSESP::command_entities(uint8_t device_type, JsonObject output, const int8_t id) {
|
|
||||||
JsonObject node;
|
|
||||||
|
|
||||||
for (const auto & emsdevice : emsdevices) {
|
|
||||||
if (emsdevice && (emsdevice->device_type() == device_type)) {
|
|
||||||
emsdevice->list_device_entries(output);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// list all available commands, return as json
|
|
||||||
bool EMSESP::command_commands(uint8_t device_type, JsonObject output, const int8_t id) {
|
|
||||||
return Command::list(device_type, output);
|
|
||||||
}
|
|
||||||
|
|
||||||
// send a read request, passing it into to the Tx Service, with optional offset and length
|
// 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) {
|
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);
|
txservice_.read_request(type_id, dest, offset, length, front);
|
||||||
|
|||||||
@@ -251,8 +251,6 @@ class EMSESP {
|
|||||||
static void process_version(std::shared_ptr<const Telegram> telegram);
|
static void process_version(std::shared_ptr<const Telegram> telegram);
|
||||||
static void publish_response(std::shared_ptr<const Telegram> telegram);
|
static void publish_response(std::shared_ptr<const Telegram> telegram);
|
||||||
static void publish_all_loop();
|
static void publish_all_loop();
|
||||||
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);
|
|
||||||
|
|
||||||
static constexpr uint32_t EMS_FETCH_FREQUENCY = 60000; // check every minute
|
static constexpr uint32_t EMS_FETCH_FREQUENCY = 60000; // check every minute
|
||||||
static constexpr uint8_t EMS_WAIT_KM_TIMEOUT = 60; // wait one minute
|
static constexpr uint8_t EMS_WAIT_KM_TIMEOUT = 60; // wait one minute
|
||||||
|
|||||||
103
src/system.cpp
103
src/system.cpp
@@ -848,8 +848,6 @@ void System::commands_init() {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// these commands will return data in JSON format
|
// these commands will return data in JSON format
|
||||||
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("response"), System::command_response, FL_(commands_response));
|
||||||
Command::add(EMSdevice::DeviceType::SYSTEM, F("allvalues"), System::command_allvalues, FL_(allvalues_cmd));
|
Command::add(EMSdevice::DeviceType::SYSTEM, F("allvalues"), System::command_allvalues, FL_(allvalues_cmd));
|
||||||
|
|
||||||
@@ -1249,11 +1247,6 @@ bool System::check_upgrade(bool factory_settings) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// list commands
|
|
||||||
bool System::command_commands(const char * value, const int8_t id, JsonObject output) {
|
|
||||||
return Command::list(EMSdevice::DeviceType::SYSTEM, output);
|
|
||||||
}
|
|
||||||
|
|
||||||
// convert settings file into json object
|
// convert settings file into json object
|
||||||
void System::extractSettings(const char * filename, const char * section, JsonObject output) {
|
void System::extractSettings(const char * filename, const char * section, JsonObject output) {
|
||||||
#ifndef EMSESP_STANDALONE
|
#ifndef EMSESP_STANDALONE
|
||||||
@@ -1291,27 +1284,41 @@ bool System::saveSettings(const char * filename, const char * section, JsonObjec
|
|||||||
}
|
}
|
||||||
|
|
||||||
// return back a system value
|
// return back a system value
|
||||||
bool System::get_value_info(JsonObject root, const char * command) {
|
bool System::get_value_info(JsonObject output, const char * cmd) {
|
||||||
if (command == nullptr || strlen(command) == 0) {
|
if (cmd == nullptr || strlen(cmd) == 0) {
|
||||||
LOG_ERROR("empty system command");
|
LOG_ERROR("empty system command");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// cmd is lower case of the command
|
// check for hardcoded "info"/"value"
|
||||||
char cmd[COMMAND_MAX_LENGTH];
|
if (!strcmp(cmd, F_(info)) || !strcmp(cmd, F_(value))) {
|
||||||
strlcpy(cmd, Helpers::toLower(command).c_str(), sizeof(cmd));
|
return command_info("", 0, output);
|
||||||
|
}
|
||||||
|
|
||||||
// fetch all the data from the system
|
// fetch all the data from the system in a different json
|
||||||
|
JsonDocument doc;
|
||||||
|
JsonObject root = doc.to<JsonObject>();
|
||||||
(void)command_info("", 0, root);
|
(void)command_info("", 0, root);
|
||||||
|
|
||||||
// check for hardcoded "info"
|
// list all entities
|
||||||
if (!strcmp(cmd, F_(info)) || !strcmp(cmd, F_(value))) {
|
if (!strcmp(cmd, F_(entities))) {
|
||||||
|
for (JsonPair p : root) {
|
||||||
|
if (p.value().is<JsonObject>()) {
|
||||||
|
// String prefix = p.key().c_str();
|
||||||
|
for (JsonPair p1 : p.value().as<JsonObject>()) {
|
||||||
|
JsonObject entity = output[String(p.key().c_str()) + '.' + p1.key().c_str()].to<JsonObject>();
|
||||||
|
get_value_json(entity, p.key().c_str(), p1.key().c_str(), p1.value());
|
||||||
|
}
|
||||||
|
} // else { // we don't have pairs in json root object
|
||||||
|
// get_value_json(entity, "", p.key().c_str(), p.value());
|
||||||
|
// }
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
char * val = strstr(cmd, "/value");
|
char * val = strstr(cmd, "/value");
|
||||||
if (val) {
|
if (val) {
|
||||||
val[0] = '\0';
|
*val = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
char * slash = strchr(cmd, '/');
|
char * slash = strchr(cmd, '/');
|
||||||
@@ -1320,40 +1327,58 @@ bool System::get_value_info(JsonObject root, const char * command) {
|
|||||||
slash++;
|
slash++;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string s;
|
// list values for a jsonObject in system, e.g. /api/system/network
|
||||||
|
if (!slash || !strcmp(slash, F_(info)) || !strcmp(slash, F_(values))) {
|
||||||
|
for (JsonPair p : root) {
|
||||||
|
if (Helpers::toLower(p.key().c_str()) == cmd && p.value().is<JsonObject>()) {
|
||||||
|
for (JsonPair p1 : p.value().as<JsonObject>()) {
|
||||||
|
output[p1.key().c_str()] = p1.value().as<std::string>();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// value info or api_data for a single value
|
||||||
// Loop through all the key-value pairs in root to find the key, case independent
|
// Loop through all the key-value pairs in root to find the key, case independent
|
||||||
if (slash) { // search the top level first
|
if (slash) { // search the top level first
|
||||||
for (JsonPair p : root) {
|
for (JsonPair p : root) {
|
||||||
if (p.value().is<JsonObject>() && Helpers::toLower(p.key().c_str()) == cmd) {
|
if (p.value().is<JsonObject>() && Helpers::toLower(p.key().c_str()) == cmd) {
|
||||||
for (JsonPair p1 : p.value().as<JsonObject>()) {
|
for (JsonPair p1 : p.value().as<JsonObject>()) {
|
||||||
if (Helpers::toLower(p1.key().c_str()) == slash && !p1.value().is<JsonObject>()) {
|
if (Helpers::toLower(p1.key().c_str()) == slash && !p1.value().is<JsonObject>()) {
|
||||||
s = p1.value().as<std::string>();
|
if (val) {
|
||||||
break;
|
output["api_data"] = p1.value().as<std::string>();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
get_value_json(output, p.key().c_str(), p1.key().c_str(), p1.value());
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} // else skipt, but we don't have value pairs in system root
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void System::get_value_json(JsonObject output, const std::string & circuit, const std::string & name, JsonVariant val) {
|
||||||
|
output["name"] = name;
|
||||||
|
if (circuit.length()) {
|
||||||
|
output["circuit"] = circuit;
|
||||||
|
}
|
||||||
|
output["readable"] = true;
|
||||||
|
output["writable"] = false;
|
||||||
|
output["visible"] = true;
|
||||||
|
if (val.is<bool>()) {
|
||||||
|
output["value"] = val.as<bool>();
|
||||||
|
output["type"] = "boolean";
|
||||||
|
} else if (val.is<String>() || val.is<const char *>() || val.is<std::string>()) {
|
||||||
|
output["value"] = val.as<std::string>();
|
||||||
|
output["type"] = "string";
|
||||||
} else {
|
} else {
|
||||||
for (JsonPair p : root) {
|
output["value"] = val.as<float>();
|
||||||
if (Helpers::toLower(p.key().c_str()) == cmd && !p.value().is<JsonObject>()) {
|
output["type"] = "number";
|
||||||
s = p.value().as<std::string>();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
root.clear(); // clear json, we only one a single value
|
|
||||||
|
|
||||||
if (!s.empty()) {
|
|
||||||
if (val) {
|
|
||||||
root["api_data"] = s;
|
|
||||||
} else {
|
|
||||||
root["value"] = s;
|
|
||||||
}
|
|
||||||
return true; // found
|
|
||||||
}
|
|
||||||
|
|
||||||
return false; // not found
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// export status information including the device information
|
// export status information including the device information
|
||||||
|
|||||||
@@ -59,10 +59,10 @@ class System {
|
|||||||
static bool command_watch(const char * value, const int8_t id);
|
static bool command_watch(const char * value, const int8_t id);
|
||||||
static bool command_message(const char * value, const int8_t id);
|
static bool command_message(const char * value, const int8_t id);
|
||||||
static bool command_info(const char * value, const int8_t id, JsonObject output);
|
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_response(const char * value, const int8_t id, JsonObject output);
|
||||||
static bool command_allvalues(const char * value, const int8_t id, JsonObject output);
|
static bool command_allvalues(const char * value, const int8_t id, JsonObject output);
|
||||||
static bool get_value_info(JsonObject root, const char * cmd);
|
static bool get_value_info(JsonObject root, const char * cmd);
|
||||||
|
static void get_value_json(JsonObject output, const std::string & circuit, const std::string & name, JsonVariant val);
|
||||||
|
|
||||||
#if defined(EMSESP_TEST)
|
#if defined(EMSESP_TEST)
|
||||||
static bool command_test(const char * value, const int8_t id);
|
static bool command_test(const char * value, const int8_t id);
|
||||||
|
|||||||
@@ -343,75 +343,43 @@ bool TemperatureSensor::updated_values() {
|
|||||||
|
|
||||||
// called from emsesp.cpp for commands
|
// called from emsesp.cpp for commands
|
||||||
bool TemperatureSensor::get_value_info(JsonObject output, const char * cmd, const int8_t id) {
|
bool TemperatureSensor::get_value_info(JsonObject output, const char * cmd, const int8_t id) {
|
||||||
// check of it a 'commands' command
|
|
||||||
if (Helpers::toLower(cmd) == F_(commands)) {
|
|
||||||
return Command::list(EMSdevice::DeviceType::TEMPERATURESENSOR, output);
|
|
||||||
}
|
|
||||||
|
|
||||||
// return empty json if there are no sensors
|
// return empty json if there are no sensors
|
||||||
if (sensors_.empty()) {
|
if (sensors_.empty()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t show_all = 0;
|
if (!strcmp(cmd, F_(info)) || !strcmp(cmd, F_(values))) {
|
||||||
if (Helpers::hasValue(cmd)) {
|
|
||||||
show_all = (strncmp(cmd, F_(info), 4) == 0) ? 1 : (strncmp(cmd, F_(values), 6) == 0) ? 2 : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// see if we're showing all sensors
|
|
||||||
if (show_all) {
|
|
||||||
for (const auto & sensor : sensors_) {
|
for (const auto & sensor : sensors_) {
|
||||||
if (show_all == 1) {
|
if (Helpers::hasValue(sensor.temperature_c)) {
|
||||||
// info
|
char val[10];
|
||||||
JsonObject dataSensor = output[sensor.name()].to<JsonObject>();
|
output[sensor.name()] = serialized(Helpers::render_value(val, sensor.temperature_c, 10, EMSESP::system_.fahrenheit() ? 2 : 0));
|
||||||
addSensorJson(dataSensor, sensor);
|
|
||||||
} else {
|
|
||||||
// values, shortname version. Also used in 'system allvalues'
|
|
||||||
if (Helpers::hasValue(sensor.temperature_c)) {
|
|
||||||
char val[10];
|
|
||||||
output[sensor.name()] = serialized(Helpers::render_value(val, sensor.temperature_c, 10, EMSESP::system_.fahrenheit() ? 2 : 0));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// this is for a specific sensor
|
if (!strcmp(cmd, F_(entities))) {
|
||||||
// make a copy of the string command for parsing, and lowercase it
|
for (const auto & sensor : sensors_) {
|
||||||
char sensor_name[COMMAND_MAX_LENGTH] = {'\0'};
|
get_value_json(output[sensor.name()].to<JsonObject>(), sensor);
|
||||||
char * attribute_s = nullptr;
|
}
|
||||||
strlcpy(sensor_name, Helpers::toLower(cmd).c_str(), sizeof(sensor_name));
|
return true;
|
||||||
|
|
||||||
// check for a specific attribute to fetch instead of the complete record
|
|
||||||
char * breakp = strchr(sensor_name, '/');
|
|
||||||
if (breakp) {
|
|
||||||
*breakp = '\0';
|
|
||||||
attribute_s = breakp + 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// this is for a specific sensor
|
||||||
|
const char * attribute_s = Command::get_attribute(cmd);
|
||||||
|
|
||||||
for (const auto & sensor : sensors_) {
|
for (const auto & sensor : sensors_) {
|
||||||
// match custom name or sensor ID
|
// match custom name or sensor ID
|
||||||
if (sensor_name == Helpers::toLower(sensor.name()) || sensor_name == Helpers::toLower(sensor.id())) {
|
if (cmd == Helpers::toLower(sensor.name()) || cmd == Helpers::toLower(sensor.id())) {
|
||||||
// add all the data elements
|
get_value_json(output, sensor);
|
||||||
addSensorJson(output, sensor);
|
return Command::set_attirbute(output, cmd, attribute_s);
|
||||||
// if we're filtering on an attribute, go find it
|
|
||||||
if (attribute_s) {
|
|
||||||
if (output.containsKey(attribute_s)) {
|
|
||||||
std::string data = output[attribute_s].as<std::string>();
|
|
||||||
output.clear();
|
|
||||||
output["api_data"] = data; // always as string
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return EMSESP::return_not_found(output, attribute_s, sensor_name); // not found
|
|
||||||
}
|
|
||||||
return true; // found a match, exit
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false; // not found
|
return false; // not found
|
||||||
}
|
}
|
||||||
|
|
||||||
void TemperatureSensor::addSensorJson(JsonObject output, const Sensor & sensor) {
|
void TemperatureSensor::get_value_json(JsonObject output, const Sensor & sensor) {
|
||||||
output["id"] = sensor.id();
|
output["id"] = sensor.id();
|
||||||
output["name"] = sensor.name();
|
output["name"] = sensor.name();
|
||||||
if (Helpers::hasValue(sensor.temperature_c)) {
|
if (Helpers::hasValue(sensor.temperature_c)) {
|
||||||
|
|||||||
@@ -151,8 +151,8 @@ class TemperatureSensor {
|
|||||||
bool temperature_convert_complete();
|
bool temperature_convert_complete();
|
||||||
int16_t get_temperature_c(const uint8_t addr[]);
|
int16_t get_temperature_c(const uint8_t addr[]);
|
||||||
uint64_t get_id(const uint8_t addr[]);
|
uint64_t get_id(const uint8_t addr[]);
|
||||||
|
void get_value_json(JsonObject output, const Sensor & sensor);
|
||||||
void remove_ha_topic(const std::string & id);
|
void remove_ha_topic(const std::string & id);
|
||||||
void addSensorJson(JsonObject output, const Sensor & sensor);
|
|
||||||
|
|
||||||
std::vector<Sensor> sensors_; // our list of active sensors
|
std::vector<Sensor> sensors_; // our list of active sensors
|
||||||
|
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
#define EMSESP_APP_VERSION "3.7.0-dev.28"
|
#define EMSESP_APP_VERSION "3.7.0-dev.29"
|
||||||
|
|||||||
@@ -256,20 +256,6 @@ void WebCustomEntityService::show_values(JsonObject output) {
|
|||||||
|
|
||||||
// process json output for info/commands and value_info
|
// process json output for info/commands and value_info
|
||||||
bool WebCustomEntityService::get_value_info(JsonObject output, const char * cmd) {
|
bool WebCustomEntityService::get_value_info(JsonObject output, const char * cmd) {
|
||||||
// check of it a 'commands' command
|
|
||||||
if (Helpers::toLower(cmd) == F_(commands)) {
|
|
||||||
output[F_(info)] = Helpers::translated_word(FL_(info_cmd));
|
|
||||||
output[F_(commands)] = Helpers::translated_word(FL_(commands_cmd));
|
|
||||||
output[F_(values)] = Helpers::translated_word(FL_(values_cmd));
|
|
||||||
|
|
||||||
for (const auto & entity : *customEntityItems_) {
|
|
||||||
if (entity.writeable) {
|
|
||||||
output[entity.name] = "custom entity";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if no custom entries, return empty json
|
// if no custom entries, return empty json
|
||||||
// even if we're looking for a specific entity
|
// even if we're looking for a specific entity
|
||||||
// https://github.com/emsesp/EMS-ESP32/issues/1297
|
// https://github.com/emsesp/EMS-ESP32/issues/1297
|
||||||
@@ -278,7 +264,7 @@ bool WebCustomEntityService::get_value_info(JsonObject output, const char * cmd)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// if it's info or values...
|
// if it's info or values...
|
||||||
if (strlen(cmd) == 0 || Helpers::toLower(cmd) == F_(values) || Helpers::toLower(cmd) == F_(info)) {
|
if (!strlen(cmd) || !strcmp(cmd, F_(values)) || !strcmp(cmd, F_(info))) {
|
||||||
// list all names
|
// list all names
|
||||||
for (const CustomEntityItem & entity : *customEntityItems_) {
|
for (const CustomEntityItem & entity : *customEntityItems_) {
|
||||||
render_value(output, entity);
|
render_value(output, entity);
|
||||||
@@ -286,59 +272,50 @@ bool WebCustomEntityService::get_value_info(JsonObject output, const char * cmd)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
char command_s[COMMAND_MAX_LENGTH];
|
// list all entities
|
||||||
strlcpy(command_s, Helpers::toLower(cmd).c_str(), sizeof(command_s));
|
if (!strcmp(cmd, F_(entities))) {
|
||||||
char * attribute_s = nullptr;
|
for (const auto & entity : *customEntityItems_) {
|
||||||
|
auto nest = output[entity.name].to<JsonObject>();
|
||||||
// check specific attribute to fetch instead of the complete record
|
get_value_json(nest, entity);
|
||||||
char * breakp = strchr(command_s, '/');
|
}
|
||||||
if (breakp) {
|
return true;
|
||||||
*breakp = '\0';
|
|
||||||
attribute_s = breakp + 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// specific value info
|
||||||
|
const char * attribute_s = Command::get_attribute(cmd);
|
||||||
for (const auto & entity : *customEntityItems_) {
|
for (const auto & entity : *customEntityItems_) {
|
||||||
if (Helpers::toLower(entity.name) == command_s) {
|
if (Helpers::toLower(entity.name) == cmd) {
|
||||||
output["name"] = entity.name;
|
get_value_json(output, entity);
|
||||||
output["ram"] = entity.ram;
|
return Command::set_attirbute(output, cmd, attribute_s);
|
||||||
output["type"] = entity.value_type == DeviceValueType::BOOL ? "boolean" : entity.value_type == DeviceValueType::STRING ? "string" : F_(number);
|
|
||||||
if (entity.uom > 0) {
|
|
||||||
output["uom"] = EMSdevice::uom_to_string(entity.uom);
|
|
||||||
}
|
|
||||||
output["readable"] = true;
|
|
||||||
output["writeable"] = entity.writeable;
|
|
||||||
output["visible"] = true;
|
|
||||||
if (entity.ram == 0) {
|
|
||||||
output["device_id"] = Helpers::hextoa(entity.device_id);
|
|
||||||
output["type_id"] = Helpers::hextoa(entity.type_id);
|
|
||||||
output["offset"] = entity.offset;
|
|
||||||
if (entity.value_type != DeviceValueType::BOOL && entity.value_type != DeviceValueType::STRING) {
|
|
||||||
output["factor"] = entity.factor;
|
|
||||||
} else if (entity.value_type == DeviceValueType::STRING) {
|
|
||||||
output["bytes"] = (uint8_t)entity.factor;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
render_value(output, entity, true); // create the "value" field
|
|
||||||
|
|
||||||
if (attribute_s) {
|
|
||||||
if (output.containsKey(attribute_s)) {
|
|
||||||
std::string data = output[attribute_s].as<std::string>();
|
|
||||||
output.clear();
|
|
||||||
output["api_data"] = data; // always as string
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return EMSESP::return_not_found(output, attribute_s, command_s); // not found
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (output.size()) {
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false; // not found
|
return false; // not found
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// build the json for specific entity
|
||||||
|
void WebCustomEntityService::get_value_json(JsonObject output, const CustomEntityItem & entity) {
|
||||||
|
output["name"] = entity.name;
|
||||||
|
output["storage"] = entity.ram ? "ram" : "ems";
|
||||||
|
output["type"] = entity.value_type == DeviceValueType::BOOL ? "boolean" : entity.value_type == DeviceValueType::STRING ? "string" : F_(number);
|
||||||
|
if (entity.uom > 0) {
|
||||||
|
output["uom"] = EMSdevice::uom_to_string(entity.uom);
|
||||||
|
}
|
||||||
|
output["readable"] = true;
|
||||||
|
output["writeable"] = entity.writeable;
|
||||||
|
output["visible"] = true;
|
||||||
|
if (entity.ram == 0) {
|
||||||
|
output["device_id"] = Helpers::hextoa(entity.device_id);
|
||||||
|
output["type_id"] = Helpers::hextoa(entity.type_id);
|
||||||
|
output["offset"] = entity.offset;
|
||||||
|
if (entity.value_type != DeviceValueType::BOOL && entity.value_type != DeviceValueType::STRING) {
|
||||||
|
output["factor"] = entity.factor;
|
||||||
|
} else if (entity.value_type == DeviceValueType::STRING) {
|
||||||
|
output["bytes"] = (uint8_t)entity.factor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
render_value(output, entity, true); // create the "value" field
|
||||||
|
}
|
||||||
|
|
||||||
// publish single value
|
// publish single value
|
||||||
void WebCustomEntityService::publish_single(const CustomEntityItem & entity) {
|
void WebCustomEntityService::publish_single(const CustomEntityItem & entity) {
|
||||||
if (!Mqtt::enabled() || !Mqtt::publish_single()) {
|
if (!Mqtt::enabled() || !Mqtt::publish_single()) {
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ class WebCustomEntityService : public StatefulService<WebCustomEntity> {
|
|||||||
void publish(const bool force = false);
|
void publish(const bool force = false);
|
||||||
bool command_setvalue(const char * value, const int8_t id, const char * name);
|
bool command_setvalue(const char * value, const int8_t id, const char * name);
|
||||||
bool get_value_info(JsonObject output, const char * cmd);
|
bool get_value_info(JsonObject output, const char * cmd);
|
||||||
|
void get_value_json(JsonObject output, const CustomEntityItem & entity);
|
||||||
bool get_value(std::shared_ptr<const Telegram> telegram);
|
bool get_value(std::shared_ptr<const Telegram> telegram);
|
||||||
void fetch();
|
void fetch();
|
||||||
void render_value(JsonObject output, CustomEntityItem entity, const bool useVal = false, const bool web = false, const bool add_uom = false);
|
void render_value(JsonObject output, CustomEntityItem entity, const bool useVal = false, const bool web = false, const bool add_uom = false);
|
||||||
|
|||||||
@@ -132,26 +132,11 @@ bool WebSchedulerService::command_setvalue(const char * value, const int8_t id,
|
|||||||
|
|
||||||
// process json output for info/commands and value_info
|
// process json output for info/commands and value_info
|
||||||
bool WebSchedulerService::get_value_info(JsonObject output, const char * cmd) {
|
bool WebSchedulerService::get_value_info(JsonObject output, const char * cmd) {
|
||||||
// check of it a 'commands' command
|
|
||||||
if (Helpers::toLower(cmd) == F_(commands)) {
|
|
||||||
output[F_(info)] = Helpers::translated_word(FL_(info_cmd));
|
|
||||||
output[F_(commands)] = Helpers::translated_word(FL_(commands_cmd));
|
|
||||||
output[F_(values)] = Helpers::translated_word(FL_(values_cmd));
|
|
||||||
|
|
||||||
for (const ScheduleItem & scheduleItem : *scheduleItems_) {
|
|
||||||
if (!scheduleItem.name.empty()) {
|
|
||||||
output[scheduleItem.name] = "activate schedule";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (scheduleItems_->size() == 0) {
|
if (scheduleItems_->size() == 0) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strlen(cmd) == 0 || Helpers::toLower(cmd) == F_(values) || Helpers::toLower(cmd) == F_(info)) {
|
if (!strlen(cmd) || !strcmp(cmd, F_(values)) || !strcmp(cmd, F_(info))) {
|
||||||
// list all names
|
// list all names
|
||||||
for (const ScheduleItem & scheduleItem : *scheduleItems_) {
|
for (const ScheduleItem & scheduleItem : *scheduleItems_) {
|
||||||
if (!scheduleItem.name.empty()) {
|
if (!scheduleItem.name.empty()) {
|
||||||
@@ -165,68 +150,59 @@ bool WebSchedulerService::get_value_info(JsonObject output, const char * cmd) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
char command_s[COMMAND_MAX_LENGTH];
|
const char * attribute_s = Command::get_attribute(cmd);
|
||||||
strlcpy(command_s, Helpers::toLower(cmd).c_str(), sizeof(command_s));
|
|
||||||
char * attribute_s = nullptr;
|
|
||||||
|
|
||||||
// check specific attribute to fetch instead of the complete record
|
if (!strcmp(cmd, F_(entities))) {
|
||||||
char * breakp = strchr(command_s, '/');
|
uint8_t i = 0;
|
||||||
if (breakp) {
|
char name[30];
|
||||||
*breakp = '\0';
|
for (const ScheduleItem & scheduleItem : *scheduleItems_) {
|
||||||
attribute_s = breakp + 1;
|
strlcpy(name, scheduleItem.name == "" ? Helpers::smallitoa(name, i++) : scheduleItem.name.c_str(), sizeof(name));
|
||||||
|
get_value_json(output[name].to<JsonObject>(), scheduleItem);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const ScheduleItem & scheduleItem : *scheduleItems_) {
|
for (const ScheduleItem & scheduleItem : *scheduleItems_) {
|
||||||
if (Helpers::toLower(scheduleItem.name) == command_s) {
|
if (Helpers::toLower(scheduleItem.name) == cmd) {
|
||||||
output["name"] = scheduleItem.name;
|
get_value_json(output, scheduleItem);
|
||||||
output["type"] = "boolean";
|
return Command::set_attirbute(output, cmd, attribute_s);
|
||||||
if (EMSESP::system_.bool_format() == BOOL_FORMAT_TRUEFALSE) {
|
|
||||||
output["value"] = scheduleItem.active;
|
|
||||||
} else if (EMSESP::system_.bool_format() == BOOL_FORMAT_10) {
|
|
||||||
output["value"] = scheduleItem.active ? 1 : 0;
|
|
||||||
} else {
|
|
||||||
char result[12];
|
|
||||||
output["value"] = Helpers::render_boolean(result, scheduleItem.active);
|
|
||||||
}
|
|
||||||
if (scheduleItem.flags == SCHEDULEFLAG_SCHEDULE_CONDITION) {
|
|
||||||
output["condition"] = scheduleItem.time;
|
|
||||||
} else if (scheduleItem.flags == SCHEDULEFLAG_SCHEDULE_ONCHANGE) {
|
|
||||||
output["onchange"] = scheduleItem.time;
|
|
||||||
} else if (scheduleItem.flags == SCHEDULEFLAG_SCHEDULE_TIMER) {
|
|
||||||
output["timer"] = scheduleItem.time;
|
|
||||||
} else if (scheduleItem.flags != 0) {
|
|
||||||
output["time"] = scheduleItem.time;
|
|
||||||
}
|
|
||||||
output["command"] = scheduleItem.cmd;
|
|
||||||
output["cmd_data"] = scheduleItem.value;
|
|
||||||
output["readable"] = true;
|
|
||||||
output["writeable"] = true;
|
|
||||||
output["visible"] = true;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (attribute_s) {
|
|
||||||
if (output.containsKey(attribute_s)) {
|
|
||||||
std::string data = output[attribute_s].as<std::string>();
|
|
||||||
output.clear();
|
|
||||||
output["api_data"] = data; // always as a string
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return EMSESP::return_not_found(output, attribute_s, command_s); // not found
|
|
||||||
}
|
|
||||||
|
|
||||||
if (output.size()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false; // not found
|
return false; // not found
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// build the json for specific entity
|
||||||
|
void WebSchedulerService::get_value_json(JsonObject output, const ScheduleItem & scheduleItem) {
|
||||||
|
output["name"] = scheduleItem.name;
|
||||||
|
output["type"] = "boolean";
|
||||||
|
if (EMSESP::system_.bool_format() == BOOL_FORMAT_TRUEFALSE) {
|
||||||
|
output["value"] = scheduleItem.active;
|
||||||
|
} else if (EMSESP::system_.bool_format() == BOOL_FORMAT_10) {
|
||||||
|
output["value"] = scheduleItem.active ? 1 : 0;
|
||||||
|
} else {
|
||||||
|
char result[12];
|
||||||
|
output["value"] = Helpers::render_boolean(result, scheduleItem.active);
|
||||||
|
}
|
||||||
|
if (scheduleItem.flags == SCHEDULEFLAG_SCHEDULE_CONDITION) {
|
||||||
|
output["condition"] = scheduleItem.time;
|
||||||
|
} else if (scheduleItem.flags == SCHEDULEFLAG_SCHEDULE_ONCHANGE) {
|
||||||
|
output["onchange"] = scheduleItem.time;
|
||||||
|
} else if (scheduleItem.flags == SCHEDULEFLAG_SCHEDULE_TIMER) {
|
||||||
|
output["timer"] = scheduleItem.time;
|
||||||
|
} else if (scheduleItem.flags != SCHEDULEFLAG_SCHEDULE_IMMEDIATE) {
|
||||||
|
output["time"] = scheduleItem.time;
|
||||||
|
}
|
||||||
|
output["command"] = scheduleItem.cmd;
|
||||||
|
output["cmd_data"] = scheduleItem.value;
|
||||||
|
bool hasName = scheduleItem.name != "";
|
||||||
|
output["readable"] = hasName;
|
||||||
|
output["writeable"] = hasName;
|
||||||
|
output["visible"] = hasName;
|
||||||
|
}
|
||||||
|
|
||||||
// publish single value
|
// publish single value
|
||||||
void WebSchedulerService::publish_single(const char * name, const bool state) {
|
void WebSchedulerService::publish_single(const char * name, const bool state) {
|
||||||
if (!Mqtt::enabled() || !Mqtt::publish_single() || name == nullptr || name[0] == '\0') {
|
if (!Mqtt::enabled() || !Mqtt::publish_single() || name == nullptr || name[0] == '\0') {
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ class WebSchedulerService : public StatefulService<WebScheduler> {
|
|||||||
bool has_commands();
|
bool has_commands();
|
||||||
bool command_setvalue(const char * value, const int8_t id, const char * name);
|
bool command_setvalue(const char * value, const int8_t id, const char * name);
|
||||||
bool get_value_info(JsonObject output, const char * cmd);
|
bool get_value_info(JsonObject output, const char * cmd);
|
||||||
|
void get_value_json(JsonObject output, const ScheduleItem & scheduleItem);
|
||||||
void ha_reset() {
|
void ha_reset() {
|
||||||
ha_registered_ = false;
|
ha_registered_ = false;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user