mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-06 15:59:52 +03:00
alova - refactor wifi scan
This commit is contained in:
@@ -35,9 +35,10 @@ export const alovaInstance = createAlova({
|
|||||||
|
|
||||||
responded: {
|
responded: {
|
||||||
onSuccess: async (response) => {
|
onSuccess: async (response) => {
|
||||||
if (response.status === 202) {
|
// if (response.status === 202) {
|
||||||
throw new Error('Wait');
|
// throw new Error('Wait'); // wifi scan in progress
|
||||||
} else if (response.status === 205) {
|
// } 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');
|
||||||
|
|||||||
@@ -4,7 +4,10 @@ import type { WiFiNetworkList, NetworkSettings, NetworkStatus } from 'types';
|
|||||||
|
|
||||||
export const readNetworkStatus = () => alovaInstance.Get<NetworkStatus>('/rest/networkStatus');
|
export const readNetworkStatus = () => alovaInstance.Get<NetworkStatus>('/rest/networkStatus');
|
||||||
export const scanNetworks = () => alovaInstance.Get('/rest/scanNetworks');
|
export const scanNetworks = () => alovaInstance.Get('/rest/scanNetworks');
|
||||||
export const listNetworks = () => alovaInstance.Get<WiFiNetworkList>('/rest/listNetworks');
|
export const listNetworks = () =>
|
||||||
|
alovaInstance.Get<WiFiNetworkList>('/rest/listNetworks', {
|
||||||
|
name: 'listNetworks'
|
||||||
|
});
|
||||||
export const readNetworkSettings = () =>
|
export const readNetworkSettings = () =>
|
||||||
alovaInstance.Get<NetworkSettings>('/rest/networkSettings', { name: 'networkSettings' });
|
alovaInstance.Get<NetworkSettings>('/rest/networkSettings', { name: 'networkSettings' });
|
||||||
export const updateNetworkSettings = (wifiSettings: NetworkSettings) =>
|
export const updateNetworkSettings = (wifiSettings: NetworkSettings) =>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import type { AxiosPromise } from 'axios';
|
|||||||
|
|
||||||
import type { SecuritySettings, Token } from 'types';
|
import type { SecuritySettings, Token } from 'types';
|
||||||
|
|
||||||
// TODO move to Alova
|
// TODO move these 3 to Alova
|
||||||
export function readSecuritySettings(): AxiosPromise<SecuritySettings> {
|
export function readSecuritySettings(): AxiosPromise<SecuritySettings> {
|
||||||
return AXIOS.get('/securitySettings');
|
return AXIOS.get('/securitySettings');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,10 +4,8 @@ import type { AxiosPromise } from 'axios';
|
|||||||
|
|
||||||
import type { OTASettings, SystemStatus, LogSettings } from 'types';
|
import type { OTASettings, SystemStatus, LogSettings } from 'types';
|
||||||
|
|
||||||
export const readSystemStatus = (timeout?: number) =>
|
// SystemStatus - also used to ping in Restart monitor
|
||||||
alovaInstance.Get<SystemStatus>('/rest/systemStatus', {
|
export const readSystemStatus = () => alovaInstance.Get<SystemStatus>('/rest/systemStatus');
|
||||||
params: { timeout }
|
|
||||||
});
|
|
||||||
|
|
||||||
// commands
|
// commands
|
||||||
export const restart = () => alovaInstance.Post('/rest/restart');
|
export const restart = () => alovaInstance.Post('/rest/restart');
|
||||||
@@ -23,5 +21,6 @@ export const readLogSettings = () => alovaInstance.Get<LogSettings>(`/rest/logSe
|
|||||||
export const updateLogSettings = (data: any) => alovaInstance.Post('/rest/logSettings', data);
|
export const updateLogSettings = (data: any) => alovaInstance.Post('/rest/logSettings', data);
|
||||||
export const fetchLog = () => alovaInstance.Post('/rest/fetchLog');
|
export const fetchLog = () => alovaInstance.Post('/rest/fetchLog');
|
||||||
|
|
||||||
|
// TODO fileupload move to Alova
|
||||||
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);
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
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 { useRequest } from 'alova';
|
// eslint-disable-next-line import/named
|
||||||
import { useState, useCallback, useRef } from 'react';
|
import { updateState, useRequest } from 'alova';
|
||||||
import { toast } from 'react-toastify';
|
import { useState, useRef } from 'react';
|
||||||
|
|
||||||
import WiFiNetworkSelector from './WiFiNetworkSelector';
|
import WiFiNetworkSelector from './WiFiNetworkSelector';
|
||||||
import type { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
@@ -15,48 +15,37 @@ const NUM_POLLS = 10;
|
|||||||
const POLLING_FREQUENCY = 1000;
|
const POLLING_FREQUENCY = 1000;
|
||||||
|
|
||||||
const WiFiNetworkScanner: FC = () => {
|
const WiFiNetworkScanner: FC = () => {
|
||||||
const { LL } = useI18nContext();
|
|
||||||
|
|
||||||
const pollCount = useRef(0);
|
const pollCount = useRef(0);
|
||||||
|
const { LL } = useI18nContext();
|
||||||
const [errorMessage, setErrorMessage] = useState<string>();
|
const [errorMessage, setErrorMessage] = useState<string>();
|
||||||
|
|
||||||
const { data: networkList, send: getNetworkList } = useRequest(NetworkApi.listNetworks, {
|
const { send: scanNetworks, onComplete: onCompleteScanNetworks } = useRequest(NetworkApi.scanNetworks); // is called on page load to start network scan
|
||||||
|
const {
|
||||||
|
data: networkList,
|
||||||
|
send: getNetworkList,
|
||||||
|
onSuccess: onSuccessNetworkList
|
||||||
|
} = useRequest(NetworkApi.listNetworks, {
|
||||||
immediate: false
|
immediate: false
|
||||||
});
|
});
|
||||||
|
|
||||||
const {
|
onSuccessNetworkList((event) => {
|
||||||
send: scanNetworks,
|
if (!event.data) {
|
||||||
onSuccess: onSuccessScanNetworks,
|
|
||||||
onError: onErrorScanNetworks
|
|
||||||
} = useRequest(NetworkApi.scanNetworks);
|
|
||||||
|
|
||||||
const finishedWithError = useCallback((message: string) => {
|
|
||||||
toast.error(message);
|
|
||||||
setErrorMessage(message);
|
|
||||||
pollCount.current = 0;
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
onErrorScanNetworks((event) => {
|
|
||||||
console.log('onErrorScanNetworks'); // TODO fix
|
|
||||||
if (event.error?.message === 'Wait') {
|
|
||||||
// 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(scanNetworks, POLLING_FREQUENCY);
|
setTimeout(getNetworkList, POLLING_FREQUENCY);
|
||||||
} else {
|
} else {
|
||||||
finishedWithError(LL.PROBLEM_LOADING());
|
setErrorMessage(LL.PROBLEM_LOADING());
|
||||||
|
pollCount.current = 0;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
finishedWithError(LL.PROBLEM_LOADING());
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
onSuccessScanNetworks(() => {
|
onCompleteScanNetworks(() => {
|
||||||
console.log('onCompleteScanNetworks'); // TODO fix
|
|
||||||
pollCount.current = 0;
|
pollCount.current = 0;
|
||||||
void getNetworkList(); // fetch the list
|
setErrorMessage(undefined);
|
||||||
|
updateState('listNetworks', () => undefined);
|
||||||
|
void getNetworkList();
|
||||||
});
|
});
|
||||||
|
|
||||||
const renderNetworkScanner = () => {
|
const renderNetworkScanner = () => {
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import { useRest } from 'utils';
|
|||||||
import { createUserValidator } from 'validators';
|
import { createUserValidator } from 'validators';
|
||||||
|
|
||||||
const ManageUsersForm: FC = () => {
|
const ManageUsersForm: FC = () => {
|
||||||
|
// TODO move to Alova
|
||||||
const { loadData, saving, data, setData, saveData, errorMessage } = useRest<SecuritySettings>({
|
const { loadData, saving, data, setData, saveData, errorMessage } = useRest<SecuritySettings>({
|
||||||
read: SecurityApi.readSecuritySettings,
|
read: SecurityApi.readSecuritySettings,
|
||||||
update: SecurityApi.updateSecuritySettings
|
update: SecurityApi.updateSecuritySettings
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ const SecuritySettingsForm: FC = () => {
|
|||||||
const { LL } = useI18nContext();
|
const { LL } = useI18nContext();
|
||||||
|
|
||||||
const [fieldErrors, setFieldErrors] = useState<ValidateFieldsError>();
|
const [fieldErrors, setFieldErrors] = useState<ValidateFieldsError>();
|
||||||
|
// TODO move to Alova
|
||||||
const { loadData, saving, data, setData, origData, dirtyFlags, blocker, setDirtyFlags, saveData, errorMessage } =
|
const { loadData, saving, data, setData, origData, dirtyFlags, blocker, setDirtyFlags, saveData, errorMessage } =
|
||||||
useRest<SecuritySettings>({
|
useRest<SecuritySettings>({
|
||||||
read: SecurityApi.readSecuritySettings,
|
read: SecurityApi.readSecuritySettings,
|
||||||
|
|||||||
@@ -12,7 +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
|
// TODO fileupload move to alova
|
||||||
uploadGeneralFile: (file: File, config?: FileUploadConfig) => AxiosPromise<void>;
|
uploadGeneralFile: (file: File, config?: FileUploadConfig) => AxiosPromise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import { FormLoader } from 'components';
|
|||||||
import { useI18nContext } from 'i18n/i18n-react';
|
import { useI18nContext } from 'i18n/i18n-react';
|
||||||
|
|
||||||
const RESTART_TIMEOUT = 2 * 60 * 1000;
|
const RESTART_TIMEOUT = 2 * 60 * 1000;
|
||||||
const POLL_TIMEOUT = 2000;
|
|
||||||
const POLL_INTERVAL = 5000;
|
const POLL_INTERVAL = 5000;
|
||||||
|
|
||||||
const RestartMonitor: FC = () => {
|
const RestartMonitor: FC = () => {
|
||||||
@@ -17,14 +16,15 @@ const RestartMonitor: FC = () => {
|
|||||||
|
|
||||||
const { LL } = useI18nContext();
|
const { LL } = useI18nContext();
|
||||||
|
|
||||||
const { send: readSystemStatus } = useRequest((timeout) => SystemApi.readSystemStatus(timeout), {
|
const { send: readSystemStatus } = useRequest(SystemApi.readSystemStatus(), {
|
||||||
|
force: true,
|
||||||
immediate: false
|
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 readSystemStatus(POLL_TIMEOUT);
|
await readSystemStatus();
|
||||||
document.location.href = '/fileUpdated';
|
document.location.href = '/fileUpdated';
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (new Date().getTime() < timeoutAt.current) {
|
if (new Date().getTime() < timeoutAt.current) {
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ const SystemStatusForm: FC = () => {
|
|||||||
immediate: false
|
immediate: false
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data: data, send: loadData, error } = useRequest(SystemApi.readSystemStatus);
|
const { data: data, send: loadData, error } = useRequest(SystemApi.readSystemStatus, { force: true });
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
void axios.get(VERSIONCHECK_ENDPOINT).then((response) => {
|
void axios.get(VERSIONCHECK_ENDPOINT).then((response) => {
|
||||||
|
|||||||
@@ -184,9 +184,7 @@ const SettingsEntities: FC = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function showHex(value: number, digit: number) {
|
function showHex(value: number, digit: number) {
|
||||||
return digit === 4
|
return '0x' + value.toString(16).toUpperCase().padStart(digit, '0');
|
||||||
? '0x' + ('000' + value.toString(16).toUpperCase()).slice(-4)
|
|
||||||
: '0x' + ('0' + value.toString(16).toUpperCase()).slice(-2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const renderEntity = () => {
|
const renderEntity = () => {
|
||||||
@@ -212,7 +210,7 @@ const SettingsEntities: FC = () => {
|
|||||||
<Row key={ei.name} item={ei} onClick={() => editEntityItem(ei)}>
|
<Row key={ei.name} item={ei} onClick={() => editEntityItem(ei)}>
|
||||||
<Cell>{ei.name}</Cell>
|
<Cell>{ei.name}</Cell>
|
||||||
<Cell>{showHex(ei.device_id as number, 2)}</Cell>
|
<Cell>{showHex(ei.device_id as number, 2)}</Cell>
|
||||||
<Cell>{showHex(ei.type_id as number, 4)}</Cell>
|
<Cell>{showHex(ei.type_id as number, 3)}</Cell>
|
||||||
<Cell>{ei.offset}</Cell>
|
<Cell>{ei.offset}</Cell>
|
||||||
<Cell>{formatValue(ei.value, ei.uom)}</Cell>
|
<Cell>{formatValue(ei.value, ei.uom)}</Cell>
|
||||||
</Row>
|
</Row>
|
||||||
|
|||||||
@@ -58,8 +58,8 @@ const SettingsEntitiesDialog = ({
|
|||||||
// convert to hex strings straight away
|
// convert to hex strings straight away
|
||||||
setEditItem({
|
setEditItem({
|
||||||
...selectedItem,
|
...selectedItem,
|
||||||
device_id: selectedItem.device_id.toString(16).toUpperCase().slice(-2),
|
device_id: selectedItem.device_id.toString(16).toUpperCase(),
|
||||||
type_id: selectedItem.type_id.toString(16).toUpperCase().slice(-4)
|
type_id: selectedItem.type_id.toString(16).toUpperCase()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [open, selectedItem]);
|
}, [open, selectedItem]);
|
||||||
|
|||||||
@@ -12,11 +12,12 @@ WiFiScanner::WiFiScanner(AsyncWebServer * server, SecurityManager * securityMana
|
|||||||
};
|
};
|
||||||
|
|
||||||
void WiFiScanner::scanNetworks(AsyncWebServerRequest * request) {
|
void WiFiScanner::scanNetworks(AsyncWebServerRequest * request) {
|
||||||
|
request->send(202); // special code to indicate scan in progress
|
||||||
|
|
||||||
if (WiFi.scanComplete() != -1) {
|
if (WiFi.scanComplete() != -1) {
|
||||||
WiFi.scanDelete();
|
WiFi.scanDelete();
|
||||||
WiFi.scanNetworks(true);
|
WiFi.scanNetworks(true);
|
||||||
}
|
}
|
||||||
request->send(202); // special code to indicate scan in progress
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WiFiScanner::listNetworks(AsyncWebServerRequest * request) {
|
void WiFiScanner::listNetworks(AsyncWebServerRequest * request) {
|
||||||
|
|||||||
@@ -271,7 +271,8 @@ const FACTORY_RESET_ENDPOINT = REST_ENDPOINT_ROOT + 'factoryReset';
|
|||||||
const UPLOAD_FILE_ENDPOINT = REST_ENDPOINT_ROOT + 'uploadFile';
|
const UPLOAD_FILE_ENDPOINT = REST_ENDPOINT_ROOT + 'uploadFile';
|
||||||
const SIGN_IN_ENDPOINT = REST_ENDPOINT_ROOT + 'signIn';
|
const SIGN_IN_ENDPOINT = REST_ENDPOINT_ROOT + 'signIn';
|
||||||
const GENERATE_TOKEN_ENDPOINT = REST_ENDPOINT_ROOT + 'generateToken';
|
const GENERATE_TOKEN_ENDPOINT = REST_ENDPOINT_ROOT + 'generateToken';
|
||||||
const system_status = {
|
|
||||||
|
let system_status = {
|
||||||
emsesp_version: '3.6.0-demo',
|
emsesp_version: '3.6.0-demo',
|
||||||
esp_platform: 'ESP32',
|
esp_platform: 'ESP32',
|
||||||
max_alloc_heap: 89,
|
max_alloc_heap: 89,
|
||||||
@@ -2023,19 +2024,20 @@ rest_server.post(NETWORK_SETTINGS_ENDPOINT, (req, res) => {
|
|||||||
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
|
if (countWifiScanPoll++ === 4) {
|
||||||
res.json(list_networks);
|
|
||||||
});
|
|
||||||
rest_server.get(SCAN_NETWORKS_ENDPOINT, (req, res) => {
|
|
||||||
console.log('scan networks');
|
|
||||||
if (countWifiScanPoll++ === 2) {
|
|
||||||
console.log('done, have list');
|
console.log('done, have list');
|
||||||
res.sendStatus(200); // ready to send list
|
res.json(list_networks); // send list
|
||||||
} else {
|
} else {
|
||||||
console.log('...waiting #' + countWifiScanPoll);
|
console.log('...waiting #' + countWifiScanPoll);
|
||||||
res.sendStatus(202); // waiting....
|
res.sendStatus(200); // waiting....
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
// TODO should be a post as its a command?
|
||||||
|
rest_server.get(SCAN_NETWORKS_ENDPOINT, (req, res) => {
|
||||||
|
console.log('start scan networks');
|
||||||
|
countWifiScanPoll = 0; // stop the poll
|
||||||
|
res.sendStatus(200); // always 202, poll for list
|
||||||
|
});
|
||||||
|
|
||||||
// AP
|
// AP
|
||||||
rest_server.get(AP_SETTINGS_ENDPOINT, (req, res) => {
|
rest_server.get(AP_SETTINGS_ENDPOINT, (req, res) => {
|
||||||
@@ -2092,6 +2094,9 @@ rest_server.post(TIME_ENDPOINT, (req, res) => {
|
|||||||
|
|
||||||
// SYSTEM
|
// SYSTEM
|
||||||
rest_server.get(SYSTEM_STATUS_ENDPOINT, (req, res) => {
|
rest_server.get(SYSTEM_STATUS_ENDPOINT, (req, res) => {
|
||||||
|
console.log('get systemStatus');
|
||||||
|
// create some random data to see if caching works
|
||||||
|
system_status.fs_used = Math.floor(Math.random() * (Math.floor(200) - 100) + 100);
|
||||||
res.json(system_status);
|
res.json(system_status);
|
||||||
});
|
});
|
||||||
rest_server.get(SECURITY_SETTINGS_ENDPOINT, (req, res) => {
|
rest_server.get(SECURITY_SETTINGS_ENDPOINT, (req, res) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user