Merge pull request #1888 from proddy/dev

fix system command
This commit is contained in:
Proddy
2024-07-24 17:59:59 +02:00
committed by GitHub
22 changed files with 209 additions and 136 deletions

View File

@@ -30,7 +30,7 @@
"@mui/material": "^5.16.4", "@mui/material": "^5.16.4",
"@table-library/react-table-library": "4.1.7", "@table-library/react-table-library": "4.1.7",
"@types/lodash-es": "^4.17.12", "@types/lodash-es": "^4.17.12",
"@types/node": "^20.14.11", "@types/node": "^20.14.12",
"@types/react": "^18.3.3", "@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0", "@types/react-dom": "^18.3.0",
"@types/react-router-dom": "^5.3.3", "@types/react-router-dom": "^5.3.3",
@@ -47,7 +47,7 @@
"react-router-dom": "^6.25.1", "react-router-dom": "^6.25.1",
"react-toastify": "^10.0.5", "react-toastify": "^10.0.5",
"typesafe-i18n": "^5.26.2", "typesafe-i18n": "^5.26.2",
"typescript": "^5.5.3" "typescript": "^5.5.4"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.24.9", "@babel/core": "^7.24.9",
@@ -59,7 +59,7 @@
"concurrently": "^8.2.2", "concurrently": "^8.2.2",
"eslint": "^9.7.0", "eslint": "^9.7.0",
"eslint-config-prettier": "^9.1.0", "eslint-config-prettier": "^9.1.0",
"preact": "^10.22.1", "preact": "^10.23.0",
"prettier": "^3.3.3", "prettier": "^3.3.3",
"rollup-plugin-visualizer": "^5.12.0", "rollup-plugin-visualizer": "^5.12.0",
"terser": "^5.31.3", "terser": "^5.31.3",

View File

