diff --git a/Web App/web/src/views/Charging.vue b/Web App/web/src/views/Charging.vue index 045176a..a3ff4cd 100644 --- a/Web App/web/src/views/Charging.vue +++ b/Web App/web/src/views/Charging.vue @@ -1781,12 +1781,58 @@ async function refreshCtl() { modbusHost.value = ctl.value?.modbusHost || ""; modbusPort.value = ctl.value?.modbusPort || 502; syncSettingsDraft(); + chaseSettings(); } catch (e) { ctlError.value = e.message; ctl.value = null; + stopSettingsRetry(); } } +// --- Waiting for the half of the snapshot that answers late ------------------- +// +// A snapshot has two halves on two messages. The telemetry comes from the +// trigger and is there by the time the read returns; the settings come when the +// charger gets round to answering the request for them, which on this A5191 was +// measured at around half a minute — long after the read that asked has gone. +// The frame is not lost: it lands in the server's state and the next read +// carries it. But nothing on this page took a next read, so a settings card that +// came up empty stayed empty until something else happened to refresh it, which +// is what "it doesn't always load" was. +// +// So a refresh that comes back without them queues another look, at widening +// gaps, and then stops. Stopping matters: the message the server asks with is +// one the reference reads as carrying an Anker bug, so a charger that never +// answers it is a real possibility, and a page left open all day must not poll +// one for ever. +const SETTINGS_RETRY_MS = [6000, 12000, 24000, 45000]; +let settingsRetryAt = 0; +let settingsRetryFor = ""; +let settingsRetryTimer = null; + +function stopSettingsRetry() { + clearTimeout(settingsRetryTimer); + settingsRetryTimer = null; +} + +function chaseSettings() { + const sn = ctlSerial.value.trim(); + // A different charger is a different question, and gets its own patience. + if (sn !== settingsRetryFor) { + settingsRetryFor = sn; + settingsRetryAt = 0; + } + stopSettingsRetry(); + if (!sn || !ctlReadsDevice.value || dev.value.settings) { + settingsRetryAt = 0; + return; + } + const wait = SETTINGS_RETRY_MS[settingsRetryAt]; + if (wait === undefined) return; // asked enough times; the Refresh button remains + settingsRetryAt++; + settingsRetryTimer = setTimeout(refreshCtl, wait); +} + // --- The charger's address on the local network (Modbus mode) --- // Enabled on the device in the Anker app under Settings > Integrations > Modbus // TCP, which is where the address to type here comes from. @@ -1899,6 +1945,7 @@ onMounted(async () => { onUnmounted(() => { stopLivePoll(); + stopSettingsRetry(); document.removeEventListener("visibilitychange", onPageVisibility); });