Feat/ux mqtt sentinels sampling caption#131
Merged
1technophile merged 4 commits intoMay 18, 2026
Merged
Conversation
When the user has MQTT enabled but the broker link is down, publishData()
silently returned false on every BLE advert, with no signal to the user
that data was being lost. The device list, history DB, and Android
foreground-service notification kept rendering as if nothing was wrong,
while Home Assistant saw a gap.
Add a ``droppedSinceDisconnect`` counter and ``disconnectedSince``
timestamp on MqttManager (only counted when MQTT is configured on, so
opted-out users never see a banner). Reset both on broker reconnect.
Surface in the device-list as a collapsing banner ("MQTT not connected
— N readings lost since HH:MM" with Retry), and as a suffix on the
Android FGS notification body ("MQTT down – N lost"). Wire
ForegroundNotifier to MqttManager's statusChanged / droppedChanged so
the notification repaints immediately on state flip rather than waiting
for the 10s refresh tick.
Two known sentinel inconsistencies, fixed at the point of leak: 1. iBeacon adverts. DeviceManager_advertisement.cpp:203 (known path) drops ``model_id == IBEACON`` before MQTT publish. The unknown-device path's mirror at :343 only dropped ``RMAC`` / ``prmac`` — so an iBeacon adv from a not-yet-paired device kept being republished to the broker. Add the IBEACON check there too. 2. -99 / "no reading yet" sentinels in the device-list row. Device subclasses default temperature/humidity to -99 (device_sensor.h); the detail screens guard ``> -40`` but DeviceWidget's three list-row Text components rendered raw, so devices flickered as "-99.0°" between discovery and first decode. Apply the same -40 threshold and a "—" placeholder, matching the detail-screen idiom.
MQTT publishes every advertisement, but the in-app DB writes are
rate-limited by SettingsManager.updateInterval{Thermo,Plant,Env}
(default 20 min). Users comparing the app's chart to Home Assistant's
saw spikes in HA that the app never recorded, with no explanation.
Add a small italic caption under the Thermometer / PlantSensor /
Environmental history charts: "1 sample / N min · change in Settings",
binding N to the relevant interval property so it tracks user changes
live. Factored as components/ItemSamplingCaption.qml for reuse.
No tap target wired yet — Desktop and Mobile route to Settings via
different idioms and a passive caption beats half-working navigation.
The setters exist in C++ (SettingsManager::setUpdateInterval{Thermo,Plant,
Env}) but no QML Settings control writes to them today. Promising a path
that isn't there is worse than no instruction, so trim to just
"1 sample / N min". Wiring real Settings controls to those setters can
be a follow-up.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Three small, additive UX wins from auditing the data flow of a single BLE advertisement (which fans out to four sinks: phone SQLite, MQTT broker, Android notification, QML display) — and finding cases where they fall silently out of sync.
1. MQTT-down is no longer silent (
4b1ede1)MqttManager: newdroppedSinceDisconnectcounter anddisconnectedSincetimestamp, only counted when MQTT is configured on (opt-out users see nothing). Both reset on reconnect.ForegroundNotifierlistens tostatusChanged/droppedChangedso it repaints immediately rather than waiting for its 10 s refresh tick.2. Sentinel filtering is consistent across sinks (
4966935)DeviceManager_advertisement.cpp:343(unknown-device path) now dropsmodel_id == "IBEACON", mirroring the known-device path at :203. Previously iBeacon adverts from not-yet-paired devices were silently republished to MQTT.DeviceWidget.qmllist rows guard temperature> -40and humidity> 0and render—instead of-99.0°between BLE discovery and first decode (matches the detail-screen idiom).3. Chart sampling-interval caption (
2f8fb70,a4190d4)qml/components/ItemSamplingCaption.qml, wired into Thermometer / PlantSensor / Environmental detail screens. ReadssettingsManager.updateInterval{Thermo,Plant,Env}(defaults 120 / 240 / 60 min fromSettingsManager.h).Why this came up
Audit traced one advert through
MqttManager::publishData,DeviceTheengs::needsUpdateDb,ForegroundNotifier, and the QML list model. Several gates differ across paths (sentinel filters, IBEACON filter asymmetry, DB rate-limiting, silent MQTT drop). This PR ships the cheap, user-visible wins.Bigger items —
isEnabled()should gate the publish path too, MQTT topic instability across the known/unknown boundary — are left for separate discussion.Checklist: