diff --git a/.github/workflows/github-releases-to-discord.yml b/.github/workflows/github-releases-to-discord.yml index b73618f81..bad6e0917 100644 --- a/.github/workflows/github-releases-to-discord.yml +++ b/.github/workflows/github-releases-to-discord.yml @@ -9,16 +9,15 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Github Releases To Discord uses: SethCohen/github-releases-to-discord@v1.13.1 with: webhook_url: ${{ secrets.WEBHOOK_URL }} - color: "2105893" - username: "Release Changelog" - avatar_url: "https://cdn.discordapp.com/icons/816637840644505620/0b14718532d855c452903851b4f0c9a2.png" - content: "||@everyone||" - footer_title: "Changelog" - footer_icon_url: "https://cdn.discordapp.com/icons/816637840644505620/0b14718532d855c452903851b4f0c9a2.png" + color: '2105893' + username: 'Release Changelog' + avatar_url: 'https://cdn.discordapp.com/icons/816637840644505620/0b14718532d855c452903851b4f0c9a2.png' + content: '||@everyone||' + footer_title: 'Changelog' + footer_icon_url: 'https://cdn.discordapp.com/icons/816637840644505620/0b14718532d855c452903851b4f0c9a2.png' footer_timestamp: true - diff --git a/.github/workflows/pre_release.yml b/.github/workflows/pre_release.yml index 06c09b0ff..0f5e8d914 100644 --- a/.github/workflows/pre_release.yml +++ b/.github/workflows/pre_release.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-python@v4 with: python-version: '3.11' diff --git a/.github/workflows/sonar_check.yml b/.github/workflows/sonar_check.yml index a5777a8e7..fd7f73f3d 100644 --- a/.github/workflows/sonar_check.yml +++ b/.github/workflows/sonar_check.yml @@ -14,7 +14,7 @@ jobs: env: BUILD_WRAPPER_OUT_DIR: bw-output steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis - name: Install sonar-scanner and build-wrapper diff --git a/.github/workflows/tagged_release.yml b/.github/workflows/tagged_release.yml index a480a8bd5..b1ae80694 100644 --- a/.github/workflows/tagged_release.yml +++ b/.github/workflows/tagged_release.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-python@v4 with: python-version: '3.11' diff --git a/.github/workflows/test_release.yml b/.github/workflows/test_release.yml index d932ad6d4..e79684864 100644 --- a/.github/workflows/test_release.yml +++ b/.github/workflows/test_release.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-python@v4 with: python-version: '3.11' diff --git a/.vscode/settings.json b/.vscode/settings.json index 1b4c362dd..7039a6101 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -10,7 +10,6 @@ "eslint.nodePath": "interface/.yarn/sdks", "eslint.workingDirectories": ["interface"], "prettier.prettierPath": "", - "typescript.tsdk": "interface/.yarn/sdks/typescript/lib", "typescript.enablePromptUseWorkspaceTsdk": true, "files.associations": { "*.tsx": "typescriptreact", @@ -27,7 +26,51 @@ "type_traits": "cpp", "utility": "cpp", "string": "cpp", - "string_view": "cpp" + "string_view": "cpp", + "atomic": "cpp", + "bitset": "cpp", + "cctype": "cpp", + "chrono": "cpp", + "clocale": "cpp", + "cmath": "cpp", + "condition_variable": "cpp", + "cstdarg": "cpp", + "cstddef": "cpp", + "cstdint": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "ctime": "cpp", + "cwchar": "cpp", + "cwctype": "cpp", + "deque": "cpp", + "list": "cpp", + "unordered_map": "cpp", + "unordered_set": "cpp", + "vector": "cpp", + "exception": "cpp", + "algorithm": "cpp", + "iterator": "cpp", + "map": "cpp", + "memory": "cpp", + "memory_resource": "cpp", + "numeric": "cpp", + "random": "cpp", + "set": "cpp", + "fstream": "cpp", + "initializer_list": "cpp", + "iomanip": "cpp", + "iosfwd": "cpp", + "iostream": "cpp", + "limits": "cpp", + "mutex": "cpp", + "new": "cpp", + "sstream": "cpp", + "stdexcept": "cpp", + "streambuf": "cpp", + "thread": "cpp", + "cinttypes": "cpp", + "typeinfo": "cpp" }, "todo-tree.filtering.excludeGlobs": [ "**/vendor/**", diff --git a/CHANGELOG_LATEST.md b/CHANGELOG_LATEST.md index 88e087192..6508f8d8c 100644 --- a/CHANGELOG_LATEST.md +++ b/CHANGELOG_LATEST.md @@ -4,8 +4,7 @@ ## **IMPORTANT! BREAKING CHANGES** -- move dhw functions from mixer/solar to water -Writeable Text entities have moved from type `sensor` to `text` in Home Assistant to make them also editable within an HA dashboard. Examples are `datetime`, `holidays`, `switchtime`, `vacations`, `maintenancedate`...). You will need to manually remove any old discovery topics from your MQTT broker using an application like MQTT Explorer. +Writeable Text entities have moved from type `sensor` to `text` in Home Assistant to make them also editable within an HA dashboard. Examples are `datetime`, `holidays`, `switchtime`, `vacations`, `maintenancedate`... You will need to manually remove any old discovery topics from your MQTT broker using an application like MQTT Explorer. ## Added @@ -21,6 +20,7 @@ Writeable Text entities have moved from type `sensor` to `text` in Home Assistan - optional bssid in network settings - extension module EM100 [#1315](https://github.com/emsesp/EMS-ESP32/discussions/1315) - digital_out with new options for polarity and startup state +- Added 'system allvalues' command that dumps all the EMS device values, plus sensors and any custom entities ## Fixed diff --git a/interface/package.json b/interface/package.json index fcfeebe33..6c5ec7b0d 100644 --- a/interface/package.json +++ b/interface/package.json @@ -51,8 +51,8 @@ "devDependencies": { "@preact/compat": "^17.1.2", "@preact/preset-vite": "^2.6.0", - "@typescript-eslint/eslint-plugin": "^6.10.0", - "@typescript-eslint/parser": "^6.10.0", + "@typescript-eslint/eslint-plugin": "^6.11.0", + "@typescript-eslint/parser": "^6.11.0", "concurrently": "^8.2.2", "eslint": "^8.53.0", "eslint-config-airbnb": "^19.0.4", @@ -65,8 +65,8 @@ "eslint-plugin-prettier": "alpha", "eslint-plugin-react": "^7.33.2", "eslint-plugin-react-hooks": "^4.6.0", - "preact": "^10.18.2", - "prettier": "^3.0.3", + "preact": "^10.19.1", + "prettier": "^3.1.0", "rollup-plugin-visualizer": "^5.9.2", "terser": "^5.24.0", "vite": "^4.5.0", diff --git a/interface/yarn.lock b/interface/yarn.lock index 3e81772d7..db6d6cc23 100644 --- a/interface/yarn.lock +++ b/interface/yarn.lock @@ -1510,15 +1510,15 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/eslint-plugin@npm:^6.10.0": - version: 6.10.0 - resolution: "@typescript-eslint/eslint-plugin@npm:6.10.0" +"@typescript-eslint/eslint-plugin@npm:^6.11.0": + version: 6.11.0 + resolution: "@typescript-eslint/eslint-plugin@npm:6.11.0" dependencies: "@eslint-community/regexpp": "npm:^4.5.1" - "@typescript-eslint/scope-manager": "npm:6.10.0" - "@typescript-eslint/type-utils": "npm:6.10.0" - "@typescript-eslint/utils": "npm:6.10.0" - "@typescript-eslint/visitor-keys": "npm:6.10.0" + "@typescript-eslint/scope-manager": "npm:6.11.0" + "@typescript-eslint/type-utils": "npm:6.11.0" + "@typescript-eslint/utils": "npm:6.11.0" + "@typescript-eslint/visitor-keys": "npm:6.11.0" debug: "npm:^4.3.4" graphemer: "npm:^1.4.0" ignore: "npm:^5.2.4" @@ -1531,44 +1531,44 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 54fd83cff912bae212934aae5abcb810cf182771778e1062f2aaf75989d300c5f23bdb03b8b3d587ece799dfabebfdc5cf6356e1ce07398011d728a3d0d0d381 + checksum: c9c9e7a918e2f3ef8cb200c9158b70553a1014529867411b35e141c1d26713dd281907af1a231e640e8c4c73c3245a20cfc0e56a1cc95874889ce88c04706c78 languageName: node linkType: hard -"@typescript-eslint/parser@npm:^6.10.0": - version: 6.10.0 - resolution: "@typescript-eslint/parser@npm:6.10.0" +"@typescript-eslint/parser@npm:^6.11.0": + version: 6.11.0 + resolution: "@typescript-eslint/parser@npm:6.11.0" dependencies: - "@typescript-eslint/scope-manager": "npm:6.10.0" - "@typescript-eslint/types": "npm:6.10.0" - "@typescript-eslint/typescript-estree": "npm:6.10.0" - "@typescript-eslint/visitor-keys": "npm:6.10.0" + "@typescript-eslint/scope-manager": "npm:6.11.0" + "@typescript-eslint/types": "npm:6.11.0" + "@typescript-eslint/typescript-estree": "npm:6.11.0" + "@typescript-eslint/visitor-keys": "npm:6.11.0" debug: "npm:^4.3.4" peerDependencies: eslint: ^7.0.0 || ^8.0.0 peerDependenciesMeta: typescript: optional: true - checksum: d24a981807ea1ee5e5bbd9be2996b06eb99908c717464c6274b596c094b0e2609c1d88fcb8bef3479a8e8d39bc61a7103651b23981e47a5d89f6dec77e3bec38 + checksum: abb2aff0d4f06937337d1b2da77df4e1501d708b0bce1707c523206ee10e6aa732e1ae6548da56b9889459f23c375a6f0ae2e3a208e972dab8eb3b46680d839a languageName: node linkType: hard -"@typescript-eslint/scope-manager@npm:6.10.0": - version: 6.10.0 - resolution: "@typescript-eslint/scope-manager@npm:6.10.0" +"@typescript-eslint/scope-manager@npm:6.11.0": + version: 6.11.0 + resolution: "@typescript-eslint/scope-manager@npm:6.11.0" dependencies: - "@typescript-eslint/types": "npm:6.10.0" - "@typescript-eslint/visitor-keys": "npm:6.10.0" - checksum: 518cd60f9e9f5eef24f566f6a43d05241593a4520db6a93df714adac7b04b8bc2a1a89764f7a0aa23432e35e5f57ab2a3129f8f67ef211fa808c6bda29c28c78 + "@typescript-eslint/types": "npm:6.11.0" + "@typescript-eslint/visitor-keys": "npm:6.11.0" + checksum: 60702ab23710c59ab0b52ffc66f77e24382cec8f684e3e43d4269cc17f414d3cb3a3bb85e232ea9f1e0f7e85506529978a5eea3c08945c01ed7aed4d4997b472 languageName: node linkType: hard -"@typescript-eslint/type-utils@npm:6.10.0": - version: 6.10.0 - resolution: "@typescript-eslint/type-utils@npm:6.10.0" +"@typescript-eslint/type-utils@npm:6.11.0": + version: 6.11.0 + resolution: "@typescript-eslint/type-utils@npm:6.11.0" dependencies: - "@typescript-eslint/typescript-estree": "npm:6.10.0" - "@typescript-eslint/utils": "npm:6.10.0" + "@typescript-eslint/typescript-estree": "npm:6.11.0" + "@typescript-eslint/utils": "npm:6.11.0" debug: "npm:^4.3.4" ts-api-utils: "npm:^1.0.1" peerDependencies: @@ -1576,23 +1576,23 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: e4e5b119730fe615a60fb9118ab408a471dab11304a70d469393a0aac6d06238377cd87693129160c600b7a03804e2552d3a7192d291ea3db10d2390983b3628 + checksum: 478819bbbab39a0d11dc6276fc9b90e0b2576d7e32d761c811369657dc12bfaf95084bf951714ea82015259d736dec70770d229d6547b066ea0fc4133039082f languageName: node linkType: hard -"@typescript-eslint/types@npm:6.10.0": - version: 6.10.0 - resolution: "@typescript-eslint/types@npm:6.10.0" - checksum: bc8faf3d00f1d4eaad0760f64a7e428646e65adc5322f41dc9a2d15d5df23e53b09605d69126c373630851cb258c15ba82cf66d949897d3758844964b0e98087 +"@typescript-eslint/types@npm:6.11.0": + version: 6.11.0 + resolution: "@typescript-eslint/types@npm:6.11.0" + checksum: 3ea55101325950d9594f839b38aa1c0958c3b8401ca9a8d2e4247997bb30dff7ac5e760e888de48a3ea9af3cb656eafb3e2cddc837a523a300ebccb63e150185 languageName: node linkType: hard -"@typescript-eslint/typescript-estree@npm:6.10.0": - version: 6.10.0 - resolution: "@typescript-eslint/typescript-estree@npm:6.10.0" +"@typescript-eslint/typescript-estree@npm:6.11.0": + version: 6.11.0 + resolution: "@typescript-eslint/typescript-estree@npm:6.11.0" dependencies: - "@typescript-eslint/types": "npm:6.10.0" - "@typescript-eslint/visitor-keys": "npm:6.10.0" + "@typescript-eslint/types": "npm:6.11.0" + "@typescript-eslint/visitor-keys": "npm:6.11.0" debug: "npm:^4.3.4" globby: "npm:^11.1.0" is-glob: "npm:^4.0.3" @@ -1601,34 +1601,34 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 41fc6dd0cfe8fb4c7ddc30d91e71d23ea1e0cbc261e8022ab089ddde6589eefdb89f66492d2ab4ae20dd45f51657022d9278bccc64aef7c6be0df756a081c0b5 + checksum: 9d2333e517d50035f2c962b3966ebf8b35db0ac139c537cf4f1c4fd7b8d8914671671ad3bccdd59ef88fc4d29f441c0412a6c119ac6463bd2fbe8059d5209219 languageName: node linkType: hard -"@typescript-eslint/utils@npm:6.10.0": - version: 6.10.0 - resolution: "@typescript-eslint/utils@npm:6.10.0" +"@typescript-eslint/utils@npm:6.11.0": + version: 6.11.0 + resolution: "@typescript-eslint/utils@npm:6.11.0" dependencies: "@eslint-community/eslint-utils": "npm:^4.4.0" "@types/json-schema": "npm:^7.0.12" "@types/semver": "npm:^7.5.0" - "@typescript-eslint/scope-manager": "npm:6.10.0" - "@typescript-eslint/types": "npm:6.10.0" - "@typescript-eslint/typescript-estree": "npm:6.10.0" + "@typescript-eslint/scope-manager": "npm:6.11.0" + "@typescript-eslint/types": "npm:6.11.0" + "@typescript-eslint/typescript-estree": "npm:6.11.0" semver: "npm:^7.5.4" peerDependencies: eslint: ^7.0.0 || ^8.0.0 - checksum: acf55bc231483f8b8d2d64ad9a261d0499085277b5ce3506cf579297401f78d88253ae52a9afad35cc32a532b53794367e32449283c06b2e89602c63184f011e + checksum: 7b8c17bd191b06cc77fe341f32fb7b4126d47a6ec05e5112567d4424a1896cf851935ff867c825d7e3361c317a48fe5304f95e454089f9aecc182bd42b1e4176 languageName: node linkType: hard -"@typescript-eslint/visitor-keys@npm:6.10.0": - version: 6.10.0 - resolution: "@typescript-eslint/visitor-keys@npm:6.10.0" +"@typescript-eslint/visitor-keys@npm:6.11.0": + version: 6.11.0 + resolution: "@typescript-eslint/visitor-keys@npm:6.11.0" dependencies: - "@typescript-eslint/types": "npm:6.10.0" + "@typescript-eslint/types": "npm:6.11.0" eslint-visitor-keys: "npm:^3.4.1" - checksum: 17a6962e10ffbcc286d202c7dfcc0dfa489c76ab7838b3522e90b3e87cbe2cdd7a24ffab434d9ca6dfed361801f11c3349ba01f808093c65c5365a9179ee5eb0 + checksum: d89ef8579737f23a1a81506724e2c5cfec92fa4431232f93c4b6970a21382c6c0ad09ba21ffe8d25725d43aecce351fee2797c9170012ef0c00e5be7592e8233 languageName: node linkType: hard @@ -1658,8 +1658,8 @@ __metadata: "@types/react": "npm:^18.2.37" "@types/react-dom": "npm:^18.2.15" "@types/react-router-dom": "npm:^5.3.3" - "@typescript-eslint/eslint-plugin": "npm:^6.10.0" - "@typescript-eslint/parser": "npm:^6.10.0" + "@typescript-eslint/eslint-plugin": "npm:^6.11.0" + "@typescript-eslint/parser": "npm:^6.11.0" alova: "npm:^2.13.1" async-validator: "npm:^4.2.5" concurrently: "npm:^8.2.2" @@ -1678,8 +1678,8 @@ __metadata: jwt-decode: "npm:^4.0.0" lodash-es: "npm:^4.17.21" mime-types: "npm:^2.1.35" - preact: "npm:^10.18.2" - prettier: "npm:^3.0.3" + preact: "npm:^10.19.1" + prettier: "npm:^3.1.0" react: "npm:latest" react-dom: "npm:latest" react-dropzone: "npm:^14.2.3" @@ -6758,10 +6758,10 @@ __metadata: languageName: node linkType: hard -"preact@npm:^10.18.2": - version: 10.18.2 - resolution: "preact@npm:10.18.2" - checksum: c7dcd6ea812adb0bdc215366b14aadc44724b6dd6c4e9aadd986126d94abde62f3e02e18d6157a9984873be9877f206c0afa10a09346178c4c828a103a66a0e1 +"preact@npm:^10.19.1": + version: 10.19.1 + resolution: "preact@npm:10.19.1" + checksum: 1dce5b00d9031aca2266ef64cc38b27a4696f1c4d78baecc1f66a9bf2798c022a792b97257d64db450723edb69c12bc967e993d3b516734eff57895b9258c419 languageName: node linkType: hard @@ -6795,12 +6795,12 @@ __metadata: languageName: node linkType: hard -"prettier@npm:^3.0.3": - version: 3.0.3 - resolution: "prettier@npm:3.0.3" +"prettier@npm:^3.1.0": + version: 3.1.0 + resolution: "prettier@npm:3.1.0" bin: prettier: bin/prettier.cjs - checksum: ccf1ead9794b017be6b42d0873f459070beef2069eb393c8b4c0d11aa3430acefc54f6d5f44a5b7ce9af05ad8daf694b912f0aa2808d1c22dfa86e61e9d563f8 + checksum: e95e8f93c6b9aea2ac1e86bebe329bee90c8c50d9a23d1f593eba8d7f39b33b3641eb28785001505b6723c47895a5322ad12a2fb855b289cb7bae450ffc34425 languageName: node linkType: hard diff --git a/src/analogsensor.cpp b/src/analogsensor.cpp index eba7393e7..b94cb2c6d 100644 --- a/src/analogsensor.cpp +++ b/src/analogsensor.cpp @@ -616,7 +616,8 @@ void AnalogSensor::publish_values(const bool force) { } JsonObject dev = config.createNestedObject("dev"); - JsonArray ids = dev.createNestedArray("ids"); + dev["name"] = name; + JsonArray ids = dev.createNestedArray("ids"); ids.add(Mqtt::basename()); // add "availability" section diff --git a/src/analogsensor.h b/src/analogsensor.h index 132b20e50..b33fb1137 100644 --- a/src/analogsensor.h +++ b/src/analogsensor.h @@ -156,6 +156,9 @@ class AnalogSensor { bool get_value_info(JsonObject & output, const char * cmd, const int8_t id) const; void store_counters(); + bool command_info(const char * value, const int8_t id, JsonObject & output) const; + + #if defined(EMSESP_TEST) void test(); #endif @@ -169,7 +172,6 @@ class AnalogSensor { void remove_ha_topic(const int8_t type, const uint8_t id) const; bool command_setvalue(const char * value, const int8_t gpio); void measure(); - bool command_info(const char * value, const int8_t id, JsonObject & output) const; bool command_commands(const char * value, const int8_t id, JsonObject & output); std::vector sensors_; // our list of sensors diff --git a/src/command.cpp b/src/command.cpp index 353b17763..46a6d7673 100644 --- a/src/command.cpp +++ b/src/command.cpp @@ -510,7 +510,7 @@ void Command::show(uuid::console::Shell & shell, uint8_t device_type, bool verbo } shell.print(cl); // pad with spaces - while (i++ < 22) { + while (i++ < 30) { shell.print(' '); } shell.print(COLOR_BRIGHT_CYAN); @@ -521,7 +521,7 @@ void Command::show(uuid::console::Shell & shell, uint8_t device_type, bool verbo shell.print(Helpers::translated_word(cf.description_)); if (!cf.has_flags(CommandFlag::ADMIN_ONLY)) { shell.print(' '); - shell.print(COLOR_BRIGHT_RED); + shell.print(COLOR_BRIGHT_GREEN); shell.print('*'); } shell.print(COLOR_RESET); @@ -601,7 +601,7 @@ void Command::show_devices(uuid::console::Shell & shell) { // output list of all commands to console // calls show with verbose mode set void Command::show_all(uuid::console::Shell & shell) { - shell.println("Available commands (*=authorization not required): "); + shell.printfln("Showing all available commands (%s*%s=authentication not required):", COLOR_BRIGHT_GREEN, COLOR_RESET); // show system first shell.print(COLOR_BOLD_ON); @@ -615,9 +615,9 @@ void Command::show_all(uuid::console::Shell & shell) { shell.print(COLOR_YELLOW); shell.printf(" %s: ", EMSdevice::device_type_2_device_name(EMSdevice::DeviceType::CUSTOM)); shell.println(COLOR_RESET); - shell.printf(" info: %slists all values %s*", COLOR_BRIGHT_CYAN, COLOR_BRIGHT_RED); + shell.printf(" info:\t\t\t\t%slists all values %s*", COLOR_BRIGHT_CYAN, COLOR_BRIGHT_GREEN); shell.println(COLOR_RESET); - shell.printf(" commands: %slists all commands %s*", COLOR_BRIGHT_CYAN, COLOR_BRIGHT_RED); + shell.printf(" commands:\t\t\t%slists all commands %s*", COLOR_BRIGHT_CYAN, COLOR_BRIGHT_GREEN); shell.print(COLOR_RESET); show(shell, EMSdevice::DeviceType::CUSTOM, true); @@ -626,9 +626,9 @@ void Command::show_all(uuid::console::Shell & shell) { shell.print(COLOR_YELLOW); shell.printf(" %s: ", EMSdevice::device_type_2_device_name(EMSdevice::DeviceType::SCHEDULER)); shell.println(COLOR_RESET); - shell.printf(" info: %slists all values %s*", COLOR_BRIGHT_CYAN, COLOR_BRIGHT_RED); + shell.printf(" info:\t\t\t\t%slists all values %s*", COLOR_BRIGHT_CYAN, COLOR_BRIGHT_GREEN); shell.println(COLOR_RESET); - shell.printf(" commands: %slists all commands %s*", COLOR_BRIGHT_CYAN, COLOR_BRIGHT_RED); + shell.printf(" commands:\t\t\t%slists all commands %s*", COLOR_BRIGHT_CYAN, COLOR_BRIGHT_GREEN); shell.print(COLOR_RESET); show(shell, EMSdevice::DeviceType::SCHEDULER, true); diff --git a/src/console.cpp b/src/console.cpp index 6d0c07c48..e74ecded8 100644 --- a/src/console.cpp +++ b/src/console.cpp @@ -348,15 +348,6 @@ static void setup_commands(std::shared_ptr & commands) { "local"); }); - commands->add_command(ShellContext::MAIN, CommandFlags::USER, string_vector{F_(set)}, [](Shell & shell, const std::vector & arguments) { - to_app(shell).webSettingsService.read([&](WebSettings & settings) { - shell.printfln("Language: %s", settings.locale.c_str()); - shell.printfln(F_(tx_mode_fmt), settings.tx_mode); - shell.printfln(F_(bus_id_fmt), settings.ems_bus_id); - shell.printfln(F_(board_profile_fmt), settings.board_profile.c_str()); - }); - }); - // // EMS device commands // @@ -609,12 +600,13 @@ void EMSESPShell::stopped() { // show welcome banner void EMSESPShell::display_banner() { println(); - printfln("┌────────────────────────────────────────┐"); - printfln("│ %sEMS-ESP version %-12s%s │", COLOR_BOLD_ON, EMSESP_APP_VERSION, COLOR_BOLD_OFF); - printfln("│ %s%shttps://github.com/emsesp/EMS-ESP32%s │", COLOR_BRIGHT_GREEN, COLOR_UNDERLINE, COLOR_RESET); - printfln("│ │"); - printfln("│ type %shelp%s to show available commands │", COLOR_UNDERLINE, COLOR_RESET); - printfln("└────────────────────────────────────────┘"); + printfln("┌───────────────────────────────────────┐"); + printfln("│ %sEMS-ESP version %-12s%s │", COLOR_BOLD_ON, EMSESP_APP_VERSION, COLOR_BOLD_OFF); + printfln("│ %s%shttps://github.com/emsesp/EMS-ESP32%s │", COLOR_BRIGHT_GREEN, COLOR_UNDERLINE, COLOR_RESET); + printfln("│ │"); + printfln("│ type %shelp%s to show available commands │", COLOR_UNDERLINE, COLOR_RESET); + printfln("│ use %ssu%s to access Admin commands │", COLOR_UNDERLINE, COLOR_RESET); + printfln("└───────────────────────────────────────┘"); println(); // set console name diff --git a/src/emsdevice.cpp b/src/emsdevice.cpp index 8f9b14cc5..2a75662fd 100644 --- a/src/emsdevice.cpp +++ b/src/emsdevice.cpp @@ -827,29 +827,9 @@ void EMSdevice::publish_value(void * value_p) const { } // looks up the UOM for a given key from the device value table -// key is the fullname -std::string EMSdevice::get_value_uom(const char * key) const { - // the key may have a TAG string prefixed at the beginning. If so, remove it - char new_key[80]; - strlcpy(new_key, key, sizeof(new_key)); - char * key_p = new_key; - - for (uint8_t i = 0; i < DeviceValue::NUM_TAGS; i++) { - auto tag = Helpers::translated_word(DeviceValue::DeviceValueTAG_s[i]); - if (tag) { - std::string key2 = key; // copy string to a std::string so we can use the find function - uint8_t length = strlen(tag); - if ((key2.find(tag) != std::string::npos) && (key[length] == ' ')) { - key_p += length + 1; // remove the tag - break; - } - } - } - - // look up key in our device value list +std::string EMSdevice::get_value_uom(const std::string & shortname) const { for (const auto & dv : devicevalues_) { - auto fullname = dv.get_fullname(); - if ((!dv.has_state(DeviceValueState::DV_WEB_EXCLUDE) && !fullname.empty()) && (fullname == key_p)) { + if ((!dv.has_state(DeviceValueState::DV_WEB_EXCLUDE)) && (dv.short_name == shortname)) { // ignore TIME since "minutes" is already added to the string value if ((dv.uom == DeviceValueUOM::NONE) || (dv.uom == DeviceValueUOM::MINUTES)) { break; @@ -861,6 +841,43 @@ std::string EMSdevice::get_value_uom(const char * key) const { return std::string{}; // not found } +bool EMSdevice::export_values(uint8_t device_type, JsonObject & output, const int8_t id, const uint8_t output_target) { + bool has_value = false; + uint8_t tag; + if (id >= 1 && id <= (1 + DeviceValueTAG::TAG_HS16 - DeviceValueTAG::TAG_HC1)) { + tag = DeviceValueTAG::TAG_HC1 + id - 1; // this sets also WWC and HS + } else if (id == -1 || id == 0) { + tag = DeviceValueTAG::TAG_NONE; + } else { + return false; + } + + if (id > 0 || output_target == EMSdevice::OUTPUT_TARGET::API_VERBOSE) { + for (const auto & emsdevice : EMSESP::emsdevices) { + if (emsdevice && (emsdevice->device_type() == device_type)) { + has_value |= emsdevice->generate_values(output, tag, (id < 1), output_target); // use nested for id -1 and 0 + } + } + return has_value; + } + + // for nested output add for each tag + for (tag = DeviceValueTAG::TAG_BOILER_DATA_WW; tag <= DeviceValueTAG::TAG_HS16; tag++) { + JsonObject output_hc = output; + bool nest_created = false; + for (const auto & emsdevice : EMSESP::emsdevices) { + if (emsdevice && (emsdevice->device_type() == device_type)) { + if (!nest_created && emsdevice->has_tags(tag)) { + output_hc = output.createNestedObject(EMSdevice::tag_to_mqtt(tag)); + nest_created = true; + } + has_value |= emsdevice->generate_values(output_hc, tag, true, output_target); // use nested for id -1 and 0 + } + } + } + return has_value; +} + // prepare array of device values used for the WebUI // this is loosely based of the function generate_values used for the MQTT and Console // except additional data is stored in the JSON document needed for the Web UI like the UOM and command diff --git a/src/emsdevice.h b/src/emsdevice.h index d0133c2bc..c022c8e78 100644 --- a/src/emsdevice.h +++ b/src/emsdevice.h @@ -47,12 +47,13 @@ class EMSdevice { // static functions, used outside the class like in console.cpp, command.cpp, emsesp.cpp, mqtt.cpp static const char * device_type_2_device_name(const uint8_t device_type); static uint8_t device_name_2_device_type(const char * topic); - static const char * tag_to_string(uint8_t tag, const bool translate = true); static const char * uom_to_string(uint8_t uom); static const char * tag_to_mqtt(uint8_t tag); + static uint8_t decode_brand(uint8_t value); + static bool export_values(uint8_t device_type, JsonObject & output, const int8_t id, const uint8_t output_target); - static uint8_t decode_brand(uint8_t value); + // non static const char * device_type_name(); // returns short non-translated device type name const char * device_type_2_device_name_translated(); // returns translated device type name @@ -213,9 +214,10 @@ class EMSdevice { void register_telegram_type(const uint16_t telegram_type_id, const char * telegram_type_name, bool fetch, const process_function_p cb); bool handle_telegram(std::shared_ptr telegram); - std::string get_value_uom(const char * key) const; - bool get_value_info(JsonObject & root, const char * cmd, const int8_t id); - void get_dv_info(JsonObject & json); + std::string get_value_uom(const std::string & shortname) const; + + bool get_value_info(JsonObject & root, const char * cmd, const int8_t id); + void get_dv_info(JsonObject & json); enum OUTPUT_TARGET : uint8_t { API_VERBOSE, API_SHORTNAMES, MQTT, CONSOLE }; bool generate_values(JsonObject & output, const uint8_t tag_filter, const bool nested, const uint8_t output_target); diff --git a/src/emsesp.cpp b/src/emsesp.cpp index fe73b1d5c..7c75e0025 100644 --- a/src/emsesp.cpp +++ b/src/emsesp.cpp @@ -386,28 +386,32 @@ void EMSESP::show_device_values(uuid::console::Shell & shell) { // print line for (JsonPair p : json) { - const char * key = p.key().c_str(); - shell.printf(" %s: ", key); - JsonVariant data = p.value(); - shell.print(COLOR_BRIGHT_GREEN); - shell.print(data.as()); - // if there is a uom print it - std::string uom = emsdevice->get_value_uom(key); - if (uom == "°C" && EMSESP::system_.fahrenheit()) { - uom = "°F"; - } - if (!uom.empty()) { - shell.print(' '); - shell.print(uom); - } + std::string key = p.key().c_str(); // this will be fullname and the shortname in brackets - shell.print(COLOR_RESET); - shell.println(); + // extract the shortname from the key, which is in brackets + std::size_t first_bracket = key.find_last_of('('); + std::size_t last_bracket = key.find_last_of(')'); + std::string shortname = key.substr(first_bracket + 1, last_bracket - first_bracket - 1); + std::string uom = emsdevice->get_value_uom(key.substr(first_bracket + 1, last_bracket - first_bracket - 1)); + + shell.printfln(" %s: %s%s %s%s", key.c_str(), COLOR_BRIGHT_GREEN, p.value().as().c_str(), uom.c_str(), COLOR_RESET); } shell.println(); } } } + + // show any custom entities + if (webCustomEntityService.count_entities() > 0) { + shell.printfln("Custom entities:"); + StaticJsonDocument custom_doc; // use max size + JsonObject custom_output = custom_doc.to(); + webCustomEntityService.show_values(custom_output); + for (JsonPair p : custom_output) { + shell.printfln(" %s: %s%s%s", p.key().c_str(), COLOR_BRIGHT_GREEN, p.value().as().c_str(), COLOR_RESET); + } + shell.println(); + } } // show temperature sensors and Analog sensors @@ -1174,14 +1178,17 @@ bool EMSESP::add_device(const uint8_t device_id, const uint8_t product_id, const device_type, F_(info), [device_type](const char * value, const int8_t id, JsonObject & output) { - return command_info(device_type, output, id, EMSdevice::OUTPUT_TARGET::API_VERBOSE); + 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 command_info(device_type, output, id, EMSdevice::OUTPUT_TARGET::API_SHORTNAMES); // HIDDEN command showing short names, used in e.g. /api/boiler + return EMSdevice::export_values(device_type, + output, + id, + EMSdevice::OUTPUT_TARGET::API_SHORTNAMES); // HIDDEN command showing short names, used in e.g. /api/boiler }, nullptr, CommandFlag::HIDDEN); // this command is hidden @@ -1222,43 +1229,6 @@ bool EMSESP::command_commands(uint8_t device_type, JsonObject & output, const in return Command::list(device_type, output); } -// export all values for a specific device -bool EMSESP::command_info(uint8_t device_type, JsonObject & output, const int8_t id, const uint8_t output_target) { - bool has_value = false; - uint8_t tag; - if (id >= 1 && id <= (1 + DeviceValueTAG::TAG_HS16 - DeviceValueTAG::TAG_HC1)) { - tag = DeviceValueTAG::TAG_HC1 + id - 1; // this sets also WWC and HS - } else if (id == -1 || id == 0) { - tag = DeviceValueTAG::TAG_NONE; - } else { - return false; - } - - if (id > 0 || output_target == EMSdevice::OUTPUT_TARGET::API_VERBOSE) { - for (const auto & emsdevice : emsdevices) { - if (emsdevice && (emsdevice->device_type() == device_type)) { - has_value |= emsdevice->generate_values(output, tag, (id < 1), output_target); // use nested for id -1 and 0 - } - } - return has_value; - } - // for nested output add for each tag - for (tag = DeviceValueTAG::TAG_BOILER_DATA_WW; tag <= DeviceValueTAG::TAG_HS16; tag++) { - JsonObject output_hc = output; - bool nest_created = false; - for (const auto & emsdevice : emsdevices) { - if (emsdevice && (emsdevice->device_type() == device_type)) { - if (!nest_created && emsdevice->has_tags(tag)) { - output_hc = output.createNestedObject(EMSdevice::tag_to_mqtt(tag)); - nest_created = true; - } - has_value |= emsdevice->generate_values(output_hc, tag, true, output_target); // use nested for id -1 and 0 - } - } - } - return has_value; -} - // 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) { txservice_.read_request(type_id, dest, offset, length, front); diff --git a/src/emsesp.h b/src/emsesp.h index 30634c103..e5d074460 100644 --- a/src/emsesp.h +++ b/src/emsesp.h @@ -245,7 +245,6 @@ class EMSESP { static void process_version(std::shared_ptr telegram); static void publish_response(std::shared_ptr telegram); static void publish_all_loop(); - static bool command_info(uint8_t device_type, JsonObject & output, const int8_t id, const uint8_t output_target); 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); diff --git a/src/locale_common.h b/src/locale_common.h index 3049b6f54..86b10f48a 100644 --- a/src/locale_common.h +++ b/src/locale_common.h @@ -125,7 +125,6 @@ MAKE_WORD_CUSTOM(EMSESP, "EMS-ESP") MAKE_WORD_CUSTOM(host_fmt, "Host: %s") MAKE_WORD_CUSTOM(port_fmt, "Port: %d") MAKE_WORD_CUSTOM(hostname_fmt, "Hostname: %s") -MAKE_WORD_CUSTOM(board_profile_fmt, "Board Profile: %s") MAKE_WORD_CUSTOM(mark_interval_fmt, "Mark interval: %lus") MAKE_WORD_CUSTOM(wifi_ssid_fmt, "WiFi SSID: %s") MAKE_WORD_CUSTOM(wifi_password_fmt, "WiFi Password: %S") diff --git a/src/locale_translations.h b/src/locale_translations.h index f9df8f01d..d0f4c9341 100644 --- a/src/locale_translations.h +++ b/src/locale_translations.h @@ -58,7 +58,6 @@ MAKE_WORD_TRANSLATION(water_device, "Water Module", "Wassermodul", "", "", "Modu MAKE_WORD_TRANSLATION(pool_device, "Pool Module", "Poolmodul", "", "", "Moduł basenu", "", "", "", "") // TODO translate // commands -// TODO translate MAKE_WORD_TRANSLATION(info_cmd, "lists 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") // TODO translate MAKE_WORD_TRANSLATION(commands_cmd, "lists 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") // TODO translate MAKE_WORD_TRANSLATION(entities_cmd, "lists 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à") // TODO translate @@ -74,6 +73,7 @@ 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") // TODO translate MAKE_WORD_TRANSLATION(commands_response, "get response","Hole Antwort","Verzoek om antwoord", "", "", "", "uzyskaj odpowiedź", "", "", "gelen cevap", "") // TODO translate MAKE_WORD_TRANSLATION(coldshot_cmd, "send a cold shot of water", "", "", "", "uruchom tryśnięcie zimnej wody", "", "", "soğuk su gönder", "") // TODO translate +MAKE_WORD_TRANSLATION(allvalues_cmd, "output all values", "", "", "", "", "", "", "", "") // TODO translate // tags MAKE_WORD_TRANSLATION(tag_boiler_data_ww, "dhw", "WW", "dhw", "VV", "CWU", "dhw", "ecs", "SKS", "dhw") diff --git a/src/mqtt.cpp b/src/mqtt.cpp index c3066354f..178eb902b 100644 --- a/src/mqtt.cpp +++ b/src/mqtt.cpp @@ -745,21 +745,24 @@ bool Mqtt::queue_ha(const char * topic, const JsonObject & payload) { bool Mqtt::publish_ha_sensor_config(DeviceValue & dv, const char * model, const char * brand, const bool remove, const bool create_device_config) { StaticJsonDocument dev_json; - // always create the ids + // always create the ids (discovery indentifiers) + // with the name always + // and the manufacturer and model if we're creating the device config for the first entity JsonArray ids = dev_json.createNestedArray("ids"); char ha_device[40]; auto device_type_name = EMSdevice::device_type_2_device_name(dv.device_type); snprintf(ha_device, sizeof(ha_device), "%s-%s", Mqtt::basename().c_str(), device_type_name); ids.add(ha_device); + auto cap_name = strdup(device_type_name); + Helpers::CharToUpperUTF8(cap_name); // capitalize first letter + dev_json["name"] = Mqtt::basename() + " " + cap_name; + free(cap_name); + if (create_device_config) { - auto cap_name = strdup(device_type_name); - Helpers::CharToUpperUTF8(cap_name); // capitalize first letter - dev_json["name"] = Mqtt::basename() + " " + cap_name; dev_json["mf"] = brand; dev_json["mdl"] = model; dev_json["via_device"] = "ems-esp"; - free(cap_name); } // calculate the min and max @@ -794,7 +797,8 @@ bool Mqtt::publish_system_ha_sensor_config(uint8_t type, const char * name, cons StaticJsonDocument doc; JsonObject dev_json = doc.createNestedObject("dev"); - JsonArray ids = dev_json.createNestedArray("ids"); + dev_json["name"] = Mqtt::basename(); + JsonArray ids = dev_json.createNestedArray("ids"); ids.add(Mqtt::basename()); return publish_ha_sensor_config( @@ -1261,6 +1265,9 @@ bool Mqtt::publish_ha_climate_config(const uint8_t tag, const bool has_roomtemp, snprintf(ha_device, sizeof(ha_device), "%s-thermostat", Mqtt::basename().c_str()); ids.add(ha_device); + // device name must be different to the entity name, take the ids value we just created + dev["name"] = ha_device; + // add "availability" section add_avty_to_doc(topic_t, doc.as(), seltemp_cond, has_roomtemp ? currtemp_cond : nullptr, hc_mode_cond); diff --git a/src/shower.cpp b/src/shower.cpp index d95c97e3c..cea52509e 100644 --- a/src/shower.cpp +++ b/src/shower.cpp @@ -211,7 +211,8 @@ void Shower::set_shower_state(bool state, bool force) { } JsonObject dev = doc.createNestedObject("dev"); - JsonArray ids = dev.createNestedArray("ids"); + dev["name"] = "EMS-ESP"; + JsonArray ids = dev.createNestedArray("ids"); ids.add(Mqtt::basename()); Mqtt::add_avty_to_doc(stat_t, doc.as()); // add "availability" section @@ -240,7 +241,8 @@ void Shower::set_shower_state(bool state, bool force) { doc["ent_cat"] = "diagnostic"; JsonObject dev2 = doc.createNestedObject("dev"); - JsonArray ids2 = dev2.createNestedArray("ids"); + dev2["name"] = "EMS-ESP"; + JsonArray ids2 = dev2.createNestedArray("ids"); ids2.add(Mqtt::basename()); Mqtt::add_avty_to_doc(stat_t, doc.as(), "value_json.duration is defined"); // add "availability" section @@ -266,7 +268,8 @@ void Shower::set_shower_state(bool state, bool force) { doc["ent_cat"] = "diagnostic"; JsonObject dev3 = doc.createNestedObject("dev"); - JsonArray ids3 = dev3.createNestedArray("ids"); + dev3["name"] = "EMS-ESP"; + JsonArray ids3 = dev3.createNestedArray("ids"); ids3.add(Mqtt::basename()); Mqtt::add_avty_to_doc(stat_t, doc.as(), "value_json.timestamp is defined"); // add "availability" section diff --git a/src/system.cpp b/src/system.cpp index c6c9fe98d..dfcbb0f97 100644 --- a/src/system.cpp +++ b/src/system.cpp @@ -106,6 +106,35 @@ bool System::command_response(const char * value, const int8_t id, JsonObject & return true; } +// output all the EMS devices and their values, plus the sensors and any custom entities +// not scheduler as these are records with no output data +bool System::command_allvalues(const char * value, const int8_t id, JsonObject & output) { + DynamicJsonDocument doc(EMSESP_JSON_SIZE_XXXLARGE); + JsonObject device_output; + + for (const auto & device_class : EMSFactory::device_handlers()) { + for (const auto & emsdevice : EMSESP::emsdevices) { + if (emsdevice->device_type() == device_class.first) { + std::string title = emsdevice->device_type_2_device_name_translated() + std::string(" ") + emsdevice->to_string(); + device_output = output.createNestedObject(title); + emsesp::EMSdevice::export_values(emsdevice->device_type(), device_output, id, EMSdevice::OUTPUT_TARGET::API_VERBOSE); + } + } + } + + // Custom entities + device_output = output.createNestedObject("Custom Entities"); + EMSESP::webCustomEntityService.get_value_info(device_output, ""); + + // Sensors + device_output = output.createNestedObject("Analog Sensors"); + EMSESP::analogsensor_.command_info(nullptr, 0, device_output); + device_output = output.createNestedObject("Temperature Sensors"); + EMSESP::temperaturesensor_.command_info(nullptr, 0, device_output); + + return true; +} + // fetch device values bool System::command_fetch(const char * value, const int8_t id) { std::string value_s; @@ -767,6 +796,7 @@ void System::commands_init() { // restart and watch (and test) are also exposed as Console commands Command::add(EMSdevice::DeviceType::SYSTEM, F_(restart), System::command_restart, FL_(restart_cmd), CommandFlag::ADMIN_ONLY); Command::add(EMSdevice::DeviceType::SYSTEM, F_(watch), System::command_watch, FL_(watch_cmd)); + #if defined(EMSESP_TEST) Command::add(EMSdevice::DeviceType::SYSTEM, ("test"), System::command_test, FL_(test_cmd)); #endif @@ -775,6 +805,8 @@ void System::commands_init() { 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("allvalues"), System::command_allvalues, FL_(allvalues_cmd)); + // MQTT subscribe "ems-esp/system/#" Mqtt::subscribe(EMSdevice::DeviceType::SYSTEM, "system/#", nullptr); // use empty function callback @@ -906,6 +938,8 @@ void System::show_system(uuid::console::Shell & shell) { refreshHeapMem(); // refresh free heap and max alloc heap shell.println("System:"); + shell.printfln(" Version: %s", EMSESP_APP_VERSION); + shell.printfln(" Language: %s", locale().c_str()); shell.printfln(" Board profile: %s", board_profile().c_str()); shell.printfln(" Uptime: %s", uuid::log::format_timestamp_ms(uuid::get_uptime_ms(), 3).c_str()); #ifndef EMSESP_STANDALONE diff --git a/src/system.h b/src/system.h index 9d8e756e4..bf8f5c237 100644 --- a/src/system.h +++ b/src/system.h @@ -60,6 +60,8 @@ class System { 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_allvalues(const char * value, const int8_t id, JsonObject & output); + #if defined(EMSESP_TEST) static bool command_test(const char * value, const int8_t id); #endif diff --git a/src/temperaturesensor.cpp b/src/temperaturesensor.cpp index 42dfc8544..3f91c463c 100644 --- a/src/temperaturesensor.cpp +++ b/src/temperaturesensor.cpp @@ -544,7 +544,8 @@ void TemperatureSensor::publish_values(const bool force) { config["name"] = name; JsonObject dev = config.createNestedObject("dev"); - JsonArray ids = dev.createNestedArray("ids"); + dev["name"] = Mqtt::basename(); + JsonArray ids = dev.createNestedArray("ids"); ids.add(Mqtt::basename()); // add "availability" section diff --git a/src/temperaturesensor.h b/src/temperaturesensor.h index 353b8f8fa..3d7363054 100644 --- a/src/temperaturesensor.h +++ b/src/temperaturesensor.h @@ -111,6 +111,8 @@ class TemperatureSensor { bool update(const std::string & id, const std::string & name, int16_t offset); + bool command_info(const char * value, const int8_t id, JsonObject & output); + #if defined(EMSESP_TEST) void test(); #endif @@ -152,7 +154,6 @@ class TemperatureSensor { uint64_t get_id(const uint8_t addr[]); void remove_ha_topic(const std::string & id); - bool command_info(const char * value, const int8_t id, JsonObject & output); bool command_commands(const char * value, const int8_t id, JsonObject & output); std::vector sensors_; // our list of active sensors diff --git a/src/test/test.cpp b/src/test/test.cpp index 0ba654b85..f993854a2 100644 --- a/src/test/test.cpp +++ b/src/test/test.cpp @@ -275,11 +275,17 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const bool ok = false; if (command == "general") { - shell.printfln("Testing adding a general boiler & thermostat..."); + shell.printfln("Testing adding a boiler, thermostat and sensors..."); run_test("general"); + + // add sensors + emsesp::EMSESP::analogsensor_.test(); + emsesp::EMSESP::temperaturesensor_.test(); + // shell.invoke_command("show devices"); shell.invoke_command("show values"); - shell.invoke_command("call system publish"); + shell.invoke_command("call system allvalues"); + // shell.invoke_command("call system publish"); // shell.invoke_command("show mqtt"); ok = true; } diff --git a/src/uart/emsuart_esp32.cpp b/src/uart/emsuart_esp32.cpp index 6055ac3c4..cbe01b288 100644 --- a/src/uart/emsuart_esp32.cpp +++ b/src/uart/emsuart_esp32.cpp @@ -34,6 +34,7 @@ namespace emsesp { static QueueHandle_t uart_queue; uint8_t tx_mode_ = 0xFF; +uint32_t inverse_mask = 0; /* * receive task, wait for break and call incoming_telegram @@ -82,8 +83,15 @@ void EMSuart::start(const uint8_t tx_mode, const uint8_t rx_gpio, const uint8_t .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, .source_clk = UART_SCLK_APB, }; +#if defined(EMSUART_RX_INVERT) + inverse_mask |= UART_SIGNAL_RXD_INV; +#endif +#if defined(EMSUART_TX_INVERT) + inverse_mask |= UART_SIGNAL_TXD_INV; +#endif uart_param_config(EMSUART_NUM, &uart_config); uart_set_pin(EMSUART_NUM, tx_gpio, rx_gpio, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); + uart_set_line_inverse(EMSUART_NUM, inverse_mask); uart_driver_install(EMSUART_NUM, 129, 0, (EMS_MAXBUFFERSIZE + 1) * 2, &uart_queue, 0); // buffer must be > fifo uart_set_rx_full_threshold(EMSUART_NUM, 1); uart_set_rx_timeout(EMSUART_NUM, 0); // disable @@ -136,9 +144,9 @@ uint16_t EMSuart::transmit(const uint8_t * buf, const uint8_t len) { uart_write_bytes(EMSUART_NUM, &buf[i], 1); delayMicroseconds(EMSUART_TX_WAIT_PLUS); } - uart_set_line_inverse(EMSUART_NUM, UART_SIGNAL_TXD_INV); + uart_set_line_inverse(EMSUART_NUM, UART_SIGNAL_TXD_INV ^ inverse_mask); delayMicroseconds(EMSUART_TX_BRK_PLUS); - uart_set_line_inverse(EMSUART_NUM, 0); + uart_set_line_inverse(EMSUART_NUM, inverse_mask); return EMS_TX_STATUS_OK; } @@ -147,9 +155,9 @@ uint16_t EMSuart::transmit(const uint8_t * buf, const uint8_t len) { uart_write_bytes(EMSUART_NUM, &buf[i], 1); delayMicroseconds(EMSUART_TX_WAIT_HT3); } - uart_set_line_inverse(EMSUART_NUM, UART_SIGNAL_TXD_INV); + uart_set_line_inverse(EMSUART_NUM, UART_SIGNAL_TXD_INV ^ inverse_mask); delayMicroseconds(EMSUART_TX_BRK_HT3); - uart_set_line_inverse(EMSUART_NUM, 0); + uart_set_line_inverse(EMSUART_NUM, inverse_mask); return EMS_TX_STATUS_OK; } @@ -164,9 +172,9 @@ uint16_t EMSuart::transmit(const uint8_t * buf, const uint8_t len) { uart_get_buffered_data_len(EMSUART_NUM, &rx1); } while ((rx1 == rx0) && (--timeoutcnt)); } - uart_set_line_inverse(EMSUART_NUM, UART_SIGNAL_TXD_INV); + uart_set_line_inverse(EMSUART_NUM, UART_SIGNAL_TXD_INV ^ inverse_mask); delayMicroseconds(EMSUART_TX_BRK_EMS); - uart_set_line_inverse(EMSUART_NUM, 0); + uart_set_line_inverse(EMSUART_NUM, inverse_mask); return EMS_TX_STATUS_OK; } diff --git a/src/version.h b/src/version.h index 4a56be2f2..edd008ea5 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define EMSESP_APP_VERSION "3.6.3-test.7b" +#define EMSESP_APP_VERSION "3.6.3-dev.8a" diff --git a/src/web/WebCustomEntityService.cpp b/src/web/WebCustomEntityService.cpp index 74cfcbc1e..f8b18ff80 100644 --- a/src/web/WebCustomEntityService.cpp +++ b/src/web/WebCustomEntityService.cpp @@ -182,7 +182,8 @@ bool WebCustomEntityService::command_setvalue(const char * value, const std::str } // output of a single value -void WebCustomEntityService::render_value(JsonObject & output, CustomEntityItem entity, const bool useVal, const bool web) { +// if add_uom is true it will add the UOM string to the value +void WebCustomEntityService::render_value(JsonObject & output, CustomEntityItem entity, const bool useVal, const bool web, const bool add_uom) { char payload[12]; std::string name = useVal ? "value" : entity.name; switch (entity.value_type) { @@ -201,28 +202,33 @@ void WebCustomEntityService::render_value(JsonObject & output, CustomEntityItem break; case DeviceValueType::INT: if ((int8_t)entity.value != EMS_VALUE_INT_NOTSET) { - output[name] = serialized(Helpers::render_value(payload, entity.factor * (int8_t)entity.value, 2)); + std::string v = Helpers::render_value(payload, entity.factor * (int8_t)entity.value, 2); + output[name] = add_uom ? serialized(v + ' ' + EMSdevice::uom_to_string(entity.uom)) : serialized(v); } break; case DeviceValueType::UINT: if ((uint8_t)entity.value != EMS_VALUE_UINT_NOTSET) { - output[name] = serialized(Helpers::render_value(payload, entity.factor * (uint8_t)entity.value, 2)); + std::string v = Helpers::render_value(payload, entity.factor * (uint8_t)entity.value, 2); + output[name] = add_uom ? serialized(v + ' ' + EMSdevice::uom_to_string(entity.uom)) : serialized(v); } break; case DeviceValueType::SHORT: if ((int16_t)entity.value != EMS_VALUE_SHORT_NOTSET) { - output[name] = serialized(Helpers::render_value(payload, entity.factor * (int16_t)entity.value, 2)); + std::string v = Helpers::render_value(payload, entity.factor * (int16_t)entity.value, 2); + output[name] = add_uom ? serialized(v + ' ' + EMSdevice::uom_to_string(entity.uom)) : serialized(v); } break; case DeviceValueType::USHORT: if ((uint16_t)entity.value != EMS_VALUE_USHORT_NOTSET) { - output[name] = serialized(Helpers::render_value(payload, entity.factor * (uint16_t)entity.value, 2)); + std::string v = Helpers::render_value(payload, entity.factor * (uint16_t)entity.value, 2); + output[name] = add_uom ? serialized(v + ' ' + EMSdevice::uom_to_string(entity.uom)) : serialized(v); } break; case DeviceValueType::ULONG: case DeviceValueType::TIME: if (entity.value != EMS_VALUE_ULONG_NOTSET) { - output[name] = serialized(Helpers::render_value(payload, entity.factor * entity.value, 2)); + std::string v = Helpers::render_value(payload, entity.factor * entity.value, 2); + output[name] = add_uom ? serialized(v + ' ' + EMSdevice::uom_to_string(entity.uom)) : serialized(v); } break; case DeviceValueType::STRING: @@ -236,6 +242,15 @@ void WebCustomEntityService::render_value(JsonObject & output, CustomEntityItem } } +// display all custom entities +// adding each one, with UOM to a json object string +void WebCustomEntityService::show_values(JsonObject & output) { + for (const CustomEntityItem & entity : *customEntityItems) { + render_value(output, entity, false, false, true); // with add_uom + } +} + + // process json output for info/commands and value_info bool WebCustomEntityService::get_value_info(JsonObject & output, const char * cmd) { EMSESP::webCustomEntityService.read([&](WebCustomEntity & webEntity) { customEntityItems = &webEntity.customEntityItems; }); @@ -247,11 +262,13 @@ bool WebCustomEntityService::get_value_info(JsonObject & output, const char * cm } return true; } + // if no entries, return empty json // https://github.com/emsesp/EMS-ESP32/issues/1297 if (customEntityItems->size() == 0) { return true; } + if (strlen(cmd) == 0 || Helpers::toLower(cmd) == F_(values) || Helpers::toLower(cmd) == F_(info)) { // list all names for (const CustomEntityItem & entity : *customEntityItems) { @@ -410,7 +427,8 @@ void WebCustomEntityService::publish(const bool force) { } } JsonObject dev = config.createNestedObject("dev"); - JsonArray ids = dev.createNestedArray("ids"); + dev["name"] = Mqtt::basename(); + JsonArray ids = dev.createNestedArray("ids"); ids.add(Mqtt::basename()); // add "availability" section diff --git a/src/web/WebCustomEntityService.h b/src/web/WebCustomEntityService.h index 816b1bdb5..1b18e2073 100644 --- a/src/web/WebCustomEntityService.h +++ b/src/web/WebCustomEntityService.h @@ -52,22 +52,23 @@ class WebCustomEntityService : public StatefulService { public: WebCustomEntityService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager); - void begin(); - void publish_single(const CustomEntityItem & entity); - void publish(const bool force = false); - bool command_setvalue(const char * value, const std::string name); - bool get_value_info(JsonObject & output, const char * cmd); - bool get_value(std::shared_ptr telegram); - void fetch(); - void render_value(JsonObject & output, CustomEntityItem entity, const bool useVal = false, const bool web = false); + void begin(); + void publish_single(const CustomEntityItem & entity); + void publish(const bool force = false); + bool command_setvalue(const char * value, const std::string name); + bool get_value_info(JsonObject & output, const char * cmd); + bool get_value(std::shared_ptr telegram); + void fetch(); + void render_value(JsonObject & output, CustomEntityItem entity, const bool useVal = false, const bool web = false, const bool add_uom = false); + void show_values(JsonObject & output); + void generate_value_web(JsonObject & output); + uint8_t count_entities(); uint8_t has_commands(); - void generate_value_web(JsonObject & output); void ha_reset() { ha_registered_ = false; } - private: HttpEndpoint _httpEndpoint; FSPersistence _fsPersistence; diff --git a/src/web/WebCustomizationService.cpp b/src/web/WebCustomizationService.cpp index ab5fe1603..d6a8b8e08 100644 --- a/src/web/WebCustomizationService.cpp +++ b/src/web/WebCustomizationService.cpp @@ -99,7 +99,7 @@ StateUpdateResult WebCustomization::update(JsonObject & root, WebCustomization & #ifdef EMSESP_STANDALONE // invoke some fake data for testing const char * json = "{\"ts\":[],\"as\":[],\"masked_entities\":[{\"product_id\":123,\"device_id\":8,\"entity_ids\":[\"08heatingactive|my custom " - "name for heating active\",\"08tapwateractive\"]}]}"; + "name for heating active (HS1)\",\"08tapwateractive\"]}]}"; StaticJsonDocument<500> doc; deserializeJson(doc, json); root = doc.as(); diff --git a/src/web/WebSchedulerService.cpp b/src/web/WebSchedulerService.cpp index f7c61b1e3..91321c996 100644 --- a/src/web/WebSchedulerService.cpp +++ b/src/web/WebSchedulerService.cpp @@ -288,7 +288,8 @@ void WebSchedulerService::publish(const bool force) { } JsonObject dev = config.createNestedObject("dev"); - JsonArray ids = dev.createNestedArray("ids"); + dev["name"] = Mqtt::basename(); + JsonArray ids = dev.createNestedArray("ids"); ids.add(Mqtt::basename()); // add "availability" section