@@ -9,7 +9,6 @@ import DeviceHubIcon from '@mui/icons-material/DeviceHub';
import DirectionsBusIcon from '@mui/icons-material/DirectionsBus'; import DirectionsBusIcon from '@mui/icons-material/DirectionsBus';
import LogoDevIcon from '@mui/icons-material/LogoDev'; import LogoDevIcon from '@mui/icons-material/LogoDev';
import MemoryIcon from '@mui/icons-material/Memory'; import MemoryIcon from '@mui/icons-material/Memory';
import PermScanWifiIcon from '@mui/icons-material/PermScanWifi';
import PowerSettingsNewIcon from '@mui/icons-material/PowerSettingsNew'; import PowerSettingsNewIcon from '@mui/icons-material/PowerSettingsNew';
import RefreshIcon from '@mui/icons-material/Refresh'; import RefreshIcon from '@mui/icons-material/Refresh';
import RouterIcon from '@mui/icons-material/Router'; import RouterIcon from '@mui/icons-material/Router';
@@ -34,7 +33,6 @@ import {
import * as SystemApi from 'api/system'; import * as SystemApi from 'api/system';
import * as EMSESP from 'app/main/api';
import { dialogStyle } from 'CustomTheme'; import { dialogStyle } from 'CustomTheme';
import { useRequest } from 'alova'; import { useRequest } from 'alova';
import { busConnectionStatus } from 'app/main/types'; import { busConnectionStatus } from 'app/main/types';

View File

@@ -1839,12 +1839,12 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@types/node@npm:^20.14.11": "@types/node@npm:^20.14.12":
version: 20.14.11 version: 20.14.12
resolution: "@types/node@npm:20.14.11" resolution: "@types/node@npm:20.14.12"
dependencies: dependencies:
undici-types: "npm:~5.26.4" undici-types: "npm:~5.26.4"
checksum: 10c0/5306becc0ff41d81b1e31524bd376e958d0741d1ce892dffd586b9ae0cb6553c62b0d62abd16da8bea6b9a2c17572d360450535d7c073794b0cef9cb4e39691e checksum: 10c0/59bc5fa11fdd23fd517f859063118f54a1ab53d3399ef63c926f8902429d7453abc0db22ef4b0a6110026b6ab81b6472fee894e1d235c24b01a0b3e10cfae0bb
languageName: node languageName: node
linkType: hard linkType: hard
@@ -2085,7 +2085,7 @@ __metadata:
"@trivago/prettier-plugin-sort-imports": "npm:^4.3.0" "@trivago/prettier-plugin-sort-imports": "npm:^4.3.0"
"@types/babel__core": "npm:^7" "@types/babel__core": "npm:^7"
"@types/lodash-es": "npm:^4.17.12" "@types/lodash-es": "npm:^4.17.12"
"@types/node": "npm:^20.14.11" "@types/node": "npm:^20.14.12"
"@types/react": "npm:^18.3.3" "@types/react": "npm:^18.3.3"
"@types/react-dom": "npm:^18.3.0" "@types/react-dom": "npm:^18.3.0"
"@types/react-router-dom": "npm:^5.3.3" "@types/react-router-dom": "npm:^5.3.3"
@@ -2098,7 +2098,7 @@ __metadata:
jwt-decode: "npm:^4.0.0" jwt-decode: "npm:^4.0.0"
lodash-es: "npm:^4.17.21" lodash-es: "npm:^4.17.21"
mime-types: "npm:^2.1.35" mime-types: "npm:^2.1.35"
preact: "npm:^10.22.1" preact: "npm:^10.23.0"
prettier: "npm:^3.3.3" prettier: "npm:^3.3.3"
react: "npm:latest" react: "npm:latest"
react-dom: "npm:latest" react-dom: "npm:latest"
@@ -2109,7 +2109,7 @@ __metadata:
rollup-plugin-visualizer: "npm:^5.12.0" rollup-plugin-visualizer: "npm:^5.12.0"
terser: "npm:^5.31.3" terser: "npm:^5.31.3"
typesafe-i18n: "npm:^5.26.2" typesafe-i18n: "npm:^5.26.2"
typescript: "npm:^5.5.3" typescript: "npm:^5.5.4"
typescript-eslint: "npm:8.0.0-alpha.10" typescript-eslint: "npm:8.0.0-alpha.10"
vite: "npm:^5.3.4" vite: "npm:^5.3.4"
vite-plugin-imagemin: "npm:^0.6.1" vite-plugin-imagemin: "npm:^0.6.1"
@@ -6070,10 +6070,10 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"preact@npm:^10.22.1": "preact@npm:^10.23.0":
version: 10.22.1 version: 10.23.0
resolution: "preact@npm:10.22.1" resolution: "preact@npm:10.23.0"
checksum: 10c0/9163b97d6fc0ce6b945ed77695d00c4fa07e317d0723e7b9d10c748153d30596abab8b26861ae45591e47bff25515da91406ce7f1c9e66cd9cac7e7f6c927930 checksum: 10c0/00bcf490ce13c0fd70e3d2e2418466419b31f201b28d35f173d7ddcb66b421a3f6ca569541de581cbbf4ec7b2adef3f391d631dca7a4fd86708d81ca08259c1c
languageName: node languageName: node
linkType: hard linkType: hard
@@ -7297,23 +7297,23 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"typescript@npm:^5.5.3": "typescript@npm:^5.5.4":
version: 5.5.3 version: 5.5.4
resolution: "typescript@npm:5.5.3" resolution: "typescript@npm:5.5.4"
bin: bin:
tsc: bin/tsc tsc: bin/tsc
tsserver: bin/tsserver tsserver: bin/tsserver
checksum: 10c0/f52c71ccbc7080b034b9d3b72051d563601a4815bf3e39ded188e6ce60813f75dbedf11ad15dd4d32a12996a9ed8c7155b46c93a9b9c9bad1049766fe614bbdd checksum: 10c0/422be60f89e661eab29ac488c974b6cc0a660fb2228003b297c3d10c32c90f3bcffc1009b43876a082515a3c376b1eefcce823d6e78982e6878408b9a923199c
languageName: node languageName: node
linkType: hard linkType: hard
"typescript@patch:typescript@npm%3A^5.5.3#optional!builtin<compat/typescript>": "typescript@patch:typescript@npm%3A^5.5.4#optional!builtin<compat/typescript>":
version: 5.5.3 version: 5.5.4
resolution: "typescript@patch:typescript@npm%3A5.5.3#optional!builtin<compat/typescript>::version=5.5.3&hash=b45daf" resolution: "typescript@patch:typescript@npm%3A5.5.4#optional!builtin<compat/typescript>::version=5.5.4&hash=b45daf"
bin: bin:
tsc: bin/tsc tsc: bin/tsc
tsserver: bin/tsserver tsserver: bin/tsserver
checksum: 10c0/5a437c416251334deeaf29897157032311f3f126547cfdc4b133768b606cb0e62bcee733bb97cf74c42fe7268801aea1392d8e40988cdef112e9546eba4c03c5 checksum: 10c0/10dd9881baba22763de859e8050d6cb6e2db854197495c6f1929b08d1eb2b2b00d0b5d9b0bcee8472f1c3f4a7ef6a5d7ebe0cfd703f853aa5ae465b8404bc1ba
languageName: node languageName: node
linkType: hard linkType: hard

View File

@@ -12,7 +12,6 @@
"dependencies": { "dependencies": {
"@msgpack/msgpack": "^2.8.0", "@msgpack/msgpack": "^2.8.0",
"@types/multer": "^1.4.11", "@types/multer": "^1.4.11",
"compression": "^1.7.4",
"express": "^4.19.2", "express": "^4.19.2",
"itty-router": "^5.0.17", "itty-router": "^5.0.17",
"multer": "^1.4.5-lts.1" "multer": "^1.4.5-lts.1"

View File

@@ -705,13 +705,13 @@ bool AnalogSensor::get_value_info(JsonObject output, const char * cmd, const int
output["api_data"] = data; // always as a string output["api_data"] = data; // always as a string
return true; return true;
} }
return EMSESP::return_not_found(output, "attribute", sensor_name); // not found return EMSESP::return_not_found(output, attribute_s, sensor_name); // not found
} }
return true; // found a match, exit return true; // found a match, exit
} }
} }
return EMSESP::return_not_found(output, cmd, F_(analogsensor)); // not found return false; // not found
} }
void AnalogSensor::addSensorJson(JsonObject output, const Sensor & sensor) { void AnalogSensor::addSensorJson(JsonObject output, const Sensor & sensor) {

View File

@@ -63,7 +63,6 @@ uint8_t Command::process(const char * path, const bool is_admin, const JsonObjec
int8_t id_n = -1; // default hc int8_t id_n = -1; // default hc
// check for a device as first item in the path // check for a device as first item in the path
// if its not a known device (thermostat, boiler etc) look for any special MQTT subscriptions
const char * device_s = nullptr; const char * device_s = nullptr;
if (!num_paths) { if (!num_paths) {
// we must look for the device in the JSON body // we must look for the device in the JSON body
@@ -72,7 +71,7 @@ uint8_t Command::process(const char * path, const bool is_admin, const JsonObjec
} }
} else { } else {
// extract it from the path // extract it from the path
device_s = p.paths().front().c_str(); // get the device (boiler, thermostat, system etc) device_s = p.paths().front().c_str(); // get the device type name (boiler, thermostat, system etc)
} }
// validate the device, make sure it exists // validate the device, make sure it exists
@@ -172,7 +171,7 @@ uint8_t Command::process(const char * path, const bool is_admin, const JsonObjec
} }
uint8_t device_type = EMSdevice::device_name_2_device_type(device_p); uint8_t device_type = EMSdevice::device_name_2_device_type(device_p);
if (CommandRet::OK != Command::call(device_type, data_s, "", true, id_d, output)) { if (Command::call(device_type, data_s, "", true, id_d, output) != CommandRet::OK) {
return CommandRet::INVALID; return CommandRet::INVALID;
} }
@@ -340,15 +339,16 @@ uint8_t Command::call(const uint8_t device_type, const char * cmd, const char *
} }
} }
// first see if there is a command registered and it's valid // see if there is a command registered and it's valid
auto cf = find_command(device_type, device_id, cmd, flag); auto cf = find_command(device_type, device_id, cmd, flag);
if (!cf) { if (!cf) {
std::string err = std::string("unknown command ") + cmd; // if we don't already have a message set, set it to invalid command
LOG_WARNING("Command failed: %s", err.c_str()); if (output["message"]) {
LOG_WARNING("Command failed: %s", output["message"].as<const char *>());
// if we don't alread have a message set, set it to invalid command } else {
if (!output["message"]) { std::string err = "no " + std::string(cmd) + " in " + dname;
output["message"] = err; output["message"] = err;
LOG_WARNING("Command failed: %s", err.c_str());
} }
return CommandRet::ERROR; return CommandRet::ERROR;
} }
@@ -382,7 +382,7 @@ uint8_t Command::call(const uint8_t device_type, const char * cmd, const char *
if (!single_command && EMSESP::cmd_is_readonly(device_type, device_id, cmd, id)) { if (!single_command && EMSESP::cmd_is_readonly(device_type, device_id, cmd, id)) {
return_code = CommandRet::INVALID; // error on readonly or invalid hc return_code = CommandRet::INVALID; // error on readonly or invalid hc
} else { } else {
// call it... // call the command...
return_code = ((cf->cmdfunction_)(value, id)) ? CommandRet::OK : CommandRet::ERROR; return_code = ((cf->cmdfunction_)(value, id)) ? CommandRet::OK : CommandRet::ERROR;
} }
} }
@@ -400,12 +400,13 @@ uint8_t Command::call(const uint8_t device_type, const char * cmd, const char *
LOG_WARNING(error); LOG_WARNING(error);
} else { } else {
if (single_command) { if (single_command) {
LOG_DEBUG(("%sCalling command %s"), ro.c_str(), info_s); // log as DEBUG (TRACE) regarless if compiled with EMSESP_DEBUG
logger_.debug(("%sCalled command %s"), ro.c_str(), info_s);
} else { } else {
if (id > 0) { if (id > 0) {
LOG_INFO(("%sCalling command %s with value %s and id %d on device 0x%02X"), ro.c_str(), info_s, value, id, device_id); LOG_INFO(("%sCalled command %s with value %s and id %d on device 0x%02X"), ro.c_str(), info_s, value, id, device_id);
} else { } else {
LOG_INFO(("%sCalling command %s with value %s"), ro.c_str(), info_s, value); LOG_INFO(("%sCalled command %s with value %s"), ro.c_str(), info_s, value);
} }
} }
} }
@@ -506,10 +507,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) {
// force add info and commands for those non-EMS devices // check of it a 'commands' command
if (device_type == EMSdevice::DeviceType::TEMPERATURESENSOR || device_type == EMSdevice::DeviceType::ANALOGSENSOR) { 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_(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));
} else if (cmdfunctions_.empty()) { } else if (cmdfunctions_.empty()) {
output["message"] = "no commands available"; output["message"] = "no commands available";
return false; return false;
@@ -544,13 +546,14 @@ void Command::show(uuid::console::Shell & shell, uint8_t device_type, bool verbo
} }
} }
// non EMS devices always have an info and commands command // non EMS devices always have an info, commands and values
bool show_info = (device_type == EMSdevice::DeviceType::TEMPERATURESENSOR || device_type == EMSdevice::DeviceType::ANALOGSENSOR bool show_info = (device_type == EMSdevice::DeviceType::TEMPERATURESENSOR || device_type == EMSdevice::DeviceType::ANALOGSENSOR
|| device_type == EMSdevice::DeviceType::SCHEDULER || device_type == EMSdevice::DeviceType::CUSTOM); || device_type == EMSdevice::DeviceType::SCHEDULER || device_type == EMSdevice::DeviceType::CUSTOM);
if (!verbose && show_info) { if (!verbose && show_info) {
sorted_cmds.push_back(F_(info)); sorted_cmds.push_back(F_(info));
sorted_cmds.push_back(F_(commands)); sorted_cmds.push_back(F_(commands));
sorted_cmds.push_back(F_(values));
} }
sorted_cmds.sort(); // sort them sorted_cmds.sort(); // sort them
@@ -570,9 +573,11 @@ void Command::show(uuid::console::Shell & shell, uint8_t device_type, bool verbo
// we hard code 'info' and 'commands' commands so print them first // we hard code 'info' and 'commands' commands so print them first
if (show_info) { if (show_info) {
shell.printf(" info:\t\t\t\t%slists all values %s*", COLOR_BRIGHT_CYAN, COLOR_BRIGHT_GREEN); shell.printf(" info:\t\t\t\t%slist all values %s*", COLOR_BRIGHT_CYAN, COLOR_BRIGHT_GREEN);
shell.println(COLOR_RESET); shell.println(COLOR_RESET);
shell.printf(" commands:\t\t\t%slists all commands %s*", COLOR_BRIGHT_CYAN, COLOR_BRIGHT_GREEN); shell.printf(" commands:\t\t\t%slist all commands %s*", COLOR_BRIGHT_CYAN, COLOR_BRIGHT_GREEN);
shell.println(COLOR_RESET);
shell.printf(" values:\t\t\t%slist all values %s*", COLOR_BRIGHT_CYAN, COLOR_BRIGHT_GREEN);
shell.println(COLOR_RESET); shell.println(COLOR_RESET);
} }
@@ -612,7 +617,6 @@ bool Command::device_has_commands(const uint8_t device_type) {
return true; // we always have System return true; // we always have System
} }
// if there are no entries to scheduler/custom/temperaturesensor/analogsensor, don't error but return a message
if (device_type == EMSdevice::DeviceType::SCHEDULER) { if (device_type == EMSdevice::DeviceType::SCHEDULER) {
return true; return true;
} }
@@ -631,7 +635,6 @@ bool Command::device_has_commands(const uint8_t device_type) {
for (const auto & emsdevice : EMSESP::emsdevices) { for (const auto & emsdevice : EMSESP::emsdevices) {
if (emsdevice && (emsdevice->device_type() == device_type)) { if (emsdevice && (emsdevice->device_type() == device_type)) {
// device found, now see if it has any commands
for (const auto & cf : cmdfunctions_) { for (const auto & cf : cmdfunctions_) {
if (cf.device_type_ == device_type) { if (cf.device_type_ == device_type) {
return true; return true;

View File

@@ -575,17 +575,17 @@ static void setup_commands(std::shared_ptr<Commands> & commands) {
return; return;
} else { } else {
// show message if no data returned (e.g. for analogsensor, temperaturesensor, custom) // show message if no data returned (e.g. for analogsensor, temperaturesensor, custom)
shell.println("No data."); shell.println("Command executed. Check log for messages.");
return; return;
} }
} } else if (return_code == CommandRet::NOT_FOUND) {
if (return_code == CommandRet::NOT_FOUND) {
shell.println("Unknown command"); shell.println("Unknown command");
shell.print("Available commands are: "); shell.print("Available commands are: ");
Command::show(shell, device_type, false); // non-verbose mode Command::show(shell, device_type, false); // non-verbose mode
} else if (return_code != CommandRet::OK) { } else if ((return_code == CommandRet::ERROR) || (return_code == CommandRet::FAIL)) {
shell.printfln("Bad syntax (error code %d)", return_code); shell.printfln("Bad syntax. Check arguments.");
} else {
shell.printfln("Command failed with error code %d", return_code);
} }
}, },
[](Shell & shell, const std::vector<std::string> & current_arguments, const std::string & next_argument) -> std::vector<std::string> { [](Shell & shell, const std::vector<std::string> & current_arguments, const std::string & next_argument) -> std::vector<std::string> {

View File

@@ -212,9 +212,6 @@ uint8_t EMSdevice::device_name_2_device_type(const char * topic) {
if (!strcmp(lowtopic, F_(thermostat))) { if (!strcmp(lowtopic, F_(thermostat))) {
return DeviceType::THERMOSTAT; return DeviceType::THERMOSTAT;
} }
if (!strcmp(lowtopic, F_(system))) {
return DeviceType::SYSTEM;
}
if (!strcmp(lowtopic, F_(scheduler))) { if (!strcmp(lowtopic, F_(scheduler))) {
return DeviceType::SCHEDULER; return DeviceType::SCHEDULER;
} }
@@ -227,12 +224,6 @@ uint8_t EMSdevice::device_name_2_device_type(const char * topic) {
if (!strcmp(lowtopic, F_(mixer))) { if (!strcmp(lowtopic, F_(mixer))) {
return DeviceType::MIXER; return DeviceType::MIXER;
} }
if (!strcmp(lowtopic, F_(temperaturesensor))) {
return DeviceType::TEMPERATURESENSOR;
}
if (!strcmp(lowtopic, F_(analogsensor))) {
return DeviceType::ANALOGSENSOR;
}
if (!strcmp(lowtopic, F_(switch))) { if (!strcmp(lowtopic, F_(switch))) {
return DeviceType::SWITCH; return DeviceType::SWITCH;
} }
@@ -248,9 +239,6 @@ uint8_t EMSdevice::device_name_2_device_type(const char * topic) {
if (!strcmp(lowtopic, F_(heatsource))) { if (!strcmp(lowtopic, F_(heatsource))) {
return DeviceType::HEATSOURCE; return DeviceType::HEATSOURCE;
} }
if (!strcmp(lowtopic, F_(custom))) {
return DeviceType::CUSTOM;
}
if (!strcmp(lowtopic, F_(ventilation))) { if (!strcmp(lowtopic, F_(ventilation))) {
return DeviceType::VENTILATION; return DeviceType::VENTILATION;
} }
@@ -261,6 +249,23 @@ uint8_t EMSdevice::device_name_2_device_type(const char * topic) {
return DeviceType::POOL; return DeviceType::POOL;
} }
// non EMS
if (!strcmp(lowtopic, F_(custom))) {
return DeviceType::CUSTOM;
}
if (!strcmp(lowtopic, F_(temperaturesensor))) {
return DeviceType::TEMPERATURESENSOR;
}
if (!strcmp(lowtopic, F_(analogsensor))) {
return DeviceType::ANALOGSENSOR;
}
if (!strcmp(lowtopic, F_(scheduler))) {
return DeviceType::SCHEDULER;
}
if (!strcmp(lowtopic, F_(system))) {
return DeviceType::SYSTEM;
}
return DeviceType::UNKNOWN; return DeviceType::UNKNOWN;
} }
@@ -1598,18 +1603,14 @@ bool EMSdevice::get_value_info(JsonObject output, const char * cmd, const int8_t
// if we're filtering on an attribute, go find it // if we're filtering on an attribute, go find it
if (attribute_s) { if (attribute_s) {
#if defined(EMSESP_DEBUG)
EMSESP::logger().debug("[DEBUG] fetching single attribute %s", attribute_s);
#endif
if (json.containsKey(attribute_s)) { if (json.containsKey(attribute_s)) {
std::string data = json[attribute_s].as<std::string>(); std::string data = json[attribute_s].as<std::string>();
output.clear(); output.clear();
output["api_data"] = data; // always as string output["api_data"] = data; // always as string
return true; return true;
} }
return EMSESP::return_not_found(output, "attribute", command_s); // not found return EMSESP::return_not_found(output, attribute_s, command_s); // not found
} }
return true; return true;
} }
} }

View File

@@ -742,8 +742,8 @@ void EMSESP::publish_response(std::shared_ptr<const Telegram> telegram) {
buffer = nullptr; buffer = nullptr;
} }
// builds json with the detail of each value, for a given EMS device // builds json with the detail of each value, for a given device type
// for other types like sensors, scheduler, custom entities it will process single commands like 'info', 'values', 'commands', 'entities'... // device type can be EMS devices looking for entities, or a sensor/scheduler/custom entity etc looking for values extracted from the info command
bool EMSESP::get_device_value_info(JsonObject root, const char * cmd, const int8_t id, const uint8_t devicetype) { bool EMSESP::get_device_value_info(JsonObject root, const char * cmd, const int8_t id, const uint8_t devicetype) {
// check first for EMS devices // check first for EMS devices
bool found_device = false; bool found_device = false;
@@ -794,7 +794,7 @@ bool EMSESP::get_device_value_info(JsonObject root, const char * cmd, const int8
bool EMSESP::return_not_found(JsonObject output, const char * msg, const char * cmd) { bool EMSESP::return_not_found(JsonObject output, const char * msg, const char * cmd) {
output.clear(); output.clear();
char error[100]; char error[100];
snprintf(error, sizeof(error), "cannot find %s in %s", msg, cmd); snprintf(error, sizeof(error), "no %s in %s", msg, cmd);
output["message"] = error; output["message"] = error;
return false; return false;
} }
@@ -1312,7 +1312,7 @@ bool EMSESP::add_device(const uint8_t device_id, const uint8_t product_id, const
default_name = "Cascaded Controller"; default_name = "Cascaded Controller";
device_type = DeviceType::CONTROLLER; device_type = DeviceType::CONTROLLER;
} else { } else {
LOG_WARNING("Unrecognized EMS device (device ID 0x%02X, no product ID). Please report on GitHub.", device_id); LOG_WARNING("Unrecognized EMS device (deviceID 0x%02X, no productID). Please report on GitHub.", device_id);
return false; return false;
} }
} }
@@ -1363,13 +1363,9 @@ bool EMSESP::add_device(const uint8_t device_id, const uint8_t product_id, const
device_type, device_type,
F_(values), F_(values),
[device_type](const char * value, const int8_t id, JsonObject output) { [device_type](const char * value, const int8_t id, JsonObject output) {
return EMSdevice::export_values(device_type, return EMSdevice::export_values(device_type, output, id, EMSdevice::OUTPUT_TARGET::API_SHORTNAMES);
output,
id,
EMSdevice::OUTPUT_TARGET::API_SHORTNAMES); // HIDDEN command showing short names, used in e.g. /api/boiler
}, },
nullptr, FL_(values_cmd));
CommandFlag::HIDDEN); // this command is hidden
Command::add( Command::add(
device_type, device_type,
F_(commands), F_(commands),

View File

@@ -151,7 +151,7 @@ MAKE_WORD_CUSTOM(nvs_optional, "[nvs]")
MAKE_WORD_CUSTOM(offset_optional, "[offset]") MAKE_WORD_CUSTOM(offset_optional, "[offset]")
MAKE_WORD_CUSTOM(length_optional, "[length]") MAKE_WORD_CUSTOM(length_optional, "[length]")
MAKE_WORD_CUSTOM(typeid_mandatory, "<type ID>") MAKE_WORD_CUSTOM(typeid_mandatory, "<type ID>")
MAKE_WORD_CUSTOM(deviceid_mandatory, "<device ID>") MAKE_WORD_CUSTOM(deviceid_mandatory, "<deviceID>")
MAKE_WORD_CUSTOM(device_type_optional, "[device]") MAKE_WORD_CUSTOM(device_type_optional, "[device]")
MAKE_WORD_CUSTOM(invalid_log_level, "Invalid log level") MAKE_WORD_CUSTOM(invalid_log_level, "Invalid log level")
MAKE_WORD_CUSTOM(log_level_optional, "[level]") MAKE_WORD_CUSTOM(log_level_optional, "[level]")

View File

@@ -59,7 +59,7 @@ MAKE_WORD_TRANSLATION(water_device, "Water Module", "Wassermodul", "", "", "Modu
MAKE_WORD_TRANSLATION(pool_device, "Pool Module", "Poolmodul", "", "", "Moduł basenu", "", "", "", "", "") // TODO translate MAKE_WORD_TRANSLATION(pool_device, "Pool Module", "Poolmodul", "", "", "Moduł basenu", "", "", "", "", "") // TODO translate
// commands // commands
MAKE_WORD_TRANSLATION(info_cmd, "list all values", "Liste aller Werte", "lijst van alle waardes", "", "wyświetl wszystkie wartości", "Viser alle verdier", "", "Tüm değerleri listele", "elenca tutti i valori", "zobraziť všetky hodnoty") // TODO translate MAKE_WORD_TRANSLATION(info_cmd, "list all values (verbose)", "Liste aller Werte", "lijst van alle waardes", "", "wyświetl wszystkie wartości", "Viser alle verdier", "", "Tüm değerleri listele", "elenca tutti i valori", "zobraziť všetky hodnoty") // TODO translate
MAKE_WORD_TRANSLATION(commands_cmd, "list all commands", "Liste aller Kommandos", "lijst van alle commando's", "", "wyświetl wszystkie komendy", "Viser alle kommandoer", "", "Tüm komutları listele", "elencaa tutti i comandi", "zobraziť všetky príkazy") // TODO translate MAKE_WORD_TRANSLATION(commands_cmd, "list all commands", "Liste aller Kommandos", "lijst van alle commando's", "", "wyświetl wszystkie komendy", "Viser alle kommandoer", "", "Tüm komutları listele", "elencaa tutti i comandi", "zobraziť všetky príkazy") // TODO translate
MAKE_WORD_TRANSLATION(entities_cmd, "list all entities", "Liste aller Entitäten", "lijst van alle entiteiten", "", "wyświetl wszsytkie encje", "Viser alle enheter", "", "Tüm varlıkları listele", "elenca tutte le entità", "zobraziť všetky entity") // TODO translate MAKE_WORD_TRANSLATION(entities_cmd, "list all entities", "Liste aller Entitäten", "lijst van alle entiteiten", "", "wyświetl wszsytkie encje", "Viser alle enheter", "", "Tüm varlıkları listele", "elenca tutte le entità", "zobraziť všetky entity") // TODO translate
MAKE_WORD_TRANSLATION(send_cmd, "send a telegram", "Sende EMS-Telegramm", "stuur een telegram", "", "wyślij telegram", "send et telegram", "", "Bir telegram gönder", "invia un telegramma", "poslať telegram") // TODO translate MAKE_WORD_TRANSLATION(send_cmd, "send a telegram", "Sende EMS-Telegramm", "stuur een telegram", "", "wyślij telegram", "send et telegram", "", "Bir telegram gönder", "invia un telegramma", "poslať telegram") // TODO translate
@@ -74,8 +74,9 @@ MAKE_WORD_TRANSLATION(schedule_cmd, "enable schedule item", "Aktiviere Zeitplan"
MAKE_WORD_TRANSLATION(entity_cmd, "set custom value on ems", "Sende eigene Entitäten zu EMS", "verstuur custom waarde naar EMS", "", "wyślij własną wartość na EMS", "", "", "emp üzerinde özel değer ayarla", "imposta valori personalizzati su EMS", "nastaviť vlastnú hodnotu na ems") // TODO translate MAKE_WORD_TRANSLATION(entity_cmd, "set custom value on ems", "Sende eigene Entitäten zu EMS", "verstuur custom waarde naar EMS", "", "wyślij własną wartość na EMS", "", "", "emp üzerinde özel değer ayarla", "imposta valori personalizzati su EMS", "nastaviť vlastnú hodnotu na ems") // TODO translate
MAKE_WORD_TRANSLATION(commands_response, "get response", "Hole Antwort", "Verzoek om antwoord", "", "uzyskaj odpowiedź", "", "", "gelen cevap", "", "získať odpoveď") // TODO translate MAKE_WORD_TRANSLATION(commands_response, "get response", "Hole Antwort", "Verzoek om antwoord", "", "uzyskaj odpowiedź", "", "", "gelen cevap", "", "získať odpoveď") // TODO translate
MAKE_WORD_TRANSLATION(coldshot_cmd, "send a cold shot of water", "", "", "", "uruchom tryśnięcie zimnej wody", "", "", "soğuk su gönder", "", "pošlite studenú dávku vody") // TODO translate MAKE_WORD_TRANSLATION(coldshot_cmd, "send a cold shot of water", "", "", "", "uruchom tryśnięcie zimnej wody", "", "", "soğuk su gönder", "", "pošlite studenú dávku vody") // TODO translate
MAKE_WORD_TRANSLATION(allvalues_cmd, "output all values", "", "", "", "wyświetl wszystkie wartości", "", "", "", "", "vypísať všetky hodnoty") // TODO translate MAKE_WORD_TRANSLATION(allvalues_cmd, "output all values in system", "", "", "", "wyświetl wszystkie wartości", "", "", "", "", "vypísať všetky hodnoty") // TODO translate
MAKE_WORD_TRANSLATION(message_cmd, "send a message", "", "", "", "", "", "", "", "", "") // TODO translate MAKE_WORD_TRANSLATION(message_cmd, "send a message", "", "", "", "", "", "", "", "", "") // TODO translate
MAKE_WORD_TRANSLATION(values_cmd, "list all values", "", "", "", "", "", "", "", "", "") // TODO translate
// tags // tags
MAKE_WORD_TRANSLATION(tag_hc1, "hc1", "HK1", "hc1", "VK1", "OG1", "hc1", "hc1", "ID1", "hc1", "hc1") MAKE_WORD_TRANSLATION(tag_hc1, "hc1", "HK1", "hc1", "VK1", "OG1", "hc1", "hc1", "ID1", "hc1", "hc1")

View File

@@ -144,24 +144,20 @@ bool System::command_fetch(const char * value, const int8_t id) {
if (value_s == "all") { if (value_s == "all") {
LOG_INFO("Requesting data from EMS devices"); LOG_INFO("Requesting data from EMS devices");
EMSESP::fetch_device_values(); EMSESP::fetch_device_values();
return true;
} else if (value_s == (F_(boiler))) { } else if (value_s == (F_(boiler))) {
EMSESP::fetch_device_values_type(EMSdevice::DeviceType::BOILER); EMSESP::fetch_device_values_type(EMSdevice::DeviceType::BOILER);
return true;
} else if (value_s == (F_(thermostat))) { } else if (value_s == (F_(thermostat))) {
EMSESP::fetch_device_values_type(EMSdevice::DeviceType::THERMOSTAT); EMSESP::fetch_device_values_type(EMSdevice::DeviceType::THERMOSTAT);
return true;
} else if (value_s == (F_(solar))) { } else if (value_s == (F_(solar))) {
EMSESP::fetch_device_values_type(EMSdevice::DeviceType::SOLAR); EMSESP::fetch_device_values_type(EMSdevice::DeviceType::SOLAR);
return true;
} else if (value_s == (F_(mixer))) { } else if (value_s == (F_(mixer))) {
EMSESP::fetch_device_values_type(EMSdevice::DeviceType::MIXER); EMSESP::fetch_device_values_type(EMSdevice::DeviceType::MIXER);
return true;
} }
} else {
EMSESP::fetch_device_values(); // default if no name or id is given
} }
EMSESP::fetch_device_values(); // default if no name or id is given return true; // always true
return true;
} }
// mqtt publish // mqtt publish
@@ -857,7 +853,6 @@ void System::commands_init() {
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));
// MQTT subscribe "ems-esp/system/#" // MQTT subscribe "ems-esp/system/#"
Mqtt::subscribe(EMSdevice::DeviceType::SYSTEM, "system/#", nullptr); // use empty function callback Mqtt::subscribe(EMSdevice::DeviceType::SYSTEM, "system/#", nullptr); // use empty function callback
} }
@@ -1295,14 +1290,25 @@ bool System::saveSettings(const char * filename, const char * section, JsonObjec
return false; // not found return false; // not found
} }
// return back a system value
bool System::get_value_info(JsonObject root, const char * command) { bool System::get_value_info(JsonObject root, const char * command) {
if (command == nullptr || strlen(command) == 0) { if (command == nullptr || strlen(command) == 0) {
LOG_ERROR("empty system command"); LOG_ERROR("empty system command");
return false; return false;
} }
// cmd is lower case of the command
char cmd[COMMAND_MAX_LENGTH]; char cmd[COMMAND_MAX_LENGTH];
strlcpy(cmd, Helpers::toLower(command).c_str(), sizeof(cmd)); strlcpy(cmd, Helpers::toLower(command).c_str(), sizeof(cmd));
// fetch all the data from the system
(void)command_info("", 0, root);
// check for hardcoded "info"
if (!strcmp(cmd, F_(info))) {
return true;
}
char * val = strstr(cmd, "/value"); char * val = strstr(cmd, "/value");
if (val) { if (val) {
val[0] = '\0'; val[0] = '\0';
@@ -1314,14 +1320,6 @@ bool System::get_value_info(JsonObject root, const char * command) {
slash++; slash++;
} }
// fetch all the data from the system
(void)command_info("", 0, root);
// check for hardcoded "info"
if (Helpers::toLower(cmd) == F_(info)) {
return true;
}
std::string s; std::string s;
// 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
@@ -1344,8 +1342,9 @@ bool System::get_value_info(JsonObject root, const char * command) {
} }
} }
root.clear(); // clear json, we only one a single value
if (!s.empty()) { if (!s.empty()) {
root.clear();
if (val) { if (val) {
root["api_data"] = s; root["api_data"] = s;
} else { } else {
@@ -1354,7 +1353,7 @@ bool System::get_value_info(JsonObject root, const char * command) {
return true; // found return true; // found
} }
return EMSESP::return_not_found(root, "data", command); // not found return false; // not found
} }
// export status information including the device information // export status information including the device information
@@ -1623,7 +1622,11 @@ bool System::command_info(const char * value, const int8_t id, JsonObject output
#if defined(EMSESP_TEST) #if defined(EMSESP_TEST)
// run a test, e.g. http://ems-esp/api?device=system&cmd=test&data=boiler // run a test, e.g. http://ems-esp/api?device=system&cmd=test&data=boiler
bool System::command_test(const char * value, const int8_t id) { bool System::command_test(const char * value, const int8_t id) {
return Test::test(value, id); if (value) {
return Test::test(value, id);
} else {
return false;
}
} }
#endif #endif

View File

@@ -554,7 +554,7 @@ void TxService::add(uint8_t operation, const uint8_t * data, const uint8_t lengt
// send a Tx telegram to request data from an EMS device // send a Tx telegram to request data from an EMS device
void TxService::read_request(const uint16_t type_id, const uint8_t dest, const uint8_t offset, const uint8_t length, const bool front) { void TxService::read_request(const uint16_t type_id, const uint8_t dest, const uint8_t offset, const uint8_t length, const bool front) {
LOG_DEBUG("Tx read request to device 0x%02X for type ID 0x%02X", dest, type_id); LOG_DEBUG("Tx read request to deviceID 0x%02X for typeID 0x%02X", dest, type_id);
uint8_t message_data = (type_id > 0xFF) ? (EMS_MAX_TELEGRAM_MESSAGE_LENGTH - 2) : EMS_MAX_TELEGRAM_MESSAGE_LENGTH; uint8_t message_data = (type_id > 0xFF) ? (EMS_MAX_TELEGRAM_MESSAGE_LENGTH - 2) : EMS_MAX_TELEGRAM_MESSAGE_LENGTH;
if (length > 0 && length < message_data) { if (length > 0 && length < message_data) {

View File

@@ -32,8 +32,13 @@
#include "helpers.h" #include "helpers.h"
#if defined(EMSESP_STANDALONE)
#define MAX_RX_TELEGRAMS 100 // size of Rx queue
#define MAX_TX_TELEGRAMS 200 // size of Tx queue
#else
#define MAX_RX_TELEGRAMS 10 // size of Rx queue #define MAX_RX_TELEGRAMS 10 // size of Rx queue
#define MAX_TX_TELEGRAMS 100 // size of Tx queue #define MAX_TX_TELEGRAMS 100 // size of Tx queue
#endif
// default values for null values // default values for null values
static constexpr uint8_t EMS_VALUE_BOOL = 0xFF; // used to mark that something is a boolean static constexpr uint8_t EMS_VALUE_BOOL = 0xFF; // used to mark that something is a boolean

View File

@@ -402,13 +402,13 @@ bool TemperatureSensor::get_value_info(JsonObject output, const char * cmd, cons
output["api_data"] = data; // always as string output["api_data"] = data; // always as string
return true; return true;
} }
return EMSESP::return_not_found(output, "attribute", sensor_name); // not found return EMSESP::return_not_found(output, attribute_s, sensor_name); // not found
} }
return true; // found a match, exit return true; // found a match, exit
} }
} }
return EMSESP::return_not_found(output, cmd, F_(temperaturesensor)); // not found return false; // not found
} }
void TemperatureSensor::addSensorJson(JsonObject output, const Sensor & sensor) { void TemperatureSensor::addSensorJson(JsonObject output, const Sensor & sensor) {

View File

@@ -963,27 +963,38 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
// load devices // load devices
test("boiler"); test("boiler");
// test("thermostat"); test("thermostat");
test("2thermostats"); // test("2thermostats");
if (single) { if (single) {
// run dedicated tests only // run dedicated tests only
// EMSESP::webCustomEntityService.test(); // custom entities EMSESP::webCustomEntityService.test(); // custom entities
// EMSESP::webCustomizationService.test(); // set customizations - this will overwrite any settings in the FS EMSESP::webCustomizationService.test(); // set customizations - this will overwrite any settings in the FS
// EMSESP::temperaturesensor_.test(); // add temperature sensors EMSESP::temperaturesensor_.test(); // add temperature sensors
// EMSESP::webSchedulerService.test(); // run scheduler tests, and conditions EMSESP::webSchedulerService.test(); // run scheduler tests, and conditions
// request.url("/api/thermostat/commands"); shell.invoke_command("call system fetch");
request.url("/api/system/fetch");
EMSESP::webAPIService.webAPIService(&request);
// request.url("/api/system");
// EMSESP::webAPIService.webAPIService(&request);
// request.url("/api/system/system/version");
// EMSESP::webAPIService.webAPIService(&request);
// request.url("/api/system/bad");
// EMSESP::webAPIService.webAPIService(&request); // EMSESP::webAPIService.webAPIService(&request);
request.url("/api/thermostat/hc1/mode2"); // request.url("/api/boiler");
EMSESP::webAPIService.webAPIService(&request); // EMSESP::webAPIService.webAPIService(&request);
// request.url("/api/boiler/bad");
// EMSESP::webAPIService.webAPIService(&request);
request.url("/api/thermostat/hc2/mode"); // request.url("/api/custom");
EMSESP::webAPIService.webAPIService(&request); // EMSESP::webAPIService.webAPIService(&request);
// request.url("/api/custom/seltemp");
request.url("/api/thermostat/hc1/mode"); // EMSESP::webAPIService.webAPIService(&request);
EMSESP::webAPIService.webAPIService(&request); // request.url("/api/custom/bad");
// EMSESP::webAPIService.webAPIService(&request);
} else { } else {
EMSESP::webCustomEntityService.test(); // custom entities EMSESP::webCustomEntityService.test(); // custom entities
@@ -991,6 +1002,8 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
EMSESP::temperaturesensor_.test(); // add temperature sensors EMSESP::temperaturesensor_.test(); // add temperature sensors
EMSESP::webSchedulerService.test(); // run scheduler tests, and conditions EMSESP::webSchedulerService.test(); // run scheduler tests, and conditions
request.method(HTTP_GET);
// boiler // boiler
request.url("/api/boiler"); request.url("/api/boiler");
EMSESP::webAPIService.webAPIService(&request); EMSESP::webAPIService.webAPIService(&request);
@@ -1018,22 +1031,34 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
// custom // custom
request.url("/api/custom"); request.url("/api/custom");
EMSESP::webAPIService.webAPIService(&request); EMSESP::webAPIService.webAPIService(&request);
request.url("/api/custom/info");
EMSESP::webAPIService.webAPIService(&request);
request.url("/api/custom/seltemp"); request.url("/api/custom/seltemp");
EMSESP::webAPIService.webAPIService(&request); EMSESP::webAPIService.webAPIService(&request);
// system // system
request.url("/api/system"); request.url("/api/system");
EMSESP::webAPIService.webAPIService(&request); EMSESP::webAPIService.webAPIService(&request);
request.url("/api/system/info");
EMSESP::webAPIService.webAPIService(&request);
request.url("/api/system/settings/locale"); request.url("/api/system/settings/locale");
EMSESP::webAPIService.webAPIService(&request); EMSESP::webAPIService.webAPIService(&request);
request.url("/api/system/fetch");
EMSESP::webAPIService.webAPIService(&request);
// scheduler // scheduler
request.url("/api/scheduler");
EMSESP::webAPIService.webAPIService(&request);
request.url("/api/scheduler/info"); request.url("/api/scheduler/info");
EMSESP::webAPIService.webAPIService(&request); EMSESP::webAPIService.webAPIService(&request);
request.url("/api/scheduler/test_scheduler"); request.url("/api/scheduler/test_scheduler");
EMSESP::webAPIService.webAPIService(&request); EMSESP::webAPIService.webAPIService(&request);
// temperaturesensor // temperaturesensor
request.url("/api/temperaturesensor");
EMSESP::webAPIService.webAPIService(&request);
request.url("/api/temperaturesensor/info");
EMSESP::webAPIService.webAPIService(&request);
request.url("/api/temperaturesensor/test_sensor2"); request.url("/api/temperaturesensor/test_sensor2");
EMSESP::webAPIService.webAPIService(&request); EMSESP::webAPIService.webAPIService(&request);
request.url("/api/temperaturesensor/0B_0C0D_0E0F_1011"); request.url("/api/temperaturesensor/0B_0C0D_0E0F_1011");
@@ -1044,11 +1069,40 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
// analogsensor // analogsensor
request.url("/api/analogsensor"); request.url("/api/analogsensor");
EMSESP::webAPIService.webAPIService(&request); EMSESP::webAPIService.webAPIService(&request);
request.url("/api/analogsensor/info");
EMSESP::webAPIService.webAPIService(&request);
request.url("/api/analogsensor/test_analog1"); request.url("/api/analogsensor/test_analog1");
EMSESP::webAPIService.webAPIService(&request); EMSESP::webAPIService.webAPIService(&request);
request.url("/api/analogsensor/test_analog1/offset"); request.url("/api/analogsensor/test_analog1/offset");
EMSESP::webAPIService.webAPIService(&request); EMSESP::webAPIService.webAPIService(&request);
// system calls with POST
request.method(HTTP_POST);
// these next 3 should return empty JSON in their response
// but there will be a log message
char data[] = "{\"cmd\":\"send\",\"data\":\"0B 90 FF 13 01 01 B9 01\"}";
deserializeJson(doc, data);
json = doc.as<JsonVariant>();
request.url("/api/system");
EMSESP::webAPIService.webAPIService(&request, json);
char data2[] = "{\"device\":\"system\", \"cmd\":\"send\",\"value\":\"0B 90 FF 13 01 01 B9 02\"}";
deserializeJson(doc, data2);
json = doc.as<JsonVariant>();
request.url("/api");
EMSESP::webAPIService.webAPIService(&request, json);
char data4[] = "{\"value\":\"0B 90 FF 13 01 01 B9 03\"}";
deserializeJson(doc, data4);
json = doc.as<JsonVariant>();
request.url("/api/system/send");
EMSESP::webAPIService.webAPIService(&request, json);
// console commands
shell.invoke_command("call system fetch");
shell.invoke_command("call system send \"0B 90 FF 13 01 01 B9\"");
// //
// This next batch should all fail // This next batch should all fail
// //
@@ -1070,14 +1124,24 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
// system // system
request.url("/api/system/settings/locale2"); request.url("/api/system/settings/locale2");
EMSESP::webAPIService.webAPIService(&request); EMSESP::webAPIService.webAPIService(&request);
request.url("/api/system/settings2");
EMSESP::webAPIService.webAPIService(&request);
request.url("/api/system/settings2/locale2");
EMSESP::webAPIService.webAPIService(&request);
// scheduler // scheduler
request.url("/api/scheduler/test_scheduler2"); request.url("/api/scheduler/test_scheduler2");
EMSESP::webAPIService.webAPIService(&request); EMSESP::webAPIService.webAPIService(&request);
request.url("/api/scheduler/test_scheduler/val");
EMSESP::webAPIService.webAPIService(&request);
request.url("/api/scheduler/test_scheduler2/val2");
EMSESP::webAPIService.webAPIService(&request);
// custom // custom
request.url("/api/custom/seltemp2"); request.url("/api/custom/seltemp2");
EMSESP::webAPIService.webAPIService(&request); EMSESP::webAPIService.webAPIService(&request);
request.url("/api/custom/seltemp/val");
EMSESP::webAPIService.webAPIService(&request);
// temperaturesensor // temperaturesensor
request.url("/api/temperaturesensor/test_sensor20"); request.url("/api/temperaturesensor/test_sensor20");
@@ -1092,7 +1156,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
EMSESP::webAPIService.webAPIService(&request); EMSESP::webAPIService.webAPIService(&request);
request.url("/api/analogsensor/test_analog10"); request.url("/api/analogsensor/test_analog10");
EMSESP::webAPIService.webAPIService(&request); EMSESP::webAPIService.webAPIService(&request);
request.url("/api/analogsensor/test_analog10/bad"); request.url("/api/analogsensor/test_analog10/bad2");
EMSESP::webAPIService.webAPIService(&request); EMSESP::webAPIService.webAPIService(&request);
} }
} }

