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, Checkbox, Dialog, DialogActions, DialogContent, DialogTitle, FormControlLabel, Grid2 as Grid, Link, Typography } from '@mui/material'; 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 SystemMonitor from 'app/status/SystemMonitor'; import { FormLoader, SectionContent, useLayoutTitle } from 'components'; import { useI18nContext } from 'i18n/i18n-react'; const Version = () => { const { LL } = useI18nContext(); const [restarting, setRestarting] = useState(false); const [openInstallDialog, setOpenInstallDialog] = useState(false); const [usingDevVersion, setUsingDevVersion] = useState(false); const [upgradeAvailable, setUpgradeAvailable] = useState(false); const [internetLive, setInternetLive] = useState(false); const [downloadOnly, setDownloadOnly] = useState(false); 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 { 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: data, send: loadData, error } = useRequest(SystemApi.readSystemStatus).onSuccess((event) => { // older version of EMS-ESP on 4MB boards, can't use OTA because of SSL support in HttpClient if (event.data.arduino_version.startsWith('Tasmota')) { setDownloadOnly(true); } setUsingDevVersion(event.data.emsesp_version.includes('dev')); }); 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) { sendCheckUpgrade(latestDevVersion.name + ',' + latestVersion.name) .catch((error: Error) => { toast.error('Failed to check for upgrades: ' + error.message); }) .finally(() => { setInternetLive(true); }); } }, [latestVersion, latestDevVersion]); const getBinURL = () => { if (!internetLive) { return ''; } const filename = 'EMS-ESP-' + (usingDevVersion ? latestDevVersion.name : latestVersion.name).replaceAll( '.', '_' ) + '-' + getPlatform() + '.bin'; return usingDevVersion ? DEV_URL + filename : STABLE_URL + 'v' + latestVersion.name + '/' + 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'); const renderInstallDialog = () => ( closeInstallDialog()} > {LL.INSTALL() + ' ' + (usingDevVersion ? LL.DEVELOPMENT() : LL.STABLE()) + ' Firmware'} {LL.INSTALL_VERSION(usingDevVersion ? latestDevVersion?.name : latestVersion?.name)} ); const showFirmwareDialog = (useDevVersion?: boolean) => { setUsingDevVersion(useDevVersion || usingDevVersion); setOpenInstallDialog(true); }; const closeInstallDialog = () => { setOpenInstallDialog(false); setUsingDevVersion(data.emsesp_version.includes('dev')); }; const showButtons = (showDev?: boolean) => { if (downloadOnly) { return ( ); } return ( ); }; const content = () => { if (!data) { return ; } const isDev = data.emsesp_version.includes('dev'); return ( <> {LL.THIS_VERSION()} {LL.VERSION()} {data.emsesp_version} {data.build_flags && (   ({data.build_flags}) )} {LL.PLATFORM()} {getPlatform()}   ({data.psram ? '+PSRAM' : '-PSRAM'}) {LL.RELEASE_TYPE()} } checked={!isDev} label={LL.STABLE()} sx={{ '& .MuiSvgIcon-root': { fontSize: 18 } }} /> } checked={isDev} label={LL.DEVELOPMENT()} sx={{ '& .MuiSvgIcon-root': { fontSize: 18 } }} /> {internetLive ? ( <> {LL.AVAILABLE_VERSION()} {LL.STABLE()} {latestVersion.name} {latestVersion.published_at && (  ( {LL.DAYS_AGO( Math.floor( (Date.now() - new Date(latestVersion.published_at).getTime()) / (1000 * 60 * 60 * 24) ) )} ) )} {!usingDevVersion && showButtons(false)} {LL.DEVELOPMENT()} {latestDevVersion.name} {latestDevVersion.published_at && (  ( {LL.DAYS_AGO( Math.floor( (Date.now() - new Date(latestDevVersion.published_at).getTime()) / (1000 * 60 * 60 * 24) ) )} ) )} {showButtons(true)} {upgradeAvailable ? ( {LL.UPGRADE_AVAILABLE()} ) : ( {LL.LATEST_VERSION()} )} ) : ( {LL.INTERNET_CONNECTION_REQUIRED()} )} {renderInstallDialog()} ); }; return ( {restarting ? : content()} ); }; export default Version;