mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-06 15:59:52 +03:00
translations and finish writeDevice
This commit is contained in:
@@ -42,7 +42,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.25.7",
|
"@babel/core": "^7.25.7",
|
||||||
"@eslint/js": "^9.11.1",
|
"@eslint/js": "^9.12.0",
|
||||||
"@preact/compat": "^18.3.1",
|
"@preact/compat": "^18.3.1",
|
||||||
"@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",
|
||||||
@@ -52,7 +52,7 @@
|
|||||||
"@types/react-dom": "^18.3.0",
|
"@types/react-dom": "^18.3.0",
|
||||||
"@types/react-router-dom": "^5.3.3",
|
"@types/react-router-dom": "^5.3.3",
|
||||||
"concurrently": "^9.0.1",
|
"concurrently": "^9.0.1",
|
||||||
"eslint": "^9.11.1",
|
"eslint": "^9.12.0",
|
||||||
"eslint-config-prettier": "^9.1.0",
|
"eslint-config-prettier": "^9.1.0",
|
||||||
"formidable": "^3.5.1",
|
"formidable": "^3.5.1",
|
||||||
"prettier": "^3.3.3",
|
"prettier": "^3.3.3",
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useCallback, useEffect, useState } from 'react';
|
import { useCallback, useState } from 'react';
|
||||||
import { useBlocker } from 'react-router-dom';
|
import { useBlocker } from 'react-router-dom';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
|
|
||||||
@@ -27,6 +27,7 @@ import {
|
|||||||
useLayoutTitle
|
useLayoutTitle
|
||||||
} from 'components';
|
} from 'components';
|
||||||
import { useI18nContext } from 'i18n/i18n-react';
|
import { useI18nContext } from 'i18n/i18n-react';
|
||||||
|
import { useInterval } from 'utils';
|
||||||
|
|
||||||
import { readCustomEntities, writeCustomEntities } from '../../api/app';
|
import { readCustomEntities, writeCustomEntities } from '../../api/app';
|
||||||
import SettingsCustomEntitiesDialog from './CustomEntitiesDialog';
|
import SettingsCustomEntitiesDialog from './CustomEntitiesDialog';
|
||||||
@@ -52,17 +53,11 @@ const CustomEntities = () => {
|
|||||||
initialData: []
|
initialData: []
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useInterval(() => {
|
||||||
const timer = setInterval(async () => {
|
if (!dialogOpen && !numChanges) {
|
||||||
if (dialogOpen || numChanges > 0) {
|
void fetchEntities();
|
||||||
return;
|
}
|
||||||
}
|
}, 3000);
|
||||||
await fetchEntities();
|
|
||||||
}, 2000);
|
|
||||||
return () => {
|
|
||||||
clearInterval(timer);
|
|
||||||
};
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const { send: writeEntities } = useRequest(
|
const { send: writeEntities } = useRequest(
|
||||||
(data: Entities) => writeCustomEntities(data),
|
(data: Entities) => writeCustomEntities(data),
|
||||||
@@ -295,7 +290,7 @@ const CustomEntities = () => {
|
|||||||
<SectionContent>
|
<SectionContent>
|
||||||
{blocker ? <BlockNavigation blocker={blocker} /> : null}
|
{blocker ? <BlockNavigation blocker={blocker} /> : null}
|
||||||
<Box mb={2} color="warning.main">
|
<Box mb={2} color="warning.main">
|
||||||
<Typography variant="body2">{LL.ENTITIES_HELP_1()}</Typography>
|
<Typography variant="body1">{LL.ENTITIES_HELP_1()}</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
{renderEntity()}
|
{renderEntity()}
|
||||||
|
|||||||
@@ -427,7 +427,7 @@ const Customizations = () => {
|
|||||||
const renderDeviceList = () => (
|
const renderDeviceList = () => (
|
||||||
<>
|
<>
|
||||||
<Box mb={1} color="warning.main">
|
<Box mb={1} color="warning.main">
|
||||||
<Typography variant="body2">{LL.CUSTOMIZATIONS_HELP_1()}.</Typography>
|
<Typography variant="body1">{LL.CUSTOMIZATIONS_HELP_1()}.</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
<Box display="flex" flexWrap="wrap" alignItems="center" gap={2}>
|
<Box display="flex" flexWrap="wrap" alignItems="center" gap={2}>
|
||||||
{rename ? (
|
{rename ? (
|
||||||
|
|||||||
@@ -22,23 +22,29 @@ import { useRequest } from 'alova/client';
|
|||||||
import { FormLoader, SectionContent, useLayoutTitle } from 'components';
|
import { FormLoader, SectionContent, useLayoutTitle } from 'components';
|
||||||
import { AuthenticatedContext } from 'contexts/authentication';
|
import { AuthenticatedContext } from 'contexts/authentication';
|
||||||
import { useI18nContext } from 'i18n/i18n-react';
|
import { useI18nContext } from 'i18n/i18n-react';
|
||||||
|
import { useInterval } from 'utils';
|
||||||
|
|
||||||
import { readDashboard, writeDeviceValue } from '../../api/app';
|
import { readDashboard, writeDeviceValue } from '../../api/app';
|
||||||
import DeviceIcon from './DeviceIcon';
|
import DeviceIcon from './DeviceIcon';
|
||||||
import DashboardDevicesDialog from './DevicesDialog';
|
import DashboardDevicesDialog from './DevicesDialog';
|
||||||
import { formatValue } from './deviceValue';
|
import { formatValue } from './deviceValue';
|
||||||
import { type DashboardItem, type DeviceValue } from './types';
|
import { type DashboardItem, DeviceEntityMask, type DeviceValue } from './types';
|
||||||
import { deviceValueItemValidation } from './validators';
|
import { deviceValueItemValidation } from './validators';
|
||||||
|
|
||||||
const Dashboard = () => {
|
const Dashboard = () => {
|
||||||
const { LL } = useI18nContext();
|
const { LL } = useI18nContext();
|
||||||
const { me } = useContext(AuthenticatedContext);
|
const { me } = useContext(AuthenticatedContext);
|
||||||
|
|
||||||
useLayoutTitle('Dashboard'); // TODO translate
|
useLayoutTitle(LL.DASHBOARD());
|
||||||
|
|
||||||
const [firstLoad, setFirstLoad] = useState<boolean>(true);
|
const [firstLoad, setFirstLoad] = useState<boolean>(true);
|
||||||
const [showAll, setShowAll] = useState<boolean>(true);
|
const [showAll, setShowAll] = useState<boolean>(true);
|
||||||
|
|
||||||
|
const [deviceValueDialogOpen, setDeviceValueDialogOpen] = useState<boolean>(false);
|
||||||
|
|
||||||
|
const [selectedDashboardItem, setSelectedDashboardItem] =
|
||||||
|
useState<DashboardItem>();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
data,
|
data,
|
||||||
send: fetchDashboard,
|
send: fetchDashboard,
|
||||||
@@ -55,17 +61,11 @@ const Dashboard = () => {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const [deviceValueDialogOpen, setDeviceValueDialogOpen] = useState(false);
|
|
||||||
const [selectedDeviceValue, setSelectedDeviceValue] = useState<DeviceValue>();
|
|
||||||
|
|
||||||
const deviceValueDialogClose = () => {
|
|
||||||
setDeviceValueDialogOpen(false);
|
|
||||||
void sendDeviceData(selectedDevice);
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO get this working next
|
|
||||||
const deviceValueDialogSave = async (devicevalue: DeviceValue) => {
|
const deviceValueDialogSave = async (devicevalue: DeviceValue) => {
|
||||||
const id = Number(device_select.state.id);
|
if (!selectedDashboardItem) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const id = selectedDashboardItem.parentNode.id; // this is the parent ID
|
||||||
await sendDeviceValue({ id, c: devicevalue.c ?? '', v: devicevalue.v })
|
await sendDeviceValue({ id, c: devicevalue.c ?? '', v: devicevalue.v })
|
||||||
.then(() => {
|
.then(() => {
|
||||||
toast.success(LL.WRITE_CMD_SENT());
|
toast.success(LL.WRITE_CMD_SENT());
|
||||||
@@ -73,10 +73,9 @@ const Dashboard = () => {
|
|||||||
.catch((error: Error) => {
|
.catch((error: Error) => {
|
||||||
toast.error(error.message);
|
toast.error(error.message);
|
||||||
})
|
})
|
||||||
.finally(async () => {
|
.finally(() => {
|
||||||
setDeviceValueDialogOpen(false);
|
setDeviceValueDialogOpen(false);
|
||||||
await sendDeviceData(id);
|
setSelectedDashboardItem(undefined);
|
||||||
setSelectedDeviceValue(undefined);
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -105,7 +104,7 @@ const Dashboard = () => {
|
|||||||
const tree = useTree(
|
const tree = useTree(
|
||||||
{ nodes: data },
|
{ nodes: data },
|
||||||
{
|
{
|
||||||
onChange: null
|
onChange: null // not used but needed
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
treeIcon: {
|
treeIcon: {
|
||||||
@@ -118,25 +117,19 @@ const Dashboard = () => {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useInterval(() => {
|
||||||
const timer = setInterval(() => {
|
if (!deviceValueDialogOpen) {
|
||||||
if (deviceValueDialogOpen) {
|
void fetchDashboard();
|
||||||
return;
|
}
|
||||||
}
|
}, 3000);
|
||||||
fetchDashboard();
|
|
||||||
}, 2000);
|
|
||||||
return () => {
|
|
||||||
clearInterval(timer);
|
|
||||||
};
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
// auto expand on first load
|
// auto expand on first load
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (firstLoad && data.length && !tree.state.ids.length) {
|
if (firstLoad && Array.isArray(data) && data.length && !tree.state.ids.length) {
|
||||||
tree.fns.onToggleAll({});
|
tree.fns.onToggleAll({});
|
||||||
setFirstLoad(false);
|
setFirstLoad(false);
|
||||||
}
|
}
|
||||||
}, [data]);
|
}, [loading]);
|
||||||
|
|
||||||
const showName = (di: DashboardItem) => {
|
const showName = (di: DashboardItem) => {
|
||||||
if (di.id < 100) {
|
if (di.id < 100) {
|
||||||
@@ -145,7 +138,7 @@ const Dashboard = () => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<span style="font-size: 14px">
|
<span style="font-size: 14px">
|
||||||
<DeviceIcon type_id={di.t} />
|
<DeviceIcon type_id={di.t ?? 0} />
|
||||||
{di.n}
|
{di.n}
|
||||||
</span>
|
</span>
|
||||||
<span style={{ color: 'lightblue' }}> ({di.nodes?.length})</span>
|
<span style={{ color: 'lightblue' }}> ({di.nodes?.length})</span>
|
||||||
@@ -153,20 +146,14 @@ const Dashboard = () => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return <span style="color:lightgrey">{di.n}</span>;
|
return <span style="color:lightgrey">{di.dv ? di.dv.id.slice(2) : ''}</span>;
|
||||||
};
|
};
|
||||||
|
|
||||||
const showDeviceValue = (di: DashboardItem) => {
|
const hasMask = (id: string, mask: number) =>
|
||||||
// convert di to dv
|
(parseInt(id.slice(0, 2), 16) & mask) === mask;
|
||||||
// TODO should we not just use dv?
|
|
||||||
const dv: DeviceValue = {
|
const editDashboardValue = (di: DashboardItem) => {
|
||||||
id: ' ' + di.n,
|
setSelectedDashboardItem(di);
|
||||||
v: di.v,
|
|
||||||
u: di.u,
|
|
||||||
c: di.c,
|
|
||||||
l: di.l
|
|
||||||
};
|
|
||||||
setSelectedDeviceValue(dv);
|
|
||||||
setDeviceValueDialogOpen(true);
|
setDeviceValueDialogOpen(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -185,21 +172,10 @@ const Dashboard = () => {
|
|||||||
return <FormLoader onRetry={fetchDashboard} errorMessage={error?.message} />;
|
return <FormLoader onRetry={fetchDashboard} errorMessage={error?.message} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (data.length === 0) {
|
|
||||||
// return (
|
|
||||||
// <Typography variant="body2" color="warning">
|
|
||||||
// {/* TODO translate */}
|
|
||||||
// No entities found.
|
|
||||||
// </Typography>
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Typography mb={2} variant="body2" color="warning">
|
<Typography mb={2} variant="body1" color="warning">
|
||||||
{/* TODO translate */}
|
{LL.DASHBOARD_1()}
|
||||||
The dashboard shows all EMS entities that are marked as favorite, and the
|
|
||||||
sensors.
|
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
<ToggleButtonGroup
|
<ToggleButtonGroup
|
||||||
@@ -235,9 +211,8 @@ const Dashboard = () => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{!loading && data.length === 0 ? (
|
{!loading && data.length === 0 ? (
|
||||||
<Typography variant="body2" color="warning">
|
<Typography variant="subtitle2" color="warning">
|
||||||
{/* TODO translate */}
|
{LL.NO_DATA()}
|
||||||
No entities found.
|
|
||||||
</Typography>
|
</Typography>
|
||||||
) : (
|
) : (
|
||||||
<Table
|
<Table
|
||||||
@@ -257,19 +232,21 @@ const Dashboard = () => {
|
|||||||
)}
|
)}
|
||||||
<Cell pinRight>
|
<Cell pinRight>
|
||||||
<span style={{ color: 'lightgrey' }}>
|
<span style={{ color: 'lightgrey' }}>
|
||||||
{formatValue(LL, di.v, di.u)}
|
{di.dv && formatValue(LL, di.dv.v, di.dv.u)}
|
||||||
</span>
|
</span>
|
||||||
</Cell>
|
</Cell>
|
||||||
|
|
||||||
<Cell stiff>
|
<Cell stiff>
|
||||||
{me.admin && di.c && (
|
{me.admin &&
|
||||||
<IconButton
|
di.dv?.c &&
|
||||||
size="small"
|
!hasMask(di.dv.id, DeviceEntityMask.DV_READONLY) && (
|
||||||
onClick={() => showDeviceValue(di)}
|
<IconButton
|
||||||
>
|
size="small"
|
||||||
<EditIcon color="primary" sx={{ fontSize: 16 }} />
|
onClick={() => editDashboardValue(di)}
|
||||||
</IconButton>
|
>
|
||||||
)}
|
<EditIcon color="primary" sx={{ fontSize: 16 }} />
|
||||||
|
</IconButton>
|
||||||
|
)}
|
||||||
</Cell>
|
</Cell>
|
||||||
</Row>
|
</Row>
|
||||||
))}
|
))}
|
||||||
@@ -286,14 +263,14 @@ const Dashboard = () => {
|
|||||||
return (
|
return (
|
||||||
<SectionContent>
|
<SectionContent>
|
||||||
{renderContent()}
|
{renderContent()}
|
||||||
{selectedDeviceValue && (
|
{selectedDashboardItem && selectedDashboardItem.dv && (
|
||||||
<DashboardDevicesDialog
|
<DashboardDevicesDialog
|
||||||
open={deviceValueDialogOpen}
|
open={deviceValueDialogOpen}
|
||||||
onClose={deviceValueDialogClose}
|
onClose={() => setDeviceValueDialogOpen(false)}
|
||||||
onSave={deviceValueDialogSave}
|
onSave={deviceValueDialogSave}
|
||||||
selectedItem={selectedDeviceValue}
|
selectedItem={selectedDashboardItem.dv}
|
||||||
writeable={true}
|
writeable={true}
|
||||||
validator={deviceValueItemValidation(selectedDeviceValue)}
|
validator={deviceValueItemValidation(selectedDashboardItem.dv)}
|
||||||
progress={submitting}
|
progress={submitting}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ import { useRequest } from 'alova/client';
|
|||||||
import { MessageBox, SectionContent, useLayoutTitle } from 'components';
|
import { MessageBox, SectionContent, useLayoutTitle } from 'components';
|
||||||
import { AuthenticatedContext } from 'contexts/authentication';
|
import { AuthenticatedContext } from 'contexts/authentication';
|
||||||
import { useI18nContext } from 'i18n/i18n-react';
|
import { useI18nContext } from 'i18n/i18n-react';
|
||||||
|
import { useInterval } from 'utils';
|
||||||
|
|
||||||
import { readCoreData, readDeviceData, writeDeviceValue } from '../../api/app';
|
import { readCoreData, readDeviceData, writeDeviceValue } from '../../api/app';
|
||||||
import DeviceIcon from './DeviceIcon';
|
import DeviceIcon from './DeviceIcon';
|
||||||
@@ -77,7 +78,7 @@ const Devices = () => {
|
|||||||
const [selectedDeviceValue, setSelectedDeviceValue] = useState<DeviceValue>();
|
const [selectedDeviceValue, setSelectedDeviceValue] = useState<DeviceValue>();
|
||||||
const [onlyFav, setOnlyFav] = useState(false);
|
const [onlyFav, setOnlyFav] = useState(false);
|
||||||
const [deviceValueDialogOpen, setDeviceValueDialogOpen] = useState(false);
|
const [deviceValueDialogOpen, setDeviceValueDialogOpen] = useState(false);
|
||||||
const [showDeviceInfo, setShowDeviceInfo] = useState<boolean>(false);
|
const [showDeviceInfo, setShowDeviceInfo] = useState(false);
|
||||||
const [selectedDevice, setSelectedDevice] = useState<number>();
|
const [selectedDevice, setSelectedDevice] = useState<number>();
|
||||||
|
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
@@ -418,17 +419,11 @@ const Devices = () => {
|
|||||||
downloadBlob(new Blob([csvData], { type: 'text/csv;charset:utf-8' }));
|
downloadBlob(new Blob([csvData], { type: 'text/csv;charset:utf-8' }));
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useInterval(() => {
|
||||||
const timer = setInterval(() => {
|
if (!deviceValueDialogOpen) {
|
||||||
if (deviceValueDialogOpen) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
selectedDevice ? void sendDeviceData(selectedDevice) : void sendCoreData();
|
selectedDevice ? void sendDeviceData(selectedDevice) : void sendCoreData();
|
||||||
}, 2000);
|
}
|
||||||
return () => {
|
}, 3000);
|
||||||
clearInterval(timer);
|
|
||||||
};
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const deviceValueDialogSave = async (devicevalue: DeviceValue) => {
|
const deviceValueDialogSave = async (devicevalue: DeviceValue) => {
|
||||||
const id = Number(device_select.state.id);
|
const id = Number(device_select.state.id);
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ import { useRequest } from 'alova/client';
|
|||||||
import { SectionContent, useLayoutTitle } from 'components';
|
import { SectionContent, useLayoutTitle } from 'components';
|
||||||
import { AuthenticatedContext } from 'contexts/authentication';
|
import { AuthenticatedContext } from 'contexts/authentication';
|
||||||
import { useI18nContext } from 'i18n/i18n-react';
|
import { useI18nContext } from 'i18n/i18n-react';
|
||||||
import { saveFile } from 'utils/file';
|
import { saveFile } from 'utils';
|
||||||
|
|
||||||
import { API, callAction } from '../../api/app';
|
import { API, callAction } from '../../api/app';
|
||||||
import type { APIcall } from './types';
|
import type { APIcall } from './types';
|
||||||
@@ -147,7 +147,7 @@ const Help = () => {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
<Box p={2} color="warning.main">
|
<Box p={2} color="warning.main">
|
||||||
<Typography mb={1} variant="body2">
|
<Typography mb={1} variant="body1">
|
||||||
{LL.HELP_INFORMATION_4()}
|
{LL.HELP_INFORMATION_4()}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@@ -175,7 +175,7 @@ const Modules = () => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Box mb={2} color="warning.main">
|
<Box mb={2} color="warning.main">
|
||||||
<Typography variant="body2">{LL.MODULES_DESCRIPTION()}</Typography>
|
<Typography variant="body1">{LL.MODULES_DESCRIPTION()}</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
<Table
|
<Table
|
||||||
data={{ nodes: modules }}
|
data={{ nodes: modules }}
|
||||||
|
|||||||
@@ -318,7 +318,7 @@ const Scheduler = () => {
|
|||||||
<SectionContent>
|
<SectionContent>
|
||||||
{blocker ? <BlockNavigation blocker={blocker} /> : null}
|
{blocker ? <BlockNavigation blocker={blocker} /> : null}
|
||||||
<Box mb={2} color="warning.main">
|
<Box mb={2} color="warning.main">
|
||||||
<Typography variant="body2">{LL.SCHEDULER_HELP_1()}</Typography>
|
<Typography variant="body1">{LL.SCHEDULER_HELP_1()}</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
{renderSchedule()}
|
{renderSchedule()}
|
||||||
|
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ const Sensors = () => {
|
|||||||
analog_enabled: false,
|
analog_enabled: false,
|
||||||
platform: 'ESP32'
|
platform: 'ESP32'
|
||||||
},
|
},
|
||||||
pollingTime: 2000
|
pollingTime: 3000
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -116,14 +116,10 @@ export interface CoreData {
|
|||||||
|
|
||||||
export interface DashboardItem {
|
export interface DashboardItem {
|
||||||
id: number; // unique index
|
id: number; // unique index
|
||||||
n: string; // name
|
t?: number; // type from DeviceType
|
||||||
v?: unknown; // value, optional
|
n?: string; // name
|
||||||
u: number; // uom
|
dv?: DeviceValue;
|
||||||
t: number; // type from DeviceType
|
nodes?: DashboardItem[]; // children nodes, optional
|
||||||
c?: string; // command, optional
|
|
||||||
l?: string[]; // list, optional
|
|
||||||
h?: string; // help text, optional
|
|
||||||
nodes?: DashboardItem[]; // nodes, optional
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DashboardData {
|
export interface DashboardData {
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ import {
|
|||||||
useLayoutTitle
|
useLayoutTitle
|
||||||
} from 'components';
|
} from 'components';
|
||||||
import { useI18nContext } from 'i18n/i18n-react';
|
import { useI18nContext } from 'i18n/i18n-react';
|
||||||
import { saveFile } from 'utils/file';
|
import { saveFile } from 'utils';
|
||||||
|
|
||||||
const DownloadUpload = () => {
|
const DownloadUpload = () => {
|
||||||
const { LL } = useI18nContext();
|
const { LL } = useI18nContext();
|
||||||
@@ -221,7 +221,7 @@ const DownloadUpload = () => {
|
|||||||
{LL.DOWNLOAD(0)}
|
{LL.DOWNLOAD(0)}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
<Typography mb={1} variant="body2" color="warning">
|
<Typography mb={1} variant="body1" color="warning">
|
||||||
{LL.DOWNLOAD_SETTINGS_TEXT()}
|
{LL.DOWNLOAD_SETTINGS_TEXT()}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Grid container spacing={1}>
|
<Grid container spacing={1}>
|
||||||
@@ -269,7 +269,7 @@ const DownloadUpload = () => {
|
|||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
<Box color="warning.main" sx={{ pb: 2 }}>
|
<Box color="warning.main" sx={{ pb: 2 }}>
|
||||||
<Typography variant="body2">{LL.UPLOAD_TEXT()}</Typography>
|
<Typography variant="body1">{LL.UPLOAD_TEXT()}</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<SingleUpload doRestart={doRestart} />
|
<SingleUpload doRestart={doRestart} />
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ const APStatus = () => {
|
|||||||
data,
|
data,
|
||||||
send: loadData,
|
send: loadData,
|
||||||
error
|
error
|
||||||
} = useAutoRequest(APApi.readAPStatus, { pollingTime: 5000 });
|
} = useAutoRequest(APApi.readAPStatus, { pollingTime: 3000 });
|
||||||
|
|
||||||
const { LL } = useI18nContext();
|
const { LL } = useI18nContext();
|
||||||
useLayoutTitle(LL.STATUS_OF(LL.ACCESS_POINT(0)));
|
useLayoutTitle(LL.STATUS_OF(LL.ACCESS_POINT(0)));
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ const SystemActivity = () => {
|
|||||||
data,
|
data,
|
||||||
send: loadData,
|
send: loadData,
|
||||||
error
|
error
|
||||||
} = useAutoRequest(readActivity, { pollingTime: 2000 });
|
} = useAutoRequest(readActivity, { pollingTime: 3000 });
|
||||||
|
|
||||||
const { LL } = useI18nContext();
|
const { LL } = useI18nContext();
|
||||||
|
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ const HardwareStatus = () => {
|
|||||||
data,
|
data,
|
||||||
send: loadData,
|
send: loadData,
|
||||||
error
|
error
|
||||||
} = useAutoRequest(SystemApi.readSystemStatus, { pollingTime: 2000 });
|
} = useAutoRequest(SystemApi.readSystemStatus, { pollingTime: 3000 });
|
||||||
|
|
||||||
const content = () => {
|
const content = () => {
|
||||||
if (!data) {
|
if (!data) {
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ const MqttStatus = () => {
|
|||||||
data,
|
data,
|
||||||
send: loadData,
|
send: loadData,
|
||||||
error
|
error
|
||||||
} = useAutoRequest(MqttApi.readMqttStatus, { pollingTime: 5000 });
|
} = useAutoRequest(MqttApi.readMqttStatus, { pollingTime: 3000 });
|
||||||
|
|
||||||
const { LL } = useI18nContext();
|
const { LL } = useI18nContext();
|
||||||
useLayoutTitle(LL.STATUS_OF('MQTT'));
|
useLayoutTitle(LL.STATUS_OF('MQTT'));
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ const NTPStatus = () => {
|
|||||||
data,
|
data,
|
||||||
send: loadData,
|
send: loadData,
|
||||||
error
|
error
|
||||||
} = useAutoRequest(NTPApi.readNTPStatus, { pollingTime: 5000 });
|
} = useAutoRequest(NTPApi.readNTPStatus, { pollingTime: 3000 });
|
||||||
|
|
||||||
const [localTime, setLocalTime] = useState<string>('');
|
const [localTime, setLocalTime] = useState<string>('');
|
||||||
const [settingTime, setSettingTime] = useState<boolean>(false);
|
const [settingTime, setSettingTime] = useState<boolean>(false);
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ const NetworkStatus = () => {
|
|||||||
data,
|
data,
|
||||||
send: loadData,
|
send: loadData,
|
||||||
error
|
error
|
||||||
} = useAutoRequest(NetworkApi.readNetworkStatus, { pollingTime: 5000 });
|
} = useAutoRequest(NetworkApi.readNetworkStatus, { pollingTime: 3000 });
|
||||||
|
|
||||||
const { LL } = useI18nContext();
|
const { LL } = useI18nContext();
|
||||||
useLayoutTitle(LL.STATUS_OF(LL.NETWORK(1)));
|
useLayoutTitle(LL.STATUS_OF(LL.NETWORK(1)));
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ const RestartMonitor = () => {
|
|||||||
initialData: { status: 'Getting ready...' },
|
initialData: { status: 'Getting ready...' },
|
||||||
async middleware(_, next) {
|
async middleware(_, next) {
|
||||||
if (count++ >= 1) {
|
if (count++ >= 1) {
|
||||||
// skip first request (1 seconds) to allow AsyncWS to send its response
|
// skip first request (1 second) to allow AsyncWS to send its response
|
||||||
await next();
|
await next();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ const SystemStatus = () => {
|
|||||||
error
|
error
|
||||||
} = useAutoRequest(readSystemStatus, {
|
} = useAutoRequest(readSystemStatus, {
|
||||||
initialData: [],
|
initialData: [],
|
||||||
pollingTime: 5000,
|
pollingTime: 3000,
|
||||||
async middleware(_, next) {
|
async middleware(_, next) {
|
||||||
if (!restarting) {
|
if (!restarting) {
|
||||||
await next();
|
await next();
|
||||||
|
|||||||
@@ -340,7 +340,10 @@ const de: Translation = {
|
|||||||
PLEASE_WAIT: 'Bitte warten',
|
PLEASE_WAIT: 'Bitte warten',
|
||||||
RESTARTING_PRE: 'Initialisierung',
|
RESTARTING_PRE: 'Initialisierung',
|
||||||
RESTARTING_POST: 'Vorbereitung',
|
RESTARTING_POST: 'Vorbereitung',
|
||||||
AUTO_SCROLL: 'Automatisches Scrollen'
|
AUTO_SCROLL: 'Automatisches Scrollen',
|
||||||
|
DASHBOARD: 'Dashboard', // TODO translate
|
||||||
|
NO_DATA: 'No data available', // TODO translate
|
||||||
|
DASHBOARD_1: 'Customize your dashboard by marking EMS entities as Favorites using the Customizations module.' // TODO translate
|
||||||
};
|
};
|
||||||
|
|
||||||
export default de;
|
export default de;
|
||||||
|
|||||||
@@ -340,7 +340,10 @@ const en: Translation = {
|
|||||||
PLEASE_WAIT: 'Please wait',
|
PLEASE_WAIT: 'Please wait',
|
||||||
RESTARTING_PRE: 'Initializing',
|
RESTARTING_PRE: 'Initializing',
|
||||||
RESTARTING_POST: 'Preparing',
|
RESTARTING_POST: 'Preparing',
|
||||||
AUTO_SCROLL: 'Auto Scroll'
|
AUTO_SCROLL: 'Auto Scroll',
|
||||||
|
DASHBOARD: 'Dashboard',
|
||||||
|
NO_DATA: 'No data available',
|
||||||
|
DASHBOARD_1: 'Customize your dashboard by marking EMS entities as Favorites using the Customizations module.',
|
||||||
};
|
};
|
||||||
|
|
||||||
export default en;
|
export default en;
|
||||||
|
|||||||
@@ -340,7 +340,10 @@ const fr: Translation = {
|
|||||||
PLEASE_WAIT: 'Please wait', // TODO translate
|
PLEASE_WAIT: 'Please wait', // TODO translate
|
||||||
RESTARTING_PRE: 'Initializing', // TODO translate
|
RESTARTING_PRE: 'Initializing', // TODO translate
|
||||||
RESTARTING_POST: 'Preparing', // TODO translate
|
RESTARTING_POST: 'Preparing', // TODO translate
|
||||||
AUTO_SCROLL: 'Auto Scroll' // TODO translate
|
AUTO_SCROLL: 'Auto Scroll', // TODO translate
|
||||||
|
DASHBOARD: 'Dashboard', // TODO translate
|
||||||
|
NO_DATA: 'No data available', // TODO translate
|
||||||
|
DASHBOARD_1: 'Customize your dashboard by marking EMS entities as Favorites using the Customizations module.' // TODO translate
|
||||||
};
|
};
|
||||||
|
|
||||||
export default fr;
|
export default fr;
|
||||||
|
|||||||
@@ -340,7 +340,10 @@ const it: Translation = {
|
|||||||
PLEASE_WAIT: 'Please wait', // TODO translate
|
PLEASE_WAIT: 'Please wait', // TODO translate
|
||||||
RESTARTING_PRE: 'Initializing', // TODO translate
|
RESTARTING_PRE: 'Initializing', // TODO translate
|
||||||
RESTARTING_POST: 'Preparing', // TODO translate
|
RESTARTING_POST: 'Preparing', // TODO translate
|
||||||
AUTO_SCROLL: 'Auto Scroll' // TODO translate
|
AUTO_SCROLL: 'Auto Scroll', // TODO translate
|
||||||
|
DASHBOARD: 'Dashboard', // TODO translate
|
||||||
|
NO_DATA: 'No data available', // TODO translate
|
||||||
|
DASHBOARD_1: 'Customize your dashboard by marking EMS entities as Favorites using the Customizations module.' // TODO translate
|
||||||
};
|
};
|
||||||
|
|
||||||
export default it;
|
export default it;
|
||||||
|
|||||||
@@ -340,7 +340,10 @@ const nl: Translation = {
|
|||||||
PLEASE_WAIT: 'Please wait', // TODO translate
|
PLEASE_WAIT: 'Please wait', // TODO translate
|
||||||
RESTARTING_PRE: 'Initializing', // TODO translate
|
RESTARTING_PRE: 'Initializing', // TODO translate
|
||||||
RESTARTING_POST: 'Preparing', // TODO translate
|
RESTARTING_POST: 'Preparing', // TODO translate
|
||||||
AUTO_SCROLL: 'Auto Scroll' // TODO translate
|
AUTO_SCROLL: 'Auto Scroll', // TODO translate
|
||||||
|
DASHBOARD: 'Dashboard', // TODO translate
|
||||||
|
NO_DATA: 'No data available', // TODO translate
|
||||||
|
DASHBOARD_1: 'Customize your dashboard by marking EMS entities as Favorites using the Customizations module.' // TODO translate
|
||||||
};
|
};
|
||||||
|
|
||||||
export default nl;
|
export default nl;
|
||||||
|
|||||||
@@ -340,7 +340,10 @@ const no: Translation = {
|
|||||||
PLEASE_WAIT: 'Please wait', // TODO translate
|
PLEASE_WAIT: 'Please wait', // TODO translate
|
||||||
RESTARTING_PRE: 'Initializing', // TODO translate
|
RESTARTING_PRE: 'Initializing', // TODO translate
|
||||||
RESTARTING_POST: 'Preparing', // TODO translate
|
RESTARTING_POST: 'Preparing', // TODO translate
|
||||||
AUTO_SCROLL: 'Auto Scroll' // TODO translate
|
AUTO_SCROLL: 'Auto Scroll', // TODO translate
|
||||||
|
DASHBOARD: 'Dashboard', // TODO translate
|
||||||
|
NO_DATA: 'No data available', // TODO translate
|
||||||
|
DASHBOARD_1: 'Customize your dashboard by marking EMS entities as Favorites using the Customizations module.' // TODO translate
|
||||||
};
|
};
|
||||||
|
|
||||||
export default no;
|
export default no;
|
||||||
|
|||||||
@@ -340,7 +340,10 @@ const pl: BaseTranslation = {
|
|||||||
PLEASE_WAIT: 'Please wait', // TODO translate
|
PLEASE_WAIT: 'Please wait', // TODO translate
|
||||||
RESTARTING_PRE: 'Initializing', // TODO translate
|
RESTARTING_PRE: 'Initializing', // TODO translate
|
||||||
RESTARTING_POST: 'Preparing', // TODO translate
|
RESTARTING_POST: 'Preparing', // TODO translate
|
||||||
AUTO_SCROLL: 'Auto Scroll' // TODO translate
|
AUTO_SCROLL: 'Auto Scroll', // TODO translate
|
||||||
|
DASHBOARD: 'Dashboard', // TODO translate
|
||||||
|
NO_DATA: 'No data available', // TODO translate
|
||||||
|
DASHBOARD_1: 'Customize your dashboard by marking EMS entities as Favorites using the Customizations module.' // TODO translate
|
||||||
};
|
};
|
||||||
|
|
||||||
export default pl;
|
export default pl;
|
||||||
|
|||||||
@@ -340,7 +340,10 @@ const sk: Translation = {
|
|||||||
PLEASE_WAIT: 'Čakajte prosím',
|
PLEASE_WAIT: 'Čakajte prosím',
|
||||||
RESTARTING_PRE: 'Prebieha inicializácia',
|
RESTARTING_PRE: 'Prebieha inicializácia',
|
||||||
RESTARTING_POST: 'Príprava',
|
RESTARTING_POST: 'Príprava',
|
||||||
AUTO_SCROLL: 'Auto Scroll' // TODO translate
|
AUTO_SCROLL: 'Auto Scroll', // TODO translate
|
||||||
|
DASHBOARD: 'Dashboard', // TODO translate
|
||||||
|
NO_DATA: 'No data available', // TODO translate
|
||||||
|
DASHBOARD_1: 'Customize your dashboard by marking EMS entities as Favorites using the Customizations module.' // TODO translate
|
||||||
};
|
};
|
||||||
|
|
||||||
export default sk;
|
export default sk;
|
||||||
|
|||||||
@@ -340,7 +340,10 @@ const sv: Translation = {
|
|||||||
PLEASE_WAIT: 'Please wait', // TODO translate
|
PLEASE_WAIT: 'Please wait', // TODO translate
|
||||||
RESTARTING_PRE: 'Initializing', // TODO translate
|
RESTARTING_PRE: 'Initializing', // TODO translate
|
||||||
RESTARTING_POST: 'Preparing', // TODO translate
|
RESTARTING_POST: 'Preparing', // TODO translate
|
||||||
AUTO_SCROLL: 'Auto Scroll' // TODO translate
|
AUTO_SCROLL: 'Auto Scroll', // TODO translate
|
||||||
|
DASHBOARD: 'Dashboard', // TODO translate
|
||||||
|
NO_DATA: 'No data available', // TODO translate
|
||||||
|
DASHBOARD_1: 'Customize your dashboard by marking EMS entities as Favorites using the Customizations module.' // TODO translate
|
||||||
};
|
};
|
||||||
|
|
||||||
export default sv;
|
export default sv;
|
||||||
|
|||||||
@@ -340,7 +340,10 @@ const tr: Translation = {
|
|||||||
PLEASE_WAIT: 'Please wait', // TODO translate
|
PLEASE_WAIT: 'Please wait', // TODO translate
|
||||||
RESTARTING_PRE: 'Initializing', // TODO translate
|
RESTARTING_PRE: 'Initializing', // TODO translate
|
||||||
RESTARTING_POST: 'Preparing', // TODO translate
|
RESTARTING_POST: 'Preparing', // TODO translate
|
||||||
AUTO_SCROLL: 'Auto Scroll' // TODO translate
|
AUTO_SCROLL: 'Auto Scroll', // TODO translate
|
||||||
|
DASHBOARD: 'Dashboard', // TODO translate
|
||||||
|
NO_DATA: 'No data available', // TODO translate
|
||||||
|
DASHBOARD_1: 'Customize your dashboard by marking EMS entities as Favorites using the Customizations module.' // TODO translate
|
||||||
};
|
};
|
||||||
|
|
||||||
export default tr;
|
export default tr;
|
||||||
|
|||||||
@@ -3,4 +3,6 @@ export * from './route';
|
|||||||
export * from './submit';
|
export * from './submit';
|
||||||
export * from './time';
|
export * from './time';
|
||||||
export * from './useRest';
|
export * from './useRest';
|
||||||
|
export * from './useInterval';
|
||||||
export * from './props';
|
export * from './props';
|
||||||
|
export * from './file';
|
||||||
|
|||||||
22
interface/src/utils/useInterval.ts
Normal file
22
interface/src/utils/useInterval.ts
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import { useEffect, useRef } from 'react';
|
||||||
|
|
||||||
|
// adapted from https://www.joshwcomeau.com/snippets/react-hooks/use-interval/
|
||||||
|
export const useInterval = (callback: () => void, delay: number) => {
|
||||||
|
const intervalRef = useRef<number | null>(null);
|
||||||
|
const savedCallback = useRef<() => void>(callback);
|
||||||
|
useEffect(() => {
|
||||||
|
savedCallback.current = callback;
|
||||||
|
}, [callback]);
|
||||||
|
useEffect(() => {
|
||||||
|
const tick = () => savedCallback.current();
|
||||||
|
if (typeof delay === 'number') {
|
||||||
|
intervalRef.current = window.setInterval(tick, delay);
|
||||||
|
return () => {
|
||||||
|
if (intervalRef.current !== null) {
|
||||||
|
window.clearInterval(intervalRef.current);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}, [delay]);
|
||||||
|
return intervalRef;
|
||||||
|
};
|
||||||
@@ -918,10 +918,10 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@eslint/js@npm:9.11.1, @eslint/js@npm:^9.11.1":
|
"@eslint/js@npm:9.12.0, @eslint/js@npm:^9.12.0":
|
||||||
version: 9.11.1
|
version: 9.12.0
|
||||||
resolution: "@eslint/js@npm:9.11.1"
|
resolution: "@eslint/js@npm:9.12.0"
|
||||||
checksum: 10c0/22916ef7b09c6f60c62635d897c66e1e3e38d90b5a5cf5e62769033472ecbcfb6ec7c886090a4b32fe65d6ce371da54384e46c26a899e38184dfc152c6152f7b
|
checksum: 10c0/325650a59a1ce3d97c69441501ebaf415607248bacbe8c8ca35adc7cb73b524f592f266a75772f496b06f3239e3ee1996722a242148085f0ee5fb3dd7065897c
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -941,6 +941,23 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"@humanfs/core@npm:^0.19.0":
|
||||||
|
version: 0.19.0
|
||||||
|
resolution: "@humanfs/core@npm:0.19.0"
|
||||||
|
checksum: 10c0/f87952d5caba6ae427a620eff783c5d0b6cef0cfc256dec359cdaa636c5f161edb8d8dad576742b3de7f0b2f222b34aad6870248e4b7d2177f013426cbcda232
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
|
"@humanfs/node@npm:^0.16.5":
|
||||||
|
version: 0.16.5
|
||||||
|
resolution: "@humanfs/node@npm:0.16.5"
|
||||||
|
dependencies:
|
||||||
|
"@humanfs/core": "npm:^0.19.0"
|
||||||
|
"@humanwhocodes/retry": "npm:^0.3.0"
|
||||||
|
checksum: 10c0/41c365ab09e7c9eaeed373d09243195aef616d6745608a36fc3e44506148c28843872f85e69e2bf5f1e992e194286155a1c1cecfcece6a2f43875e37cd243935
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"@humanwhocodes/module-importer@npm:^1.0.1":
|
"@humanwhocodes/module-importer@npm:^1.0.1":
|
||||||
version: 1.0.1
|
version: 1.0.1
|
||||||
resolution: "@humanwhocodes/module-importer@npm:1.0.1"
|
resolution: "@humanwhocodes/module-importer@npm:1.0.1"
|
||||||
@@ -955,6 +972,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"@humanwhocodes/retry@npm:^0.3.1":
|
||||||
|
version: 0.3.1
|
||||||
|
resolution: "@humanwhocodes/retry@npm:0.3.1"
|
||||||
|
checksum: 10c0/f0da1282dfb45e8120480b9e2e275e2ac9bbe1cf016d046fdad8e27cc1285c45bb9e711681237944445157b430093412b4446c1ab3fc4bb037861b5904101d3b
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"@isaacs/cliui@npm:^8.0.2":
|
"@isaacs/cliui@npm:^8.0.2":
|
||||||
version: 8.0.2
|
version: 8.0.2
|
||||||
resolution: "@isaacs/cliui@npm:8.0.2"
|
resolution: "@isaacs/cliui@npm:8.0.2"
|
||||||
@@ -1196,7 +1220,7 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@nodelib/fs.walk@npm:^1.2.3, @nodelib/fs.walk@npm:^1.2.8":
|
"@nodelib/fs.walk@npm:^1.2.3":
|
||||||
version: 1.2.8
|
version: 1.2.8
|
||||||
resolution: "@nodelib/fs.walk@npm:1.2.8"
|
resolution: "@nodelib/fs.walk@npm:1.2.8"
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -1844,7 +1868,7 @@ __metadata:
|
|||||||
"@babel/core": "npm:^7.25.7"
|
"@babel/core": "npm:^7.25.7"
|
||||||
"@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.11.1"
|
"@eslint/js": "npm:^9.12.0"
|
||||||
"@mui/icons-material": "npm:^6.1.2"
|
"@mui/icons-material": "npm:^6.1.2"
|
||||||
"@mui/material": "npm:^6.1.2"
|
"@mui/material": "npm:^6.1.2"
|
||||||
"@preact/compat": "npm:^18.3.1"
|
"@preact/compat": "npm:^18.3.1"
|
||||||
@@ -1859,7 +1883,7 @@ __metadata:
|
|||||||
alova: "npm:3.0.17"
|
alova: "npm:3.0.17"
|
||||||
async-validator: "npm:^4.2.5"
|
async-validator: "npm:^4.2.5"
|
||||||
concurrently: "npm:^9.0.1"
|
concurrently: "npm:^9.0.1"
|
||||||
eslint: "npm:^9.11.1"
|
eslint: "npm:^9.12.0"
|
||||||
eslint-config-prettier: "npm:^9.1.0"
|
eslint-config-prettier: "npm:^9.1.0"
|
||||||
formidable: "npm:^3.5.1"
|
formidable: "npm:^3.5.1"
|
||||||
jwt-decode: "npm:^4.0.0"
|
jwt-decode: "npm:^4.0.0"
|
||||||
@@ -3322,7 +3346,7 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"eslint-scope@npm:^8.0.2":
|
"eslint-scope@npm:^8.1.0":
|
||||||
version: 8.1.0
|
version: 8.1.0
|
||||||
resolution: "eslint-scope@npm:8.1.0"
|
resolution: "eslint-scope@npm:8.1.0"
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -3339,27 +3363,27 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"eslint-visitor-keys@npm:^4.0.0, eslint-visitor-keys@npm:^4.1.0":
|
"eslint-visitor-keys@npm:^4.1.0":
|
||||||
version: 4.1.0
|
version: 4.1.0
|
||||||
resolution: "eslint-visitor-keys@npm:4.1.0"
|
resolution: "eslint-visitor-keys@npm:4.1.0"
|
||||||
checksum: 10c0/5483ef114c93a136aa234140d7aa3bd259488dae866d35cb0d0b52e6a158f614760a57256ac8d549acc590a87042cb40f6951815caa821e55dc4fd6ef4c722eb
|
checksum: 10c0/5483ef114c93a136aa234140d7aa3bd259488dae866d35cb0d0b52e6a158f614760a57256ac8d549acc590a87042cb40f6951815caa821e55dc4fd6ef4c722eb
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"eslint@npm:^9.11.1":
|
"eslint@npm:^9.12.0":
|
||||||
version: 9.11.1
|
version: 9.12.0
|
||||||
resolution: "eslint@npm:9.11.1"
|
resolution: "eslint@npm:9.12.0"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@eslint-community/eslint-utils": "npm:^4.2.0"
|
"@eslint-community/eslint-utils": "npm:^4.2.0"
|
||||||
"@eslint-community/regexpp": "npm:^4.11.0"
|
"@eslint-community/regexpp": "npm:^4.11.0"
|
||||||
"@eslint/config-array": "npm:^0.18.0"
|
"@eslint/config-array": "npm:^0.18.0"
|
||||||
"@eslint/core": "npm:^0.6.0"
|
"@eslint/core": "npm:^0.6.0"
|
||||||
"@eslint/eslintrc": "npm:^3.1.0"
|
"@eslint/eslintrc": "npm:^3.1.0"
|
||||||
"@eslint/js": "npm:9.11.1"
|
"@eslint/js": "npm:9.12.0"
|
||||||
"@eslint/plugin-kit": "npm:^0.2.0"
|
"@eslint/plugin-kit": "npm:^0.2.0"
|
||||||
|
"@humanfs/node": "npm:^0.16.5"
|
||||||
"@humanwhocodes/module-importer": "npm:^1.0.1"
|
"@humanwhocodes/module-importer": "npm:^1.0.1"
|
||||||
"@humanwhocodes/retry": "npm:^0.3.0"
|
"@humanwhocodes/retry": "npm:^0.3.1"
|
||||||
"@nodelib/fs.walk": "npm:^1.2.8"
|
|
||||||
"@types/estree": "npm:^1.0.6"
|
"@types/estree": "npm:^1.0.6"
|
||||||
"@types/json-schema": "npm:^7.0.15"
|
"@types/json-schema": "npm:^7.0.15"
|
||||||
ajv: "npm:^6.12.4"
|
ajv: "npm:^6.12.4"
|
||||||
@@ -3367,9 +3391,9 @@ __metadata:
|
|||||||
cross-spawn: "npm:^7.0.2"
|
cross-spawn: "npm:^7.0.2"
|
||||||
debug: "npm:^4.3.2"
|
debug: "npm:^4.3.2"
|
||||||
escape-string-regexp: "npm:^4.0.0"
|
escape-string-regexp: "npm:^4.0.0"
|
||||||
eslint-scope: "npm:^8.0.2"
|
eslint-scope: "npm:^8.1.0"
|
||||||
eslint-visitor-keys: "npm:^4.0.0"
|
eslint-visitor-keys: "npm:^4.1.0"
|
||||||
espree: "npm:^10.1.0"
|
espree: "npm:^10.2.0"
|
||||||
esquery: "npm:^1.5.0"
|
esquery: "npm:^1.5.0"
|
||||||
esutils: "npm:^2.0.2"
|
esutils: "npm:^2.0.2"
|
||||||
fast-deep-equal: "npm:^3.1.3"
|
fast-deep-equal: "npm:^3.1.3"
|
||||||
@@ -3379,13 +3403,11 @@ __metadata:
|
|||||||
ignore: "npm:^5.2.0"
|
ignore: "npm:^5.2.0"
|
||||||
imurmurhash: "npm:^0.1.4"
|
imurmurhash: "npm:^0.1.4"
|
||||||
is-glob: "npm:^4.0.0"
|
is-glob: "npm:^4.0.0"
|
||||||
is-path-inside: "npm:^3.0.3"
|
|
||||||
json-stable-stringify-without-jsonify: "npm:^1.0.1"
|
json-stable-stringify-without-jsonify: "npm:^1.0.1"
|
||||||
lodash.merge: "npm:^4.6.2"
|
lodash.merge: "npm:^4.6.2"
|
||||||
minimatch: "npm:^3.1.2"
|
minimatch: "npm:^3.1.2"
|
||||||
natural-compare: "npm:^1.4.0"
|
natural-compare: "npm:^1.4.0"
|
||||||
optionator: "npm:^0.9.3"
|
optionator: "npm:^0.9.3"
|
||||||
strip-ansi: "npm:^6.0.1"
|
|
||||||
text-table: "npm:^0.2.0"
|
text-table: "npm:^0.2.0"
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
jiti: "*"
|
jiti: "*"
|
||||||
@@ -3394,11 +3416,11 @@ __metadata:
|
|||||||
optional: true
|
optional: true
|
||||||
bin:
|
bin:
|
||||||
eslint: bin/eslint.js
|
eslint: bin/eslint.js
|
||||||
checksum: 10c0/fc9afc31155fef8c27fc4fd00669aeafa4b89ce5abfbf6f60e05482c03d7ff1d5e7546e416aa47bf0f28c9a56597a94663fd0264c2c42a1890f53cac49189f24
|
checksum: 10c0/67cf6ea3ea28dcda7dd54aac33e2d4028eb36991d13defb0d2339c3eaa877d5dddd12cd4416ddc701a68bcde9e0bb9e65524c2e4e9914992c724f5b51e949dda
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"espree@npm:^10.0.1, espree@npm:^10.1.0":
|
"espree@npm:^10.0.1, espree@npm:^10.2.0":
|
||||||
version: 10.2.0
|
version: 10.2.0
|
||||||
resolution: "espree@npm:10.2.0"
|
resolution: "espree@npm:10.2.0"
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -4552,13 +4574,6 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"is-path-inside@npm:^3.0.3":
|
|
||||||
version: 3.0.3
|
|
||||||
resolution: "is-path-inside@npm:3.0.3"
|
|
||||||
checksum: 10c0/cf7d4ac35fb96bab6a1d2c3598fe5ebb29aafb52c0aaa482b5a3ed9d8ba3edc11631e3ec2637660c44b3ce0e61a08d54946e8af30dec0b60a7c27296c68ffd05
|
|
||||||
languageName: node
|
|
||||||
linkType: hard
|
|
||||||
|
|
||||||
"is-plain-obj@npm:^1.0.0, is-plain-obj@npm:^1.1.0":
|
"is-plain-obj@npm:^1.0.0, is-plain-obj@npm:^1.1.0":
|
||||||
version: 1.1.0
|
version: 1.1.0
|
||||||
resolution: "is-plain-obj@npm:1.1.0"
|
resolution: "is-plain-obj@npm:1.1.0"
|
||||||
|
|||||||
@@ -4294,31 +4294,19 @@ function getDashboardEntityData(id: number) {
|
|||||||
else if (id == 10) device_data = emsesp_devicedata_10;
|
else if (id == 10) device_data = emsesp_devicedata_10;
|
||||||
else if (id == 99) device_data = emsesp_devicedata_99;
|
else if (id == 99) device_data = emsesp_devicedata_99;
|
||||||
|
|
||||||
// filter device_data
|
// filter device_data on
|
||||||
// and only favorite items (bit 8 set), only for non-Custom Entities
|
// - only add favorite (mask has bit 8 set) except for Custom Entities (type 99)
|
||||||
// and replace id by striping off the 2-char mask
|
|
||||||
let new_data = (device_data as any).data
|
let new_data = (device_data as any).data
|
||||||
.map(({ id, m, x, s, ...rest }) => ({
|
.filter((item) => id === 99 || parseInt(item.id.slice(0, 2), 16) & 0x08)
|
||||||
...rest,
|
|
||||||
id2: id
|
|
||||||
}))
|
|
||||||
.filter((item) => id === 99 || parseInt(item.id2.slice(0, 2), 16) & 0x08)
|
|
||||||
.map((item, index) => ({
|
.map((item, index) => ({
|
||||||
id: id * 100 + index, // unique id
|
id: id * 100 + index, // mandatory unique id for table
|
||||||
n: item.id2.slice(2), // name
|
dv: item // devicevalue
|
||||||
v: item.v, // value
|
|
||||||
u: item.u, // uom
|
|
||||||
c: item.c, // command
|
|
||||||
l: item.l, // list
|
|
||||||
h: item.h // help
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// TODO only and command if not marked as READONLY
|
|
||||||
|
|
||||||
return new_data;
|
return new_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Router starts here...
|
// Router routing starts here...
|
||||||
router
|
router
|
||||||
// EMS-ESP Settings
|
// EMS-ESP Settings
|
||||||
.get(EMSESP_SETTINGS_ENDPOINT, () => settings)
|
.get(EMSESP_SETTINGS_ENDPOINT, () => settings)
|
||||||
@@ -4360,8 +4348,10 @@ router
|
|||||||
[];
|
[];
|
||||||
let dashboard_object: { id?: number; n?: string; t?: number; nodes?: any[] } =
|
let dashboard_object: { id?: number; n?: string; t?: number; nodes?: any[] } =
|
||||||
{};
|
{};
|
||||||
|
|
||||||
let fake = false;
|
let fake = false;
|
||||||
// let fake = true; // fakes no data
|
|
||||||
|
fake = true; // for testing
|
||||||
|
|
||||||
if (!fake) {
|
if (!fake) {
|
||||||
// pick EMS devices from coredata
|
// pick EMS devices from coredata
|
||||||
@@ -4397,9 +4387,11 @@ router
|
|||||||
let sensor_data: any[] = [];
|
let sensor_data: any[] = [];
|
||||||
sensor_data = emsesp_sensordata.ts.map((item, index) => ({
|
sensor_data = emsesp_sensordata.ts.map((item, index) => ({
|
||||||
id: 980 + index,
|
id: 980 + index,
|
||||||
n: item.n ? item.n : item.id, // name may not be set
|
dv: {
|
||||||
v: item.t ? item.t : undefined, // can have no value
|
id: ' ' + item.n,
|
||||||
u: item.u
|
v: item.t, // value is called t in ts (temperature)
|
||||||
|
u: item.u
|
||||||
|
}
|
||||||
}));
|
}));
|
||||||
dashboard_object = {
|
dashboard_object = {
|
||||||
id: 98,
|
id: 98,
|
||||||
@@ -4417,9 +4409,11 @@ router
|
|||||||
sensor_data = emsesp_sensordata.as.filter((item) => item.t !== 0);
|
sensor_data = emsesp_sensordata.as.filter((item) => item.t !== 0);
|
||||||
sensor_data = sensor_data.map((item, index) => ({
|
sensor_data = sensor_data.map((item, index) => ({
|
||||||
id: 970 + index,
|
id: 970 + index,
|
||||||
n: item.n,
|
dv: {
|
||||||
v: item.v,
|
id: ' ' + item.n,
|
||||||
u: item.u
|
v: item.v,
|
||||||
|
u: item.u
|
||||||
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
dashboard_object = {
|
dashboard_object = {
|
||||||
@@ -4432,9 +4426,24 @@ router
|
|||||||
if ((dashboard_object.nodes ?? []).length > 0) {
|
if ((dashboard_object.nodes ?? []).length > 0) {
|
||||||
dashboard_data.push(dashboard_object);
|
dashboard_data.push(dashboard_object);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// for testing
|
||||||
|
// single object
|
||||||
|
// const element = emsesp_coredata.devices[3]; // pick the 4th device
|
||||||
|
// const id = element.id;
|
||||||
|
// dashboard_object = {
|
||||||
|
// id: id,
|
||||||
|
// n: element.n,
|
||||||
|
// t: element.t,
|
||||||
|
// nodes: getDashboardEntityData(id)
|
||||||
|
// };
|
||||||
|
// if ((dashboard_object.nodes ?? []).length > 0) {
|
||||||
|
// dashboard_data.push(dashboard_object);
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
// console.log('dashboard_data: ', dashboard_data);
|
// console.log('dashboard_data: ', dashboard_data);
|
||||||
|
// return dashboard_data; // if not using msgpack
|
||||||
return new Response(encoder.encode(dashboard_data), { headers }); // msgpack it
|
return new Response(encoder.encode(dashboard_data), { headers }); // msgpack it
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -4570,7 +4579,9 @@ router
|
|||||||
}
|
}
|
||||||
|
|
||||||
// await delay(1000); // wait to show spinner
|
// await delay(1000); // wait to show spinner
|
||||||
console.log('device value saved', content);
|
console.log(
|
||||||
|
'Device Value updated. command:' + command + ' value:' + value + ' id:' + id
|
||||||
|
);
|
||||||
return status(200);
|
return status(200);
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user