add auto check for firmware updates

This commit is contained in:
proddy
2026-09-14 19:33:20 +02:00
parent 7ae9d87a72
commit 167f194bdf
21 changed files with 56 additions and 2 deletions
+1
View File
@@ -17,6 +17,7 @@ This release is based on the latest Espressif/Arduino core version 3. It brings
- pc0Flow in l/min [#3224](https://github.com/emsesp/EMS-ESP32/issues/3224) - pc0Flow in l/min [#3224](https://github.com/emsesp/EMS-ESP32/issues/3224)
- remove HA config for excluded entities [#3229](https://github.com/emsesp/EMS-ESP32/issues/3229) - remove HA config for excluded entities [#3229](https://github.com/emsesp/EMS-ESP32/issues/3229)
- `show system` reports the Ethernet status on boards with a PHY, so a failed initialisation or a link that never came up is visible instead of Ethernet being omitted completely. Also shows the loop task's lowest free stack, to help diagnose reboots - `show system` reports the Ethernet status on boards with a PHY, so a failed initialisation or a link that never came up is visible instead of Ethernet being omitted completely. Also shows the loop task's lowest free stack, to help diagnose reboots
- new Application Setting "Automatically check for firmware updates", off by default. EMS-ESP only contacts emsesp.org for the latest version when it's enabled, so the Version page shows the available versions
## Fixed ## Fixed
+1
View File
@@ -55,6 +55,7 @@ export interface Settings {
email_subject: string; email_subject: string;
developer_mode: boolean; developer_mode: boolean;
disable_reset: boolean; disable_reset: boolean;
auto_fw_check: boolean;
} }
export enum busConnectionStatus { export enum busConnectionStatus {
@@ -512,6 +512,18 @@ const ApplicationSettings = () => {
</Grid> </Grid>
</> </>
)} )}
<Typography color="secondary">Firmware</Typography>
<BlockFormControlLabel
control={
<Checkbox
checked={data.auto_fw_check}
onChange={updateFormValue}
name="auto_fw_check"
/>
}
label={LL.AUTO_FW_CHECK()}
/>
<Typography sx={{ pb: 1, pt: 2 }} variant="h6" color="primary"> <Typography sx={{ pb: 1, pt: 2 }} variant="h6" color="primary">
{LL.SENSORS()} {LL.SENSORS()}
</Typography> </Typography>
+1
View File
@@ -321,6 +321,7 @@ const cs: Translation = {
DASHBOARD: 'Dashboard', DASHBOARD: 'Dashboard',
DEVELOPER_MODE: 'Režim vývojáře', DEVELOPER_MODE: 'Režim vývojáře',
DISABLE_RESET: 'Zakázat obnovení továrního nastavení', DISABLE_RESET: 'Zakázat obnovení továrního nastavení',
AUTO_FW_CHECK: 'Automaticky kontrolovat aktualizace firmwaru',
BYTES: 'Bajty', BYTES: 'Bajty',
BITMASK: 'Bit Mask', BITMASK: 'Bit Mask',
DUPLICATE: 'Duplikát', DUPLICATE: 'Duplikát',
+1
View File
@@ -321,6 +321,7 @@ const de: Translation = {
DASHBOARD: 'Dashboard', DASHBOARD: 'Dashboard',
DEVELOPER_MODE: 'Entwicklermodus', DEVELOPER_MODE: 'Entwicklermodus',
DISABLE_RESET: 'Werkseinstellungen deaktivieren', DISABLE_RESET: 'Werkseinstellungen deaktivieren',
AUTO_FW_CHECK: 'Automatisch nach Firmware-Updates suchen',
BYTES: 'Bytes', BYTES: 'Bytes',
BITMASK: 'Bit Maske', BITMASK: 'Bit Maske',
DUPLICATE: 'Kopieren', DUPLICATE: 'Kopieren',
+1
View File
@@ -321,6 +321,7 @@ const en: Translation = {
DASHBOARD: 'Dashboard', DASHBOARD: 'Dashboard',
DEVELOPER_MODE: 'Developer Mode', DEVELOPER_MODE: 'Developer Mode',
DISABLE_RESET: 'Disable Factory Reset', DISABLE_RESET: 'Disable Factory Reset',
AUTO_FW_CHECK: 'Automatically check for firmware updates',
BYTES: 'Bytes', BYTES: 'Bytes',
BITMASK: 'Bit Mask', BITMASK: 'Bit Mask',
DUPLICATE: 'Duplicate', DUPLICATE: 'Duplicate',
+1
View File
@@ -321,6 +321,7 @@ const fr: Translation = {
DASHBOARD: 'Tableau de bord', DASHBOARD: 'Tableau de bord',
DEVELOPER_MODE: 'Mode développeur', DEVELOPER_MODE: 'Mode développeur',
DISABLE_RESET: 'Désactiver la réinitialisation de fabrique', DISABLE_RESET: 'Désactiver la réinitialisation de fabrique',
AUTO_FW_CHECK: 'Vérifier automatiquement les mises à jour du firmware',
BYTES: 'Octets', BYTES: 'Octets',
BITMASK: 'Masque de bits', BITMASK: 'Masque de bits',
DUPLICATE: 'Dupliquer', DUPLICATE: 'Dupliquer',
+1
View File
@@ -321,6 +321,7 @@ const it: Translation = {
DASHBOARD: 'Pannello di controllo', DASHBOARD: 'Pannello di controllo',
DEVELOPER_MODE: 'Modalità sviluppatore', DEVELOPER_MODE: 'Modalità sviluppatore',
DISABLE_RESET: 'Disabilita la ripristino di fabbrica', DISABLE_RESET: 'Disabilita la ripristino di fabbrica',
AUTO_FW_CHECK: 'Controlla automaticamente gli aggiornamenti del firmware',
BYTES: 'Byte', BYTES: 'Byte',
BITMASK: 'Bitmask', BITMASK: 'Bitmask',
DUPLICATE: 'Duplicato', DUPLICATE: 'Duplicato',
+1
View File
@@ -321,6 +321,7 @@ const nl: Translation = {
DASHBOARD: 'Dashboard', DASHBOARD: 'Dashboard',
DEVELOPER_MODE: 'Ontwikkelaarsmodus', DEVELOPER_MODE: 'Ontwikkelaarsmodus',
DISABLE_RESET: 'Fabrieksinstellingen uitschakelen', DISABLE_RESET: 'Fabrieksinstellingen uitschakelen',
AUTO_FW_CHECK: 'Automatisch controleren op firmware-updates',
BYTES: 'Bytes', BYTES: 'Bytes',
BITMASK: 'Bit Mask', BITMASK: 'Bit Mask',
DUPLICATE: 'Duplicaat', DUPLICATE: 'Duplicaat',
+1
View File
@@ -321,6 +321,7 @@ const no: Translation = {
DASHBOARD: 'Dashboard', DASHBOARD: 'Dashboard',
DEVELOPER_MODE: 'Utvikler modus', DEVELOPER_MODE: 'Utvikler modus',
DISABLE_RESET: 'Deaktiver fabrikkinnstillinger', DISABLE_RESET: 'Deaktiver fabrikkinnstillinger',
AUTO_FW_CHECK: 'Se automatisk etter nye firmware versjoner',
BYTES: 'Bytes', BYTES: 'Bytes',
BITMASK: 'Bitmask', BITMASK: 'Bitmask',
DUPLICATE: 'Duplikat', DUPLICATE: 'Duplikat',
+1
View File
@@ -321,6 +321,7 @@ const pl: BaseTranslation = {
DASHBOARD: 'Pulpit', DASHBOARD: 'Pulpit',
DEVELOPER_MODE: 'Tryb programisty', DEVELOPER_MODE: 'Tryb programisty',
DISABLE_RESET: 'Wyłącz reset fabryczny', DISABLE_RESET: 'Wyłącz reset fabryczny',
AUTO_FW_CHECK: 'Automatycznie sprawdzaj aktualizacje firmware',
BYTES: 'Bajty', BYTES: 'Bajty',
BITMASK: 'Bit Mask', BITMASK: 'Bit Mask',
DUPLICATE: 'Duplicate', DUPLICATE: 'Duplicate',
+1
View File
@@ -321,6 +321,7 @@ const sk: Translation = {
DASHBOARD: 'Panel', DASHBOARD: 'Panel',
DEVELOPER_MODE: 'Režim vývojára', DEVELOPER_MODE: 'Režim vývojára',
DISABLE_RESET: 'Zakázať továrenské nastavenia', DISABLE_RESET: 'Zakázať továrenské nastavenia',
AUTO_FW_CHECK: 'Automaticky kontrolovať aktualizácie firmvéru',
BYTES: 'Bytov', BYTES: 'Bytov',
BITMASK: 'Bitová maska', BITMASK: 'Bitová maska',
DUPLICATE: 'Duplicitné', DUPLICATE: 'Duplicitné',
+1
View File
@@ -321,6 +321,7 @@ const sv: Translation = {
DASHBOARD: 'Kontrollpanel', DASHBOARD: 'Kontrollpanel',
DEVELOPER_MODE: 'Utvecklarläge', DEVELOPER_MODE: 'Utvecklarläge',
DISABLE_RESET: 'Inaktivera fabriksåterställning', DISABLE_RESET: 'Inaktivera fabriksåterställning',
AUTO_FW_CHECK: 'Sök automatiskt efter nya firmwareversioner',
BYTES: 'Bytes', BYTES: 'Bytes',
BITMASK: 'Bitmask', BITMASK: 'Bitmask',
DUPLICATE: 'Dublett', DUPLICATE: 'Dublett',
+1
View File
@@ -321,6 +321,7 @@ const tr: Translation = {
DASHBOARD: 'Kontrol Paneli', DASHBOARD: 'Kontrol Paneli',
DEVELOPER_MODE: 'Geliştirici Modu', DEVELOPER_MODE: 'Geliştirici Modu',
DISABLE_RESET: 'Fabrika ayarlarını devre dışı bırak', DISABLE_RESET: 'Fabrika ayarlarını devre dışı bırak',
AUTO_FW_CHECK: 'Firmware güncellemelerini otomatik olarak denetle',
BYTES: 'Bayt', BYTES: 'Bayt',
BITMASK: 'Bit Maskesi', BITMASK: 'Bit Maskesi',
DUPLICATE: 'Çift', DUPLICATE: 'Çift',
+1
View File
@@ -66,6 +66,7 @@ let settings = {
modbus_timeout: 10000, modbus_timeout: 10000,
developer_mode: true, developer_mode: true,
disable_reset: false, disable_reset: false,
auto_fw_check: false,
email_enabled: false, email_enabled: false,
email_security: 2, email_security: 2,
email_server: 'smtp.gmail.com', email_server: 'smtp.gmail.com',
+4
View File
@@ -121,6 +121,10 @@
#define EMSESP_DEFAULT_TELNET_ENABLED true #define EMSESP_DEFAULT_TELNET_ENABLED true
#endif #endif
#ifndef EMSESP_DEFAULT_AUTO_FW_CHECK
#define EMSESP_DEFAULT_AUTO_FW_CHECK false
#endif
#ifndef EMSESP_DEFAULT_MODBUS_ENABLED #ifndef EMSESP_DEFAULT_MODBUS_ENABLED
#define EMSESP_DEFAULT_MODBUS_ENABLED false #define EMSESP_DEFAULT_MODBUS_ENABLED false
#endif #endif
+2
View File
@@ -720,6 +720,7 @@ void System::store_settings(WebSettings & settings) {
system_name_ = settings.system_name; system_name_ = settings.system_name;
developer_mode_ = settings.developer_mode; developer_mode_ = settings.developer_mode;
disable_reset_ = settings.disable_reset; disable_reset_ = settings.disable_reset;
auto_fw_check_ = settings.auto_fw_check;
} }
// Starts up core services // Starts up core services
@@ -2733,6 +2734,7 @@ bool System::command_info(const char * value, const int8_t id, JsonObject output
node["forceHeatingOff"] = settings.boiler_heatingoff; node["forceHeatingOff"] = settings.boiler_heatingoff;
node["developerMode"] = settings.developer_mode; node["developerMode"] = settings.developer_mode;
node["disableReset"] = settings.disable_reset; node["disableReset"] = settings.disable_reset;
node["autoFwCheck"] = settings.auto_fw_check;
}); });
// Devices - show EMS devices if we have any // Devices - show EMS devices if we have any
+9
View File
@@ -207,6 +207,14 @@ class System {
disable_reset_ = disable_reset; disable_reset_ = disable_reset;
} }
bool auto_fw_check() {
return auto_fw_check_;
}
void auto_fw_check(bool auto_fw_check) {
auto_fw_check_ = auto_fw_check;
}
// Boolean Format API/MQTT // Boolean Format API/MQTT
uint8_t bool_format() { uint8_t bool_format() {
return bool_format_; return bool_format_;
@@ -447,6 +455,7 @@ class System {
uint32_t modbus_timeout_; uint32_t modbus_timeout_;
bool developer_mode_; bool developer_mode_;
bool disable_reset_; bool disable_reset_;
bool auto_fw_check_;
uint32_t fstotal_; uint32_t fstotal_;
uint32_t psram_; uint32_t psram_;
uint32_t appused_; uint32_t appused_;
+7
View File
@@ -85,6 +85,7 @@ void WebSettings::read(WebSettings & settings, JsonObject root) {
root["modbus_timeout"] = settings.modbus_timeout; root["modbus_timeout"] = settings.modbus_timeout;
root["developer_mode"] = settings.developer_mode; root["developer_mode"] = settings.developer_mode;
root["disable_reset"] = settings.disable_reset; root["disable_reset"] = settings.disable_reset;
root["auto_fw_check"] = settings.auto_fw_check;
root["email_enabled"] = settings.email_enabled; root["email_enabled"] = settings.email_enabled;
root["email_security"] = settings.email_security; root["email_security"] = settings.email_security;
root["email_server"] = settings.email_server; root["email_server"] = settings.email_server;
@@ -310,6 +311,12 @@ StateUpdateResult WebSettings::update(JsonObject root, WebSettings & settings) {
settings.disable_reset = root["disable_reset"]; settings.disable_reset = root["disable_reset"];
EMSESP::system_.disable_reset(settings.disable_reset); EMSESP::system_.disable_reset(settings.disable_reset);
settings.auto_fw_check = root["auto_fw_check"] | EMSESP_DEFAULT_AUTO_FW_CHECK;
EMSESP::system_.auto_fw_check(settings.auto_fw_check);
if (settings.auto_fw_check && !original_settings.auto_fw_check) {
EMSESP::webStatusService.schedule_versions_refresh(); // just switched on, so look straight away
}
settings.bool_dashboard = root["bool_dashboard"] | EMSESP_DEFAULT_BOOL_FORMAT; settings.bool_dashboard = root["bool_dashboard"] | EMSESP_DEFAULT_BOOL_FORMAT;
EMSESP::system_.bool_dashboard(settings.bool_dashboard); EMSESP::system_.bool_dashboard(settings.bool_dashboard);
+1
View File
@@ -122,6 +122,7 @@ class WebSettings {
bool developer_mode; // developer mode bool developer_mode; // developer mode
bool disable_reset; // disable reset bool disable_reset; // disable reset
bool auto_fw_check; // periodically check emsesp.org for a newer firmware version
static void read(WebSettings & settings, JsonObject root); static void read(WebSettings & settings, JsonObject root);
static StateUpdateResult update(JsonObject root, WebSettings & settings); static StateUpdateResult update(JsonObject root, WebSettings & settings);
+7 -2
View File
@@ -402,10 +402,15 @@ void WebStatusService::schedule_versions_refresh() {
versions_next_fetch_ms_ = next; versions_next_fetch_ms_ = next;
} }
// periodic refresh (1 hour) of the cached versions.json // periodic refresh (1 hour) of the cached versions.json, only when auto_fw_check is enabled
// runs on the main loop task, which has a much bigger stack than AsyncTCP needed for https // runs on the main loop task so the blocking fetch never happens in an AsyncTCP callback
void WebStatusService::loop() { void WebStatusService::loop() {
#ifndef EMSESP_STANDALONE #ifndef EMSESP_STANDALONE
// only reach out to emsesp.org if the user has asked us to
if (!EMSESP::system_.auto_fw_check()) {
return;
}
// need a network // need a network
if (!EMSESP::network_.network_connected()) { if (!EMSESP::network_.network_connected()) {
return; return;