diff --git a/CHANGELOG_LATEST.md b/CHANGELOG_LATEST.md index d131ad6c6..37bccce83 100644 --- a/CHANGELOG_LATEST.md +++ b/CHANGELOG_LATEST.md @@ -48,6 +48,7 @@ For more details go to [www.emsesp.org](https://www.emsesp.org/). - internal ESP32 temperature sensor on the S3 [#2077](https://github.com/emsesp/EMS-ESP32/issues/2077) - MQTT status topic (used in connect and last will) set to Retain [#2086](https://github.com/emsesp/EMS-ESP32/discussions/2086) - Czech language [2096](https://github.com/emsesp/EMS-ESP32/issues/2096) +- Developer Mode and send EMS Read Commands from WebUI [#2116](https://github.com/emsesp/EMS-ESP32/issues/2116) ## Fixed diff --git a/interface/eslint.config.js b/interface/eslint.config.js index c53ece12c..4ccfc79ac 100644 --- a/interface/eslint.config.js +++ b/interface/eslint.config.js @@ -31,6 +31,8 @@ export default tseslint.config( '@typescript-eslint/no-unsafe-enum-comparison': 'off', '@typescript-eslint/no-unused-expressions': 'off', '@typescript-eslint/no-unsafe-assignment': 'off', + '@typescript-eslint/no-unsafe-member-access': 'off', + '@typescript-eslint/no-unsafe-call': 'off', '@typescript-eslint/no-misused-promises': [ 'error', { diff --git a/interface/package.json b/interface/package.json index 8fb2e1a10..4385914e9 100644 --- a/interface/package.json +++ b/interface/package.json @@ -24,8 +24,8 @@ "@alova/adapter-xhr": "2.0.8", "@emotion/react": "^11.13.3", "@emotion/styled": "^11.13.0", - "@mui/icons-material": "^6.1.4", - "@mui/material": "^6.1.4", + "@mui/icons-material": "^6.1.5", + "@mui/material": "^6.1.5", "@table-library/react-table-library": "4.1.7", "alova": "3.1.0", "async-validator": "^4.2.5", @@ -47,7 +47,7 @@ "@preact/preset-vite": "^2.9.1", "@trivago/prettier-plugin-sort-imports": "^4.3.0", "@types/formidable": "^3", - "@types/node": "^22.7.7", + "@types/node": "^22.7.8", "@types/react": "^18.3.11", "@types/react-dom": "^18.3.1", "@types/react-router-dom": "^5.3.3", @@ -58,7 +58,7 @@ "prettier": "^3.3.3", "rollup-plugin-visualizer": "^5.12.0", "terser": "^5.36.0", - "typescript-eslint": "8.10.0", + "typescript-eslint": "8.11.0", "vite": "^5.4.9", "vite-plugin-imagemin": "^0.6.1", "vite-tsconfig-paths": "^5.0.1" diff --git a/interface/src/AuthenticatedRouting.tsx b/interface/src/AuthenticatedRouting.tsx index adf39beb1..2171d81d8 100644 --- a/interface/src/AuthenticatedRouting.tsx +++ b/interface/src/AuthenticatedRouting.tsx @@ -15,6 +15,7 @@ import DownloadUpload from 'app/settings/DownloadUpload'; import MqttSettings from 'app/settings/MqttSettings'; import NTPSettings from 'app/settings/NTPSettings'; import Settings from 'app/settings/Settings'; +import Version from 'app/settings/Version'; import Network from 'app/settings/network/Network'; import Security from 'app/settings/security/Security'; import APStatus from 'app/status/APStatus'; @@ -51,6 +52,7 @@ const AuthenticatedRouting = () => { {me.admin && ( <> } /> + } /> } /> } /> } /> diff --git a/interface/src/app/main/Dashboard.tsx b/interface/src/app/main/Dashboard.tsx index 389311787..eb89f925b 100644 --- a/interface/src/app/main/Dashboard.tsx +++ b/interface/src/app/main/Dashboard.tsx @@ -102,6 +102,9 @@ const Dashboard = () => { Row: ` cursor: pointer; background-color: #1e1e1e; + &:nth-of-type(odd) .td { + background-color: #303030; + }, &:hover .td { background-color: #177ac9; } @@ -234,7 +237,7 @@ const Dashboard = () => { - {LL.DASHBOARD_1()} + {LL.DASHBOARD_1()}. @@ -274,7 +277,7 @@ const Dashboard = () => { }} > {!loading && data.length === 0 ? ( - + {LL.NO_DATA()} ) : ( diff --git a/interface/src/app/main/Devices.tsx b/interface/src/app/main/Devices.tsx index ddd30fe39..22ebb45f9 100644 --- a/interface/src/app/main/Devices.tsx +++ b/interface/src/app/main/Devices.tsx @@ -166,11 +166,6 @@ const Devices = () => { Table: ` --data-table-library_grid-template-columns: repeat(1, minmax(0, 1fr)) 130px; `, - BaseRow: ` - // .td { - // height: 42px; - // } - `, HeaderRow: ` .th { padding: 8px; @@ -268,7 +263,7 @@ const Devices = () => { ), VALUE: (array) => - // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-member-access + // eslint-disable-next-line @typescript-eslint/no-unsafe-return array.sort((a, b) => a.v.toString().localeCompare(b.v.toString())) } } @@ -362,7 +357,9 @@ const Devices = () => { }, { accessor: (dv: DeviceValue) => - DeviceValueUOM_s[dv.u].replace(/[^a-zA-Z0-9]/g, ''), + dv.u !== undefined && DeviceValueUOM_s[dv.u] + ? DeviceValueUOM_s[dv.u].replace(/[^a-zA-Z0-9]/g, '') + : '', name: 'UoM' }, { diff --git a/interface/src/app/main/Help.tsx b/interface/src/app/main/Help.tsx index 9c36096aa..6c8f6f26b 100644 --- a/interface/src/app/main/Help.tsx +++ b/interface/src/app/main/Help.tsx @@ -51,19 +51,19 @@ const Help = () => { } }); - 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: 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 @@ -103,7 +103,7 @@ const Help = () => { sx={{ maxHeight: { xs: 100, md: 250 } }} - onError={(e) => setNotFound(true)} + onError={() => setNotFound(true)} src={ notFound ? '' @@ -162,11 +162,11 @@ const Help = () => { color="primary" onClick={() => sendAPI({ device: 'system', cmd: 'info', id: 0 })} > - {LL.DOWNLOAD(1)} {LL.SUPPORT_INFORMATION(0)} + {LL.SUPPORT_INFORMATION(0)} - + */} diff --git a/interface/src/app/main/Sensors.tsx b/interface/src/app/main/Sensors.tsx index eebc08384..876499770 100644 --- a/interface/src/app/main/Sensors.tsx +++ b/interface/src/app/main/Sensors.tsx @@ -219,7 +219,7 @@ const Sensors = () => { sortToggleType: SortToggleType.AlternateWithReset, sortFns: { GPIO: (array) => array.sort((a, b) => a.g - b.g), - // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access + // eslint-disable-next-line @typescript-eslint/no-unsafe-return NAME: (array) => array.sort((a, b) => a.n.localeCompare(b.n)), TYPE: (array) => array.sort((a, b) => a.t - b.t), VALUE: (array) => array.sort((a, b) => a.v - b.v) @@ -238,7 +238,7 @@ const Sensors = () => { }, sortToggleType: SortToggleType.AlternateWithReset, sortFns: { - // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access + // eslint-disable-next-line @typescript-eslint/no-unsafe-return NAME: (array) => array.sort((a, b) => a.n.localeCompare(b.n)), VALUE: (array) => array.sort((a, b) => a.t - b.t) } diff --git a/interface/src/app/main/types.ts b/interface/src/app/main/types.ts index 38398bccb..d037d338e 100644 --- a/interface/src/app/main/types.ts +++ b/interface/src/app/main/types.ts @@ -42,6 +42,7 @@ export interface Settings { modbus_port: number; modbus_max_clients: number; modbus_timeout: number; + developer_mode: boolean; } export enum busConnectionStatus { @@ -273,6 +274,7 @@ export interface APIcall { device: string; cmd: string; id: number; + data?: string; // optional } export interface Action { diff --git a/interface/src/app/settings/ApplicationSettings.tsx b/interface/src/app/settings/ApplicationSettings.tsx index 946f295fd..6af5901b4 100644 --- a/interface/src/app/settings/ApplicationSettings.tsx +++ b/interface/src/app/settings/ApplicationSettings.tsx @@ -686,6 +686,16 @@ const ApplicationSettings = () => { {LL.SPECIAL_FUNCTIONS()} + + } + label={LL.DEVELOPER_MODE()} + /> { } label={LL.HEATINGOFF()} /> - { const { LL } = useI18nContext(); const [restarting, setRestarting] = useState(false); - const [openDialog, setOpenDialog] = useState(false); - const [useDev, setUseDev] = useState(false); - const [upgradeAvailable, setUpgradeAvailable] = useState(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 }), @@ -71,13 +45,6 @@ const DownloadUpload = () => { const { data, send: loadData, error } = useRequest(SystemApi.readSystemStatus); - const { send: sendUploadURL } = useRequest( - (url: string) => callAction({ action: 'uploadURL', param: url }), - { - immediate: false - } - ); - const doRestart = async () => { setRestarting(true); await sendAPI({ device: 'system', cmd: 'restart', id: 0 }).catch( @@ -87,134 +54,13 @@ const DownloadUpload = () => { ); }; - // 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 - // immediate: false, - // initialData: '3.6.5' - }); - - // called immediately to get the latest version, on page load, then check for upgrade - const { data: latestDevVersion } = useRequest(getDevVersion, { - // uncomment next 2 lines for testing, uses https://github.com/emsesp/EMS-ESP32/releases/download/latest/EMS-ESP-3_7_0-dev_31-ESP32-16MB+.bin - // immediate: false, - // initialData: '3.7.0-dev.32' - }).onSuccess((event) => { - void sendCheckUpgrade(event.data); - }); - - const STABLE_URL = 'https://github.com/emsesp/EMS-ESP32/releases/download/'; - const STABLE_RELNOTES_URL = - 'https://github.com/emsesp/EMS-ESP32/blob/main/CHANGELOG.md'; - - const DEV_URL = 'https://github.com/emsesp/EMS-ESP32/releases/download/latest/'; - const DEV_RELNOTES_URL = - 'https://github.com/emsesp/EMS-ESP32/blob/dev/CHANGELOG_LATEST.md'; - - const getBinURL = (useDevVersion: boolean) => { - if (!latestVersion || !latestDevVersion) { - return ''; - } - const filename = - 'EMS-ESP-' + - (useDevVersion ? latestDevVersion : latestVersion).replaceAll('.', '_') + - '-' + - getPlatform() + - '.bin'; - return useDevVersion - ? DEV_URL + filename - : STABLE_URL + 'v' + latestVersion + '/' + filename; - }; - - const getPlatform = () => { - return ( - [data.esp_platform, data.flash_chip_size >= 16384 ? '16MB' : '4MB'].join('-') + - (data.psram ? '+' : '') - ); - }; - - const installFirmwareURL = async (url: string) => { - await sendUploadURL(url).catch((error: Error) => { - toast.error(error.message); - }); - setRestarting(true); - }; - useLayoutTitle(LL.DOWNLOAD_UPLOAD()); - const internet_live = - latestDevVersion !== undefined && latestVersion !== undefined; - - const renderUploadDialog = () => { - if (!internet_live) { - return null; - } - - return ( - setOpenDialog(false)} - > - - {LL.INSTALL('') + - ' ' + - (useDev ? LL.DEVELOPMENT() : LL.STABLE()) + - ' Firmware'} - - - - {LL.INSTALL_VERSION(useDev ? latestDevVersion : latestVersion)} - - - {LL.RELEASE_NOTES()} - -  |  - - {LL.DOWNLOAD(1)} - - - - - - - - ); - }; - - // useDevVersion = true to force using the dev version - const showFirmwareDialog = (useDevVersion: boolean) => { - if (useDevVersion || data.emsesp_version.includes('dev')) { - setUseDev(true); - } - setOpenDialog(true); - }; - const content = () => { if (!data) { return ; } - const isDev = data.emsesp_version.includes('dev'); - return ( <> @@ -232,7 +78,7 @@ const DownloadUpload = () => { color="primary" onClick={() => sendExportData('settings')} > - {LL.DOWNLOAD(1)} {LL.SETTINGS_OF(LL.APPLICATION())} + {LL.SETTINGS_OF(LL.APPLICATION())} @@ -273,68 +119,6 @@ const DownloadUpload = () => { - - - {LL.EMS_ESP_VER()} - - - - - {LL.VERSION() + ':'} {data.emsesp_version} - {data.build_flags && ( - -   ({data.build_flags}) - - )} - - - Platform: {getPlatform()} - - - Release: {isDev ? LL.DEVELOPMENT() : LL.STABLE()} - {!isDev && ( - - )} - - - -    - {upgradeAvailable ? LL.UPGRADE_AVAILABLE() : LL.LATEST_VERSION()} - {upgradeAvailable && - internet_live && - (data.psram ? ( - - ) : ( - <> -    - - {LL.DOWNLOAD(1)} v - {isDev ? latestDevVersion : latestVersion} - - - ))} - - - {renderUploadDialog()} - ); }; diff --git a/interface/src/app/settings/Settings.tsx b/interface/src/app/settings/Settings.tsx index 78afb8214..e40c55ed7 100644 --- a/interface/src/app/settings/Settings.tsx +++ b/interface/src/app/settings/Settings.tsx @@ -1,6 +1,7 @@ import { useState } from 'react'; import AccessTimeIcon from '@mui/icons-material/AccessTime'; +import BuildIcon from '@mui/icons-material/Build'; import CancelIcon from '@mui/icons-material/Cancel'; import DeviceHubIcon from '@mui/icons-material/DeviceHub'; import ImportExportIcon from '@mui/icons-material/ImportExport'; @@ -20,7 +21,7 @@ import { List } from '@mui/material'; -import { API } from 'api/app'; +import { API, callAction } from 'api/app'; import { dialogStyle } from 'CustomTheme'; import { useRequest } from 'alova/client'; @@ -39,6 +40,11 @@ const Settings = () => { immediate: false }); + // get installed version + const { data } = useRequest(() => callAction({ action: 'checkUpgrade' }), { + initialData: { emsesp_version: '...' } + }); + const doFormat = async () => { await sendAPI({ device: 'system', cmd: 'format', id: 0 }).then(() => { setConfirmFactoryReset(false); @@ -77,10 +83,18 @@ const Settings = () => { const content = () => ( <> + + @@ -88,7 +102,7 @@ const Settings = () => { @@ -96,7 +110,7 @@ const Settings = () => { @@ -104,7 +118,7 @@ const Settings = () => { @@ -112,14 +126,14 @@ const Settings = () => { diff --git a/interface/src/app/settings/Version.tsx b/interface/src/app/settings/Version.tsx new file mode 100644 index 000000000..ba4ee53eb --- /dev/null +++ b/interface/src/app/settings/Version.tsx @@ -0,0 +1,261 @@ +import { useState } from 'react'; +import { toast } from 'react-toastify'; + +import CancelIcon from '@mui/icons-material/Cancel'; +import InfoOutlinedIcon from '@mui/icons-material/InfoOutlined'; +import WarningIcon from '@mui/icons-material/Warning'; +import { + Box, + Button, + Dialog, + DialogActions, + DialogContent, + DialogTitle, + Link, + Typography +} from '@mui/material'; + +import * as SystemApi from 'api/system'; +import { callAction } from 'api/app'; +import { getDevVersion, getStableVersion } from 'api/system'; + +import { dialogStyle } from 'CustomTheme'; +import { useRequest } from 'alova/client'; +import RestartMonitor from 'app/status/RestartMonitor'; +import { FormLoader, SectionContent, useLayoutTitle } from 'components'; +import { useI18nContext } from 'i18n/i18n-react'; + +const Version = () => { + const { LL } = useI18nContext(); + + const [restarting, setRestarting] = useState(false); + const [openDialog, setOpenDialog] = useState(false); + const [useDev, setUseDev] = useState(false); + const [upgradeAvailable, setUpgradeAvailable] = useState(false); + + const { send: sendCheckUpgrade } = useRequest( + (version: string) => callAction({ action: 'checkUpgrade', param: version }), + { + immediate: false + } + ).onSuccess((event) => { + setUpgradeAvailable((event.data as { upgradeable: boolean }).upgradeable); + }); + + const { data, send: loadData, error } = useRequest(SystemApi.readSystemStatus); + + const { send: sendUploadURL } = useRequest( + (url: string) => callAction({ action: 'uploadURL', param: url }), + { + immediate: false + } + ); + + // 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 + immediate: false, + initialData: '3.6.5' + }); + + // called immediately to get the latest version, on page load, then check for upgrade + const { data: latestDevVersion } = useRequest(getDevVersion, { + // uncomment next 2 lines for testing, uses https://github.com/emsesp/EMS-ESP32/releases/download/latest/EMS-ESP-3_7_0-dev_31-ESP32-16MB+.bin + immediate: false, + initialData: '3.7.0-dev.32' + }).onSuccess((event) => { + void sendCheckUpgrade(event.data); + }); + + const STABLE_URL = 'https://github.com/emsesp/EMS-ESP32/releases/download/'; + const STABLE_RELNOTES_URL = + 'https://github.com/emsesp/EMS-ESP32/blob/main/CHANGELOG.md'; + + const DEV_URL = 'https://github.com/emsesp/EMS-ESP32/releases/download/latest/'; + const DEV_RELNOTES_URL = + 'https://github.com/emsesp/EMS-ESP32/blob/dev/CHANGELOG_LATEST.md'; + + const getBinURL = (useDevVersion: boolean) => { + if (!latestVersion || !latestDevVersion) { + return ''; + } + const filename = + 'EMS-ESP-' + + (useDevVersion ? latestDevVersion : latestVersion).replaceAll('.', '_') + + '-' + + getPlatform() + + '.bin'; + return useDevVersion + ? DEV_URL + filename + : STABLE_URL + 'v' + latestVersion + '/' + filename; + }; + + const getPlatform = () => { + return ( + [data.esp_platform, data.flash_chip_size >= 16384 ? '16MB' : '4MB'].join('-') + + (data.psram ? '+' : '') + ); + }; + + const installFirmwareURL = async (url: string) => { + await sendUploadURL(url).catch((error: Error) => { + toast.error(error.message); + }); + setRestarting(true); + }; + + useLayoutTitle(LL.EMS_ESP_VER()); + + const internet_live = + latestDevVersion !== undefined && latestVersion !== undefined; + + const renderUploadDialog = () => { + if (!internet_live) { + return null; + } + + return ( + setOpenDialog(false)} + > + + {LL.INSTALL('') + + ' ' + + (useDev ? LL.DEVELOPMENT() : LL.STABLE()) + + ' Firmware'} + + + + {LL.INSTALL_VERSION(useDev ? latestDevVersion : latestVersion)} + + + changelog + +  |  + + {LL.DOWNLOAD(1)} + + + + + + + + ); + }; + + // useDevVersion = true to force using the dev version + const showFirmwareDialog = (useDevVersion: boolean) => { + if (useDevVersion || data.emsesp_version.includes('dev')) { + setUseDev(true); + } + setOpenDialog(true); + }; + + const content = () => { + if (!data) { + return ; + } + + const isDev = data.emsesp_version.includes('dev'); + + return ( + <> + + Firmware Version Check + + + + + {LL.VERSION() + ':'} {data.emsesp_version} + {data.build_flags && ( + +   ({data.build_flags}) + + )} + + + Platform: {getPlatform()} + + + + Release:  + + {isDev ? LL.DEVELOPMENT() : LL.STABLE()} + + {!isDev && ( + + )} + + + + +    + {upgradeAvailable ? LL.UPGRADE_AVAILABLE() : LL.LATEST_VERSION()} + {upgradeAvailable && + internet_live && + (data.psram ? ( + + ) : ( + <> +    + + {LL.DOWNLOAD(1)} v + {isDev ? latestDevVersion : latestVersion} + + + ))} + + + {renderUploadDialog()} + + + ); + }; + + return ( + {restarting ? : content()} + ); +}; + +export default Version; diff --git a/interface/src/app/status/Status.tsx b/interface/src/app/status/Status.tsx index f3a53dbdd..7d0785af9 100644 --- a/interface/src/app/status/Status.tsx +++ b/interface/src/app/status/Status.tsx @@ -1,9 +1,7 @@ import { useContext, useState } from 'react'; -import { useNavigate } from 'react-router-dom'; import { toast } from 'react-toastify'; import AccessTimeIcon from '@mui/icons-material/AccessTime'; -import BuildIcon from '@mui/icons-material/Build'; import CancelIcon from '@mui/icons-material/Cancel'; import DeviceHubIcon from '@mui/icons-material/DeviceHub'; import DirectionsBusIcon from '@mui/icons-material/DirectionsBus'; @@ -13,7 +11,6 @@ import PowerSettingsNewIcon from '@mui/icons-material/PowerSettingsNew'; import RouterIcon from '@mui/icons-material/Router'; import SettingsInputAntennaIcon from '@mui/icons-material/SettingsInputAntenna'; import TimerIcon from '@mui/icons-material/Timer'; -import UpgradeIcon from '@mui/icons-material/Upgrade'; import WifiIcon from '@mui/icons-material/Wifi'; import { Avatar, @@ -46,8 +43,6 @@ import RestartMonitor from './RestartMonitor'; const SystemStatus = () => { const { LL } = useI18nContext(); - const navigate = useNavigate(); - useLayoutTitle(LL.STATUS_OF('')); const { me } = useContext(AuthenticatedContext); @@ -248,28 +243,6 @@ const SystemStatus = () => { return ( <> - - - - - - - - {me.admin && ( - - )} - - @@ -292,6 +265,15 @@ const SystemStatus = () => { )} + + { to="/status/activity" /> - - { : RouterIcon } bgcolor={networkStatusHighlight()} - label={LL.STATUS_OF(LL.NETWORK(1))} + label={LL.NETWORK(1)} text={networkStatus()} to="/status/network" /> @@ -327,7 +300,7 @@ const SystemStatus = () => { disabled={!me.admin} icon={DeviceHubIcon} bgcolor={activeHighlight(data.mqtt_status)} - label={LL.STATUS_OF('MQTT')} + label="MQTT" text={data.mqtt_status ? LL.ACTIVE() : LL.INACTIVE(0)} to="/status/mqtt" /> @@ -336,7 +309,7 @@ const SystemStatus = () => { disabled={!me.admin} icon={AccessTimeIcon} bgcolor={ntpStatusHighlight()} - label={LL.STATUS_OF('NTP')} + label="NTP" text={ntpStatus()} to="/status/ntp" /> @@ -345,7 +318,7 @@ const SystemStatus = () => { disabled={!me.admin} icon={SettingsInputAntennaIcon} bgcolor={activeHighlight(data.ap_status)} - label={LL.STATUS_OF(LL.ACCESS_POINT(0))} + label={LL.ACCESS_POINT(0)} text={data.ap_status ? LL.ACTIVE() : LL.INACTIVE(0)} to="/status/ap" /> diff --git a/interface/src/app/status/SystemLog.tsx b/interface/src/app/status/SystemLog.tsx index 8028cb98e..b644b48f5 100644 --- a/interface/src/app/status/SystemLog.tsx +++ b/interface/src/app/status/SystemLog.tsx @@ -2,13 +2,23 @@ import { useEffect, useRef, useState } from 'react'; import { toast } from 'react-toastify'; import DownloadIcon from '@mui/icons-material/GetApp'; +import PlayArrowIcon from '@mui/icons-material/PlayArrow'; import WarningIcon from '@mui/icons-material/Warning'; -import { Box, Button, Checkbox, MenuItem, TextField, styled } from '@mui/material'; +import { + Box, + Button, + Checkbox, + IconButton, + MenuItem, + TextField, + styled +} from '@mui/material'; import Grid from '@mui/material/Grid2'; +import { API } from 'api/app'; import { fetchLogES, readLogSettings, updateLogSettings } from 'api/system'; -import { useSSE } from 'alova/client'; +import { useRequest, useSSE } from 'alova/client'; import { BlockFormControlLabel, BlockNavigation, @@ -80,9 +90,20 @@ const SystemLog = () => { update: updateLogSettings }); + const { send } = useRequest( + (data: string) => API({ device: 'system', cmd: 'read', id: 0, data: data }), + { + immediate: false + } + ); + + const [readValue, setReadValue] = useState(''); + const [readOpen, setReadOpen] = useState(false); const [logEntries, setLogEntries] = useState([]); const [autoscroll, setAutoscroll] = useState(true); + const ALPHA_NUMERIC_DASH_REGEX = /^[a-fA-F0-9 ]+$/; + const updateFormValue = updateValueDirty( origData, dirtyFlags, @@ -150,6 +171,19 @@ const SystemLog = () => { } }, [logEntries.length]); + const sendReadCommand = () => { + if (readValue === '') { + setReadOpen(!readOpen); + return; + } + + if (readValue.split(' ').filter((word) => word !== '').length > 1) { + void send(readValue); + setReadOpen(false); + setReadValue(''); + } + }; + const content = () => { if (!data) { return ; @@ -163,7 +197,7 @@ const SystemLog = () => { name="level" label={LL.LOG_LEVEL()} value={data.level} - sx={{ width: '15ch' }} + sx={{ width: '10ch' }} variant="outlined" onChange={updateFormValue} margin="normal" @@ -218,25 +252,71 @@ const SystemLog = () => { label={LL.AUTO_SCROLL()} /> - - {dirtyFlags && dirtyFlags.length !== 0 && ( + + {dirtyFlags && dirtyFlags.length !== 0 && ( + + )} + + + {readOpen ? ( + { + e.preventDefault(); + sendReadCommand(); + }} + > + { + setReadOpen(false); + setReadValue(''); + }} + > + + + { + const value = e.target.value; + if (value !== '' && !ALPHA_NUMERIC_DASH_REGEX.test(value)) { + return; + } + setReadValue(value); + }} + focused={true} + size="small" + label="Send Read command" // doesn't need translating - developer only + helperText=" [offset] [len]" + /> + + ) : ( + <> + {data.developer_mode && ( + + + + )} + )} + { event.preventDefault(); const droppedFiles = event.dataTransfer.files; if (droppedFiles.length > 0) { - checkFileExtension(droppedFiles[0]); + checkFileExtension(droppedFiles[0] as File); } }; diff --git a/interface/src/i18n/cz/index.ts b/interface/src/i18n/cz/index.ts index 9484275f9..56f30b84f 100644 --- a/interface/src/i18n/cz/index.ts +++ b/interface/src/i18n/cz/index.ts @@ -177,7 +177,6 @@ const cz: Translation = { SYSTEM_FACTORY_TEXT_DIALOG: 'Opravdu chcete resetovat EMS-ESP do továrního nastavení?', STABLE: 'Stabilní', DEVELOPMENT: 'Vývojová verze', - RELEASE_NOTES: 'poznámky k vydání', EMS_ESP_VER: 'Verze firmwaru', UPTIME: 'Doba provozu systému', FREE_MEMORY: 'Volná paměť', @@ -344,6 +343,7 @@ const cz: Translation = { DASHBOARD: 'Dashboard', NO_DATA: 'Žádná data nejsou k dispozici', DASHBOARD_1: 'Přizpůsobte si dashboard označením EMS entit jako Oblíbené pomocí modulu Přizpůsobení.', + DEVELOPER_MODE: 'Developer Mode' // TODO translate }; export default cz; diff --git a/interface/src/i18n/de/index.ts b/interface/src/i18n/de/index.ts index 663481a89..c1879447d 100644 --- a/interface/src/i18n/de/index.ts +++ b/interface/src/i18n/de/index.ts @@ -177,7 +177,6 @@ const de: Translation = { SYSTEM_FACTORY_TEXT_DIALOG: 'Sind Sie sicher, alle Einstellungen auf Werkseinstellung zu setzen?', STABLE: 'Stabil', DEVELOPMENT: 'Entwicklung', - RELEASE_NOTES: 'Versionshinweise', EMS_ESP_VER: 'Firmware-Version', UPTIME: 'Systembetriebszeit', FREE_MEMORY: 'Freier RAM Speicher', @@ -343,7 +342,8 @@ const de: Translation = { AUTO_SCROLL: 'Automatisches Scrollen', DASHBOARD: 'Dashboard', NO_DATA: 'Keine Daten verfügbar', - DASHBOARD_1: 'Passen Sie Ihr Dashboard an, indem Sie EMS-Entitäten mithilfe des Moduls „Anpassungen“ als Favorit markieren.' + DASHBOARD_1: 'Passen Sie Ihr Dashboard an, indem Sie EMS-Entitäten mithilfe des Moduls „Anpassungen“ als Favorit markieren.', + DEVELOPER_MODE: 'Entwicklermodus' }; export default de; diff --git a/interface/src/i18n/en/index.ts b/interface/src/i18n/en/index.ts index 394d983ef..5fab58f4a 100644 --- a/interface/src/i18n/en/index.ts +++ b/interface/src/i18n/en/index.ts @@ -115,7 +115,7 @@ const en: Translation = { READONLY: 'Enable read-only mode (blocks all outgoing EMS Tx Write commands)', UNDERCLOCK_CPU: 'Underclock CPU speed', REMOTE_TIMEOUT: 'Remote timeout', - REMOTE_TIMEOUT_EN: 'Disable remote on missing roomtemperature', + REMOTE_TIMEOUT_EN: 'Disable remote on missing room temperature', HEATINGOFF: 'Start boiler with forced heating off', MIN_DURATION: 'Wait time', ENABLE_SHOWER_TIMER: 'Enable Shower Timer', @@ -177,7 +177,6 @@ const en: Translation = { SYSTEM_FACTORY_TEXT_DIALOG: 'Are you sure you want to reset EMS-ESP to its factory defaults?', STABLE: 'Stable', DEVELOPMENT: 'Development', - RELEASE_NOTES: 'release notes', EMS_ESP_VER: 'Firmware Version', UPTIME: 'System Uptime', FREE_MEMORY: 'Free Memory', @@ -344,6 +343,7 @@ const en: Translation = { DASHBOARD: 'Dashboard', NO_DATA: 'No data available', DASHBOARD_1: 'Customize your dashboard by marking EMS entities as Favorite using the Customizations module.', + DEVELOPER_MODE: 'Developer Mode' }; export default en; diff --git a/interface/src/i18n/fr/index.ts b/interface/src/i18n/fr/index.ts index 7e9348eec..180ecdafe 100644 --- a/interface/src/i18n/fr/index.ts +++ b/interface/src/i18n/fr/index.ts @@ -116,7 +116,7 @@ const fr: Translation = { UNDERCLOCK_CPU: 'Underclock du CPU', HEATINGOFF: 'Start boiler with forced heating off', // TODO translate REMOTE_TIMEOUT: 'Remote timeout', - REMOTE_TIMEOUT_EN: 'Disable remote on missing roomtemperature', + REMOTE_TIMEOUT_EN: 'Disable remote on missing room temperature', // TODO translate MIN_DURATION: 'Wait time', ENABLE_SHOWER_TIMER: 'Activer la minuterie de la douche', ENABLE_SHOWER_ALERT: 'Activer les alertes de durée de douche', @@ -177,7 +177,6 @@ const fr: Translation = { SYSTEM_FACTORY_TEXT_DIALOG: "Êtes-vous sûr de vouloir réinitialiser l'appareil à ses paramètres d'usine ?", STABLE: 'Stable', // TODO translate DEVELOPMENT: 'Développement', - RELEASE_NOTES: 'notes de version', EMS_ESP_VER: 'Firmware Version', // TODO translate UPTIME: 'Durée de fonctionnement du système', FREE_MEMORY: 'Libre Memory', @@ -343,7 +342,8 @@ const fr: Translation = { AUTO_SCROLL: 'Auto Scroll', // TODO translate DASHBOARD: 'Dashboard', // TODO translate NO_DATA: 'No data available', // TODO translate - DASHBOARD_1: 'Customize your dashboard by marking EMS entities as Favorite using the Customizations module.' // TODO translate + DASHBOARD_1: 'Customize your dashboard by marking EMS entities as Favorite using the Customizations module.', // TODO translate + DEVELOPER_MODE: 'Developer Mode' // TODO translate }; export default fr; diff --git a/interface/src/i18n/it/index.ts b/interface/src/i18n/it/index.ts index 9dc2ae4e4..b6b6820ea 100644 --- a/interface/src/i18n/it/index.ts +++ b/interface/src/i18n/it/index.ts @@ -115,7 +115,7 @@ const it: Translation = { READONLY: 'Abilita modalità sola-lettura (blocca tutti i comandi di scrittura EMS Tx in uscita)', UNDERCLOCK_CPU: 'Abbassa velocità della CPU', REMOTE_TIMEOUT: 'Remote timeout', - REMOTE_TIMEOUT_EN: 'Disable remote on missing roomtemperature', + REMOTE_TIMEOUT_EN: 'Disable remote on missing room temperature', // TODO translate HEATINGOFF: 'Avviamento caldaia con riscaldamento forzato spento', MIN_DURATION: 'Wait time', ENABLE_SHOWER_TIMER: 'Abilita timer doccia', @@ -177,7 +177,6 @@ const it: Translation = { SYSTEM_FACTORY_TEXT_DIALOG: 'Sei sicuro di voler ripristinare il dispositivo alle impostazioni di fabbrica??', STABLE: 'Stable', // TODO translate DEVELOPMENT: 'Sviluppo', - RELEASE_NOTES: 'note rilascio', EMS_ESP_VER: 'Versione Firmware', UPTIME: 'Tempo di attività del sistema', FREE_MEMORY: 'Free Memory', @@ -343,7 +342,8 @@ const it: Translation = { AUTO_SCROLL: 'Auto Scroll', // TODO translate DASHBOARD: 'Dashboard', // TODO translate NO_DATA: 'No data available', // TODO translate - DASHBOARD_1: 'Customize your dashboard by marking EMS entities as Favorite using the Customizations module.' // TODO translate + DASHBOARD_1: 'Customize your dashboard by marking EMS entities as Favorite using the Customizations module.', // TODO translate + DEVELOPER_MODE: 'Developer Mode' // TODO translate }; export default it; diff --git a/interface/src/i18n/nl/index.ts b/interface/src/i18n/nl/index.ts index c238a8afb..22a690fbc 100644 --- a/interface/src/i18n/nl/index.ts +++ b/interface/src/i18n/nl/index.ts @@ -115,7 +115,7 @@ const nl: Translation = { READONLY: 'Activeer read-only modus (blokkeert alle outgaande EMS Tx schrijf commandos)', UNDERCLOCK_CPU: 'Underclock CPU snelheid', REMOTE_TIMEOUT: 'Remote timeout', - REMOTE_TIMEOUT_EN: 'Disable remote on missing roomtemperature', + REMOTE_TIMEOUT_EN: 'Disable remote on missing room temperature', // TODO translate HEATINGOFF: 'Start ketel met geforceerde verwarming uit', MIN_DURATION: 'Wait time', ENABLE_SHOWER_TIMER: 'Activeer Douche Timer (tijdmeting)', @@ -177,7 +177,6 @@ const nl: Translation = { SYSTEM_FACTORY_TEXT_DIALOG: 'Weet je zeker dat je een reset naar fabrieksinstellingen uit wilt voeren?', STABLE: 'Stable', DEVELOPMENT: 'Development', - RELEASE_NOTES: 'release notes', EMS_ESP_VER: 'Firmware Versie', UPTIME: 'Systeem Uptime', FREE_MEMORY: 'Free Memory', @@ -343,7 +342,8 @@ const nl: Translation = { AUTO_SCROLL: 'Auto Scroll', // TODO translate DASHBOARD: 'Dashboard', // TODO translate NO_DATA: 'No data available', // TODO translate - DASHBOARD_1: 'Customize your dashboard by marking EMS entities as Favorite using the Customizations module.' // TODO translate + DASHBOARD_1: 'Customize your dashboard by marking EMS entities as Favorite using the Customizations module.', // TODO translate + DEVELOPER_MODE: 'Developer Mode' // TODO translate }; export default nl; diff --git a/interface/src/i18n/no/index.ts b/interface/src/i18n/no/index.ts index 4909f7351..6d9f73239 100644 --- a/interface/src/i18n/no/index.ts +++ b/interface/src/i18n/no/index.ts @@ -115,7 +115,7 @@ const no: Translation = { READONLY: 'Aktiver read-only modus (blokker all EMS Tx Skriving)', UNDERCLOCK_CPU: 'Underklokking av prosessorhastighet', REMOTE_TIMEOUT: 'Remote timeout', - REMOTE_TIMEOUT_EN: 'Disable remote control on missing roomtemperature', + REMOTE_TIMEOUT_EN: 'Disable remote control on missing room temperature', // TODO translate HEATINGOFF: 'Start boiler with forced heating off', // TODO translate MIN_DURATION: 'Wait time', ENABLE_SHOWER_TIMER: 'Aktiver Dusjtimer', @@ -177,7 +177,6 @@ const no: Translation = { SYSTEM_FACTORY_TEXT_DIALOG: 'Er du sikker på at du vil resette enheten til fabrikkinstillinger?', STABLE: 'Stable', // TODO translate DEVELOPMENT: 'Development', - RELEASE_NOTES: 'release notes', EMS_ESP_VER: 'Firmware Version', // TODO translate UPTIME: 'System Oppetid', FREE_MEMORY: 'Ledig Memory', @@ -343,7 +342,8 @@ const no: Translation = { AUTO_SCROLL: 'Auto Scroll', // TODO translate DASHBOARD: 'Dashboard', // TODO translate NO_DATA: 'No data available', // TODO translate - DASHBOARD_1: 'Customize your dashboard by marking EMS entities as Favorite using the Customizations module.' // TODO translate + DASHBOARD_1: 'Customize your dashboard by marking EMS entities as Favorite using the Customizations module.', // TODO translate + DEVELOPER_MODE: 'Developer Mode' // TODO translate }; export default no; diff --git a/interface/src/i18n/pl/index.ts b/interface/src/i18n/pl/index.ts index 23d91b964..927ae11e9 100644 --- a/interface/src/i18n/pl/index.ts +++ b/interface/src/i18n/pl/index.ts @@ -115,7 +115,7 @@ const pl: BaseTranslation = { READONLY: 'Tryb pracy "tylko do odczytu" (blokuje wszystkie komendy zapisu na magistralę EMS)', UNDERCLOCK_CPU: 'Obniż taktowanie CPU', REMOTE_TIMEOUT: 'Remote timeout', - REMOTE_TIMEOUT_EN: 'Disable remote control on missing roomtemperature', + REMOTE_TIMEOUT_EN: 'Disable remote control on missing room temperature', // TODO translate HEATINGOFF: 'Uruchom kocioł z wymuszonym wyłączonym grzaniem', MIN_DURATION: 'Wait time', ENABLE_SHOWER_TIMER: 'Aktywuj minutnik prysznica', @@ -177,7 +177,6 @@ const pl: BaseTranslation = { SYSTEM_FACTORY_TEXT_DIALOG: 'Na pewno chcesz przywrócić ustawienia fabryczne interfejsu EMS-ESP? ', STABLE: 'Stable', // TODO translate DEVELOPMENT: 'Testowe', - RELEASE_NOTES: 'lista zmian', EMS_ESP_VER: 'Wersja Firmware', UPTIME: 'Czas działania systemu', FREE_MEMORY: 'Wolne Memory', // TODO translate @@ -343,7 +342,8 @@ const pl: BaseTranslation = { AUTO_SCROLL: 'Auto Scroll', // TODO translate DASHBOARD: 'Dashboard', // TODO translate NO_DATA: 'No data available', // TODO translate - DASHBOARD_1: 'Customize your dashboard by marking EMS entities as Favorite using the Customizations module.' // TODO translate + DASHBOARD_1: 'Customize your dashboard by marking EMS entities as Favorite using the Customizations module.', // TODO translate + DEVELOPER_MODE: 'Developer Mode' // TODO translate }; export default pl; diff --git a/interface/src/i18n/sk/index.ts b/interface/src/i18n/sk/index.ts index f27363d89..95023429a 100644 --- a/interface/src/i18n/sk/index.ts +++ b/interface/src/i18n/sk/index.ts @@ -115,7 +115,7 @@ const sk: Translation = { READONLY: 'Povoliť režim len na čítanie (blokuje všetky odchádzajúce príkazy EMS Tx Write)', UNDERCLOCK_CPU: 'Podtaktovanie rýchlosti procesora', REMOTE_TIMEOUT: 'Remote timeout', - REMOTE_TIMEOUT_EN: 'Disable remote on missing roomtemperature', + REMOTE_TIMEOUT_EN: 'Disable remote on missing room temperature', // TODO translate HEATINGOFF: 'Spustiť kotol s vynúteným vykurovaním', MIN_DURATION: 'Wait time', ENABLE_SHOWER_TIMER: 'Povoliť časovač sprchovania', @@ -177,7 +177,6 @@ const sk: Translation = { SYSTEM_FACTORY_TEXT_DIALOG: 'Naozaj chcete resetovať EMS-ESP na predvolené výrobné nastavenia?', STABLE: 'Stabilná', DEVELOPMENT: 'Vývojárska', - RELEASE_NOTES: 'poznámky k verzii', EMS_ESP_VER: 'Firmware verzia', UPTIME: 'Beh systému', FREE_MEMORY: 'Voľné Memory', @@ -343,7 +342,8 @@ const sk: Translation = { AUTO_SCROLL: 'Automatické rolovanie', DASHBOARD: 'Panel', NO_DATA: 'Nie sú k dispozícii žiadne údaje', - DASHBOARD_1: 'Prispôsobte si svoj informačný panel tak, že označíte entity EMS ako Obľúbené pomocou modulu Prispôsobenia.' + DASHBOARD_1: 'Prispôsobte si svoj informačný panel tak, že označíte entity EMS ako Obľúbené pomocou modulu Prispôsobenia.', + DEVELOPER_MODE: 'Developer Mode' // TODO translate }; export default sk; diff --git a/interface/src/i18n/sv/index.ts b/interface/src/i18n/sv/index.ts index 193166751..f9e296ee1 100644 --- a/interface/src/i18n/sv/index.ts +++ b/interface/src/i18n/sv/index.ts @@ -115,7 +115,7 @@ const sv: Translation = { READONLY: 'Aktivera read-only (blockerar alla utgående skrivkommandon mot EMS-bussen)', UNDERCLOCK_CPU: 'Nedklocka Processorhastighet', REMOTE_TIMEOUT: 'Remote timeout', - REMOTE_TIMEOUT_EN: 'Disable remote on missing roomtemperature', + REMOTE_TIMEOUT_EN: 'Disable remote on missing room temperature', // TODO translate HEATINGOFF: 'Start boiler with forced heating off', // TODO translate MIN_DURATION: 'Wait time', ENABLE_SHOWER_TIMER: 'Aktivera Dusch-timer', @@ -177,7 +177,6 @@ const sv: Translation = { SYSTEM_FACTORY_TEXT_DIALOG: 'Är du säker att du vill fabriksåterställa enheten?', STABLE: 'Stable', // TODO translate DEVELOPMENT: 'Utveckling', - RELEASE_NOTES: 'release-logg', EMS_ESP_VER: 'Firmware Version', // TODO translate UPTIME: 'Systemets Upptid', FREE_MEMORY: 'Ledigt Memory', @@ -343,7 +342,8 @@ const sv: Translation = { AUTO_SCROLL: 'Auto Scroll', // TODO translate DASHBOARD: 'Dashboard', // TODO translate NO_DATA: 'No data available', // TODO translate - DASHBOARD_1: 'Customize your dashboard by marking EMS entities as Favorite using the Customizations module.' // TODO translate + DASHBOARD_1: 'Customize your dashboard by marking EMS entities as Favorite using the Customizations module.', // TODO translate + DEVELOPER_MODE: 'Developer Mode' // TODO translate }; export default sv; diff --git a/interface/src/i18n/tr/index.ts b/interface/src/i18n/tr/index.ts index d471de55d..1e5f4fbf9 100644 --- a/interface/src/i18n/tr/index.ts +++ b/interface/src/i18n/tr/index.ts @@ -115,7 +115,7 @@ const tr: Translation = { READONLY: 'Salt okunur modu devreye al (bütün giden EMS Tx Yazma komutlarını engeller)', UNDERCLOCK_CPU: 'İşlemci hızını düşür', REMOTE_TIMEOUT: 'Remote timeout', - REMOTE_TIMEOUT_EN: 'Disable remote on missing roomtemperature', + REMOTE_TIMEOUT_EN: 'Disable remote on missing room temperature', // TODO translate HEATINGOFF: 'Start boiler with forced heating off', // TODO translate MIN_DURATION: 'Wait time', ENABLE_SHOWER_TIMER: 'Duş Sayacını Devreye Al', @@ -177,7 +177,6 @@ const tr: Translation = { SYSTEM_FACTORY_TEXT_DIALOG: 'Cihazı fabrika ayarlarına döndürmek istediğinize emin misiniz?', STABLE: 'Stable', // TODO translate DEVELOPMENT: 'Geliştirme', - RELEASE_NOTES: 'yayınlanma notları', EMS_ESP_VER: 'Firmware Sürümü', UPTIME: 'Sistem Çalışma Süresi', FREE_MEMORY: 'Yığın Memory', @@ -343,7 +342,8 @@ const tr: Translation = { AUTO_SCROLL: 'Auto Scroll', // TODO translate DASHBOARD: 'Dashboard', // TODO translate NO_DATA: 'No data available', // TODO translate - DASHBOARD_1: 'Customize your dashboard by marking EMS entities as Favorite using the Customizations module.' // TODO translate + DASHBOARD_1: 'Customize your dashboard by marking EMS entities as Favorite using the Customizations module.', // TODO translate + DEVELOPER_MODE: 'Developer Mode' // TODO translate }; export default tr; diff --git a/interface/src/types/system.ts b/interface/src/types/system.ts index b71586af3..94a9c18df 100644 --- a/interface/src/types/system.ts +++ b/interface/src/types/system.ts @@ -67,4 +67,5 @@ export interface LogSettings { max_messages: number; compact: boolean; psram: boolean; + developer_mode: boolean; } diff --git a/interface/yarn.lock b/interface/yarn.lock index d93dc53e0..235df7f5b 100644 --- a/interface/yarn.lock +++ b/interface/yarn.lock @@ -1076,38 +1076,38 @@ __metadata: languageName: node linkType: hard -"@mui/core-downloads-tracker@npm:^6.1.4": - version: 6.1.4 - resolution: "@mui/core-downloads-tracker@npm:6.1.4" - checksum: 10c0/bfd84a726c883dd681b2cda13b977eb6646c1da66ea59905dbe7b857ec4ac86576a318eb116d54633e7c479aecb52fe0c75fb957f1b6081a6c8857dd5ce4c5b9 +"@mui/core-downloads-tracker@npm:^6.1.5": + version: 6.1.5 + resolution: "@mui/core-downloads-tracker@npm:6.1.5" + checksum: 10c0/c8767b7a8046e669ea687108dd2c62352e48c61379657a1b88798c12ec47cc3f99eedf30758294a17a81f2dcef22aeb08f992aecdf6e0876f312d345ba1d5f3d languageName: node linkType: hard -"@mui/icons-material@npm:^6.1.4": - version: 6.1.4 - resolution: "@mui/icons-material@npm:6.1.4" +"@mui/icons-material@npm:^6.1.5": + version: 6.1.5 + resolution: "@mui/icons-material@npm:6.1.5" dependencies: "@babel/runtime": "npm:^7.25.7" peerDependencies: - "@mui/material": ^6.1.4 + "@mui/material": ^6.1.5 "@types/react": ^17.0.0 || ^18.0.0 || ^19.0.0 react: ^17.0.0 || ^18.0.0 || ^19.0.0 peerDependenciesMeta: "@types/react": optional: true - checksum: 10c0/8e4e8a20c7183fae76f1e013669212404696e9e146aa413afbc705ee56f0a32cfef6143a16f9ec24aeb1e8dfb567d50f9b04b9bdf381ad8bd7a2c9b09d25186c + checksum: 10c0/112f7570b8d27019a16b619a3a5b9f01cb7d8a244d50014596e17f06ed5f569888aeac2223c058da37567b5a358c99a53ee2afdf8958bc4a34b964a02f796787 languageName: node linkType: hard -"@mui/material@npm:^6.1.4": - version: 6.1.4 - resolution: "@mui/material@npm:6.1.4" +"@mui/material@npm:^6.1.5": + version: 6.1.5 + resolution: "@mui/material@npm:6.1.5" dependencies: "@babel/runtime": "npm:^7.25.7" - "@mui/core-downloads-tracker": "npm:^6.1.4" - "@mui/system": "npm:^6.1.4" + "@mui/core-downloads-tracker": "npm:^6.1.5" + "@mui/system": "npm:^6.1.5" "@mui/types": "npm:^7.2.18" - "@mui/utils": "npm:^6.1.4" + "@mui/utils": "npm:^6.1.5" "@popperjs/core": "npm:^2.11.8" "@types/react-transition-group": "npm:^4.4.11" clsx: "npm:^2.1.1" @@ -1118,7 +1118,7 @@ __metadata: peerDependencies: "@emotion/react": ^11.5.0 "@emotion/styled": ^11.3.0 - "@mui/material-pigment-css": ^6.1.4 + "@mui/material-pigment-css": ^6.1.5 "@types/react": ^17.0.0 || ^18.0.0 || ^19.0.0 react: ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^17.0.0 || ^18.0.0 || ^19.0.0 @@ -1131,16 +1131,16 @@ __metadata: optional: true "@types/react": optional: true - checksum: 10c0/3729e56129b27706ebfab67428035dc7f0136dfd745281b467c7da07e78248cc8e2f36939cd6c33967fd565c5b5eff336629e3f7a2d877e9b176d24df67c9c81 + checksum: 10c0/982a2446fd511a952627aa8567e302528ad3a2ad8b3125574a38facaef2a5a076a723c67076682f95b09f9fe4dbf3445213fe6655658d23419b49440ae11873e languageName: node linkType: hard -"@mui/private-theming@npm:^6.1.4": - version: 6.1.4 - resolution: "@mui/private-theming@npm:6.1.4" +"@mui/private-theming@npm:^6.1.5": + version: 6.1.5 + resolution: "@mui/private-theming@npm:6.1.5" dependencies: "@babel/runtime": "npm:^7.25.7" - "@mui/utils": "npm:^6.1.4" + "@mui/utils": "npm:^6.1.5" prop-types: "npm:^15.8.1" peerDependencies: "@types/react": ^17.0.0 || ^18.0.0 || ^19.0.0 @@ -1148,13 +1148,13 @@ __metadata: peerDependenciesMeta: "@types/react": optional: true - checksum: 10c0/37c81ca4529afbec2a4710d4dfa1597a5f9a33ff3ae775fa68474f86b223ed4ab953526e49883d77638ad62f0c944716c2b0dc58a105624ca91fe60a633e3b4a + checksum: 10c0/3a5a470c78daa60fa3c9346a15617ab4d6ad3c544b564fe4b2fe6f3155cb4955b0c670395a9074e91956b1cb50bca96fc07d03cad92759147bebadcacd00f36c languageName: node linkType: hard -"@mui/styled-engine@npm:^6.1.4": - version: 6.1.4 - resolution: "@mui/styled-engine@npm:6.1.4" +"@mui/styled-engine@npm:^6.1.5": + version: 6.1.5 + resolution: "@mui/styled-engine@npm:6.1.5" dependencies: "@babel/runtime": "npm:^7.25.7" "@emotion/cache": "npm:^11.13.1" @@ -1171,19 +1171,19 @@ __metadata: optional: true "@emotion/styled": optional: true - checksum: 10c0/ce8f53a704aa607152ef5ef25d95bdd5c4399f7dbf240acd6e4057c24d84536bb3c884fcb13c5e88d87dbfff42935c82af2e63800ba033ad481847b1967ccf52 + checksum: 10c0/7a4830a7f1736d399c06d414cd6762ff4a830e976946da4a58b77e864b6d6abb4385800e644367e57c670397bf1f12690e82ffe05f185c85c8dafd132a67ca2a languageName: node linkType: hard -"@mui/system@npm:^6.1.4": - version: 6.1.4 - resolution: "@mui/system@npm:6.1.4" +"@mui/system@npm:^6.1.5": + version: 6.1.5 + resolution: "@mui/system@npm:6.1.5" dependencies: "@babel/runtime": "npm:^7.25.7" - "@mui/private-theming": "npm:^6.1.4" - "@mui/styled-engine": "npm:^6.1.4" + "@mui/private-theming": "npm:^6.1.5" + "@mui/styled-engine": "npm:^6.1.5" "@mui/types": "npm:^7.2.18" - "@mui/utils": "npm:^6.1.4" + "@mui/utils": "npm:^6.1.5" clsx: "npm:^2.1.1" csstype: "npm:^3.1.3" prop-types: "npm:^15.8.1" @@ -1199,7 +1199,7 @@ __metadata: optional: true "@types/react": optional: true - checksum: 10c0/766f1c695254df54b06de1af231cdf30752f71a79181edd4c24044405144b7a72c4c23248155f4041999993aa4f568878eccd130c100b4b332e7dd6b322dfd75 + checksum: 10c0/7e8ce81b7e6a5810c0856427dbd7f89f62a23ab151e0199813e7cd7e9d47e4719004f6b576c5cad0121735cfb0c984ea022c494796202e2c0c054c6a60995c40 languageName: node linkType: hard @@ -1215,9 +1215,9 @@ __metadata: languageName: node linkType: hard -"@mui/utils@npm:^6.1.4": - version: 6.1.4 - resolution: "@mui/utils@npm:6.1.4" +"@mui/utils@npm:^6.1.5": + version: 6.1.5 + resolution: "@mui/utils@npm:6.1.5" dependencies: "@babel/runtime": "npm:^7.25.7" "@mui/types": "npm:^7.2.18" @@ -1231,7 +1231,7 @@ __metadata: peerDependenciesMeta: "@types/react": optional: true - checksum: 10c0/cac4f05904897c28444e7ef2a6891678d36c0a8fae921ccacebcd7b53da99e4c6cab05669328fdabff624313de68f1b5bcd427cba36024b6c3505b5ee945eb05 + checksum: 10c0/899191334f321aedf993e6a79cd63ac511e8ef23a84c1e156ca4a82c407e97f86f9f3d4250765f5c9e71d9af963bdc738e6d63fc62f9088fc5ad9c055fc3b111 languageName: node linkType: hard @@ -1685,12 +1685,12 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:^22.7.7": - version: 22.7.7 - resolution: "@types/node@npm:22.7.7" +"@types/node@npm:^22.7.8": + version: 22.7.8 + resolution: "@types/node@npm:22.7.8" dependencies: undici-types: "npm:~6.19.2" - checksum: 10c0/07268a1e990ad9d9b1865092881317ea679a46eb6706d83a8874eec75fdddae6cfd6452e4e68b651561183e2a8f8548276f3155744bc402c2545978c19b70d65 + checksum: 10c0/3d3b3a2ec5a57ca4fd37b34dce415620993ca5f87cea2c728ffe73aa31446dbfe19c53171c478447bd7d78011ef4845a46ab2f0dc38e699cc75b3d100a60c690 languageName: node linkType: hard @@ -1785,15 +1785,15 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/eslint-plugin@npm:8.10.0": - version: 8.10.0 - resolution: "@typescript-eslint/eslint-plugin@npm:8.10.0" +"@typescript-eslint/eslint-plugin@npm:8.11.0": + version: 8.11.0 + resolution: "@typescript-eslint/eslint-plugin@npm:8.11.0" dependencies: "@eslint-community/regexpp": "npm:^4.10.0" - "@typescript-eslint/scope-manager": "npm:8.10.0" - "@typescript-eslint/type-utils": "npm:8.10.0" - "@typescript-eslint/utils": "npm:8.10.0" - "@typescript-eslint/visitor-keys": "npm:8.10.0" + "@typescript-eslint/scope-manager": "npm:8.11.0" + "@typescript-eslint/type-utils": "npm:8.11.0" + "@typescript-eslint/utils": "npm:8.11.0" + "@typescript-eslint/visitor-keys": "npm:8.11.0" graphemer: "npm:^1.4.0" ignore: "npm:^5.3.1" natural-compare: "npm:^1.4.0" @@ -1804,66 +1804,66 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 10c0/4b77ba9c865a2a14e238cd330b5901f0274b8ce1c13324fccd0339b8eea82a50a4709394c903fd8cd5bd0d3aebace0761ff9a4a19fa20b00bb61349b7671c035 + checksum: 10c0/be509f7bb0c0c596801059b06995a81a1c326cc6ac31d96a32f7b6b7d7b495f9bad4dc442aa6e923d22515e62c668d3c14695c68bd6e0be1d4bf72158b7fd2d6 languageName: node linkType: hard -"@typescript-eslint/parser@npm:8.10.0": - version: 8.10.0 - resolution: "@typescript-eslint/parser@npm:8.10.0" +"@typescript-eslint/parser@npm:8.11.0": + version: 8.11.0 + resolution: "@typescript-eslint/parser@npm:8.11.0" dependencies: - "@typescript-eslint/scope-manager": "npm:8.10.0" - "@typescript-eslint/types": "npm:8.10.0" - "@typescript-eslint/typescript-estree": "npm:8.10.0" - "@typescript-eslint/visitor-keys": "npm:8.10.0" + "@typescript-eslint/scope-manager": "npm:8.11.0" + "@typescript-eslint/types": "npm:8.11.0" + "@typescript-eslint/typescript-estree": "npm:8.11.0" + "@typescript-eslint/visitor-keys": "npm:8.11.0" debug: "npm:^4.3.4" peerDependencies: eslint: ^8.57.0 || ^9.0.0 peerDependenciesMeta: typescript: optional: true - checksum: 10c0/7becb2457c085c239838d301796074b790f46dd38c9fbc14ec1dec8e993c7115cd8a66cdc07983c3a68a2dd92e24e8acc49d69a4ebcc29e9869957eb52d1cb74 + checksum: 10c0/e83f239fec60697083e5dcb1c8948340e783ea6e043fe9a65d557faef8882963b09d69aacd736eb8ab18a768769a7bbfc3de0f1251d4bba080613541acb0741c languageName: node linkType: hard -"@typescript-eslint/scope-manager@npm:8.10.0": - version: 8.10.0 - resolution: "@typescript-eslint/scope-manager@npm:8.10.0" +"@typescript-eslint/scope-manager@npm:8.11.0": + version: 8.11.0 + resolution: "@typescript-eslint/scope-manager@npm:8.11.0" dependencies: - "@typescript-eslint/types": "npm:8.10.0" - "@typescript-eslint/visitor-keys": "npm:8.10.0" - checksum: 10c0/b8bb8635c4d6c00a3578d6265e3ee0f5d96d0c9dee534ed588aa411c3f4497fd71cce730c3ae7571e52453d955b191bc9edcc47c9af21a20c90e9a20f2371108 + "@typescript-eslint/types": "npm:8.11.0" + "@typescript-eslint/visitor-keys": "npm:8.11.0" + checksum: 10c0/0910da62d8ae261711dd9f89d5c7d8e96ff13c50054436256e5a661309229cb49e3b8189c9468d36b6c4d3f7cddd121519ea78f9b18c9b869a808834b079b2ea languageName: node linkType: hard -"@typescript-eslint/type-utils@npm:8.10.0": - version: 8.10.0 - resolution: "@typescript-eslint/type-utils@npm:8.10.0" +"@typescript-eslint/type-utils@npm:8.11.0": + version: 8.11.0 + resolution: "@typescript-eslint/type-utils@npm:8.11.0" dependencies: - "@typescript-eslint/typescript-estree": "npm:8.10.0" - "@typescript-eslint/utils": "npm:8.10.0" + "@typescript-eslint/typescript-estree": "npm:8.11.0" + "@typescript-eslint/utils": "npm:8.11.0" debug: "npm:^4.3.4" ts-api-utils: "npm:^1.3.0" peerDependenciesMeta: typescript: optional: true - checksum: 10c0/1af8fce8394279e6ac7bcef449a132072ee36e374c8d557564246ffe7150230844901ca0305e29525bf37c87010e03bf8bedec76fccbfe1e41931cb4f274e208 + checksum: 10c0/b69e31c1599ceeb20c29052a4ddb33a554174a3a4c55ee37d90c9b8250af6ef978a0b9ddbeefef4e83d62c4caea1bfa2d8088527f397bde69fb4ab9b360d794a languageName: node linkType: hard -"@typescript-eslint/types@npm:8.10.0": - version: 8.10.0 - resolution: "@typescript-eslint/types@npm:8.10.0" - checksum: 10c0/f27dd43c8383e02e914a254257627e393dfc0f08b0f74a253c106813ae361f090271b2f3f2ef588fa3ca1329897d873da595bb5641fe8e3091b25eddca24b5d2 +"@typescript-eslint/types@npm:8.11.0": + version: 8.11.0 + resolution: "@typescript-eslint/types@npm:8.11.0" + checksum: 10c0/5ccdd3eeee077a6fc8e7f4bc0e0cbc9327b1205a845253ec5c0c6c49ff915e853161df00c24a0ffb4b8ec745d3f153dd0e066400a021c844c026e31121f46699 languageName: node linkType: hard -"@typescript-eslint/typescript-estree@npm:8.10.0": - version: 8.10.0 - resolution: "@typescript-eslint/typescript-estree@npm:8.10.0" +"@typescript-eslint/typescript-estree@npm:8.11.0": + version: 8.11.0 + resolution: "@typescript-eslint/typescript-estree@npm:8.11.0" dependencies: - "@typescript-eslint/types": "npm:8.10.0" - "@typescript-eslint/visitor-keys": "npm:8.10.0" + "@typescript-eslint/types": "npm:8.11.0" + "@typescript-eslint/visitor-keys": "npm:8.11.0" debug: "npm:^4.3.4" fast-glob: "npm:^3.3.2" is-glob: "npm:^4.0.3" @@ -1873,31 +1873,31 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 10c0/535a740fe25be0e28fe68c41e3264273d1e5169c9f938e08cc0e3415c357726f43efa44621960108c318fc3305c425d29f3223b6e731d44d67f84058a8947304 + checksum: 10c0/b629ad3cd32b005d5c1d67c36958a418f8672efebea869399834f4f201ebf90b942165eebb5c9d9799dcabdc2cc26e5fabb00629f76b158847f42e1a491a75a6 languageName: node linkType: hard -"@typescript-eslint/utils@npm:8.10.0": - version: 8.10.0 - resolution: "@typescript-eslint/utils@npm:8.10.0" +"@typescript-eslint/utils@npm:8.11.0": + version: 8.11.0 + resolution: "@typescript-eslint/utils@npm:8.11.0" dependencies: "@eslint-community/eslint-utils": "npm:^4.4.0" - "@typescript-eslint/scope-manager": "npm:8.10.0" - "@typescript-eslint/types": "npm:8.10.0" - "@typescript-eslint/typescript-estree": "npm:8.10.0" + "@typescript-eslint/scope-manager": "npm:8.11.0" + "@typescript-eslint/types": "npm:8.11.0" + "@typescript-eslint/typescript-estree": "npm:8.11.0" peerDependencies: eslint: ^8.57.0 || ^9.0.0 - checksum: 10c0/a21a2933517176abd00fcd5d8d80023e35dc3d89d5746bbac43790b4e984ab1f371117db08048bce7f42d54c64f4e0e35161149f8f34fd25a27bff9d1110fd16 + checksum: 10c0/bb5bcc8d928a55b22298e76f834ea6a9fe125a9ffeb6ac23bee0258b3ed32f41e281888a3d0be226a05e1011bb3b70e42a71a40366acdefea6779131c46bc522 languageName: node linkType: hard -"@typescript-eslint/visitor-keys@npm:8.10.0": - version: 8.10.0 - resolution: "@typescript-eslint/visitor-keys@npm:8.10.0" +"@typescript-eslint/visitor-keys@npm:8.11.0": + version: 8.11.0 + resolution: "@typescript-eslint/visitor-keys@npm:8.11.0" dependencies: - "@typescript-eslint/types": "npm:8.10.0" + "@typescript-eslint/types": "npm:8.11.0" eslint-visitor-keys: "npm:^3.4.3" - checksum: 10c0/14721c4ac939640d5fd1ee1b6eeb07604b11a6017e319e21dcc71e7aac2992341fc7ae1992d977bad4433b6a1d0d1c0c279e6927316b26245f6e333f922fa458 + checksum: 10c0/7a5a49609fdc47e114fe59eee56393c90b122ec8e9520f90b0c5e189635ae1ccfa8e00108f641342c2c8f4637fe9d40c77927cf7c8248a3a660812cb4b7d0c08 languageName: node linkType: hard @@ -1910,14 +1910,14 @@ __metadata: "@emotion/react": "npm:^11.13.3" "@emotion/styled": "npm:^11.13.0" "@eslint/js": "npm:^9.13.0" - "@mui/icons-material": "npm:^6.1.4" - "@mui/material": "npm:^6.1.4" + "@mui/icons-material": "npm:^6.1.5" + "@mui/material": "npm:^6.1.5" "@preact/compat": "npm:^18.3.1" "@preact/preset-vite": "npm:^2.9.1" "@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.7" + "@types/node": "npm:^22.7.8" "@types/react": "npm:^18.3.11" "@types/react-dom": "npm:^18.3.1" "@types/react-router-dom": "npm:^5.3.3" @@ -1940,7 +1940,7 @@ __metadata: terser: "npm:^5.36.0" typesafe-i18n: "npm:^5.26.2" typescript: "npm:^5.6.3" - typescript-eslint: "npm:8.10.0" + typescript-eslint: "npm:8.11.0" vite: "npm:^5.4.9" vite-plugin-imagemin: "npm:^0.6.1" vite-tsconfig-paths: "npm:^5.0.1" @@ -7042,17 +7042,17 @@ __metadata: languageName: node linkType: hard -"typescript-eslint@npm:8.10.0": - version: 8.10.0 - resolution: "typescript-eslint@npm:8.10.0" +"typescript-eslint@npm:8.11.0": + version: 8.11.0 + resolution: "typescript-eslint@npm:8.11.0" dependencies: - "@typescript-eslint/eslint-plugin": "npm:8.10.0" - "@typescript-eslint/parser": "npm:8.10.0" - "@typescript-eslint/utils": "npm:8.10.0" + "@typescript-eslint/eslint-plugin": "npm:8.11.0" + "@typescript-eslint/parser": "npm:8.11.0" + "@typescript-eslint/utils": "npm:8.11.0" peerDependenciesMeta: typescript: optional: true - checksum: 10c0/9eca1bfdea4e108bea06f0053b57f8a9eaeb43bf3316a39c6d29631bd3217ec67611e46d361417c48a5f6eeb99c4a7fc81c020734b1b47d7b8e42fa67d74ea0f + checksum: 10c0/8f9b5916c9f47b0cbb26f142d1a266a6aaf33998ec87621252dffb56d8fe0ad01a944f8d8d837e4e6058153a1deee3557527d14fa7bf7ef80a927334529db6bd languageName: node linkType: hard diff --git a/lib/framework/MqttSettingsService.cpp b/lib/framework/MqttSettingsService.cpp index 198e845f8..9274ae49b 100644 --- a/lib/framework/MqttSettingsService.cpp +++ b/lib/framework/MqttSettingsService.cpp @@ -253,7 +253,7 @@ StateUpdateResult MqttSettings::update(JsonObject root, MqttSettings & settings) bool changed = false; #ifndef TASMOTA_SDK - newSettings.enableTLS = root["enableTLS"] | false; + newSettings.enableTLS = root["enableTLS"]; newSettings.rootCA = root["rootCA"] | ""; #else newSettings.enableTLS = false; diff --git a/lib/framework/NetworkSettingsService.cpp b/lib/framework/NetworkSettingsService.cpp index aaec147f6..6db003296 100644 --- a/lib/framework/NetworkSettingsService.cpp +++ b/lib/framework/NetworkSettingsService.cpp @@ -424,12 +424,12 @@ StateUpdateResult NetworkSettings::update(JsonObject root, NetworkSettings & set settings.bssid = root["bssid"] | ""; settings.password = root["password"] | FACTORY_WIFI_PASSWORD; settings.hostname = root["hostname"] | FACTORY_WIFI_HOSTNAME; - settings.staticIPConfig = root["static_ip_config"] | false; - settings.bandwidth20 = root["bandwidth20"] | false; + settings.staticIPConfig = root["static_ip_config"]; + settings.bandwidth20 = root["bandwidth20"]; settings.tx_power = static_cast(root["tx_power"] | 0); settings.nosleep = root["nosleep"] | true; settings.enableMDNS = root["enableMDNS"] | true; - settings.enableCORS = root["enableCORS"] | false; + settings.enableCORS = root["enableCORS"]; settings.CORSOrigin = root["CORSOrigin"] | "*"; // extended settings diff --git a/mock-api/api_test.sh b/mock-api/api_test.sh deleted file mode 100755 index c6e464831..000000000 --- a/mock-api/api_test.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/sh - -# API - -curl -X GET http://ems-esp.local/api/system/info -echo "\n" - -# HA - -ha_url="http://192.168.1.42:8123" -ha_token="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiIwMzMyZjU1MjhlZmM0NGIyOTgyMjIxNThiODU1NDkyNSIsImlhdCI6MTcyMTMwNDg2NSwiZXhwIjoyMDM2NjY0ODY1fQ.Q-Y7E_i7clH3ff4Ma-OMmhZfbN7aMi_CahKwmoar" - -curl -X POST \ - ${ha_url}/api/services/script/test_notify \ - -H "Authorization: Bearer ${ha_token}" \ - -H "Content-Type: application/json" \ diff --git a/mock-api/mockServer.js b/mock-api/mockServer.js index 9c82c49ba..88bc0a9a0 100644 --- a/mock-api/mockServer.js +++ b/mock-api/mockServer.js @@ -116,7 +116,7 @@ export default () => { }; count++; res.write(`data: ${JSON.stringify(data)}\n\n`); - }, 500); + }, 1000); // if client closes connection res.on('close', () => { diff --git a/mock-api/rest_server.ts b/mock-api/rest_server.ts index f8231c602..610684aa8 100644 --- a/mock-api/rest_server.ts +++ b/mock-api/rest_server.ts @@ -199,21 +199,75 @@ function custom_support() { function check_upgrade(version: string) { console.log('check upgrade from version', version); const data = { + emsesp_version: VERSION, upgradeable: true - // upgradeable: false + // upgradeable: false, }; return data; } // START DATA +// EMS-ESP Application Settings +let settings = { + locale: 'en', + tx_mode: 1, + ems_bus_id: 11, + syslog_enabled: false, + syslog_level: 3, + trace_raw: false, + syslog_mark_interval: 0, + syslog_host: '192.168.1.8', + syslog_port: 514, + boiler_heatingoff: false, + remote_timeout: 24, + remote_timeout_en: false, + shower_timer: true, + shower_alert: false, + shower_alert_coldshot: 10, + shower_alert_trigger: 7, + shower_min_duration: 180, + rx_gpio: 4, + tx_gpio: 5, + dallas_gpio: 14, + dallas_parasite: false, + led_gpio: 2, + hide_led: true, + low_clock: false, + telnet_enabled: true, + notoken_api: false, + readonly_mode: false, + analog_enabled: true, + pbutton_gpio: 34, + solar_maxflow: 30, + board_profile: 'E32V2', + fahrenheit: false, + bool_format: 1, + bool_dashboard: 1, + enum_format: 1, + weblog_level: 6, + weblog_buffer: 50, + weblog_compact: true, + phy_type: 1, + eth_power: 15, + eth_phy_addr: 0, + eth_clock_mode: 1, + platform: 'ESP32', + modbus_enabled: false, + modbus_port: 502, + modbus_max_clients: 10, + modbus_timeout: 10000, + developer_mode: true +}; + // LOG const LOG_SETTINGS_ENDPOINT = REST_ENDPOINT_ROOT + 'logSettings'; let log_settings = { level: 6, max_messages: 50, compact: true, - psram: true + psram: true, + developer_mode: settings.developer_mode }; // NTP @@ -478,9 +532,6 @@ const signin = admin_signin; const generate_token = { token: '1234' }; -// -// EMS-ESP Project specific -// const EMSESP_SETTINGS_ENDPOINT = REST_ENDPOINT_ROOT + 'settings'; const EMSESP_CORE_DATA_ENDPOINT = REST_ENDPOINT_ROOT + 'coreData'; const EMSESP_SENSOR_DATA_ENDPOINT = REST_ENDPOINT_ROOT + 'sensorData'; @@ -493,6 +544,7 @@ const EMSESP_DEVICEENTITIES_ENDPOINT2 = REST_ENDPOINT_ROOT + 'deviceEntities/:id const EMSESP_DASHBOARD_DATA_ENDPOINT = REST_ENDPOINT_ROOT + 'dashboardData'; 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'; const EMSESP_WRITE_TEMPSENSOR_ENDPOINT = @@ -502,10 +554,10 @@ const EMSESP_CUSTOMIZATION_ENTITIES_ENDPOINT = REST_ENDPOINT_ROOT + 'customizationEntities'; const EMSESP_RESET_CUSTOMIZATIONS_ENDPOINT = REST_ENDPOINT_ROOT + 'resetCustomizations'; + 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_ACTION_ENDPOINT = REST_ENDPOINT_ROOT + 'action'; // these are used in the API calls only @@ -513,7 +565,7 @@ const EMSESP_SYSTEM_INFO_ENDPOINT = API_ENDPOINT_ROOT + 'system/info'; const emsesp_info = { System: { - version: '3.7-demo', + version: VERSION, uptime: '001+06:40:34.018', 'uptime (seconds)': 110434, freemem: 131, @@ -663,56 +715,6 @@ const emsesp_allvalues = { } }; -let settings = { - locale: 'en', - tx_mode: 1, - ems_bus_id: 11, - syslog_enabled: false, - syslog_level: 3, - trace_raw: false, - syslog_mark_interval: 0, - syslog_host: '192.168.1.8', - syslog_port: 514, - boiler_heatingoff: false, - remote_timeout: 24, - remote_timeout_en: false, - shower_timer: true, - shower_alert: false, - shower_alert_coldshot: 10, - shower_alert_trigger: 7, - shower_min_duration: 180, - rx_gpio: 4, - tx_gpio: 5, - dallas_gpio: 14, - dallas_parasite: false, - led_gpio: 2, - hide_led: true, - low_clock: false, - telnet_enabled: true, - notoken_api: false, - readonly_mode: false, - analog_enabled: true, - pbutton_gpio: 34, - solar_maxflow: 30, - board_profile: 'E32V2', - fahrenheit: false, - bool_format: 1, - bool_dashboard: 1, - enum_format: 1, - weblog_level: 6, - weblog_buffer: 50, - weblog_compact: true, - phy_type: 1, - eth_power: 15, - eth_phy_addr: 0, - eth_clock_mode: 1, - platform: 'ESP32', - modbus_enabled: false, - modbus_port: 502, - modbus_max_clients: 10, - modbus_timeout: 10000 -}; - const emsesp_coredata = { connected: true, // connected: false, @@ -4848,16 +4850,17 @@ router if (data.device === 'system') { if (cmd === 'info') { return emsesp_info; - } - if (cmd === 'format') { + } else if (cmd === 'format') { console.log('formatting...'); return status(200); - } - if (cmd === 'restart') { + } else if (cmd === 'restart') { console.log('restarting...'); system_status.status = 'restarting'; countHardwarePoll = 0; return status(200); + } else if (cmd === 'read') { + console.log('send read command:', data.data); + return status(200); } } return status(404); // not found diff --git a/platformio.ini b/platformio.ini index 4572f19d2..7c69ef39c 100644 --- a/platformio.ini +++ b/platformio.ini @@ -85,8 +85,6 @@ lib_deps = ; ; builds for GitHub Actions CI -; We don't set EMSESP_DEFAULT_BOARD_PROFILE and let the code determine the board type. e.g. with board_build.extra_flags = '-DEMSESP_DEFAULT_BOARD_PROFILE="S32"' -; ; the Web interface is built separately during the GH Action script, so skipped on these targets ; [env:ci_s_4M] @@ -240,7 +238,7 @@ lib_ldf_mode = off lib_ignore = Module EMS-ESP-Modules ; unit tests -; The code is in test/test_api.h/cpp +; The code is in ./test/test_api.* ; to run use `pio run -e native-test -t exec`. All tests should PASS. ; to update the test results, compile with -DEMSESP_UNITY_CREATE by uncommenting the line below ; then run and capture the output between "START - CUT HERE" and "END - CUT HERE" into the test_api.h file diff --git a/src/console.cpp b/src/console.cpp index f12a61464..262f02632 100644 --- a/src/console.cpp +++ b/src/console.cpp @@ -379,30 +379,25 @@ static void setup_commands(std::shared_ptr const & commands) { } }); + // read [offset] [length] commands->add_command(ShellContext::MAIN, CommandFlags::USER, {F_(read)}, string_vector{F_(deviceid_mandatory), F_(typeid_mandatory), F_(offset_optional), F_(length_optional)}, [=](Shell & shell, const std::vector & arguments) { - uint8_t device_id = Helpers::hextoint(arguments.front().c_str()); + // loop through arguments and add to data as text, separated by a space + std::string data; + for (const auto & arg : arguments) { + if (!data.empty()) { + data += " "; + } + data += arg; + } - if (!EMSESP::valid_device(device_id)) { + if (!System::readCommand(data.c_str())) { shell.printfln("Invalid deviceID"); return; } - - uint16_t type_id = Helpers::hextoint(arguments[1].c_str()); - if (arguments.size() == 4) { - uint16_t offset = Helpers::hextoint(arguments[2].c_str()); - uint8_t length = Helpers::hextoint(arguments.back().c_str()); - EMSESP::send_read_request(type_id, device_id, offset, length, true); - } else if (arguments.size() == 3) { - uint16_t offset = Helpers::hextoint(arguments.back().c_str()); - EMSESP::send_read_request(type_id, device_id, offset, 0, true); - } else { - EMSESP::send_read_request(type_id, device_id, 0, 0, true); - } - EMSESP::set_read_id(type_id); }); commands->add_command(ShellContext::MAIN, diff --git a/src/helpers.cpp b/src/helpers.cpp index 2d8f9a76c..dcef19c3b 100644 --- a/src/helpers.cpp +++ b/src/helpers.cpp @@ -99,7 +99,7 @@ char * Helpers::ultostr(char * ptr, uint32_t value, const uint8_t base) { #endif /** - * fast atoi returning a std::string + * fast itoa returning a std::string * http://www.strudel.org.uk/itoa/ * */ @@ -122,8 +122,9 @@ std::string Helpers::itoa(int16_t value) { } /* - * fast itoa and optimized for ESP32 + * fast itoa * written by Lukás Chmela, Released under GPLv3. http://www.strudel.org.uk/itoa/ version 0.4 + * optimized for ESP32 */ char * Helpers::itoa(int32_t value, char * result, const uint8_t base) { // check that the base if valid diff --git a/src/helpers.h b/src/helpers.h index e33142995..bf2f84246 100644 --- a/src/helpers.h +++ b/src/helpers.h @@ -20,7 +20,6 @@ #define EMSESP_HELPERS_H #include "telegram.h" // for EMS_VALUE_* settings - #include "common.h" namespace emsesp { diff --git a/src/locale_translations.h b/src/locale_translations.h index 5312a1813..02e100ea2 100644 --- a/src/locale_translations.h +++ b/src/locale_translations.h @@ -63,6 +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(read_cmd, "send read request", "", "", "", "", "", "", "", "", "") // 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 @@ -182,7 +183,7 @@ MAKE_WORD_TRANSLATION(eco, "eco", "Eco", "Eco", "Eko", "eko", "øko", "éco", "e MAKE_WORD_TRANSLATION(ecoplus, "eco+", "Eco+", "Eco+", "Eko+", "eko+", "øko+", "éco+", "eko+", "Eco+") MAKE_WORD_TRANSLATION(intelligent, "intelligent", "Intelligent", "intelligent", "Intelligent", "inteligentny", "intelligent", "intelligent", "akıllı", "intelligente", "inteligentný") MAKE_WORD_TRANSLATION(flow, "flow", "Durchfluss", "volumestroom", "Flöde", "przepływ", "strømme", "débit", "akım", "flusso", "tok") -MAKE_WORD_TRANSLATION(manual, "manual", "Manuell", "handmatig", "Manuell", "ręczny", "manuell", "manuel", "manuel", "manuale", "manuálny") +MAKE_WORD_TRANSLATION(manual, "manual", "manuell", "handmatig", "Manuell", "ręczny", "manuell", "manuel", "manuel", "manuale", "manuálny") MAKE_WORD_TRANSLATION(buffer, "buffer", "Speicher", "buffer", "Buffert", "bufor", "buffer", "buffer", "tampon", "Buffer", "zásobník") MAKE_WORD_TRANSLATION(bufferedflow, "buffered flow", "Durchlaufspeicher", "doorstroombuffer", "Buffertflöde", "przepływ buforowany", "bufret strømning", "", "tampon akım", "memoria flusso", "zásobníkový prietok") // TODO translate MAKE_WORD_TRANSLATION(layeredbuffer, "layered buffer", "Schichtspeicher", "gelaagde buffer", "Lagrad buffert", "bufor warstwowy", "lagdelt buffer", "", "katmanlı akım", "strato memoria", "vrstvený zásobník") // TODO translate diff --git a/src/system.cpp b/src/system.cpp index 7b3c0adc1..bdcf1615e 100644 --- a/src/system.cpp +++ b/src/system.cpp @@ -409,7 +409,8 @@ void System::reload_settings() { eth_phy_addr_ = settings.eth_phy_addr; eth_clock_mode_ = settings.eth_clock_mode; - locale_ = settings.locale; + locale_ = settings.locale; + developer_mode_ = settings.developer_mode; }); } @@ -851,6 +852,7 @@ void System::system_check() { // commands - takes static function pointers // can be called via Console using 'call system ' void System::commands_init() { + Command::add(EMSdevice::DeviceType::SYSTEM, F_(read), System::command_read, FL_(read_cmd), CommandFlag::ADMIN_ONLY); Command::add(EMSdevice::DeviceType::SYSTEM, F_(send), System::command_send, FL_(send_cmd), CommandFlag::ADMIN_ONLY); Command::add(EMSdevice::DeviceType::SYSTEM, F_(fetch), System::command_fetch, FL_(fetch_cmd), CommandFlag::ADMIN_ONLY); Command::add(EMSdevice::DeviceType::SYSTEM, F_(restart), System::command_restart, FL_(restart_cmd), CommandFlag::ADMIN_ONLY); @@ -1689,6 +1691,7 @@ bool System::command_info(const char * value, const int8_t id, JsonObject output #endif node["modbusEnabled"] = settings.modbus_enabled; node["forceHeatingOff"] = settings.boiler_heatingoff; + node["developerMode"] = settings.developer_mode; }); // Devices - show EMS devices if we have any @@ -2012,4 +2015,60 @@ bool System::uploadFirmwareURL(const char * url) { return true; // OK } +// read command, e.g. read [offset] [length] from console or API +bool System::readCommand(const char * data) { + // extract [offset] [length] from string + char * p; + char value[6]; + + // make a copy so we can iterate, max 15 chars (XX XXXX XX XX) + char data_args[15]; + strlcpy(data_args, data, sizeof(data_args)); + + uint8_t device_id = 0; // is in hex + uint16_t type_id = 0; // is in hex + uint8_t length = 0; + uint8_t offset = 0; + + // first check deviceID + if ((p = strtok(data_args, " ,"))) { // delimiter comma or space + strlcpy(value, p, 10); // get string + device_id = (uint8_t)Helpers::hextoint(value); // convert hex to int + if (!EMSESP::valid_device(device_id)) { + LOG_ERROR("Invalid device ID (%d) for read command", device_id); + return false; // invalid device + } + } + + // iterate until end + uint8_t num_args = 0; + while (p != 0) { + if ((p = strtok(nullptr, " ,"))) { // delimiter comma or space + strlcpy(value, p, 10); // get string + if (num_args == 0) { + type_id = (uint16_t)Helpers::hextoint(value); // convert hex to int + } else if (num_args == 1) { + offset = Helpers::atoint(value); // decimal + } else if (num_args == 2) { + length = Helpers::atoint(value); // decimal + } + num_args++; + } + } + + if (num_args == 0) { + return false; // invalid number of arguments + } + + EMSESP::send_read_request(type_id, device_id, offset, length, true); + EMSESP::set_read_id(type_id); + + return true; +} + +// system read command +bool System::command_read(const char * value, const int8_t id) { + return readCommand(value); +} + } // namespace emsesp diff --git a/src/system.h b/src/system.h index 3bf59eef7..ffc620a3f 100644 --- a/src/system.h +++ b/src/system.h @@ -63,6 +63,7 @@ class System { void loop(); // commands + static bool command_read(const char * value, const int8_t id); static bool command_send(const char * value, const int8_t id); static bool command_publish(const char * value, const int8_t id); static bool command_fetch(const char * value, const int8_t id); @@ -124,6 +125,8 @@ class System { static bool is_valid_gpio(uint8_t pin, bool has_psram = false); static bool load_board_profile(std::vector & data, const std::string & board_profile); + static bool readCommand(const char * data); + static void restart_requested(bool restart_requested) { restart_requested_ = restart_requested; } @@ -170,6 +173,14 @@ class System { readonly_mode_ = readonly_mode; } + bool developer_mode() { + return developer_mode_; + } + + void developer_mode(bool developer_mode) { + developer_mode_ = developer_mode; + } + // Boolean Format API/MQTT uint8_t bool_format() { return bool_format_; @@ -398,6 +409,7 @@ class System { uint16_t modbus_port_; uint8_t modbus_max_clients_; uint32_t modbus_timeout_; + bool developer_mode_; // ethernet uint8_t phy_type_; diff --git a/src/telegram.cpp b/src/telegram.cpp index 54e7ec799..8c171a04b 100644 --- a/src/telegram.cpp +++ b/src/telegram.cpp @@ -632,7 +632,7 @@ uint16_t TxService::read_next_tx(const uint8_t offset, const uint8_t length) { // some telegrams only reply with one byte less, but have higher offsets (boiler 0x10) // some reply with higher offset than requests and have not_set values intermediate (boiler 0xEA) - // We have th last byte received + // We have the last byte received if (offset + old_length >= telegram_last_->offset + telegram_last_->message_data[0]) { return 0; } diff --git a/src/test/test.cpp b/src/test/test.cpp index 50e33aec5..ef3cb8b67 100644 --- a/src/test/test.cpp +++ b/src/test/test.cpp @@ -973,16 +973,16 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const if (single) { // run dedicated tests only - EMSESP::webCustomEntityService.test(); // custom entities - EMSESP::webCustomizationService.test(); // set customizations - this will overwrite any settings in the FS - EMSESP::temperaturesensor_.test(); // add temperature sensors - EMSESP::webSchedulerService.test(); // run scheduler tests, and conditions + // EMSESP::webCustomEntityService.test(); // custom entities + // EMSESP::webCustomizationService.test(); // set customizations - this will overwrite any settings in the FS + // EMSESP::temperaturesensor_.test(); // add temperature sensors + // EMSESP::webSchedulerService.test(); // run scheduler tests, and conditions // request.url("/rest/deviceEntities"); // EMSESP::webCustomizationService.device_entities(&request); - request.url("/rest/dashboardData"); - EMSESP::webDataService.dashboard_data(&request); + // request.url("/rest/dashboardData"); + // EMSESP::webDataService.dashboard_data(&request); // COMMANDS // shell.invoke_command("call system fetch"); @@ -999,7 +999,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const // EMSESP::webAPIService.webAPIService(&request); // POST COMMANDS - // request.method(HTTP_POST); + request.method(HTTP_POST); // char data1[] = "{\"device\":\"system\", \"cmd\":\"restart\",\"id\":-1}"; // deserializeJson(doc, data1); @@ -1021,6 +1021,20 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const // request.url("/rest/action"); // EMSESP::webStatusService.action(&request, doc.as()); + char data6[] = "{\"device\":\"system\", \"cmd\":\"read\",\"value\":\"8 2 27 1\"}"; + deserializeJson(doc, data6); + json = doc.as(); + request.url("/api"); + EMSESP::webAPIService.webAPIService(&request, json); + + char data7[] = "{\"device\":\"system\", \"cmd\":\"read\",\"value\":\"10 234\"}"; + deserializeJson(doc, data7); + json = doc.as(); + request.url("/api"); + EMSESP::webAPIService.webAPIService(&request, json); + + shell.invoke_command("call system read \"8 2 27 1\""); + } else { EMSESP::webCustomEntityService.test(); // custom entities diff --git a/src/version.h b/src/version.h index 82448f289..3b42266e5 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define EMSESP_APP_VERSION "3.7.0-dev.46" \ No newline at end of file +#define EMSESP_APP_VERSION "3.7.0-dev.47" \ No newline at end of file diff --git a/src/web/WebAPIService.cpp b/src/web/WebAPIService.cpp index 063ca114f..4dd87e2b3 100644 --- a/src/web/WebAPIService.cpp +++ b/src/web/WebAPIService.cpp @@ -28,8 +28,9 @@ WebAPIService::WebAPIService(AsyncWebServer * server, SecurityManager * security server->on(EMSESP_API_SERVICE_PATH, [this](AsyncWebServerRequest * request, JsonVariant json) { webAPIService(request, json); }); } -// POST|GET /{device} -// POST|GET /{device}/{entity} +// POST|GET api/ +// POST|GET api/{device} +// POST|GET api/{device}/{entity} void WebAPIService::webAPIService(AsyncWebServerRequest * request, JsonVariant json) { JsonObject input; // if no body then treat it as a secure GET diff --git a/src/web/WebLogService.cpp b/src/web/WebLogService.cpp index 5686f05b9..78b1ff20e 100644 --- a/src/web/WebLogService.cpp +++ b/src/web/WebLogService.cpp @@ -237,12 +237,13 @@ void WebLogService::transmit(const QueuedLogMessage & message) { void WebLogService::getSetValues(AsyncWebServerRequest * request, JsonVariant json) { if ((request->method() == HTTP_GET) || (!json.is())) { // GET - return the values - auto * response = new AsyncJsonResponse(false); - JsonObject root = response->getRoot(); - root["level"] = log_level(); - root["max_messages"] = maximum_log_messages(); - root["compact"] = compact(); - root["psram"] = (EMSESP::system_.PSram() > 0); + auto * response = new AsyncJsonResponse(false); + JsonObject root = response->getRoot(); + root["level"] = log_level(); + root["max_messages"] = maximum_log_messages(); + root["compact"] = compact(); + root["psram"] = (EMSESP::system_.PSram() > 0); + root["developer_mode"] = EMSESP::system_.developer_mode(); response->setLength(); request->send(response); diff --git a/src/web/WebSettingsService.cpp b/src/web/WebSettingsService.cpp index 6be813006..e33f0aeed 100644 --- a/src/web/WebSettingsService.cpp +++ b/src/web/WebSettingsService.cpp @@ -80,6 +80,7 @@ void WebSettings::read(WebSettings & settings, JsonObject root) { root["modbus_port"] = settings.modbus_port; root["modbus_max_clients"] = settings.modbus_max_clients; root["modbus_timeout"] = settings.modbus_timeout; + root["developer_mode"] = settings.developer_mode; } // call on initialization and also when settings are updated via web or console @@ -361,6 +362,9 @@ StateUpdateResult WebSettings::update(JsonObject root, WebSettings & settings) { settings.readonly_mode = root["readonly_mode"]; EMSESP::system_.readonly_mode(settings.readonly_mode); + settings.developer_mode = root["developer_mode"]; + EMSESP::system_.developer_mode(settings.developer_mode); + settings.bool_dashboard = root["bool_dashboard"] | EMSESP_DEFAULT_BOOL_FORMAT; EMSESP::system_.bool_dashboard(settings.bool_dashboard); diff --git a/src/web/WebSettingsService.h b/src/web/WebSettingsService.h index ed20485b3..57a2a00c8 100644 --- a/src/web/WebSettingsService.h +++ b/src/web/WebSettingsService.h @@ -65,10 +65,13 @@ class WebSettings { uint8_t bool_format; uint8_t bool_dashboard; uint8_t enum_format; - int8_t weblog_level; - uint8_t weblog_buffer; - bool weblog_compact; - bool fahrenheit; + + int8_t weblog_level; + uint8_t weblog_buffer; + bool weblog_compact; + + bool fahrenheit; + bool modbus_enabled; uint16_t modbus_port; uint8_t modbus_max_clients; @@ -79,6 +82,8 @@ class WebSettings { uint8_t eth_phy_addr; uint8_t eth_clock_mode; + bool developer_mode; // developer mode + static void read(WebSettings & settings, JsonObject root); static StateUpdateResult update(JsonObject root, WebSettings & settings); diff --git a/src/web/WebStatusService.cpp b/src/web/WebStatusService.cpp index 1fffc5881..490028fed 100644 --- a/src/web/WebStatusService.cpp +++ b/src/web/WebStatusService.cpp @@ -173,10 +173,6 @@ void WebStatusService::action(AsyncWebServerRequest * request, JsonVariant json) ok = uploadURL(param.c_str()); } -#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); @@ -204,7 +200,8 @@ bool WebStatusService::checkUpgrade(JsonObject root, std::string & latest_versio emsesp::EMSESP::logger().debug("Checking for upgrade: %s > %s", EMSESP_APP_VERSION, latest_version.c_str()); #endif - root["upgradeable"] = (this_version > settings_version); + root["upgradeable"] = (this_version > settings_version); + root["emsesp_version"] = EMSESP_APP_VERSION; return true; } diff --git a/mock-api/api_test.http b/test/test_api/api_test.http similarity index 98% rename from mock-api/api_test.http rename to test/test_api/api_test.http index de23c07f9..e78f68b58 100755 --- a/mock-api/api_test.http +++ b/test/test_api/api_test.http @@ -3,7 +3,8 @@ # Open this file in VSC, modify the token, go to the API call and click on 'Send Request' (or Ctrl+Alt+R) # The response will be shown in the right panel -@host = http://ems-esp.local +# @host = http://ems-esp.local +@host = http://192.168.1.206 @host_dev = http://10.10.10.175 @host_standalone = http://localhost:3080 @host_standalone2 = http://localhost:3082 diff --git a/test/test_api/api_test.sh b/test/test_api/api_test.sh new file mode 100755 index 000000000..cc50fcdd2 --- /dev/null +++ b/test/test_api/api_test.sh @@ -0,0 +1,31 @@ +#!/bin/sh + +# +# Command line test for the API +# + +# EMS_ESP API + +emsesp_url="http://192.168.1.206" +emsesp_token="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiYWRtaW4iOnRydWV9.2bHpWya2C7Q12WjNUBD6_7N3RCD7CMl-EGhyQVzFdDg" + +curl -X GET ${emsesp_url}/api/system/info +echo "\n" + +curl -X POST \ + -H "Authorization: Bearer ${emsesp_token}" \ + -H "Content-Type: application/json" \ + -d '{"data":"8 1"}' \ + ${emsesp_url}/api/system/read + +echo "\n" + +# HA API + +ha_url="http://192.168.1.42:8123" +ha_token="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiIwMzMyZjU1MjhlZmM0NGIyOTgyMjIxNThiODU1NDkyNSIsImlhdCI6MTcyMTMwNDg2NSwiZXhwIjoyMDM2NjY0ODY1fQ.Q-Y7E_i7clH3ff4Ma-OMmhZfbN7aMi_CahKwmoar" + +# curl -X POST \ +# ${ha_url}/api/services/script/test_notify \ +# -H "Authorization: Bearer ${ha_token}" \ +# -H "Content-Type: application/json" diff --git a/test/test_api/test_api.h b/test/test_api/test_api.h index f08df7ab9..dc78d37ec 100644 --- a/test/test_api/test_api.h +++ b/test/test_api/test_api.h @@ -40,9 +40,9 @@ void test_2() { "off\",\"heatingtemp\":\"heating temperature\",\"maintenance\":\"maintenance scheduled\",\"maintenancedate\":\"next maintenance " "date\",\"maintenancetime\":\"time to next maintenance\",\"nofrostmode\":\"nofrost mode\",\"nofrosttemp\":\"nofrost " "temperature\",\"nompower\":\"nominal Power\",\"nrgheat\":\"energy heating\",\"pumpcharacter\":\"boiler pump characteristic\",\"pumpdelay\":\"pump " - "delay\",\"pumpmode\":\"boiler pump mode\",\"pumpmodmax\":\"boiler pump max power\",\"pumpmodmin\":\"boiler pump min " - "power\",\"reset\":\"reset\",\"selburnpow\":\"burner selected max power\",\"selflowtemp\":\"selected flow temperature\",\"summertemp\":\"summer " - "temperature\"}]"; + "delay\",\"pumpmode\":\"boiler pump mode\",\"pumpmodmax\":\"boiler pump max power\",\"pumpmodmin\":\"boiler pump min power\",\"pumpontemp\":\"pump " + "logic temperature\",\"reset\":\"reset\",\"selburnpow\":\"burner selected max power\",\"selflowtemp\":\"selected flow " + "temperature\",\"summertemp\":\"summer temperature\"}]"; TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/boiler/commands")); } @@ -149,8 +149,8 @@ void test_17() { } void test_18() { - auto expected_response = - "[{\"name\":\"seltemp\",\"storage\":\"ram\",\"type\":\"number\",\"readable\":true,\"writeable\":true,\"visible\":true,\"value\":\"14\"}]"; + auto expected_response = "[{\"name\":\"seltemp\",\"fullname\":\"seltemp\",\"storage\":\"ram\",\"type\":\"number\",\"readable\":true,\"writeable\":true," + "\"visible\":true,\"value\":\"14\"}]"; TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/custom/seltemp")); } @@ -163,17 +163,20 @@ void test_19() { "\"entityFormat\":1,\"base\":\"ems-esp\",\"discoveryPrefix\":\"homeassistant\",\"discoveryType\":0,\"nestedFormat\":1,\"haEnabled\":true,\"mqttQos\":0," "\"mqttRetain\":false,\"publishTimeHeartbeat\":60,\"publishTimeBoiler\":10,\"publishTimeThermostat\":10,\"publishTimeSolar\":10,\"publishTimeMixer\":" "10,\"publishTimeWater\":0,\"publishTimeOther\":10,\"publishTimeSensor\":10,\"publishSingle\":false,\"publish2command\":false,\"sendResponse\":false}," - "\"syslog\":{\"enabled\":false},\"sensor\":{\"temperatureSensors\":2,\"temperatureSensorReads\":0,\"temperatureSensorFails\":0,\"analogSensors\":2," + "\"syslog\":{\"enabled\":false},\"sensor\":{\"temperatureSensors\":2,\"temperatureSensorReads\":0,\"temperatureSensorFails\":0,\"analogSensors\":3," "\"analogSensorReads\":0,\"analogSensorFails\":0},\"api\":{\"APICalls\":0,\"APIFails\":0},\"bus\":{\"busStatus\":\"connected\",\"busProtocol\":" "\"Buderus\",\"busTelegramsReceived\":8,\"busReads\":0,\"busWrites\":0,\"busIncompleteTelegrams\":0,\"busReadsFailed\":0,\"busWritesFailed\":0," "\"busRxLineQuality\":100,\"busTxLineQuality\":100},\"settings\":{\"boardProfile\":\"S32\",\"locale\":\"en\",\"txMode\":8,\"emsBusID\":11," "\"showerTimer\":false,\"showerMinDuration\":180,\"showerAlert\":false,\"hideLed\":false,\"noTokenApi\":false,\"readonlyMode\":false,\"fahrenheit\":" "false,\"dallasParasite\":false,\"boolFormat\":1,\"boolDashboard\":1,\"enumFormat\":1,\"analogEnabled\":true,\"telnetEnabled\":true," - "\"maxWebLogBuffer\":25,\"webLogBuffer\":0,\"modbusEnabled\":false,\"forceHeatingOff\":false},\"devices\":[{\"type\":\"boiler\",\"name\":\"Custom " - "Name!!\",\"deviceID\":\"0x08\",\"productID\":123,\"brand\":\"\",\"version\":\"01.00\",\"entities\":37,\"handlersReceived\":\"0x18\"," + "\"maxWebLogBuffer\":25,\"webLogBuffer\":0,\"modbusEnabled\":false,\"forceHeatingOff\":false,\"developerMode\":false},\"devices\":[{\"type\":" + "\"boiler\",\"name\":\"My Custom " + "Boiler\",\"deviceID\":\"0x08\",\"productID\":123,\"brand\":\"\",\"version\":\"01.00\",\"entities\":37,\"handlersReceived\":\"0x18\"," "\"handlersFetched\":\"0x14 0x33\",\"handlersPending\":\"0xBF 0x10 0x11 0xC2 0x15 0x1C 0x19 0x1A 0x35 0x34 0x2A 0xD1 0xE3 0xE4 0xE5 0xE9 0x2E " "0x3B\"},{\"type\":\"thermostat\",\"name\":\"FW120\",\"deviceID\":\"0x10\",\"productID\":192,\"brand\":\"\",\"version\":\"01.00\",\"entities\":15," - "\"handlersReceived\":\"0x016F\",\"handlersFetched\":\"0x0170 0x0171\",\"handlersPending\":\"0xA3 0x06 0xA2 0x12 0x13 0x0172 0x0165 0x0168\"}]}]"; + "\"handlersReceived\":\"0x016F\",\"handlersFetched\":\"0x0170 0x0171\",\"handlersPending\":\"0xA3 0x06 0xA2 0x12 0x13 0x0172 0x0165 " + "0x0168\"},{\"type\":\"temperaturesensor\",\"name\":\"temperaturesensor\",\"entities\":2},{\"type\":\"analogsensor\",\"name\":\"analogsensor\"," + "\"entities\":3},{\"type\":\"scheduler\",\"name\":\"scheduler\",\"entities\":2},{\"type\":\"custom\",\"name\":\"custom\",\"entities\":4}]}]"; TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/system")); } @@ -186,17 +189,20 @@ void test_20() { "\"entityFormat\":1,\"base\":\"ems-esp\",\"discoveryPrefix\":\"homeassistant\",\"discoveryType\":0,\"nestedFormat\":1,\"haEnabled\":true,\"mqttQos\":0," "\"mqttRetain\":false,\"publishTimeHeartbeat\":60,\"publishTimeBoiler\":10,\"publishTimeThermostat\":10,\"publishTimeSolar\":10,\"publishTimeMixer\":" "10,\"publishTimeWater\":0,\"publishTimeOther\":10,\"publishTimeSensor\":10,\"publishSingle\":false,\"publish2command\":false,\"sendResponse\":false}," - "\"syslog\":{\"enabled\":false},\"sensor\":{\"temperatureSensors\":2,\"temperatureSensorReads\":0,\"temperatureSensorFails\":0,\"analogSensors\":2," + "\"syslog\":{\"enabled\":false},\"sensor\":{\"temperatureSensors\":2,\"temperatureSensorReads\":0,\"temperatureSensorFails\":0,\"analogSensors\":3," "\"analogSensorReads\":0,\"analogSensorFails\":0},\"api\":{\"APICalls\":0,\"APIFails\":0},\"bus\":{\"busStatus\":\"connected\",\"busProtocol\":" "\"Buderus\",\"busTelegramsReceived\":8,\"busReads\":0,\"busWrites\":0,\"busIncompleteTelegrams\":0,\"busReadsFailed\":0,\"busWritesFailed\":0," "\"busRxLineQuality\":100,\"busTxLineQuality\":100},\"settings\":{\"boardProfile\":\"S32\",\"locale\":\"en\",\"txMode\":8,\"emsBusID\":11," "\"showerTimer\":false,\"showerMinDuration\":180,\"showerAlert\":false,\"hideLed\":false,\"noTokenApi\":false,\"readonlyMode\":false,\"fahrenheit\":" "false,\"dallasParasite\":false,\"boolFormat\":1,\"boolDashboard\":1,\"enumFormat\":1,\"analogEnabled\":true,\"telnetEnabled\":true," - "\"maxWebLogBuffer\":25,\"webLogBuffer\":0,\"modbusEnabled\":false,\"forceHeatingOff\":false},\"devices\":[{\"type\":\"boiler\",\"name\":\"Custom " - "Name!!\",\"deviceID\":\"0x08\",\"productID\":123,\"brand\":\"\",\"version\":\"01.00\",\"entities\":37,\"handlersReceived\":\"0x18\"," + "\"maxWebLogBuffer\":25,\"webLogBuffer\":0,\"modbusEnabled\":false,\"forceHeatingOff\":false,\"developerMode\":false},\"devices\":[{\"type\":" + "\"boiler\",\"name\":\"My Custom " + "Boiler\",\"deviceID\":\"0x08\",\"productID\":123,\"brand\":\"\",\"version\":\"01.00\",\"entities\":37,\"handlersReceived\":\"0x18\"," "\"handlersFetched\":\"0x14 0x33\",\"handlersPending\":\"0xBF 0x10 0x11 0xC2 0x15 0x1C 0x19 0x1A 0x35 0x34 0x2A 0xD1 0xE3 0xE4 0xE5 0xE9 0x2E " "0x3B\"},{\"type\":\"thermostat\",\"name\":\"FW120\",\"deviceID\":\"0x10\",\"productID\":192,\"brand\":\"\",\"version\":\"01.00\",\"entities\":15," - "\"handlersReceived\":\"0x016F\",\"handlersFetched\":\"0x0170 0x0171\",\"handlersPending\":\"0xA3 0x06 0xA2 0x12 0x13 0x0172 0x0165 0x0168\"}]}]"; + "\"handlersReceived\":\"0x016F\",\"handlersFetched\":\"0x0170 0x0171\",\"handlersPending\":\"0xA3 0x06 0xA2 0x12 0x13 0x0172 0x0165 " + "0x0168\"},{\"type\":\"temperaturesensor\",\"name\":\"temperaturesensor\",\"entities\":2},{\"type\":\"analogsensor\",\"name\":\"analogsensor\"," + "\"entities\":3},{\"type\":\"scheduler\",\"name\":\"scheduler\",\"entities\":2},{\"type\":\"custom\",\"name\":\"custom\",\"entities\":4}]}]"; TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/system/info")); } @@ -228,8 +234,8 @@ void test_25() { } void test_26() { - auto expected_response = "[{\"name\":\"test_scheduler\",\"type\":\"boolean\",\"value\":\"on\",\"time\":\"12:00\",\"command\":\"system/" - "fetch\",\"cmd_data\":\"10\",\"readable\":true,\"writeable\":true,\"visible\":true}]"; + auto expected_response = "[{\"name\":\"test_scheduler\",\"fullname\":\"test_scheduler\",\"type\":\"boolean\",\"value\":\"on\",\"time\":\"12:00\"," + "\"command\":\"system/fetch\",\"cmd_data\":\"10\",\"readable\":true,\"writeable\":true,\"visible\":true}]"; TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/scheduler/test_scheduler")); } @@ -244,14 +250,14 @@ void test_28() { } void test_29() { - auto expected_response = - "[{\"id\":\"0B_0C0D_0E0F_1011\",\"name\":\"test_tempsensor2\",\"value\":45.6,\"type\":\"number\",\"uom\":\"°C\",\"writeable\":false}]"; + auto expected_response = "[{\"id\":\"0B_0C0D_0E0F_1011\",\"name\":\"test_tempsensor2\",\"fullname\":\"test_tempsensor2\",\"value\":45.6,\"type\":" + "\"number\",\"uom\":\"°C\",\"readable\":true,\"writeable\":false,\"visible\":true}]"; TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/temperaturesensor/test_tempsensor2")); } void test_30() { - auto expected_response = - "[{\"id\":\"0B_0C0D_0E0F_1011\",\"name\":\"test_tempsensor2\",\"value\":45.6,\"type\":\"number\",\"uom\":\"°C\",\"writeable\":false}]"; + auto expected_response = "[{\"id\":\"0B_0C0D_0E0F_1011\",\"name\":\"test_tempsensor2\",\"fullname\":\"test_tempsensor2\",\"value\":45.6,\"type\":" + "\"number\",\"uom\":\"°C\",\"readable\":true,\"writeable\":false,\"visible\":true}]"; TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/temperaturesensor/0B_0C0D_0E0F_1011")); } @@ -261,18 +267,18 @@ void test_31() { } void test_32() { - auto expected_response = "[{\"test_analogsensor1\":0,\"test_analogsensor2\":1}]"; + auto expected_response = "[{\"test_analogsensor1\":0,\"test_analogsensor2\":1,\"test_analogsensor3\":0}]"; TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/analogsensor")); } void test_33() { - auto expected_response = "[{\"test_analogsensor1\":0,\"test_analogsensor2\":1}]"; + auto expected_response = "[{\"test_analogsensor1\":0,\"test_analogsensor2\":1,\"test_analogsensor3\":0}]"; TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/analogsensor/info")); } void test_34() { - auto expected_response = - "[{\"gpio\":36,\"type\":\"number\",\"analog\":\"adc\",\"value\":0,\"writeable\":false,\"offset\":0,\"factor\":0.1,\"uom\":\"mV\"}]"; + auto expected_response = "[{\"name\":\"test_analogsensor1\",\"fullname\":\"test_analogsensor1\",\"gpio\":36,\"type\":\"number\",\"analog\":\"adc\"," + "\"value\":0,\"readable\":true,\"writeable\":false,\"visible\":true,\"offset\":0,\"factor\":0.1,\"uom\":\"mV\"}]"; TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/analogsensor/test_analogsensor1")); } @@ -287,12 +293,12 @@ void test_36() { } void test_37() { - auto expected_response = "[{\"message\":\"no bad in boiler\"}]"; + auto expected_response = "[{\"message\":\"no bad/value in boiler\"}]"; TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/boiler/bad/value")); } void test_38() { - auto expected_response = "[{\"message\":\"Command comfort failed (Error)\"}]"; + auto expected_response = "[{\"message\":\"no valu in comfort\"}]"; TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/boiler/comfort/valu")); }