Merge branch 'dev' into dev

This commit is contained in:
Proddy
2025-11-12 21:14:57 +01:00
committed by GitHub
20 changed files with 126 additions and 78 deletions

View File

@@ -22,7 +22,7 @@ For more details go to [docs.emsesp.org](https://docs.emsesp.org/).
- Internal sensors of E32V2_2
- FW200 display options [#2610](https://github.com/emsesp/EMS-ESP32/discussions/2610)
- CR11 mode settings OFF/MANUAL depends on selTemp [#2437](https://github.com/emsesp/EMS-ESP32/issues/2437)
- Fuse settings for BBQKees boards
- implemented eFuse settings for BBQKees boards to store model type and ESP chipset
- Analogsensors for pulse output [#2624](https://github.com/emsesp/EMS-ESP32/discussions/2624)
- Analogsensors frequency input [#2631](https://github.com/emsesp/EMS-ESP32/discussions/2631)
- SRC plus thermostats [#2636](https://github.com/emsesp/EMS-ESP32/issues/2636)
@@ -65,4 +65,4 @@ For more details go to [docs.emsesp.org](https://docs.emsesp.org/).
- internal system analog sensors (core_voltage, supply_voltage and gateway_temperature) cannot be accidentally removed
- double click button reconnects EMS-ESP to AP
- place system message command in side scheduler loop to reduce stack memory usage by 2KB
- syslog mark interval up to 1 hour [#2733](https://github.com/emsesp/EMS-ESP32/issues/2733)
- syslog mark interval set to 1 hour

View File

@@ -512,22 +512,24 @@ const Customizations = () => {
</Button>
</>
) : (
<Button
startIcon={<EditIcon />}
variant="outlined"
onClick={() => setRename(true)}
>
{LL.RENAME()}
</Button>
<>
<Button
startIcon={<EditIcon />}
variant="outlined"
onClick={() => setRename(true)}
>
{LL.RENAME()}
</Button>
<Button
startIcon={<SettingsBackupRestoreIcon />}
variant="outlined"
color="error"
onClick={() => setConfirmReset(true)}
>
{LL.REMOVE_ALL()}
</Button>
</>
))}
<Button
startIcon={<SettingsBackupRestoreIcon />}
variant="outlined"
color="error"
onClick={() => setConfirmReset(true)}
>
{LL.REMOVE_ALL()}
</Button>
</Box>
</>
);

View File

@@ -1,7 +1,16 @@
import { memo, useCallback, useContext } from 'react';
import PersonIcon from '@mui/icons-material/Person';
import { Avatar, Box, Button, List, ListItem, ListItemText } from '@mui/material';
import {
Avatar,
Box,
Button,
Divider,
List,
ListItem,
ListItemText,
Typography
} from '@mui/material';
import { AuthenticatedContext } from '@/contexts/authentication';
import { SectionContent, useLayoutTitle } from 'components';
@@ -12,7 +21,7 @@ const UserProfileComponent = () => {
const { LL } = useI18nContext();
const { me, signOut } = useContext(AuthenticatedContext);
useLayoutTitle(LL.USER(1));
useLayoutTitle(LL.USER_PROFILE());
const handleSignOut = useCallback(() => {
signOut(true);
@@ -20,32 +29,33 @@ const UserProfileComponent = () => {
return (
<SectionContent>
<Box padding={2} justifyContent="center" flexDirection="column">
<Box display="flex" alignItems="center" justifyContent="space-between">
<List sx={{ flexGrow: 1 }}>
<ListItem disablePadding>
<Avatar sx={{ bgcolor: '#9e9e9e', color: 'white' }}>
<PersonIcon />
</Avatar>
<ListItemText
sx={{ pl: 2, color: '#2196f3' }}
primary={me.username}
secondary={'(' + (me.admin ? LL.ADMINISTRATOR() : LL.GUEST()) + ')'}
/>
</ListItem>
</List>
<LanguageSelector />
</Box>
<Button
sx={{ mt: 2 }}
variant="outlined"
fullWidth
color="primary"
onClick={handleSignOut}
>
{LL.SIGN_OUT()}
</Button>
<List sx={{ flexGrow: 1 }}>
<ListItem disablePadding>
<Avatar sx={{ bgcolor: '#9e9e9e', color: 'white' }}>
<PersonIcon />
</Avatar>
<ListItemText
sx={{ pl: 2, color: '#2196f3' }}
primary={me.username}
secondary={'(' + (me.admin ? LL.ADMINISTRATOR() : LL.GUEST()) + ')'}
/>
</ListItem>
</List>
<Box mt={2} mb={2} display="flex" alignItems="center">
<Typography mr={2} variant="body1" align="center">
{LL.LANGUAGE()}:
</Typography>
<LanguageSelector />
</Box>
<Divider />
<Button
sx={{ mt: 2 }}
variant="outlined"
color="primary"
onClick={handleSignOut}
>
{LL.SIGN_OUT()}
</Button>
</SectionContent>
);
};

View File

@@ -284,7 +284,6 @@ const Version = () => {
const [downloadOnly, setDownloadOnly] = useState<boolean>(false);
const [showVersionInfo, setShowVersionInfo] = useState<number>(0);
// API calls with optimized error handling
const { send: sendCheckUpgrade } = useRequest(
(versions: string) => callAction({ action: 'checkUpgrade', param: versions }),
{ immediate: false }

View File

@@ -1,4 +1,4 @@
// Optimized exports - use direct exports to reduce bundle size
// use direct exports to reduce bundle size
export { default as SectionContent } from './SectionContent';
export { default as ButtonRow } from './ButtonRow';
export { default as MessageBox } from './MessageBox';

View File

@@ -355,7 +355,8 @@ const cz: Translation = {
INTERNET_CONNECTION_REQUIRED: 'Pro automatickou kontrolu a instalaci aktualizací je třeba internetové připojení',
SWITCH_RELEASE_TYPE: 'Přepnout na {0} verzi',
FIRMWARE_VERSION_INFO: 'Informace o verzi firmwaru',
NO_DATA: 'Žádná data'
NO_DATA: 'Žádná data',
USER_PROFILE: 'Uživatelský profil'
};
export default cz;

View File

@@ -40,7 +40,7 @@ const de: Translation = {
RUN_COMMAND: 'Befehl ausführen',
CHANGE_VALUE: 'Wert ändern',
CANCEL: 'Abbrechen',
REMOVE_ALL: 'Entfernen alles',
REMOVE_ALL: 'Alles entfernen',
APPLY_CHANGES: 'Änderungen anwenden ({0})',
UPDATE: 'Aktualisieren',
EXECUTE: 'Ausführen',
@@ -355,7 +355,8 @@ const de: Translation = {
INTERNET_CONNECTION_REQUIRED: 'Für die automatische Versionsprüfung und Aktualisierung ist eine Internetverbindung erforderlich',
SWITCH_RELEASE_TYPE: 'Zum {0}-Release wechseln',
FIRMWARE_VERSION_INFO: 'Firmware-Versionsinformation',
NO_DATA: 'Keine Daten'
NO_DATA: 'Keine Daten',
USER_PROFILE: 'Benutzerprofil'
};
export default de;

View File

@@ -355,7 +355,8 @@ const en: Translation = {
INTERNET_CONNECTION_REQUIRED: 'Internet connection required for automatic version checking and upgrading',
SWITCH_RELEASE_TYPE: 'Switch to {0} release',
FIRMWARE_VERSION_INFO: 'Firmware Version Information',
NO_DATA: 'No data'
NO_DATA: 'No data',
USER_PROFILE: 'User Profile'
};
export default en;

View File

@@ -355,7 +355,8 @@ const fr: Translation = {
INTERNET_CONNECTION_REQUIRED: 'Connexion Internet requise pour la vérification automatique des versions et la mise à niveau',
SWITCH_RELEASE_TYPE: 'Passer à la version {0}',
FIRMWARE_VERSION_INFO: 'Informations sur la version du firmware',
NO_DATA: 'Aucune donnée'
NO_DATA: 'Aucune donnée',
USER_PROFILE: 'Profil utilisateur'
};
export default fr;

View File

@@ -355,7 +355,8 @@ const it: Translation = {
INTERNET_CONNECTION_REQUIRED: 'Connessione internet richiesta per il controllo automatico delle versioni e l\'aggiornamento',
SWITCH_RELEASE_TYPE: 'Cambia in {0} rilascio',
FIRMWARE_VERSION_INFO: 'Informazioni sulla versione del firmware',
NO_DATA: 'Nessun dato'
NO_DATA: 'Nessun dato',
USER_PROFILE: 'Profilo utente'
};
export default it;

View File

@@ -355,7 +355,8 @@ const nl: Translation = {
INTERNET_CONNECTION_REQUIRED: 'Internetverbinding vereist voor automatische versiecontrole en -upgrade',
SWITCH_RELEASE_TYPE: 'Switch naar {0} release',
FIRMWARE_VERSION_INFO: 'Informatie over firmwareversie',
NO_DATA: 'Geen data'
NO_DATA: 'Geen data',
USER_PROFILE: 'Gebruikersprofiel'
};
export default nl;

View File

@@ -355,7 +355,8 @@ const no: Translation = {
INTERNET_CONNECTION_REQUIRED: 'Internettilkobling kreves for automatisk versjonskontroll og oppgradering',
SWITCH_RELEASE_TYPE: 'Bytt til {0} utgivelse',
FIRMWARE_VERSION_INFO: 'Informasjon om firmwareversjon',
NO_DATA: 'Ingen data'
NO_DATA: 'Ingen data',
USER_PROFILE: 'Brukerprofil'
};
export default no;

View File

@@ -355,7 +355,8 @@ const pl: BaseTranslation = {
INTERNET_CONNECTION_REQUIRED: 'Połączenie internetowe jest wymagane do automatycznej kontroli wersji i aktualizacji',
SWITCH_RELEASE_TYPE: 'Zmień na {0} wydanie',
FIRMWARE_VERSION_INFO: 'Informacje o wersji firmware',
NO_DATA: 'Brak danych'
NO_DATA: 'Brak danych',
USER_PROFILE: 'Profil użytkownika'
};
export default pl;

View File

@@ -355,7 +355,8 @@ const sk: Translation = {
INTERNET_CONNECTION_REQUIRED: 'Internetové pripojenie je potrebné pre automatickú kontrolu a aktualizáciu',
SWITCH_RELEASE_TYPE: 'Prepnúť na {0} verziu',
FIRMWARE_VERSION_INFO: 'Informácie o verzii firmware',
NO_DATA: 'Žiadne dáta'
NO_DATA: 'Žiadne dáta',
USER_PROFILE: 'Profil používateľa'
};
export default sk;

View File

@@ -355,7 +355,8 @@ const sv: Translation = {
INTERNET_CONNECTION_REQUIRED: 'Internetanslutning krävs för automatisk version kontroll och uppdatering',
SWITCH_RELEASE_TYPE: 'Byt till {0} utgåva',
FIRMWARE_VERSION_INFO: 'Information om firmwareversion',
NO_DATA: 'Ingen data'
NO_DATA: 'Ingen data',
USER_PROFILE: 'Användarprofil'
};
export default sv;

View File

@@ -355,7 +355,8 @@ const tr: Translation = {
INTERNET_CONNECTION_REQUIRED: 'Otomatik sürüm kontrolü ve güncelleme için internet bağlantısı gereklidir',
SWITCH_RELEASE_TYPE: '{0} sürümüne geç',
FIRMWARE_VERSION_INFO: 'Firmware Sürüm Bilgisi',
NO_DATA: 'Hiçbir veri yok'
NO_DATA: 'Hiçbir veri yok',
USER_PROFILE: 'Kullanıcı Profili'
};
export default tr;

View File

@@ -11,9 +11,29 @@ export const numberValue = (value?: number): string =>
export const extractEventValue = (
event: React.ChangeEvent<HTMLInputElement>
): string | number | boolean => {
const { type, valueAsNumber, checked, value } = event.target;
const { type, checked, value } = event.target;
if (type === 'number') return valueAsNumber;
if (type === 'number') {
if (value === '') return NaN;
const normalizedValue = value.replace(',', '.');
// For incomplete number entries, keep the raw string to allow smooth typing
// This includes: "0.", "1.0", "0.00", "-", "-.", "-.5", etc.
const endsWithDecimalAndZeros = /\.\d*0$/.test(normalizedValue);
const isIncomplete =
normalizedValue.endsWith('.') ||
normalizedValue === '-' ||
normalizedValue === '-.' ||
endsWithDecimalAndZeros;
if (isIncomplete) {
return normalizedValue;
}
const parsedValue = parseFloat(normalizedValue);
return parsedValue;
}
if (type === 'checkbox') return checked;
return value;
};

View File

@@ -7,7 +7,7 @@ const VALID_EXTENSIONS = new Set(['bin', 'json', 'md5']);
const ONE_SECOND_MS = 1000;
const TEN_PERCENT = 10;
// Optimized padding function
// padding function
const pad = (number) => String(number).padStart(2, '0');
// Simple throttle helper (time-based)

View File

@@ -276,10 +276,10 @@ function updateMask(entity: any, de: any, dd: any) {
const old_custom_name = dd.nodes[dd_objIndex].cn;
console.log(
'comparing names, old (' +
old_custom_name +
') with new (' +
new_custom_name +
')'
old_custom_name +
') with new (' +
new_custom_name +
')'
);
if (old_custom_name !== new_custom_name) {
changed = true;
@@ -375,15 +375,15 @@ function check_upgrade(version: string) {
console.log(
'Upgrade this version (' +
THIS_VERSION +
') to dev (' +
dev_version +
') is ' +
(DEV_VERSION_IS_UPGRADEABLE ? 'YES' : 'NO') +
' and to stable (' +
stable_version +
') is ' +
(STABLE_VERSION_IS_UPGRADEABLE ? 'YES' : 'NO')
THIS_VERSION +
') to dev (' +
dev_version +
') is ' +
(DEV_VERSION_IS_UPGRADEABLE ? 'YES' : 'NO') +
' and to stable (' +
stable_version +
') is ' +
(STABLE_VERSION_IS_UPGRADEABLE ? 'YES' : 'NO')
);
data = {
emsesp_version: THIS_VERSION,
@@ -4559,8 +4559,8 @@ router
let dashboard_object: { id?: number; n?: string; t?: number; nodes?: any[] } =
{};
// let fake = false;
let fake = true; // toggle for testing, shows a subset of data
let fake = false;
// let fake = true; // toggle for testing, shows a subset of data
if (!fake) {
// pick EMS devices from coredata

View File

@@ -1437,3 +1437,9 @@ switchprogram
brotlin
fanspd
currhum
pumpstep
constmed
constlow
proplow
chimneysweeper