Merge pull request #2117 from proddy/dev

Developer Mode and send EMS Read Commands from WebUI - #2116
This commit is contained in:
Proddy
2024-10-22 13:57:01 +02:00
committed by GitHub
52 changed files with 848 additions and 607 deletions

View File

@@ -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) - 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) - 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) - 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 ## Fixed

View File

@@ -31,6 +31,8 @@ export default tseslint.config(
'@typescript-eslint/no-unsafe-enum-comparison': 'off', '@typescript-eslint/no-unsafe-enum-comparison': 'off',
'@typescript-eslint/no-unused-expressions': 'off', '@typescript-eslint/no-unused-expressions': 'off',
'@typescript-eslint/no-unsafe-assignment': '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': [ '@typescript-eslint/no-misused-promises': [
'error', 'error',
{ {

View File

@@ -24,8 +24,8 @@
"@alova/adapter-xhr": "2.0.8", "@alova/adapter-xhr": "2.0.8",
"@emotion/react": "^11.13.3", "@emotion/react": "^11.13.3",
"@emotion/styled": "^11.13.0", "@emotion/styled": "^11.13.0",
"@mui/icons-material": "^6.1.4", "@mui/icons-material": "^6.1.5",
"@mui/material": "^6.1.4", "@mui/material": "^6.1.5",
"@table-library/react-table-library": "4.1.7", "@table-library/react-table-library": "4.1.7",
"alova": "3.1.0", "alova": "3.1.0",
"async-validator": "^4.2.5", "async-validator": "^4.2.5",
@@ -47,7 +47,7 @@
"@preact/preset-vite": "^2.9.1", "@preact/preset-vite": "^2.9.1",
"@trivago/prettier-plugin-sort-imports": "^4.3.0", "@trivago/prettier-plugin-sort-imports": "^4.3.0",
"@types/formidable": "^3", "@types/formidable": "^3",
"@types/node": "^22.7.7", "@types/node": "^22.7.8",
"@types/react": "^18.3.11", "@types/react": "^18.3.11",
"@types/react-dom": "^18.3.1", "@types/react-dom": "^18.3.1",
"@types/react-router-dom": "^5.3.3", "@types/react-router-dom": "^5.3.3",
@@ -58,7 +58,7 @@
"prettier": "^3.3.3", "prettier": "^3.3.3",
"rollup-plugin-visualizer": "^5.12.0", "rollup-plugin-visualizer": "^5.12.0",
"terser": "^5.36.0", "terser": "^5.36.0",
"typescript-eslint": "8.10.0", "typescript-eslint": "8.11.0",
"vite": "^5.4.9", "vite": "^5.4.9",
"vite-plugin-imagemin": "^0.6.1", "vite-plugin-imagemin": "^0.6.1",
"vite-tsconfig-paths": "^5.0.1" "vite-tsconfig-paths": "^5.0.1"

View File

@@ -15,6 +15,7 @@ import DownloadUpload from 'app/settings/DownloadUpload';
import MqttSettings from 'app/settings/MqttSettings'; import MqttSettings from 'app/settings/MqttSettings';
import NTPSettings from 'app/settings/NTPSettings'; import NTPSettings from 'app/settings/NTPSettings';
import Settings from 'app/settings/Settings'; import Settings from 'app/settings/Settings';
import Version from 'app/settings/Version';
import Network from 'app/settings/network/Network'; import Network from 'app/settings/network/Network';
import Security from 'app/settings/security/Security'; import Security from 'app/settings/security/Security';
import APStatus from 'app/status/APStatus'; import APStatus from 'app/status/APStatus';
@@ -51,6 +52,7 @@ const AuthenticatedRouting = () => {
{me.admin && ( {me.admin && (
<> <>
<Route path="/settings" element={<Settings />} /> <Route path="/settings" element={<Settings />} />
<Route path="/settings/version" element={<Version />} />
<Route path="/settings/application" element={<ApplicationSettings />} /> <Route path="/settings/application" element={<ApplicationSettings />} />
<Route path="/settings/mqtt" element={<MqttSettings />} /> <Route path="/settings/mqtt" element={<MqttSettings />} />
<Route path="/settings/ntp" element={<NTPSettings />} /> <Route path="/settings/ntp" element={<NTPSettings />} />

View File

@@ -102,6 +102,9 @@ const Dashboard = () => {
Row: ` Row: `
cursor: pointer; cursor: pointer;
background-color: #1e1e1e; background-color: #1e1e1e;
&:nth-of-type(odd) .td {
background-color: #303030;
},
&:hover .td { &:hover .td {
background-color: #177ac9; background-color: #177ac9;
} }
@@ -234,7 +237,7 @@ const Dashboard = () => {
<Grid container spacing={0} justifyContent="flex-start"> <Grid container spacing={0} justifyContent="flex-start">
<Grid size={11}> <Grid size={11}>
<Typography mb={2} variant="body1" color="warning"> <Typography mb={2} variant="body1" color="warning">
{LL.DASHBOARD_1()} {LL.DASHBOARD_1()}.
</Typography> </Typography>
</Grid> </Grid>
@@ -274,7 +277,7 @@ const Dashboard = () => {
}} }}
> >
{!loading && data.length === 0 ? ( {!loading && data.length === 0 ? (
<Typography variant="subtitle2" color="warning"> <Typography variant="subtitle2" color="secondary">
{LL.NO_DATA()} {LL.NO_DATA()}
</Typography> </Typography>
) : ( ) : (

View File

@@ -166,11 +166,6 @@ const Devices = () => {
Table: ` Table: `
--data-table-library_grid-template-columns: repeat(1, minmax(0, 1fr)) 130px; --data-table-library_grid-template-columns: repeat(1, minmax(0, 1fr)) 130px;
`, `,
BaseRow: `
// .td {
// height: 42px;
// }
`,
HeaderRow: ` HeaderRow: `
.th { .th {
padding: 8px; padding: 8px;
@@ -268,7 +263,7 @@ const Devices = () => {
), ),
VALUE: (array) => 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())) array.sort((a, b) => a.v.toString().localeCompare(b.v.toString()))
} }
} }
@@ -362,7 +357,9 @@ const Devices = () => {
}, },
{ {
accessor: (dv: DeviceValue) => 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' name: 'UoM'
}, },
{ {

View File

@@ -51,19 +51,19 @@ const Help = () => {
} }
}); });
const { send: sendExportAllValues } = useRequest( // const { send: sendExportAllValues } = useRequest(
() => callAction({ action: 'export', param: 'allvalues' }), // () => callAction({ action: 'export', param: 'allvalues' }),
{ // {
immediate: false // immediate: false
} // }
) // )
.onSuccess((event) => { // .onSuccess((event) => {
saveFile(event.data, 'allvalues', '.txt'); // saveFile(event.data, 'allvalues', '.txt');
toast.info(LL.DOWNLOAD_SUCCESSFUL()); // toast.info(LL.DOWNLOAD_SUCCESSFUL());
}) // })
.onError((error) => { // .onError((error) => {
toast.error(error.message); // toast.error(error.message);
}); // });
const { send: sendAPI } = useRequest((data: APIcall) => API(data), { const { send: sendAPI } = useRequest((data: APIcall) => API(data), {
immediate: false immediate: false
@@ -103,7 +103,7 @@ const Help = () => {
sx={{ sx={{
maxHeight: { xs: 100, md: 250 } maxHeight: { xs: 100, md: 250 }
}} }}
onError={(e) => setNotFound(true)} onError={() => setNotFound(true)}
src={ src={
notFound notFound
? '' ? ''
@@ -162,11 +162,11 @@ const Help = () => {
color="primary" color="primary"
onClick={() => sendAPI({ device: 'system', cmd: 'info', id: 0 })} onClick={() => sendAPI({ device: 'system', cmd: 'info', id: 0 })}
> >
{LL.DOWNLOAD(1)}&nbsp;{LL.SUPPORT_INFORMATION(0)} {LL.SUPPORT_INFORMATION(0)}
</Button> </Button>
</Box> </Box>
<Button {/* <Button
sx={{ ml: 2 }} sx={{ ml: 2 }}
startIcon={<DownloadIcon />} startIcon={<DownloadIcon />}
variant="outlined" variant="outlined"
@@ -174,7 +174,7 @@ const Help = () => {
onClick={() => sendExportAllValues()} onClick={() => sendExportAllValues()}
> >
{LL.DOWNLOAD(1)}&nbsp;{LL.ALLVALUES()} {LL.DOWNLOAD(1)}&nbsp;{LL.ALLVALUES()}
</Button> </Button> */}
<Divider sx={{ mt: 4 }} /> <Divider sx={{ mt: 4 }} />

View File

@@ -219,7 +219,7 @@ const Sensors = () => {
sortToggleType: SortToggleType.AlternateWithReset, sortToggleType: SortToggleType.AlternateWithReset,
sortFns: { sortFns: {
GPIO: (array) => array.sort((a, b) => a.g - b.g), 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)), NAME: (array) => array.sort((a, b) => a.n.localeCompare(b.n)),
TYPE: (array) => array.sort((a, b) => a.t - b.t), TYPE: (array) => array.sort((a, b) => a.t - b.t),
VALUE: (array) => array.sort((a, b) => a.v - b.v) VALUE: (array) => array.sort((a, b) => a.v - b.v)
@@ -238,7 +238,7 @@ const Sensors = () => {
}, },
sortToggleType: SortToggleType.AlternateWithReset, sortToggleType: SortToggleType.AlternateWithReset,
sortFns: { 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)), NAME: (array) => array.sort((a, b) => a.n.localeCompare(b.n)),
VALUE: (array) => array.sort((a, b) => a.t - b.t) VALUE: (array) => array.sort((a, b) => a.t - b.t)
} }

View File

@@ -42,6 +42,7 @@ export interface Settings {
modbus_port: number; modbus_port: number;
modbus_max_clients: number; modbus_max_clients: number;
modbus_timeout: number; modbus_timeout: number;
developer_mode: boolean;
} }
export enum busConnectionStatus { export enum busConnectionStatus {
@@ -273,6 +274,7 @@ export interface APIcall {
device: string; device: string;
cmd: string; cmd: string;
id: number; id: number;
data?: string; // optional
} }
export interface Action { export interface Action {

View File

@@ -686,6 +686,16 @@ const ApplicationSettings = () => {
<Typography sx={{ pb: 1, pt: 2 }} variant="h6" color="primary"> <Typography sx={{ pb: 1, pt: 2 }} variant="h6" color="primary">
{LL.SPECIAL_FUNCTIONS()} {LL.SPECIAL_FUNCTIONS()}
</Typography> </Typography>
<BlockFormControlLabel
control={
<Checkbox
checked={data.developer_mode}
onChange={updateFormValue}
name="developer_mode"
/>
}
label={LL.DEVELOPER_MODE()}
/>
<BlockFormControlLabel <BlockFormControlLabel
control={ control={
<Checkbox <Checkbox
@@ -696,7 +706,6 @@ const ApplicationSettings = () => {
} }
label={LL.HEATINGOFF()} label={LL.HEATINGOFF()}
/> />
<BlockFormControlLabel <BlockFormControlLabel
control={ control={
<Checkbox <Checkbox

View File

@@ -1,27 +1,13 @@
import { useState } from 'react'; import { useState } from 'react';
import { toast } from 'react-toastify'; import { toast } from 'react-toastify';
import CancelIcon from '@mui/icons-material/Cancel';
import DownloadIcon from '@mui/icons-material/GetApp'; import DownloadIcon from '@mui/icons-material/GetApp';
import InfoOutlinedIcon from '@mui/icons-material/InfoOutlined'; import { Box, Button, Typography } from '@mui/material';
import WarningIcon from '@mui/icons-material/Warning';
import {
Box,
Button,
Dialog,
DialogActions,
DialogContent,
DialogTitle,
Link,
Typography
} from '@mui/material';
import Grid from '@mui/material/Grid2'; import Grid from '@mui/material/Grid2';
import * as SystemApi from 'api/system'; import * as SystemApi from 'api/system';
import { API, callAction } from 'api/app'; import { API, callAction } from 'api/app';
import { getDevVersion, getStableVersion } from 'api/system';
import { dialogStyle } from 'CustomTheme';
import { useRequest } from 'alova/client'; import { useRequest } from 'alova/client';
import type { APIcall } from 'app/main/types'; import type { APIcall } from 'app/main/types';
import RestartMonitor from 'app/status/RestartMonitor'; import RestartMonitor from 'app/status/RestartMonitor';
@@ -38,18 +24,6 @@ const DownloadUpload = () => {
const { LL } = useI18nContext(); const { LL } = useI18nContext();
const [restarting, setRestarting] = useState<boolean>(false); const [restarting, setRestarting] = useState<boolean>(false);
const [openDialog, setOpenDialog] = useState<boolean>(false);
const [useDev, setUseDev] = useState<boolean>(false);
const [upgradeAvailable, setUpgradeAvailable] = useState<boolean>(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( const { send: sendExportData } = useRequest(
(type: string) => callAction({ action: 'export', param: type }), (type: string) => callAction({ action: 'export', param: type }),
@@ -71,13 +45,6 @@ const DownloadUpload = () => {
const { data, send: loadData, error } = useRequest(SystemApi.readSystemStatus); const { data, send: loadData, error } = useRequest(SystemApi.readSystemStatus);
const { send: sendUploadURL } = useRequest(
(url: string) => callAction({ action: 'uploadURL', param: url }),
{
immediate: false
}
);
const doRestart = async () => { const doRestart = async () => {
setRestarting(true); setRestarting(true);
await sendAPI({ device: 'system', cmd: 'restart', id: 0 }).catch( 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()); useLayoutTitle(LL.DOWNLOAD_UPLOAD());
const internet_live =
latestDevVersion !== undefined && latestVersion !== undefined;
const renderUploadDialog = () => {
if (!internet_live) {
return null;
}
return (
<Dialog
sx={dialogStyle}
open={openDialog}
onClose={() => setOpenDialog(false)}
>
<DialogTitle>
{LL.INSTALL('') +
' ' +
(useDev ? LL.DEVELOPMENT() : LL.STABLE()) +
' Firmware'}
</DialogTitle>
<DialogContent dividers>
<Typography mb={2}>
{LL.INSTALL_VERSION(useDev ? latestDevVersion : latestVersion)}
</Typography>
<Link
target="_blank"
href={useDev ? DEV_RELNOTES_URL : STABLE_RELNOTES_URL}
color="primary"
>
{LL.RELEASE_NOTES()}
</Link>
&nbsp;|&nbsp;
<Link target="_blank" href={getBinURL(useDev)} color="primary">
{LL.DOWNLOAD(1)}
</Link>
</DialogContent>
<DialogActions>
<Button
startIcon={<CancelIcon />}
variant="outlined"
onClick={() => setOpenDialog(false)}
color="secondary"
>
{LL.CANCEL()}
</Button>
<Button
startIcon={<WarningIcon color="warning" />}
variant="outlined"
onClick={() => installFirmwareURL(getBinURL(useDev))}
color="primary"
>
{LL.INSTALL('')}
</Button>
</DialogActions>
</Dialog>
);
};
// 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 = () => { const content = () => {
if (!data) { if (!data) {
return <FormLoader onRetry={loadData} errorMessage={error?.message} />; return <FormLoader onRetry={loadData} errorMessage={error?.message} />;
} }
const isDev = data.emsesp_version.includes('dev');
return ( return (
<> <>
<Typography sx={{ pb: 2 }} variant="h6" color="primary"> <Typography sx={{ pb: 2 }} variant="h6" color="primary">
@@ -232,7 +78,7 @@ const DownloadUpload = () => {
color="primary" color="primary"
onClick={() => sendExportData('settings')} onClick={() => sendExportData('settings')}
> >
{LL.DOWNLOAD(1)}&nbsp;{LL.SETTINGS_OF(LL.APPLICATION())} {LL.SETTINGS_OF(LL.APPLICATION())}
</Button> </Button>
<Button <Button
@@ -242,7 +88,7 @@ const DownloadUpload = () => {
color="primary" color="primary"
onClick={() => sendExportData('customizations')} onClick={() => sendExportData('customizations')}
> >
{LL.DOWNLOAD(1)}&nbsp;{LL.CUSTOMIZATIONS()} {LL.CUSTOMIZATIONS()}
</Button> </Button>
<Button <Button
sx={{ ml: 2 }} sx={{ ml: 2 }}
@@ -251,7 +97,7 @@ const DownloadUpload = () => {
color="primary" color="primary"
onClick={() => sendExportData('entities')} onClick={() => sendExportData('entities')}
> >
{LL.DOWNLOAD(1)}&nbsp;{LL.CUSTOM_ENTITIES(0)} {LL.CUSTOM_ENTITIES(0)}
</Button> </Button>
<Button <Button
sx={{ ml: 2 }} sx={{ ml: 2 }}
@@ -260,7 +106,7 @@ const DownloadUpload = () => {
color="primary" color="primary"
onClick={() => sendExportData('schedule')} onClick={() => sendExportData('schedule')}
> >
{LL.DOWNLOAD(1)}&nbsp;{LL.SCHEDULE(0)} {LL.SCHEDULE(0)}
</Button> </Button>
</Grid> </Grid>
@@ -273,68 +119,6 @@ const DownloadUpload = () => {
</Box> </Box>
<SingleUpload doRestart={doRestart} /> <SingleUpload doRestart={doRestart} />
<Typography sx={{ pt: 2 }} variant="h6" color="primary">
{LL.EMS_ESP_VER()}
</Typography>
<Box p={2} mt={2} border="1px solid grey" borderRadius={2}>
<Typography>
<b>{LL.VERSION() + ':'}</b>&nbsp;{data.emsesp_version}
{data.build_flags && (
<Typography variant="caption">
&nbsp; &#40;{data.build_flags}&#41;
</Typography>
)}
</Typography>
<Typography>
<b>Platform:</b>&nbsp;{getPlatform()}
</Typography>
<Typography>
<b>Release:</b>&nbsp;{isDev ? LL.DEVELOPMENT() : LL.STABLE()}
{!isDev && (
<Button
sx={{ ml: 2 }}
size="small"
variant="outlined"
color="primary"
onClick={() => showFirmwareDialog(true)}
>
{LL.SWITCH_DEV()}
</Button>
)}
</Typography>
<Typography mt={2} color="secondary">
<InfoOutlinedIcon color="secondary" sx={{ verticalAlign: 'middle' }} />
&nbsp;&nbsp;
{upgradeAvailable ? LL.UPGRADE_AVAILABLE() : LL.LATEST_VERSION()}
{upgradeAvailable &&
internet_live &&
(data.psram ? (
<Button
sx={{ ml: 2, textTransform: 'none' }}
size="small"
variant="outlined"
color="primary"
onClick={() => showFirmwareDialog(false)}
>
{isDev
? LL.INSTALL('v' + latestDevVersion)
: LL.INSTALL('v' + latestVersion)}
</Button>
) : (
<>
&nbsp;&nbsp;
<Link target="_blank" href={getBinURL(isDev)} color="primary">
{LL.DOWNLOAD(1)}&nbsp;v
{isDev ? latestDevVersion : latestVersion}
</Link>
</>
))}
</Typography>
{renderUploadDialog()}
</Box>
</> </>
); );
}; };

View File

@@ -1,6 +1,7 @@
import { useState } from 'react'; import { useState } from 'react';
import AccessTimeIcon from '@mui/icons-material/AccessTime'; import AccessTimeIcon from '@mui/icons-material/AccessTime';
import BuildIcon from '@mui/icons-material/Build';
import CancelIcon from '@mui/icons-material/Cancel'; import CancelIcon from '@mui/icons-material/Cancel';
import DeviceHubIcon from '@mui/icons-material/DeviceHub'; import DeviceHubIcon from '@mui/icons-material/DeviceHub';
import ImportExportIcon from '@mui/icons-material/ImportExport'; import ImportExportIcon from '@mui/icons-material/ImportExport';
@@ -20,7 +21,7 @@ import {
List List
} from '@mui/material'; } from '@mui/material';
import { API } from 'api/app'; import { API, callAction } from 'api/app';
import { dialogStyle } from 'CustomTheme'; import { dialogStyle } from 'CustomTheme';
import { useRequest } from 'alova/client'; import { useRequest } from 'alova/client';
@@ -39,6 +40,11 @@ const Settings = () => {
immediate: false immediate: false
}); });
// get installed version
const { data } = useRequest(() => callAction({ action: 'checkUpgrade' }), {
initialData: { emsesp_version: '...' }
});
const doFormat = async () => { const doFormat = async () => {
await sendAPI({ device: 'system', cmd: 'format', id: 0 }).then(() => { await sendAPI({ device: 'system', cmd: 'format', id: 0 }).then(() => {
setConfirmFactoryReset(false); setConfirmFactoryReset(false);
@@ -77,10 +83,18 @@ const Settings = () => {
const content = () => ( const content = () => (
<> <>
<List sx={{ borderRadius: 3, border: '2px solid grey' }}> <List sx={{ borderRadius: 3, border: '2px solid grey' }}>
<ListMenuItem
icon={BuildIcon}
bgcolor="#72caf9"
label={LL.EMS_ESP_VER()}
text={data.emsesp_version}
to="version"
/>
<ListMenuItem <ListMenuItem
icon={TuneIcon} icon={TuneIcon}
bgcolor="#134ba2" bgcolor="#134ba2"
label={LL.SETTINGS_OF(LL.APPLICATION())} label={LL.APPLICATION()}
text={LL.APPLICATION_SETTINGS_1()} text={LL.APPLICATION_SETTINGS_1()}
to="application" to="application"
/> />
@@ -88,7 +102,7 @@ const Settings = () => {
<ListMenuItem <ListMenuItem
icon={SettingsEthernetIcon} icon={SettingsEthernetIcon}
bgcolor="#40828f" bgcolor="#40828f"
label={LL.SETTINGS_OF(LL.NETWORK(0))} label={LL.NETWORK(0)}
text={LL.CONFIGURE(LL.SETTINGS_OF(LL.NETWORK(1)))} text={LL.CONFIGURE(LL.SETTINGS_OF(LL.NETWORK(1)))}
to="network" to="network"
/> />
@@ -96,7 +110,7 @@ const Settings = () => {
<ListMenuItem <ListMenuItem
icon={SettingsInputAntennaIcon} icon={SettingsInputAntennaIcon}
bgcolor="#5f9a5f" bgcolor="#5f9a5f"
label={LL.SETTINGS_OF(LL.ACCESS_POINT(0))} label={LL.ACCESS_POINT(0)}
text={LL.CONFIGURE(LL.ACCESS_POINT(1))} text={LL.CONFIGURE(LL.ACCESS_POINT(1))}
to="ap" to="ap"
/> />
@@ -104,7 +118,7 @@ const Settings = () => {
<ListMenuItem <ListMenuItem
icon={AccessTimeIcon} icon={AccessTimeIcon}
bgcolor="#c5572c" bgcolor="#c5572c"
label={LL.SETTINGS_OF('NTP')} label="NTP"
text={LL.CONFIGURE(LL.LOCAL_TIME(1))} text={LL.CONFIGURE(LL.LOCAL_TIME(1))}
to="ntp" to="ntp"
/> />
@@ -112,14 +126,14 @@ const Settings = () => {
<ListMenuItem <ListMenuItem
icon={DeviceHubIcon} icon={DeviceHubIcon}
bgcolor="#68374d" bgcolor="#68374d"
label={LL.SETTINGS_OF('MQTT')} label="MQTT"
text={LL.CONFIGURE('MQTT')} text={LL.CONFIGURE('MQTT')}
to="mqtt" to="mqtt"
/> />
<ListMenuItem <ListMenuItem
icon={LockIcon} icon={LockIcon}
label={LL.SETTINGS_OF(LL.SECURITY(0))} label={LL.SECURITY(0)}
text={LL.SECURITY_1()} text={LL.SECURITY_1()}
to="security" to="security"
/> />

View File

@@ -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<boolean>(false);
const [openDialog, setOpenDialog] = useState<boolean>(false);
const [useDev, setUseDev] = useState<boolean>(false);
const [upgradeAvailable, setUpgradeAvailable] = useState<boolean>(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 (
<Dialog
sx={dialogStyle}
open={openDialog}
onClose={() => setOpenDialog(false)}
>
<DialogTitle>
{LL.INSTALL('') +
' ' +
(useDev ? LL.DEVELOPMENT() : LL.STABLE()) +
' Firmware'}
</DialogTitle>
<DialogContent dividers>
<Typography mb={2}>
{LL.INSTALL_VERSION(useDev ? latestDevVersion : latestVersion)}
</Typography>
<Link
target="_blank"
href={useDev ? DEV_RELNOTES_URL : STABLE_RELNOTES_URL}
color="primary"
>
changelog
</Link>
&nbsp;|&nbsp;
<Link target="_blank" href={getBinURL(useDev)} color="primary">
{LL.DOWNLOAD(1)}
</Link>
</DialogContent>
<DialogActions>
<Button
startIcon={<CancelIcon />}
variant="outlined"
onClick={() => setOpenDialog(false)}
color="secondary"
>
{LL.CANCEL()}
</Button>
<Button
startIcon={<WarningIcon color="warning" />}
variant="outlined"
onClick={() => installFirmwareURL(getBinURL(useDev))}
color="primary"
>
{LL.INSTALL('')}
</Button>
</DialogActions>
</Dialog>
);
};
// 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 <FormLoader onRetry={loadData} errorMessage={error?.message} />;
}
const isDev = data.emsesp_version.includes('dev');
return (
<>
<Typography variant="h6" color="primary">
Firmware Version Check
</Typography>
<Box p={2} mt={2} border="1px solid grey" borderRadius={2}>
<Typography>
<b>{LL.VERSION() + ':'}</b>&nbsp;{data.emsesp_version}
{data.build_flags && (
<Typography variant="caption">
&nbsp; &#40;{data.build_flags}&#41;
</Typography>
)}
</Typography>
<Typography>
<b>Platform:</b>&nbsp;{getPlatform()}
</Typography>
<Typography>
<b>Release:</b>&nbsp;
<Link
target="_blank"
href={useDev ? DEV_RELNOTES_URL : STABLE_RELNOTES_URL}
color="primary"
>
{isDev ? LL.DEVELOPMENT() : LL.STABLE()}
</Link>
{!isDev && (
<Button
sx={{ ml: 2 }}
variant="outlined"
color="primary"
onClick={() => showFirmwareDialog(true)}
>
{LL.SWITCH_DEV()}
</Button>
)}
</Typography>
<Typography mt={2} color="warning">
<InfoOutlinedIcon color="warning" sx={{ verticalAlign: 'middle' }} />
&nbsp;&nbsp;
{upgradeAvailable ? LL.UPGRADE_AVAILABLE() : LL.LATEST_VERSION()}
{upgradeAvailable &&
internet_live &&
(data.psram ? (
<Button
sx={{ ml: 2, textTransform: 'none' }}
variant="outlined"
color="primary"
onClick={() => showFirmwareDialog(false)}
>
{isDev
? LL.INSTALL('v' + latestDevVersion)
: LL.INSTALL('v' + latestVersion)}
</Button>
) : (
<>
&nbsp;&nbsp;
<Link target="_blank" href={getBinURL(isDev)} color="primary">
{LL.DOWNLOAD(1)}&nbsp;v
{isDev ? latestDevVersion : latestVersion}
</Link>
</>
))}
</Typography>
{renderUploadDialog()}
</Box>
</>
);
};
return (
<SectionContent>{restarting ? <RestartMonitor /> : content()}</SectionContent>
);
};
export default Version;

View File

@@ -1,9 +1,7 @@
import { useContext, useState } from 'react'; import { useContext, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { toast } from 'react-toastify'; import { toast } from 'react-toastify';
import AccessTimeIcon from '@mui/icons-material/AccessTime'; import AccessTimeIcon from '@mui/icons-material/AccessTime';
import BuildIcon from '@mui/icons-material/Build';
import CancelIcon from '@mui/icons-material/Cancel'; import CancelIcon from '@mui/icons-material/Cancel';
import DeviceHubIcon from '@mui/icons-material/DeviceHub'; import DeviceHubIcon from '@mui/icons-material/DeviceHub';
import DirectionsBusIcon from '@mui/icons-material/DirectionsBus'; 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 RouterIcon from '@mui/icons-material/Router';
import SettingsInputAntennaIcon from '@mui/icons-material/SettingsInputAntenna'; import SettingsInputAntennaIcon from '@mui/icons-material/SettingsInputAntenna';
import TimerIcon from '@mui/icons-material/Timer'; import TimerIcon from '@mui/icons-material/Timer';
import UpgradeIcon from '@mui/icons-material/Upgrade';
import WifiIcon from '@mui/icons-material/Wifi'; import WifiIcon from '@mui/icons-material/Wifi';
import { import {
Avatar, Avatar,
@@ -46,8 +43,6 @@ import RestartMonitor from './RestartMonitor';
const SystemStatus = () => { const SystemStatus = () => {
const { LL } = useI18nContext(); const { LL } = useI18nContext();
const navigate = useNavigate();
useLayoutTitle(LL.STATUS_OF('')); useLayoutTitle(LL.STATUS_OF(''));
const { me } = useContext(AuthenticatedContext); const { me } = useContext(AuthenticatedContext);
@@ -248,28 +243,6 @@ const SystemStatus = () => {
return ( return (
<> <>
<List sx={{ borderRadius: 3, border: '2px solid grey' }}> <List sx={{ borderRadius: 3, border: '2px solid grey' }}>
<ListItem>
<ListItemAvatar>
<Avatar sx={{ bgcolor: '#134ba2', color: 'white' }}>
<BuildIcon />
</Avatar>
</ListItemAvatar>
<ListItemText
primary={LL.EMS_ESP_VER()}
secondary={'' + data.emsesp_version}
/>
{me.admin && (
<Button
startIcon={<UpgradeIcon />}
variant="outlined"
color="primary"
onClick={() => navigate('/settings/upload')}
>
{LL.UPDATE()}
</Button>
)}
</ListItem>
<ListItem> <ListItem>
<ListItemAvatar> <ListItemAvatar>
<Avatar sx={{ bgcolor: '#c5572c', color: 'white' }}> <Avatar sx={{ bgcolor: '#c5572c', color: 'white' }}>
@@ -292,6 +265,15 @@ const SystemStatus = () => {
)} )}
</ListItem> </ListItem>
<ListMenuItem
disabled={!me.admin}
icon={MemoryIcon}
bgcolor="#68374d"
label={LL.HARDWARE()}
text={formatNumber(data.free_heap) + ' KB' + ' ' + LL.FREE_MEMORY()}
to="/status/hardwarestatus"
/>
<ListMenuItem <ListMenuItem
disabled={!me.admin} disabled={!me.admin}
icon={DirectionsBusIcon} icon={DirectionsBusIcon}
@@ -301,15 +283,6 @@ const SystemStatus = () => {
to="/status/activity" to="/status/activity"
/> />
<ListMenuItem
disabled={!me.admin}
icon={MemoryIcon}
bgcolor="#68374d"
label={LL.STATUS_OF(LL.HARDWARE())}
text={formatNumber(data.free_heap) + ' KB' + ' ' + LL.FREE_MEMORY()}
to="/status/hardwarestatus"
/>
<ListMenuItem <ListMenuItem
disabled={!me.admin} disabled={!me.admin}
icon={ icon={
@@ -318,7 +291,7 @@ const SystemStatus = () => {
: RouterIcon : RouterIcon
} }
bgcolor={networkStatusHighlight()} bgcolor={networkStatusHighlight()}
label={LL.STATUS_OF(LL.NETWORK(1))} label={LL.NETWORK(1)}
text={networkStatus()} text={networkStatus()}
to="/status/network" to="/status/network"
/> />
@@ -327,7 +300,7 @@ const SystemStatus = () => {
disabled={!me.admin} disabled={!me.admin}
icon={DeviceHubIcon} icon={DeviceHubIcon}
bgcolor={activeHighlight(data.mqtt_status)} bgcolor={activeHighlight(data.mqtt_status)}
label={LL.STATUS_OF('MQTT')} label="MQTT"
text={data.mqtt_status ? LL.ACTIVE() : LL.INACTIVE(0)} text={data.mqtt_status ? LL.ACTIVE() : LL.INACTIVE(0)}
to="/status/mqtt" to="/status/mqtt"
/> />
@@ -336,7 +309,7 @@ const SystemStatus = () => {
disabled={!me.admin} disabled={!me.admin}
icon={AccessTimeIcon} icon={AccessTimeIcon}
bgcolor={ntpStatusHighlight()} bgcolor={ntpStatusHighlight()}
label={LL.STATUS_OF('NTP')} label="NTP"
text={ntpStatus()} text={ntpStatus()}
to="/status/ntp" to="/status/ntp"
/> />
@@ -345,7 +318,7 @@ const SystemStatus = () => {
disabled={!me.admin} disabled={!me.admin}
icon={SettingsInputAntennaIcon} icon={SettingsInputAntennaIcon}
bgcolor={activeHighlight(data.ap_status)} 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)} text={data.ap_status ? LL.ACTIVE() : LL.INACTIVE(0)}
to="/status/ap" to="/status/ap"
/> />

View File

@@ -2,13 +2,23 @@ import { useEffect, useRef, useState } from 'react';
import { toast } from 'react-toastify'; import { toast } from 'react-toastify';
import DownloadIcon from '@mui/icons-material/GetApp'; import DownloadIcon from '@mui/icons-material/GetApp';
import PlayArrowIcon from '@mui/icons-material/PlayArrow';
import WarningIcon from '@mui/icons-material/Warning'; 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 Grid from '@mui/material/Grid2';
import { API } from 'api/app';
import { fetchLogES, readLogSettings, updateLogSettings } from 'api/system'; import { fetchLogES, readLogSettings, updateLogSettings } from 'api/system';
import { useSSE } from 'alova/client'; import { useRequest, useSSE } from 'alova/client';
import { import {
BlockFormControlLabel, BlockFormControlLabel,
BlockNavigation, BlockNavigation,
@@ -80,9 +90,20 @@ const SystemLog = () => {
update: updateLogSettings 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<LogEntry[]>([]); const [logEntries, setLogEntries] = useState<LogEntry[]>([]);
const [autoscroll, setAutoscroll] = useState(true); const [autoscroll, setAutoscroll] = useState(true);
const ALPHA_NUMERIC_DASH_REGEX = /^[a-fA-F0-9 ]+$/;
const updateFormValue = updateValueDirty( const updateFormValue = updateValueDirty(
origData, origData,
dirtyFlags, dirtyFlags,
@@ -150,6 +171,19 @@ const SystemLog = () => {
} }
}, [logEntries.length]); }, [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 = () => { const content = () => {
if (!data) { if (!data) {
return <FormLoader onRetry={loadData} errorMessage={errorMessage} />; return <FormLoader onRetry={loadData} errorMessage={errorMessage} />;
@@ -163,7 +197,7 @@ const SystemLog = () => {
name="level" name="level"
label={LL.LOG_LEVEL()} label={LL.LOG_LEVEL()}
value={data.level} value={data.level}
sx={{ width: '15ch' }} sx={{ width: '10ch' }}
variant="outlined" variant="outlined"
onChange={updateFormValue} onChange={updateFormValue}
margin="normal" margin="normal"
@@ -218,6 +252,7 @@ const SystemLog = () => {
label={LL.AUTO_SCROLL()} label={LL.AUTO_SCROLL()}
/> />
</Grid> </Grid>
<Grid>
<Button <Button
startIcon={<DownloadIcon />} startIcon={<DownloadIcon />}
variant="outlined" variant="outlined"
@@ -237,6 +272,51 @@ const SystemLog = () => {
</Button> </Button>
)} )}
</Grid> </Grid>
{readOpen ? (
<Box
component="form"
sx={{ display: 'flex', alignItems: 'flex-end' }}
onSubmit={(e) => {
e.preventDefault();
sendReadCommand();
}}
>
<IconButton
disableRipple
onClick={() => {
setReadOpen(false);
setReadValue('');
}}
>
<PlayArrowIcon color="primary" sx={{ my: 2.5 }} />
</IconButton>
<TextField
value={readValue}
onChange={(e) => {
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="<deviceID> <typeID> [offset] [len]"
/>
</Box>
) : (
<>
{data.developer_mode && (
<IconButton onClick={sendReadCommand}>
<PlayArrowIcon color="primary" />
</IconButton>
)}
</>
)}
</Grid>
<Box <Box
sx={{ sx={{
backgroundColor: 'black', backgroundColor: 'black',

View File

@@ -39,7 +39,7 @@ const DragNdrop = ({ onFileSelected }) => {
event.preventDefault(); event.preventDefault();
const droppedFiles = event.dataTransfer.files; const droppedFiles = event.dataTransfer.files;
if (droppedFiles.length > 0) { if (droppedFiles.length > 0) {
checkFileExtension(droppedFiles[0]); checkFileExtension(droppedFiles[0] as File);
} }
}; };

View File

@@ -177,7 +177,6 @@ const cz: Translation = {
SYSTEM_FACTORY_TEXT_DIALOG: 'Opravdu chcete resetovat EMS-ESP do továrního nastavení?', SYSTEM_FACTORY_TEXT_DIALOG: 'Opravdu chcete resetovat EMS-ESP do továrního nastavení?',
STABLE: 'Stabilní', STABLE: 'Stabilní',
DEVELOPMENT: 'Vývojová verze', DEVELOPMENT: 'Vývojová verze',
RELEASE_NOTES: 'poznámky k vydání',
EMS_ESP_VER: 'Verze firmwaru', EMS_ESP_VER: 'Verze firmwaru',
UPTIME: 'Doba provozu systému', UPTIME: 'Doba provozu systému',
FREE_MEMORY: 'Volná paměť', FREE_MEMORY: 'Volná paměť',
@@ -344,6 +343,7 @@ const cz: Translation = {
DASHBOARD: 'Dashboard', DASHBOARD: 'Dashboard',
NO_DATA: 'Žádná data nejsou k dispozici', 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í.', 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; export default cz;

View File

@@ -177,7 +177,6 @@ const de: Translation = {
SYSTEM_FACTORY_TEXT_DIALOG: 'Sind Sie sicher, alle Einstellungen auf Werkseinstellung zu setzen?', SYSTEM_FACTORY_TEXT_DIALOG: 'Sind Sie sicher, alle Einstellungen auf Werkseinstellung zu setzen?',
STABLE: 'Stabil', STABLE: 'Stabil',
DEVELOPMENT: 'Entwicklung', DEVELOPMENT: 'Entwicklung',
RELEASE_NOTES: 'Versionshinweise',
EMS_ESP_VER: 'Firmware-Version', EMS_ESP_VER: 'Firmware-Version',
UPTIME: 'Systembetriebszeit', UPTIME: 'Systembetriebszeit',
FREE_MEMORY: 'Freier RAM Speicher', FREE_MEMORY: 'Freier RAM Speicher',
@@ -343,7 +342,8 @@ const de: Translation = {
AUTO_SCROLL: 'Automatisches Scrollen', AUTO_SCROLL: 'Automatisches Scrollen',
DASHBOARD: 'Dashboard', DASHBOARD: 'Dashboard',
NO_DATA: 'Keine Daten verfügbar', 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; export default de;

View File

@@ -115,7 +115,7 @@ const en: Translation = {
READONLY: 'Enable read-only mode (blocks all outgoing EMS Tx Write commands)', READONLY: 'Enable read-only mode (blocks all outgoing EMS Tx Write commands)',
UNDERCLOCK_CPU: 'Underclock CPU speed', UNDERCLOCK_CPU: 'Underclock CPU speed',
REMOTE_TIMEOUT: 'Remote timeout', 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', HEATINGOFF: 'Start boiler with forced heating off',
MIN_DURATION: 'Wait time', MIN_DURATION: 'Wait time',
ENABLE_SHOWER_TIMER: 'Enable Shower Timer', 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?', SYSTEM_FACTORY_TEXT_DIALOG: 'Are you sure you want to reset EMS-ESP to its factory defaults?',
STABLE: 'Stable', STABLE: 'Stable',
DEVELOPMENT: 'Development', DEVELOPMENT: 'Development',
RELEASE_NOTES: 'release notes',
EMS_ESP_VER: 'Firmware Version', EMS_ESP_VER: 'Firmware Version',
UPTIME: 'System Uptime', UPTIME: 'System Uptime',
FREE_MEMORY: 'Free Memory', FREE_MEMORY: 'Free Memory',
@@ -344,6 +343,7 @@ const en: Translation = {
DASHBOARD: 'Dashboard', DASHBOARD: 'Dashboard',
NO_DATA: 'No data available', NO_DATA: 'No data available',
DASHBOARD_1: 'Customize your dashboard by marking EMS entities as Favorite using the Customizations module.', DASHBOARD_1: 'Customize your dashboard by marking EMS entities as Favorite using the Customizations module.',
DEVELOPER_MODE: 'Developer Mode'
}; };
export default en; export default en;

View File

@@ -116,7 +116,7 @@ const fr: Translation = {
UNDERCLOCK_CPU: 'Underclock du CPU', UNDERCLOCK_CPU: 'Underclock du CPU',
HEATINGOFF: 'Start boiler with forced heating off', // TODO translate HEATINGOFF: 'Start boiler with forced heating off', // TODO translate
REMOTE_TIMEOUT: 'Remote timeout', 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', MIN_DURATION: 'Wait time',
ENABLE_SHOWER_TIMER: 'Activer la minuterie de la douche', ENABLE_SHOWER_TIMER: 'Activer la minuterie de la douche',
ENABLE_SHOWER_ALERT: 'Activer les alertes de durée de 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 ?", SYSTEM_FACTORY_TEXT_DIALOG: "Êtes-vous sûr de vouloir réinitialiser l'appareil à ses paramètres d'usine ?",
STABLE: 'Stable', // TODO translate STABLE: 'Stable', // TODO translate
DEVELOPMENT: 'Développement', DEVELOPMENT: 'Développement',
RELEASE_NOTES: 'notes de version',
EMS_ESP_VER: 'Firmware Version', // TODO translate EMS_ESP_VER: 'Firmware Version', // TODO translate
UPTIME: 'Durée de fonctionnement du système', UPTIME: 'Durée de fonctionnement du système',
FREE_MEMORY: 'Libre Memory', FREE_MEMORY: 'Libre Memory',
@@ -343,7 +342,8 @@ const fr: Translation = {
AUTO_SCROLL: 'Auto Scroll', // TODO translate AUTO_SCROLL: 'Auto Scroll', // TODO translate
DASHBOARD: 'Dashboard', // TODO translate DASHBOARD: 'Dashboard', // TODO translate
NO_DATA: 'No data available', // 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; export default fr;

View File

@@ -115,7 +115,7 @@ const it: Translation = {
READONLY: 'Abilita modalità sola-lettura (blocca tutti i comandi di scrittura EMS Tx in uscita)', READONLY: 'Abilita modalità sola-lettura (blocca tutti i comandi di scrittura EMS Tx in uscita)',
UNDERCLOCK_CPU: 'Abbassa velocità della CPU', UNDERCLOCK_CPU: 'Abbassa velocità della CPU',
REMOTE_TIMEOUT: 'Remote timeout', 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', HEATINGOFF: 'Avviamento caldaia con riscaldamento forzato spento',
MIN_DURATION: 'Wait time', MIN_DURATION: 'Wait time',
ENABLE_SHOWER_TIMER: 'Abilita timer doccia', 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??', SYSTEM_FACTORY_TEXT_DIALOG: 'Sei sicuro di voler ripristinare il dispositivo alle impostazioni di fabbrica??',
STABLE: 'Stable', // TODO translate STABLE: 'Stable', // TODO translate
DEVELOPMENT: 'Sviluppo', DEVELOPMENT: 'Sviluppo',
RELEASE_NOTES: 'note rilascio',
EMS_ESP_VER: 'Versione Firmware', EMS_ESP_VER: 'Versione Firmware',
UPTIME: 'Tempo di attività del sistema', UPTIME: 'Tempo di attività del sistema',
FREE_MEMORY: 'Free Memory', FREE_MEMORY: 'Free Memory',
@@ -343,7 +342,8 @@ const it: Translation = {
AUTO_SCROLL: 'Auto Scroll', // TODO translate AUTO_SCROLL: 'Auto Scroll', // TODO translate
DASHBOARD: 'Dashboard', // TODO translate DASHBOARD: 'Dashboard', // TODO translate
NO_DATA: 'No data available', // 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; export default it;

View File

@@ -115,7 +115,7 @@ const nl: Translation = {
READONLY: 'Activeer read-only modus (blokkeert alle outgaande EMS Tx schrijf commandos)', READONLY: 'Activeer read-only modus (blokkeert alle outgaande EMS Tx schrijf commandos)',
UNDERCLOCK_CPU: 'Underclock CPU snelheid', UNDERCLOCK_CPU: 'Underclock CPU snelheid',
REMOTE_TIMEOUT: 'Remote timeout', 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', HEATINGOFF: 'Start ketel met geforceerde verwarming uit',
MIN_DURATION: 'Wait time', MIN_DURATION: 'Wait time',
ENABLE_SHOWER_TIMER: 'Activeer Douche Timer (tijdmeting)', 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?', SYSTEM_FACTORY_TEXT_DIALOG: 'Weet je zeker dat je een reset naar fabrieksinstellingen uit wilt voeren?',
STABLE: 'Stable', STABLE: 'Stable',
DEVELOPMENT: 'Development', DEVELOPMENT: 'Development',
RELEASE_NOTES: 'release notes',
EMS_ESP_VER: 'Firmware Versie', EMS_ESP_VER: 'Firmware Versie',
UPTIME: 'Systeem Uptime', UPTIME: 'Systeem Uptime',
FREE_MEMORY: 'Free Memory', FREE_MEMORY: 'Free Memory',
@@ -343,7 +342,8 @@ const nl: Translation = {
AUTO_SCROLL: 'Auto Scroll', // TODO translate AUTO_SCROLL: 'Auto Scroll', // TODO translate
DASHBOARD: 'Dashboard', // TODO translate DASHBOARD: 'Dashboard', // TODO translate
NO_DATA: 'No data available', // 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; export default nl;

View File

@@ -115,7 +115,7 @@ const no: Translation = {
READONLY: 'Aktiver read-only modus (blokker all EMS Tx Skriving)', READONLY: 'Aktiver read-only modus (blokker all EMS Tx Skriving)',
UNDERCLOCK_CPU: 'Underklokking av prosessorhastighet', UNDERCLOCK_CPU: 'Underklokking av prosessorhastighet',
REMOTE_TIMEOUT: 'Remote timeout', 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 HEATINGOFF: 'Start boiler with forced heating off', // TODO translate
MIN_DURATION: 'Wait time', MIN_DURATION: 'Wait time',
ENABLE_SHOWER_TIMER: 'Aktiver Dusjtimer', 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?', SYSTEM_FACTORY_TEXT_DIALOG: 'Er du sikker på at du vil resette enheten til fabrikkinstillinger?',
STABLE: 'Stable', // TODO translate STABLE: 'Stable', // TODO translate
DEVELOPMENT: 'Development', DEVELOPMENT: 'Development',
RELEASE_NOTES: 'release notes',
EMS_ESP_VER: 'Firmware Version', // TODO translate EMS_ESP_VER: 'Firmware Version', // TODO translate
UPTIME: 'System Oppetid', UPTIME: 'System Oppetid',
FREE_MEMORY: 'Ledig Memory', FREE_MEMORY: 'Ledig Memory',
@@ -343,7 +342,8 @@ const no: Translation = {
AUTO_SCROLL: 'Auto Scroll', // TODO translate AUTO_SCROLL: 'Auto Scroll', // TODO translate
DASHBOARD: 'Dashboard', // TODO translate DASHBOARD: 'Dashboard', // TODO translate
NO_DATA: 'No data available', // 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; export default no;

View File

@@ -115,7 +115,7 @@ const pl: BaseTranslation = {
READONLY: 'Tryb pracy "tylko do odczytu" (blokuje wszystkie komendy zapisu na magistralę EMS)', READONLY: 'Tryb pracy "tylko do odczytu" (blokuje wszystkie komendy zapisu na magistralę EMS)',
UNDERCLOCK_CPU: 'Obniż taktowanie CPU', UNDERCLOCK_CPU: 'Obniż taktowanie CPU',
REMOTE_TIMEOUT: 'Remote timeout', 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', HEATINGOFF: 'Uruchom kocioł z wymuszonym wyłączonym grzaniem',
MIN_DURATION: 'Wait time', MIN_DURATION: 'Wait time',
ENABLE_SHOWER_TIMER: 'Aktywuj minutnik prysznica', 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? ', SYSTEM_FACTORY_TEXT_DIALOG: 'Na pewno chcesz przywrócić ustawienia fabryczne interfejsu EMS-ESP? ',
STABLE: 'Stable', // TODO translate STABLE: 'Stable', // TODO translate
DEVELOPMENT: 'Testowe', DEVELOPMENT: 'Testowe',
RELEASE_NOTES: 'lista zmian',
EMS_ESP_VER: 'Wersja Firmware', EMS_ESP_VER: 'Wersja Firmware',
UPTIME: 'Czas działania systemu', UPTIME: 'Czas działania systemu',
FREE_MEMORY: 'Wolne Memory', // TODO translate FREE_MEMORY: 'Wolne Memory', // TODO translate
@@ -343,7 +342,8 @@ const pl: BaseTranslation = {
AUTO_SCROLL: 'Auto Scroll', // TODO translate AUTO_SCROLL: 'Auto Scroll', // TODO translate
DASHBOARD: 'Dashboard', // TODO translate DASHBOARD: 'Dashboard', // TODO translate
NO_DATA: 'No data available', // 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; export default pl;

View File

@@ -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)', READONLY: 'Povoliť režim len na čítanie (blokuje všetky odchádzajúce príkazy EMS Tx Write)',
UNDERCLOCK_CPU: 'Podtaktovanie rýchlosti procesora', UNDERCLOCK_CPU: 'Podtaktovanie rýchlosti procesora',
REMOTE_TIMEOUT: 'Remote timeout', 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', HEATINGOFF: 'Spustiť kotol s vynúteným vykurovaním',
MIN_DURATION: 'Wait time', MIN_DURATION: 'Wait time',
ENABLE_SHOWER_TIMER: 'Povoliť časovač sprchovania', 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?', SYSTEM_FACTORY_TEXT_DIALOG: 'Naozaj chcete resetovať EMS-ESP na predvolené výrobné nastavenia?',
STABLE: 'Stabilná', STABLE: 'Stabilná',
DEVELOPMENT: 'Vývojárska', DEVELOPMENT: 'Vývojárska',
RELEASE_NOTES: 'poznámky k verzii',
EMS_ESP_VER: 'Firmware verzia', EMS_ESP_VER: 'Firmware verzia',
UPTIME: 'Beh systému', UPTIME: 'Beh systému',
FREE_MEMORY: 'Voľné Memory', FREE_MEMORY: 'Voľné Memory',
@@ -343,7 +342,8 @@ const sk: Translation = {
AUTO_SCROLL: 'Automatické rolovanie', AUTO_SCROLL: 'Automatické rolovanie',
DASHBOARD: 'Panel', DASHBOARD: 'Panel',
NO_DATA: 'Nie sú k dispozícii žiadne údaje', 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; export default sk;

View File

@@ -115,7 +115,7 @@ const sv: Translation = {
READONLY: 'Aktivera read-only (blockerar alla utgående skrivkommandon mot EMS-bussen)', READONLY: 'Aktivera read-only (blockerar alla utgående skrivkommandon mot EMS-bussen)',
UNDERCLOCK_CPU: 'Nedklocka Processorhastighet', UNDERCLOCK_CPU: 'Nedklocka Processorhastighet',
REMOTE_TIMEOUT: 'Remote timeout', 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 HEATINGOFF: 'Start boiler with forced heating off', // TODO translate
MIN_DURATION: 'Wait time', MIN_DURATION: 'Wait time',
ENABLE_SHOWER_TIMER: 'Aktivera Dusch-timer', 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?', SYSTEM_FACTORY_TEXT_DIALOG: 'Är du säker att du vill fabriksåterställa enheten?',
STABLE: 'Stable', // TODO translate STABLE: 'Stable', // TODO translate
DEVELOPMENT: 'Utveckling', DEVELOPMENT: 'Utveckling',
RELEASE_NOTES: 'release-logg',
EMS_ESP_VER: 'Firmware Version', // TODO translate EMS_ESP_VER: 'Firmware Version', // TODO translate
UPTIME: 'Systemets Upptid', UPTIME: 'Systemets Upptid',
FREE_MEMORY: 'Ledigt Memory', FREE_MEMORY: 'Ledigt Memory',
@@ -343,7 +342,8 @@ const sv: Translation = {
AUTO_SCROLL: 'Auto Scroll', // TODO translate AUTO_SCROLL: 'Auto Scroll', // TODO translate
DASHBOARD: 'Dashboard', // TODO translate DASHBOARD: 'Dashboard', // TODO translate
NO_DATA: 'No data available', // 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; export default sv;

View File

@@ -115,7 +115,7 @@ const tr: Translation = {
READONLY: 'Salt okunur modu devreye al (bütün giden EMS Tx Yazma komutlarını engeller)', READONLY: 'Salt okunur modu devreye al (bütün giden EMS Tx Yazma komutlarını engeller)',
UNDERCLOCK_CPU: 'İşlemci hızını düşür', UNDERCLOCK_CPU: 'İşlemci hızını düşür',
REMOTE_TIMEOUT: 'Remote timeout', 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 HEATINGOFF: 'Start boiler with forced heating off', // TODO translate
MIN_DURATION: 'Wait time', MIN_DURATION: 'Wait time',
ENABLE_SHOWER_TIMER: 'Duş Sayacını Devreye Al', 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?', SYSTEM_FACTORY_TEXT_DIALOG: 'Cihazı fabrika ayarlarına döndürmek istediğinize emin misiniz?',
STABLE: 'Stable', // TODO translate STABLE: 'Stable', // TODO translate
DEVELOPMENT: 'Geliştirme', DEVELOPMENT: 'Geliştirme',
RELEASE_NOTES: 'yayınlanma notları',
EMS_ESP_VER: 'Firmware Sürümü', EMS_ESP_VER: 'Firmware Sürümü',
UPTIME: 'Sistem Çalışma Süresi', UPTIME: 'Sistem Çalışma Süresi',
FREE_MEMORY: 'Yığın Memory', FREE_MEMORY: 'Yığın Memory',
@@ -343,7 +342,8 @@ const tr: Translation = {
AUTO_SCROLL: 'Auto Scroll', // TODO translate AUTO_SCROLL: 'Auto Scroll', // TODO translate
DASHBOARD: 'Dashboard', // TODO translate DASHBOARD: 'Dashboard', // TODO translate
NO_DATA: 'No data available', // 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; export default tr;

View File

@@ -67,4 +67,5 @@ export interface LogSettings {
max_messages: number; max_messages: number;
compact: boolean; compact: boolean;
psram: boolean; psram: boolean;
developer_mode: boolean;
} }

View File

@@ -1076,38 +1076,38 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@mui/core-downloads-tracker@npm:^6.1.4": "@mui/core-downloads-tracker@npm:^6.1.5":
version: 6.1.4 version: 6.1.5
resolution: "@mui/core-downloads-tracker@npm:6.1.4" resolution: "@mui/core-downloads-tracker@npm:6.1.5"
checksum: 10c0/bfd84a726c883dd681b2cda13b977eb6646c1da66ea59905dbe7b857ec4ac86576a318eb116d54633e7c479aecb52fe0c75fb957f1b6081a6c8857dd5ce4c5b9 checksum: 10c0/c8767b7a8046e669ea687108dd2c62352e48c61379657a1b88798c12ec47cc3f99eedf30758294a17a81f2dcef22aeb08f992aecdf6e0876f312d345ba1d5f3d
languageName: node languageName: node
linkType: hard linkType: hard
"@mui/icons-material@npm:^6.1.4": "@mui/icons-material@npm:^6.1.5":
version: 6.1.4 version: 6.1.5
resolution: "@mui/icons-material@npm:6.1.4" resolution: "@mui/icons-material@npm:6.1.5"
dependencies: dependencies:
"@babel/runtime": "npm:^7.25.7" "@babel/runtime": "npm:^7.25.7"
peerDependencies: peerDependencies:
"@mui/material": ^6.1.4 "@mui/material": ^6.1.5
"@types/react": ^17.0.0 || ^18.0.0 || ^19.0.0 "@types/react": ^17.0.0 || ^18.0.0 || ^19.0.0
react: ^17.0.0 || ^18.0.0 || ^19.0.0 react: ^17.0.0 || ^18.0.0 || ^19.0.0
peerDependenciesMeta: peerDependenciesMeta:
"@types/react": "@types/react":
optional: true optional: true
checksum: 10c0/8e4e8a20c7183fae76f1e013669212404696e9e146aa413afbc705ee56f0a32cfef6143a16f9ec24aeb1e8dfb567d50f9b04b9bdf381ad8bd7a2c9b09d25186c checksum: 10c0/112f7570b8d27019a16b619a3a5b9f01cb7d8a244d50014596e17f06ed5f569888aeac2223c058da37567b5a358c99a53ee2afdf8958bc4a34b964a02f796787
languageName: node languageName: node
linkType: hard linkType: hard
"@mui/material@npm:^6.1.4": "@mui/material@npm:^6.1.5":
version: 6.1.4 version: 6.1.5
resolution: "@mui/material@npm:6.1.4" resolution: "@mui/material@npm:6.1.5"
dependencies: dependencies:
"@babel/runtime": "npm:^7.25.7" "@babel/runtime": "npm:^7.25.7"
"@mui/core-downloads-tracker": "npm:^6.1.4" "@mui/core-downloads-tracker": "npm:^6.1.5"
"@mui/system": "npm:^6.1.4" "@mui/system": "npm:^6.1.5"
"@mui/types": "npm:^7.2.18" "@mui/types": "npm:^7.2.18"
"@mui/utils": "npm:^6.1.4" "@mui/utils": "npm:^6.1.5"
"@popperjs/core": "npm:^2.11.8" "@popperjs/core": "npm:^2.11.8"
"@types/react-transition-group": "npm:^4.4.11" "@types/react-transition-group": "npm:^4.4.11"
clsx: "npm:^2.1.1" clsx: "npm:^2.1.1"
@@ -1118,7 +1118,7 @@ __metadata:
peerDependencies: peerDependencies:
"@emotion/react": ^11.5.0 "@emotion/react": ^11.5.0
"@emotion/styled": ^11.3.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 "@types/react": ^17.0.0 || ^18.0.0 || ^19.0.0
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 react-dom: ^17.0.0 || ^18.0.0 || ^19.0.0
@@ -1131,16 +1131,16 @@ __metadata:
optional: true optional: true
"@types/react": "@types/react":
optional: true optional: true
checksum: 10c0/3729e56129b27706ebfab67428035dc7f0136dfd745281b467c7da07e78248cc8e2f36939cd6c33967fd565c5b5eff336629e3f7a2d877e9b176d24df67c9c81 checksum: 10c0/982a2446fd511a952627aa8567e302528ad3a2ad8b3125574a38facaef2a5a076a723c67076682f95b09f9fe4dbf3445213fe6655658d23419b49440ae11873e
languageName: node languageName: node
linkType: hard linkType: hard
"@mui/private-theming@npm:^6.1.4": "@mui/private-theming@npm:^6.1.5":
version: 6.1.4 version: 6.1.5
resolution: "@mui/private-theming@npm:6.1.4" resolution: "@mui/private-theming@npm:6.1.5"
dependencies: dependencies:
"@babel/runtime": "npm:^7.25.7" "@babel/runtime": "npm:^7.25.7"
"@mui/utils": "npm:^6.1.4" "@mui/utils": "npm:^6.1.5"
prop-types: "npm:^15.8.1" prop-types: "npm:^15.8.1"
peerDependencies: peerDependencies:
"@types/react": ^17.0.0 || ^18.0.0 || ^19.0.0 "@types/react": ^17.0.0 || ^18.0.0 || ^19.0.0
@@ -1148,13 +1148,13 @@ __metadata:
peerDependenciesMeta: peerDependenciesMeta:
"@types/react": "@types/react":
optional: true optional: true
checksum: 10c0/37c81ca4529afbec2a4710d4dfa1597a5f9a33ff3ae775fa68474f86b223ed4ab953526e49883d77638ad62f0c944716c2b0dc58a105624ca91fe60a633e3b4a checksum: 10c0/3a5a470c78daa60fa3c9346a15617ab4d6ad3c544b564fe4b2fe6f3155cb4955b0c670395a9074e91956b1cb50bca96fc07d03cad92759147bebadcacd00f36c
languageName: node languageName: node
linkType: hard linkType: hard
"@mui/styled-engine@npm:^6.1.4": "@mui/styled-engine@npm:^6.1.5":
version: 6.1.4 version: 6.1.5
resolution: "@mui/styled-engine@npm:6.1.4" resolution: "@mui/styled-engine@npm:6.1.5"
dependencies: dependencies:
"@babel/runtime": "npm:^7.25.7" "@babel/runtime": "npm:^7.25.7"
"@emotion/cache": "npm:^11.13.1" "@emotion/cache": "npm:^11.13.1"
@@ -1171,19 +1171,19 @@ __metadata:
optional: true optional: true
"@emotion/styled": "@emotion/styled":
optional: true optional: true
checksum: 10c0/ce8f53a704aa607152ef5ef25d95bdd5c4399f7dbf240acd6e4057c24d84536bb3c884fcb13c5e88d87dbfff42935c82af2e63800ba033ad481847b1967ccf52 checksum: 10c0/7a4830a7f1736d399c06d414cd6762ff4a830e976946da4a58b77e864b6d6abb4385800e644367e57c670397bf1f12690e82ffe05f185c85c8dafd132a67ca2a
languageName: node languageName: node
linkType: hard linkType: hard
"@mui/system@npm:^6.1.4": "@mui/system@npm:^6.1.5":
version: 6.1.4 version: 6.1.5
resolution: "@mui/system@npm:6.1.4" resolution: "@mui/system@npm:6.1.5"
dependencies: dependencies:
"@babel/runtime": "npm:^7.25.7" "@babel/runtime": "npm:^7.25.7"
"@mui/private-theming": "npm:^6.1.4" "@mui/private-theming": "npm:^6.1.5"
"@mui/styled-engine": "npm:^6.1.4" "@mui/styled-engine": "npm:^6.1.5"
"@mui/types": "npm:^7.2.18" "@mui/types": "npm:^7.2.18"
"@mui/utils": "npm:^6.1.4" "@mui/utils": "npm:^6.1.5"
clsx: "npm:^2.1.1" clsx: "npm:^2.1.1"
csstype: "npm:^3.1.3" csstype: "npm:^3.1.3"
prop-types: "npm:^15.8.1" prop-types: "npm:^15.8.1"
@@ -1199,7 +1199,7 @@ __metadata:
optional: true optional: true
"@types/react": "@types/react":
optional: true optional: true
checksum: 10c0/766f1c695254df54b06de1af231cdf30752f71a79181edd4c24044405144b7a72c4c23248155f4041999993aa4f568878eccd130c100b4b332e7dd6b322dfd75 checksum: 10c0/7e8ce81b7e6a5810c0856427dbd7f89f62a23ab151e0199813e7cd7e9d47e4719004f6b576c5cad0121735cfb0c984ea022c494796202e2c0c054c6a60995c40
languageName: node languageName: node
linkType: hard linkType: hard
@@ -1215,9 +1215,9 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@mui/utils@npm:^6.1.4": "@mui/utils@npm:^6.1.5":
version: 6.1.4 version: 6.1.5
resolution: "@mui/utils@npm:6.1.4" resolution: "@mui/utils@npm:6.1.5"
dependencies: dependencies:
"@babel/runtime": "npm:^7.25.7" "@babel/runtime": "npm:^7.25.7"
"@mui/types": "npm:^7.2.18" "@mui/types": "npm:^7.2.18"
@@ -1231,7 +1231,7 @@ __metadata:
peerDependenciesMeta: peerDependenciesMeta:
"@types/react": "@types/react":
optional: true optional: true
checksum: 10c0/cac4f05904897c28444e7ef2a6891678d36c0a8fae921ccacebcd7b53da99e4c6cab05669328fdabff624313de68f1b5bcd427cba36024b6c3505b5ee945eb05 checksum: 10c0/899191334f321aedf993e6a79cd63ac511e8ef23a84c1e156ca4a82c407e97f86f9f3d4250765f5c9e71d9af963bdc738e6d63fc62f9088fc5ad9c055fc3b111
languageName: node languageName: node
linkType: hard linkType: hard
@@ -1685,12 +1685,12 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@types/node@npm:^22.7.7": "@types/node@npm:^22.7.8":
version: 22.7.7 version: 22.7.8
resolution: "@types/node@npm:22.7.7" resolution: "@types/node@npm:22.7.8"
dependencies: dependencies:
undici-types: "npm:~6.19.2" undici-types: "npm:~6.19.2"
checksum: 10c0/07268a1e990ad9d9b1865092881317ea679a46eb6706d83a8874eec75fdddae6cfd6452e4e68b651561183e2a8f8548276f3155744bc402c2545978c19b70d65 checksum: 10c0/3d3b3a2ec5a57ca4fd37b34dce415620993ca5f87cea2c728ffe73aa31446dbfe19c53171c478447bd7d78011ef4845a46ab2f0dc38e699cc75b3d100a60c690
languageName: node languageName: node
linkType: hard linkType: hard
@@ -1785,15 +1785,15 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@typescript-eslint/eslint-plugin@npm:8.10.0": "@typescript-eslint/eslint-plugin@npm:8.11.0":
version: 8.10.0 version: 8.11.0
resolution: "@typescript-eslint/eslint-plugin@npm:8.10.0" resolution: "@typescript-eslint/eslint-plugin@npm:8.11.0"
dependencies: dependencies:
"@eslint-community/regexpp": "npm:^4.10.0" "@eslint-community/regexpp": "npm:^4.10.0"
"@typescript-eslint/scope-manager": "npm:8.10.0" "@typescript-eslint/scope-manager": "npm:8.11.0"
"@typescript-eslint/type-utils": "npm:8.10.0" "@typescript-eslint/type-utils": "npm:8.11.0"
"@typescript-eslint/utils": "npm:8.10.0" "@typescript-eslint/utils": "npm:8.11.0"
"@typescript-eslint/visitor-keys": "npm:8.10.0" "@typescript-eslint/visitor-keys": "npm:8.11.0"
graphemer: "npm:^1.4.0" graphemer: "npm:^1.4.0"
ignore: "npm:^5.3.1" ignore: "npm:^5.3.1"
natural-compare: "npm:^1.4.0" natural-compare: "npm:^1.4.0"
@@ -1804,66 +1804,66 @@ __metadata:
peerDependenciesMeta: peerDependenciesMeta:
typescript: typescript:
optional: true optional: true
checksum: 10c0/4b77ba9c865a2a14e238cd330b5901f0274b8ce1c13324fccd0339b8eea82a50a4709394c903fd8cd5bd0d3aebace0761ff9a4a19fa20b00bb61349b7671c035 checksum: 10c0/be509f7bb0c0c596801059b06995a81a1c326cc6ac31d96a32f7b6b7d7b495f9bad4dc442aa6e923d22515e62c668d3c14695c68bd6e0be1d4bf72158b7fd2d6
languageName: node languageName: node
linkType: hard linkType: hard
"@typescript-eslint/parser@npm:8.10.0": "@typescript-eslint/parser@npm:8.11.0":
version: 8.10.0 version: 8.11.0
resolution: "@typescript-eslint/parser@npm:8.10.0" resolution: "@typescript-eslint/parser@npm:8.11.0"
dependencies: dependencies:
"@typescript-eslint/scope-manager": "npm:8.10.0" "@typescript-eslint/scope-manager": "npm:8.11.0"
"@typescript-eslint/types": "npm:8.10.0" "@typescript-eslint/types": "npm:8.11.0"
"@typescript-eslint/typescript-estree": "npm:8.10.0" "@typescript-eslint/typescript-estree": "npm:8.11.0"
"@typescript-eslint/visitor-keys": "npm:8.10.0" "@typescript-eslint/visitor-keys": "npm:8.11.0"
debug: "npm:^4.3.4" debug: "npm:^4.3.4"
peerDependencies: peerDependencies:
eslint: ^8.57.0 || ^9.0.0 eslint: ^8.57.0 || ^9.0.0
peerDependenciesMeta: peerDependenciesMeta:
typescript: typescript:
optional: true optional: true
checksum: 10c0/7becb2457c085c239838d301796074b790f46dd38c9fbc14ec1dec8e993c7115cd8a66cdc07983c3a68a2dd92e24e8acc49d69a4ebcc29e9869957eb52d1cb74 checksum: 10c0/e83f239fec60697083e5dcb1c8948340e783ea6e043fe9a65d557faef8882963b09d69aacd736eb8ab18a768769a7bbfc3de0f1251d4bba080613541acb0741c
languageName: node languageName: node
linkType: hard linkType: hard
"@typescript-eslint/scope-manager@npm:8.10.0": "@typescript-eslint/scope-manager@npm:8.11.0":
version: 8.10.0 version: 8.11.0
resolution: "@typescript-eslint/scope-manager@npm:8.10.0" resolution: "@typescript-eslint/scope-manager@npm:8.11.0"
dependencies: dependencies:
"@typescript-eslint/types": "npm:8.10.0" "@typescript-eslint/types": "npm:8.11.0"
"@typescript-eslint/visitor-keys": "npm:8.10.0" "@typescript-eslint/visitor-keys": "npm:8.11.0"
checksum: 10c0/b8bb8635c4d6c00a3578d6265e3ee0f5d96d0c9dee534ed588aa411c3f4497fd71cce730c3ae7571e52453d955b191bc9edcc47c9af21a20c90e9a20f2371108 checksum: 10c0/0910da62d8ae261711dd9f89d5c7d8e96ff13c50054436256e5a661309229cb49e3b8189c9468d36b6c4d3f7cddd121519ea78f9b18c9b869a808834b079b2ea
languageName: node languageName: node
linkType: hard linkType: hard
"@typescript-eslint/type-utils@npm:8.10.0": "@typescript-eslint/type-utils@npm:8.11.0":
version: 8.10.0 version: 8.11.0
resolution: "@typescript-eslint/type-utils@npm:8.10.0" resolution: "@typescript-eslint/type-utils@npm:8.11.0"
dependencies: dependencies:
"@typescript-eslint/typescript-estree": "npm:8.10.0" "@typescript-eslint/typescript-estree": "npm:8.11.0"
"@typescript-eslint/utils": "npm:8.10.0" "@typescript-eslint/utils": "npm:8.11.0"
debug: "npm:^4.3.4" debug: "npm:^4.3.4"
ts-api-utils: "npm:^1.3.0" ts-api-utils: "npm:^1.3.0"
peerDependenciesMeta: peerDependenciesMeta:
typescript: typescript:
optional: true optional: true
checksum: 10c0/1af8fce8394279e6ac7bcef449a132072ee36e374c8d557564246ffe7150230844901ca0305e29525bf37c87010e03bf8bedec76fccbfe1e41931cb4f274e208 checksum: 10c0/b69e31c1599ceeb20c29052a4ddb33a554174a3a4c55ee37d90c9b8250af6ef978a0b9ddbeefef4e83d62c4caea1bfa2d8088527f397bde69fb4ab9b360d794a
languageName: node languageName: node
linkType: hard linkType: hard
"@typescript-eslint/types@npm:8.10.0": "@typescript-eslint/types@npm:8.11.0":
version: 8.10.0 version: 8.11.0
resolution: "@typescript-eslint/types@npm:8.10.0" resolution: "@typescript-eslint/types@npm:8.11.0"
checksum: 10c0/f27dd43c8383e02e914a254257627e393dfc0f08b0f74a253c106813ae361f090271b2f3f2ef588fa3ca1329897d873da595bb5641fe8e3091b25eddca24b5d2 checksum: 10c0/5ccdd3eeee077a6fc8e7f4bc0e0cbc9327b1205a845253ec5c0c6c49ff915e853161df00c24a0ffb4b8ec745d3f153dd0e066400a021c844c026e31121f46699
languageName: node languageName: node
linkType: hard linkType: hard
"@typescript-eslint/typescript-estree@npm:8.10.0": "@typescript-eslint/typescript-estree@npm:8.11.0":
version: 8.10.0 version: 8.11.0
resolution: "@typescript-eslint/typescript-estree@npm:8.10.0" resolution: "@typescript-eslint/typescript-estree@npm:8.11.0"
dependencies: dependencies:
"@typescript-eslint/types": "npm:8.10.0" "@typescript-eslint/types": "npm:8.11.0"
"@typescript-eslint/visitor-keys": "npm:8.10.0" "@typescript-eslint/visitor-keys": "npm:8.11.0"
debug: "npm:^4.3.4" debug: "npm:^4.3.4"
fast-glob: "npm:^3.3.2" fast-glob: "npm:^3.3.2"
is-glob: "npm:^4.0.3" is-glob: "npm:^4.0.3"
@@ -1873,31 +1873,31 @@ __metadata:
peerDependenciesMeta: peerDependenciesMeta:
typescript: typescript:
optional: true optional: true
checksum: 10c0/535a740fe25be0e28fe68c41e3264273d1e5169c9f938e08cc0e3415c357726f43efa44621960108c318fc3305c425d29f3223b6e731d44d67f84058a8947304 checksum: 10c0/b629ad3cd32b005d5c1d67c36958a418f8672efebea869399834f4f201ebf90b942165eebb5c9d9799dcabdc2cc26e5fabb00629f76b158847f42e1a491a75a6
languageName: node languageName: node
linkType: hard linkType: hard
"@typescript-eslint/utils@npm:8.10.0": "@typescript-eslint/utils@npm:8.11.0":
version: 8.10.0 version: 8.11.0
resolution: "@typescript-eslint/utils@npm:8.10.0" resolution: "@typescript-eslint/utils@npm:8.11.0"
dependencies: dependencies:
"@eslint-community/eslint-utils": "npm:^4.4.0" "@eslint-community/eslint-utils": "npm:^4.4.0"
"@typescript-eslint/scope-manager": "npm:8.10.0" "@typescript-eslint/scope-manager": "npm:8.11.0"
"@typescript-eslint/types": "npm:8.10.0" "@typescript-eslint/types": "npm:8.11.0"
"@typescript-eslint/typescript-estree": "npm:8.10.0" "@typescript-eslint/typescript-estree": "npm:8.11.0"
peerDependencies: peerDependencies:
eslint: ^8.57.0 || ^9.0.0 eslint: ^8.57.0 || ^9.0.0
checksum: 10c0/a21a2933517176abd00fcd5d8d80023e35dc3d89d5746bbac43790b4e984ab1f371117db08048bce7f42d54c64f4e0e35161149f8f34fd25a27bff9d1110fd16 checksum: 10c0/bb5bcc8d928a55b22298e76f834ea6a9fe125a9ffeb6ac23bee0258b3ed32f41e281888a3d0be226a05e1011bb3b70e42a71a40366acdefea6779131c46bc522
languageName: node languageName: node
linkType: hard linkType: hard
"@typescript-eslint/visitor-keys@npm:8.10.0": "@typescript-eslint/visitor-keys@npm:8.11.0":
version: 8.10.0 version: 8.11.0
resolution: "@typescript-eslint/visitor-keys@npm:8.10.0" resolution: "@typescript-eslint/visitor-keys@npm:8.11.0"
dependencies: dependencies:
"@typescript-eslint/types": "npm:8.10.0" "@typescript-eslint/types": "npm:8.11.0"
eslint-visitor-keys: "npm:^3.4.3" eslint-visitor-keys: "npm:^3.4.3"
checksum: 10c0/14721c4ac939640d5fd1ee1b6eeb07604b11a6017e319e21dcc71e7aac2992341fc7ae1992d977bad4433b6a1d0d1c0c279e6927316b26245f6e333f922fa458 checksum: 10c0/7a5a49609fdc47e114fe59eee56393c90b122ec8e9520f90b0c5e189635ae1ccfa8e00108f641342c2c8f4637fe9d40c77927cf7c8248a3a660812cb4b7d0c08
languageName: node languageName: node
linkType: hard linkType: hard
@@ -1910,14 +1910,14 @@ __metadata:
"@emotion/react": "npm:^11.13.3" "@emotion/react": "npm:^11.13.3"
"@emotion/styled": "npm:^11.13.0" "@emotion/styled": "npm:^11.13.0"
"@eslint/js": "npm:^9.13.0" "@eslint/js": "npm:^9.13.0"
"@mui/icons-material": "npm:^6.1.4" "@mui/icons-material": "npm:^6.1.5"
"@mui/material": "npm:^6.1.4" "@mui/material": "npm:^6.1.5"
"@preact/compat": "npm:^18.3.1" "@preact/compat": "npm:^18.3.1"
"@preact/preset-vite": "npm:^2.9.1" "@preact/preset-vite": "npm:^2.9.1"
"@table-library/react-table-library": "npm:4.1.7" "@table-library/react-table-library": "npm:4.1.7"
"@trivago/prettier-plugin-sort-imports": "npm:^4.3.0" "@trivago/prettier-plugin-sort-imports": "npm:^4.3.0"
"@types/formidable": "npm:^3" "@types/formidable": "npm:^3"
"@types/node": "npm:^22.7.7" "@types/node": "npm:^22.7.8"
"@types/react": "npm:^18.3.11" "@types/react": "npm:^18.3.11"
"@types/react-dom": "npm:^18.3.1" "@types/react-dom": "npm:^18.3.1"
"@types/react-router-dom": "npm:^5.3.3" "@types/react-router-dom": "npm:^5.3.3"
@@ -1940,7 +1940,7 @@ __metadata:
terser: "npm:^5.36.0" terser: "npm:^5.36.0"
typesafe-i18n: "npm:^5.26.2" typesafe-i18n: "npm:^5.26.2"
typescript: "npm:^5.6.3" typescript: "npm:^5.6.3"
typescript-eslint: "npm:8.10.0" typescript-eslint: "npm:8.11.0"
vite: "npm:^5.4.9" vite: "npm:^5.4.9"
vite-plugin-imagemin: "npm:^0.6.1" vite-plugin-imagemin: "npm:^0.6.1"
vite-tsconfig-paths: "npm:^5.0.1" vite-tsconfig-paths: "npm:^5.0.1"
@@ -7042,17 +7042,17 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"typescript-eslint@npm:8.10.0": "typescript-eslint@npm:8.11.0":
version: 8.10.0 version: 8.11.0
resolution: "typescript-eslint@npm:8.10.0" resolution: "typescript-eslint@npm:8.11.0"
dependencies: dependencies:
"@typescript-eslint/eslint-plugin": "npm:8.10.0" "@typescript-eslint/eslint-plugin": "npm:8.11.0"
"@typescript-eslint/parser": "npm:8.10.0" "@typescript-eslint/parser": "npm:8.11.0"
"@typescript-eslint/utils": "npm:8.10.0" "@typescript-eslint/utils": "npm:8.11.0"
peerDependenciesMeta: peerDependenciesMeta:
typescript: typescript:
optional: true optional: true
checksum: 10c0/9eca1bfdea4e108bea06f0053b57f8a9eaeb43bf3316a39c6d29631bd3217ec67611e46d361417c48a5f6eeb99c4a7fc81c020734b1b47d7b8e42fa67d74ea0f checksum: 10c0/8f9b5916c9f47b0cbb26f142d1a266a6aaf33998ec87621252dffb56d8fe0ad01a944f8d8d837e4e6058153a1deee3557527d14fa7bf7ef80a927334529db6bd
languageName: node languageName: node
linkType: hard linkType: hard

View File

@@ -253,7 +253,7 @@ StateUpdateResult MqttSettings::update(JsonObject root, MqttSettings & settings)
bool changed = false; bool changed = false;
#ifndef TASMOTA_SDK #ifndef TASMOTA_SDK
newSettings.enableTLS = root["enableTLS"] | false; newSettings.enableTLS = root["enableTLS"];
newSettings.rootCA = root["rootCA"] | ""; newSettings.rootCA = root["rootCA"] | "";
#else #else
newSettings.enableTLS = false; newSettings.enableTLS = false;

View File

@@ -424,12 +424,12 @@ StateUpdateResult NetworkSettings::update(JsonObject root, NetworkSettings & set
settings.bssid = root["bssid"] | ""; settings.bssid = root["bssid"] | "";
settings.password = root["password"] | FACTORY_WIFI_PASSWORD; settings.password = root["password"] | FACTORY_WIFI_PASSWORD;
settings.hostname = root["hostname"] | FACTORY_WIFI_HOSTNAME; settings.hostname = root["hostname"] | FACTORY_WIFI_HOSTNAME;
settings.staticIPConfig = root["static_ip_config"] | false; settings.staticIPConfig = root["static_ip_config"];
settings.bandwidth20 = root["bandwidth20"] | false; settings.bandwidth20 = root["bandwidth20"];
settings.tx_power = static_cast<uint8_t>(root["tx_power"] | 0); settings.tx_power = static_cast<uint8_t>(root["tx_power"] | 0);
settings.nosleep = root["nosleep"] | true; settings.nosleep = root["nosleep"] | true;
settings.enableMDNS = root["enableMDNS"] | true; settings.enableMDNS = root["enableMDNS"] | true;
settings.enableCORS = root["enableCORS"] | false; settings.enableCORS = root["enableCORS"];
settings.CORSOrigin = root["CORSOrigin"] | "*"; settings.CORSOrigin = root["CORSOrigin"] | "*";
// extended settings // extended settings

View File

@@ -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" \

View File

@@ -116,7 +116,7 @@ export default () => {
}; };
count++; count++;
res.write(`data: ${JSON.stringify(data)}\n\n`); res.write(`data: ${JSON.stringify(data)}\n\n`);
}, 500); }, 1000);
// if client closes connection // if client closes connection
res.on('close', () => { res.on('close', () => {

View File

@@ -199,21 +199,75 @@ function custom_support() {
function check_upgrade(version: string) { function check_upgrade(version: string) {
console.log('check upgrade from version', version); console.log('check upgrade from version', version);
const data = { const data = {
emsesp_version: VERSION,
upgradeable: true upgradeable: true
// upgradeable: false // upgradeable: false,
}; };
return data; return data;
} }
// START 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 // LOG
const LOG_SETTINGS_ENDPOINT = REST_ENDPOINT_ROOT + 'logSettings'; const LOG_SETTINGS_ENDPOINT = REST_ENDPOINT_ROOT + 'logSettings';
let log_settings = { let log_settings = {
level: 6, level: 6,
max_messages: 50, max_messages: 50,
compact: true, compact: true,
psram: true psram: true,
developer_mode: settings.developer_mode
}; };
// NTP // NTP
@@ -478,9 +532,6 @@ const signin = admin_signin;
const generate_token = { token: '1234' }; const generate_token = { token: '1234' };
//
// EMS-ESP Project specific
//
const EMSESP_SETTINGS_ENDPOINT = REST_ENDPOINT_ROOT + 'settings'; const EMSESP_SETTINGS_ENDPOINT = REST_ENDPOINT_ROOT + 'settings';
const EMSESP_CORE_DATA_ENDPOINT = REST_ENDPOINT_ROOT + 'coreData'; const EMSESP_CORE_DATA_ENDPOINT = REST_ENDPOINT_ROOT + 'coreData';
const EMSESP_SENSOR_DATA_ENDPOINT = REST_ENDPOINT_ROOT + 'sensorData'; 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_DASHBOARD_DATA_ENDPOINT = REST_ENDPOINT_ROOT + 'dashboardData';
const EMSESP_BOARDPROFILE_ENDPOINT = REST_ENDPOINT_ROOT + 'boardProfile'; const EMSESP_BOARDPROFILE_ENDPOINT = REST_ENDPOINT_ROOT + 'boardProfile';
const EMSESP_WRITE_DEVICEVALUE_ENDPOINT = REST_ENDPOINT_ROOT + 'writeDeviceValue'; const EMSESP_WRITE_DEVICEVALUE_ENDPOINT = REST_ENDPOINT_ROOT + 'writeDeviceValue';
const EMSESP_WRITE_DEVICENAME_ENDPOINT = REST_ENDPOINT_ROOT + 'writeDeviceName'; const EMSESP_WRITE_DEVICENAME_ENDPOINT = REST_ENDPOINT_ROOT + 'writeDeviceName';
const EMSESP_WRITE_TEMPSENSOR_ENDPOINT = const EMSESP_WRITE_TEMPSENSOR_ENDPOINT =
@@ -502,10 +554,10 @@ const EMSESP_CUSTOMIZATION_ENTITIES_ENDPOINT =
REST_ENDPOINT_ROOT + 'customizationEntities'; REST_ENDPOINT_ROOT + 'customizationEntities';
const EMSESP_RESET_CUSTOMIZATIONS_ENDPOINT = const EMSESP_RESET_CUSTOMIZATIONS_ENDPOINT =
REST_ENDPOINT_ROOT + 'resetCustomizations'; REST_ENDPOINT_ROOT + 'resetCustomizations';
const EMSESP_SCHEDULE_ENDPOINT = REST_ENDPOINT_ROOT + 'schedule'; const EMSESP_SCHEDULE_ENDPOINT = REST_ENDPOINT_ROOT + 'schedule';
const EMSESP_CUSTOMENTITIES_ENDPOINT = REST_ENDPOINT_ROOT + 'customEntities'; const EMSESP_CUSTOMENTITIES_ENDPOINT = REST_ENDPOINT_ROOT + 'customEntities';
const EMSESP_MODULES_ENDPOINT = REST_ENDPOINT_ROOT + 'modules'; const EMSESP_MODULES_ENDPOINT = REST_ENDPOINT_ROOT + 'modules';
const EMSESP_ACTION_ENDPOINT = REST_ENDPOINT_ROOT + 'action'; const EMSESP_ACTION_ENDPOINT = REST_ENDPOINT_ROOT + 'action';
// these are used in the API calls only // 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 = { const emsesp_info = {
System: { System: {
version: '3.7-demo', version: VERSION,
uptime: '001+06:40:34.018', uptime: '001+06:40:34.018',
'uptime (seconds)': 110434, 'uptime (seconds)': 110434,
freemem: 131, 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 = { const emsesp_coredata = {
connected: true, connected: true,
// connected: false, // connected: false,
@@ -4848,16 +4850,17 @@ router
if (data.device === 'system') { if (data.device === 'system') {
if (cmd === 'info') { if (cmd === 'info') {
return emsesp_info; return emsesp_info;
} } else if (cmd === 'format') {
if (cmd === 'format') {
console.log('formatting...'); console.log('formatting...');
return status(200); return status(200);
} } else if (cmd === 'restart') {
if (cmd === 'restart') {
console.log('restarting...'); console.log('restarting...');
system_status.status = 'restarting'; system_status.status = 'restarting';
countHardwarePoll = 0; countHardwarePoll = 0;
return status(200); return status(200);
} else if (cmd === 'read') {
console.log('send read command:', data.data);
return status(200);
} }
} }
return status(404); // not found return status(404); // not found

View File

@@ -85,8 +85,6 @@ lib_deps =
; ;
; builds for GitHub Actions CI ; 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 ; the Web interface is built separately during the GH Action script, so skipped on these targets
; ;
[env:ci_s_4M] [env:ci_s_4M]
@@ -240,7 +238,7 @@ lib_ldf_mode = off
lib_ignore = Module EMS-ESP-Modules lib_ignore = Module EMS-ESP-Modules
; unit tests ; 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 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 ; 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 ; then run and capture the output between "START - CUT HERE" and "END - CUT HERE" into the test_api.h file

View File

@@ -379,30 +379,25 @@ static void setup_commands(std::shared_ptr<Commands> const & commands) {
} }
}); });
// read <deviceID> <type ID> [offset] [length]
commands->add_command(ShellContext::MAIN, commands->add_command(ShellContext::MAIN,
CommandFlags::USER, CommandFlags::USER,
{F_(read)}, {F_(read)},
string_vector{F_(deviceid_mandatory), F_(typeid_mandatory), F_(offset_optional), F_(length_optional)}, string_vector{F_(deviceid_mandatory), F_(typeid_mandatory), F_(offset_optional), F_(length_optional)},
[=](Shell & shell, const std::vector<std::string> & arguments) { [=](Shell & shell, const std::vector<std::string> & 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"); shell.printfln("Invalid deviceID");
return; 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, commands->add_command(ShellContext::MAIN,

View File

@@ -99,7 +99,7 @@ char * Helpers::ultostr(char * ptr, uint32_t value, const uint8_t base) {
#endif #endif
/** /**
* fast atoi returning a std::string * fast itoa returning a std::string
* http://www.strudel.org.uk/itoa/ * 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 * 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) { char * Helpers::itoa(int32_t value, char * result, const uint8_t base) {
// check that the base if valid // check that the base if valid

View File

@@ -20,7 +20,6 @@
#define EMSESP_HELPERS_H #define EMSESP_HELPERS_H
#include "telegram.h" // for EMS_VALUE_* settings #include "telegram.h" // for EMS_VALUE_* settings
#include "common.h" #include "common.h"
namespace emsesp { namespace emsesp {

View File

@@ -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(commands_cmd, "list all commands", "Liste aller Kommandos", "lijst van alle commando's", "", "wyświetl wszystkie komendy", "Viser alle kommandoer", "", "Tüm komutları listele", "elencaa tutti i comandi", "zobraziť všetky príkazy") // TODO translate
MAKE_WORD_TRANSLATION(entities_cmd, "list all entities", "Liste aller Entitäten", "lijst van alle entiteiten", "", "wyświetl wszsytkie encje", "Viser alle enheter", "", "Tüm varlıkları listele", "elenca tutte le entità", "zobraziť všetky entity") // TODO translate MAKE_WORD_TRANSLATION(entities_cmd, "list all entities", "Liste aller Entitäten", "lijst van alle entiteiten", "", "wyświetl wszsytkie encje", "Viser alle enheter", "", "Tüm varlıkları listele", "elenca tutte le entità", "zobraziť všetky entity") // TODO translate
MAKE_WORD_TRANSLATION(send_cmd, "send a telegram", "Sende EMS-Telegramm", "stuur een telegram", "", "wyślij telegram", "send et telegram", "", "Bir telegram gönder", "invia un telegramma", "poslať telegram") // TODO translate MAKE_WORD_TRANSLATION(send_cmd, "send a telegram", "Sende EMS-Telegramm", "stuur een telegram", "", "wyślij telegram", "send et telegram", "", "Bir telegram gönder", "invia un telegramma", "poslať telegram") // TODO translate
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(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(changeloglevel_cmd, "change log level", "Ändere Protokollebene", "aanpassen log niveau", "", "zmień poziom log-u", "endre loggnivå", "", "Kayıt seviyesini değiştir", "cambia livello registrazione", "zmeniť úroveň protokolu") // TODO translate
MAKE_WORD_TRANSLATION(fetch_cmd, "refresh all EMS values", "Aktualisiere alle EMS-Werte", "Verversen alle EMS waardes", "", "odśwież wszystkie wartości EMS", "oppfrisk alle EMS verdier", "", "Bütün EMS değerlerini yenile", "aggiornare tutti i valori EMS", "obnoviť všetky hodnoty EMS") // TODO translate MAKE_WORD_TRANSLATION(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(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(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(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(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(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 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

View File

@@ -410,6 +410,7 @@ void System::reload_settings() {
eth_clock_mode_ = settings.eth_clock_mode; 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 // commands - takes static function pointers
// can be called via Console using 'call system <cmd>' // can be called via Console using 'call system <cmd>'
void System::commands_init() { 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_(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_(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); 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 #endif
node["modbusEnabled"] = settings.modbus_enabled; node["modbusEnabled"] = settings.modbus_enabled;
node["forceHeatingOff"] = settings.boiler_heatingoff; node["forceHeatingOff"] = settings.boiler_heatingoff;
node["developerMode"] = settings.developer_mode;
}); });
// Devices - show EMS devices if we have any // Devices - show EMS devices if we have any
@@ -2012,4 +2015,60 @@ bool System::uploadFirmwareURL(const char * url) {
return true; // OK return true; // OK
} }
// read command, e.g. read <deviceID> <type ID> [offset] [length] from console or API
bool System::readCommand(const char * data) {
// extract <deviceID> <type ID> [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 } // namespace emsesp

View File

@@ -63,6 +63,7 @@ class System {
void loop(); void loop();
// commands // 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_send(const char * value, const int8_t id);
static bool command_publish(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); 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 is_valid_gpio(uint8_t pin, bool has_psram = false);
static bool load_board_profile(std::vector<int8_t> & data, const std::string & board_profile); static bool load_board_profile(std::vector<int8_t> & data, const std::string & board_profile);
static bool readCommand(const char * data);
static void restart_requested(bool restart_requested) { static void restart_requested(bool restart_requested) {
restart_requested_ = restart_requested; restart_requested_ = restart_requested;
} }
@@ -170,6 +173,14 @@ class System {
readonly_mode_ = readonly_mode; readonly_mode_ = readonly_mode;
} }
bool developer_mode() {
return developer_mode_;
}
void developer_mode(bool developer_mode) {
developer_mode_ = developer_mode;
}
// Boolean Format API/MQTT // Boolean Format API/MQTT
uint8_t bool_format() { uint8_t bool_format() {
return bool_format_; return bool_format_;
@@ -398,6 +409,7 @@ class System {
uint16_t modbus_port_; uint16_t modbus_port_;
uint8_t modbus_max_clients_; uint8_t modbus_max_clients_;
uint32_t modbus_timeout_; uint32_t modbus_timeout_;
bool developer_mode_;
// ethernet // ethernet
uint8_t phy_type_; uint8_t phy_type_;

View File

@@ -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 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) // 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]) { if (offset + old_length >= telegram_last_->offset + telegram_last_->message_data[0]) {
return 0; return 0;
} }

View File

@@ -973,16 +973,16 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
if (single) { if (single) {
// run dedicated tests only // run dedicated tests only
EMSESP::webCustomEntityService.test(); // custom entities // EMSESP::webCustomEntityService.test(); // custom entities
EMSESP::webCustomizationService.test(); // set customizations - this will overwrite any settings in the FS // EMSESP::webCustomizationService.test(); // set customizations - this will overwrite any settings in the FS
EMSESP::temperaturesensor_.test(); // add temperature sensors // EMSESP::temperaturesensor_.test(); // add temperature sensors
EMSESP::webSchedulerService.test(); // run scheduler tests, and conditions // EMSESP::webSchedulerService.test(); // run scheduler tests, and conditions
// request.url("/rest/deviceEntities"); // request.url("/rest/deviceEntities");
// EMSESP::webCustomizationService.device_entities(&request); // EMSESP::webCustomizationService.device_entities(&request);
request.url("/rest/dashboardData"); // request.url("/rest/dashboardData");
EMSESP::webDataService.dashboard_data(&request); // EMSESP::webDataService.dashboard_data(&request);
// COMMANDS // COMMANDS
// shell.invoke_command("call system fetch"); // 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); // EMSESP::webAPIService.webAPIService(&request);
// POST COMMANDS // POST COMMANDS
// request.method(HTTP_POST); request.method(HTTP_POST);
// char data1[] = "{\"device\":\"system\", \"cmd\":\"restart\",\"id\":-1}"; // char data1[] = "{\"device\":\"system\", \"cmd\":\"restart\",\"id\":-1}";
// deserializeJson(doc, data1); // deserializeJson(doc, data1);
@@ -1021,6 +1021,20 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
// request.url("/rest/action"); // request.url("/rest/action");
// EMSESP::webStatusService.action(&request, doc.as<JsonVariant>()); // EMSESP::webStatusService.action(&request, doc.as<JsonVariant>());
char data6[] = "{\"device\":\"system\", \"cmd\":\"read\",\"value\":\"8 2 27 1\"}";
deserializeJson(doc, data6);
json = doc.as<JsonVariant>();
request.url("/api");
EMSESP::webAPIService.webAPIService(&request, json);
char data7[] = "{\"device\":\"system\", \"cmd\":\"read\",\"value\":\"10 234\"}";
deserializeJson(doc, data7);
json = doc.as<JsonVariant>();
request.url("/api");
EMSESP::webAPIService.webAPIService(&request, json);
shell.invoke_command("call system read \"8 2 27 1\"");
} else { } else {
EMSESP::webCustomEntityService.test(); // custom entities EMSESP::webCustomEntityService.test(); // custom entities

View File

@@ -1 +1 @@
#define EMSESP_APP_VERSION "3.7.0-dev.46" #define EMSESP_APP_VERSION "3.7.0-dev.47"

View File

@@ -28,8 +28,9 @@ WebAPIService::WebAPIService(AsyncWebServer * server, SecurityManager * security
server->on(EMSESP_API_SERVICE_PATH, [this](AsyncWebServerRequest * request, JsonVariant json) { webAPIService(request, json); }); server->on(EMSESP_API_SERVICE_PATH, [this](AsyncWebServerRequest * request, JsonVariant json) { webAPIService(request, json); });
} }
// POST|GET /{device} // POST|GET api/
// POST|GET /{device}/{entity} // POST|GET api/{device}
// POST|GET api/{device}/{entity}
void WebAPIService::webAPIService(AsyncWebServerRequest * request, JsonVariant json) { void WebAPIService::webAPIService(AsyncWebServerRequest * request, JsonVariant json) {
JsonObject input; JsonObject input;
// if no body then treat it as a secure GET // if no body then treat it as a secure GET

View File

@@ -243,6 +243,7 @@ void WebLogService::getSetValues(AsyncWebServerRequest * request, JsonVariant js
root["max_messages"] = maximum_log_messages(); root["max_messages"] = maximum_log_messages();
root["compact"] = compact(); root["compact"] = compact();
root["psram"] = (EMSESP::system_.PSram() > 0); root["psram"] = (EMSESP::system_.PSram() > 0);
root["developer_mode"] = EMSESP::system_.developer_mode();
response->setLength(); response->setLength();
request->send(response); request->send(response);

View File

@@ -80,6 +80,7 @@ void WebSettings::read(WebSettings & settings, JsonObject root) {
root["modbus_port"] = settings.modbus_port; root["modbus_port"] = settings.modbus_port;
root["modbus_max_clients"] = settings.modbus_max_clients; root["modbus_max_clients"] = settings.modbus_max_clients;
root["modbus_timeout"] = settings.modbus_timeout; 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 // 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"]; settings.readonly_mode = root["readonly_mode"];
EMSESP::system_.readonly_mode(settings.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; settings.bool_dashboard = root["bool_dashboard"] | EMSESP_DEFAULT_BOOL_FORMAT;
EMSESP::system_.bool_dashboard(settings.bool_dashboard); EMSESP::system_.bool_dashboard(settings.bool_dashboard);

View File

@@ -65,10 +65,13 @@ class WebSettings {
uint8_t bool_format; uint8_t bool_format;
uint8_t bool_dashboard; uint8_t bool_dashboard;
uint8_t enum_format; uint8_t enum_format;
int8_t weblog_level; int8_t weblog_level;
uint8_t weblog_buffer; uint8_t weblog_buffer;
bool weblog_compact; bool weblog_compact;
bool fahrenheit; bool fahrenheit;
bool modbus_enabled; bool modbus_enabled;
uint16_t modbus_port; uint16_t modbus_port;
uint8_t modbus_max_clients; uint8_t modbus_max_clients;
@@ -79,6 +82,8 @@ class WebSettings {
uint8_t eth_phy_addr; uint8_t eth_phy_addr;
uint8_t eth_clock_mode; uint8_t eth_clock_mode;
bool developer_mode; // developer mode
static void read(WebSettings & settings, JsonObject root); static void read(WebSettings & settings, JsonObject root);
static StateUpdateResult update(JsonObject root, WebSettings & settings); static StateUpdateResult update(JsonObject root, WebSettings & settings);

View File

@@ -173,10 +173,6 @@ void WebStatusService::action(AsyncWebServerRequest * request, JsonVariant json)
ok = uploadURL(param.c_str()); 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) #if defined(EMSESP_STANDALONE) && !defined(EMSESP_UNITY)
Serial.printf("%sweb output: %s[%s]", COLOR_WHITE, COLOR_BRIGHT_CYAN, request->url().c_str()); Serial.printf("%sweb output: %s[%s]", COLOR_WHITE, COLOR_BRIGHT_CYAN, request->url().c_str());
Serial.printf(" %s(%d)%s ", ok ? COLOR_BRIGHT_GREEN : COLOR_BRIGHT_RED, ok ? 200 : 400, COLOR_YELLOW); Serial.printf(" %s(%d)%s ", ok ? COLOR_BRIGHT_GREEN : COLOR_BRIGHT_RED, ok ? 200 : 400, COLOR_YELLOW);
@@ -205,6 +201,7 @@ bool WebStatusService::checkUpgrade(JsonObject root, std::string & latest_versio
#endif #endif
root["upgradeable"] = (this_version > settings_version); root["upgradeable"] = (this_version > settings_version);
root["emsesp_version"] = EMSESP_APP_VERSION;
return true; return true;
} }

View File

@@ -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) # 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 # 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_dev = http://10.10.10.175
@host_standalone = http://localhost:3080 @host_standalone = http://localhost:3080
@host_standalone2 = http://localhost:3082 @host_standalone2 = http://localhost:3082

31
test/test_api/api_test.sh Executable file
View File

@@ -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"

View File

@@ -40,9 +40,9 @@ void test_2() {
"off\",\"heatingtemp\":\"heating temperature\",\"maintenance\":\"maintenance scheduled\",\"maintenancedate\":\"next maintenance " "off\",\"heatingtemp\":\"heating temperature\",\"maintenance\":\"maintenance scheduled\",\"maintenancedate\":\"next maintenance "
"date\",\"maintenancetime\":\"time to next maintenance\",\"nofrostmode\":\"nofrost mode\",\"nofrosttemp\":\"nofrost " "date\",\"maintenancetime\":\"time to next maintenance\",\"nofrostmode\":\"nofrost mode\",\"nofrosttemp\":\"nofrost "
"temperature\",\"nompower\":\"nominal Power\",\"nrgheat\":\"energy heating\",\"pumpcharacter\":\"boiler pump characteristic\",\"pumpdelay\":\"pump " "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 " "delay\",\"pumpmode\":\"boiler pump mode\",\"pumpmodmax\":\"boiler pump max power\",\"pumpmodmin\":\"boiler pump min power\",\"pumpontemp\":\"pump "
"power\",\"reset\":\"reset\",\"selburnpow\":\"burner selected max power\",\"selflowtemp\":\"selected flow temperature\",\"summertemp\":\"summer " "logic temperature\",\"reset\":\"reset\",\"selburnpow\":\"burner selected max power\",\"selflowtemp\":\"selected flow "
"temperature\"}]"; "temperature\",\"summertemp\":\"summer temperature\"}]";
TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/boiler/commands")); TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/boiler/commands"));
} }
@@ -149,8 +149,8 @@ void test_17() {
} }
void test_18() { void test_18() {
auto expected_response = auto expected_response = "[{\"name\":\"seltemp\",\"fullname\":\"seltemp\",\"storage\":\"ram\",\"type\":\"number\",\"readable\":true,\"writeable\":true,"
"[{\"name\":\"seltemp\",\"storage\":\"ram\",\"type\":\"number\",\"readable\":true,\"writeable\":true,\"visible\":true,\"value\":\"14\"}]"; "\"visible\":true,\"value\":\"14\"}]";
TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/custom/seltemp")); 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," "\"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\":" "\"mqttRetain\":false,\"publishTimeHeartbeat\":60,\"publishTimeBoiler\":10,\"publishTimeThermostat\":10,\"publishTimeSolar\":10,\"publishTimeMixer\":"
"10,\"publishTimeWater\":0,\"publishTimeOther\":10,\"publishTimeSensor\":10,\"publishSingle\":false,\"publish2command\":false,\"sendResponse\":false}," "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\":" "\"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," "\"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," "\"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\":" "\"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," "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 " "\"maxWebLogBuffer\":25,\"webLogBuffer\":0,\"modbusEnabled\":false,\"forceHeatingOff\":false,\"developerMode\":false},\"devices\":[{\"type\":"
"Name!!\",\"deviceID\":\"0x08\",\"productID\":123,\"brand\":\"\",\"version\":\"01.00\",\"entities\":37,\"handlersReceived\":\"0x18\"," "\"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 " "\"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," "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")); 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," "\"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\":" "\"mqttRetain\":false,\"publishTimeHeartbeat\":60,\"publishTimeBoiler\":10,\"publishTimeThermostat\":10,\"publishTimeSolar\":10,\"publishTimeMixer\":"
"10,\"publishTimeWater\":0,\"publishTimeOther\":10,\"publishTimeSensor\":10,\"publishSingle\":false,\"publish2command\":false,\"sendResponse\":false}," "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\":" "\"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," "\"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," "\"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\":" "\"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," "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 " "\"maxWebLogBuffer\":25,\"webLogBuffer\":0,\"modbusEnabled\":false,\"forceHeatingOff\":false,\"developerMode\":false},\"devices\":[{\"type\":"
"Name!!\",\"deviceID\":\"0x08\",\"productID\":123,\"brand\":\"\",\"version\":\"01.00\",\"entities\":37,\"handlersReceived\":\"0x18\"," "\"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 " "\"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," "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")); TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/system/info"));
} }
@@ -228,8 +234,8 @@ void test_25() {
} }
void test_26() { void test_26() {
auto expected_response = "[{\"name\":\"test_scheduler\",\"type\":\"boolean\",\"value\":\"on\",\"time\":\"12:00\",\"command\":\"system/" auto expected_response = "[{\"name\":\"test_scheduler\",\"fullname\":\"test_scheduler\",\"type\":\"boolean\",\"value\":\"on\",\"time\":\"12:00\","
"fetch\",\"cmd_data\":\"10\",\"readable\":true,\"writeable\":true,\"visible\":true}]"; "\"command\":\"system/fetch\",\"cmd_data\":\"10\",\"readable\":true,\"writeable\":true,\"visible\":true}]";
TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/scheduler/test_scheduler")); TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/scheduler/test_scheduler"));
} }
@@ -244,14 +250,14 @@ void test_28() {
} }
void test_29() { void test_29() {
auto expected_response = auto expected_response = "[{\"id\":\"0B_0C0D_0E0F_1011\",\"name\":\"test_tempsensor2\",\"fullname\":\"test_tempsensor2\",\"value\":45.6,\"type\":"
"[{\"id\":\"0B_0C0D_0E0F_1011\",\"name\":\"test_tempsensor2\",\"value\":45.6,\"type\":\"number\",\"uom\":\"°C\",\"writeable\":false}]"; "\"number\",\"uom\":\"°C\",\"readable\":true,\"writeable\":false,\"visible\":true}]";
TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/temperaturesensor/test_tempsensor2")); TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/temperaturesensor/test_tempsensor2"));
} }
void test_30() { void test_30() {
auto expected_response = auto expected_response = "[{\"id\":\"0B_0C0D_0E0F_1011\",\"name\":\"test_tempsensor2\",\"fullname\":\"test_tempsensor2\",\"value\":45.6,\"type\":"
"[{\"id\":\"0B_0C0D_0E0F_1011\",\"name\":\"test_tempsensor2\",\"value\":45.6,\"type\":\"number\",\"uom\":\"°C\",\"writeable\":false}]"; "\"number\",\"uom\":\"°C\",\"readable\":true,\"writeable\":false,\"visible\":true}]";
TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/temperaturesensor/0B_0C0D_0E0F_1011")); TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/temperaturesensor/0B_0C0D_0E0F_1011"));
} }
@@ -261,18 +267,18 @@ void test_31() {
} }
void test_32() { 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")); TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/analogsensor"));
} }
void test_33() { 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")); TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/analogsensor/info"));
} }
void test_34() { void test_34() {
auto expected_response = auto expected_response = "[{\"name\":\"test_analogsensor1\",\"fullname\":\"test_analogsensor1\",\"gpio\":36,\"type\":\"number\",\"analog\":\"adc\","
"[{\"gpio\":36,\"type\":\"number\",\"analog\":\"adc\",\"value\":0,\"writeable\":false,\"offset\":0,\"factor\":0.1,\"uom\":\"mV\"}]"; "\"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")); TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/analogsensor/test_analogsensor1"));
} }
@@ -287,12 +293,12 @@ void test_36() {
} }
void test_37() { 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")); TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/boiler/bad/value"));
} }
void test_38() { 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")); TEST_ASSERT_EQUAL_STRING(expected_response, call_url("/api/boiler/comfort/valu"));
} }