From b1d666d7b97f69d107dae088fa262caf486d8129 Mon Sep 17 00:00:00 2001 From: Proddy Date: Sun, 18 Jun 2023 10:46:50 +0200 Subject: [PATCH] alova - refactor wifi scan --- interface/src/api/endpoints.ts | 7 +-- interface/src/api/network.ts | 5 +- interface/src/api/security.ts | 2 +- interface/src/api/system.ts | 7 ++- .../framework/network/WiFiNetworkScanner.tsx | 49 +++++++------------ .../framework/security/ManageUsersForm.tsx | 1 + .../security/SecuritySettingsForm.tsx | 1 + .../framework/system/GeneralFileUpload.tsx | 2 +- .../src/framework/system/RestartMonitor.tsx | 6 +-- .../src/framework/system/SystemStatusForm.tsx | 2 +- interface/src/project/SettingsEntities.tsx | 6 +-- .../src/project/SettingsEntitiesDialog.tsx | 4 +- lib/framework/WiFiScanner.cpp | 3 +- mock-api/server.js | 23 +++++---- 14 files changed, 58 insertions(+), 60 deletions(-) diff --git a/interface/src/api/endpoints.ts b/interface/src/api/endpoints.ts index 9153dd17c..ddb1514af 100644 --- a/interface/src/api/endpoints.ts +++ b/interface/src/api/endpoints.ts @@ -35,9 +35,10 @@ export const alovaInstance = createAlova({ responded: { onSuccess: async (response) => { - if (response.status === 202) { - throw new Error('Wait'); - } else if (response.status === 205) { + // if (response.status === 202) { + // throw new Error('Wait'); // wifi scan in progress + // } else + if (response.status === 205) { throw new Error('Reboot required'); } else if (response.status === 400) { throw new Error('Request Failed'); diff --git a/interface/src/api/network.ts b/interface/src/api/network.ts index 03bb7ead6..77610f9ed 100644 --- a/interface/src/api/network.ts +++ b/interface/src/api/network.ts @@ -4,7 +4,10 @@ import type { WiFiNetworkList, NetworkSettings, NetworkStatus } from 'types'; export const readNetworkStatus = () => alovaInstance.Get('/rest/networkStatus'); export const scanNetworks = () => alovaInstance.Get('/rest/scanNetworks'); -export const listNetworks = () => alovaInstance.Get('/rest/listNetworks'); +export const listNetworks = () => + alovaInstance.Get('/rest/listNetworks', { + name: 'listNetworks' + }); export const readNetworkSettings = () => alovaInstance.Get('/rest/networkSettings', { name: 'networkSettings' }); export const updateNetworkSettings = (wifiSettings: NetworkSettings) => diff --git a/interface/src/api/security.ts b/interface/src/api/security.ts index 1fecb6611..ff4cb4e64 100644 --- a/interface/src/api/security.ts +++ b/interface/src/api/security.ts @@ -3,7 +3,7 @@ import type { AxiosPromise } from 'axios'; import type { SecuritySettings, Token } from 'types'; -// TODO move to Alova +// TODO move these 3 to Alova export function readSecuritySettings(): AxiosPromise { return AXIOS.get('/securitySettings'); } diff --git a/interface/src/api/system.ts b/interface/src/api/system.ts index 24bdaa10e..41c4bb639 100644 --- a/interface/src/api/system.ts +++ b/interface/src/api/system.ts @@ -4,10 +4,8 @@ import type { AxiosPromise } from 'axios'; import type { OTASettings, SystemStatus, LogSettings } from 'types'; -export const readSystemStatus = (timeout?: number) => - alovaInstance.Get('/rest/systemStatus', { - params: { timeout } - }); +// SystemStatus - also used to ping in Restart monitor +export const readSystemStatus = () => alovaInstance.Get('/rest/systemStatus'); // commands export const restart = () => alovaInstance.Post('/rest/restart'); @@ -23,5 +21,6 @@ export const readLogSettings = () => alovaInstance.Get(`/rest/logSe export const updateLogSettings = (data: any) => alovaInstance.Post('/rest/logSettings', data); export const fetchLog = () => alovaInstance.Post('/rest/fetchLog'); +// TODO fileupload move to Alova export const uploadFile = (file: File, config?: FileUploadConfig): AxiosPromise => startUploadFile('/uploadFile', file, config); diff --git a/interface/src/framework/network/WiFiNetworkScanner.tsx b/interface/src/framework/network/WiFiNetworkScanner.tsx index 72a967f21..f7d227104 100644 --- a/interface/src/framework/network/WiFiNetworkScanner.tsx +++ b/interface/src/framework/network/WiFiNetworkScanner.tsx @@ -1,8 +1,8 @@ import PermScanWifiIcon from '@mui/icons-material/PermScanWifi'; import { Button } from '@mui/material'; -import { useRequest } from 'alova'; -import { useState, useCallback, useRef } from 'react'; -import { toast } from 'react-toastify'; +// eslint-disable-next-line import/named +import { updateState, useRequest } from 'alova'; +import { useState, useRef } from 'react'; import WiFiNetworkSelector from './WiFiNetworkSelector'; import type { FC } from 'react'; @@ -15,48 +15,37 @@ const NUM_POLLS = 10; const POLLING_FREQUENCY = 1000; const WiFiNetworkScanner: FC = () => { - const { LL } = useI18nContext(); - const pollCount = useRef(0); + const { LL } = useI18nContext(); const [errorMessage, setErrorMessage] = useState(); - 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 }); - const { - send: scanNetworks, - 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 + onSuccessNetworkList((event) => { + if (!event.data) { const completedPollCount = pollCount.current + 1; if (completedPollCount < NUM_POLLS) { pollCount.current = completedPollCount; - setTimeout(scanNetworks, POLLING_FREQUENCY); + setTimeout(getNetworkList, POLLING_FREQUENCY); } else { - finishedWithError(LL.PROBLEM_LOADING()); + setErrorMessage(LL.PROBLEM_LOADING()); + pollCount.current = 0; } - } else { - finishedWithError(LL.PROBLEM_LOADING()); } }); - onSuccessScanNetworks(() => { - console.log('onCompleteScanNetworks'); // TODO fix + onCompleteScanNetworks(() => { pollCount.current = 0; - void getNetworkList(); // fetch the list + setErrorMessage(undefined); + updateState('listNetworks', () => undefined); + void getNetworkList(); }); const renderNetworkScanner = () => { diff --git a/interface/src/framework/security/ManageUsersForm.tsx b/interface/src/framework/security/ManageUsersForm.tsx index e4aa4862a..1c0f6a856 100644 --- a/interface/src/framework/security/ManageUsersForm.tsx +++ b/interface/src/framework/security/ManageUsersForm.tsx @@ -23,6 +23,7 @@ import { useRest } from 'utils'; import { createUserValidator } from 'validators'; const ManageUsersForm: FC = () => { + // TODO move to Alova const { loadData, saving, data, setData, saveData, errorMessage } = useRest({ read: SecurityApi.readSecuritySettings, update: SecurityApi.updateSecuritySettings diff --git a/interface/src/framework/security/SecuritySettingsForm.tsx b/interface/src/framework/security/SecuritySettingsForm.tsx index 14930d399..67839522d 100644 --- a/interface/src/framework/security/SecuritySettingsForm.tsx +++ b/interface/src/framework/security/SecuritySettingsForm.tsx @@ -18,6 +18,7 @@ const SecuritySettingsForm: FC = () => { const { LL } = useI18nContext(); const [fieldErrors, setFieldErrors] = useState(); + // TODO move to Alova const { loadData, saving, data, setData, origData, dirtyFlags, blocker, setDirtyFlags, saveData, errorMessage } = useRest({ read: SecurityApi.readSecuritySettings, diff --git a/interface/src/framework/system/GeneralFileUpload.tsx b/interface/src/framework/system/GeneralFileUpload.tsx index 8e2243fed..e7336dc18 100644 --- a/interface/src/framework/system/GeneralFileUpload.tsx +++ b/interface/src/framework/system/GeneralFileUpload.tsx @@ -12,7 +12,7 @@ import { useI18nContext } from 'i18n/i18n-react'; import * as EMSESP from 'project/api'; interface UploadFileProps { - // TODO fileupload upload move to alova + // TODO fileupload move to alova uploadGeneralFile: (file: File, config?: FileUploadConfig) => AxiosPromise; } diff --git a/interface/src/framework/system/RestartMonitor.tsx b/interface/src/framework/system/RestartMonitor.tsx index 83ad443ba..c7112a244 100644 --- a/interface/src/framework/system/RestartMonitor.tsx +++ b/interface/src/framework/system/RestartMonitor.tsx @@ -8,7 +8,6 @@ import { FormLoader } from 'components'; import { useI18nContext } from 'i18n/i18n-react'; const RESTART_TIMEOUT = 2 * 60 * 1000; -const POLL_TIMEOUT = 2000; const POLL_INTERVAL = 5000; const RestartMonitor: FC = () => { @@ -17,14 +16,15 @@ const RestartMonitor: FC = () => { const { LL } = useI18nContext(); - const { send: readSystemStatus } = useRequest((timeout) => SystemApi.readSystemStatus(timeout), { + const { send: readSystemStatus } = useRequest(SystemApi.readSystemStatus(), { + force: true, immediate: false }); const timeoutAt = useRef(new Date().getTime() + RESTART_TIMEOUT); const poll = useRef(async () => { try { - await readSystemStatus(POLL_TIMEOUT); + await readSystemStatus(); document.location.href = '/fileUpdated'; } catch (error) { if (new Date().getTime() < timeoutAt.current) { diff --git a/interface/src/framework/system/SystemStatusForm.tsx b/interface/src/framework/system/SystemStatusForm.tsx index 54d3b922f..c90202624 100644 --- a/interface/src/framework/system/SystemStatusForm.tsx +++ b/interface/src/framework/system/SystemStatusForm.tsx @@ -73,7 +73,7 @@ const SystemStatusForm: FC = () => { immediate: false }); - const { data: data, send: loadData, error } = useRequest(SystemApi.readSystemStatus); + const { data: data, send: loadData, error } = useRequest(SystemApi.readSystemStatus, { force: true }); useEffect(() => { void axios.get(VERSIONCHECK_ENDPOINT).then((response) => { diff --git a/interface/src/project/SettingsEntities.tsx b/interface/src/project/SettingsEntities.tsx index 9d83cd329..cec062a6a 100644 --- a/interface/src/project/SettingsEntities.tsx +++ b/interface/src/project/SettingsEntities.tsx @@ -184,9 +184,7 @@ const SettingsEntities: FC = () => { } function showHex(value: number, digit: number) { - return digit === 4 - ? '0x' + ('000' + value.toString(16).toUpperCase()).slice(-4) - : '0x' + ('0' + value.toString(16).toUpperCase()).slice(-2); + return '0x' + value.toString(16).toUpperCase().padStart(digit, '0'); } const renderEntity = () => { @@ -212,7 +210,7 @@ const SettingsEntities: FC = () => { editEntityItem(ei)}> {ei.name} {showHex(ei.device_id as number, 2)} - {showHex(ei.type_id as number, 4)} + {showHex(ei.type_id as number, 3)} {ei.offset} {formatValue(ei.value, ei.uom)} diff --git a/interface/src/project/SettingsEntitiesDialog.tsx b/interface/src/project/SettingsEntitiesDialog.tsx index 1ae09bbd0..5e16f627b 100644 --- a/interface/src/project/SettingsEntitiesDialog.tsx +++ b/interface/src/project/SettingsEntitiesDialog.tsx @@ -58,8 +58,8 @@ const SettingsEntitiesDialog = ({ // convert to hex strings straight away setEditItem({ ...selectedItem, - device_id: selectedItem.device_id.toString(16).toUpperCase().slice(-2), - type_id: selectedItem.type_id.toString(16).toUpperCase().slice(-4) + device_id: selectedItem.device_id.toString(16).toUpperCase(), + type_id: selectedItem.type_id.toString(16).toUpperCase() }); } }, [open, selectedItem]); diff --git a/lib/framework/WiFiScanner.cpp b/lib/framework/WiFiScanner.cpp index 708179686..3813c9ff6 100644 --- a/lib/framework/WiFiScanner.cpp +++ b/lib/framework/WiFiScanner.cpp @@ -12,11 +12,12 @@ WiFiScanner::WiFiScanner(AsyncWebServer * server, SecurityManager * securityMana }; void WiFiScanner::scanNetworks(AsyncWebServerRequest * request) { + request->send(202); // special code to indicate scan in progress + if (WiFi.scanComplete() != -1) { WiFi.scanDelete(); WiFi.scanNetworks(true); } - request->send(202); // special code to indicate scan in progress } void WiFiScanner::listNetworks(AsyncWebServerRequest * request) { diff --git a/mock-api/server.js b/mock-api/server.js index df2096afb..045ab6695 100644 --- a/mock-api/server.js +++ b/mock-api/server.js @@ -271,7 +271,8 @@ const FACTORY_RESET_ENDPOINT = REST_ENDPOINT_ROOT + 'factoryReset'; const UPLOAD_FILE_ENDPOINT = REST_ENDPOINT_ROOT + 'uploadFile'; const SIGN_IN_ENDPOINT = REST_ENDPOINT_ROOT + 'signIn'; const GENERATE_TOKEN_ENDPOINT = REST_ENDPOINT_ROOT + 'generateToken'; -const system_status = { + +let system_status = { emsesp_version: '3.6.0-demo', esp_platform: 'ESP32', max_alloc_heap: 89, @@ -2023,19 +2024,20 @@ rest_server.post(NETWORK_SETTINGS_ENDPOINT, (req, res) => { res.sendStatus(200); }); rest_server.get(LIST_NETWORKS_ENDPOINT, (req, res) => { - countWifiScanPoll = 0; // stop the poll - res.json(list_networks); -}); -rest_server.get(SCAN_NETWORKS_ENDPOINT, (req, res) => { - console.log('scan networks'); - if (countWifiScanPoll++ === 2) { + if (countWifiScanPoll++ === 4) { console.log('done, have list'); - res.sendStatus(200); // ready to send list + res.json(list_networks); // send list } else { 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 rest_server.get(AP_SETTINGS_ENDPOINT, (req, res) => { @@ -2092,6 +2094,9 @@ rest_server.post(TIME_ENDPOINT, (req, res) => { // SYSTEM 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); }); rest_server.get(SECURITY_SETTINGS_ENDPOINT, (req, res) => {