mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-06 15:59:52 +03:00
325 lines
10 KiB
TypeScript
325 lines
10 KiB
TypeScript
import { useEffect, useState } from 'react';
|
|
import { toast } from 'react-toastify';
|
|
|
|
import CancelIcon from '@mui/icons-material/Cancel';
|
|
import CheckIcon from '@mui/icons-material/Done';
|
|
import DownloadIcon from '@mui/icons-material/GetApp';
|
|
import InfoOutlinedIcon from '@mui/icons-material/InfoOutlined';
|
|
import WarningIcon from '@mui/icons-material/Warning';
|
|
import {
|
|
Box,
|
|
Button,
|
|
Dialog,
|
|
DialogActions,
|
|
DialogContent,
|
|
DialogTitle,
|
|
Link,
|
|
Typography
|
|
} from '@mui/material';
|
|
import Grid from '@mui/material/Grid2';
|
|
|
|
import * as SystemApi from 'api/system';
|
|
import { callAction } from 'api/app';
|
|
import { getDevVersion, getStableVersion } from 'api/system';
|
|
|
|
import { dialogStyle } from 'CustomTheme';
|
|
import { useRequest } from 'alova/client';
|
|
import RestartMonitor from 'app/status/RestartMonitor';
|
|
import { FormLoader, SectionContent, useLayoutTitle } from 'components';
|
|
import { useI18nContext } from 'i18n/i18n-react';
|
|
|
|
const Version = () => {
|
|
const { LL } = useI18nContext();
|
|
|
|
const [restarting, setRestarting] = useState<boolean>(false);
|
|
const [openDialog, setOpenDialog] = useState<boolean>(false);
|
|
const [useDev, setUseDev] = useState<boolean>(false);
|
|
const [upgradeAvailable, setUpgradeAvailable] = useState<boolean>(false);
|
|
|
|
const { send: sendCheckUpgrade } = useRequest(
|
|
(versions: string) => callAction({ action: 'checkUpgrade', param: versions }),
|
|
{
|
|
immediate: false
|
|
}
|
|
).onSuccess((event) => {
|
|
const data = event.data as { emsesp_version: string; upgradeable: boolean };
|
|
setUpgradeAvailable(data.upgradeable);
|
|
});
|
|
|
|
const { data, send: loadData, error } = useRequest(SystemApi.readSystemStatus);
|
|
|
|
const { send: sendUploadURL } = useRequest(
|
|
(url: string) => callAction({ action: 'uploadURL', param: url }),
|
|
{
|
|
immediate: false
|
|
}
|
|
);
|
|
|
|
// called immediately to get the latest versions on page load
|
|
const { data: latestVersion } = useRequest(getStableVersion);
|
|
const { data: latestDevVersion } = useRequest(getDevVersion);
|
|
|
|
useEffect(() => {
|
|
if (latestVersion && latestDevVersion) {
|
|
// console.log("Latest versions, stable: " + latestVersion + " dev: " + latestDevVersion);
|
|
sendCheckUpgrade(latestDevVersion + ',' + latestVersion).catch(
|
|
(error: Error) => {
|
|
toast.error('Failed to check upgrade: ' + error.message);
|
|
}
|
|
);
|
|
}
|
|
}, [latestVersion, latestDevVersion]);
|
|
|
|
const STABLE_URL = 'https://github.com/emsesp/EMS-ESP32/releases/download/';
|
|
const STABLE_RELNOTES_URL =
|
|
'https://github.com/emsesp/EMS-ESP32/blob/main/CHANGELOG.md';
|
|
|
|
const DEV_URL = 'https://github.com/emsesp/EMS-ESP32/releases/download/latest/';
|
|
const DEV_RELNOTES_URL =
|
|
'https://github.com/emsesp/EMS-ESP32/blob/dev/CHANGELOG_LATEST.md';
|
|
|
|
const getBinURL = (useDevVersion: boolean) => {
|
|
if (!latestVersion || !latestDevVersion) {
|
|
return '';
|
|
}
|
|
const filename =
|
|
'EMS-ESP-' +
|
|
(useDevVersion ? latestDevVersion : latestVersion).replaceAll('.', '_') +
|
|
'-' +
|
|
getPlatform() +
|
|
'.bin';
|
|
return useDevVersion
|
|
? DEV_URL + filename
|
|
: STABLE_URL + 'v' + latestVersion + '/' + filename;
|
|
};
|
|
|
|
const getPlatform = () => {
|
|
return (
|
|
[data.esp_platform, data.flash_chip_size >= 16384 ? '16MB' : '4MB'].join('-') +
|
|
(data.psram ? '+' : '')
|
|
);
|
|
};
|
|
|
|
const installFirmwareURL = async (url: string) => {
|
|
await sendUploadURL(url).catch((error: Error) => {
|
|
toast.error(error.message);
|
|
});
|
|
setRestarting(true);
|
|
};
|
|
|
|
useLayoutTitle('EMS-ESP Firmware');
|
|
|
|
// see if we have internet access
|
|
const internet_live =
|
|
latestDevVersion !== undefined && latestVersion !== undefined;
|
|
|
|
// check for older boards where auto-upgrade is not supported
|
|
const download_only = data && !data.psram;
|
|
|
|
const renderUploadDialog = () => {
|
|
if (!internet_live) {
|
|
return null;
|
|
}
|
|
|
|
return (
|
|
<Dialog
|
|
sx={dialogStyle}
|
|
open={openDialog}
|
|
onClose={() => setOpenDialog(false)}
|
|
>
|
|
<DialogTitle>
|
|
{(download_only ? LL.DOWNLOAD(0) : LL.INSTALL('')) + ' ' + ' Firmware'}
|
|
</DialogTitle>
|
|
<DialogContent dividers>
|
|
<Typography mb={2}>
|
|
{LL.INSTALL_VERSION(
|
|
download_only ? LL.DOWNLOAD(1) : LL.INSTALL(''),
|
|
useDev ? latestDevVersion : latestVersion
|
|
)}
|
|
</Typography>
|
|
</DialogContent>
|
|
<DialogActions>
|
|
<Button
|
|
startIcon={<CancelIcon />}
|
|
variant="outlined"
|
|
onClick={() => setOpenDialog(false)}
|
|
color="secondary"
|
|
>
|
|
{LL.CANCEL()}
|
|
</Button>
|
|
<Button
|
|
startIcon={<DownloadIcon />}
|
|
variant="outlined"
|
|
onClick={() => setOpenDialog(false)}
|
|
color="primary"
|
|
>
|
|
<Link target="_blank" href={getBinURL(useDev)} color="primary">
|
|
{LL.DOWNLOAD(1)}
|
|
</Link>
|
|
</Button>
|
|
{!download_only && (
|
|
<Button
|
|
startIcon={<WarningIcon color="warning" />}
|
|
variant="outlined"
|
|
onClick={() => installFirmwareURL(getBinURL(useDev))}
|
|
color="primary"
|
|
>
|
|
{LL.INSTALL('')}
|
|
</Button>
|
|
)}
|
|
</DialogActions>
|
|
</Dialog>
|
|
);
|
|
};
|
|
|
|
const showFirmwareDialog = (useDevVersion: boolean) => {
|
|
if (useDevVersion || data.emsesp_version.includes('dev')) {
|
|
setUseDev(true);
|
|
}
|
|
setOpenDialog(true);
|
|
};
|
|
|
|
const content = () => {
|
|
if (!data) {
|
|
return <FormLoader onRetry={loadData} errorMessage={error?.message} />;
|
|
}
|
|
|
|
const isDev = data.emsesp_version.includes('dev');
|
|
|
|
return (
|
|
<>
|
|
<Box p={2} border="1px solid grey" borderRadius={2}>
|
|
<Typography sx={{ pb: 2 }} variant="h6" color="primary">
|
|
Firmware Version
|
|
</Typography>
|
|
|
|
<Grid container spacing={4}>
|
|
<Grid mb={1}>
|
|
<Typography mb={1} color="secondary">
|
|
{LL.VERSION()}
|
|
</Typography>
|
|
<Typography mb={1} color="secondary">
|
|
Platform
|
|
</Typography>
|
|
<Typography mb={1} color="secondary">
|
|
Release Type
|
|
</Typography>
|
|
</Grid>
|
|
<Grid mb={1}>
|
|
<Typography mb={1}>
|
|
{data.emsesp_version}
|
|
{data.build_flags && (
|
|
<Typography variant="caption">
|
|
({data.build_flags})
|
|
</Typography>
|
|
)}
|
|
</Typography>
|
|
<Typography mb={1}>{getPlatform()}</Typography>
|
|
<Typography mb={1}>
|
|
{isDev ? LL.DEVELOPMENT() : LL.STABLE()}
|
|
{!isDev && internet_live && (
|
|
<Typography variant="caption">
|
|
<Button
|
|
sx={{ ml: 2 }}
|
|
variant="outlined"
|
|
color="primary"
|
|
size="small"
|
|
onClick={() => showFirmwareDialog(true)}
|
|
>
|
|
{LL.SWITCH_DEV()}
|
|
</Button>
|
|
</Typography>
|
|
)}
|
|
</Typography>
|
|
</Grid>
|
|
</Grid>
|
|
|
|
<Typography sx={{ pb: 2 }} variant="h6" color="primary">
|
|
{LL.AVAILABLE_VERSION()}
|
|
</Typography>
|
|
|
|
{internet_live ? (
|
|
<>
|
|
<Grid container spacing={4}>
|
|
<Grid mb={1}>
|
|
<Typography mb={1} color="secondary">
|
|
{LL.STABLE()}
|
|
</Typography>
|
|
<Typography mb={1} color="secondary">
|
|
{LL.DEVELOPMENT()}
|
|
</Typography>
|
|
</Grid>
|
|
<Grid mb={1}>
|
|
<Typography mb={1}>
|
|
{latestVersion}
|
|
<Link target="_blank" href={STABLE_RELNOTES_URL} color="primary">
|
|
(changelog)
|
|
</Link>
|
|
{!isDev && upgradeAvailable && (
|
|
<Button
|
|
sx={{ ml: 2 }}
|
|
variant="outlined"
|
|
color="warning"
|
|
size="small"
|
|
onClick={() => showFirmwareDialog(false)}
|
|
>
|
|
Upgrade…
|
|
</Button>
|
|
)}
|
|
</Typography>
|
|
<Typography mb={1}>
|
|
{latestDevVersion}
|
|
<Link target="_blank" href={DEV_RELNOTES_URL} color="primary">
|
|
(changelog)
|
|
</Link>
|
|
{isDev && upgradeAvailable && (
|
|
<Button
|
|
sx={{ ml: 2 }}
|
|
variant="outlined"
|
|
color="warning"
|
|
size="small"
|
|
onClick={() => showFirmwareDialog(false)}
|
|
>
|
|
Upgrade…
|
|
</Button>
|
|
)}
|
|
</Typography>
|
|
</Grid>
|
|
</Grid>
|
|
{upgradeAvailable ? (
|
|
<Typography color="warning">
|
|
<InfoOutlinedIcon
|
|
color="warning"
|
|
sx={{ verticalAlign: 'middle', mr: 2 }}
|
|
/>
|
|
{LL.UPGRADE_AVAILABLE()}
|
|
</Typography>
|
|
) : (
|
|
<Typography color="success">
|
|
<CheckIcon
|
|
color="success"
|
|
sx={{ verticalAlign: 'middle', mr: 2 }}
|
|
/>
|
|
{LL.LATEST_VERSION()}
|
|
</Typography>
|
|
)}
|
|
</>
|
|
) : (
|
|
<Typography mb={1} color="warning">
|
|
not online
|
|
</Typography>
|
|
)}
|
|
|
|
{renderUploadDialog()}
|
|
</Box>
|
|
</>
|
|
);
|
|
};
|
|
|
|
return (
|
|
<SectionContent>{restarting ? <RestartMonitor /> : content()}</SectionContent>
|
|
);
|
|
};
|
|
|
|
export default Version;
|