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 - Internal sensors of E32V2_2
- FW200 display options [#2610](https://github.com/emsesp/EMS-ESP32/discussions/2610) - 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) - 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 for pulse output [#2624](https://github.com/emsesp/EMS-ESP32/discussions/2624)
- Analogsensors frequency input [#2631](https://github.com/emsesp/EMS-ESP32/discussions/2631) - Analogsensors frequency input [#2631](https://github.com/emsesp/EMS-ESP32/discussions/2631)
- SRC plus thermostats [#2636](https://github.com/emsesp/EMS-ESP32/issues/2636) - 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 - internal system analog sensors (core_voltage, supply_voltage and gateway_temperature) cannot be accidentally removed
- double click button reconnects EMS-ESP to AP - double click button reconnects EMS-ESP to AP
- place system message command in side scheduler loop to reduce stack memory usage by 2KB - 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>
</> </>
) : ( ) : (
<Button <>
startIcon={<EditIcon />} <Button
variant="outlined" startIcon={<EditIcon />}
onClick={() => setRename(true)} variant="outlined"
> onClick={() => setRename(true)}
{LL.RENAME()} >
</Button> {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> </Box>
</> </>
); );

View File

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

View File

@@ -284,7 +284,6 @@ const Version = () => {
const [downloadOnly, setDownloadOnly] = useState<boolean>(false); const [downloadOnly, setDownloadOnly] = useState<boolean>(false);
const [showVersionInfo, setShowVersionInfo] = useState<number>(0); const [showVersionInfo, setShowVersionInfo] = useState<number>(0);
// API calls with optimized error handling
const { send: sendCheckUpgrade } = useRequest( const { send: sendCheckUpgrade } = useRequest(
(versions: string) => callAction({ action: 'checkUpgrade', param: versions }), (versions: string) => callAction({ action: 'checkUpgrade', param: versions }),
{ immediate: false } { 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 SectionContent } from './SectionContent';
export { default as ButtonRow } from './ButtonRow'; export { default as ButtonRow } from './ButtonRow';
export { default as MessageBox } from './MessageBox'; 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í', INTERNET_CONNECTION_REQUIRED: 'Pro automatickou kontrolu a instalaci aktualizací je třeba internetové připojení',
SWITCH_RELEASE_TYPE: 'Přepnout na {0} verzi', SWITCH_RELEASE_TYPE: 'Přepnout na {0} verzi',
FIRMWARE_VERSION_INFO: 'Informace o verzi firmwaru', FIRMWARE_VERSION_INFO: 'Informace o verzi firmwaru',
NO_DATA: 'Žádná data' NO_DATA: 'Žádná data',
USER_PROFILE: 'Uživatelský profil'
}; };
export default cz; export default cz;

View File

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

View File

@@ -355,7 +355,8 @@ const en: Translation = {
INTERNET_CONNECTION_REQUIRED: 'Internet connection required for automatic version checking and upgrading', INTERNET_CONNECTION_REQUIRED: 'Internet connection required for automatic version checking and upgrading',
SWITCH_RELEASE_TYPE: 'Switch to {0} release', SWITCH_RELEASE_TYPE: 'Switch to {0} release',
FIRMWARE_VERSION_INFO: 'Firmware Version Information', FIRMWARE_VERSION_INFO: 'Firmware Version Information',
NO_DATA: 'No data' NO_DATA: 'No data',
USER_PROFILE: 'User Profile'
}; };
export default en; 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', INTERNET_CONNECTION_REQUIRED: 'Connexion Internet requise pour la vérification automatique des versions et la mise à niveau',
SWITCH_RELEASE_TYPE: 'Passer à la version {0}', SWITCH_RELEASE_TYPE: 'Passer à la version {0}',
FIRMWARE_VERSION_INFO: 'Informations sur la version du firmware', 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; 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', INTERNET_CONNECTION_REQUIRED: 'Connessione internet richiesta per il controllo automatico delle versioni e l\'aggiornamento',
SWITCH_RELEASE_TYPE: 'Cambia in {0} rilascio', SWITCH_RELEASE_TYPE: 'Cambia in {0} rilascio',
FIRMWARE_VERSION_INFO: 'Informazioni sulla versione del firmware', FIRMWARE_VERSION_INFO: 'Informazioni sulla versione del firmware',
NO_DATA: 'Nessun dato' NO_DATA: 'Nessun dato',
USER_PROFILE: 'Profilo utente'
}; };
export default it; export default it;

View File

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

View File

@@ -355,7 +355,8 @@ const no: Translation = {
INTERNET_CONNECTION_REQUIRED: 'Internettilkobling kreves for automatisk versjonskontroll og oppgradering', INTERNET_CONNECTION_REQUIRED: 'Internettilkobling kreves for automatisk versjonskontroll og oppgradering',
SWITCH_RELEASE_TYPE: 'Bytt til {0} utgivelse', SWITCH_RELEASE_TYPE: 'Bytt til {0} utgivelse',
FIRMWARE_VERSION_INFO: 'Informasjon om firmwareversjon', FIRMWARE_VERSION_INFO: 'Informasjon om firmwareversjon',
NO_DATA: 'Ingen data' NO_DATA: 'Ingen data',
USER_PROFILE: 'Brukerprofil'
}; };
export default no; 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', INTERNET_CONNECTION_REQUIRED: 'Połączenie internetowe jest wymagane do automatycznej kontroli wersji i aktualizacji',
SWITCH_RELEASE_TYPE: 'Zmień na {0} wydanie', SWITCH_RELEASE_TYPE: 'Zmień na {0} wydanie',
FIRMWARE_VERSION_INFO: 'Informacje o wersji firmware', FIRMWARE_VERSION_INFO: 'Informacje o wersji firmware',
NO_DATA: 'Brak danych' NO_DATA: 'Brak danych',
USER_PROFILE: 'Profil użytkownika'
}; };
export default pl; 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', INTERNET_CONNECTION_REQUIRED: 'Internetové pripojenie je potrebné pre automatickú kontrolu a aktualizáciu',
SWITCH_RELEASE_TYPE: 'Prepnúť na {0} verziu', SWITCH_RELEASE_TYPE: 'Prepnúť na {0} verziu',
FIRMWARE_VERSION_INFO: 'Informácie o verzii firmware', 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; 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', INTERNET_CONNECTION_REQUIRED: 'Internetanslutning krävs för automatisk version kontroll och uppdatering',
SWITCH_RELEASE_TYPE: 'Byt till {0} utgåva', SWITCH_RELEASE_TYPE: 'Byt till {0} utgåva',
FIRMWARE_VERSION_INFO: 'Information om firmwareversion', FIRMWARE_VERSION_INFO: 'Information om firmwareversion',
NO_DATA: 'Ingen data' NO_DATA: 'Ingen data',
USER_PROFILE: 'Användarprofil'
}; };
export default sv; 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', 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ç', SWITCH_RELEASE_TYPE: '{0} sürümüne geç',
FIRMWARE_VERSION_INFO: 'Firmware Sürüm Bilgisi', 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; export default tr;

View File

@@ -11,9 +11,29 @@ export const numberValue = (value?: number): string =>
export const extractEventValue = ( export const extractEventValue = (
event: React.ChangeEvent<HTMLInputElement> event: React.ChangeEvent<HTMLInputElement>
): string | number | boolean => { ): 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; if (type === 'checkbox') return checked;
return value; return value;
}; };

View File

@@ -7,7 +7,7 @@ const VALID_EXTENSIONS = new Set(['bin', 'json', 'md5']);
const ONE_SECOND_MS = 1000; const ONE_SECOND_MS = 1000;
const TEN_PERCENT = 10; const TEN_PERCENT = 10;
// Optimized padding function // padding function
const pad = (number) => String(number).padStart(2, '0'); const pad = (number) => String(number).padStart(2, '0');
// Simple throttle helper (time-based) // 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; const old_custom_name = dd.nodes[dd_objIndex].cn;
console.log( console.log(
'comparing names, old (' + 'comparing names, old (' +
old_custom_name + old_custom_name +
') with new (' + ') with new (' +
new_custom_name + new_custom_name +
')' ')'
); );
if (old_custom_name !== new_custom_name) { if (old_custom_name !== new_custom_name) {
changed = true; changed = true;
@@ -375,15 +375,15 @@ function check_upgrade(version: string) {
console.log( console.log(
'Upgrade this version (' + 'Upgrade this version (' +
THIS_VERSION + THIS_VERSION +
') to dev (' + ') to dev (' +
dev_version + dev_version +
') is ' + ') is ' +
(DEV_VERSION_IS_UPGRADEABLE ? 'YES' : 'NO') + (DEV_VERSION_IS_UPGRADEABLE ? 'YES' : 'NO') +
' and to stable (' + ' and to stable (' +
stable_version + stable_version +
') is ' + ') is ' +
(STABLE_VERSION_IS_UPGRADEABLE ? 'YES' : 'NO') (STABLE_VERSION_IS_UPGRADEABLE ? 'YES' : 'NO')
); );
data = { data = {
emsesp_version: THIS_VERSION, emsesp_version: THIS_VERSION,
@@ -4559,8 +4559,8 @@ router
let dashboard_object: { id?: number; n?: string; t?: number; nodes?: any[] } = let dashboard_object: { id?: number; n?: string; t?: number; nodes?: any[] } =
{}; {};
// let fake = false; let fake = false;
let fake = true; // toggle for testing, shows a subset of data // let fake = true; // toggle for testing, shows a subset of data
if (!fake) { if (!fake) {
// pick EMS devices from coredata // pick EMS devices from coredata

View File

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