mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-06 15:59:52 +03:00
more alova ports
This commit is contained in:
@@ -50,7 +50,7 @@
|
|||||||
"@typescript-eslint/eslint-plugin": "^5.59.11",
|
"@typescript-eslint/eslint-plugin": "^5.59.11",
|
||||||
"@typescript-eslint/parser": "^5.59.11",
|
"@typescript-eslint/parser": "^5.59.11",
|
||||||
"@vitejs/plugin-react-swc": "^3.3.2",
|
"@vitejs/plugin-react-swc": "^3.3.2",
|
||||||
"eslint": "^8.42.0",
|
"eslint": "^8.43.0",
|
||||||
"eslint-config-airbnb": "^19.0.4",
|
"eslint-config-airbnb": "^19.0.4",
|
||||||
"eslint-config-airbnb-typescript": "^17.0.0",
|
"eslint-config-airbnb-typescript": "^17.0.0",
|
||||||
"eslint-config-prettier": "^8.8.0",
|
"eslint-config-prettier": "^8.8.0",
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ const AuthenticatedRouting: FC = () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// TODO how to replace AXIOS.interceptors.response.use ???
|
// TODO replace AXIOS.interceptors.response.use ???
|
||||||
const axiosHandlerId = AXIOS.interceptors.response.use((response) => response, handleApiResponseError);
|
const axiosHandlerId = AXIOS.interceptors.response.use((response) => response, handleApiResponseError);
|
||||||
return () => AXIOS.interceptors.response.eject(axiosHandlerId);
|
return () => AXIOS.interceptors.response.eject(axiosHandlerId);
|
||||||
}, [handleApiResponseError]);
|
}, [handleApiResponseError]);
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ const SignIn: FC = () => {
|
|||||||
|
|
||||||
const signIn = async () => {
|
const signIn = async () => {
|
||||||
try {
|
try {
|
||||||
|
// TODO move to Alova
|
||||||
const { data: loginResponse } = await AuthenticationApi.signIn(signInRequest);
|
const { data: loginResponse } = await AuthenticationApi.signIn(signInRequest);
|
||||||
authenticationContext.signIn(loginResponse.access_token);
|
authenticationContext.signIn(loginResponse.access_token);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -9,10 +9,11 @@ import type { Me, SignInRequest, SignInResponse } from 'types';
|
|||||||
export const SIGN_IN_PATHNAME = 'loginPathname';
|
export const SIGN_IN_PATHNAME = 'loginPathname';
|
||||||
export const SIGN_IN_SEARCH = 'loginSearch';
|
export const SIGN_IN_SEARCH = 'loginSearch';
|
||||||
|
|
||||||
// TODO move to Alova
|
// TODO move verifyAuthorization to Alova
|
||||||
export function verifyAuthorization(): AxiosPromise<void> {
|
export function verifyAuthorization(): AxiosPromise<void> {
|
||||||
return AXIOS.get('/verifyAuthorization');
|
return AXIOS.get('/verifyAuthorization');
|
||||||
}
|
}
|
||||||
|
// TODO move signIn to Alova
|
||||||
export function signIn(request: SignInRequest): AxiosPromise<SignInResponse> {
|
export function signIn(request: SignInRequest): AxiosPromise<SignInResponse> {
|
||||||
return AXIOS.post('/signIn', request);
|
return AXIOS.post('/signIn', request);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ export const EVENT_SOURCE_ROOT = 'http://' + host + '/es/';
|
|||||||
|
|
||||||
export const alovaInstance = createAlova({
|
export const alovaInstance = createAlova({
|
||||||
statesHook: ReactHook,
|
statesHook: ReactHook,
|
||||||
timeout: 3000,
|
// timeout: 3000,
|
||||||
localCache: {
|
localCache: {
|
||||||
GET: {
|
GET: {
|
||||||
mode: 'placeholder',
|
mode: 'placeholder',
|
||||||
@@ -35,7 +35,9 @@ export const alovaInstance = createAlova({
|
|||||||
|
|
||||||
responded: {
|
responded: {
|
||||||
onSuccess: async (response) => {
|
onSuccess: async (response) => {
|
||||||
if (response.status == 205) {
|
if (response.status === 202) {
|
||||||
|
throw new Error('Wait');
|
||||||
|
} else if (response.status === 205) {
|
||||||
throw new Error('Reboot required');
|
throw new Error('Reboot required');
|
||||||
} else if (response.status === 400) {
|
} else if (response.status === 400) {
|
||||||
throw new Error('Request Failed');
|
throw new Error('Request Failed');
|
||||||
@@ -117,7 +119,7 @@ export const AXIOS_BIN = axios.create({
|
|||||||
transformResponse: [(data) => unpack(data)]
|
transformResponse: [(data) => unpack(data)]
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO replace upload with alova, see https://alova.js.org/next-step/download-upload-progress
|
// TODO replace fileupload with alova, see https://alova.js.org/next-step/download-upload-progress
|
||||||
export interface FileUploadConfig {
|
export interface FileUploadConfig {
|
||||||
cancelToken?: CancelToken;
|
cancelToken?: CancelToken;
|
||||||
onUploadProgress?: (progressEvent: AxiosProgressEvent) => void;
|
onUploadProgress?: (progressEvent: AxiosProgressEvent) => void;
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
import { AXIOS } from './endpoints';
|
import { alovaInstance } from './endpoints';
|
||||||
import type { AxiosPromise } from 'axios';
|
|
||||||
|
|
||||||
import type { Features } from 'types';
|
import type { Features } from 'types';
|
||||||
|
|
||||||
// TODO move to Alova
|
export const readFeatures = () => alovaInstance.Get<Features>('/rest/features');
|
||||||
export function readFeatures(): AxiosPromise<Features> {
|
|
||||||
return AXIOS.get('/features');
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,52 +1,27 @@
|
|||||||
import { AXIOS, AXIOS_BIN, alovaInstance, startUploadFile } from './endpoints';
|
import { alovaInstance, startUploadFile } from './endpoints';
|
||||||
import type { FileUploadConfig } from './endpoints';
|
import type { FileUploadConfig } from './endpoints';
|
||||||
import type { AxiosPromise } from 'axios';
|
import type { AxiosPromise } from 'axios';
|
||||||
|
|
||||||
import type { OTASettings, SystemStatus, LogSettings, LogEntries } from 'types';
|
import type { OTASettings, SystemStatus, LogSettings } from 'types';
|
||||||
|
|
||||||
// TODO move to Alova
|
|
||||||
// TODO fix this next!
|
|
||||||
|
|
||||||
export const readSystemStatus = (timeout?: number) =>
|
export const readSystemStatus = (timeout?: number) =>
|
||||||
alovaInstance.Get<SystemStatus>('/rest/systemStatus', {
|
alovaInstance.Get<SystemStatus>('/rest/systemStatus', {
|
||||||
params: { timeout }
|
params: { timeout }
|
||||||
});
|
});
|
||||||
|
|
||||||
// export function readSystemStatus(timeout?: number): AxiosPromise<SystemStatus> {
|
// commands
|
||||||
// return AXIOS.get('/systemStatus', { timeout });
|
export const restart = () => alovaInstance.Post('/rest/restart');
|
||||||
// }
|
export const partition = () => alovaInstance.Post('/rest/partition');
|
||||||
|
export const factoryReset = () => alovaInstance.Post('/rest/factoryReset');
|
||||||
|
|
||||||
export function restart(): AxiosPromise<void> {
|
// OTA
|
||||||
return AXIOS.post('/restart');
|
export const readOTASettings = () => alovaInstance.Get<OTASettings>(`/rest/otaSettings`);
|
||||||
}
|
export const updateOTASettings = (data: any) => alovaInstance.Post('/rest/otaSettings', data);
|
||||||
|
|
||||||
export function partition(): AxiosPromise<void> {
|
// SystemLog
|
||||||
return AXIOS.post('/partition');
|
export const readLogSettings = () => alovaInstance.Get<LogSettings>(`/rest/logSettings`);
|
||||||
}
|
export const updateLogSettings = (data: any) => alovaInstance.Post('/rest/logSettings', data);
|
||||||
|
export const fetchLog = () => alovaInstance.Post('/rest/fetchLog');
|
||||||
export function factoryReset(): AxiosPromise<void> {
|
|
||||||
return AXIOS.post('/factoryReset');
|
|
||||||
}
|
|
||||||
|
|
||||||
export function readOTASettings(): AxiosPromise<OTASettings> {
|
|
||||||
return AXIOS.get('/otaSettings');
|
|
||||||
}
|
|
||||||
|
|
||||||
export function updateOTASettings(otaSettings: OTASettings): AxiosPromise<OTASettings> {
|
|
||||||
return AXIOS.post('/otaSettings', otaSettings);
|
|
||||||
}
|
|
||||||
|
|
||||||
export const uploadFile = (file: File, config?: FileUploadConfig): AxiosPromise<void> =>
|
export const uploadFile = (file: File, config?: FileUploadConfig): AxiosPromise<void> =>
|
||||||
startUploadFile('/uploadFile', file, config);
|
startUploadFile('/uploadFile', file, config);
|
||||||
|
|
||||||
export function readLogSettings(): AxiosPromise<LogSettings> {
|
|
||||||
return AXIOS.get('/logSettings');
|
|
||||||
}
|
|
||||||
|
|
||||||
export function updateLogSettings(logSettings: LogSettings): AxiosPromise<LogSettings> {
|
|
||||||
return AXIOS.post('/logSettings', logSettings);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function readLogEntries(): AxiosPromise<LogEntries> {
|
|
||||||
return AXIOS_BIN.get('/fetchLog');
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import { useI18nContext } from 'i18n/i18n-react';
|
|||||||
import { extractErrorMessage } from 'utils';
|
import { extractErrorMessage } from 'utils';
|
||||||
|
|
||||||
interface MediaUploadOptions {
|
interface MediaUploadOptions {
|
||||||
|
// TODO fileupload move to alova
|
||||||
upload: (file: File, config?: FileUploadConfig) => AxiosPromise<void>;
|
upload: (file: File, config?: FileUploadConfig) => AxiosPromise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,30 +1,14 @@
|
|||||||
import { useCallback, useEffect, useState } from 'react';
|
import { useRequest } from 'alova';
|
||||||
|
|
||||||
import { FeaturesContext } from '.';
|
import { FeaturesContext } from '.';
|
||||||
import type { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
|
|
||||||
import type { Features } from 'types';
|
|
||||||
import type { RequiredChildrenProps } from 'utils';
|
import type { RequiredChildrenProps } from 'utils';
|
||||||
import * as FeaturesApi from 'api/features';
|
import * as FeaturesApi from 'api/features';
|
||||||
import { ApplicationError, LoadingSpinner } from 'components';
|
import { ApplicationError, LoadingSpinner } from 'components';
|
||||||
import { extractErrorMessage } from 'utils';
|
|
||||||
|
|
||||||
const FeaturesLoader: FC<RequiredChildrenProps> = (props) => {
|
const FeaturesLoader: FC<RequiredChildrenProps> = (props) => {
|
||||||
const [errorMessage, setErrorMessage] = useState<string>();
|
const { data: features, error } = useRequest(FeaturesApi.readFeatures);
|
||||||
const [features, setFeatures] = useState<Features>();
|
|
||||||
|
|
||||||
const loadFeatures = useCallback(async () => {
|
|
||||||
try {
|
|
||||||
const response = await FeaturesApi.readFeatures();
|
|
||||||
setFeatures(response.data);
|
|
||||||
} catch (error) {
|
|
||||||
setErrorMessage(extractErrorMessage(error, 'Failed to fetch application details.'));
|
|
||||||
}
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
void loadFeatures();
|
|
||||||
}, [loadFeatures]);
|
|
||||||
|
|
||||||
if (features) {
|
if (features) {
|
||||||
return (
|
return (
|
||||||
@@ -38,8 +22,8 @@ const FeaturesLoader: FC<RequiredChildrenProps> = (props) => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (errorMessage) {
|
if (error) {
|
||||||
return <ApplicationError message={errorMessage} />;
|
return <ApplicationError message={error?.message} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
return <LoadingSpinner height="100vh" />;
|
return <LoadingSpinner height="100vh" />;
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import {
|
|||||||
InputAdornment,
|
InputAdornment,
|
||||||
TextField
|
TextField
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
|
// eslint-disable-next-line import/named
|
||||||
import { updateState, useRequest } from 'alova';
|
import { updateState, useRequest } from 'alova';
|
||||||
import { useContext, useEffect, useState } from 'react';
|
import { useContext, useEffect, useState } from 'react';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
@@ -29,6 +30,7 @@ import type { FC } from 'react';
|
|||||||
|
|
||||||
import type { NetworkSettings } from 'types';
|
import type { NetworkSettings } from 'types';
|
||||||
import * as NetworkApi from 'api/network';
|
import * as NetworkApi from 'api/network';
|
||||||
|
import * as SystemApi from 'api/system';
|
||||||
import {
|
import {
|
||||||
BlockFormControlLabel,
|
BlockFormControlLabel,
|
||||||
ButtonRow,
|
ButtonRow,
|
||||||
@@ -40,7 +42,7 @@ import {
|
|||||||
BlockNavigation
|
BlockNavigation
|
||||||
} from 'components';
|
} from 'components';
|
||||||
import { useI18nContext } from 'i18n/i18n-react';
|
import { useI18nContext } from 'i18n/i18n-react';
|
||||||
import * as EMSESP from 'project/api';
|
|
||||||
import { numberValue, updateValueDirty, useRest2 } from 'utils';
|
import { numberValue, updateValueDirty, useRest2 } from 'utils';
|
||||||
|
|
||||||
import { validate } from 'validators';
|
import { validate } from 'validators';
|
||||||
@@ -71,7 +73,7 @@ const WiFiSettingsForm: FC = () => {
|
|||||||
update: NetworkApi.updateNetworkSettings
|
update: NetworkApi.updateNetworkSettings
|
||||||
});
|
});
|
||||||
|
|
||||||
const { send: restartCommand } = useRequest(EMSESP.restart(), {
|
const { send: restartCommand } = useRequest(SystemApi.restart(), {
|
||||||
immediate: false
|
immediate: false
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,82 +1,63 @@
|
|||||||
import PermScanWifiIcon from '@mui/icons-material/PermScanWifi';
|
import PermScanWifiIcon from '@mui/icons-material/PermScanWifi';
|
||||||
import { Button } from '@mui/material';
|
import { Button } from '@mui/material';
|
||||||
import { useEffect, useState, useCallback, useRef } from 'react';
|
import { useRequest } from 'alova';
|
||||||
|
import { useState, useCallback, useRef } from 'react';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
|
|
||||||
import WiFiNetworkSelector from './WiFiNetworkSelector';
|
import WiFiNetworkSelector from './WiFiNetworkSelector';
|
||||||
import type { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
import type { WiFiNetwork, WiFiNetworkList } from 'types';
|
|
||||||
import * as NetworkApi from 'api/network';
|
import * as NetworkApi from 'api/network';
|
||||||
import { ButtonRow, FormLoader, SectionContent } from 'components';
|
import { ButtonRow, FormLoader, SectionContent } from 'components';
|
||||||
|
|
||||||
import { useI18nContext } from 'i18n/i18n-react';
|
import { useI18nContext } from 'i18n/i18n-react';
|
||||||
|
|
||||||
const NUM_POLLS = 10;
|
const NUM_POLLS = 10;
|
||||||
const POLLING_FREQUENCY = 500;
|
const POLLING_FREQUENCY = 1000;
|
||||||
|
|
||||||
const compareNetworks = (network1: WiFiNetwork, network2: WiFiNetwork) => {
|
|
||||||
if (network1.rssi < network2.rssi) return 1;
|
|
||||||
if (network1.rssi > network2.rssi) return -1;
|
|
||||||
return 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
const WiFiNetworkScanner: FC = () => {
|
const WiFiNetworkScanner: FC = () => {
|
||||||
const { LL } = useI18nContext();
|
const { LL } = useI18nContext();
|
||||||
|
|
||||||
const pollCount = useRef(0);
|
const pollCount = useRef(0);
|
||||||
const [networkList, setNetworkList] = useState<WiFiNetworkList>();
|
|
||||||
const [errorMessage, setErrorMessage] = useState<string>();
|
const [errorMessage, setErrorMessage] = useState<string>();
|
||||||
|
|
||||||
|
const { data: networkList, send: getNetworkList } = useRequest(NetworkApi.listNetworks, {
|
||||||
|
immediate: false
|
||||||
|
});
|
||||||
|
|
||||||
|
const {
|
||||||
|
send: scanNetworks,
|
||||||
|
onSuccess: onSuccessScanNetworks,
|
||||||
|
onError: onErrorScanNetworks
|
||||||
|
} = useRequest(NetworkApi.scanNetworks);
|
||||||
|
|
||||||
const finishedWithError = useCallback((message: string) => {
|
const finishedWithError = useCallback((message: string) => {
|
||||||
toast.error(message);
|
toast.error(message);
|
||||||
setNetworkList(undefined);
|
|
||||||
setErrorMessage(message);
|
setErrorMessage(message);
|
||||||
|
pollCount.current = 0;
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const pollNetworkList = useCallback(async () => {
|
onErrorScanNetworks((event) => {
|
||||||
try {
|
console.log('onErrorScanNetworks'); // TODO fix
|
||||||
const response = await NetworkApi.listNetworks();
|
if (event.error?.message === 'Wait') {
|
||||||
if (response.status === 202) {
|
// 202
|
||||||
|
console.log('not ready...: ', event.error?.message); // TODO fix
|
||||||
const completedPollCount = pollCount.current + 1;
|
const completedPollCount = pollCount.current + 1;
|
||||||
if (completedPollCount < NUM_POLLS) {
|
if (completedPollCount < NUM_POLLS) {
|
||||||
pollCount.current = completedPollCount;
|
pollCount.current = completedPollCount;
|
||||||
setTimeout(pollNetworkList, POLLING_FREQUENCY);
|
setTimeout(scanNetworks, POLLING_FREQUENCY);
|
||||||
} else {
|
} else {
|
||||||
finishedWithError(LL.PROBLEM_LOADING());
|
finishedWithError(LL.PROBLEM_LOADING());
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
const newNetworkList = response.data;
|
|
||||||
newNetworkList.networks.sort(compareNetworks);
|
|
||||||
setNetworkList(newNetworkList);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
if (error.response) {
|
|
||||||
finishedWithError(LL.PROBLEM_LOADING() + ' ' + error.response?.data.message);
|
|
||||||
} else {
|
} else {
|
||||||
finishedWithError(LL.PROBLEM_LOADING());
|
finishedWithError(LL.PROBLEM_LOADING());
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
}, [finishedWithError, LL]);
|
|
||||||
|
|
||||||
const startNetworkScan = useCallback(async () => {
|
onSuccessScanNetworks(() => {
|
||||||
|
console.log('onCompleteScanNetworks'); // TODO fix
|
||||||
pollCount.current = 0;
|
pollCount.current = 0;
|
||||||
setNetworkList(undefined);
|
void getNetworkList(); // fetch the list
|
||||||
setErrorMessage(undefined);
|
});
|
||||||
try {
|
|
||||||
await NetworkApi.scanNetworks();
|
|
||||||
setTimeout(pollNetworkList, POLLING_FREQUENCY);
|
|
||||||
} catch (error) {
|
|
||||||
if (error.response) {
|
|
||||||
finishedWithError(LL.PROBLEM_LOADING() + ' ' + error.response?.data.message);
|
|
||||||
} else {
|
|
||||||
finishedWithError(LL.PROBLEM_LOADING());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, [finishedWithError, pollNetworkList, LL]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
void startNetworkScan();
|
|
||||||
}, [startNetworkScan]);
|
|
||||||
|
|
||||||
const renderNetworkScanner = () => {
|
const renderNetworkScanner = () => {
|
||||||
if (!networkList) {
|
if (!networkList) {
|
||||||
@@ -93,7 +74,7 @@ const WiFiNetworkScanner: FC = () => {
|
|||||||
startIcon={<PermScanWifiIcon />}
|
startIcon={<PermScanWifiIcon />}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
color="secondary"
|
color="secondary"
|
||||||
onClick={startNetworkScan}
|
onClick={scanNetworks}
|
||||||
disabled={!errorMessage && !networkList}
|
disabled={!errorMessage && !networkList}
|
||||||
>
|
>
|
||||||
{LL.SCAN_AGAIN()}…
|
{LL.SCAN_AGAIN()}…
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import CancelIcon from '@mui/icons-material/Cancel';
|
import CancelIcon from '@mui/icons-material/Cancel';
|
||||||
import WarningIcon from '@mui/icons-material/Warning';
|
import WarningIcon from '@mui/icons-material/Warning';
|
||||||
import { Button, Checkbox, MenuItem } from '@mui/material';
|
import { Button, Checkbox, MenuItem } from '@mui/material';
|
||||||
|
// eslint-disable-next-line import/named
|
||||||
import { updateState } from 'alova';
|
import { updateState } from 'alova';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { selectedTimeZone, timeZoneSelectItems, TIME_ZONES } from './TZ';
|
import { selectedTimeZone, timeZoneSelectItems, TIME_ZONES } from './TZ';
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import { useI18nContext } from 'i18n/i18n-react';
|
|||||||
import * as EMSESP from 'project/api';
|
import * as EMSESP from 'project/api';
|
||||||
|
|
||||||
interface UploadFileProps {
|
interface UploadFileProps {
|
||||||
|
// TODO fileupload upload move to alova
|
||||||
uploadGeneralFile: (file: File, config?: FileUploadConfig) => AxiosPromise<void>;
|
uploadGeneralFile: (file: File, config?: FileUploadConfig) => AxiosPromise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,21 +18,31 @@ import {
|
|||||||
} from 'components';
|
} from 'components';
|
||||||
|
|
||||||
import { useI18nContext } from 'i18n/i18n-react';
|
import { useI18nContext } from 'i18n/i18n-react';
|
||||||
import { numberValue, updateValueDirty, useRest } from 'utils';
|
import { numberValue, updateValueDirty, useRest2 } from 'utils';
|
||||||
|
|
||||||
import { validate } from 'validators';
|
import { validate } from 'validators';
|
||||||
import { OTA_SETTINGS_VALIDATOR } from 'validators/system';
|
import { OTA_SETTINGS_VALIDATOR } from 'validators/system';
|
||||||
|
|
||||||
const OTASettingsForm: FC = () => {
|
const OTASettingsForm: FC = () => {
|
||||||
const { loadData, saving, data, setData, origData, dirtyFlags, setDirtyFlags, blocker, saveData, errorMessage } =
|
const {
|
||||||
useRest<OTASettings>({
|
loadData,
|
||||||
|
saveData,
|
||||||
|
saving,
|
||||||
|
updateDataValue,
|
||||||
|
data,
|
||||||
|
origData,
|
||||||
|
dirtyFlags,
|
||||||
|
setDirtyFlags,
|
||||||
|
blocker,
|
||||||
|
errorMessage
|
||||||
|
} = useRest2<OTASettings>({
|
||||||
read: SystemApi.readOTASettings,
|
read: SystemApi.readOTASettings,
|
||||||
update: SystemApi.updateOTASettings
|
update: SystemApi.updateOTASettings
|
||||||
});
|
});
|
||||||
|
|
||||||
const { LL } = useI18nContext();
|
const { LL } = useI18nContext();
|
||||||
|
|
||||||
const updateFormValue = updateValueDirty(origData, dirtyFlags, setDirtyFlags, setData);
|
const updateFormValue = updateValueDirty(origData, dirtyFlags, setDirtyFlags, updateDataValue);
|
||||||
|
|
||||||
const [fieldErrors, setFieldErrors] = useState<ValidateFieldsError>();
|
const [fieldErrors, setFieldErrors] = useState<ValidateFieldsError>();
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { useRequest } from 'alova';
|
||||||
import { useRef, useState, useEffect } from 'react';
|
import { useRef, useState, useEffect } from 'react';
|
||||||
import type { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
|
|
||||||
@@ -16,10 +17,14 @@ const RestartMonitor: FC = () => {
|
|||||||
|
|
||||||
const { LL } = useI18nContext();
|
const { LL } = useI18nContext();
|
||||||
|
|
||||||
|
const { send: readSystemStatus } = useRequest((timeout) => SystemApi.readSystemStatus(timeout), {
|
||||||
|
immediate: false
|
||||||
|
});
|
||||||
|
|
||||||
const timeoutAt = useRef(new Date().getTime() + RESTART_TIMEOUT);
|
const timeoutAt = useRef(new Date().getTime() + RESTART_TIMEOUT);
|
||||||
const poll = useRef(async () => {
|
const poll = useRef(async () => {
|
||||||
try {
|
try {
|
||||||
await SystemApi.readSystemStatus(POLL_TIMEOUT);
|
await readSystemStatus(POLL_TIMEOUT);
|
||||||
document.location.href = '/fileUpdated';
|
document.location.href = '/fileUpdated';
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (new Date().getTime() < timeoutAt.current) {
|
if (new Date().getTime() < timeoutAt.current) {
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
import DownloadIcon from '@mui/icons-material/GetApp';
|
import DownloadIcon from '@mui/icons-material/GetApp';
|
||||||
import WarningIcon from '@mui/icons-material/Warning';
|
import WarningIcon from '@mui/icons-material/Warning';
|
||||||
import { Box, styled, Button, Checkbox, MenuItem, Grid, TextField } from '@mui/material';
|
import { Box, styled, Button, Checkbox, MenuItem, Grid, TextField } from '@mui/material';
|
||||||
import { useState, useEffect, useCallback } from 'react';
|
// eslint-disable-next-line import/named
|
||||||
|
import { useRequest } from 'alova';
|
||||||
|
import { useState, useEffect } from 'react';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
import type { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
|
|
||||||
import type { LogSettings, LogEntry, LogEntries } from 'types';
|
import type { LogSettings, LogEntry } from 'types';
|
||||||
import { addAccessTokenParameter } from 'api/authentication';
|
import { addAccessTokenParameter } from 'api/authentication';
|
||||||
import { EVENT_SOURCE_ROOT } from 'api/endpoints';
|
import { EVENT_SOURCE_ROOT } from 'api/endpoints';
|
||||||
import * as SystemApi from 'api/system';
|
import * as SystemApi from 'api/system';
|
||||||
@@ -14,7 +16,7 @@ import { SectionContent, FormLoader, BlockFormControlLabel, BlockNavigation } fr
|
|||||||
|
|
||||||
import { useI18nContext } from 'i18n/i18n-react';
|
import { useI18nContext } from 'i18n/i18n-react';
|
||||||
import { LogLevel } from 'types';
|
import { LogLevel } from 'types';
|
||||||
import { useRest, updateValueDirty, extractErrorMessage } from 'utils';
|
import { updateValueDirty, useRest2 } from 'utils';
|
||||||
|
|
||||||
export const LOG_EVENTSOURCE_URL = EVENT_SOURCE_ROOT + 'log';
|
export const LOG_EVENTSOURCE_URL = EVENT_SOURCE_ROOT + 'log';
|
||||||
|
|
||||||
@@ -49,15 +51,20 @@ const levelLabel = (level: LogLevel) => {
|
|||||||
const SystemLog: FC = () => {
|
const SystemLog: FC = () => {
|
||||||
const { LL } = useI18nContext();
|
const { LL } = useI18nContext();
|
||||||
|
|
||||||
// TODO replace with const { data: data, send: loadData, error } = useRequest(APApi.readAPStatus);
|
const { loadData, data, updateDataValue, origData, dirtyFlags, setDirtyFlags, blocker, saveData, errorMessage } =
|
||||||
const { loadData, data, setData, origData, dirtyFlags, blocker, setDirtyFlags, setOrigData } = useRest<LogSettings>({
|
useRest2<LogSettings>({
|
||||||
read: SystemApi.readLogSettings
|
read: SystemApi.readLogSettings,
|
||||||
|
update: SystemApi.updateLogSettings
|
||||||
});
|
});
|
||||||
|
|
||||||
const [errorMessage, setErrorMessage] = useState<string>();
|
// called on page load to reset pointer and fetch all log entries
|
||||||
const [logEntries, setLogEntries] = useState<LogEntries>({ events: [] });
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
const { send: fetchLog } = useRequest(SystemApi.fetchLog());
|
||||||
|
const [logEntries, setLogEntries] = useState<LogEntry[]>([]);
|
||||||
const [lastIndex, setLastIndex] = useState<number>(0);
|
const [lastIndex, setLastIndex] = useState<number>(0);
|
||||||
|
|
||||||
|
const updateFormValue = updateValueDirty(origData, dirtyFlags, setDirtyFlags, updateDataValue);
|
||||||
|
|
||||||
const paddedLevelLabel = (level: LogLevel) => {
|
const paddedLevelLabel = (level: LogLevel) => {
|
||||||
const label = levelLabel(level);
|
const label = levelLabel(level);
|
||||||
return data?.compact ? ' ' + label[0] : label.padStart(8, '\xa0');
|
return data?.compact ? ' ' + label[0] : label.padStart(8, '\xa0');
|
||||||
@@ -73,11 +80,9 @@ const SystemLog: FC = () => {
|
|||||||
return data?.compact ? label : label.padEnd(7, '\xa0');
|
return data?.compact ? label : label.padEnd(7, '\xa0');
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateFormValue = updateValueDirty(origData, dirtyFlags, setDirtyFlags, setData);
|
|
||||||
|
|
||||||
const onDownload = () => {
|
const onDownload = () => {
|
||||||
let result = '';
|
let result = '';
|
||||||
for (const i of logEntries.events) {
|
for (const i of logEntries) {
|
||||||
result += i.t + ' ' + levelLabel(i.l) + ' ' + i.i + ': [' + i.n + '] ' + i.m + '\n';
|
result += i.t + ' ' + levelLabel(i.l) + ' ' + i.i + ': [' + i.n + '] ' + i.m + '\n';
|
||||||
}
|
}
|
||||||
const a = document.createElement('a');
|
const a = document.createElement('a');
|
||||||
@@ -94,29 +99,22 @@ const SystemLog: FC = () => {
|
|||||||
const logentry = JSON.parse(rawData as string) as LogEntry;
|
const logentry = JSON.parse(rawData as string) as LogEntry;
|
||||||
if (logentry.i > lastIndex) {
|
if (logentry.i > lastIndex) {
|
||||||
setLastIndex(logentry.i);
|
setLastIndex(logentry.i);
|
||||||
setLogEntries((old) => ({ events: [...old.events, logentry] }));
|
setLogEntries((log) => [...log, logentry]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const fetchLog = useCallback(async () => {
|
const saveSettings = async () => {
|
||||||
try {
|
await saveData();
|
||||||
await SystemApi.readLogEntries();
|
};
|
||||||
} catch (error) {
|
|
||||||
setErrorMessage(extractErrorMessage(error, LL.PROBLEM_LOADING()));
|
|
||||||
}
|
|
||||||
}, [LL]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
void fetchLog();
|
|
||||||
}, [fetchLog]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const es = new EventSource(addAccessTokenParameter(LOG_EVENTSOURCE_URL));
|
const es = new EventSource(addAccessTokenParameter(LOG_EVENTSOURCE_URL));
|
||||||
es.onmessage = onMessage;
|
es.onmessage = onMessage;
|
||||||
es.onerror = () => {
|
es.onerror = () => {
|
||||||
es.close();
|
es.close();
|
||||||
window.location.reload();
|
toast.error('EventSource failed');
|
||||||
|
// window.location.reload();
|
||||||
};
|
};
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
@@ -124,28 +122,6 @@ const SystemLog: FC = () => {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
const saveSettings = async () => {
|
|
||||||
if (data) {
|
|
||||||
try {
|
|
||||||
const response = await SystemApi.updateLogSettings({
|
|
||||||
level: data.level,
|
|
||||||
max_messages: data.max_messages,
|
|
||||||
compact: data.compact
|
|
||||||
});
|
|
||||||
|
|
||||||
if (response.status !== 200) {
|
|
||||||
toast.error(LL.PROBLEM_UPDATING());
|
|
||||||
} else {
|
|
||||||
setOrigData(response.data);
|
|
||||||
setDirtyFlags([]);
|
|
||||||
toast.success(LL.UPDATED_OF(LL.SETTINGS()));
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
toast.error(extractErrorMessage(error, LL.PROBLEM_UPDATING()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const content = () => {
|
const content = () => {
|
||||||
if (!data) {
|
if (!data) {
|
||||||
return <FormLoader onRetry={loadData} errorMessage={errorMessage} />;
|
return <FormLoader onRetry={loadData} errorMessage={errorMessage} />;
|
||||||
@@ -231,8 +207,7 @@ const SystemLog: FC = () => {
|
|||||||
p: 1
|
p: 1
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{logEntries &&
|
{logEntries.map((e) => (
|
||||||
logEntries.events.map((e) => (
|
|
||||||
<LogEntryLine key={e.i}>
|
<LogEntryLine key={e.i}>
|
||||||
<span>{e.t}</span>
|
<span>{e.t}</span>
|
||||||
{data.compact && <span>{paddedLevelLabel(e.l)} </span>}
|
{data.compact && <span>{paddedLevelLabel(e.l)} </span>}
|
||||||
|
|||||||
@@ -35,12 +35,11 @@ import { toast } from 'react-toastify';
|
|||||||
import RestartMonitor from './RestartMonitor';
|
import RestartMonitor from './RestartMonitor';
|
||||||
import type { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
|
|
||||||
import type { SystemStatus, Version } from 'types';
|
import type { Version } from 'types';
|
||||||
import * as SystemApi from 'api/system';
|
import * as SystemApi from 'api/system';
|
||||||
import { ButtonRow, FormLoader, SectionContent, MessageBox } from 'components';
|
import { ButtonRow, FormLoader, SectionContent, MessageBox } 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 { extractErrorMessage } from 'utils';
|
|
||||||
|
|
||||||
export const VERSIONCHECK_ENDPOINT = 'https://api.github.com/repos/emsesp/EMS-ESP32/releases/latest';
|
export const VERSIONCHECK_ENDPOINT = 'https://api.github.com/repos/emsesp/EMS-ESP32/releases/latest';
|
||||||
export const VERSIONCHECK_DEV_ENDPOINT = 'https://api.github.com/repos/emsesp/EMS-ESP32/releases/tags/latest';
|
export const VERSIONCHECK_DEV_ENDPOINT = 'https://api.github.com/repos/emsesp/EMS-ESP32/releases/tags/latest';
|
||||||
@@ -52,9 +51,6 @@ function formatNumber(num: number) {
|
|||||||
|
|
||||||
const SystemStatusForm: FC = () => {
|
const SystemStatusForm: FC = () => {
|
||||||
const { LL } = useI18nContext();
|
const { LL } = useI18nContext();
|
||||||
const [restarting, setRestarting] = useState<boolean>();
|
|
||||||
|
|
||||||
const { data: data, send: loadData, error } = useRequest(SystemApi.readSystemStatus);
|
|
||||||
|
|
||||||
const { me } = useContext(AuthenticatedContext);
|
const { me } = useContext(AuthenticatedContext);
|
||||||
const [confirmRestart, setConfirmRestart] = useState<boolean>(false);
|
const [confirmRestart, setConfirmRestart] = useState<boolean>(false);
|
||||||
@@ -63,6 +59,21 @@ const SystemStatusForm: FC = () => {
|
|||||||
const [showingVersion, setShowingVersion] = useState<boolean>(false);
|
const [showingVersion, setShowingVersion] = useState<boolean>(false);
|
||||||
const [latestVersion, setLatestVersion] = useState<Version>();
|
const [latestVersion, setLatestVersion] = useState<Version>();
|
||||||
const [latestDevVersion, setLatestDevVersion] = useState<Version>();
|
const [latestDevVersion, setLatestDevVersion] = useState<Version>();
|
||||||
|
const [restarting, setRestarting] = useState<boolean>();
|
||||||
|
|
||||||
|
const { send: restartCommand } = useRequest(SystemApi.restart(), {
|
||||||
|
immediate: false
|
||||||
|
});
|
||||||
|
|
||||||
|
const { send: factoryResetCommand } = useRequest(SystemApi.factoryReset(), {
|
||||||
|
immediate: false
|
||||||
|
});
|
||||||
|
|
||||||
|
const { send: partitionCommand } = useRequest(SystemApi.partition(), {
|
||||||
|
immediate: false
|
||||||
|
});
|
||||||
|
|
||||||
|
const { data: data, send: loadData, error } = useRequest(SystemApi.readSystemStatus);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
void axios.get(VERSIONCHECK_ENDPOINT).then((response) => {
|
void axios.get(VERSIONCHECK_ENDPOINT).then((response) => {
|
||||||
@@ -83,30 +94,47 @@ const SystemStatusForm: FC = () => {
|
|||||||
|
|
||||||
const restart = async () => {
|
const restart = async () => {
|
||||||
setProcessing(true);
|
setProcessing(true);
|
||||||
try {
|
await restartCommand()
|
||||||
const response = await SystemApi.restart();
|
.then(() => {
|
||||||
if (response.status === 200) {
|
|
||||||
setRestarting(true);
|
setRestarting(true);
|
||||||
}
|
})
|
||||||
} catch (error) {
|
.catch((err) => {
|
||||||
toast.error(extractErrorMessage(error, LL.PROBLEM_LOADING()));
|
toast.error(err.message);
|
||||||
} finally {
|
})
|
||||||
|
.finally(() => {
|
||||||
setConfirmRestart(false);
|
setConfirmRestart(false);
|
||||||
setProcessing(false);
|
setProcessing(false);
|
||||||
}
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const factoryReset = async () => {
|
||||||
|
setProcessing(true);
|
||||||
|
await factoryResetCommand()
|
||||||
|
.then(() => {
|
||||||
|
setRestarting(true);
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
toast.error(err.message);
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
setConfirmFactoryReset(false);
|
||||||
|
setProcessing(false);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const partition = async () => {
|
const partition = async () => {
|
||||||
setProcessing(true);
|
setProcessing(true);
|
||||||
try {
|
await partitionCommand()
|
||||||
await SystemApi.partition();
|
.then(() => {
|
||||||
setRestarting(true);
|
setRestarting(true);
|
||||||
} catch (error) {
|
})
|
||||||
toast.error(extractErrorMessage(error, LL.PROBLEM_LOADING()));
|
.catch((err) => {
|
||||||
} finally {
|
toast.error(err.message);
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
setConfirmRestart(false);
|
setConfirmRestart(false);
|
||||||
setProcessing(false);
|
setProcessing(false);
|
||||||
}
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const renderRestartDialog = () => (
|
const renderRestartDialog = () => (
|
||||||
@@ -201,19 +229,6 @@ const SystemStatusForm: FC = () => {
|
|||||||
</Dialog>
|
</Dialog>
|
||||||
);
|
);
|
||||||
|
|
||||||
const factoryReset = async () => {
|
|
||||||
setProcessing(true);
|
|
||||||
try {
|
|
||||||
await SystemApi.factoryReset();
|
|
||||||
setRestarting(true);
|
|
||||||
} catch (error) {
|
|
||||||
toast.error(extractErrorMessage(error, LL.PROBLEM_UPDATING()));
|
|
||||||
} finally {
|
|
||||||
setConfirmFactoryReset(false);
|
|
||||||
setProcessing(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const renderFactoryResetDialog = () => (
|
const renderFactoryResetDialog = () => (
|
||||||
<Dialog open={confirmFactoryReset} onClose={() => setConfirmFactoryReset(false)}>
|
<Dialog open={confirmFactoryReset} onClose={() => setConfirmFactoryReset(false)}>
|
||||||
<DialogTitle>{LL.FACTORY_RESET()}</DialogTitle>
|
<DialogTitle>{LL.FACTORY_RESET()}</DialogTitle>
|
||||||
@@ -243,7 +258,7 @@ const SystemStatusForm: FC = () => {
|
|||||||
|
|
||||||
const content = () => {
|
const content = () => {
|
||||||
if (!data) {
|
if (!data) {
|
||||||
return <FormLoader onRetry={loadData} errorMessage={errorMessage} />;
|
return <FormLoader onRetry={loadData} errorMessage={error?.message} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ const UploadFileForm: FC = () => {
|
|||||||
const { LL } = useI18nContext();
|
const { LL } = useI18nContext();
|
||||||
|
|
||||||
const uploadFile = useRef(async (file: File, config?: FileUploadConfig) => {
|
const uploadFile = useRef(async (file: File, config?: FileUploadConfig) => {
|
||||||
|
// TODO fileupload move to alova
|
||||||
const response = await SystemApi.uploadFile(file, config);
|
const response = await SystemApi.uploadFile(file, config);
|
||||||
if (response.status === 200) {
|
if (response.status === 200) {
|
||||||
setRestarting(true);
|
setRestarting(true);
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import { createSettingsValidator } from './validators';
|
|||||||
import type { Settings } from './types';
|
import type { Settings } from './types';
|
||||||
import type { ValidateFieldsError } from 'async-validator';
|
import type { ValidateFieldsError } from 'async-validator';
|
||||||
import type { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
|
import * as SystemApi from 'api/system';
|
||||||
import {
|
import {
|
||||||
SectionContent,
|
SectionContent,
|
||||||
FormLoader,
|
FormLoader,
|
||||||
@@ -69,7 +70,7 @@ const SettingsApplication: FC = () => {
|
|||||||
immediate: false
|
immediate: false
|
||||||
});
|
});
|
||||||
|
|
||||||
const { send: restartCommand } = useRequest(EMSESP.restart(), {
|
const { send: restartCommand } = useRequest(SystemApi.restart(), {
|
||||||
immediate: false
|
immediate: false
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ import * as EMSESP from './api';
|
|||||||
import { DeviceEntityMask } from './types';
|
import { DeviceEntityMask } from './types';
|
||||||
import type { DeviceShort, DeviceEntity } from './types';
|
import type { DeviceShort, DeviceEntity } from './types';
|
||||||
import type { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
|
import * as SystemApi from 'api/system';
|
||||||
import { ButtonRow, SectionContent, MessageBox, BlockNavigation } from 'components';
|
import { ButtonRow, SectionContent, MessageBox, BlockNavigation } from 'components';
|
||||||
|
|
||||||
import RestartMonitor from 'framework/system/RestartMonitor';
|
import RestartMonitor from 'framework/system/RestartMonitor';
|
||||||
@@ -78,7 +79,7 @@ const SettingsCustomization: FC = () => {
|
|||||||
setOriginalSettings(event.data);
|
setOriginalSettings(event.data);
|
||||||
});
|
});
|
||||||
|
|
||||||
const { send: restartCommand } = useRequest(EMSESP.restart(), {
|
const { send: restartCommand } = useRequest(SystemApi.restart(), {
|
||||||
immediate: false
|
immediate: false
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import WarningIcon from '@mui/icons-material/Warning';
|
|||||||
import { Button, Typography, Box } from '@mui/material';
|
import { Button, Typography, Box } from '@mui/material';
|
||||||
import { Table, Header, HeaderRow, HeaderCell, Body, Row, Cell } from '@table-library/react-table-library/table';
|
import { Table, Header, HeaderRow, HeaderCell, Body, Row, Cell } from '@table-library/react-table-library/table';
|
||||||
import { useTheme } from '@table-library/react-table-library/theme';
|
import { useTheme } from '@table-library/react-table-library/theme';
|
||||||
|
// eslint-disable-next-line import/named
|
||||||
import { updateState, useRequest } from 'alova';
|
import { updateState, useRequest } from 'alova';
|
||||||
import { useState, useCallback } from 'react';
|
import { useState, useCallback } from 'react';
|
||||||
import { unstable_useBlocker as useBlocker } from 'react-router-dom';
|
import { unstable_useBlocker as useBlocker } from 'react-router-dom';
|
||||||
@@ -108,8 +109,8 @@ const SettingsEntities: FC = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const saveEntities = async () => {
|
const saveEntities = async () => {
|
||||||
await writeEntities(
|
await writeEntities({
|
||||||
entities
|
entities: entities
|
||||||
.filter((ei) => !ei.deleted)
|
.filter((ei) => !ei.deleted)
|
||||||
.map((condensed_ei) => ({
|
.map((condensed_ei) => ({
|
||||||
id: condensed_ei.id,
|
id: condensed_ei.id,
|
||||||
@@ -122,7 +123,7 @@ const SettingsEntities: FC = () => {
|
|||||||
writeable: condensed_ei.writeable,
|
writeable: condensed_ei.writeable,
|
||||||
value_type: condensed_ei.value_type
|
value_type: condensed_ei.value_type
|
||||||
}))
|
}))
|
||||||
)
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
toast.success(LL.ENTITIES_UPDATED());
|
toast.success(LL.ENTITIES_UPDATED());
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import WarningIcon from '@mui/icons-material/Warning';
|
|||||||
import { Box, Typography, Divider, Stack, Button } from '@mui/material';
|
import { Box, Typography, Divider, Stack, Button } from '@mui/material';
|
||||||
import { Table, Header, HeaderRow, HeaderCell, Body, Row, Cell } from '@table-library/react-table-library/table';
|
import { Table, Header, HeaderRow, HeaderCell, Body, Row, Cell } from '@table-library/react-table-library/table';
|
||||||
import { useTheme } from '@table-library/react-table-library/theme';
|
import { useTheme } from '@table-library/react-table-library/theme';
|
||||||
|
// eslint-disable-next-line import/named
|
||||||
import { updateState, useRequest } from 'alova';
|
import { updateState, useRequest } from 'alova';
|
||||||
import { useState, useEffect, useCallback } from 'react';
|
import { useState, useEffect, useCallback } from 'react';
|
||||||
import { unstable_useBlocker as useBlocker } from 'react-router-dom';
|
import { unstable_useBlocker as useBlocker } from 'react-router-dom';
|
||||||
@@ -108,8 +109,8 @@ const SettingsScheduler: FC = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const saveSchedule = async () => {
|
const saveSchedule = async () => {
|
||||||
await writeSchedule(
|
await writeSchedule({
|
||||||
schedule
|
schedule: schedule
|
||||||
.filter((si) => !si.deleted)
|
.filter((si) => !si.deleted)
|
||||||
.map((condensed_si) => ({
|
.map((condensed_si) => ({
|
||||||
id: condensed_si.id,
|
id: condensed_si.id,
|
||||||
@@ -120,7 +121,7 @@ const SettingsScheduler: FC = () => {
|
|||||||
value: condensed_si.value,
|
value: condensed_si.value,
|
||||||
name: condensed_si.name
|
name: condensed_si.name
|
||||||
}))
|
}))
|
||||||
)
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
toast.success(LL.SCHEDULE_UPDATED());
|
toast.success(LL.SCHEDULE_UPDATED());
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -31,7 +31,6 @@ export const getBoardProfile = (boardProfile: string) =>
|
|||||||
alovaInstance.Get('/rest/boardProfile', {
|
alovaInstance.Get('/rest/boardProfile', {
|
||||||
params: { boardProfile }
|
params: { boardProfile }
|
||||||
});
|
});
|
||||||
export const restart = () => alovaInstance.Post('/rest/restart');
|
|
||||||
|
|
||||||
// DashboardSensors
|
// DashboardSensors
|
||||||
export const readSensorData = () => alovaInstance.Get<SensorData>('/rest/sensorData');
|
export const readSensorData = () => alovaInstance.Get<SensorData>('/rest/sensorData');
|
||||||
@@ -70,7 +69,7 @@ export const readSchedule = () =>
|
|||||||
alovaInstance.Get<ScheduleItem[]>('/rest/schedule', {
|
alovaInstance.Get<ScheduleItem[]>('/rest/schedule', {
|
||||||
name: 'schedule',
|
name: 'schedule',
|
||||||
transformData(data: any) {
|
transformData(data: any) {
|
||||||
return data.map((si: ScheduleItem) => ({
|
return data.schedule.map((si: ScheduleItem) => ({
|
||||||
...si,
|
...si,
|
||||||
o_id: si.id,
|
o_id: si.id,
|
||||||
o_active: si.active,
|
o_active: si.active,
|
||||||
@@ -85,12 +84,12 @@ export const readSchedule = () =>
|
|||||||
});
|
});
|
||||||
export const writeSchedule = (data: any) => alovaInstance.Post('/rest/schedule', data);
|
export const writeSchedule = (data: any) => alovaInstance.Post('/rest/schedule', data);
|
||||||
|
|
||||||
// SettingsCustomization
|
// SettingsEntities
|
||||||
export const readEntities = () =>
|
export const readEntities = () =>
|
||||||
alovaInstance.Get<EntityItem[]>('/rest/entities', {
|
alovaInstance.Get<EntityItem[]>('/rest/entities', {
|
||||||
name: 'entities',
|
name: 'entities',
|
||||||
transformData(data: any) {
|
transformData(data: any) {
|
||||||
return data.map((ei: EntityItem) => ({
|
return data.entities.map((ei: EntityItem) => ({
|
||||||
...ei,
|
...ei,
|
||||||
o_id: ei.id,
|
o_id: ei.id,
|
||||||
o_device_id: ei.device_id,
|
o_device_id: ei.device_id,
|
||||||
|
|||||||
@@ -42,10 +42,6 @@ export interface LogEntry {
|
|||||||
m: string;
|
m: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LogEntries {
|
|
||||||
events: LogEntry[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface LogSettings {
|
export interface LogSettings {
|
||||||
level: number;
|
level: number;
|
||||||
max_messages: number;
|
max_messages: number;
|
||||||
|
|||||||
@@ -620,10 +620,10 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@eslint/js@npm:8.42.0":
|
"@eslint/js@npm:8.43.0":
|
||||||
version: 8.42.0
|
version: 8.43.0
|
||||||
resolution: "@eslint/js@npm:8.42.0"
|
resolution: "@eslint/js@npm:8.43.0"
|
||||||
checksum: 4ae46df1f32095cf9527d1f6a8a30512151f8eb66dd883a226face17c9e7cfdd2dcb3d4e3124fb67ac5801e0a776b1d7bba368276cfb1e1e4eefb047e38b41d6
|
checksum: ff1a1587e8f28c21dda36a331cf70ca16b76e5897cecf10f6b4c326abddf18db565ee5f71feb89cbb0d3d20ff321a2536357562c0233868eed70784640b73cf4
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -1546,7 +1546,7 @@ __metadata:
|
|||||||
alova: ^2.6.1
|
alova: ^2.6.1
|
||||||
async-validator: ^4.2.5
|
async-validator: ^4.2.5
|
||||||
axios: ^1.4.0
|
axios: ^1.4.0
|
||||||
eslint: ^8.42.0
|
eslint: ^8.43.0
|
||||||
eslint-config-airbnb: ^19.0.4
|
eslint-config-airbnb: ^19.0.4
|
||||||
eslint-config-airbnb-typescript: ^17.0.0
|
eslint-config-airbnb-typescript: ^17.0.0
|
||||||
eslint-config-prettier: ^8.8.0
|
eslint-config-prettier: ^8.8.0
|
||||||
@@ -2850,14 +2850,14 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"eslint@npm:^8.42.0":
|
"eslint@npm:^8.43.0":
|
||||||
version: 8.42.0
|
version: 8.43.0
|
||||||
resolution: "eslint@npm:8.42.0"
|
resolution: "eslint@npm:8.43.0"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@eslint-community/eslint-utils": ^4.2.0
|
"@eslint-community/eslint-utils": ^4.2.0
|
||||||
"@eslint-community/regexpp": ^4.4.0
|
"@eslint-community/regexpp": ^4.4.0
|
||||||
"@eslint/eslintrc": ^2.0.3
|
"@eslint/eslintrc": ^2.0.3
|
||||||
"@eslint/js": 8.42.0
|
"@eslint/js": 8.43.0
|
||||||
"@humanwhocodes/config-array": ^0.11.10
|
"@humanwhocodes/config-array": ^0.11.10
|
||||||
"@humanwhocodes/module-importer": ^1.0.1
|
"@humanwhocodes/module-importer": ^1.0.1
|
||||||
"@nodelib/fs.walk": ^1.2.8
|
"@nodelib/fs.walk": ^1.2.8
|
||||||
@@ -2895,7 +2895,7 @@ __metadata:
|
|||||||
text-table: ^0.2.0
|
text-table: ^0.2.0
|
||||||
bin:
|
bin:
|
||||||
eslint: bin/eslint.js
|
eslint: bin/eslint.js
|
||||||
checksum: 8ab5a3c1619008c946497a16b88a811b1f6c49a750a9bd0f81085dff4166418b9da4e46108b09d920877ab2f5981e3613332653b7f5e3917d8088bc4b8d40b5a
|
checksum: 1f9ff2c774e852c179ba569a3b672cbc4cf91aa59843ee32f7da363c10b5aad842672005ac04c760f6077b3471da428562274e0fcb0a78c2056866b3d36be948
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
|||||||
@@ -16,16 +16,15 @@ ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
|||||||
template <typename TReader, typename TStringStorage>
|
template <typename TReader, typename TStringStorage>
|
||||||
class MsgPackDeserializer {
|
class MsgPackDeserializer {
|
||||||
public:
|
public:
|
||||||
MsgPackDeserializer(MemoryPool* pool, TReader reader,
|
MsgPackDeserializer(MemoryPool * pool, TReader reader, TStringStorage stringStorage)
|
||||||
TStringStorage stringStorage)
|
: _pool(pool)
|
||||||
: _pool(pool),
|
, _reader(reader)
|
||||||
_reader(reader),
|
, _stringStorage(stringStorage)
|
||||||
_stringStorage(stringStorage),
|
, _foundSomething(false) {
|
||||||
_foundSomething(false) {}
|
}
|
||||||
|
|
||||||
template <typename TFilter>
|
template <typename TFilter>
|
||||||
DeserializationError parse(VariantData& variant, TFilter filter,
|
DeserializationError parse(VariantData & variant, TFilter filter, DeserializationOption::NestingLimit nestingLimit) {
|
||||||
DeserializationOption::NestingLimit nestingLimit) {
|
|
||||||
DeserializationError::Code err;
|
DeserializationError::Code err;
|
||||||
err = parseVariant(&variant, filter, nestingLimit);
|
err = parseVariant(&variant, filter, nestingLimit);
|
||||||
return _foundSomething ? err : DeserializationError::EmptyInput;
|
return _foundSomething ? err : DeserializationError::EmptyInput;
|
||||||
@@ -33,12 +32,10 @@ class MsgPackDeserializer {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
template <typename TFilter>
|
template <typename TFilter>
|
||||||
DeserializationError::Code parseVariant(
|
DeserializationError::Code parseVariant(VariantData * variant, TFilter filter, DeserializationOption::NestingLimit nestingLimit) {
|
||||||
VariantData* variant, TFilter filter,
|
|
||||||
DeserializationOption::NestingLimit nestingLimit) {
|
|
||||||
DeserializationError::Code err;
|
DeserializationError::Code err;
|
||||||
|
|
||||||
uint8_t code = 0; // TODO: why do we need to initialize this variable?
|
uint8_t code = 0;
|
||||||
err = readByte(code);
|
err = readByte(code);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
@@ -223,7 +220,7 @@ class MsgPackDeserializer {
|
|||||||
return DeserializationError::Ok;
|
return DeserializationError::Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
DeserializationError::Code readByte(uint8_t& value) {
|
DeserializationError::Code readByte(uint8_t & value) {
|
||||||
int c = _reader.read();
|
int c = _reader.read();
|
||||||
if (c < 0)
|
if (c < 0)
|
||||||
return DeserializationError::IncompleteInput;
|
return DeserializationError::IncompleteInput;
|
||||||
@@ -231,15 +228,15 @@ class MsgPackDeserializer {
|
|||||||
return DeserializationError::Ok;
|
return DeserializationError::Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
DeserializationError::Code readBytes(uint8_t* p, size_t n) {
|
DeserializationError::Code readBytes(uint8_t * p, size_t n) {
|
||||||
if (_reader.readBytes(reinterpret_cast<char*>(p), n) == n)
|
if (_reader.readBytes(reinterpret_cast<char *>(p), n) == n)
|
||||||
return DeserializationError::Ok;
|
return DeserializationError::Ok;
|
||||||
return DeserializationError::IncompleteInput;
|
return DeserializationError::IncompleteInput;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
DeserializationError::Code readBytes(T& value) {
|
DeserializationError::Code readBytes(T & value) {
|
||||||
return readBytes(reinterpret_cast<uint8_t*>(&value), sizeof(value));
|
return readBytes(reinterpret_cast<uint8_t *>(&value), sizeof(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
DeserializationError::Code skipBytes(size_t n) {
|
DeserializationError::Code skipBytes(size_t n) {
|
||||||
@@ -251,7 +248,7 @@ class MsgPackDeserializer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
DeserializationError::Code readInteger(T& value) {
|
DeserializationError::Code readInteger(T & value) {
|
||||||
DeserializationError::Code err;
|
DeserializationError::Code err;
|
||||||
|
|
||||||
err = readBytes(value);
|
err = readBytes(value);
|
||||||
@@ -264,7 +261,7 @@ class MsgPackDeserializer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
DeserializationError::Code readInteger(VariantData* variant) {
|
DeserializationError::Code readInteger(VariantData * variant) {
|
||||||
DeserializationError::Code err;
|
DeserializationError::Code err;
|
||||||
T value;
|
T value;
|
||||||
|
|
||||||
@@ -278,8 +275,7 @@ class MsgPackDeserializer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
typename enable_if<sizeof(T) == 4, DeserializationError::Code>::type
|
typename enable_if<sizeof(T) == 4, DeserializationError::Code>::type readFloat(VariantData * variant) {
|
||||||
readFloat(VariantData* variant) {
|
|
||||||
DeserializationError::Code err;
|
DeserializationError::Code err;
|
||||||
T value;
|
T value;
|
||||||
|
|
||||||
@@ -294,8 +290,7 @@ class MsgPackDeserializer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
typename enable_if<sizeof(T) == 8, DeserializationError::Code>::type
|
typename enable_if<sizeof(T) == 8, DeserializationError::Code>::type readDouble(VariantData * variant) {
|
||||||
readDouble(VariantData* variant) {
|
|
||||||
DeserializationError::Code err;
|
DeserializationError::Code err;
|
||||||
T value;
|
T value;
|
||||||
|
|
||||||
@@ -310,12 +305,11 @@ class MsgPackDeserializer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
typename enable_if<sizeof(T) == 4, DeserializationError::Code>::type
|
typename enable_if<sizeof(T) == 4, DeserializationError::Code>::type readDouble(VariantData * variant) {
|
||||||
readDouble(VariantData* variant) {
|
|
||||||
DeserializationError::Code err;
|
DeserializationError::Code err;
|
||||||
uint8_t i[8]; // input is 8 bytes
|
uint8_t i[8]; // input is 8 bytes
|
||||||
T value; // output is 4 bytes
|
T value; // output is 4 bytes
|
||||||
uint8_t* o = reinterpret_cast<uint8_t*>(&value);
|
uint8_t * o = reinterpret_cast<uint8_t *>(&value);
|
||||||
|
|
||||||
err = readBytes(i, 8);
|
err = readBytes(i, 8);
|
||||||
if (err)
|
if (err)
|
||||||
@@ -329,7 +323,7 @@ class MsgPackDeserializer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
DeserializationError::Code readString(VariantData* variant) {
|
DeserializationError::Code readString(VariantData * variant) {
|
||||||
DeserializationError::Code err;
|
DeserializationError::Code err;
|
||||||
T size;
|
T size;
|
||||||
|
|
||||||
@@ -364,7 +358,7 @@ class MsgPackDeserializer {
|
|||||||
return skipBytes(size);
|
return skipBytes(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
DeserializationError::Code readString(VariantData* variant, size_t n) {
|
DeserializationError::Code readString(VariantData * variant, size_t n) {
|
||||||
DeserializationError::Code err;
|
DeserializationError::Code err;
|
||||||
|
|
||||||
err = readString(n);
|
err = readString(n);
|
||||||
@@ -396,9 +390,7 @@ class MsgPackDeserializer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename TSize, typename TFilter>
|
template <typename TSize, typename TFilter>
|
||||||
DeserializationError::Code readArray(
|
DeserializationError::Code readArray(VariantData * variant, TFilter filter, DeserializationOption::NestingLimit nestingLimit) {
|
||||||
VariantData* variant, TFilter filter,
|
|
||||||
DeserializationOption::NestingLimit nestingLimit) {
|
|
||||||
DeserializationError::Code err;
|
DeserializationError::Code err;
|
||||||
TSize size;
|
TSize size;
|
||||||
|
|
||||||
@@ -410,9 +402,7 @@ class MsgPackDeserializer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename TFilter>
|
template <typename TFilter>
|
||||||
DeserializationError::Code readArray(
|
DeserializationError::Code readArray(VariantData * variant, size_t n, TFilter filter, DeserializationOption::NestingLimit nestingLimit) {
|
||||||
VariantData* variant, size_t n, TFilter filter,
|
|
||||||
DeserializationOption::NestingLimit nestingLimit) {
|
|
||||||
DeserializationError::Code err;
|
DeserializationError::Code err;
|
||||||
|
|
||||||
if (nestingLimit.reached())
|
if (nestingLimit.reached())
|
||||||
@@ -420,7 +410,7 @@ class MsgPackDeserializer {
|
|||||||
|
|
||||||
bool allowArray = filter.allowArray();
|
bool allowArray = filter.allowArray();
|
||||||
|
|
||||||
CollectionData* array;
|
CollectionData * array;
|
||||||
if (allowArray) {
|
if (allowArray) {
|
||||||
ARDUINOJSON_ASSERT(variant != 0);
|
ARDUINOJSON_ASSERT(variant != 0);
|
||||||
array = &variant->toArray();
|
array = &variant->toArray();
|
||||||
@@ -431,7 +421,7 @@ class MsgPackDeserializer {
|
|||||||
TFilter memberFilter = filter[0U];
|
TFilter memberFilter = filter[0U];
|
||||||
|
|
||||||
for (; n; --n) {
|
for (; n; --n) {
|
||||||
VariantData* value;
|
VariantData * value;
|
||||||
|
|
||||||
if (memberFilter.allow()) {
|
if (memberFilter.allow()) {
|
||||||
ARDUINOJSON_ASSERT(array != 0);
|
ARDUINOJSON_ASSERT(array != 0);
|
||||||
@@ -451,9 +441,7 @@ class MsgPackDeserializer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename TSize, typename TFilter>
|
template <typename TSize, typename TFilter>
|
||||||
DeserializationError::Code readObject(
|
DeserializationError::Code readObject(VariantData * variant, TFilter filter, DeserializationOption::NestingLimit nestingLimit) {
|
||||||
VariantData* variant, TFilter filter,
|
|
||||||
DeserializationOption::NestingLimit nestingLimit) {
|
|
||||||
DeserializationError::Code err;
|
DeserializationError::Code err;
|
||||||
TSize size;
|
TSize size;
|
||||||
|
|
||||||
@@ -465,15 +453,13 @@ class MsgPackDeserializer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename TFilter>
|
template <typename TFilter>
|
||||||
DeserializationError::Code readObject(
|
DeserializationError::Code readObject(VariantData * variant, size_t n, TFilter filter, DeserializationOption::NestingLimit nestingLimit) {
|
||||||
VariantData* variant, size_t n, TFilter filter,
|
|
||||||
DeserializationOption::NestingLimit nestingLimit) {
|
|
||||||
DeserializationError::Code err;
|
DeserializationError::Code err;
|
||||||
|
|
||||||
if (nestingLimit.reached())
|
if (nestingLimit.reached())
|
||||||
return DeserializationError::TooDeep;
|
return DeserializationError::TooDeep;
|
||||||
|
|
||||||
CollectionData* object;
|
CollectionData * object;
|
||||||
if (filter.allowObject()) {
|
if (filter.allowObject()) {
|
||||||
ARDUINOJSON_ASSERT(variant != 0);
|
ARDUINOJSON_ASSERT(variant != 0);
|
||||||
object = &variant->toObject();
|
object = &variant->toObject();
|
||||||
@@ -488,7 +474,7 @@ class MsgPackDeserializer {
|
|||||||
|
|
||||||
JsonString key = _stringStorage.str();
|
JsonString key = _stringStorage.str();
|
||||||
TFilter memberFilter = filter[key.c_str()];
|
TFilter memberFilter = filter[key.c_str()];
|
||||||
VariantData* member;
|
VariantData * member;
|
||||||
|
|
||||||
if (memberFilter.allow()) {
|
if (memberFilter.allow()) {
|
||||||
ARDUINOJSON_ASSERT(object != 0);
|
ARDUINOJSON_ASSERT(object != 0);
|
||||||
@@ -497,7 +483,7 @@ class MsgPackDeserializer {
|
|||||||
// This MUST be done before adding the slot.
|
// This MUST be done before adding the slot.
|
||||||
key = _stringStorage.save();
|
key = _stringStorage.save();
|
||||||
|
|
||||||
VariantSlot* slot = object->addSlot(_pool);
|
VariantSlot * slot = object->addSlot(_pool);
|
||||||
if (!slot)
|
if (!slot)
|
||||||
return DeserializationError::NoMemory;
|
return DeserializationError::NoMemory;
|
||||||
|
|
||||||
@@ -554,7 +540,7 @@ class MsgPackDeserializer {
|
|||||||
return skipBytes(size + 1U);
|
return skipBytes(size + 1U);
|
||||||
}
|
}
|
||||||
|
|
||||||
MemoryPool* _pool;
|
MemoryPool * _pool;
|
||||||
TReader _reader;
|
TReader _reader;
|
||||||
TStringStorage _stringStorage;
|
TStringStorage _stringStorage;
|
||||||
bool _foundSomething;
|
bool _foundSomething;
|
||||||
@@ -567,7 +553,7 @@ ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
|||||||
// Parses a MessagePack input and puts the result in a JsonDocument.
|
// Parses a MessagePack input and puts the result in a JsonDocument.
|
||||||
// https://arduinojson.org/v6/api/msgpack/deserializemsgpack/
|
// https://arduinojson.org/v6/api/msgpack/deserializemsgpack/
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
DeserializationError deserializeMsgPack(JsonDocument& doc, Args&&... args) {
|
DeserializationError deserializeMsgPack(JsonDocument & doc, Args &&... args) {
|
||||||
using namespace detail;
|
using namespace detail;
|
||||||
return deserialize<MsgPackDeserializer>(doc, detail::forward<Args>(args)...);
|
return deserialize<MsgPackDeserializer>(doc, detail::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
@@ -575,11 +561,9 @@ DeserializationError deserializeMsgPack(JsonDocument& doc, Args&&... args) {
|
|||||||
// Parses a MessagePack input and puts the result in a JsonDocument.
|
// Parses a MessagePack input and puts the result in a JsonDocument.
|
||||||
// https://arduinojson.org/v6/api/msgpack/deserializemsgpack/
|
// https://arduinojson.org/v6/api/msgpack/deserializemsgpack/
|
||||||
template <typename TChar, typename... Args>
|
template <typename TChar, typename... Args>
|
||||||
DeserializationError deserializeMsgPack(JsonDocument& doc, TChar* input,
|
DeserializationError deserializeMsgPack(JsonDocument & doc, TChar * input, Args &&... args) {
|
||||||
Args&&... args) {
|
|
||||||
using namespace detail;
|
using namespace detail;
|
||||||
return deserialize<MsgPackDeserializer>(doc, input,
|
return deserialize<MsgPackDeserializer>(doc, input, detail::forward<Args>(args)...);
|
||||||
detail::forward<Args>(args)...);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
||||||
|
|||||||
@@ -20,13 +20,14 @@ template <typename T, typename Enable = void>
|
|||||||
struct Comparer;
|
struct Comparer;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct Comparer<T, typename enable_if<IsString<T>::value>::type>
|
struct Comparer<T, typename enable_if<IsString<T>::value>::type> : ComparerBase {
|
||||||
: ComparerBase {
|
T rhs;
|
||||||
T rhs; // TODO: store adapted string?
|
|
||||||
|
|
||||||
explicit Comparer(T value) : rhs(value) {}
|
explicit Comparer(T value)
|
||||||
|
: rhs(value) {
|
||||||
|
}
|
||||||
|
|
||||||
CompareResult visitString(const char* lhs, size_t n) {
|
CompareResult visitString(const char * lhs, size_t n) {
|
||||||
int i = stringCompare(adaptString(rhs), adaptString(lhs, n));
|
int i = stringCompare(adaptString(rhs), adaptString(lhs, n));
|
||||||
if (i < 0)
|
if (i < 0)
|
||||||
return COMPARE_RESULT_GREATER;
|
return COMPARE_RESULT_GREATER;
|
||||||
@@ -45,12 +46,12 @@ struct Comparer<T, typename enable_if<IsString<T>::value>::type>
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct Comparer<T, typename enable_if<is_integral<T>::value ||
|
struct Comparer<T, typename enable_if<is_integral<T>::value || is_floating_point<T>::value>::type> : ComparerBase {
|
||||||
is_floating_point<T>::value>::type>
|
|
||||||
: ComparerBase {
|
|
||||||
T rhs;
|
T rhs;
|
||||||
|
|
||||||
explicit Comparer(T value) : rhs(value) {}
|
explicit Comparer(T value)
|
||||||
|
: rhs(value) {
|
||||||
|
}
|
||||||
|
|
||||||
CompareResult visitFloat(JsonFloat lhs) {
|
CompareResult visitFloat(JsonFloat lhs) {
|
||||||
return arithmeticCompare(lhs, rhs);
|
return arithmeticCompare(lhs, rhs);
|
||||||
@@ -77,15 +78,19 @@ struct NullComparer : ComparerBase {
|
|||||||
|
|
||||||
template <>
|
template <>
|
||||||
struct Comparer<decltype(nullptr), void> : NullComparer {
|
struct Comparer<decltype(nullptr), void> : NullComparer {
|
||||||
explicit Comparer(decltype(nullptr)) : NullComparer() {}
|
explicit Comparer(decltype(nullptr))
|
||||||
|
: NullComparer() {
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ArrayComparer : ComparerBase {
|
struct ArrayComparer : ComparerBase {
|
||||||
const CollectionData* _rhs;
|
const CollectionData * _rhs;
|
||||||
|
|
||||||
explicit ArrayComparer(const CollectionData& rhs) : _rhs(&rhs) {}
|
explicit ArrayComparer(const CollectionData & rhs)
|
||||||
|
: _rhs(&rhs) {
|
||||||
|
}
|
||||||
|
|
||||||
CompareResult visitArray(const CollectionData& lhs) {
|
CompareResult visitArray(const CollectionData & lhs) {
|
||||||
if (JsonArrayConst(&lhs) == JsonArrayConst(_rhs))
|
if (JsonArrayConst(&lhs) == JsonArrayConst(_rhs))
|
||||||
return COMPARE_RESULT_EQUAL;
|
return COMPARE_RESULT_EQUAL;
|
||||||
else
|
else
|
||||||
@@ -94,11 +99,13 @@ struct ArrayComparer : ComparerBase {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct ObjectComparer : ComparerBase {
|
struct ObjectComparer : ComparerBase {
|
||||||
const CollectionData* _rhs;
|
const CollectionData * _rhs;
|
||||||
|
|
||||||
explicit ObjectComparer(const CollectionData& rhs) : _rhs(&rhs) {}
|
explicit ObjectComparer(const CollectionData & rhs)
|
||||||
|
: _rhs(&rhs) {
|
||||||
|
}
|
||||||
|
|
||||||
CompareResult visitObject(const CollectionData& lhs) {
|
CompareResult visitObject(const CollectionData & lhs) {
|
||||||
if (JsonObjectConst(&lhs) == JsonObjectConst(_rhs))
|
if (JsonObjectConst(&lhs) == JsonObjectConst(_rhs))
|
||||||
return COMPARE_RESULT_EQUAL;
|
return COMPARE_RESULT_EQUAL;
|
||||||
else
|
else
|
||||||
@@ -107,13 +114,15 @@ struct ObjectComparer : ComparerBase {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct RawComparer : ComparerBase {
|
struct RawComparer : ComparerBase {
|
||||||
const char* _rhsData;
|
const char * _rhsData;
|
||||||
size_t _rhsSize;
|
size_t _rhsSize;
|
||||||
|
|
||||||
explicit RawComparer(const char* rhsData, size_t rhsSize)
|
explicit RawComparer(const char * rhsData, size_t rhsSize)
|
||||||
: _rhsData(rhsData), _rhsSize(rhsSize) {}
|
: _rhsData(rhsData)
|
||||||
|
, _rhsSize(rhsSize) {
|
||||||
|
}
|
||||||
|
|
||||||
CompareResult visitRawJson(const char* lhsData, size_t lhsSize) {
|
CompareResult visitRawJson(const char * lhsData, size_t lhsSize) {
|
||||||
size_t size = _rhsSize < lhsSize ? _rhsSize : lhsSize;
|
size_t size = _rhsSize < lhsSize ? _rhsSize : lhsSize;
|
||||||
int n = memcmp(lhsData, _rhsData, size);
|
int n = memcmp(lhsData, _rhsData, size);
|
||||||
if (n < 0)
|
if (n < 0)
|
||||||
@@ -126,16 +135,18 @@ struct RawComparer : ComparerBase {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct VariantComparer : ComparerBase {
|
struct VariantComparer : ComparerBase {
|
||||||
const VariantData* rhs;
|
const VariantData * rhs;
|
||||||
|
|
||||||
explicit VariantComparer(const VariantData* value) : rhs(value) {}
|
explicit VariantComparer(const VariantData * value)
|
||||||
|
: rhs(value) {
|
||||||
|
}
|
||||||
|
|
||||||
CompareResult visitArray(const CollectionData& lhs) {
|
CompareResult visitArray(const CollectionData & lhs) {
|
||||||
ArrayComparer comparer(lhs);
|
ArrayComparer comparer(lhs);
|
||||||
return accept(comparer);
|
return accept(comparer);
|
||||||
}
|
}
|
||||||
|
|
||||||
CompareResult visitObject(const CollectionData& lhs) {
|
CompareResult visitObject(const CollectionData & lhs) {
|
||||||
ObjectComparer comparer(lhs);
|
ObjectComparer comparer(lhs);
|
||||||
return accept(comparer);
|
return accept(comparer);
|
||||||
}
|
}
|
||||||
@@ -145,12 +156,12 @@ struct VariantComparer : ComparerBase {
|
|||||||
return accept(comparer);
|
return accept(comparer);
|
||||||
}
|
}
|
||||||
|
|
||||||
CompareResult visitString(const char* lhs, size_t) {
|
CompareResult visitString(const char * lhs, size_t) {
|
||||||
Comparer<const char*> comparer(lhs);
|
Comparer<const char *> comparer(lhs);
|
||||||
return accept(comparer);
|
return accept(comparer);
|
||||||
}
|
}
|
||||||
|
|
||||||
CompareResult visitRawJson(const char* lhsData, size_t lhsSize) {
|
CompareResult visitRawJson(const char * lhsData, size_t lhsSize) {
|
||||||
RawComparer comparer(lhsData, lhsSize);
|
RawComparer comparer(lhsData, lhsSize);
|
||||||
return accept(comparer);
|
return accept(comparer);
|
||||||
}
|
}
|
||||||
@@ -177,7 +188,7 @@ struct VariantComparer : ComparerBase {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
template <typename TComparer>
|
template <typename TComparer>
|
||||||
CompareResult accept(TComparer& comparer) {
|
CompareResult accept(TComparer & comparer) {
|
||||||
CompareResult reversedResult = variantAccept(rhs, comparer);
|
CompareResult reversedResult = variantAccept(rhs, comparer);
|
||||||
switch (reversedResult) {
|
switch (reversedResult) {
|
||||||
case COMPARE_RESULT_GREATER:
|
case COMPARE_RESULT_GREATER:
|
||||||
@@ -191,15 +202,14 @@ struct VariantComparer : ComparerBase {
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct Comparer<T, typename enable_if<is_convertible<
|
struct Comparer<T, typename enable_if<is_convertible<T, ArduinoJson::JsonVariantConst>::value>::type> : VariantComparer {
|
||||||
T, ArduinoJson::JsonVariantConst>::value>::type>
|
explicit Comparer(const T & value)
|
||||||
: VariantComparer {
|
: VariantComparer(VariantAttorney::getData(value)) {
|
||||||
explicit Comparer(const T& value)
|
}
|
||||||
: VariantComparer(VariantAttorney::getData(value)) {}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
CompareResult compare(ArduinoJson::JsonVariantConst lhs, const T& rhs) {
|
CompareResult compare(ArduinoJson::JsonVariantConst lhs, const T & rhs) {
|
||||||
Comparer<T> comparer(rhs);
|
Comparer<T> comparer(rhs);
|
||||||
return variantAccept(VariantAttorney::getData(lhs), comparer);
|
return variantAccept(VariantAttorney::getData(lhs), comparer);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,9 @@ const delay = (ms) => new Promise((res) => setTimeout(res, ms));
|
|||||||
const API_ENDPOINT_ROOT = '/api/';
|
const API_ENDPOINT_ROOT = '/api/';
|
||||||
const REST_ENDPOINT_ROOT = '/rest/';
|
const REST_ENDPOINT_ROOT = '/rest/';
|
||||||
|
|
||||||
|
// network poll
|
||||||
|
let countWifiScanPoll = 0;
|
||||||
|
|
||||||
// LOG
|
// LOG
|
||||||
const LOG_SETTINGS_ENDPOINT = REST_ENDPOINT_ROOT + 'logSettings';
|
const LOG_SETTINGS_ENDPOINT = REST_ENDPOINT_ROOT + 'logSettings';
|
||||||
log_settings = {
|
log_settings = {
|
||||||
@@ -27,7 +30,7 @@ log_settings = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const FETCH_LOG_ENDPOINT = REST_ENDPOINT_ROOT + 'fetchLog';
|
const FETCH_LOG_ENDPOINT = REST_ENDPOINT_ROOT + 'fetchLog';
|
||||||
const fetch_log = {
|
let fetch_log = {
|
||||||
events: [
|
events: [
|
||||||
{
|
{
|
||||||
t: '000+00:00:00.001',
|
t: '000+00:00:00.001',
|
||||||
@@ -1780,9 +1783,9 @@ const emsesp_devicedata_99 = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// CUSTOM ENTITIES
|
// CUSTOM ENTITIES
|
||||||
let emsesp_entities = [
|
let emsesp_entities = {
|
||||||
// entities: []
|
// entities: []
|
||||||
// entities: [
|
entities: [
|
||||||
{
|
{
|
||||||
id: 0,
|
id: 0,
|
||||||
device_id: 8,
|
device_id: 8,
|
||||||
@@ -1794,12 +1797,12 @@ let emsesp_entities = [
|
|||||||
value_type: 1,
|
value_type: 1,
|
||||||
writeable: true
|
writeable: true
|
||||||
}
|
}
|
||||||
];
|
]
|
||||||
|
};
|
||||||
|
|
||||||
// SCHEDULE
|
// SCHEDULE
|
||||||
let emsesp_schedule =
|
let emsesp_schedule = {
|
||||||
// schedule: [
|
schedule: [
|
||||||
[
|
|
||||||
{
|
{
|
||||||
id: 1,
|
id: 1,
|
||||||
active: true,
|
active: true,
|
||||||
@@ -1836,7 +1839,8 @@ let emsesp_schedule =
|
|||||||
value: '',
|
value: '',
|
||||||
name: 'auto_restart'
|
name: 'auto_restart'
|
||||||
}
|
}
|
||||||
];
|
]
|
||||||
|
};
|
||||||
|
|
||||||
// CUSTOMIZATIONS
|
// CUSTOMIZATIONS
|
||||||
const emsesp_deviceentities_1 = [{}];
|
const emsesp_deviceentities_1 = [{}];
|
||||||
@@ -1993,16 +1997,13 @@ const emsesp_deviceentities_4 = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
// LOG
|
// LOG
|
||||||
rest_server.get(FETCH_LOG_ENDPOINT, (req, res) => {
|
rest_server.post(FETCH_LOG_ENDPOINT, (req, res) => {
|
||||||
const encoded = msgpack.encode(fetch_log);
|
console.log('command: fetchLog');
|
||||||
console.log('fetchlog');
|
res.sendStatus(200);
|
||||||
res.write(encoded, 'binary');
|
|
||||||
res.end(null, 'binary');
|
|
||||||
});
|
});
|
||||||
rest_server.get(LOG_SETTINGS_ENDPOINT, (req, res) => {
|
rest_server.get(LOG_SETTINGS_ENDPOINT, (req, res) => {
|
||||||
res.json(log_settings);
|
res.json(log_settings);
|
||||||
});
|
});
|
||||||
// TODO do we need to send back here a res.SendStatus(200) ?
|
|
||||||
rest_server.post(LOG_SETTINGS_ENDPOINT, (req, res) => {
|
rest_server.post(LOG_SETTINGS_ENDPOINT, (req, res) => {
|
||||||
log_settings = req.body;
|
log_settings = req.body;
|
||||||
console.log(JSON.stringify(log_settings));
|
console.log(JSON.stringify(log_settings));
|
||||||
@@ -2019,14 +2020,21 @@ rest_server.get(NETWORK_SETTINGS_ENDPOINT, (req, res) => {
|
|||||||
rest_server.post(NETWORK_SETTINGS_ENDPOINT, (req, res) => {
|
rest_server.post(NETWORK_SETTINGS_ENDPOINT, (req, res) => {
|
||||||
network_settings = req.body;
|
network_settings = req.body;
|
||||||
console.log(JSON.stringify(network_settings));
|
console.log(JSON.stringify(network_settings));
|
||||||
// TODO do we need to send back here a res.SendStatus(200) ?
|
|
||||||
res.sendStatus(200);
|
res.sendStatus(200);
|
||||||
});
|
});
|
||||||
rest_server.get(LIST_NETWORKS_ENDPOINT, (req, res) => {
|
rest_server.get(LIST_NETWORKS_ENDPOINT, (req, res) => {
|
||||||
|
countWifiScanPoll = 0; // stop the poll
|
||||||
res.json(list_networks);
|
res.json(list_networks);
|
||||||
});
|
});
|
||||||
rest_server.get(SCAN_NETWORKS_ENDPOINT, (req, res) => {
|
rest_server.get(SCAN_NETWORKS_ENDPOINT, (req, res) => {
|
||||||
res.sendStatus(202); // reboot required
|
console.log('scan networks');
|
||||||
|
if (countWifiScanPoll++ === 2) {
|
||||||
|
console.log('done, have list');
|
||||||
|
res.sendStatus(200); // ready to send list
|
||||||
|
} else {
|
||||||
|
console.log('...waiting #' + countWifiScanPoll);
|
||||||
|
res.sendStatus(202); // waiting....
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// AP
|
// AP
|
||||||
@@ -2050,8 +2058,7 @@ rest_server.get(OTA_SETTINGS_ENDPOINT, (req, res) => {
|
|||||||
rest_server.post(OTA_SETTINGS_ENDPOINT, (req, res) => {
|
rest_server.post(OTA_SETTINGS_ENDPOINT, (req, res) => {
|
||||||
ota_settings = req.body;
|
ota_settings = req.body;
|
||||||
console.log(JSON.stringify(ota_settings));
|
console.log(JSON.stringify(ota_settings));
|
||||||
res.json(ota_settings);
|
res.sendStatus(200);
|
||||||
// TODO do we need to send back a res.sendStatus(200); ?
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// MQTT
|
// MQTT
|
||||||
@@ -2061,8 +2068,7 @@ rest_server.get(MQTT_SETTINGS_ENDPOINT, (req, res) => {
|
|||||||
rest_server.post(MQTT_SETTINGS_ENDPOINT, (req, res) => {
|
rest_server.post(MQTT_SETTINGS_ENDPOINT, (req, res) => {
|
||||||
mqtt_settings = req.body;
|
mqtt_settings = req.body;
|
||||||
console.log(JSON.stringify(mqtt_settings));
|
console.log(JSON.stringify(mqtt_settings));
|
||||||
res.json(mqtt_settings);
|
res.sendStatus(200);
|
||||||
// TODO do we need to send back a res.sendStatus(200); ?
|
|
||||||
});
|
});
|
||||||
rest_server.get(MQTT_STATUS_ENDPOINT, (req, res) => {
|
rest_server.get(MQTT_STATUS_ENDPOINT, (req, res) => {
|
||||||
res.json(mqtt_status);
|
res.json(mqtt_status);
|
||||||
@@ -2075,9 +2081,7 @@ rest_server.get(NTP_SETTINGS_ENDPOINT, (req, res) => {
|
|||||||
rest_server.post(NTP_SETTINGS_ENDPOINT, (req, res) => {
|
rest_server.post(NTP_SETTINGS_ENDPOINT, (req, res) => {
|
||||||
ntp_settings = req.body;
|
ntp_settings = req.body;
|
||||||
console.log(JSON.stringify(ntp_settings));
|
console.log(JSON.stringify(ntp_settings));
|
||||||
// TODO do we need to send back a res.sendStatus(200); ?
|
res.sendStatus(200);
|
||||||
|
|
||||||
res.json(ntp_settings);
|
|
||||||
});
|
});
|
||||||
rest_server.get(NTP_STATUS_ENDPOINT, (req, res) => {
|
rest_server.get(NTP_STATUS_ENDPOINT, (req, res) => {
|
||||||
res.json(ntp_status);
|
res.json(ntp_status);
|
||||||
@@ -2096,9 +2100,7 @@ rest_server.get(SECURITY_SETTINGS_ENDPOINT, (req, res) => {
|
|||||||
rest_server.post(SECURITY_SETTINGS_ENDPOINT, (req, res) => {
|
rest_server.post(SECURITY_SETTINGS_ENDPOINT, (req, res) => {
|
||||||
security_settings = req.body;
|
security_settings = req.body;
|
||||||
console.log(JSON.stringify(security_settings));
|
console.log(JSON.stringify(security_settings));
|
||||||
// TODO do we need to send back a res.sendStatus(200); ?
|
res.sendStatus(200);
|
||||||
|
|
||||||
res.json(security_settings);
|
|
||||||
});
|
});
|
||||||
rest_server.get(FEATURES_ENDPOINT, (req, res) => {
|
rest_server.get(FEATURES_ENDPOINT, (req, res) => {
|
||||||
res.json(features);
|
res.json(features);
|
||||||
@@ -2118,9 +2120,7 @@ rest_server.post(UPLOAD_FILE_ENDPOINT, (req, res) => {
|
|||||||
});
|
});
|
||||||
rest_server.post(SIGN_IN_ENDPOINT, (req, res) => {
|
rest_server.post(SIGN_IN_ENDPOINT, (req, res) => {
|
||||||
console.log('Signed in as ' + req.body.username);
|
console.log('Signed in as ' + req.body.username);
|
||||||
// TODO do we need to send back a res.sendStatus(200); ?
|
res.json(signin); // watch out, this has a return value
|
||||||
|
|
||||||
res.json(signin);
|
|
||||||
});
|
});
|
||||||
rest_server.get(GENERATE_TOKEN_ENDPOINT, (req, res) => {
|
rest_server.get(GENERATE_TOKEN_ENDPOINT, (req, res) => {
|
||||||
res.json(generate_token);
|
res.json(generate_token);
|
||||||
@@ -2693,7 +2693,7 @@ rest_server.get(SCHEDULE_ENDPOINT, (req, res) => {
|
|||||||
|
|
||||||
const ENTITIES_ENDPOINT = REST_ENDPOINT_ROOT + 'entities';
|
const ENTITIES_ENDPOINT = REST_ENDPOINT_ROOT + 'entities';
|
||||||
rest_server.get(ENTITIES_ENDPOINT, (req, res) => {
|
rest_server.get(ENTITIES_ENDPOINT, (req, res) => {
|
||||||
console.log('Sending Entities data');
|
console.log('Sending Custom Entities data');
|
||||||
res.json(emsesp_entities);
|
res.json(emsesp_entities);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -2734,5 +2734,5 @@ rest_server.get(ES_LOG_ENDPOINT, function (req, res) {
|
|||||||
log_index = 0;
|
log_index = 0;
|
||||||
}
|
}
|
||||||
fetch_log.events.push(data); // append to buffer
|
fetch_log.events.push(data); // append to buffer
|
||||||
}, 1000);
|
}, 3000);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -24,25 +24,16 @@ namespace emsesp {
|
|||||||
|
|
||||||
WebLogService::WebLogService(AsyncWebServer * server, SecurityManager * securityManager)
|
WebLogService::WebLogService(AsyncWebServer * server, SecurityManager * securityManager)
|
||||||
: events_(EVENT_SOURCE_LOG_PATH)
|
: events_(EVENT_SOURCE_LOG_PATH)
|
||||||
, setValues_(LOG_SETTINGS_PATH, std::bind(&WebLogService::setValues, this, _1, _2), 256) { // for POSTS
|
, setValues_(LOG_SETTINGS_PATH, std::bind(&WebLogService::setValues, this, _1, _2), 256) {
|
||||||
|
|
||||||
events_.setFilter(securityManager->filterRequest(AuthenticationPredicates::IS_ADMIN));
|
events_.setFilter(securityManager->filterRequest(AuthenticationPredicates::IS_ADMIN));
|
||||||
|
|
||||||
server->addHandler(&events_);
|
server->on(LOG_SETTINGS_PATH, HTTP_GET, std::bind(&WebLogService::getValues, this, _1)); // get settings
|
||||||
server->on(EVENT_SOURCE_LOG_PATH, HTTP_GET, std::bind(&WebLogService::forbidden, this, _1));
|
|
||||||
|
|
||||||
// for bring back the whole log
|
// for bring back the whole log - is a command, hence a POST
|
||||||
server->on(FETCH_LOG_PATH, HTTP_GET, std::bind(&WebLogService::fetchLog, this, _1));
|
server->on(FETCH_LOG_PATH, HTTP_POST, std::bind(&WebLogService::fetchLog, this, _1));
|
||||||
|
|
||||||
// get when page is loaded
|
|
||||||
server->on(LOG_SETTINGS_PATH, HTTP_GET, std::bind(&WebLogService::getValues, this, _1));
|
|
||||||
|
|
||||||
// for setting a level
|
|
||||||
server->addHandler(&setValues_);
|
server->addHandler(&setValues_);
|
||||||
}
|
server->addHandler(&events_);
|
||||||
|
|
||||||
void WebLogService::forbidden(AsyncWebServerRequest * request) {
|
|
||||||
request->send(403);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// start the log service with INFO level
|
// start the log service with INFO level
|
||||||
@@ -211,6 +202,7 @@ void WebLogService::transmit(const QueuedLogMessage & message) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// send the complete log buffer to the API, not filtering on log level
|
// send the complete log buffer to the API, not filtering on log level
|
||||||
|
// done by resetting the pointer
|
||||||
void WebLogService::fetchLog(AsyncWebServerRequest * request) {
|
void WebLogService::fetchLog(AsyncWebServerRequest * request) {
|
||||||
log_message_id_tail_ = 0;
|
log_message_id_tail_ = 0;
|
||||||
request->send(200);
|
request->send(200);
|
||||||
@@ -224,6 +216,8 @@ void WebLogService::setValues(AsyncWebServerRequest * request, JsonVariant & jso
|
|||||||
|
|
||||||
auto && body = json.as<JsonObject>();
|
auto && body = json.as<JsonObject>();
|
||||||
|
|
||||||
|
// TODO refactor into one load and one save
|
||||||
|
|
||||||
uuid::log::Level level = body["level"];
|
uuid::log::Level level = body["level"];
|
||||||
log_level(level);
|
log_level(level);
|
||||||
|
|
||||||
|
|||||||
@@ -58,7 +58,6 @@ class WebLogService : public uuid::log::Handler {
|
|||||||
const std::shared_ptr<const uuid::log::Message> content_; // Log message content
|
const std::shared_ptr<const uuid::log::Message> content_; // Log message content
|
||||||
};
|
};
|
||||||
|
|
||||||
void forbidden(AsyncWebServerRequest * request);
|
|
||||||
void transmit(const QueuedLogMessage & message);
|
void transmit(const QueuedLogMessage & message);
|
||||||
void fetchLog(AsyncWebServerRequest * request);
|
void fetchLog(AsyncWebServerRequest * request);
|
||||||
void getValues(AsyncWebServerRequest * request);
|
void getValues(AsyncWebServerRequest * request);
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ void WebScheduler::read(WebScheduler & webScheduler, JsonObject & root) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// call on initialization and also when the Scheduile web page is updated
|
// call on initialization and also when the Scheduile web page is saved
|
||||||
// this loads the data into the internal class
|
// this loads the data into the internal class
|
||||||
StateUpdateResult WebScheduler::update(JsonObject & root, WebScheduler & webScheduler) {
|
StateUpdateResult WebScheduler::update(JsonObject & root, WebScheduler & webScheduler) {
|
||||||
#ifdef EMSESP_STANDALONE
|
#ifdef EMSESP_STANDALONE
|
||||||
|
|||||||
Reference in New Issue
Block a user