alova - refactor wifi scan

This commit is contained in:
Proddy
2023-06-18 10:46:50 +02:00
parent ed55a96b80
commit b1d666d7b9
14 changed files with 58 additions and 60 deletions

View File

@@ -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');

View File

@@ -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) =>

View File

@@ -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');
} }

View File

@@ -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);

View File

@@ -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 = () => {

View File

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

View File

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

View File

@@ -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>;
} }

View File

@@ -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) {

View File

@@ -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) => {

View File

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

View File

@@ -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]);

View File

@@ -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) {

View File

@@ -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) => {