diff --git a/.gitignore b/.gitignore
index 2eb46fa12..8eef96223 100644
--- a/.gitignore
+++ b/.gitignore
@@ -47,9 +47,6 @@ interface/src/i18n/i18n-types.ts
interface/src/i18n/i18n-util.ts
interface/src/i18n/i18n-util.sync.ts
interface/src/i18n/i18n-util.async.ts
-# mock-api uploads
-*/uploads/*
-!uploads/README.md
# scripts
test.sh
diff --git a/interface/package.json b/interface/package.json
index 252358b2d..3b82bb022 100644
--- a/interface/package.json
+++ b/interface/package.json
@@ -21,7 +21,7 @@
"lint": "eslint . --fix"
},
"dependencies": {
- "@alova/adapter-xhr": "2.0.4",
+ "@alova/adapter-xhr": "2.0.5",
"@emotion/react": "^11.13.0",
"@emotion/styled": "^11.13.0",
"@mui/icons-material": "^5.16.7",
diff --git a/interface/src/api/system.ts b/interface/src/api/system.ts
index ff9007b31..ce380e8b8 100644
--- a/interface/src/api/system.ts
+++ b/interface/src/api/system.ts
@@ -45,3 +45,6 @@ export const uploadFile = (file: File) => {
timeout: 60000 // override timeout for uploading firmware - 1 minute
});
};
+
+export const uploadURL = (data: { url: string }) =>
+ alovaInstance.Post('/rest/uploadURL', data);
diff --git a/interface/src/app/main/Help.tsx b/interface/src/app/main/Help.tsx
index dbc939e3e..fa4411e21 100644
--- a/interface/src/app/main/Help.tsx
+++ b/interface/src/app/main/Help.tsx
@@ -113,7 +113,7 @@ const Help = () => {
color="primary"
onClick={() => callAPI('system', 'allvalues')}
>
- {LL.ALLVALUES(0)}
+ {LL.ALLVALUES(0)}
diff --git a/interface/src/app/main/Sensors.tsx b/interface/src/app/main/Sensors.tsx
index b93b61cb3..7833e3066 100644
--- a/interface/src/app/main/Sensors.tsx
+++ b/interface/src/app/main/Sensors.tsx
@@ -59,15 +59,18 @@ const Sensors = () => {
const [analogDialogOpen, setAnalogDialogOpen] = useState(false);
const [creating, setCreating] = useState(false);
- const { data: sensorData } = useAutoRequest(() => readSensorData(), {
- initialData: {
- ts: [],
- as: [],
- analog_enabled: false,
- platform: 'ESP32'
- },
- pollingTime: 2000
- });
+ const { data: sensorData, send: fetchSensorData } = useAutoRequest(
+ () => readSensorData(),
+ {
+ initialData: {
+ ts: [],
+ as: [],
+ analog_enabled: false,
+ platform: 'ESP32'
+ },
+ pollingTime: 2000
+ }
+ );
const { send: sendTemperatureSensor } = useRequest(
(data: WriteTemperatureSensor) => writeTemperatureSensor(data),
@@ -256,6 +259,7 @@ const Sensors = () => {
const onTemperatureDialogClose = () => {
setTemperatureDialogOpen(false);
+ void fetchSensorData();
};
const onTemperatureDialogSave = async (ts: TemperatureSensor) => {
@@ -269,6 +273,7 @@ const Sensors = () => {
.finally(() => {
setTemperatureDialogOpen(false);
setSelectedTemperatureSensor(undefined);
+ void fetchSensorData();
});
};
@@ -283,6 +288,7 @@ const Sensors = () => {
const onAnalogDialogClose = () => {
setAnalogDialogOpen(false);
+ void fetchSensorData();
};
const addAnalogSensor = () => {
@@ -322,6 +328,7 @@ const Sensors = () => {
.finally(() => {
setAnalogDialogOpen(false);
setSelectedAnalogSensor(undefined);
+ void fetchSensorData();
});
};
diff --git a/interface/src/app/settings/DownloadUpload.tsx b/interface/src/app/settings/DownloadUpload.tsx
index c63138d2e..cae8044cd 100644
--- a/interface/src/app/settings/DownloadUpload.tsx
+++ b/interface/src/app/settings/DownloadUpload.tsx
@@ -3,6 +3,7 @@ import { toast } from 'react-toastify';
import DownloadIcon from '@mui/icons-material/GetApp';
import PowerSettingsNewIcon from '@mui/icons-material/PowerSettingsNew';
+import WarningIcon from '@mui/icons-material/Warning';
import { Box, Button, Divider, Link, Typography } from '@mui/material';
import * as SystemApi from 'api/system';
@@ -15,6 +16,7 @@ import {
} from 'api/app';
import { getDevVersion, getStableVersion } from 'api/system';
+import { dialogStyle } from 'CustomTheme';
import { useRequest } from 'alova/client';
import type { APIcall } from 'app/main/types';
import RestartMonitor from 'app/status/RestartMonitor';
@@ -72,6 +74,13 @@ const DownloadUpload = () => {
error
} = useRequest(SystemApi.readHardwareStatus);
+ const { send: sendUploadURL } = useRequest(
+ (data: { url: string }) => SystemApi.uploadURL(data),
+ {
+ immediate: false
+ }
+ );
+
const { send: restartCommand } = useRequest(SystemApi.restart(), {
immediate: false
});
@@ -87,14 +96,19 @@ const DownloadUpload = () => {
};
// called immediately to get the latest version, on page load
- // set immediate to false to avoid calling the API on page load and GH blocking while testing!
const { data: latestVersion } = useRequest(getStableVersion, {
immediate: true
- // immediate: false
+ // uncomment for testing
+ // https://github.com/emsesp/EMS-ESP32/releases/download/v3.6.5/EMS-ESP-3_6_5-ESP32-16MB+.bin
+ // immediate: false,
+ // initialData: '3.6.5'
});
const { data: latestDevVersion } = useRequest(getDevVersion, {
immediate: true
- // immediate: false
+ // uncomment for testing
+ // https://github.com/emsesp/EMS-ESP32/releases/download/latest/EMS-ESP-3_7_0-dev_31-ESP32-16MB+.bin
+ // immediate: false,
+ // initialData: '3.7.0-dev.31'
});
const STABLE_URL = 'https://github.com/emsesp/EMS-ESP32/releases/download/';
@@ -115,6 +129,13 @@ const DownloadUpload = () => {
);
};
+ const installFirmwareURL = async (url: string) => {
+ await sendUploadURL({ url: url }).catch((error: Error) => {
+ toast.error(error.message);
+ });
+ setRestarting(true);
+ };
+
const saveFile = (json: unknown, filename: string) => {
const anchor = document.createElement('a');
anchor.href = URL.createObjectURL(
@@ -275,6 +296,20 @@ const DownloadUpload = () => {
{LL.DOWNLOAD(1)}
)
+ }
+ variant="outlined"
+ color="primary"
+ onClick={() =>
+ installFirmwareURL(
+ STABLE_URL + 'v' + latestVersion + '/' + getBinURL(latestVersion)
+ )
+ }
+ >
+ Install
+
)}
{latestDevVersion && (
@@ -295,6 +330,18 @@ const DownloadUpload = () => {
{LL.DOWNLOAD(1)}
)
+ }
+ variant="outlined"
+ color="primary"
+ onClick={() =>
+ installFirmwareURL(DEV_URL + getBinURL(latestDevVersion))
+ }
+ >
+ Install
+
)}
@@ -326,7 +373,13 @@ const DownloadUpload = () => {
};
return (
- {restarting ? : content()}
+
+ {restarting ? (
+
+ ) : (
+ content()
+ )}
+
);
};
diff --git a/interface/src/app/status/RestartMonitor.tsx b/interface/src/app/status/RestartMonitor.tsx
index ba358af4a..685cac3e8 100644
--- a/interface/src/app/status/RestartMonitor.tsx
+++ b/interface/src/app/status/RestartMonitor.tsx
@@ -1,4 +1,4 @@
-import { useEffect, useRef, useState } from 'react';
+import { type FC, useEffect, useRef, useState } from 'react';
import * as SystemApi from 'api/system';
@@ -6,10 +6,14 @@ import { useRequest } from 'alova/client';
import { FormLoader } from 'components';
import { useI18nContext } from 'i18n/i18n-react';
-const RESTART_TIMEOUT = 2 * 60 * 1000;
-const POLL_INTERVAL = 1000;
+const RESTART_TIMEOUT = 2 * 60 * 1000; // 2 minutes
+const POLL_INTERVAL = 1000; // every 1 second
-const RestartMonitor = () => {
+export interface RestartMonitorProps {
+ message?: string;
+}
+
+const RestartMonitor: FC = ({ message }) => {
const [failed, setFailed] = useState(false);
const [timeoutId, setTimeoutId] = useState();
const { LL } = useI18nContext();
@@ -38,7 +42,7 @@ const RestartMonitor = () => {
return (
);
diff --git a/interface/src/app/status/Status.tsx b/interface/src/app/status/Status.tsx
index e591b8d8b..cca48dbee 100644
--- a/interface/src/app/status/Status.tsx
+++ b/interface/src/app/status/Status.tsx
@@ -306,7 +306,7 @@ const SystemStatus = () => {
);
const content = () => {
- if (!data) {
+ if (!data || !LL) {
return ;
}
@@ -321,7 +321,7 @@ const SystemStatus = () => {
{me.admin && (