View File

@@ -1 +1 @@
#define EMSESP_APP_VERSION "3.7.0-dev.26" #define EMSESP_APP_VERSION "3.7.0-dev.27"

View File

@@ -55,8 +55,9 @@ void WebAPIService::webAPIService(AsyncWebServerRequest * request, JsonVariant j
// HTTP GET // HTTP GET
JsonDocument input_doc; // has no body JSON so create dummy as empty input object JsonDocument input_doc; // has no body JSON so create dummy as empty input object
input = input_doc.to<JsonObject>(); input = input_doc.to<JsonObject>();
} else { } else {
// HTTP_POST | HTTP_PUT | HTTP_PATCH // HTTP_POST
input = json.as<JsonObject>(); // extract values from the json. these will be used as default values input = json.as<JsonObject>(); // extract values from the json. these will be used as default values
} }
parse(request, input); parse(request, input);
@@ -134,7 +135,6 @@ void WebAPIService::parse(AsyncWebServerRequest * request, JsonObject input) {
if (api_data) { if (api_data) {
request->send(200, "text/plain; charset=utf-8", api_data); request->send(200, "text/plain; charset=utf-8", api_data);
#if defined(EMSESP_STANDALONE) #if defined(EMSESP_STANDALONE)
Serial.println();
Serial.printf("%sweb output: %s[%s] %s(200)%s ", COLOR_WHITE, COLOR_BRIGHT_CYAN, request->url().c_str(), COLOR_BRIGHT_GREEN, COLOR_MAGENTA); Serial.printf("%sweb output: %s[%s] %s(200)%s ", COLOR_WHITE, COLOR_BRIGHT_CYAN, request->url().c_str(), COLOR_BRIGHT_GREEN, COLOR_MAGENTA);
serializeJson(output, Serial); serializeJson(output, Serial);
Serial.println(COLOR_RESET); Serial.println(COLOR_RESET);
@@ -158,7 +158,6 @@ void WebAPIService::parse(AsyncWebServerRequest * request, JsonObject input) {
api_count_++; api_count_++;
#if defined(EMSESP_STANDALONE) #if defined(EMSESP_STANDALONE)
Serial.println();
Serial.printf("%sweb output: %s[%s]", COLOR_WHITE, COLOR_BRIGHT_CYAN, request->url().c_str()); Serial.printf("%sweb output: %s[%s]", COLOR_WHITE, COLOR_BRIGHT_CYAN, request->url().c_str());
Serial.printf(" %s(%d)%s ", ret_codes[return_code] == 200 ? COLOR_BRIGHT_GREEN : COLOR_BRIGHT_RED, ret_codes[return_code], COLOR_YELLOW); Serial.printf(" %s(%d)%s ", ret_codes[return_code] == 200 ? COLOR_BRIGHT_GREEN : COLOR_BRIGHT_RED, ret_codes[return_code], COLOR_YELLOW);
serializeJson(output, Serial); serializeJson(output, Serial);

View File

@@ -256,10 +256,12 @@ 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) {
// if it's commands... // check of it a 'commands' command
if (Helpers::toLower(cmd) == F_(commands)) { if (Helpers::toLower(cmd) == F_(commands)) {
output[F_(info)] = Helpers::translated_word(FL_(info_cmd)); output[F_(info)] = Helpers::translated_word(FL_(info_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));
for (const auto & entity : *customEntityItems_) { for (const auto & entity : *customEntityItems_) {
if (entity.writeable) { if (entity.writeable) {
output[entity.name] = "custom entity"; output[entity.name] = "custom entity";
@@ -325,7 +327,7 @@ bool WebCustomEntityService::get_value_info(JsonObject output, const char * cmd)
output["api_data"] = data; // always as string output["api_data"] = data; // always as string
return true; return true;
} }
return EMSESP::return_not_found(output, "attribute", command_s); // not found return EMSESP::return_not_found(output, attribute_s, command_s); // not found
} }
} }
@@ -334,7 +336,7 @@ bool WebCustomEntityService::get_value_info(JsonObject output, const char * cmd)
} }
} }
return EMSESP::return_not_found(output, cmd, F_(custom)); // not found return false; // not found
} }
// publish single value // publish single value

