Skip to content

Feat/ux mqtt sentinels sampling caption#131

Merged
1technophile merged 4 commits into
developmentfrom
feat/ux-mqtt-sentinels-sampling-caption
May 18, 2026
Merged

Feat/ux mqtt sentinels sampling caption#131
1technophile merged 4 commits into
developmentfrom
feat/ux-mqtt-sentinels-sampling-caption

Conversation

@1technophile
Copy link
Copy Markdown
Member

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: new droppedSinceDisconnect counter and disconnectedSince timestamp, only counted when MQTT is configured on (opt-out users see nothing). Both reset on reconnect.
  • Device list: collapsing green banner "MQTT not connected — N readings lost since HH:MM" with Retry, auto-hides when the broker comes back.
  • Android FGS notification body gets a "MQTT down – N lost" suffix. ForegroundNotifier listens to statusChanged/droppedChanged so 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 drops model_id == "IBEACON", mirroring the known-device path at :203. Previously iBeacon adverts from not-yet-paired devices were silently republished to MQTT.
  • DeviceWidget.qml list rows guard temperature > -40 and humidity > 0 and render instead of -99.0° between BLE discovery and first decode (matches the detail-screen idiom).

3. Chart sampling-interval caption (2f8fb70, a4190d4)

  • New qml/components/ItemSamplingCaption.qml, wired into Thermometer / PlantSensor / Environmental detail screens. Reads settingsManager.updateInterval{Thermo,Plant,Env} (defaults 120 / 240 / 60 min from SettingsManager.h).
  • Shows "1 sample / N min" under the chart so users understand why the in-app history is coarser than the broker timeseries (every advert).
  • The C++ setters exist but no QML Settings control is wired to them today, so the caption is informational only — no misleading "change in Settings" cue.

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:

  • The pull request is done against the latest development branch
  • Only one feature/fix was added per PR and the code change compiles without warnings
  • I accept the DCO.

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.
@1technophile 1technophile merged commit c719b23 into development May 18, 2026
10 checks passed
@1technophile 1technophile deleted the feat/ux-mqtt-sentinels-sampling-caption branch May 18, 2026 14:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant