From 4f399b51f5d192e0f126948f597213c2b9166159 Mon Sep 17 00:00:00 2001 From: Proddy Date: Sat, 7 May 2022 17:46:13 +0200 Subject: [PATCH 01/13] package updates --- interface/package-lock.json | 14 +++++++------- interface/package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/interface/package-lock.json b/interface/package-lock.json index d40e263ce..77fea275b 100644 --- a/interface/package-lock.json +++ b/interface/package-lock.json @@ -29,7 +29,7 @@ "react": "^17.0.2", "react-app-rewired": "^2.2.1", "react-dom": "^17.0.2", - "react-dropzone": "^14.2.0", + "react-dropzone": "^14.2.1", "react-icons": "^4.3.1", "react-router-dom": "^6.3.0", "react-scripts": "5.0.1", @@ -14437,9 +14437,9 @@ } }, "node_modules/react-dropzone": { - "version": "14.2.0", - "resolved": "https://registry.npmjs.org/react-dropzone/-/react-dropzone-14.2.0.tgz", - "integrity": "sha512-D7AXPtRba8rd7DBOejh3W2v1Uax6i7XKPYPuMr13XFPfnDcPHHvlEfp3raVpdj3XMHlRfYuf2H5+m8p7mlgKdQ==", + "version": "14.2.1", + "resolved": "https://registry.npmjs.org/react-dropzone/-/react-dropzone-14.2.1.tgz", + "integrity": "sha512-jzX6wDtAjlfwZ+Fbg+G17EszWUkQVxhMTWMfAC9qSUq7II2pKglHA8aarbFKl0mLpRPDaNUcy+HD/Sf4gkf76Q==", "dependencies": { "attr-accept": "^2.2.2", "file-selector": "^0.6.0", @@ -27793,9 +27793,9 @@ } }, "react-dropzone": { - "version": "14.2.0", - "resolved": "https://registry.npmjs.org/react-dropzone/-/react-dropzone-14.2.0.tgz", - "integrity": "sha512-D7AXPtRba8rd7DBOejh3W2v1Uax6i7XKPYPuMr13XFPfnDcPHHvlEfp3raVpdj3XMHlRfYuf2H5+m8p7mlgKdQ==", + "version": "14.2.1", + "resolved": "https://registry.npmjs.org/react-dropzone/-/react-dropzone-14.2.1.tgz", + "integrity": "sha512-jzX6wDtAjlfwZ+Fbg+G17EszWUkQVxhMTWMfAC9qSUq7II2pKglHA8aarbFKl0mLpRPDaNUcy+HD/Sf4gkf76Q==", "requires": { "attr-accept": "^2.2.2", "file-selector": "^0.6.0", diff --git a/interface/package.json b/interface/package.json index 837318bef..413709d0b 100644 --- a/interface/package.json +++ b/interface/package.json @@ -25,7 +25,7 @@ "react": "^17.0.2", "react-app-rewired": "^2.2.1", "react-dom": "^17.0.2", - "react-dropzone": "^14.2.0", + "react-dropzone": "^14.2.1", "react-icons": "^4.3.1", "react-router-dom": "^6.3.0", "react-scripts": "5.0.1", From b35ab94509a7a436f993f02a85575df058d42301 Mon Sep 17 00:00:00 2001 From: Proddy Date: Sat, 7 May 2022 17:46:31 +0200 Subject: [PATCH 02/13] upload script example --- scripts/upload_fw.py | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 scripts/upload_fw.py diff --git a/scripts/upload_fw.py b/scripts/upload_fw.py new file mode 100644 index 000000000..0de980efe --- /dev/null +++ b/scripts/upload_fw.py @@ -0,0 +1,10 @@ +# for calling dos upload from Window WSL2 Linux, because serial ports are not mapped yet +# example file +Import('env') +from subprocess import call + +def upload(source, target, env): + print("bin file: " + str(target[0])) + call(["cmd.exe", "/c", "c:\\Users\\paul\\OneDrive\\Desktop\\ems-esp32.bat"]) + +env.AddPostAction("$BUILD_DIR/${PROGNAME}.bin", [upload]) From f243162724e1e46cb829b9891d6b956bb8dfb242 Mon Sep 17 00:00:00 2001 From: Proddy Date: Sat, 7 May 2022 17:46:49 +0200 Subject: [PATCH 03/13] comments --- lib_standalone/Features.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib_standalone/Features.h b/lib_standalone/Features.h index f51037050..28cd6d551 100644 --- a/lib_standalone/Features.h +++ b/lib_standalone/Features.h @@ -28,7 +28,7 @@ #define FT_OTA 0 #endif -// upload firmware feature off by default +// upload firmware/file feature off by default #ifndef FT_UPLOAD_FIRMWARE #define FT_UPLOAD_FIRMWARE 0 #endif From 9923b60d64da6ca499b00cb9ea73abac24b31044 Mon Sep 17 00:00:00 2001 From: Proddy Date: Sat, 7 May 2022 17:49:02 +0200 Subject: [PATCH 04/13] Feature: upload customization settings from a file #256 --- interface/src/AppRouting.tsx | 5 +- interface/src/api/endpoints.ts | 2 +- interface/src/api/system.ts | 6 +- .../src/components/upload/SingleUpload.tsx | 3 +- .../src/components/upload/useFileUpload.ts | 2 +- .../framework/system/FirmwareFileUpload.tsx | 33 --- .../framework/system/GeneralFileUpload.tsx | 28 ++ ...eRestartMonitor.tsx => RestartMonitor.tsx} | 6 +- interface/src/framework/system/System.tsx | 6 +- .../src/framework/system/SystemStatusForm.tsx | 2 +- .../src/framework/system/UploadFileForm.tsx | 26 ++ .../framework/system/UploadFirmwareForm.tsx | 26 -- interface/src/project/HelpInformation.tsx | 32 ++- lib/framework/ESP8266React.cpp | 2 +- lib/framework/ESP8266React.h | 4 +- lib/framework/FSPersistence.h | 14 +- lib/framework/UploadFileService.cpp | 122 ++++++++ ...dFirmwareService.h => UploadFileService.h} | 13 +- lib/framework/UploadFirmwareService.cpp | 68 ----- lib_standalone/ESP8266React.h | 8 + mock-api/server.js | 8 +- src/emsesp.cpp | 10 +- src/system.cpp | 267 ++++++------------ src/system.h | 3 + src/test/test.cpp | 2 + src/version.h | 2 +- 26 files changed, 348 insertions(+), 352 deletions(-) delete mode 100644 interface/src/framework/system/FirmwareFileUpload.tsx create mode 100644 interface/src/framework/system/GeneralFileUpload.tsx rename interface/src/framework/system/{FirmwareRestartMonitor.tsx => RestartMonitor.tsx} (89%) create mode 100644 interface/src/framework/system/UploadFileForm.tsx delete mode 100644 interface/src/framework/system/UploadFirmwareForm.tsx create mode 100644 lib/framework/UploadFileService.cpp rename lib/framework/{UploadFirmwareService.h => UploadFileService.h} (67%) delete mode 100644 lib/framework/UploadFirmwareService.cpp diff --git a/interface/src/AppRouting.tsx b/interface/src/AppRouting.tsx index 4017d9d14..4861c715d 100644 --- a/interface/src/AppRouting.tsx +++ b/interface/src/AppRouting.tsx @@ -47,10 +47,7 @@ const AppRouting: FC = () => { } /> - } - /> + } /> {features.security && ( void; } -export const uploadFile = (url: string, file: File, config?: FileUploadConfig): AxiosPromise => { +export const startUploadFile = (url: string, file: File, config?: FileUploadConfig): AxiosPromise => { const formData = new FormData(); formData.append('file', file); diff --git a/interface/src/api/system.ts b/interface/src/api/system.ts index 4db11723d..f93ff4853 100644 --- a/interface/src/api/system.ts +++ b/interface/src/api/system.ts @@ -2,7 +2,7 @@ import { AxiosPromise } from 'axios'; import { OTASettings, SystemStatus, LogSettings, LogEntries } from '../types'; -import { AXIOS, AXIOS_BIN, FileUploadConfig, uploadFile } from './endpoints'; +import { AXIOS, AXIOS_BIN, FileUploadConfig, startUploadFile } from './endpoints'; export function readSystemStatus(timeout?: number): AxiosPromise { return AXIOS.get('/systemStatus', { timeout }); @@ -24,8 +24,8 @@ export function updateOTASettings(otaSettings: OTASettings): AxiosPromise => - uploadFile('/uploadFirmware', file, config); +export const uploadFile = (file: File, config?: FileUploadConfig): AxiosPromise => + startUploadFile('/uploadFile', file, config); export function readLogSettings(): AxiosPromise { return AXIOS.get('/logSettings'); diff --git a/interface/src/components/upload/SingleUpload.tsx b/interface/src/components/upload/SingleUpload.tsx index f1cb6fb18..acdc15071 100644 --- a/interface/src/components/upload/SingleUpload.tsx +++ b/interface/src/components/upload/SingleUpload.tsx @@ -32,7 +32,8 @@ const SingleUpload: FC = ({ onDrop, onCancel, uploading, prog const dropzoneState = useDropzone({ onDrop, accept: { - 'application/octet-stream': ['.bin'] + 'application/octet-stream': ['.bin'], + 'application/json': ['.json'] }, disabled: uploading, multiple: false diff --git a/interface/src/components/upload/useFileUpload.ts b/interface/src/components/upload/useFileUpload.ts index b7529020f..0cc12b1aa 100644 --- a/interface/src/components/upload/useFileUpload.ts +++ b/interface/src/components/upload/useFileUpload.ts @@ -42,7 +42,7 @@ const useFileUpload = ({ upload }: MediaUploadOptions) => { cancelToken: cancelToken.token }); resetUploadingStates(); - enqueueSnackbar('Upload successful', { variant: 'success' }); + enqueueSnackbar('File uploaded', { variant: 'success' }); } catch (error: unknown) { if (axios.isCancel(error)) { enqueueSnackbar('Upload aborted', { variant: 'warning' }); diff --git a/interface/src/framework/system/FirmwareFileUpload.tsx b/interface/src/framework/system/FirmwareFileUpload.tsx deleted file mode 100644 index a0b212fdf..000000000 --- a/interface/src/framework/system/FirmwareFileUpload.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import { AxiosPromise } from 'axios'; -import { FC } from 'react'; - -import { FileUploadConfig } from '../../api/endpoints'; -import { MessageBox, SingleUpload, useFileUpload } from '../../components'; - -interface UploadFirmwareProps { - uploadFirmware: (file: File, config?: FileUploadConfig) => AxiosPromise; -} - -const FirmwareFileUpload: FC = ({ uploadFirmware }) => { - const [uploadFile, cancelUpload, uploading, uploadProgress] = useFileUpload({ upload: uploadFirmware }); - - return ( - <> - {!uploading && ( - - )} - - - ); -}; - -export default FirmwareFileUpload; diff --git a/interface/src/framework/system/GeneralFileUpload.tsx b/interface/src/framework/system/GeneralFileUpload.tsx new file mode 100644 index 000000000..8f084b69e --- /dev/null +++ b/interface/src/framework/system/GeneralFileUpload.tsx @@ -0,0 +1,28 @@ +import { AxiosPromise } from 'axios'; +import { FC } from 'react'; + +import { FileUploadConfig } from '../../api/endpoints'; +import { MessageBox, SingleUpload, useFileUpload } from '../../components'; + +interface UploadFileProps { + uploadGeneralFile: (file: File, config?: FileUploadConfig) => AxiosPromise; +} + +const GeneralFileUpload: FC = ({ uploadGeneralFile }) => { + const [uploadFile, cancelUpload, uploading, uploadProgress] = useFileUpload({ upload: uploadGeneralFile }); + + return ( + <> + {!uploading && ( + + )} + + + ); +}; + +export default GeneralFileUpload; diff --git a/interface/src/framework/system/FirmwareRestartMonitor.tsx b/interface/src/framework/system/RestartMonitor.tsx similarity index 89% rename from interface/src/framework/system/FirmwareRestartMonitor.tsx rename to interface/src/framework/system/RestartMonitor.tsx index 7dd050c6e..3e832f302 100644 --- a/interface/src/framework/system/FirmwareRestartMonitor.tsx +++ b/interface/src/framework/system/RestartMonitor.tsx @@ -8,7 +8,7 @@ const RESTART_TIMEOUT = 2 * 60 * 1000; const POLL_TIMEOUT = 2000; const POLL_INTERVAL = 5000; -const FirmwareRestartMonitor: FC = () => { +const RestartMonitor: FC = () => { const [failed, setFailed] = useState(false); const [timeoutId, setTimeoutId] = useState(); @@ -16,7 +16,7 @@ const FirmwareRestartMonitor: FC = () => { const poll = useRef(async () => { try { await SystemApi.readSystemStatus(POLL_TIMEOUT); - document.location.href = '/firmwareUpdated'; + document.location.href = '/fileUpdated'; } catch (error: unknown) { if (new Date().getTime() < timeoutAt.current) { setTimeoutId(setTimeout(poll.current, POLL_INTERVAL)); @@ -40,4 +40,4 @@ const FirmwareRestartMonitor: FC = () => { ); }; -export default FirmwareRestartMonitor; +export default RestartMonitor; diff --git a/interface/src/framework/system/System.tsx b/interface/src/framework/system/System.tsx index 553f60ad0..07cf8296d 100644 --- a/interface/src/framework/system/System.tsx +++ b/interface/src/framework/system/System.tsx @@ -6,7 +6,7 @@ import { Tab } from '@mui/material'; import { useRouterTab, RouterTabs, useLayoutTitle, RequireAdmin } from '../../components'; import { AuthenticatedContext } from '../../contexts/authentication'; import { FeaturesContext } from '../../contexts/features'; -import UploadFirmwareForm from './UploadFirmwareForm'; +import UploadFileForm from './UploadFileForm'; import SystemStatusForm from './SystemStatusForm'; import OTASettingsForm from './OTASettingsForm'; @@ -26,7 +26,7 @@ const System: FC = () => { {features.ota && } - {features.upload_firmware && } + {features.upload_firmware && } } /> @@ -46,7 +46,7 @@ const System: FC = () => { path="upload" element={ - + } /> diff --git a/interface/src/framework/system/SystemStatusForm.tsx b/interface/src/framework/system/SystemStatusForm.tsx index 62c333fce..52c1a3a4b 100644 --- a/interface/src/framework/system/SystemStatusForm.tsx +++ b/interface/src/framework/system/SystemStatusForm.tsx @@ -159,7 +159,7 @@ const SystemStatusForm: FC = () => { Use  - {'UPLOAD FIRMWARE'} + {'UPLOAD'}  to apply the new firmware diff --git a/interface/src/framework/system/UploadFileForm.tsx b/interface/src/framework/system/UploadFileForm.tsx new file mode 100644 index 000000000..29f161310 --- /dev/null +++ b/interface/src/framework/system/UploadFileForm.tsx @@ -0,0 +1,26 @@ +import { FC, useRef, useState } from 'react'; + +import * as SystemApi from '../../api/system'; +import { SectionContent } from '../../components'; +import { FileUploadConfig } from '../../api/endpoints'; + +import GeneralFileUpload from './GeneralFileUpload'; +import RestartMonitor from './RestartMonitor'; + +const UploadFileForm: FC = () => { + const [restarting, setRestarting] = useState(); + + const uploadFile = useRef(async (file: File, config?: FileUploadConfig) => { + const response = await SystemApi.uploadFile(file, config); + setRestarting(true); + return response; + }); + + return ( + + {restarting ? : } + + ); +}; + +export default UploadFileForm; diff --git a/interface/src/framework/system/UploadFirmwareForm.tsx b/interface/src/framework/system/UploadFirmwareForm.tsx deleted file mode 100644 index 5af94f0de..000000000 --- a/interface/src/framework/system/UploadFirmwareForm.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import { FC, useRef, useState } from 'react'; - -import * as SystemApi from '../../api/system'; -import { SectionContent } from '../../components'; -import { FileUploadConfig } from '../../api/endpoints'; - -import FirmwareFileUpload from './FirmwareFileUpload'; -import FirmwareRestartMonitor from './FirmwareRestartMonitor'; - -const UploadFirmwareForm: FC = () => { - const [restarting, setRestarting] = useState(); - - const uploadFirmware = useRef(async (file: File, config?: FileUploadConfig) => { - const response = await SystemApi.uploadFirmware(file, config); - setRestarting(true); - return response; - }); - - return ( - - {restarting ? : } - - ); -}; - -export default UploadFirmwareForm; diff --git a/interface/src/project/HelpInformation.tsx b/interface/src/project/HelpInformation.tsx index 803f30b83..e081facca 100644 --- a/interface/src/project/HelpInformation.tsx +++ b/interface/src/project/HelpInformation.tsx @@ -36,7 +36,7 @@ const HelpInformation: FC = () => { } else { const json = response.data; const a = document.createElement('a'); - const filename = 'emsesp_' + endpoint + '.txt'; + const filename = 'emsesp_' + endpoint + '.json'; a.href = URL.createObjectURL( new Blob([JSON.stringify(json, null, 2)], { type: 'text/plain' @@ -112,26 +112,30 @@ const HelpInformation: FC = () => { {me.admin && ( <> - + Export Data - - Download the current system information, application settings and any customizations using the buttons - below. + + Download the current system information to show EMS statistics and connected devices + + + + + + Export the application settings and any customizations to a JSON file. These files can later be uploaded + via the System menu. + + + Be careful when sharing the settings as the file contains passwords and other sensitive system + information. -