mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-06 15:59:52 +03:00
Merge pull request #2303 from proddy/dev
show ntp time in status, use useInterval everywhere instead of alova'…
This commit is contained in:
@@ -35,7 +35,7 @@
|
||||
"react": "^19.0.0",
|
||||
"react-dom": "^19.0.0",
|
||||
"react-icons": "^5.4.0",
|
||||
"react-router": "^7.0.2",
|
||||
"react-router": "^7.1.0",
|
||||
"react-toastify": "^11.0.2",
|
||||
"typesafe-i18n": "^5.26.2",
|
||||
"typescript": "^5.7.2"
|
||||
|
||||
@@ -57,7 +57,7 @@ const CustomEntities = () => {
|
||||
if (!dialogOpen && !numChanges) {
|
||||
void fetchEntities();
|
||||
}
|
||||
}, 3000);
|
||||
});
|
||||
|
||||
const { send: writeEntities } = useRequest(
|
||||
(data: Entities) => writeCustomEntities(data),
|
||||
|
||||
@@ -149,7 +149,7 @@ const Dashboard = () => {
|
||||
if (!deviceValueDialogOpen) {
|
||||
void fetchDashboard();
|
||||
}
|
||||
}, 3000);
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
showAll
|
||||
|
||||
@@ -419,7 +419,7 @@ const Devices = () => {
|
||||
if (!deviceValueDialogOpen) {
|
||||
selectedDevice ? void sendDeviceData(selectedDevice) : void sendCoreData();
|
||||
}
|
||||
}, 3000);
|
||||
});
|
||||
|
||||
const deviceValueDialogSave = async (devicevalue: DeviceValue) => {
|
||||
const id = Number(device_select.state.id);
|
||||
|
||||
@@ -90,7 +90,7 @@ const Sensors = () => {
|
||||
if (!temperatureDialogOpen && !analogDialogOpen) {
|
||||
void fetchSensorData();
|
||||
}
|
||||
}, 3000);
|
||||
});
|
||||
|
||||
const common_theme = useTheme({
|
||||
BaseRow: `
|
||||
|
||||
@@ -14,11 +14,12 @@ import type { Theme } from '@mui/material';
|
||||
|
||||
import * as APApi from 'api/ap';
|
||||
|
||||
import { useAutoRequest } from 'alova/client';
|
||||
import { useRequest } from 'alova/client';
|
||||
import { FormLoader, SectionContent, useLayoutTitle } from 'components';
|
||||
import { useI18nContext } from 'i18n/i18n-react';
|
||||
import type { APStatusType } from 'types';
|
||||
import { APNetworkStatus } from 'types';
|
||||
import { useInterval } from 'utils';
|
||||
|
||||
export const apStatusHighlight = ({ status }: APStatusType, theme: Theme) => {
|
||||
switch (status) {
|
||||
@@ -34,11 +35,11 @@ export const apStatusHighlight = ({ status }: APStatusType, theme: Theme) => {
|
||||
};
|
||||
|
||||
const APStatus = () => {
|
||||
const {
|
||||
data,
|
||||
send: loadData,
|
||||
error
|
||||
} = useAutoRequest(APApi.readAPStatus, { pollingTime: 3000 });
|
||||
const { data, send: loadData, error } = useRequest(APApi.readAPStatus);
|
||||
|
||||
useInterval(() => {
|
||||
void loadData();
|
||||
});
|
||||
|
||||
const { LL } = useI18nContext();
|
||||
useLayoutTitle(LL.ACCESS_POINT(0));
|
||||
|
||||
@@ -8,20 +8,21 @@ import {
|
||||
Table
|
||||
} from '@table-library/react-table-library/table';
|
||||
import { useTheme as tableTheme } from '@table-library/react-table-library/theme';
|
||||
import { useAutoRequest } from 'alova/client';
|
||||
import { useRequest } from 'alova/client';
|
||||
import { FormLoader, SectionContent, useLayoutTitle } from 'components';
|
||||
import { useI18nContext } from 'i18n/i18n-react';
|
||||
import type { Translation } from 'i18n/i18n-types';
|
||||
import { useInterval } from 'utils';
|
||||
|
||||
import { readActivity } from '../../api/app';
|
||||
import type { Stat } from '../main/types';
|
||||
|
||||
const SystemActivity = () => {
|
||||
const {
|
||||
data,
|
||||
send: loadData,
|
||||
error
|
||||
} = useAutoRequest(readActivity, { pollingTime: 3000 });
|
||||
const { data, send: loadData, error } = useRequest(readActivity);
|
||||
|
||||
useInterval(() => {
|
||||
void loadData();
|
||||
});
|
||||
|
||||
const { LL } = useI18nContext();
|
||||
|
||||
|
||||
@@ -17,9 +17,10 @@ import {
|
||||
|
||||
import * as SystemApi from 'api/system';
|
||||
|
||||
import { useAutoRequest } from 'alova/client';
|
||||
import { useRequest } from 'alova/client';
|
||||
import { FormLoader, SectionContent, useLayoutTitle } from 'components';
|
||||
import { useI18nContext } from 'i18n/i18n-react';
|
||||
import { useInterval } from 'utils';
|
||||
|
||||
import BBQKeesIcon from './bbqkees.svg';
|
||||
|
||||
@@ -32,11 +33,11 @@ const HardwareStatus = () => {
|
||||
|
||||
useLayoutTitle(LL.HARDWARE());
|
||||
|
||||
const {
|
||||
data,
|
||||
send: loadData,
|
||||
error
|
||||
} = useAutoRequest(SystemApi.readSystemStatus, { pollingTime: 3000 });
|
||||
const { data, send: loadData, error } = useRequest(SystemApi.readSystemStatus);
|
||||
|
||||
useInterval(() => {
|
||||
void loadData();
|
||||
});
|
||||
|
||||
const content = () => {
|
||||
if (!data) {
|
||||
|
||||
@@ -15,11 +15,12 @@ import type { Theme } from '@mui/material';
|
||||
|
||||
import * as MqttApi from 'api/mqtt';
|
||||
|
||||
import { useAutoRequest } from 'alova/client';
|
||||
import { useRequest } from 'alova/client';
|
||||
import { FormLoader, SectionContent, useLayoutTitle } from 'components';
|
||||
import { useI18nContext } from 'i18n/i18n-react';
|
||||
import type { MqttStatusType } from 'types';
|
||||
import { MqttDisconnectReason } from 'types';
|
||||
import { useInterval } from 'utils';
|
||||
|
||||
export const mqttStatusHighlight = (
|
||||
{ enabled, connected }: MqttStatusType,
|
||||
@@ -54,11 +55,11 @@ export const mqttQueueHighlight = (
|
||||
};
|
||||
|
||||
const MqttStatus = () => {
|
||||
const {
|
||||
data,
|
||||
send: loadData,
|
||||
error
|
||||
} = useAutoRequest(MqttApi.readMqttStatus, { pollingTime: 3000 });
|
||||
const { data, send: loadData, error } = useRequest(MqttApi.readMqttStatus);
|
||||
|
||||
useInterval(() => {
|
||||
void loadData();
|
||||
});
|
||||
|
||||
const { LL } = useI18nContext();
|
||||
useLayoutTitle('MQTT');
|
||||
|
||||
@@ -28,19 +28,20 @@ import type { Theme } from '@mui/material';
|
||||
import * as NTPApi from 'api/ntp';
|
||||
|
||||
import { dialogStyle } from 'CustomTheme';
|
||||
import { useAutoRequest, useRequest } from 'alova/client';
|
||||
import { useRequest } from 'alova/client';
|
||||
import { ButtonRow, FormLoader, SectionContent, useLayoutTitle } from 'components';
|
||||
import { useI18nContext } from 'i18n/i18n-react';
|
||||
import type { NTPStatusType, Time } from 'types';
|
||||
import { NTPSyncStatus } from 'types';
|
||||
import { useInterval } from 'utils';
|
||||
import { formatDateTime, formatLocalDateTime } from 'utils';
|
||||
|
||||
const NTPStatus = () => {
|
||||
const {
|
||||
data,
|
||||
send: loadData,
|
||||
error
|
||||
} = useAutoRequest(NTPApi.readNTPStatus, { pollingTime: 3000 });
|
||||
const { data, send: loadData, error } = useRequest(NTPApi.readNTPStatus);
|
||||
|
||||
useInterval(() => {
|
||||
void loadData();
|
||||
});
|
||||
|
||||
const [localTime, setLocalTime] = useState<string>('');
|
||||
const [settingTime, setSettingTime] = useState<boolean>(false);
|
||||
|
||||
@@ -18,11 +18,12 @@ import type { Theme } from '@mui/material';
|
||||
|
||||
import * as NetworkApi from 'api/network';
|
||||
|
||||
import { useAutoRequest } from 'alova/client';
|
||||
import { useRequest } from 'alova/client';
|
||||
import { FormLoader, SectionContent, useLayoutTitle } from 'components';
|
||||
import { useI18nContext } from 'i18n/i18n-react';
|
||||
import type { NetworkStatusType } from 'types';
|
||||
import { NetworkConnectionStatus } from 'types';
|
||||
import { useInterval } from 'utils';
|
||||
|
||||
const isConnected = ({ status }: NetworkStatusType) =>
|
||||
status === NetworkConnectionStatus.WIFI_STATUS_CONNECTED ||
|
||||
@@ -81,11 +82,11 @@ const IPs = (status: NetworkStatusType) => {
|
||||
};
|
||||
|
||||
const NetworkStatus = () => {
|
||||
const {
|
||||
data,
|
||||
send: loadData,
|
||||
error
|
||||
} = useAutoRequest(NetworkApi.readNetworkStatus, { pollingTime: 3000 });
|
||||
const { data, send: loadData, error } = useRequest(NetworkApi.readNetworkStatus);
|
||||
|
||||
useInterval(() => {
|
||||
void loadData();
|
||||
});
|
||||
|
||||
const { LL } = useI18nContext();
|
||||
useLayoutTitle(LL.NETWORK(1));
|
||||
|
||||
@@ -11,9 +11,10 @@ import {
|
||||
import { readSystemStatus } from 'api/system';
|
||||
|
||||
import { dialogStyle } from 'CustomTheme';
|
||||
import { useAutoRequest } from 'alova/client';
|
||||
import { useRequest } from 'alova/client';
|
||||
import MessageBox from 'components/MessageBox';
|
||||
import { useI18nContext } from 'i18n/i18n-react';
|
||||
import { useInterval } from 'utils';
|
||||
|
||||
const RestartMonitor = () => {
|
||||
const [errorMessage, setErrorMessage] = useState<string>();
|
||||
@@ -22,8 +23,7 @@ const RestartMonitor = () => {
|
||||
|
||||
let count = 0;
|
||||
|
||||
const { data } = useAutoRequest(readSystemStatus, {
|
||||
pollingTime: 1000,
|
||||
const { data, send } = useRequest(readSystemStatus, {
|
||||
force: true,
|
||||
initialData: { status: 'Getting ready...' },
|
||||
async middleware(_, next) {
|
||||
@@ -42,6 +42,10 @@ const RestartMonitor = () => {
|
||||
setErrorMessage(error.message);
|
||||
});
|
||||
|
||||
useInterval(() => {
|
||||
void send();
|
||||
}, 1000); // check every second
|
||||
|
||||
return (
|
||||
<Dialog fullWidth={true} sx={dialogStyle} open={true}>
|
||||
<DialogContent dividers>
|
||||
|
||||
@@ -30,13 +30,15 @@ import { API } from 'api/app';
|
||||
import { readSystemStatus } from 'api/system';
|
||||
|
||||
import { dialogStyle } from 'CustomTheme';
|
||||
import { useAutoRequest, useRequest } from 'alova/client';
|
||||
import { useRequest } from 'alova/client';
|
||||
import { type APIcall, busConnectionStatus } from 'app/main/types';
|
||||
import { FormLoader, SectionContent, useLayoutTitle } from 'components';
|
||||
import ListMenuItem from 'components/layout/ListMenuItem';
|
||||
import { AuthenticatedContext } from 'contexts/authentication';
|
||||
import { useI18nContext } from 'i18n/i18n-react';
|
||||
import { NTPSyncStatus, NetworkConnectionStatus } from 'types';
|
||||
import { useInterval } from 'utils';
|
||||
import { formatDateTime } from 'utils/time';
|
||||
|
||||
import RestartMonitor from './RestartMonitor';
|
||||
|
||||
@@ -58,9 +60,8 @@ const SystemStatus = () => {
|
||||
data,
|
||||
send: loadData,
|
||||
error
|
||||
} = useAutoRequest(readSystemStatus, {
|
||||
} = useRequest(readSystemStatus, {
|
||||
initialData: [],
|
||||
pollingTime: 3000,
|
||||
async middleware(_, next) {
|
||||
if (!restarting) {
|
||||
await next();
|
||||
@@ -68,6 +69,10 @@ const SystemStatus = () => {
|
||||
}
|
||||
});
|
||||
|
||||
useInterval(() => {
|
||||
void loadData();
|
||||
});
|
||||
|
||||
const theme = useTheme();
|
||||
|
||||
const formatDurationSec = (duration_sec: number) => {
|
||||
@@ -134,7 +139,7 @@ const SystemStatus = () => {
|
||||
case NTPSyncStatus.NTP_INACTIVE:
|
||||
return LL.INACTIVE(0);
|
||||
case NTPSyncStatus.NTP_ACTIVE:
|
||||
return LL.ACTIVE();
|
||||
return LL.ACTIVE() + ' (' + formatDateTime(data.ntp_time ?? '') + ')';
|
||||
default:
|
||||
return LL.UNKNOWN();
|
||||
}
|
||||
@@ -301,7 +306,7 @@ const SystemStatus = () => {
|
||||
icon={DeviceHubIcon}
|
||||
bgcolor={activeHighlight(data.mqtt_status)}
|
||||
label="MQTT"
|
||||
text={data.mqtt_status ? LL.ACTIVE() : LL.INACTIVE(0)}
|
||||
text={data.mqtt_status ? LL.CONNECTED(0) : LL.INACTIVE(0)}
|
||||
to="/status/mqtt"
|
||||
/>
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ export interface SystemStatus {
|
||||
num_sensors: number;
|
||||
num_analogs: number;
|
||||
ntp_status: number;
|
||||
ntp_time?: string;
|
||||
mqtt_status: boolean;
|
||||
ap_status: boolean;
|
||||
network_status: NetworkConnectionStatus;
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import { useEffect, useRef } from 'react';
|
||||
|
||||
const DEFAULT_DELAY = 3000;
|
||||
|
||||
// adapted from https://www.joshwcomeau.com/snippets/react-hooks/use-interval/
|
||||
export const useInterval = (callback: () => void, delay: number) => {
|
||||
export const useInterval = (callback: () => void, delay: number = DEFAULT_DELAY) => {
|
||||
const intervalRef = useRef<number | null>(null);
|
||||
const savedCallback = useRef<() => void>(callback);
|
||||
|
||||
@@ -11,14 +13,12 @@ export const useInterval = (callback: () => void, delay: number) => {
|
||||
|
||||
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;
|
||||
|
||||
@@ -1607,7 +1607,7 @@ __metadata:
|
||||
react: "npm:^19.0.0"
|
||||
react-dom: "npm:^19.0.0"
|
||||
react-icons: "npm:^5.4.0"
|
||||
react-router: "npm:^7.0.2"
|
||||
react-router: "npm:^7.1.0"
|
||||
react-toastify: "npm:^11.0.2"
|
||||
rollup-plugin-visualizer: "npm:^5.12.0"
|
||||
terser: "npm:^5.37.0"
|
||||
@@ -5589,9 +5589,9 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react-router@npm:^7.0.2":
|
||||
version: 7.0.2
|
||||
resolution: "react-router@npm:7.0.2"
|
||||
"react-router@npm:^7.1.0":
|
||||
version: 7.1.0
|
||||
resolution: "react-router@npm:7.1.0"
|
||||
dependencies:
|
||||
"@types/cookie": "npm:^0.6.0"
|
||||
cookie: "npm:^1.0.1"
|
||||
@@ -5603,7 +5603,7 @@ __metadata:
|
||||
peerDependenciesMeta:
|
||||
react-dom:
|
||||
optional: true
|
||||
checksum: 10c0/f6c04939218a3d7f2b03b215c2299eab4dbb0dea4a16e0acfd8bf181ec69ff42d66abdba10a25cc3297c514f052a0d03bfb80431225eb763bb27e4e5b0b4a106
|
||||
checksum: 10c0/c4f4c76dc885cb2b351575052417f0a95ad454ae7cc27f42e5dcde993697b206eab9f5eb3f9a3acb1284331d41f8667bd4d10e246d463c3debd7d4de3edaa50b
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
||||
@@ -518,6 +518,7 @@ let system_status = {
|
||||
num_analogs: 1,
|
||||
free_heap: 143,
|
||||
ntp_status: 2,
|
||||
ntp_time: '2021-04-01T14:25:42Z',
|
||||
mqtt_status: true,
|
||||
ap_status: false,
|
||||
network_status: 3, // wifi connected
|
||||
|
||||
Reference in New Issue
Block a user