From a2e41d6d1e2dbe4e416b2465457aa7bc98a17b51 Mon Sep 17 00:00:00 2001 From: proddy Date: Sat, 28 Sep 2024 21:01:37 +0200 Subject: [PATCH 01/22] URL updates --- interface/package.json | 8 +- interface/src/api/app.ts | 9 +- interface/src/app/main/Help.tsx | 122 ++++++++++-------- interface/src/app/main/types.ts | 6 + interface/src/app/settings/DownloadUpload.tsx | 43 +++--- interface/src/utils/file.ts | 11 ++ interface/yarn.lock | 40 +++--- mock-api/rest_server.ts | 113 ++++++++++------ platformio.ini | 2 +- src/locale_translations.h | 2 +- src/system.cpp | 16 ++- src/system.h | 4 +- src/test/test.cpp | 3 - src/web/WebCustomEntityService.cpp | 1 - src/web/WebStatusService.cpp | 60 ++++++--- src/web/WebStatusService.h | 14 +- 16 files changed, 277 insertions(+), 177 deletions(-) create mode 100644 interface/src/utils/file.ts diff --git a/interface/package.json b/interface/package.json index 508e1ac10..b331a4168 100644 --- a/interface/package.json +++ b/interface/package.json @@ -27,7 +27,7 @@ "@mui/icons-material": "^6.1.1", "@mui/material": "^6.1.1", "@table-library/react-table-library": "4.1.7", - "alova": "3.0.16", + "alova": "3.0.17", "async-validator": "^4.2.5", "jwt-decode": "^4.0.0", "mime-types": "^2.1.35", @@ -47,8 +47,8 @@ "@preact/preset-vite": "^2.9.1", "@trivago/prettier-plugin-sort-imports": "^4.3.0", "@types/formidable": "^3", - "@types/node": "^22.7.3", - "@types/react": "^18.3.9", + "@types/node": "^22.7.4", + "@types/react": "^18.3.10", "@types/react-dom": "^18.3.0", "@types/react-router-dom": "^5.3.3", "concurrently": "^9.0.1", @@ -57,7 +57,7 @@ "formidable": "^3.5.1", "prettier": "^3.3.3", "rollup-plugin-visualizer": "^5.12.0", - "terser": "^5.34.0", + "terser": "^5.34.1", "typescript-eslint": "8.7.0", "vite": "^5.4.8", "vite-plugin-imagemin": "^0.6.1", diff --git a/interface/src/api/app.ts b/interface/src/api/app.ts index 1863a6893..a856d2096 100644 --- a/interface/src/api/app.ts +++ b/interface/src/api/app.ts @@ -2,6 +2,7 @@ import { alovaInstance } from 'api/endpoints'; import type { APIcall, + Action, Activity, CoreData, DeviceData, @@ -52,9 +53,9 @@ export const readActivity = () => alovaInstance.Get('/rest/activity'); // API export const API = (apiCall: APIcall) => alovaInstance.Post('/api', apiCall); -// DownloadUpload -export const exportData = (type: string) => - alovaInstance.Get('/rest/exportData', { params: { type } }); +// Generic action +export const callAction = (action: Action) => + alovaInstance.Post('/rest/action', action); // SettingsCustomization export const readDeviceEntities = (id: number) => @@ -118,7 +119,7 @@ export const writeModules = (data: { license: string; }) => alovaInstance.Post('/rest/modules', data); -// SettingsEntities +// CustomEntities export const readCustomEntities = () => alovaInstance.Get('/rest/customEntities', { transform(data) { diff --git a/interface/src/app/main/Help.tsx b/interface/src/app/main/Help.tsx index 32b410f04..e8bd18d22 100644 --- a/interface/src/app/main/Help.tsx +++ b/interface/src/app/main/Help.tsx @@ -1,4 +1,4 @@ -import { useContext } from 'react'; +import { useContext, useState } from 'react'; import { toast } from 'react-toastify'; import CommentIcon from '@mui/icons-material/CommentTwoTone'; @@ -16,18 +16,17 @@ import { ListItemAvatar, ListItemButton, ListItemText, - Paper, Stack, - Typography, - styled + Typography } from '@mui/material'; import { useRequest } from 'alova/client'; import { SectionContent, useLayoutTitle } from 'components'; import { AuthenticatedContext } from 'contexts/authentication'; import { useI18nContext } from 'i18n/i18n-react'; +import { saveFile } from 'utils/file'; -import { API } from '../../api/app'; +import { API, callAction } from '../../api/app'; import type { APIcall } from './types'; const Help = () => { @@ -36,33 +35,79 @@ const Help = () => { const { me } = useContext(AuthenticatedContext); - const { send: sendAPI } = useRequest((data: APIcall) => API(data), { - immediate: false - }).onSuccess((event) => { - const anchor = document.createElement('a'); - anchor.href = URL.createObjectURL( - new Blob([JSON.stringify(event.data, null, 2)], { - type: 'text/plain' - }) - ); + const [customSupportIMG, setCustomSupportIMG] = useState(null); + const [customSupportHTML, setCustomSupportHTML] = useState(null); - anchor.download = - 'emsesp_' + event.args[0].device + '_' + event.args[0].entity + '.txt'; - anchor.click(); - URL.revokeObjectURL(anchor.href); - toast.info(LL.DOWNLOAD_SUCCESSFUL()); - }); + useRequest(() => callAction({ action: 'customSupport' })).onSuccess( + (event: { data: { img_url: string; html: string[] } }) => { + if (event.data) { + setCustomSupportIMG(event.data.img_url); + setCustomSupportHTML(event.data.html.join('
')); + } + } + ); - const callAPI = async (device: string, cmd: string) => { - await sendAPI({ device, cmd, id: 0 }).catch((error: Error) => { + const { send: sendExportAllValues } = useRequest( + () => callAction({ action: 'export', param: 'allvalues' }), + { + immediate: false + } + ) + .onSuccess((event) => { + saveFile(event.data, 'allvalues', '.txt'); + toast.info(LL.DOWNLOAD_SUCCESSFUL()); + }) + .onError((error) => { + toast.error(error.message); + }); + + const { send: sendAPI } = useRequest((data: APIcall) => API(data), { + immediate: false + }) + .onSuccess((event) => { + saveFile(event.data, 'system_info', '.json'); + toast.info(LL.DOWNLOAD_SUCCESSFUL()); + }) + .onError((error) => { toast.error(error.message); }); - }; return ( <> - {me.admin ? ( + } + sx={{ + borderRadius: 3, + border: '2px solid grey', + justifyContent: 'space-evenly', + alignItems: 'center' + }} + > + + {customSupportHTML ? ( +
+ ) : ( + LL.HELP_INFORMATION_5() + )} + + + + + {me.admin && ( @@ -100,31 +145,6 @@ const Help = () => { - ) : ( - } - sx={{ - borderRadius: 3, - border: '2px solid grey', - justifyContent: 'space-around', - alignItems: 'center' - }} - > - - {LL.HELP_INFORMATION_5()} - - - )} @@ -135,7 +155,7 @@ const Help = () => { startIcon={} variant="outlined" color="primary" - onClick={() => callAPI('system', 'info')} + onClick={() => sendAPI({ device: 'system', cmd: 'info', id: 0 })} > {LL.DOWNLOAD(1)} {LL.SUPPORT_INFORMATION(0)} @@ -146,7 +166,7 @@ const Help = () => { startIcon={} variant="outlined" color="primary" - onClick={() => callAPI('system', 'allvalues')} + onClick={() => sendExportAllValues()} > {LL.DOWNLOAD(1)} {LL.ALLVALUES()} diff --git a/interface/src/app/main/types.ts b/interface/src/app/main/types.ts index 0a615e058..1efa9bfc8 100644 --- a/interface/src/app/main/types.ts +++ b/interface/src/app/main/types.ts @@ -265,6 +265,12 @@ export interface APIcall { cmd: string; id: number; } + +export interface Action { + action: string; + param?: string; // optional +} + export interface WriteAnalogSensor { id: number; gpio: number; diff --git a/interface/src/app/settings/DownloadUpload.tsx b/interface/src/app/settings/DownloadUpload.tsx index c222c4901..dffb7f81b 100644 --- a/interface/src/app/settings/DownloadUpload.tsx +++ b/interface/src/app/settings/DownloadUpload.tsx @@ -18,7 +18,7 @@ import { import Grid from '@mui/material/Grid2'; import * as SystemApi from 'api/system'; -import { API, exportData } from 'api/app'; +import { API, callAction } from 'api/app'; import { checkUpgrade, getDevVersion, @@ -37,6 +37,7 @@ import { useLayoutTitle } from 'components'; import { useI18nContext } from 'i18n/i18n-react'; +import { saveFile } from 'utils/file'; const DownloadUpload = () => { const { LL } = useI18nContext(); @@ -46,11 +47,23 @@ const DownloadUpload = () => { const [useDev, setUseDev] = useState(false); const [upgradeAvailable, setUpgradeAvailable] = useState(false); - const { send: sendExportData } = useRequest((type: string) => exportData(type), { - immediate: false - }) + const { send: sendCheckUpgrade } = useRequest( + (version: string) => callAction({ action: 'checkUpgrade', param: version }), + { + immediate: false + } + ).onSuccess((event) => { + setUpgradeAvailable((event.data as { upgradeable: boolean }).upgradeable); + }); + + const { send: sendExportData } = useRequest( + (type: string) => callAction({ action: 'export', param: type }), + { + immediate: false + } + ) .onSuccess((event) => { - saveFile(event.data, event.args[0]); + saveFile(event.data, event.args[0], '.json'); toast.info(LL.DOWNLOAD_SUCCESSFUL()); }) .onError((error) => { @@ -83,12 +96,6 @@ const DownloadUpload = () => { ); }; - const { send: sendCheckUpgrade } = useRequest(checkUpgrade, { - immediate: false - }).onSuccess((event) => { - setUpgradeAvailable(event.data.upgradeable); - }); - // called immediately to get the latest version, on page load const { data: latestVersion } = useRequest(getStableVersion, { // uncomment next 2 lines for testing, uses https://github.com/emsesp/EMS-ESP32/releases/download/v3.6.5/EMS-ESP-3_6_5-ESP32-16MB+.bin @@ -102,7 +109,7 @@ const DownloadUpload = () => { // immediate: false, // initialData: '3.7.0-dev.32' }).onSuccess((event) => { - void sendCheckUpgrade({ version: event.data }); + void sendCheckUpgrade(event.data); }); const STABLE_URL = 'https://github.com/emsesp/EMS-ESP32/releases/download/'; @@ -142,18 +149,6 @@ const DownloadUpload = () => { setRestarting(true); }; - const saveFile = (json: unknown, filename: string) => { - const anchor = document.createElement('a'); - anchor.href = URL.createObjectURL( - new Blob([JSON.stringify(json, null, 2)], { - type: 'text/plain' - }) - ); - anchor.download = 'emsesp_' + filename + '.json'; - anchor.click(); - URL.revokeObjectURL(anchor.href); - }; - useLayoutTitle(LL.DOWNLOAD_UPLOAD()); const internet_live = diff --git a/interface/src/utils/file.ts b/interface/src/utils/file.ts new file mode 100644 index 000000000..d6d5df4d5 --- /dev/null +++ b/interface/src/utils/file.ts @@ -0,0 +1,11 @@ +export const saveFile = (json: unknown, filename: string, extension: string) => { + const anchor = document.createElement('a'); + anchor.href = URL.createObjectURL( + new Blob([JSON.stringify(json, null, 2)], { + type: 'text/plain' + }) + ); + anchor.download = 'emsesp_' + filename + extension; + anchor.click(); + URL.revokeObjectURL(anchor.href); +}; diff --git a/interface/yarn.lock b/interface/yarn.lock index 5c976fafc..398f61769 100644 --- a/interface/yarn.lock +++ b/interface/yarn.lock @@ -1446,12 +1446,12 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:^22.7.3": - version: 22.7.3 - resolution: "@types/node@npm:22.7.3" +"@types/node@npm:^22.7.4": + version: 22.7.4 + resolution: "@types/node@npm:22.7.4" dependencies: undici-types: "npm:~6.19.2" - checksum: 10c0/0e579813528b0370454337a952f43b792cd12731e10fdca0fdb627158e980c1219bba99e9048c134b6a19325d817016059afe016ccd372326c838a1b85a51574 + checksum: 10c0/c22bf54515c78ff3170142c1e718b90e2a0003419dc2d55f79c9c9362edd590a6ab1450deb09ff6e1b32d1b4698da407930b16285e8be3a009ea6cd2695cac01 languageName: node linkType: hard @@ -1518,13 +1518,13 @@ __metadata: languageName: node linkType: hard -"@types/react@npm:^18.3.9": - version: 18.3.9 - resolution: "@types/react@npm:18.3.9" +"@types/react@npm:^18.3.10": + version: 18.3.10 + resolution: "@types/react@npm:18.3.10" dependencies: "@types/prop-types": "npm:*" csstype: "npm:^3.0.2" - checksum: 10c0/a92b8e061d0c833e096254782c56a802316593f4a907fb834b557cabe848a0829b9eb6056404ea239eb4d5ec5ac7b7724309761516c0a7a277916fa04dd4f805 + checksum: 10c0/f5be1de1b0331c1fdb33d577f4cf7f1b949d4bded5347b2351a537f03c51dade5be115e21b161dcf1b37061954d320f6a0bdf8d7b70e24eda51071fdd614383d languageName: node linkType: hard @@ -1678,11 +1678,11 @@ __metadata: "@table-library/react-table-library": "npm:4.1.7" "@trivago/prettier-plugin-sort-imports": "npm:^4.3.0" "@types/formidable": "npm:^3" - "@types/node": "npm:^22.7.3" - "@types/react": "npm:^18.3.9" + "@types/node": "npm:^22.7.4" + "@types/react": "npm:^18.3.10" "@types/react-dom": "npm:^18.3.0" "@types/react-router-dom": "npm:^5.3.3" - alova: "npm:3.0.16" + alova: "npm:3.0.17" async-validator: "npm:^4.2.5" concurrently: "npm:^9.0.1" eslint: "npm:^9.11.1" @@ -1698,7 +1698,7 @@ __metadata: react-router-dom: "npm:^6.26.2" react-toastify: "npm:^10.0.5" rollup-plugin-visualizer: "npm:^5.12.0" - terser: "npm:^5.34.0" + terser: "npm:^5.34.1" typesafe-i18n: "npm:^5.26.2" typescript: "npm:^5.6.2" typescript-eslint: "npm:8.7.0" @@ -1764,13 +1764,13 @@ __metadata: languageName: node linkType: hard -"alova@npm:3.0.16": - version: 3.0.16 - resolution: "alova@npm:3.0.16" +"alova@npm:3.0.17": + version: 3.0.17 + resolution: "alova@npm:3.0.17" dependencies: "@alova/shared": "npm:^1.0.5" rate-limiter-flexible: "npm:^5.0.3" - checksum: 10c0/66cb597f4f00feda04b7619dd852fde92bc920cc97b018be70791240c8e8c64677a998a02a684f3aace5997322236a677264f25afe6bcaf4ec856ae42be859a8 + checksum: 10c0/e8a2ae885a3ff44dafec230d9388dc22b6445bb0cf8511fc9855b5a98ad9961941b0d33a7da874df23db4af0dba75872a470e3edebbdcc5ead8aecbc7fcc3d6b languageName: node linkType: hard @@ -6654,9 +6654,9 @@ __metadata: languageName: node linkType: hard -"terser@npm:^5.34.0": - version: 5.34.0 - resolution: "terser@npm:5.34.0" +"terser@npm:^5.34.1": + version: 5.34.1 + resolution: "terser@npm:5.34.1" dependencies: "@jridgewell/source-map": "npm:^0.3.3" acorn: "npm:^8.8.2" @@ -6664,7 +6664,7 @@ __metadata: source-map-support: "npm:~0.5.20" bin: terser: bin/terser - checksum: 10c0/74e8ef4e565e5600415cd9377a90eed419b8076465d453c0c76aef4053c45371512d2de76c34d01e004cdd49ea5a749d77eeb343f7e665b2d172158ca08ba23e + checksum: 10c0/51c7d704c5c4ae88bf937124112c9972aed4e1fd29d805cc2d86e0f54cd631ecd4e69db5bb3c1e3b450c741c86e2313328bea0fde925329e8a31a07a7941723c languageName: node linkType: hard diff --git a/mock-api/rest_server.ts b/mock-api/rest_server.ts index 5b3b2476d..c2e449bd4 100644 --- a/mock-api/rest_server.ts +++ b/mock-api/rest_server.ts @@ -117,6 +117,55 @@ function updateMask(entity: any, de: any, dd: any) { } } +// called by Action endpoint +function export_data(type: string) { + console.log('exporting ' + type + '...'); + switch (type) { + case 'settings': + return emsesp_info; + case 'customizations': + return emsesp_deviceentities_2; // fixed for one device + case 'entities': + return emsesp_customentities; + case 'schedule': + return emsesp_schedule; + case 'modules': + return emsesp_modules; + case 'allvalues': + return emsesp_allvalues; + default: + return status(404); + } +} + +// called by Action endpoint +function custom_support() { + return { + html: [ + 'This product is installed and managed by:', + '', + 'Bosch Installer Example', + 'Nefit Road 12', + '1234 AB Amsterdam', + 'Phone: +31 123 456 789', + 'email: support@boschinstaller.nl', + '', + "For help and questions please contact your installer." + ], + img_url: 'https://emsesp.org/_media/images/designer.png' + }; +} + +// called by Action endpoint +function check_upgrade(version: string) { + console.log('check upgrade from version', version); + const data = { + upgradeable: true + // upgradeable: false + }; + return data; +} + // START DATA // LOG @@ -402,7 +451,6 @@ const EMSESP_DEVICEDATA_ENDPOINT2 = REST_ENDPOINT_ROOT + 'deviceData/:id?'; const EMSESP_DEVICEENTITIES_ENDPOINT1 = REST_ENDPOINT_ROOT + 'deviceEntities'; const EMSESP_DEVICEENTITIES_ENDPOINT2 = REST_ENDPOINT_ROOT + 'deviceEntities/:id?'; -const EMSESP_CHECK_UPGRADE_ENDPOINT = REST_ENDPOINT_ROOT + 'checkUpgrade'; const EMSESP_BOARDPROFILE_ENDPOINT = REST_ENDPOINT_ROOT + 'boardProfile'; const EMSESP_WRITE_DEVICEVALUE_ENDPOINT = REST_ENDPOINT_ROOT + 'writeDeviceValue'; const EMSESP_WRITE_DEVICENAME_ENDPOINT = REST_ENDPOINT_ROOT + 'writeDeviceName'; @@ -416,7 +464,8 @@ const EMSESP_RESET_CUSTOMIZATIONS_ENDPOINT = const EMSESP_SCHEDULE_ENDPOINT = REST_ENDPOINT_ROOT + 'schedule'; const EMSESP_CUSTOMENTITIES_ENDPOINT = REST_ENDPOINT_ROOT + 'customEntities'; const EMSESP_MODULES_ENDPOINT = REST_ENDPOINT_ROOT + 'modules'; -const EMSESP_EXPORT_DATA_ENDPOINT = REST_ENDPOINT_ROOT + 'exportData'; + +const EMSESP_ACTION_ENDPOINT = REST_ENDPOINT_ROOT + 'action'; // these are used in the API calls only const EMSESP_SYSTEM_INFO_ENDPOINT = API_ENDPOINT_ROOT + 'system/info'; @@ -4081,16 +4130,10 @@ router router .get(ACTIVITY_ENDPOINT, () => activity) .get(SYSTEM_STATUS_ENDPOINT, () => { - if (countHardwarePoll === 0) { - console.log('Resetting hardware count...'); - } - if (countHardwarePoll >= 2) { countHardwarePoll = 0; system_status.status = 'ready'; } - - console.log('Hardware count ' + countHardwarePoll + ' of 2'); countHardwarePoll++; return system_status; @@ -4402,17 +4445,6 @@ router return status(200); }) - // check upgrade - .post(EMSESP_CHECK_UPGRADE_ENDPOINT, async (request: any) => { - const content = await request.json(); - console.log('check upgrade from ', content.version); - const data = { - upgradeable: true - // upgradeable: false - }; - return data; - }) - // Settings - board profile .get(EMSESP_BOARDPROFILE_ENDPOINT, (request) => { const board_profile = request.query.boardProfile; @@ -4549,32 +4581,32 @@ router return data; }) - // Download Settings - .get(EMSESP_EXPORT_DATA_ENDPOINT, (request) => { - const type = request.query.type; - console.log('exporting ' + type + ' data'); - switch (type) { - case 'settings': - return emsesp_info; - case 'customizations': - return emsesp_deviceentities_2; // fixed for one device - case 'entities': - return emsesp_customentities; - case 'schedule': - return emsesp_schedule; - case 'modules': - return emsesp_modules; - default: - return status(404); - } - }) - // upload URL .post('/rest/uploadURL', () => { console.log('upload File from URL'); return status(200); }) + // generic action for all /rest/... endpoints + // takes an action and param in JSON + .post(EMSESP_ACTION_ENDPOINT, async (request: any) => { + const content = await request.json(); + if (content.hasOwnProperty('action')) { + const action = content.action; + if (action === 'export') { + // export data + return export_data(content.param); + } else if (action === 'customSupport') { + // send custom support + return custom_support(); + } else if (action === 'checkUpgrade') { + // check upgrade + return check_upgrade(content.param); + } + } + return status(404); // cmd not found + }) + // API which are usually POST for security .post(EMSESP_SYSTEM_INFO_ENDPOINT, () => emsesp_info) .get(EMSESP_SYSTEM_INFO_ENDPOINT, () => emsesp_info) @@ -4594,9 +4626,6 @@ router if (cmd === 'info') { return emsesp_info; } - if (cmd === 'allvalues') { - return emsesp_allvalues; - } if (cmd === 'format') { console.log('formatting...'); return status(200); diff --git a/platformio.ini b/platformio.ini index 0b8ae8d43..604d2e2e5 100644 --- a/platformio.ini +++ b/platformio.ini @@ -39,7 +39,7 @@ unbuild_flags = ${common.core_unbuild_flags} [espressif32_base] -platform = espressif32@6.8.1 +platform = espressif32@6.9.0 framework = arduino board_build.filesystem = littlefs build_flags = diff --git a/src/locale_translations.h b/src/locale_translations.h index 35a88d45c..b48f469a2 100644 --- a/src/locale_translations.h +++ b/src/locale_translations.h @@ -75,7 +75,7 @@ MAKE_WORD_TRANSLATION(schedule_cmd, "enable schedule item", "Aktiviere Zeitplane 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(coldshot_cmd, "send a cold shot of water", "Zugabe einer Menge kalten Wassers", "", "", "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 in system", "Alle Werte im System ausgeben", "", "", "wyświetl wszystkie wartości", "", "", "", "", "vypísať všetky hodnoty") // TODO translate +MAKE_WORD_TRANSLATION(allvalues_cmd, "output all values in system", "Alle Werte im System ausgeben", "", "", "wyświetl wszystkie wartości", "", "", "", "", "vypísať všetky hodnoty") // TODO remove MAKE_WORD_TRANSLATION(message_cmd, "send a message", "Eine Nachricht senden", "", "", "", "", "", "", "", "poslať správu") // TODO translate MAKE_WORD_TRANSLATION(values_cmd, "list all values", "Liste alle Werte auf", "", "", "", "", "", "", "", "vypísať všetky hodnoty") // TODO translate diff --git a/src/system.cpp b/src/system.cpp index f796514d8..d5478b512 100644 --- a/src/system.cpp +++ b/src/system.cpp @@ -113,6 +113,7 @@ bool System::command_response(const char * value, const int8_t id, JsonObject ou // output all the devices and the values // not system info +// TODO remove? bool System::command_allvalues(const char * value, const int8_t id, JsonObject output) { JsonDocument doc; JsonObject device_output; @@ -874,7 +875,7 @@ void System::commands_init() { // these commands will return data in JSON format 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)); // TODO remove // MQTT subscribe "ems-esp/system/#" Mqtt::subscribe(EMSdevice::DeviceType::SYSTEM, "system/#", nullptr); // use empty function callback @@ -1139,7 +1140,7 @@ void System::show_system(uuid::console::Shell & shell) { // see if there is a restore of an older settings file that needs to be applied bool System::check_restore() { - bool reboot_required = false; + bool reboot_required = false; // true if we need to reboot #ifndef EMSESP_STANDALONE File new_file = LittleFS.open(TEMP_FILENAME_PATH); @@ -1167,11 +1168,20 @@ bool System::check_restore() { } else if (settings_type == "entities") { // it's a entity file, just replace it and there's no need to reboot saveSettings(EMSESP_CUSTOMENTITY_FILE, "Entities", input); + } else if (settings_type == "custom_support") { + // it's a custom support file - save it to /config + new_file.close(); + if (LittleFS.rename(TEMP_FILENAME_PATH, EMSESP_CUSTOMSUPPORT_FILE)) { + LOG_INFO("Custom support information loaded"); + return false; // no need to reboot + } else { + LOG_ERROR("Failed to save custom support file"); + } } else { LOG_ERROR("Unrecognized file uploaded"); } } else { - LOG_ERROR("Unrecognized file uploaded, not json. Will be removed."); + LOG_ERROR("Unrecognized file uploaded, not json."); } // close (just in case) and remove the temp file diff --git a/src/system.h b/src/system.h index 2e980a22b..22b89be5a 100644 --- a/src/system.h +++ b/src/system.h @@ -43,6 +43,8 @@ using uuid::console::Shell; #define EMSESP_FS_CONFIG_DIRECTORY "/config" +#define EMSESP_CUSTOMSUPPORT_FILE "/config/customSupport.json" + namespace emsesp { enum PHY_type : uint8_t { PHY_TYPE_NONE = 0, PHY_TYPE_LAN8720, PHY_TYPE_TLK110 }; @@ -63,7 +65,7 @@ class System { static bool command_message(const char * value, const int8_t id); static bool command_info(const char * value, const int8_t id, JsonObject output); static bool command_response(const char * value, const int8_t id, JsonObject output); - static bool command_allvalues(const char * value, const int8_t id, JsonObject output); + static bool command_allvalues(const char * value, const int8_t id, JsonObject output); // TODO fix static bool get_value_info(JsonObject root, const char * cmd); static void get_value_json(JsonObject output, const std::string & circuit, const std::string & name, JsonVariant val); diff --git a/src/test/test.cpp b/src/test/test.cpp index c81d98b96..60f7b9ebb 100644 --- a/src/test/test.cpp +++ b/src/test/test.cpp @@ -327,7 +327,6 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const // shell.invoke_command("show devices"); // shell.invoke_command("show values"); - // shell.invoke_command("call system allvalues"); // shell.invoke_command("call system publish"); // shell.invoke_command("show mqtt"); ok = true; @@ -792,7 +791,6 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const shell.invoke_command("call temperaturesensor"); shell.invoke_command("show values"); - shell.invoke_command("call system allvalues"); shell.invoke_command("call temperaturesensor info"); shell.invoke_command("call temperaturesensor values"); @@ -842,7 +840,6 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const shell.invoke_command("call analogsensor"); shell.invoke_command("show values"); - shell.invoke_command("call system allvalues"); shell.invoke_command("call analogsensor info"); shell.invoke_command("call analogsensor values"); diff --git a/src/web/WebCustomEntityService.cpp b/src/web/WebCustomEntityService.cpp index 0a0a56061..a26285dc8 100644 --- a/src/web/WebCustomEntityService.cpp +++ b/src/web/WebCustomEntityService.cpp @@ -463,7 +463,6 @@ uint8_t WebCustomEntityService::count_entities() { uint8_t count = 0; for (const CustomEntityItem & entity : *customEntityItems_) { render_value(output, entity); - // TODO check JsonVariant if (output[entity.name].is() || entity.writeable) { count++; } diff --git a/src/web/WebStatusService.cpp b/src/web/WebStatusService.cpp index 8ea907161..417a59e02 100644 --- a/src/web/WebStatusService.cpp +++ b/src/web/WebStatusService.cpp @@ -27,10 +27,9 @@ namespace emsesp { WebStatusService::WebStatusService(AsyncWebServer * server, SecurityManager * securityManager) { // GET server->on(EMSESP_SYSTEM_STATUS_SERVICE_PATH, HTTP_GET, [this](AsyncWebServerRequest * request) { systemStatus(request); }); - server->on(EMSESP_EXPORT_DATA_SERVICE_PATH, HTTP_GET, [this](AsyncWebServerRequest * request) { exportData(request); }); - // POST - server->on(EMSESP_CHECK_UPGRADE_PATH, [this](AsyncWebServerRequest * request, JsonVariant json) { checkUpgrade(request, json); }); + // generic action - POST + server->on(EMSESP_ACTION_SERVICE_PATH, [this](AsyncWebServerRequest * request, JsonVariant json) { action(request, json); }); } // /rest/systemStatus @@ -146,13 +145,42 @@ void WebStatusService::systemStatus(AsyncWebServerRequest * request) { request->send(response); } -// returns trues if there is an upgrade available -void WebStatusService::checkUpgrade(AsyncWebServerRequest * request, JsonVariant json) { +// generic action handler - as a POST +void WebStatusService::action(AsyncWebServerRequest * request, JsonVariant json) { auto * response = new AsyncJsonResponse(); JsonObject root = response->getRoot(); + // get action and optional param + std::string action = json["action"]; + std::string param = json["param"]; // is optional + + // TODO remove + Serial.printf("Action: %s\n", action.c_str()); + Serial.printf("Param: %s\n", param.c_str()); + + bool ok = true; + if (action == "checkUpgrade") { + ok = checkUpgrade(root, param); + } else if (action == "export") { + ok = exportData(root, param); + } else if (action == "customSupport") { + ok = customSupport(root); + } + + // send response + if (!ok) { + request->send(400); + return; + } + + response->setLength(); + request->send(response); +} + + +// returns true if there is an upgrade available +bool WebStatusService::checkUpgrade(JsonObject root, std::string & latest_version) { version::Semver200_version settings_version(EMSESP_APP_VERSION); - const std::string latest_version = json["version"] | EMSESP_APP_VERSION; version::Semver200_version this_version(latest_version); #if defined(EMSESP_DEBUG) @@ -161,16 +189,11 @@ void WebStatusService::checkUpgrade(AsyncWebServerRequest * request, JsonVariant root["upgradeable"] = (this_version > settings_version); - response->setLength(); - request->send(response); + return true; } // returns data for a specific feature/settings as a json object -void WebStatusService::exportData(AsyncWebServerRequest * request) { - auto * response = new AsyncJsonResponse(); - JsonObject root = response->getRoot(); - - String type = request->getParam("type")->value(); +bool WebStatusService::exportData(JsonObject root, std::string & type) { root["type"] = type; if (type == "settings") { @@ -189,12 +212,15 @@ void WebStatusService::exportData(AsyncWebServerRequest * request) { } else if (type == "entities") { System::extractSettings(EMSESP_CUSTOMENTITY_FILE, "Entities", root); } else { - request->send(400); - return; + return false; } + return true; +} - response->setLength(); - request->send(response); +// custom support +bool WebStatusService::customSupport(JsonObject root) { + root["custom_support"] = true; + return true; } } // namespace emsesp diff --git a/src/web/WebStatusService.h b/src/web/WebStatusService.h index d4c4806b7..3e04b2ce0 100644 --- a/src/web/WebStatusService.h +++ b/src/web/WebStatusService.h @@ -2,8 +2,8 @@ #define WebStatusService_h #define EMSESP_SYSTEM_STATUS_SERVICE_PATH "/rest/systemStatus" -#define EMSESP_CHECK_UPGRADE_PATH "/rest/checkUpgrade" -#define EMSESP_EXPORT_DATA_SERVICE_PATH "/rest/exportData" + +#define EMSESP_ACTION_SERVICE_PATH "/rest/action" #include // for version checking @@ -13,10 +13,14 @@ class WebStatusService { public: WebStatusService(AsyncWebServer * server, SecurityManager * securityManager); - private: + protected: void systemStatus(AsyncWebServerRequest * request); - void checkUpgrade(AsyncWebServerRequest * request, JsonVariant json); - void exportData(AsyncWebServerRequest * request); + void action(AsyncWebServerRequest * request, JsonVariant json); + + private: + bool checkUpgrade(JsonObject root, std::string & latest_version); + bool exportData(JsonObject root, std::string & type); + bool customSupport(JsonObject root); }; } // namespace emsesp From c9dd2d4a72ca546155eae4687cbb13027b1d95a0 Mon Sep 17 00:00:00 2001 From: proddy Date: Sun, 29 Sep 2024 09:17:11 +0200 Subject: [PATCH 02/22] move allvalues to new action endpoint --- CHANGELOG_LATEST.md | 4 ++- src/locale_translations.h | 1 - src/system.cpp | 42 ++---------------------------- src/system.h | 1 - src/test/test.cpp | 23 ++++++++++++++--- src/version.h | 2 +- src/web/WebSchedulerService.cpp | 2 +- src/web/WebStatusService.cpp | 45 ++++++++++++++++++++++++++++++--- src/web/WebStatusService.h | 5 +++- 9 files changed, 71 insertions(+), 54 deletions(-) diff --git a/CHANGELOG_LATEST.md b/CHANGELOG_LATEST.md index 6285bbc06..7b3f6a94f 100644 --- a/CHANGELOG_LATEST.md +++ b/CHANGELOG_LATEST.md @@ -40,8 +40,9 @@ For more details go to [www.emsesp.org](https://www.emsesp.org/). - autodetect and download firmware upgrades via the WebUI - command 'show log' that lists out the current weblog buffer, showing last messages. - default web log buffer to 25 lines for ESP32s with no PSRAM -- Try and determine correct board profile if none is set +- try and determine correct board profile if none is set during boot - auto Scroll in WebLog UI - reduced delay so incoming logs are faster +- uploading custom support info for Guest users [#2054] ## Fixed @@ -70,3 +71,4 @@ For more details go to [www.emsesp.org](https://www.emsesp.org/). - WebLog UI matches color schema of the terminal console correctly - Updated Web libraries, ArduinoJson - Help page doesn't show detailed tech info if the user is not 'admin' role [#2054](https://github.com/emsesp/EMS-ESP32/issues/2054) +- removed system command `allvalues` and moved to an action called `export` diff --git a/src/locale_translations.h b/src/locale_translations.h index b48f469a2..2fbbc0ec9 100644 --- a/src/locale_translations.h +++ b/src/locale_translations.h @@ -75,7 +75,6 @@ MAKE_WORD_TRANSLATION(schedule_cmd, "enable schedule item", "Aktiviere Zeitplane 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(coldshot_cmd, "send a cold shot of water", "Zugabe einer Menge kalten Wassers", "", "", "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 in system", "Alle Werte im System ausgeben", "", "", "wyświetl wszystkie wartości", "", "", "", "", "vypísať všetky hodnoty") // TODO remove MAKE_WORD_TRANSLATION(message_cmd, "send a message", "Eine Nachricht senden", "", "", "", "", "", "", "", "poslať správu") // TODO translate MAKE_WORD_TRANSLATION(values_cmd, "list all values", "Liste alle Werte auf", "", "", "", "", "", "", "", "vypísať všetky hodnoty") // TODO translate diff --git a/src/system.cpp b/src/system.cpp index d5478b512..dd506cc6c 100644 --- a/src/system.cpp +++ b/src/system.cpp @@ -111,45 +111,6 @@ bool System::command_response(const char * value, const int8_t id, JsonObject ou return true; } -// output all the devices and the values -// not system info -// TODO remove? -bool System::command_allvalues(const char * value, const int8_t id, JsonObject output) { - JsonDocument doc; - JsonObject device_output; - // default to values - if (value == nullptr || strlen(value) == 0) { - value = F_(values); - } - - // System Entities - // device_output = output["System"].to(); - // get_value_info(device_output, value); - - // EMS-Device Entities - for (const auto & emsdevice : EMSESP::emsdevices) { - std::string title = emsdevice->device_type_2_device_name_translated() + std::string(" ") + emsdevice->to_string(); - device_output = output[title].to(); - emsdevice->get_value_info(device_output, value, DeviceValueTAG::TAG_NONE); - } - - // Custom Entities - device_output = output["Custom Entities"].to(); - EMSESP::webCustomEntityService.get_value_info(device_output, value); - - // Scheduler - device_output = output["Scheduler"].to(); - EMSESP::webSchedulerService.get_value_info(device_output, value); - - // Sensors - device_output = output["Analog Sensors"].to(); - EMSESP::analogsensor_.get_value_info(device_output, value); - device_output = output["Temperature Sensors"].to(); - EMSESP::temperaturesensor_.get_value_info(device_output, value); - - return true; -} - // fetch device values bool System::command_fetch(const char * value, const int8_t id) { std::string value_s; @@ -339,6 +300,8 @@ void System::system_restart(const char * partitionname) { delay(1000); // wait 1 second ESP.restart(); #else + restart_requested(false); + restart_pending(false); if (partitionname != nullptr) { LOG_INFO("Restarting EMS-ESP from %s partition", partitionname); } else { @@ -875,7 +838,6 @@ void System::commands_init() { // these commands will return data in JSON format 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)); // TODO remove // MQTT subscribe "ems-esp/system/#" Mqtt::subscribe(EMSdevice::DeviceType::SYSTEM, "system/#", nullptr); // use empty function callback diff --git a/src/system.h b/src/system.h index 22b89be5a..9aea1dd34 100644 --- a/src/system.h +++ b/src/system.h @@ -65,7 +65,6 @@ class System { static bool command_message(const char * value, const int8_t id); static bool command_info(const char * value, const int8_t id, JsonObject output); static bool command_response(const char * value, const int8_t id, JsonObject output); - static bool command_allvalues(const char * value, const int8_t id, JsonObject output); // TODO fix static bool get_value_info(JsonObject root, const char * cmd); static void get_value_json(JsonObject output, const std::string & circuit, const std::string & name, JsonVariant val); diff --git a/src/test/test.cpp b/src/test/test.cpp index 60f7b9ebb..63f9241bf 100644 --- a/src/test/test.cpp +++ b/src/test/test.cpp @@ -989,11 +989,26 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const // EMSESP::webAPIService.webAPIService(&request); request.method(HTTP_POST); - char data_api[] = "{\"device\":\"system\", \"cmd\":\"restart\",\"id\":-1}"; - deserializeJson(doc, data_api); - json = doc.as(); + + char data1[] = "{\"device\":\"system\", \"cmd\":\"restart\",\"id\":-1}"; + deserializeJson(doc, data1); request.url("/api"); - EMSESP::webAPIService.webAPIService(&request, json); + EMSESP::webAPIService.webAPIService(&request, doc.as()); + + char data2[] = "{\"action\":\"customSupport\", \"param\":\"hello\"}"; + deserializeJson(doc, data2); + request.url("/rest/action"); + EMSESP::webStatusService.action(&request, doc.as()); + + char data3[] = "{\"action\":\"export\", \"param\":\"schedule\"}"; + deserializeJson(doc, data3); + request.url("/rest/action"); + EMSESP::webStatusService.action(&request, doc.as()); + + char data4[] = "{\"action\":\"export\", \"param\":\"allvalues\"}"; + deserializeJson(doc, data4); + request.url("/rest/action"); + EMSESP::webStatusService.action(&request, doc.as()); // request.url("/api/thermostat"); // EMSESP::webAPIService.webAPIService(&request); diff --git a/src/version.h b/src/version.h index f18b9395f..b78c093ae 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define EMSESP_APP_VERSION "3.7.0-dev.40" +#define EMSESP_APP_VERSION "3.7.0-dev.41" diff --git a/src/web/WebSchedulerService.cpp b/src/web/WebSchedulerService.cpp index 167a0f654..148f36f3a 100644 --- a/src/web/WebSchedulerService.cpp +++ b/src/web/WebSchedulerService.cpp @@ -584,7 +584,7 @@ void WebSchedulerService::test() { test_value = "(custom/seltemp)"; command("test5", test_cmd.c_str(), compute(test_value).c_str()); - // this will fail unless test("boiler") is loaded + // note: this will fail unless test("boiler") is loaded before hand test_value = "(boiler/outdoortemp)"; command("test6", test_cmd.c_str(), compute(test_value).c_str()); diff --git a/src/web/WebStatusService.cpp b/src/web/WebStatusService.cpp index 417a59e02..7260bc2eb 100644 --- a/src/web/WebStatusService.cpp +++ b/src/web/WebStatusService.cpp @@ -154,10 +154,6 @@ void WebStatusService::action(AsyncWebServerRequest * request, JsonVariant json) std::string action = json["action"]; std::string param = json["param"]; // is optional - // TODO remove - Serial.printf("Action: %s\n", action.c_str()); - Serial.printf("Param: %s\n", param.c_str()); - bool ok = true; if (action == "checkUpgrade") { ok = checkUpgrade(root, param); @@ -167,6 +163,17 @@ void WebStatusService::action(AsyncWebServerRequest * request, JsonVariant json) ok = customSupport(root); } +#if defined(EMSESP_UNITY) + // store the result so we can test with Unity later + storeResponse(output); +#endif +#if defined(EMSESP_STANDALONE) && !defined(EMSESP_UNITY) + Serial.printf("%sweb output: %s[%s]", COLOR_WHITE, COLOR_BRIGHT_CYAN, request->url().c_str()); + Serial.printf(" %s(%d)%s ", ok ? COLOR_BRIGHT_GREEN : COLOR_BRIGHT_RED, ok ? 200 : 400, COLOR_YELLOW); + serializeJson(root, Serial); + Serial.println(COLOR_RESET); +#endif + // send response if (!ok) { request->send(400); @@ -192,6 +199,34 @@ bool WebStatusService::checkUpgrade(JsonObject root, std::string & latest_versio return true; } +// output all the devices and the values +void WebStatusService::allvalues(JsonObject output) { + JsonDocument doc; + JsonObject device_output; + auto value = F_(values); + + // EMS-Device Entities + for (const auto & emsdevice : EMSESP::emsdevices) { + std::string title = emsdevice->device_type_2_device_name_translated() + std::string(" ") + emsdevice->to_string(); + device_output = output[title].to(); + emsdevice->get_value_info(device_output, value, DeviceValueTAG::TAG_NONE); + } + + // Custom Entities + device_output = output["Custom Entities"].to(); + EMSESP::webCustomEntityService.get_value_info(device_output, value); + + // Scheduler + device_output = output["Scheduler"].to(); + EMSESP::webSchedulerService.get_value_info(device_output, value); + + // Sensors + device_output = output["Analog Sensors"].to(); + EMSESP::analogsensor_.get_value_info(device_output, value); + device_output = output["Temperature Sensors"].to(); + EMSESP::temperaturesensor_.get_value_info(device_output, value); +} + // returns data for a specific feature/settings as a json object bool WebStatusService::exportData(JsonObject root, std::string & type) { root["type"] = type; @@ -211,6 +246,8 @@ bool WebStatusService::exportData(JsonObject root, std::string & type) { System::extractSettings(EMSESP_CUSTOMIZATION_FILE, "Customizations", root); } else if (type == "entities") { System::extractSettings(EMSESP_CUSTOMENTITY_FILE, "Entities", root); + } else if (type == "allvalues") { + allvalues(root); } else { return false; } diff --git a/src/web/WebStatusService.h b/src/web/WebStatusService.h index 3e04b2ce0..bc887156c 100644 --- a/src/web/WebStatusService.h +++ b/src/web/WebStatusService.h @@ -2,7 +2,6 @@ #define WebStatusService_h #define EMSESP_SYSTEM_STATUS_SERVICE_PATH "/rest/systemStatus" - #define EMSESP_ACTION_SERVICE_PATH "/rest/action" #include // for version checking @@ -13,7 +12,10 @@ class WebStatusService { public: WebStatusService(AsyncWebServer * server, SecurityManager * securityManager); +// make all functions public so we can test in the debug and standalone mode +#ifndef EMSESP_STANDALONE protected: +#endif void systemStatus(AsyncWebServerRequest * request); void action(AsyncWebServerRequest * request, JsonVariant json); @@ -21,6 +23,7 @@ class WebStatusService { bool checkUpgrade(JsonObject root, std::string & latest_version); bool exportData(JsonObject root, std::string & type); bool customSupport(JsonObject root); + void allvalues(JsonObject output); }; } // namespace emsesp From 93066e48362bfb4fc0dc5e1fb8374dbd7d449ae0 Mon Sep 17 00:00:00 2001 From: proddy Date: Sun, 29 Sep 2024 09:40:18 +0200 Subject: [PATCH 03/22] customSupport read file --- src/web/WebStatusService.cpp | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/web/WebStatusService.cpp b/src/web/WebStatusService.cpp index 7260bc2eb..642a82f6e 100644 --- a/src/web/WebStatusService.cpp +++ b/src/web/WebStatusService.cpp @@ -184,7 +184,6 @@ void WebStatusService::action(AsyncWebServerRequest * request, JsonVariant json) request->send(response); } - // returns true if there is an upgrade available bool WebStatusService::checkUpgrade(JsonObject root, std::string & latest_version) { version::Semver200_version settings_version(EMSESP_APP_VERSION); @@ -256,7 +255,23 @@ bool WebStatusService::exportData(JsonObject root, std::string & type) { // custom support bool WebStatusService::customSupport(JsonObject root) { - root["custom_support"] = true; +#ifndef EMSESP_STANDALONE + // check if we have custom support file uploaded + File file = LittleFS.open(EMSESP_CUSTOMSUPPORT_FILE, "r"); + if (!file) { + // there is no custom file, return empty object + return true; + } + + // read the contents of the file into the root output json object + DeserializationError error = deserializeJson(root, file); + if (error) { + emsesp::EMSESP::logger().err("Failed to read custom support file"); + return false; + } + + file.close(); +#endif return true; } From ab040e120edf36508c89bcd1f19fad23bce22bec Mon Sep 17 00:00:00 2001 From: proddy Date: Sun, 29 Sep 2024 11:08:49 +0200 Subject: [PATCH 04/22] move uploadURL as an action --- interface/src/api/system.ts | 8 +--- interface/src/app/main/Help.tsx | 17 ++++---- interface/src/app/settings/DownloadUpload.tsx | 11 ++---- lib/framework/UploadFileService.cpp | 17 -------- lib/framework/UploadFileService.h | 2 - mock-api/rest_server.ts | 39 ++++++++++--------- project-words.txt | 5 ++- src/system.cpp | 2 +- src/version.h | 2 +- src/web/WebStatusService.cpp | 27 +++++++++++-- src/web/WebStatusService.h | 7 +++- 11 files changed, 70 insertions(+), 67 deletions(-) diff --git a/interface/src/api/system.ts b/interface/src/api/system.ts index b1d4298e0..02b8b0dff 100644 --- a/interface/src/api/system.ts +++ b/interface/src/api/system.ts @@ -13,7 +13,7 @@ export const updateLogSettings = (data: LogSettings) => alovaInstance.Post('/rest/logSettings', data); export const fetchLogES = () => alovaInstance.Get('/es/log'); -// Get versions from github +// Get versions from GitHub export const getStableVersion = () => alovaInstanceGH.Get('latest', { transform(response: { data: { name: string } }) { @@ -34,9 +34,3 @@ export const uploadFile = (file: File) => { timeout: 60000 // override timeout for uploading firmware - 1 minute }); }; - -export const uploadURL = (data: { url: string }) => - alovaInstance.Post('/rest/uploadURL', data); - -export const checkUpgrade = (data: { version: string }) => - alovaInstance.Post('/rest/checkUpgrade', data); diff --git a/interface/src/app/main/Help.tsx b/interface/src/app/main/Help.tsx index e8bd18d22..a592ddd02 100644 --- a/interface/src/app/main/Help.tsx +++ b/interface/src/app/main/Help.tsx @@ -38,14 +38,17 @@ const Help = () => { const [customSupportIMG, setCustomSupportIMG] = useState(null); const [customSupportHTML, setCustomSupportHTML] = useState(null); - useRequest(() => callAction({ action: 'customSupport' })).onSuccess( - (event: { data: { img_url: string; html: string[] } }) => { - if (event.data) { - setCustomSupportIMG(event.data.img_url); - setCustomSupportHTML(event.data.html.join('
')); + useRequest(() => callAction({ action: 'customSupport' })).onSuccess((event) => { + if (event && event.data && Object.keys(event.data).length !== 0) { + const data = event.data.Support; + if (data.img_url) { + setCustomSupportIMG(data.img_url); + } + if (data.html) { + setCustomSupportHTML(data.html.join('
')); } } - ); + }); const { send: sendExportAllValues } = useRequest( () => callAction({ action: 'export', param: 'allvalues' }), @@ -97,7 +100,7 @@ const Help = () => { { } = useRequest(SystemApi.readSystemStatus); const { send: sendUploadURL } = useRequest( - (data: { url: string }) => uploadURL(data), + (url: string) => callAction({ action: 'uploadURL', param: url }), { immediate: false } @@ -143,7 +138,7 @@ const DownloadUpload = () => { }; const installFirmwareURL = async (url: string) => { - await sendUploadURL({ url: url }).catch((error: Error) => { + await sendUploadURL(url).catch((error: Error) => { toast.error(error.message); }); setRestarting(true); diff --git a/lib/framework/UploadFileService.cpp b/lib/framework/UploadFileService.cpp index a1ce63bb7..0a71854a4 100644 --- a/lib/framework/UploadFileService.cpp +++ b/lib/framework/UploadFileService.cpp @@ -24,11 +24,6 @@ UploadFileService::UploadFileService(AsyncWebServer * server, SecurityManager * [this](AsyncWebServerRequest * request, const String & filename, size_t index, uint8_t * data, size_t len, bool final) { handleUpload(request, filename, index, data, len, final); }); - - // upload from a URL - server->on(UPLOAD_URL_PATH, - securityManager->wrapCallback([this](AsyncWebServerRequest * request, JsonVariant json) { uploadURL(request, json); }, - AuthenticationPredicates::IS_AUTHENTICATED)); } void UploadFileService::handleUpload(AsyncWebServerRequest * request, const String & filename, size_t index, uint8_t * data, size_t len, bool final) { @@ -171,15 +166,3 @@ void UploadFileService::handleEarlyDisconnect() { _is_firmware = false; Update.abort(); } - -// upload firmware from a URL, like GitHub Release assets, Cloudflare R2 or Amazon S3 -void UploadFileService::uploadURL(AsyncWebServerRequest * request, JsonVariant json) { - if (json.is()) { - // this will keep a copy of the URL, but won't initiate the download yet - emsesp::EMSESP::system_.uploadFirmwareURL(json["url"].as()); - - // end the connection - AsyncWebServerResponse * response = request->beginResponse(200); - request->send(response); - } -} diff --git a/lib/framework/UploadFileService.h b/lib/framework/UploadFileService.h index 04a19a2c9..5afcb3028 100644 --- a/lib/framework/UploadFileService.h +++ b/lib/framework/UploadFileService.h @@ -12,7 +12,6 @@ #include #define UPLOAD_FILE_PATH "/rest/uploadFile" -#define UPLOAD_URL_PATH "/rest/uploadURL" #define TEMP_FILENAME_PATH "/tmp_upload" // for uploaded json files @@ -28,7 +27,6 @@ class UploadFileService { void handleUpload(AsyncWebServerRequest * request, const String & filename, size_t index, uint8_t * data, size_t len, bool final); void uploadComplete(AsyncWebServerRequest * request); void handleError(AsyncWebServerRequest * request, int code); - void uploadURL(AsyncWebServerRequest * request, JsonVariant json); void handleEarlyDisconnect(); }; diff --git a/mock-api/rest_server.ts b/mock-api/rest_server.ts index c2e449bd4..38e9a0474 100644 --- a/mock-api/rest_server.ts +++ b/mock-api/rest_server.ts @@ -140,19 +140,24 @@ function export_data(type: string) { // called by Action endpoint function custom_support() { + // return {}; return { - html: [ - 'This product is installed and managed by:', - '', - 'Bosch Installer Example', - 'Nefit Road 12', - '1234 AB Amsterdam', - 'Phone: +31 123 456 789', - 'email: support@boschinstaller.nl', - '', - "For help and questions please contact your installer." - ], - img_url: 'https://emsesp.org/_media/images/designer.png' + type: 'custom_support', + Support: { + html: [ + 'This product is installed and managed by:', + '', + 'Bosch Installer Example', + '', + 'Nefit Road 12', + '1234 AB Amsterdam', + 'Phone: +31 123 456 789', + 'email: support@boschinstaller.nl', + '', + "For help and questions please contact your installer." + ], + img_url: 'https://emsesp.org/_media/images/designer.png' + } }; } @@ -4581,12 +4586,6 @@ router return data; }) - // upload URL - .post('/rest/uploadURL', () => { - console.log('upload File from URL'); - return status(200); - }) - // generic action for all /rest/... endpoints // takes an action and param in JSON .post(EMSESP_ACTION_ENDPOINT, async (request: any) => { @@ -4602,6 +4601,10 @@ router } else if (action === 'checkUpgrade') { // check upgrade return check_upgrade(content.param); + } else if (action === 'uploadURL') { + // upload URL + console.log('upload File from URL', content.param); + return status(200); } } return status(404); // cmd not found diff --git a/project-words.txt b/project-words.txt index d1ea72cb8..834361ef3 100644 --- a/project-words.txt +++ b/project-words.txt @@ -1345,4 +1345,7 @@ zulufttemp zyxwvutsrqponmlkjihgfedcba Omea Bolv -hardwarestatus \ No newline at end of file +hardwarestatus +hpcurrpower +hppowerlimit +CUSTOMSUPPORT \ No newline at end of file diff --git a/src/system.cpp b/src/system.cpp index dd506cc6c..f37af24dd 100644 --- a/src/system.cpp +++ b/src/system.cpp @@ -1134,7 +1134,7 @@ bool System::check_restore() { // it's a custom support file - save it to /config new_file.close(); if (LittleFS.rename(TEMP_FILENAME_PATH, EMSESP_CUSTOMSUPPORT_FILE)) { - LOG_INFO("Custom support information loaded"); + LOG_DEBUG("Custom support information found"); return false; // no need to reboot } else { LOG_ERROR("Failed to save custom support file"); diff --git a/src/version.h b/src/version.h index b78c093ae..e0e7948ea 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define EMSESP_APP_VERSION "3.7.0-dev.41" +#define EMSESP_APP_VERSION "3.7.0-dev.42" diff --git a/src/web/WebStatusService.cpp b/src/web/WebStatusService.cpp index 642a82f6e..f630b3252 100644 --- a/src/web/WebStatusService.cpp +++ b/src/web/WebStatusService.cpp @@ -24,11 +24,12 @@ namespace emsesp { -WebStatusService::WebStatusService(AsyncWebServer * server, SecurityManager * securityManager) { +WebStatusService::WebStatusService(AsyncWebServer * server, SecurityManager * securityManager) + : _securityManager(securityManager) { // GET server->on(EMSESP_SYSTEM_STATUS_SERVICE_PATH, HTTP_GET, [this](AsyncWebServerRequest * request) { systemStatus(request); }); - // generic action - POST + // POST - generic action handler server->on(EMSESP_ACTION_SERVICE_PATH, [this](AsyncWebServerRequest * request, JsonVariant json) { action(request, json); }); } @@ -150,10 +151,14 @@ void WebStatusService::action(AsyncWebServerRequest * request, JsonVariant json) auto * response = new AsyncJsonResponse(); JsonObject root = response->getRoot(); - // get action and optional param + // get action and any optional param std::string action = json["action"]; std::string param = json["param"]; // is optional + // check if we're authenticated for admin tasks, some actions are only for admins + Authentication authentication = _securityManager->authenticateRequest(request); + bool is_admin = AuthenticationPredicates::IS_ADMIN(authentication); + bool ok = true; if (action == "checkUpgrade") { ok = checkUpgrade(root, param); @@ -161,6 +166,8 @@ void WebStatusService::action(AsyncWebServerRequest * request, JsonVariant json) ok = exportData(root, param); } else if (action == "customSupport") { ok = customSupport(root); + } else if (action == "uploadURL" && is_admin) { + ok = uploadURL(param.c_str()); } #if defined(EMSESP_UNITY) @@ -184,6 +191,7 @@ void WebStatusService::action(AsyncWebServerRequest * request, JsonVariant json) request->send(response); } +// action = checkUpgrade // returns true if there is an upgrade available bool WebStatusService::checkUpgrade(JsonObject root, std::string & latest_version) { version::Semver200_version settings_version(EMSESP_APP_VERSION); @@ -198,6 +206,7 @@ bool WebStatusService::checkUpgrade(JsonObject root, std::string & latest_versio return true; } +// action = allvalues // output all the devices and the values void WebStatusService::allvalues(JsonObject output) { JsonDocument doc; @@ -226,6 +235,7 @@ void WebStatusService::allvalues(JsonObject output) { EMSESP::temperaturesensor_.get_value_info(device_output, value); } +// action = export // returns data for a specific feature/settings as a json object bool WebStatusService::exportData(JsonObject root, std::string & type) { root["type"] = type; @@ -253,7 +263,8 @@ bool WebStatusService::exportData(JsonObject root, std::string & type) { return true; } -// custom support +// action = customSupport +// reads any upload customSupport.json file and sends to to Help page to be shown as Guest bool WebStatusService::customSupport(JsonObject root) { #ifndef EMSESP_STANDALONE // check if we have custom support file uploaded @@ -275,4 +286,12 @@ bool WebStatusService::customSupport(JsonObject root) { return true; } +// action = uploadURL +// uploads a firmware file from a URL +bool WebStatusService::uploadURL(const char * url) { + // this will keep a copy of the URL, but won't initiate the download yet + emsesp::EMSESP::system_.uploadFirmwareURL(url); + return true; +} + } // namespace emsesp diff --git a/src/web/WebStatusService.h b/src/web/WebStatusService.h index bc887156c..703464589 100644 --- a/src/web/WebStatusService.h +++ b/src/web/WebStatusService.h @@ -12,7 +12,7 @@ class WebStatusService { public: WebStatusService(AsyncWebServer * server, SecurityManager * securityManager); -// make all functions public so we can test in the debug and standalone mode +// make action function public so we can test in the debug and standalone mode #ifndef EMSESP_STANDALONE protected: #endif @@ -20,9 +20,14 @@ class WebStatusService { void action(AsyncWebServerRequest * request, JsonVariant json); private: + SecurityManager * _securityManager; + + // actions bool checkUpgrade(JsonObject root, std::string & latest_version); bool exportData(JsonObject root, std::string & type); bool customSupport(JsonObject root); + bool uploadURL(const char * url); + void allvalues(JsonObject output); }; From 670a5499dd151b21f602a29b95a280285cf0a286 Mon Sep 17 00:00:00 2001 From: proddy Date: Sun, 29 Sep 2024 16:42:09 +0200 Subject: [PATCH 05/22] use EMS-ESP-Modules.git@1.0.2 --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index 604d2e2e5..45f4bc6ab 100644 --- a/platformio.ini +++ b/platformio.ini @@ -78,7 +78,7 @@ check_flags = clangtidy: --checks=-*,clang-analyzer-*,performance-* lib_ldf_mode = chain+ lib_deps = - https://github.com/emsesp/EMS-ESP-Modules.git@1.0.1 + https://github.com/emsesp/EMS-ESP-Modules.git@1.0.2 ; ; builds for GitHub Actions CI From d5aac1789e868c95d623d84ed8dc03c9080c4fef Mon Sep 17 00:00:00 2001 From: proddy Date: Sun, 29 Sep 2024 17:44:03 +0200 Subject: [PATCH 06/22] rename custom_support type to customSupport --- src/system.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/system.cpp b/src/system.cpp index f37af24dd..62393ca89 100644 --- a/src/system.cpp +++ b/src/system.cpp @@ -1130,7 +1130,7 @@ bool System::check_restore() { } else if (settings_type == "entities") { // it's a entity file, just replace it and there's no need to reboot saveSettings(EMSESP_CUSTOMENTITY_FILE, "Entities", input); - } else if (settings_type == "custom_support") { + } else if (settings_type == "customSupport") { // it's a custom support file - save it to /config new_file.close(); if (LittleFS.rename(TEMP_FILENAME_PATH, EMSESP_CUSTOMSUPPORT_FILE)) { From 30f491b434572973de7281e8bcdcc1658224a1c2 Mon Sep 17 00:00:00 2001 From: proddy Date: Mon, 30 Sep 2024 10:08:50 +0200 Subject: [PATCH 07/22] fixes to https://github.com/emsesp/EMS-ESP32/pull/2066 --- src/web/WebStatusService.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/web/WebStatusService.cpp b/src/web/WebStatusService.cpp index f630b3252..1cf9f7cdb 100644 --- a/src/web/WebStatusService.cpp +++ b/src/web/WebStatusService.cpp @@ -209,9 +209,8 @@ bool WebStatusService::checkUpgrade(JsonObject root, std::string & latest_versio // action = allvalues // output all the devices and the values void WebStatusService::allvalues(JsonObject output) { - JsonDocument doc; - JsonObject device_output; - auto value = F_(values); + JsonObject device_output; + auto value = F_(values); // EMS-Device Entities for (const auto & emsdevice : EMSESP::emsdevices) { @@ -256,6 +255,7 @@ bool WebStatusService::exportData(JsonObject root, std::string & type) { } else if (type == "entities") { System::extractSettings(EMSESP_CUSTOMENTITY_FILE, "Entities", root); } else if (type == "allvalues") { + root.clear(); // don't need the "type" key allvalues(root); } else { return false; From 23c2f0ceba9d9951afd82b3fc897738c12750f46 Mon Sep 17 00:00:00 2001 From: proddy Date: Mon, 30 Sep 2024 15:26:47 +0200 Subject: [PATCH 08/22] add test img_url --- mock-api/rest_server.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/mock-api/rest_server.ts b/mock-api/rest_server.ts index 38e9a0474..ee91e53f8 100644 --- a/mock-api/rest_server.ts +++ b/mock-api/rest_server.ts @@ -157,6 +157,7 @@ function custom_support() { "For help and questions please contact your installer." ], img_url: 'https://emsesp.org/_media/images/designer.png' + // img_url: 'https://picsum.photos/200/300' } }; } From b5203e11f08c07a85735410756f0e02ebe5d2dd0 Mon Sep 17 00:00:00 2001 From: proddy Date: Mon, 30 Sep 2024 15:27:14 +0200 Subject: [PATCH 09/22] Show Flash size in `show system` --- src/system.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/system.cpp b/src/system.cpp index 62393ca89..c98f41512 100644 --- a/src/system.cpp +++ b/src/system.cpp @@ -994,8 +994,11 @@ void System::show_system(uuid::console::Shell & shell) { shell.printfln(" App used/free: %lu KB / %lu KB", appUsed(), appFree()); uint32_t FSused = LittleFS.usedBytes() / 1024; shell.printfln(" FS used/free: %lu KB / %lu KB", FSused, FStotal() - FSused); + shell.printfln(" Flash size: %lu KB", ESP.getFlashChipSize() / 1024); if (PSram()) { shell.printfln(" PSRAM size/free: %lu KB / %lu KB", PSram(), ESP.getFreePsram() / 1024); + } else { + shell.printfln(" PSRAM: not available"); } shell.println(); From d728b1c1168d56196bb407f18b59d9e60eb84d49 Mon Sep 17 00:00:00 2001 From: proddy Date: Mon, 30 Sep 2024 15:27:46 +0200 Subject: [PATCH 10/22] move info/commands/values to top so its not repeated --- src/command.cpp | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/src/command.cpp b/src/command.cpp index cad49e506..f80af6496 100644 --- a/src/command.cpp +++ b/src/command.cpp @@ -561,16 +561,13 @@ void Command::show(uuid::console::Shell & shell, uint8_t device_type, bool verbo } } - if (!verbose) { - sorted_cmds.push_back(F_(info)); - sorted_cmds.push_back(F_(commands)); - sorted_cmds.push_back(F_(values)); - } - sorted_cmds.sort(); // sort them // if not in verbose mode, just print them on a single line and exit if (!verbose) { + sorted_cmds.push_front(F_(info)); + sorted_cmds.push_front(F_(commands)); + sorted_cmds.push_front(F_(values)); for (const auto & cl : sorted_cmds) { shell.print(cl); shell.print(" "); @@ -582,14 +579,6 @@ void Command::show(uuid::console::Shell & shell, uint8_t device_type, bool verbo // verbose mode shell.printfln("\n%s%s %s:%s", COLOR_BOLD_ON, COLOR_YELLOW, EMSdevice::device_type_2_device_name(device_type), COLOR_RESET); - // we hard code 'info' and 'commands' commands so print them first - shell.printf(" info \t\t\t\t%slist all values %s*", COLOR_BRIGHT_CYAN, COLOR_BRIGHT_GREEN); - shell.println(COLOR_RESET); - 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); - for (const auto & cl : sorted_cmds) { // find and print the description for (const auto & cf : cmdfunctions_) { @@ -682,6 +671,13 @@ void Command::show_devices(uuid::console::Shell & shell) { // calls show with verbose mode set void Command::show_all(uuid::console::Shell & shell) { shell.printfln("Showing all available commands (%s*%s=authentication not required):", COLOR_BRIGHT_GREEN, COLOR_RESET); + shell.println("Each device has these additional default commands:"); + shell.printf(" info \t\t\t\t%slist all values with description%s*", COLOR_BRIGHT_CYAN, COLOR_BRIGHT_GREEN); + shell.println(COLOR_RESET); + 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); // show system ones first show(shell, EMSdevice::DeviceType::SYSTEM, true); From c8603dcd8139c21e73ea96377ade6d1a3c73b577 Mon Sep 17 00:00:00 2001 From: proddy Date: Mon, 30 Sep 2024 15:28:05 +0200 Subject: [PATCH 11/22] merge all "show" commands into a single command --- src/console.cpp | 79 ++++++++++++++++++--------------------- src/locale_common.h | 1 + src/locale_translations.h | 2 +- 3 files changed, 39 insertions(+), 43 deletions(-) diff --git a/src/console.cpp b/src/console.cpp index ca700c819..6c90b9815 100644 --- a/src/console.cpp +++ b/src/console.cpp @@ -76,54 +76,49 @@ static void setup_commands(std::shared_ptr & commands) { // // Show commands // - commands->add_command(ShellContext::MAIN, CommandFlags::USER, {F_(show)}, [=](Shell & shell, const std::vector & arguments) { - to_app(shell).system_.show_system(shell); - }); - commands->add_command(ShellContext::MAIN, - CommandFlags::USER, - string_vector{F_(show), F_(system)}, - [=](Shell & shell, const std::vector & arguments) { to_app(shell).system_.show_system(shell); }); + commands->add_command( + ShellContext::MAIN, + CommandFlags::USER, + {F_(show)}, + {F_(show_commands)}, + [=](Shell & shell, const std::vector & arguments) { + if (arguments.empty()) { + to_app(shell).system_.show_system(shell); + return; + } - commands->add_command(ShellContext::MAIN, - CommandFlags::ADMIN, - string_vector{F_(show), F_(users)}, - [](Shell & shell, const std::vector & arguments) { to_app(shell).system_.show_users(shell); }); - - commands->add_command(ShellContext::MAIN, - CommandFlags::USER, - string_vector{F_(show), F_(devices)}, - [](Shell & shell, const std::vector & arguments) { to_app(shell).show_devices(shell); }); - - commands->add_command(ShellContext::MAIN, CommandFlags::USER, string_vector{F_(show), F_(log)}, [](Shell & shell, const std::vector & arguments) { - to_app(shell).webLogService.show(shell); - }); - - - commands->add_command(ShellContext::MAIN, CommandFlags::USER, string_vector{F_(show), F_(ems)}, [](Shell & shell, const std::vector & arguments) { - to_app(shell).show_ems(shell); - }); - - commands->add_command(ShellContext::MAIN, CommandFlags::USER, string_vector{F_(show), F_(values)}, [](Shell & shell, const std::vector & arguments) { - to_app(shell).show_device_values(shell); - to_app(shell).show_sensor_values(shell); - }); - - commands->add_command(ShellContext::MAIN, - CommandFlags::USER, - string_vector{F_(show), F_(mqtt)}, - [](Shell & shell, const std::vector & arguments) { Mqtt::show_mqtt(shell); }); - - - commands->add_command(ShellContext::MAIN, - CommandFlags::USER, - string_vector{F_(show), F_(commands)}, - [](Shell & shell, const std::vector & arguments) { Command::show_all(shell); }); + auto command = arguments.front(); + if (command == F_(commands)) { + Command::show_all(shell); + } else if (command == F_(system)) { + to_app(shell).system_.show_system(shell); + } else if (command == F_(users) && (shell.has_flags(CommandFlags::ADMIN))) { + to_app(shell).system_.show_users(shell); // admin only + } else if (command == F_(devices)) { + to_app(shell).show_devices(shell); + } else if (command == F_(log)) { + to_app(shell).webLogService.show(shell); + } else if (command == F_(ems)) { + to_app(shell).show_ems(shell); + } else if (command == F_(values)) { + to_app(shell).show_device_values(shell); + to_app(shell).show_sensor_values(shell); + } else if (command == F_(mqtt)) { + Mqtt::show_mqtt(shell); + } else if (command == F_(commands)) { + Command::show_all(shell); + } else { + shell.printfln("Unknown show command"); + } + }, + [](Shell & shell, const std::vector & current_arguments, const std::string & next_argument) -> std::vector { + return std::vector{"system", "users", "devices", "log", "ems", "values", "mqtt", "commands"}; + }); // // System commands // - #if defined(EMSESP_TEST) // create commands test commands->add_command(ShellContext::MAIN, diff --git a/src/locale_common.h b/src/locale_common.h index 97fb49ff0..08a65d68c 100644 --- a/src/locale_common.h +++ b/src/locale_common.h @@ -154,6 +154,7 @@ MAKE_WORD_CUSTOM(deviceid_mandatory, "") MAKE_WORD_CUSTOM(device_type_optional, "[device]") MAKE_WORD_CUSTOM(invalid_log_level, "Invalid log level") MAKE_WORD_CUSTOM(log_level_optional, "[level]") +MAKE_WORD_CUSTOM(show_commands, "[system | users | devices | log | ems | values | mqtt | commands") MAKE_WORD_CUSTOM(name_mandatory, "") MAKE_WORD_CUSTOM(name_optional, "[name]") MAKE_WORD_CUSTOM(new_password_prompt1, "Enter new password: ") diff --git a/src/locale_translations.h b/src/locale_translations.h index 2fbbc0ec9..55a49b86c 100644 --- a/src/locale_translations.h +++ b/src/locale_translations.h @@ -63,7 +63,7 @@ MAKE_WORD_TRANSLATION(info_cmd, "list all values (verbose)", "Liste aller Werte" 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(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(setiovalue_cmd, "set io value", "Setze Werte E/A", "instellen standaardwaarde", "", "ustaw wartość", "sett en io verdi", "", "Giriş/Çıkış değerlerini ayarla", "imposta valore io", "nastaviť hodnotu io") // TODO translate +MAKE_WORD_TRANSLATION(setiovalue_cmd, "set I/O value", "Setze Werte E/A", "instellen standaardwaarde", "", "ustaw wartość", "sett en io verdi", "", "Giriş/Çıkış değerlerini ayarla", "imposta valore io", "nastaviť hodnotu io") // TODO translate MAKE_WORD_TRANSLATION(changeloglevel_cmd, "change log level", "Ändere Protokollebene", "aanpassen log niveau", "", "zmień poziom log-u", "endre loggnivå", "", "Kayıt seviyesini değiştir", "cambia livello registrazione", "zmeniť úroveň protokolu") // TODO translate MAKE_WORD_TRANSLATION(fetch_cmd, "refresh all EMS values", "Aktualisiere alle EMS-Werte", "Verversen alle EMS waardes", "", "odśwież wszystkie wartości EMS", "oppfrisk alle EMS verdier", "", "Bütün EMS değerlerini yenile", "aggiornare tutti i valori EMS", "obnoviť všetky hodnoty EMS") // TODO translate MAKE_WORD_TRANSLATION(restart_cmd, "restart EMS-ESP", "Neustart", "opnieuw opstarten", "", "uruchom ponownie EMS-ESP", "restart EMS-ESP", "redémarrer EMS-ESP", "EMS-ESPyi yeniden başlat", "riavvia EMS-ESP", "reštart EMS-ESP") // TODO translate From ed685d4a5eaf95b283dfe9e66446c46d9e3b7076 Mon Sep 17 00:00:00 2001 From: proddy Date: Mon, 30 Sep 2024 15:55:46 +0200 Subject: [PATCH 12/22] remove duplicate condition --- src/console.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/console.cpp b/src/console.cpp index 6c90b9815..bd7aff5e0 100644 --- a/src/console.cpp +++ b/src/console.cpp @@ -105,8 +105,6 @@ static void setup_commands(std::shared_ptr & commands) { to_app(shell).show_sensor_values(shell); } else if (command == F_(mqtt)) { Mqtt::show_mqtt(shell); - } else if (command == F_(commands)) { - Command::show_all(shell); } else { shell.printfln("Unknown show command"); } From 88a01426c1f393192ba00d948137f820c17b2ac3 Mon Sep 17 00:00:00 2001 From: proddy Date: Tue, 1 Oct 2024 09:56:32 +0200 Subject: [PATCH 13/22] fix referer for external images --- interface/src/app/main/Help.tsx | 183 ++++++++++++++++---------------- 1 file changed, 89 insertions(+), 94 deletions(-) diff --git a/interface/src/app/main/Help.tsx b/interface/src/app/main/Help.tsx index a592ddd02..da45a0f1b 100644 --- a/interface/src/app/main/Help.tsx +++ b/interface/src/app/main/Help.tsx @@ -76,114 +76,109 @@ const Help = () => { }); return ( - <> - - } + + } + sx={{ + borderRadius: 3, + border: '2px solid grey', + justifyContent: 'space-evenly', + alignItems: 'center' + }} + > + + {customSupportHTML ? ( +
+ ) : ( + LL.HELP_INFORMATION_5() + )} + + - - {customSupportHTML ? ( -
- ) : ( - LL.HELP_INFORMATION_5() - )} - - - + src={customSupportIMG || 'https://emsesp.org/_media/images/installer.jpeg'} + /> + - {me.admin && ( - - - - - - - - - - - + {me.admin && ( + + + + + + + + + + + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - )} - - - - {LL.HELP_INFORMATION_4()} - - - + + + + + + + + + + + + )} + + + {LL.HELP_INFORMATION_4()} + + - + - - ©  - - {'emsesp.org'} - - - - + + + + ©  + + {'emsesp.org'} + + + ); }; From eef130e229a69015e69d81b2a70948b6d7264b26 Mon Sep 17 00:00:00 2001 From: proddy Date: Wed, 2 Oct 2024 08:53:55 +0200 Subject: [PATCH 14/22] more spacing after back arrow --- interface/src/components/layout/LayoutAppBar.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/interface/src/components/layout/LayoutAppBar.tsx b/interface/src/components/layout/LayoutAppBar.tsx index c8f31ee0c..f254ccc77 100644 --- a/interface/src/components/layout/LayoutAppBar.tsx +++ b/interface/src/components/layout/LayoutAppBar.tsx @@ -41,6 +41,7 @@ const LayoutAppBar = ({ title, onToggleDrawer }: LayoutAppBarProps) => { {show_back && ( navigate(pathnames[0])} From fc896914e9f2b285e02c5c5a3837bce9acbb5b6f Mon Sep 17 00:00:00 2001 From: proddy Date: Wed, 2 Oct 2024 08:54:17 +0200 Subject: [PATCH 15/22] sonarlint --- .vscode/settings.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 57c1e2f0c..f8137d519 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -96,5 +96,6 @@ "sonarlint.connectedMode.project": { "connectionId": "emsesp", "projectKey": "emsesp_EMS-ESP32" - } + }, + "sonarlint.pathToCompileCommands": "${workspaceFolder}/compile_commands.json" } \ No newline at end of file From fe0d0bb11c721f0716a69d7ccd1c95a234204bee Mon Sep 17 00:00:00 2001 From: proddy Date: Wed, 2 Oct 2024 08:54:31 +0200 Subject: [PATCH 16/22] remove data type --- interface/src/app/settings/DownloadUpload.tsx | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/interface/src/app/settings/DownloadUpload.tsx b/interface/src/app/settings/DownloadUpload.tsx index ff400cdb9..c3cc12e1a 100644 --- a/interface/src/app/settings/DownloadUpload.tsx +++ b/interface/src/app/settings/DownloadUpload.tsx @@ -69,11 +69,7 @@ const DownloadUpload = () => { immediate: false }); - const { - data: data, - send: loadData, - error - } = useRequest(SystemApi.readSystemStatus); + const { data, send: loadData, error } = useRequest(SystemApi.readSystemStatus); const { send: sendUploadURL } = useRequest( (url: string) => callAction({ action: 'uploadURL', param: url }), From 465f14a1135e241b50acc92aa736a21c09f42b6a Mon Sep 17 00:00:00 2001 From: proddy Date: Wed, 2 Oct 2024 08:54:57 +0200 Subject: [PATCH 17/22] package update --- interface/package.json | 2 +- interface/yarn.lock | 116 ++++++++++++++++++++--------------------- 2 files changed, 59 insertions(+), 59 deletions(-) diff --git a/interface/package.json b/interface/package.json index b331a4168..f10624f8a 100644 --- a/interface/package.json +++ b/interface/package.json @@ -58,7 +58,7 @@ "prettier": "^3.3.3", "rollup-plugin-visualizer": "^5.12.0", "terser": "^5.34.1", - "typescript-eslint": "8.7.0", + "typescript-eslint": "8.8.0", "vite": "^5.4.8", "vite-plugin-imagemin": "^0.6.1", "vite-tsconfig-paths": "^5.0.1" diff --git a/interface/yarn.lock b/interface/yarn.lock index 398f61769..34380ea50 100644 --- a/interface/yarn.lock +++ b/interface/yarn.lock @@ -1546,15 +1546,15 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/eslint-plugin@npm:8.7.0": - version: 8.7.0 - resolution: "@typescript-eslint/eslint-plugin@npm:8.7.0" +"@typescript-eslint/eslint-plugin@npm:8.8.0": + version: 8.8.0 + resolution: "@typescript-eslint/eslint-plugin@npm:8.8.0" dependencies: "@eslint-community/regexpp": "npm:^4.10.0" - "@typescript-eslint/scope-manager": "npm:8.7.0" - "@typescript-eslint/type-utils": "npm:8.7.0" - "@typescript-eslint/utils": "npm:8.7.0" - "@typescript-eslint/visitor-keys": "npm:8.7.0" + "@typescript-eslint/scope-manager": "npm:8.8.0" + "@typescript-eslint/type-utils": "npm:8.8.0" + "@typescript-eslint/utils": "npm:8.8.0" + "@typescript-eslint/visitor-keys": "npm:8.8.0" graphemer: "npm:^1.4.0" ignore: "npm:^5.3.1" natural-compare: "npm:^1.4.0" @@ -1565,66 +1565,66 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 10c0/f04d6fa6a30e32d51feba0f08789f75ca77b6b67cfe494bdbd9aafa241871edc918fa8b344dc9d13dd59ae055d42c3920f0e542534f929afbfdca653dae598fa + checksum: 10c0/98ac37587eda02a713710f0a62ca979833482024968f1d1735881718abe102a6b49707db4f1dac0d7c731d1cbf8111d829c5125348d4829ab6fad7a7b3b344e4 languageName: node linkType: hard -"@typescript-eslint/parser@npm:8.7.0": - version: 8.7.0 - resolution: "@typescript-eslint/parser@npm:8.7.0" +"@typescript-eslint/parser@npm:8.8.0": + version: 8.8.0 + resolution: "@typescript-eslint/parser@npm:8.8.0" dependencies: - "@typescript-eslint/scope-manager": "npm:8.7.0" - "@typescript-eslint/types": "npm:8.7.0" - "@typescript-eslint/typescript-estree": "npm:8.7.0" - "@typescript-eslint/visitor-keys": "npm:8.7.0" + "@typescript-eslint/scope-manager": "npm:8.8.0" + "@typescript-eslint/types": "npm:8.8.0" + "@typescript-eslint/typescript-estree": "npm:8.8.0" + "@typescript-eslint/visitor-keys": "npm:8.8.0" debug: "npm:^4.3.4" peerDependencies: eslint: ^8.57.0 || ^9.0.0 peerDependenciesMeta: typescript: optional: true - checksum: 10c0/1d5020ff1f5d3eb726bc6034d23f0a71e8fe7a713756479a0a0b639215326f71c0b44e2c25cc290b4e7c144bd3c958f1405199711c41601f0ea9174068714a64 + checksum: 10c0/cf72a644b89c62cd55b09fa1d22b51a2c726714aac344a797f0c2ad80bfbabcb7567000fadd4ea8188aa1d923675bebdca06acc1d28ac1b8360bf28a36b46f3a languageName: node linkType: hard -"@typescript-eslint/scope-manager@npm:8.7.0": - version: 8.7.0 - resolution: "@typescript-eslint/scope-manager@npm:8.7.0" +"@typescript-eslint/scope-manager@npm:8.8.0": + version: 8.8.0 + resolution: "@typescript-eslint/scope-manager@npm:8.8.0" dependencies: - "@typescript-eslint/types": "npm:8.7.0" - "@typescript-eslint/visitor-keys": "npm:8.7.0" - checksum: 10c0/8b731a0d0bd3e8f6a322b3b25006f56879b5d2aad86625070fa438b803cf938cb8d5c597758bfa0d65d6e142b204dc6f363fa239bc44280a74e25aa427408eda + "@typescript-eslint/types": "npm:8.8.0" + "@typescript-eslint/visitor-keys": "npm:8.8.0" + checksum: 10c0/29ddf589ff0e465dbbf3eb87b79a29face4ec5a6cb617bbaafbac6ae8340d376b5b405bca762ee1c7a40cbdf7912a32734f9119f6864df048c7a0b2de21bdd3d languageName: node linkType: hard -"@typescript-eslint/type-utils@npm:8.7.0": - version: 8.7.0 - resolution: "@typescript-eslint/type-utils@npm:8.7.0" +"@typescript-eslint/type-utils@npm:8.8.0": + version: 8.8.0 + resolution: "@typescript-eslint/type-utils@npm:8.8.0" dependencies: - "@typescript-eslint/typescript-estree": "npm:8.7.0" - "@typescript-eslint/utils": "npm:8.7.0" + "@typescript-eslint/typescript-estree": "npm:8.8.0" + "@typescript-eslint/utils": "npm:8.8.0" debug: "npm:^4.3.4" ts-api-utils: "npm:^1.3.0" peerDependenciesMeta: typescript: optional: true - checksum: 10c0/2bd9fb93a50ff1c060af41528e39c775ae93b09dd71450defdb42a13c68990dd388460ae4e81fb2f4a49c38dc12152c515d43e845eca6198c44b14aab66733bc + checksum: 10c0/d6ee11f4686fb54daea1f436f73b96eb31a95f6e535abc0534abf5794e7597669a92d12300969c8afee0fc1912dbc1591664f7e37f0da5935016cc981b2921a8 languageName: node linkType: hard -"@typescript-eslint/types@npm:8.7.0": - version: 8.7.0 - resolution: "@typescript-eslint/types@npm:8.7.0" - checksum: 10c0/f7529eaea4ecc0f5e2d94ea656db8f930f6d1c1e65a3ffcb2f6bec87361173de2ea981405c2c483a35a927b3bdafb606319a1d0395a6feb1284448c8ba74c31e +"@typescript-eslint/types@npm:8.8.0": + version: 8.8.0 + resolution: "@typescript-eslint/types@npm:8.8.0" + checksum: 10c0/cd168fafcaf77641b023c4405ea3a8c30fbad1737abb5aec9fce67fe2ae20224b624b5a2e3e84900ba81dc7dd33343add3653763703a225326cc81356b182d09 languageName: node linkType: hard -"@typescript-eslint/typescript-estree@npm:8.7.0": - version: 8.7.0 - resolution: "@typescript-eslint/typescript-estree@npm:8.7.0" +"@typescript-eslint/typescript-estree@npm:8.8.0": + version: 8.8.0 + resolution: "@typescript-eslint/typescript-estree@npm:8.8.0" dependencies: - "@typescript-eslint/types": "npm:8.7.0" - "@typescript-eslint/visitor-keys": "npm:8.7.0" + "@typescript-eslint/types": "npm:8.8.0" + "@typescript-eslint/visitor-keys": "npm:8.8.0" debug: "npm:^4.3.4" fast-glob: "npm:^3.3.2" is-glob: "npm:^4.0.3" @@ -1634,31 +1634,31 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 10c0/d714605b6920a9631ab1511b569c1c158b1681c09005ab240125c442a63e906048064151a61ce5eb5f8fe75cea861ce5ae1d87be9d7296b012e4ab6d88755e8b + checksum: 10c0/9b9e849f6b2d4e250840ef8e05f55a97d6598adaf48c1e6df83084b94c30feca6a3e7916ee1c235178188d0db6364a877cbf8fe218c36d5f8d5acb50767f3273 languageName: node linkType: hard -"@typescript-eslint/utils@npm:8.7.0": - version: 8.7.0 - resolution: "@typescript-eslint/utils@npm:8.7.0" +"@typescript-eslint/utils@npm:8.8.0": + version: 8.8.0 + resolution: "@typescript-eslint/utils@npm:8.8.0" dependencies: "@eslint-community/eslint-utils": "npm:^4.4.0" - "@typescript-eslint/scope-manager": "npm:8.7.0" - "@typescript-eslint/types": "npm:8.7.0" - "@typescript-eslint/typescript-estree": "npm:8.7.0" + "@typescript-eslint/scope-manager": "npm:8.8.0" + "@typescript-eslint/types": "npm:8.8.0" + "@typescript-eslint/typescript-estree": "npm:8.8.0" peerDependencies: eslint: ^8.57.0 || ^9.0.0 - checksum: 10c0/7355b754ce2fc118773ed27a3e02b7dfae270eec73c2d896738835ecf842e8309544dfd22c5105aba6cae2787bfdd84129bbc42f4b514f57909dc7f6890b8eba + checksum: 10c0/fcf2dfd4a2d9491aa096a29c2c1fdd891ca3c13933d20cfea44e51b3d10a397e7ed9a9cd71ac9a29e8c4706264ae00c25a29394e2a6bda3291be298062901f2c languageName: node linkType: hard -"@typescript-eslint/visitor-keys@npm:8.7.0": - version: 8.7.0 - resolution: "@typescript-eslint/visitor-keys@npm:8.7.0" +"@typescript-eslint/visitor-keys@npm:8.8.0": + version: 8.8.0 + resolution: "@typescript-eslint/visitor-keys@npm:8.8.0" dependencies: - "@typescript-eslint/types": "npm:8.7.0" + "@typescript-eslint/types": "npm:8.8.0" eslint-visitor-keys: "npm:^3.4.3" - checksum: 10c0/1240da13c15f9f875644b933b0ad73713ef12f1db5715236824c1ec359e6ef082ce52dd9b2186d40e28be6a816a208c226e6e9af96e5baeb24b4399fe786ae7c + checksum: 10c0/580ce74c9b09b9e6a6f3f0ac2d2f0c6a6b983a78ce3b2544822ee08107c57142858d674897f61ff32a9a5e8fca00c916545c159bb75d134f4380884642542d38 languageName: node linkType: hard @@ -1701,7 +1701,7 @@ __metadata: terser: "npm:^5.34.1" typesafe-i18n: "npm:^5.26.2" typescript: "npm:^5.6.2" - typescript-eslint: "npm:8.7.0" + typescript-eslint: "npm:8.8.0" vite: "npm:^5.4.8" vite-plugin-imagemin: "npm:^0.6.1" vite-tsconfig-paths: "npm:^5.0.1" @@ -6803,17 +6803,17 @@ __metadata: languageName: node linkType: hard -"typescript-eslint@npm:8.7.0": - version: 8.7.0 - resolution: "typescript-eslint@npm:8.7.0" +"typescript-eslint@npm:8.8.0": + version: 8.8.0 + resolution: "typescript-eslint@npm:8.8.0" dependencies: - "@typescript-eslint/eslint-plugin": "npm:8.7.0" - "@typescript-eslint/parser": "npm:8.7.0" - "@typescript-eslint/utils": "npm:8.7.0" + "@typescript-eslint/eslint-plugin": "npm:8.8.0" + "@typescript-eslint/parser": "npm:8.8.0" + "@typescript-eslint/utils": "npm:8.8.0" peerDependenciesMeta: typescript: optional: true - checksum: 10c0/c0c3f909227c664f193d11a912851d6144a7cfcc0ac5e57f695c3e50679ef02bb491cc330ad9787e00170ce3be3a3b8c80bb81d5e20a40c1b3ee713ec3b0955a + checksum: 10c0/545f0ce051282921aff56288baf288cffe6f7bafee5149f1b87af2c67f81f8c2088924a2e0fc0f0dcd12692b6a97eca10149a619c8c85d4aaef2fe763938da8d languageName: node linkType: hard From e5b98daddea79e9b64c90e6e086452118ebd5c2d Mon Sep 17 00:00:00 2001 From: proddy Date: Wed, 2 Oct 2024 09:02:24 +0200 Subject: [PATCH 18/22] code cleanup - sonarlint --- .gitignore | 3 +++ .sonarlint/connectedMode.json | 4 +++ lib/framework/UploadFileService.cpp | 1 - src/analogsensor.cpp | 5 +--- src/command.cpp | 10 +++---- src/emsdevice.cpp | 16 +++++------ src/emsdevice.h | 34 +++++++++++------------ src/emsesp.cpp | 6 ++--- src/helpers.cpp | 4 --- src/modbus.h | 4 +-- src/roomcontrol.cpp | 5 +--- src/shower.cpp | 3 +-- src/system.cpp | 36 +++++++++---------------- src/system.h | 1 - src/temperaturesensor.cpp | 24 ++++++++--------- src/temperaturesensor.h | 10 +++---- src/web/WebAPIService.cpp | 4 +-- src/web/WebCustomEntityService.cpp | 34 +++++++++++------------ src/web/WebCustomEntityService.h | 6 ++--- src/web/WebSchedulerService.cpp | 6 ++--- {src => test/test_modbus}/modbus_test.h | 0 21 files changed, 97 insertions(+), 119 deletions(-) create mode 100644 .sonarlint/connectedMode.json rename {src => test/test_modbus}/modbus_test.h (100%) diff --git a/.gitignore b/.gitignore index 387e569b9..c6cb358e8 100644 --- a/.gitignore +++ b/.gitignore @@ -68,3 +68,6 @@ venv/ # cspell words-found-verbose.txt + +# sonarlint +compile_commands.json diff --git a/.sonarlint/connectedMode.json b/.sonarlint/connectedMode.json new file mode 100644 index 000000000..a3f4f6d2f --- /dev/null +++ b/.sonarlint/connectedMode.json @@ -0,0 +1,4 @@ +{ + "sonarCloudOrganization": "emsesp", + "projectKey": "emsesp_EMS-ESP32" +} \ No newline at end of file diff --git a/lib/framework/UploadFileService.cpp b/lib/framework/UploadFileService.cpp index 0a71854a4..7e61b5a75 100644 --- a/lib/framework/UploadFileService.cpp +++ b/lib/framework/UploadFileService.cpp @@ -86,7 +86,6 @@ void UploadFileService::handleUpload(AsyncWebServerRequest * request, const Stri Update.setMD5(_md5.data()); _md5.front() = '\0'; } - // emsesp::EMSESP::system_.upload_status(true); // force just in case, this is stop UART, MQTT and other services request->onDisconnect([this] { handleEarlyDisconnect(); }); // success, let's make sure we end the update if the client hangs up } else { handleError(request, 507); // failed to begin, send an error response Insufficient Storage diff --git a/src/analogsensor.cpp b/src/analogsensor.cpp index e839fec13..7b1703f54 100644 --- a/src/analogsensor.cpp +++ b/src/analogsensor.cpp @@ -102,9 +102,6 @@ void AnalogSensor::reload(bool get_nvs) { } } if (!found) { - // if (!System::is_valid_gpio(sensor.gpio)) { - // continue; - // } sensors_.emplace_back(sensor.gpio, sensor.name, sensor.offset, sensor.factor, sensor.uom, sensor.type); sensors_.back().ha_registered = false; // this will trigger recreate of the HA config if (sensor.type == AnalogType::COUNTER || sensor.type >= AnalogType::DIGITAL_OUT) { @@ -610,7 +607,7 @@ void AnalogSensor::publish_values(const bool force) { // see if we need to create the [devs] discovery section, as this needs only to be done once for all sensors bool is_ha_device_created = false; - for (auto & sensor : sensors_) { + for (auto const & sensor : sensors_) { if (sensor.ha_registered) { is_ha_device_created = true; break; diff --git a/src/command.cpp b/src/command.cpp index f80af6496..2befa9172 100644 --- a/src/command.cpp +++ b/src/command.cpp @@ -420,7 +420,7 @@ uint8_t Command::call(const uint8_t device_type, const char * command, const cha } else { if (single_command) { // log as DEBUG (TRACE) regardless if compiled with EMSESP_DEBUG - logger_.debug(("%sCalled command %s"), ro.c_str(), info_s); + logger_.debug("%sCalled command %s", ro.c_str(), info_s); } else { if (id > 0) { LOG_INFO(("%sCalled command %s with value %s and id %d on device 0x%02X"), ro.c_str(), info_s, value, id, device_id); @@ -499,7 +499,7 @@ void Command::erase_command(const uint8_t device_type, const char * cmd, uint8_t return; } auto it = cmdfunctions_.begin(); - for (auto & cf : cmdfunctions_) { + for (auto const & cf : cmdfunctions_) { if (Helpers::toLower(cmd) == Helpers::toLower(cf.cmd_) && (cf.device_type_ == device_type) && ((flag & 0x3F) == (cf.flags_ & 0x3F))) { cmdfunctions_.erase(it); return; @@ -565,9 +565,9 @@ void Command::show(uuid::console::Shell & shell, uint8_t device_type, bool verbo // if not in verbose mode, just print them on a single line and exit if (!verbose) { - sorted_cmds.push_front(F_(info)); - sorted_cmds.push_front(F_(commands)); - sorted_cmds.push_front(F_(values)); + sorted_cmds.emplace_front(F_(info)); + sorted_cmds.emplace_front(F_(commands)); + sorted_cmds.emplace_front(F_(values)); for (const auto & cl : sorted_cmds) { shell.print(cl); shell.print(" "); diff --git a/src/emsdevice.cpp b/src/emsdevice.cpp index c4909c314..9fda392c5 100644 --- a/src/emsdevice.cpp +++ b/src/emsdevice.cpp @@ -297,7 +297,7 @@ uint8_t EMSdevice::decode_brand(uint8_t value) { } // returns string of a human friendly description of the EMS device -const std::string EMSdevice::to_string() { +std::string EMSdevice::to_string() { // for devices that haven't been lookup yet, don't show all details if (product_id_ == 0) { return std::string(name()) + " (DeviceID:" + Helpers::hextoa(device_id_) + ")"; @@ -313,7 +313,7 @@ const std::string EMSdevice::to_string() { // returns out brand + device name // translated -const std::string EMSdevice::to_string_short() { +std::string EMSdevice::to_string_short() { if (brand_ == Brand::NO_BRAND) { return std::string(device_type_2_device_name_translated()) + ": " + name(); } @@ -553,11 +553,11 @@ void EMSdevice::add_device_value(int8_t tag, // to b } } - uint8_t state = DeviceValueState::DV_DEFAULT; // determine state - std::string custom_fullname = std::string(""); // custom fullname - auto short_name = name[0]; // entity name - bool has_cmd = (f != nullptr); // is it a command? - bool ignore = false; // ignore this entity? + uint8_t state = DeviceValueState::DV_DEFAULT; // determine state + auto custom_fullname = std::string(""); // custom fullname + auto short_name = name[0]; // entity name + bool has_cmd = (f != nullptr); // is it a command? + bool ignore = false; // ignore this entity? // get fullname, getting translation if it exists const char * const * fullname; @@ -1025,7 +1025,7 @@ void EMSdevice::generate_values_web(JsonObject output) { // this is used only for WebCustomizationService::device_entities() void EMSdevice::generate_values_web_customization(JsonArray output) { for (auto & dv : devicevalues_) { - // also show commands and entities that have an empty full name + // also show commands and entities that have an empty fullname JsonObject obj = output.add(); uint8_t fahrenheit = !EMSESP::system_.fahrenheit() ? 0 : (dv.uom == DeviceValueUOM::DEGREES) ? 2 : (dv.uom == DeviceValueUOM::DEGREES_R) ? 1 : 0; diff --git a/src/emsdevice.h b/src/emsdevice.h index d9e299830..cb7716ed9 100644 --- a/src/emsdevice.h +++ b/src/emsdevice.h @@ -42,7 +42,6 @@ class EMSdevice { , flags_(flags) , brand_(brand) { strlcpy(version_, version, sizeof(version_)); - custom_name_ = ""; // init custom name to blank } // static functions, used outside the class like in console.cpp, command.cpp, emsesp.cpp, mqtt.cpp @@ -113,7 +112,7 @@ class EMSdevice { } // set custom device name - inline void custom_name(std::string & custom_name) { + inline void custom_name(std::string const & custom_name) { custom_name_ = custom_name; } std::string name(); // returns either default or custom name if defined @@ -205,17 +204,16 @@ class EMSdevice { int get_modbus_value(uint8_t tag, const std::string & shortname, std::vector & result); int modbus_value_to_json(uint8_t tag, const std::string & shortname, const std::vector & modbus_data, JsonObject jsonValue); - const char * brand_to_char(); - const std::string to_string(); - const std::string to_string_short(); + const char * brand_to_char(); + std::string to_string(); + std::string to_string_short(); enum Handlers : uint8_t { ALL, RECEIVED, FETCHED, PENDING, IGNORED }; void show_telegram_handlers(uuid::console::Shell & shell) const; char * show_telegram_handlers(char * result, const size_t len, const uint8_t handlers); void show_mqtt_handlers(uuid::console::Shell & shell) const; - // void list_device_entries(JsonObject output) const; - void add_handlers_ignored(const uint16_t handler); + void add_handlers_ignored(const uint16_t handler); void set_climate_minmax(int8_t tag, int16_t min, uint32_t max); void setCustomizationEntity(const std::string & entity_id); @@ -456,15 +454,13 @@ class EMSdevice { uint8_t count_entities(); bool has_entities() const; - /* - void reserve_device_values(uint8_t elements) { - devicevalues_.reserve(elements); - } + // void reserve_device_values(uint8_t elements) { + // devicevalues_.reserve(elements); + // } - void reserve_telegram_functions(uint8_t elements) { - telegram_functions_.reserve(elements); - } - */ + // void reserve_telegram_functions(uint8_t elements) { + // telegram_functions_.reserve(elements); + // } #if defined(EMSESP_STANDALONE) struct TelegramFunctionDump { @@ -487,10 +483,10 @@ class EMSdevice { uint8_t device_id_ = 0; uint8_t product_id_ = 0; char version_[6]; - const char * default_name_; // the fixed name the EMS model taken from the device library - std::string custom_name_; // custom name - uint8_t flags_ = 0; - uint8_t brand_ = Brand::NO_BRAND; + const char * default_name_; // the fixed name the EMS model taken from the device library + std::string custom_name_ = ""; // custom name + uint8_t flags_ = 0; + uint8_t brand_ = Brand::NO_BRAND; bool ha_config_done_ = false; bool has_update_ = false; diff --git a/src/emsesp.cpp b/src/emsesp.cpp index bf81c7f4e..12a515590 100644 --- a/src/emsesp.cpp +++ b/src/emsesp.cpp @@ -208,7 +208,7 @@ void EMSESP::uart_init() { uint8_t tx_mode = 0; uint8_t rx_gpio = 0; uint8_t tx_gpio = 0; - EMSESP::webSettingsService.read([&](WebSettings & settings) { + EMSESP::webSettingsService.read([&](WebSettings const & settings) { tx_mode = settings.tx_mode; rx_gpio = settings.rx_gpio; tx_gpio = settings.tx_gpio; @@ -279,7 +279,7 @@ void EMSESP::show_ems(uuid::console::Shell & shell) { if (bus_status() != BUS_STATUS_OFFLINE) { shell.printfln("EMS Bus info:"); - EMSESP::webSettingsService.read([&](WebSettings & settings) { shell.printfln(" Tx mode: %d", settings.tx_mode); }); + EMSESP::webSettingsService.read([&](WebSettings const & settings) { shell.printfln(" Tx mode: %d", settings.tx_mode); }); shell.printfln(" Bus protocol: %s", EMSbus::is_ht3() ? "HT3" : "Buderus"); shell.printfln(" #recognized EMS devices: %d", EMSESP::emsdevices.size()); shell.printfln(" #telegrams received: %d", rxservice_.telegram_count()); @@ -1317,7 +1317,7 @@ bool EMSESP::add_device(const uint8_t device_id, const uint8_t product_id, const emsdevices.push_back(EMSFactory::add(device_type, device_id, product_id, version, default_name, flags, brand)); // see if we have a custom device name in our Customizations list, and if so set it - webCustomizationService.read([&](WebCustomization & settings) { + webCustomizationService.read([&](WebCustomization const & settings) { for (EntityCustomization e : settings.entityCustomizations) { if ((e.device_id == device_id) && (e.product_id == product_id)) { LOG_DEBUG("Have customizations for %s with deviceID 0x%02X productID %d", e.custom_name.c_str(), device_id, product_id); diff --git a/src/helpers.cpp b/src/helpers.cpp index 508f1819c..2d8f9a76c 100644 --- a/src/helpers.cpp +++ b/src/helpers.cpp @@ -798,10 +798,6 @@ uint16_t Helpers::string2minutes(const std::string & str) { if (tmp > 60) { return 0; } - // Serial.print("*"); - // Serial.print(tmp); - // Serial.println("*"); - res += tmp; } // Or we got an extra colon diff --git a/src/modbus.h b/src/modbus.h index 5e11f4061..5e16344e4 100644 --- a/src/modbus.h +++ b/src/modbus.h @@ -14,9 +14,7 @@ #include #if defined(EMSESP_STANDALONE) - -#include - +#include <../test/test_modbus/modbus_test.h> #endif #ifndef EMSESP_STANDALONE diff --git a/src/roomcontrol.cpp b/src/roomcontrol.cpp index 12eed60f6..890ee7ee3 100644 --- a/src/roomcontrol.cpp +++ b/src/roomcontrol.cpp @@ -124,10 +124,7 @@ void Roomctrl::send(uint8_t addr) { } temperature(addr, 0x10, hc); // send to master-thermostat } - } else if (type_[hc] == RC200 || type_[hc] == RC100) { - send_time_[hc] = uuid::get_uptime(); - temperature(addr, 0x10, hc); - } else if (type_[hc] == FB10) { + } else if (type_[hc] == RC200 || type_[hc] == RC100 || type_[hc] == FB10) { send_time_[hc] = uuid::get_uptime(); temperature(addr, 0x10, hc); // send to master-thermostat (https://github.com/emsesp/EMS-ESP32/issues/336) } else { // type==RC20 or SENSOR diff --git a/src/shower.cpp b/src/shower.cpp index cc8210740..1460c93f6 100644 --- a/src/shower.cpp +++ b/src/shower.cpp @@ -25,7 +25,7 @@ uuid::log::Logger Shower::logger_{F_(shower), uuid::log::Facility::CONSOLE}; static bool force_coldshot = false; void Shower::start() { - EMSESP::webSettingsService.read([&](WebSettings & settings) { + EMSESP::webSettingsService.read([&](WebSettings const & settings) { shower_timer_ = settings.shower_timer; shower_alert_ = settings.shower_alert; shower_alert_trigger_ = settings.shower_alert_trigger * 60; // convert from minutes to seconds @@ -61,7 +61,6 @@ void Shower::loop() { return; } - // uint32_t time_now = uuid::get_uptime(); // in ms auto time_now = uuid::get_uptime_sec(); // in sec // if already in cold mode, ignore all this logic until we're out of the cold blast diff --git a/src/system.cpp b/src/system.cpp index c98f41512..531c7ff22 100644 --- a/src/system.cpp +++ b/src/system.cpp @@ -118,13 +118,13 @@ bool System::command_fetch(const char * value, const int8_t id) { if (value_s == "all") { LOG_INFO("Requesting data from EMS devices"); EMSESP::fetch_device_values(); - } else if (value_s == (F_(boiler))) { + } else if (value_s == F_(boiler)) { EMSESP::fetch_device_values_type(EMSdevice::DeviceType::BOILER); - } else if (value_s == (F_(thermostat))) { + } else if (value_s == F_(thermostat)) { EMSESP::fetch_device_values_type(EMSdevice::DeviceType::THERMOSTAT); - } else if (value_s == (F_(solar))) { + } else if (value_s == F_(solar)) { EMSESP::fetch_device_values_type(EMSdevice::DeviceType::SOLAR); - } else if (value_s == (F_(mixer))) { + } else if (value_s == F_(mixer)) { EMSESP::fetch_device_values_type(EMSdevice::DeviceType::MIXER); } } else { @@ -339,9 +339,6 @@ void System::syslog_init() { syslog_.destination(syslog_host_.c_str(), syslog_port_); syslog_.hostname(hostname().c_str()); - // removed in 3.6.0 - // Command::add(EMSdevice::DeviceType::SYSTEM, F_(syslog), System::command_syslog_level, FL_(changeloglevel_cmd), CommandFlag::ADMIN_ONLY); - } else if (syslog_.started()) { // in case service is still running, this flushes the queue // https://github.com/emsesp/EMS-ESP/issues/496 @@ -1053,7 +1050,7 @@ void System::show_system(uuid::console::Shell & shell) { shell.printfln(" WiFi Network: Disconnected"); break; - case WL_NO_SHIELD: + // case WL_NO_SHIELD: default: shell.printfln(" WiFi MAC address: %s", WiFi.macAddress().c_str()); shell.printfln(" WiFi Network: not connected"); @@ -1087,7 +1084,7 @@ void System::show_system(uuid::console::Shell & shell) { } else { shell.printfln(" Syslog: %s", syslog_.started() ? "started" : "stopped"); shell.print(" "); - shell.printfln(F_(host_fmt), !syslog_host_.isEmpty() ? syslog_host_.c_str() : (F_(unset))); + shell.printfln(F_(host_fmt), !syslog_host_.isEmpty() ? syslog_host_.c_str() : F_(unset)); shell.printfln(" IP: %s", uuid::printable_to_string(syslog_.ip()).c_str()); shell.print(" "); shell.printfln(F_(port_fmt), syslog_port_); @@ -1167,7 +1164,7 @@ bool System::check_upgrade(bool factory_settings) { if (!factory_settings) { // fetch current version from settings file - EMSESP::webSettingsService.read([&](WebSettings & settings) { settingsVersion = settings.version.c_str(); }); + EMSESP::webSettingsService.read([&](WebSettings const & settings) { settingsVersion = settings.version.c_str(); }); // see if we're missing a version, will be < 3.5.0b13 from Dec 23 2022 missing_version = (settingsVersion.empty() || (settingsVersion.length() < 5)); @@ -1338,14 +1335,11 @@ bool System::get_value_info(JsonObject output, const char * cmd) { if (!strcmp(cmd, F_(entities))) { for (JsonPair p : root) { if (p.value().is()) { - // String prefix = p.key().c_str(); for (JsonPair p1 : p.value().as()) { JsonObject entity = output[std::string(p.key().c_str()) + "." + p1.key().c_str()].to(); get_value_json(entity, p.key().c_str(), p1.key().c_str(), p1.value()); } - } // else { // we don't have pairs in json root object - // get_value_json(entity, "", p.key().c_str(), p.value()); - // } + } } return true; } @@ -1498,7 +1492,7 @@ bool System::command_info(const char * value, const int8_t id, JsonObject output } }); #ifndef EMSESP_STANDALONE - EMSESP::esp8266React.getAPSettingsService()->read([&](APSettings & settings) { + EMSESP::esp8266React.getAPSettingsService()->read([&](const APSettings & settings) { const char * pM[] = {"always", "disconnected", "never"}; node["APProvisionMode"] = pM[settings.provisionMode]; node["APSecurity"] = settings.password.length() ? "wpa2" : "open"; @@ -1510,11 +1504,10 @@ bool System::command_info(const char * value, const int8_t id, JsonObject output node = output["ntp"].to(); #ifndef EMSESP_STANDALONE node["NTPStatus"] = EMSESP::system_.ntp_connected() ? "connected" : "disconnected"; - EMSESP::esp8266React.getNTPSettingsService()->read([&](NTPSettings & settings) { + EMSESP::esp8266React.getNTPSettingsService()->read([&](const NTPSettings & settings) { node["enabled"] = settings.enabled; node["server"] = settings.server; node["tzLabel"] = settings.tzLabel; - // node["tz format"] = settings.tzFormat; }); #endif @@ -1527,7 +1520,7 @@ bool System::command_info(const char * value, const int8_t id, JsonObject output node["MQTTPublishFails"] = Mqtt::publish_fails(); node["MQTTConnects"] = Mqtt::connect_count(); } - EMSESP::esp8266React.getMqttSettingsService()->read([&](MqttSettings & settings) { + EMSESP::esp8266React.getMqttSettingsService()->read([&](const MqttSettings & settings) { node["enabled"] = settings.enabled; node["clientID"] = settings.clientId; node["keepAlive"] = settings.keepAlive; @@ -1606,7 +1599,6 @@ bool System::command_info(const char * value, const int8_t id, JsonObject output node["busStatus"] = "unknown"; break; } - // if (EMSESP::bus_status() != EMSESP::BUS_STATUS_OFFLINE) { node["busProtocol"] = EMSbus::is_ht3() ? "HT3" : "Buderus"; node["busTelegramsReceived"] = EMSESP::rxservice_.telegram_count(); node["busReads"] = EMSESP::txservice_.telegram_read_count(); @@ -1616,11 +1608,10 @@ bool System::command_info(const char * value, const int8_t id, JsonObject output node["busWritesFailed"] = EMSESP::txservice_.telegram_write_fail_count(); node["busRxLineQuality"] = EMSESP::rxservice_.quality(); node["busTxLineQuality"] = (EMSESP::txservice_.read_quality() + EMSESP::txservice_.read_quality()) / 2; - // } // Settings node = output["settings"].to(); - EMSESP::webSettingsService.read([&](WebSettings & settings) { + EMSESP::webSettingsService.read([&](const WebSettings & settings) { node["boardProfile"] = settings.board_profile; node["locale"] = settings.locale; node["txMode"] = settings.tx_mode; @@ -1707,7 +1698,6 @@ bool System::command_info(const char * value, const int8_t id, JsonObject output obj["name"] = F_(temperaturesensor); obj["entities"] = EMSESP::temperaturesensor_.count_entities(); } - // if (EMSESP::analog_enabled()) { if (EMSESP::analogsensor_.count_entities()) { JsonObject obj = devices.add(); obj["type"] = F_(analogsensor); @@ -1870,7 +1860,7 @@ std::string System::reset_reason(uint8_t cpu) const { break; } #endif - return ("Unknown"); + return "Unknown"; } #pragma GCC diagnostic pop diff --git a/src/system.h b/src/system.h index 9aea1dd34..4251bd8b9 100644 --- a/src/system.h +++ b/src/system.h @@ -60,7 +60,6 @@ class System { static bool command_fetch(const char * value, const int8_t id); static bool command_restart(const char * value, const int8_t id); static bool command_format(const char * value, const int8_t id); - // static bool command_syslog_level(const char * value, const int8_t id); static bool command_watch(const char * value, const int8_t id); static bool command_message(const char * value, const int8_t id); static bool command_info(const char * value, const int8_t id, JsonObject output); diff --git a/src/temperaturesensor.cpp b/src/temperaturesensor.cpp index c647b82a4..5d1a65ee8 100644 --- a/src/temperaturesensor.cpp +++ b/src/temperaturesensor.cpp @@ -53,7 +53,7 @@ void TemperatureSensor::start() { // load settings void TemperatureSensor::reload() { // load the service settings - EMSESP::webSettingsService.read([&](WebSettings & settings) { + EMSESP::webSettingsService.read([&](WebSettings const & settings) { dallas_gpio_ = settings.dallas_gpio; parasite_ = settings.dallas_parasite; }); @@ -274,7 +274,7 @@ int16_t TemperatureSensor::get_temperature_c(const uint8_t addr[]) { case 11: raw_value &= ~0x1; break; - case 12: + default: // 12 break; } } @@ -302,7 +302,7 @@ bool TemperatureSensor::update(const std::string & id, const std::string & name, sensor.set_offset(offset); // store the new name and offset in our configuration - EMSESP::webCustomizationService.update([&](WebCustomization & settings) { + EMSESP::webCustomizationService.update([&id, &name, &offset, &sensor](WebCustomization & settings) { // look it up to see if it exists bool found = false; for (auto & SensorCustomization : settings.sensorCustomizations) { @@ -315,10 +315,10 @@ bool TemperatureSensor::update(const std::string & id, const std::string & name, } } if (!found) { - SensorCustomization newSensor = SensorCustomization(); - newSensor.id = id; - newSensor.name = name; - newSensor.offset = offset; + auto newSensor = SensorCustomization(); + newSensor.id = id; + newSensor.name = name; + newSensor.offset = offset; settings.sensorCustomizations.push_back(newSensor); LOG_DEBUG("Adding new customization for sensor ID %s", id.c_str()); } @@ -401,9 +401,9 @@ void TemperatureSensor::publish_sensor(const Sensor & sensor) { if (Mqtt::enabled() && Mqtt::publish_single()) { char topic[Mqtt::MQTT_TOPIC_MAX_SIZE]; if (Mqtt::publish_single2cmd()) { - snprintf(topic, sizeof(topic), "%s/%s", (F_(temperaturesensor)), sensor.name().c_str()); + snprintf(topic, sizeof(topic), "%s/%s", F_(temperaturesensor), sensor.name().c_str()); } else { - snprintf(topic, sizeof(topic), "%s%s/%s", (F_(temperaturesensor)), "_data", sensor.name().c_str()); + snprintf(topic, sizeof(topic), "%s%s/%s", F_(temperaturesensor), "_data", sensor.name().c_str()); } char payload[10]; Mqtt::queue_publish(topic, Helpers::render_value(payload, sensor.temperature_c, 10, EMSESP::system_.fahrenheit() ? 2 : 0)); @@ -513,7 +513,7 @@ void TemperatureSensor::publish_values(const bool force) { // see if we need to create the [devs] discovery section, as this needs only to be done once for all sensors bool is_ha_device_created = false; - for (auto & sensor : sensors_) { + for (const auto & sensor : sensors_) { if (sensor.ha_registered) { is_ha_device_created = true; break; @@ -570,8 +570,8 @@ std::string TemperatureSensor::Sensor::name() const { // look up in customization service for a specific sensor // and set the name and offset from that entry if it exists bool TemperatureSensor::Sensor::apply_customization() { - EMSESP::webCustomizationService.read([&](WebCustomization & settings) { - auto sensors = settings.sensorCustomizations; + EMSESP::webCustomizationService.read([&](const WebCustomization & settings) { + auto const & sensors = settings.sensorCustomizations; if (!sensors.empty()) { for (const auto & sensor : sensors) { if (id_ == sensor.id) { diff --git a/src/temperaturesensor.h b/src/temperaturesensor.h index 1d9e4d364..d63017884 100644 --- a/src/temperaturesensor.h +++ b/src/temperaturesensor.h @@ -90,23 +90,23 @@ class TemperatureSensor { return sensors_; } - uint32_t reads() { + uint32_t reads() const { return sensorreads_; } - uint32_t fails() { + uint32_t fails() const { return sensorfails_; } - bool sensor_enabled() { + bool sensor_enabled() const { return (dallas_gpio_ != 0); } - bool have_sensors() { + bool have_sensors() const { return (!sensors_.empty()); } - size_t count_entities() { + size_t count_entities() const { return sensors_.size(); } diff --git a/src/web/WebAPIService.cpp b/src/web/WebAPIService.cpp index 4175d3b75..063ca114f 100644 --- a/src/web/WebAPIService.cpp +++ b/src/web/WebAPIService.cpp @@ -58,7 +58,7 @@ void WebAPIService::webAPIService(AsyncWebServerRequest * request) { void WebAPIService::parse(AsyncWebServerRequest * request, JsonObject input) { // check if the user has admin privileges (token is included and authorized) bool is_admin = false; - EMSESP::webSettingsService.read([&](WebSettings & settings) { + EMSESP::webSettingsService.read([&](WebSettings const & settings) { Authentication authentication = _securityManager->authenticateRequest(request); is_admin = settings.notoken_api || AuthenticationPredicates::IS_ADMIN(authentication); }); @@ -94,7 +94,7 @@ void WebAPIService::parse(AsyncWebServerRequest * request, JsonObject input) { emsesp::EMSESP::system_.refreshHeapMem(); // output json buffer - AsyncJsonResponse * response = new AsyncJsonResponse(false); + auto response = new AsyncJsonResponse(false); // add more mem if needed - won't be needed in ArduinoJson 7 // while (!response->getSize()) { diff --git a/src/web/WebCustomEntityService.cpp b/src/web/WebCustomEntityService.cpp index a26285dc8..bb71fc6cf 100644 --- a/src/web/WebCustomEntityService.cpp +++ b/src/web/WebCustomEntityService.cpp @@ -47,7 +47,7 @@ void WebCustomEntityService::begin() { void WebCustomEntity::read(WebCustomEntity & webEntity, JsonObject root) { JsonArray entity = root["entities"].to(); uint8_t counter = 0; - for (const CustomEntityItem & entityItem : webEntity.customEntityItems) { + for (CustomEntityItem & entityItem : webEntity.customEntityItems) { JsonObject ei = entity.add(); ei["id"] = counter++; // id is only used to render the table and must be unique ei["ram"] = entityItem.ram; @@ -213,7 +213,7 @@ bool WebCustomEntityService::command_setvalue(const char * value, const int8_t i // output of a single value // 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) { +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) { @@ -262,7 +262,7 @@ void WebCustomEntityService::render_value(JsonObject output, CustomEntityItem en output[name] = add_uom ? serialized(v + ' ' + EMSdevice::uom_to_string(entity.uom)) : serialized(v); } break; - case DeviceValueType::STRING: + // case DeviceValueType::STRING: default: // if no type treat it as a string if (entity.data.length() > 0) { @@ -275,7 +275,7 @@ void WebCustomEntityService::render_value(JsonObject output, CustomEntityItem en // 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_) { + for (CustomEntityItem & entity : *customEntityItems_) { render_value(output, entity, false, false, true); // with add_uom } } @@ -285,14 +285,14 @@ bool WebCustomEntityService::get_value_info(JsonObject output, const char * cmd) // if no custom entries, return empty json // even if we're looking for a specific entity // https://github.com/emsesp/EMS-ESP32/issues/1297 - if (customEntityItems_->size() == 0) { + if (customEntityItems_->empty()) { return true; } // if it's info or values... if (!strlen(cmd) || !strcmp(cmd, F_(values)) || !strcmp(cmd, F_(info))) { // list all names - for (const CustomEntityItem & entity : *customEntityItems_) { + for (CustomEntityItem & entity : *customEntityItems_) { render_value(output, entity); } return true; @@ -300,7 +300,7 @@ bool WebCustomEntityService::get_value_info(JsonObject output, const char * cmd) // list all entities if (!strcmp(cmd, F_(entities))) { - for (const auto & entity : *customEntityItems_) { + for (auto & entity : *customEntityItems_) { auto nest = output[entity.name].to(); get_value_json(nest, entity); } @@ -309,7 +309,7 @@ bool WebCustomEntityService::get_value_info(JsonObject output, const char * cmd) // specific value info const char * attribute_s = Command::get_attribute(cmd); - for (const auto & entity : *customEntityItems_) { + for (auto & entity : *customEntityItems_) { if (Helpers::toLower(entity.name) == cmd) { get_value_json(output, entity); return Command::set_attribute(output, cmd, attribute_s); @@ -319,7 +319,7 @@ bool WebCustomEntityService::get_value_info(JsonObject output, const char * cmd) } // build the json for specific entity -void WebCustomEntityService::get_value_json(JsonObject output, const CustomEntityItem & entity) { +void WebCustomEntityService::get_value_json(JsonObject output, CustomEntityItem & entity) { output["name"] = entity.name; output["fullname"] = entity.name; output["storage"] = entity.ram ? "ram" : "ems"; @@ -344,7 +344,7 @@ void WebCustomEntityService::get_value_json(JsonObject output, const CustomEntit } // publish single value -void WebCustomEntityService::publish_single(const CustomEntityItem & entity) { +void WebCustomEntityService::publish_single(CustomEntityItem & entity) { if (!Mqtt::enabled() || !Mqtt::publish_single()) { return; } @@ -372,11 +372,11 @@ void WebCustomEntityService::publish(const bool force) { return; } - if (customEntityItems_->size() == 0) { + if (customEntityItems_->empty()) { return; } if (Mqtt::publish_single() && force) { - for (const CustomEntityItem & entityItem : *customEntityItems_) { + for (CustomEntityItem & entityItem : *customEntityItems_) { publish_single(entityItem); } } @@ -385,7 +385,7 @@ void WebCustomEntityService::publish(const bool force) { JsonObject output = doc.to(); bool ha_created = ha_registered_; - for (const CustomEntityItem & entityItem : *customEntityItems_) { + for (CustomEntityItem & entityItem : *customEntityItems_) { render_value(output, entityItem); // create HA config if (Mqtt::ha_enabled() && !ha_registered_) { @@ -454,14 +454,15 @@ void WebCustomEntityService::publish(const bool force) { // count only entities with valid value or command to show in dashboard uint8_t WebCustomEntityService::count_entities() { - if (customEntityItems_->size() == 0) { + if (customEntityItems_->empty()) { return 0; } JsonDocument doc; JsonObject output = doc.to(); uint8_t count = 0; - for (const CustomEntityItem & entity : *customEntityItems_) { + + for (CustomEntityItem & entity : *customEntityItems_) { render_value(output, entity); if (output[entity.name].is() || entity.writeable) { count++; @@ -557,7 +558,7 @@ void WebCustomEntityService::generate_value_web(JsonObject output) { void WebCustomEntityService::fetch() { const uint8_t len[] = {1, 1, 1, 2, 2, 3, 3, 4}; - for (auto & entity : *customEntityItems_) { + for (auto const & entity : *customEntityItems_) { if (entity.device_id > 0 && entity.type_id > 0) { // this excludes also RAM type bool needFetch = true; uint8_t fetchblock = entity.type_id > 0x0FF ? 25 : 27; @@ -579,7 +580,6 @@ void WebCustomEntityService::fetch() { } } } - // EMSESP::logger().debug("fetch custom entities"); } // called on process telegram, read from telegram diff --git a/src/web/WebCustomEntityService.h b/src/web/WebCustomEntityService.h index 15db79c7e..cacefd3b8 100644 --- a/src/web/WebCustomEntityService.h +++ b/src/web/WebCustomEntityService.h @@ -55,14 +55,14 @@ class WebCustomEntityService : public StatefulService { WebCustomEntityService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager); void begin(); - void publish_single(const CustomEntityItem & entity); + void publish_single(CustomEntityItem & entity); void publish(const bool force = false); bool command_setvalue(const char * value, const int8_t id, const char * name); bool get_value_info(JsonObject output, const char * cmd); - void get_value_json(JsonObject output, const CustomEntityItem & entity); + void get_value_json(JsonObject output, CustomEntityItem & entity); 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 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); diff --git a/src/web/WebSchedulerService.cpp b/src/web/WebSchedulerService.cpp index 148f36f3a..b1b0229c4 100644 --- a/src/web/WebSchedulerService.cpp +++ b/src/web/WebSchedulerService.cpp @@ -134,7 +134,7 @@ bool WebSchedulerService::command_setvalue(const char * value, const int8_t id, // process json output for info/commands and value_info bool WebSchedulerService::get_value_info(JsonObject output, const char * cmd) { - if (scheduleItems_->size() == 0) { + if (scheduleItems_->empty()) { return true; } @@ -233,7 +233,7 @@ void WebSchedulerService::publish(const bool force) { return; } - if (scheduleItems_->size() == 0) { + if (scheduleItems_->empty()) { return; } @@ -449,7 +449,7 @@ void WebSchedulerService::loop() { static uint32_t last_uptime_sec = 0; // get list of scheduler events and exit if it's empty - if (scheduleItems_->size() == 0) { + if (scheduleItems_->empty()) { return; } diff --git a/src/modbus_test.h b/test/test_modbus/modbus_test.h similarity index 100% rename from src/modbus_test.h rename to test/test_modbus/modbus_test.h From 52cd8fa3e8e728fb034961d2bf0562938a1ebcaf Mon Sep 17 00:00:00 2001 From: proddy Date: Wed, 2 Oct 2024 09:30:53 +0200 Subject: [PATCH 19/22] smaller box --- interface/src/app/status/RestartMonitor.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/app/status/RestartMonitor.tsx b/interface/src/app/status/RestartMonitor.tsx index 855d597c9..d95487d59 100644 --- a/interface/src/app/status/RestartMonitor.tsx +++ b/interface/src/app/status/RestartMonitor.tsx @@ -45,7 +45,7 @@ const RestartMonitor = () => { return ( - + { ) : ( - + )} From 91d6249ada54ddfcb2a13acbf091127d9e0243dc Mon Sep 17 00:00:00 2001 From: proddy Date: Wed, 2 Oct 2024 10:04:13 +0200 Subject: [PATCH 20/22] add comments --- src/system.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/system.h b/src/system.h index 4251bd8b9..60b619195 100644 --- a/src/system.h +++ b/src/system.h @@ -162,10 +162,12 @@ class System { readonly_mode_ = readonly_mode; } + // Boolean Format API/MQTT uint8_t bool_format() { return bool_format_; } + // Boolean Format Web uint8_t bool_dashboard() { return bool_dashboard_; } From 4dee94563236b310db9191fcfc5f0516cf94e369 Mon Sep 17 00:00:00 2001 From: proddy Date: Wed, 2 Oct 2024 10:04:38 +0200 Subject: [PATCH 21/22] fix HA warning, dont translate bool --- src/mqtt.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/mqtt.cpp b/src/mqtt.cpp index 0fe1e6319..d0b42dcc9 100644 --- a/src/mqtt.cpp +++ b/src/mqtt.cpp @@ -1115,11 +1115,12 @@ bool Mqtt::publish_ha_sensor_config(uint8_t type, // EMSdev // special case to handle booleans // applies to both Binary Sensor (read only) and a Switch (for a command) - // has no unit of measure or icon + // has no unit of measure or icon, and must be true/false (not on/off or 1/0) if (type == DeviceValueType::BOOL) { add_ha_bool(doc); - Helpers::render_boolean(sample_val, false); + strlcpy(sample_val, "false", sizeof(sample_val)); // default is "false" } + doc["val_tpl"] = (std::string) "{{" + val_obj + " if " + val_cond + " else " + sample_val + "}}"; // add the dev json object to the end, not for commands From 8ccc708532f6c4b5f8bf126659c0e30bc9b831b8 Mon Sep 17 00:00:00 2001 From: proddy Date: Wed, 2 Oct 2024 10:30:03 +0200 Subject: [PATCH 22/22] highlight upload box when dragging --- interface/src/components/upload/DragNdrop.tsx | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/interface/src/components/upload/DragNdrop.tsx b/interface/src/components/upload/DragNdrop.tsx index d9d06c585..44902417d 100644 --- a/interface/src/components/upload/DragNdrop.tsx +++ b/interface/src/components/upload/DragNdrop.tsx @@ -12,6 +12,7 @@ import './dragNdrop.css'; const DragNdrop = ({ onFileSelected }) => { const [file, setFile] = useState(); + const [dragged, setDragged] = useState(false); const inputRef = useRef(null); const { LL } = useI18nContext(); @@ -45,6 +46,7 @@ const DragNdrop = ({ onFileSelected }) => { const handleRemoveFile = (event) => { event.stopPropagation(); setFile(undefined); + setDragged(false); }; const handleUploadClick = (event) => { @@ -56,11 +58,17 @@ const DragNdrop = ({ onFileSelected }) => { inputRef.current?.click(); }; + const handleDragOver = (event) => { + event.preventDefault(); // prevent file from being opened + setDragged(true); + }; + return (
event.preventDefault()} + onDragOver={handleDragOver} + onDragLeave={() => setDragged(false)} onClick={handleBrowseClick} >