View File

@@ -239,8 +239,6 @@ void WebCustomizationService::writeDeviceName(AsyncWebServerRequest * request, J
uint8_t device_id = emsdevice->device_id(); uint8_t device_id = emsdevice->device_id();
auto custom_name = json["name"].as<std::string>(); auto custom_name = json["name"].as<std::string>();
// emsesp::EMSESP::logger().info("Found Device ID: %d, Product ID: %d", device_id, product_id);
// updates current record or creates a new one // updates current record or creates a new one
bool entry_exists = false; bool entry_exists = false;
update([&](WebCustomization & settings) { update([&](WebCustomization & settings) {

View File

@@ -245,7 +245,7 @@ void WebDataService::write_device_value(AsyncWebServerRequest * request, JsonVar
return_code = Command::call(device_type, cmd, data.as<bool>() ? "true" : "false", true, id, output); return_code = Command::call(device_type, cmd, data.as<bool>() ? "true" : "false", true, id, output);
} }
// write debug // write log
if (return_code != CommandRet::OK) { if (return_code != CommandRet::OK) {
EMSESP::logger().err("Write command failed %s (%s)", (const char *)output["message"], Command::return_code_string(return_code)); EMSESP::logger().err("Write command failed %s (%s)", (const char *)output["message"], Command::return_code_string(return_code));
} else { } else {

View File

@@ -136,6 +136,7 @@ bool WebSchedulerService::get_value_info(JsonObject output, const char * cmd) {
if (Helpers::toLower(cmd) == F_(commands)) { if (Helpers::toLower(cmd) == F_(commands)) {
output[F_(info)] = Helpers::translated_word(FL_(info_cmd)); output[F_(info)] = Helpers::translated_word(FL_(info_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));
for (const ScheduleItem & scheduleItem : *scheduleItems_) { for (const ScheduleItem & scheduleItem : *scheduleItems_) {
if (!scheduleItem.name.empty()) { if (!scheduleItem.name.empty()) {
@@ -196,21 +197,25 @@ bool WebSchedulerService::get_value_info(JsonObject output, const char * cmd) {
output["readable"] = true; output["readable"] = true;
output["writeable"] = true; output["writeable"] = true;
output["visible"] = true; output["visible"] = true;
break;
} }
} }
if (attribute_s && output.containsKey(attribute_s)) { if (attribute_s) {
std::string data = output[attribute_s].as<std::string>(); if (output.containsKey(attribute_s)) {
output.clear(); std::string data = output[attribute_s].as<std::string>();
output["api_data"] = data; // always as a string output.clear();
return true; 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()) { if (output.size()) {
return true; return true;
} }
return EMSESP::return_not_found(output, cmd, F_(scheduler)); // not found return false; // not found
} }
// publish single value // publish single value
@@ -604,7 +609,6 @@ void WebSchedulerService::test() {
test_value = "(custom/seltemp - boiler/flowtempoffset) * 2.8 + 5"; test_value = "(custom/seltemp - boiler/flowtempoffset) * 2.8 + 5";
command("test10", test_cmd.c_str(), compute(test_value).c_str()); command("test10", test_cmd.c_str(), compute(test_value).c_str());
// TODO add some more HTTP/URI tests
test_cmd = "{\"method\":\"POST\",\"url\":\"http://192.168.1.42:8123/api/services/script/test_notify2\", \"header\":{\"authorization\":\"Bearer " test_cmd = "{\"method\":\"POST\",\"url\":\"http://192.168.1.42:8123/api/services/script/test_notify2\", \"header\":{\"authorization\":\"Bearer "
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhMmNlYWI5NDgzMmI0ODE2YWQ2NzU4MjkzZDE2YWMxZSIsImlhdCI6MTcyMTM5MTI0NCwiZXhwIjoyMDM2NzUxMjQ0fQ." "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhMmNlYWI5NDgzMmI0ODE2YWQ2NzU4MjkzZDE2YWMxZSIsImlhdCI6MTcyMTM5MTI0NCwiZXhwIjoyMDM2NzUxMjQ0fQ."
"S5sago1tEI6lNhrDCO0dM_WsVQHkD_laAjcks8tWAqo\"}}"; "S5sago1tEI6lNhrDCO0dM_WsVQHkD_laAjcks8tWAqo\"}}";