python3-improv: emit Device-Status JSON superset (net/time/sec) for imx93-jaguar-eink#41
Conversation
Extend the imx93-jaguar-eink vendor Device-Status characteristic (e5f10002) from the flat network payload to the full Device-Status document defined in active-esl-onboard BLE-BOARD-PROFILE.md §5: - net: network fields nested under a `net` block (bearer/state/ssid/ ipv4/rssi/iface). Legacy flat top-level keys are mirrored for one release so older app builds keep working; the app prefers `net`. - time: clock-sync status (epoch/iso/source/synced) from the systemd-timesyncd stamp file. Reports ntp/none rather than trusting the flaky PCF2131 RTC. - sec: self-reported security posture (secure_element=ele, dm-crypt storage_encrypted, bonded/attested=false). secure_boot is reported `unknown` for now: the raw ELE-OCOTP0 shadow cannot be interpreted safely (every SoC has non-zero fuses) — authoritative fused/unfused state needs the ELE lifecycle query (tracked follow-up, roadmap P0-1/P2-1). We never emit a value that could be wrong. Computed off the BLE event loop (same executor path as before) so reads never block. Verified over BLE on eink-0167 (info --json). Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 4b93e6d. Configure here.
| """Blocking; call off the BLE loop. Full Device-Status superset.""" | ||
| return build_device_status(compute_net_status()) | ||
|
|
||
|
|
There was a problem hiding this comment.
Clock fields trigger periodic notifies
Medium Severity
Each refresh now embeds a fresh time block (epoch/iso) in the payload passed to _publish_net_status, but change detection still compares the full serialized JSON. When link state is unchanged, the document still differs every cycle, so _publish_net_status treats every refresh as a change and sends BLE notifications on each ~5s loop iteration instead of only on network updates.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 4b93e6d. Configure here.
Hot-patching the ota block onto eink-0167 showed the characteristic value truncatedating mid-JSON at 512 bytes (full payload with the legacy flat mirror was ~580). Drop the flat top-level state/ssid/ipv4/rssi/iface mirror (the app has preferred nested net since #41) and add a progressive shrink (time.iso → ota.os_version/hwid) before publish so a long SSID can't silently corrupt the JSON. Re-verified over BLE: complete ota block with registered:false/factory:eink/target:25/daemon:false. Co-authored-by: Cursor <cursoragent@cursor.com>
… (ota block) (#45) * python3-improv: report Foundries enrolment/OTA state in Device-Status (ota block) Add an `ota` block to the Improv Device-Status superset (vendor char e5f10002) so the app/cloud can see, during onboarding, whether the board is enrolled to a Foundries factory and running the OTA client: - registered: /var/sota/sota.toml present (the config lmp-device-register writes and aktualizr-lite.service's ConditionPathExists gate); absent => not enrolled to any factory - factory/tag/hwid/target/os_version: from /etc/os-release - daemon: aktualizr-lite.service active - up_to_date: null on the board on purpose — authoritative "on latest target" comes from the cloud->Foundries API, not a possibly-OFFLINE device All signals are root-free/best-effort and self-reported (untrusted until attested, roadmap P2-1). Verified on eink-0167 (currently un-enrolled): {"registered":false,"factory":"eink","tag":"main-imx93-jaguar-eink", "hwid":"imx93-jaguar-eink","target":25,"os_version":"5.0.11-25-96", "daemon":false,"up_to_date":null}. Supports the app/admin onboard/offboard-to-Foundries feature (BLE-triggered on-device registration + cloud offboard via Foundries API). Co-authored-by: Cursor <cursoragent@cursor.com> * python3-improv: fit Device-Status+ota under the 512-byte ATT ceiling Hot-patching the ota block onto eink-0167 showed the characteristic value truncatedating mid-JSON at 512 bytes (full payload with the legacy flat mirror was ~580). Drop the flat top-level state/ssid/ipv4/rssi/iface mirror (the app has preferred nested net since #41) and add a progressive shrink (time.iso → ota.os_version/hwid) before publish so a long SSID can't silently corrupt the JSON. Re-verified over BLE: complete ota block with registered:false/factory:eink/target:25/daemon:false. Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Alex J Lennon <ajlenon@dynamicdevices.co.uk> Co-authored-by: Cursor <cursoragent@cursor.com>


Summary
Extends the imx93-jaguar-eink vendor Device-Status characteristic (
e5f10002) from the flat network payload to the full Device-Status JSON superset defined in the app-side contract (active-esl-onboarddocs/BLE-BOARD-PROFILE.md§5 / §5.1). This implements roadmap P0-2 (net-nest + time) and the Phase-0 slice of P0-1 (sec block).net— network fields moved under a nestednetblock (bearer/state/ssid/ipv4/rssi/iface). The legacy flat top-level keys are mirrored for one release for backward compatibility; the app prefers thenetblock.time— clock-sync status (epoch/iso/source/synced) from the systemd-timesyncd stamp file. Reportsntp/noneinstead of trusting the flaky PCF2131 RTC.sec— self-reported security posture:secure_element:"ele", dm-cryptstorage_encrypted,bonded:false,attested:false.secure_bootis deliberately"unknown"— the rawELE-OCOTP0shadow can't be safely interpreted (every SoC has non-zero fuses), so authoritative fused/unfused state is a tracked follow-up (ELE lifecycle query; roadmap P0-1/P2-1). We never emit a value that could be wrong.All blocks are computed off the BLE event loop (same executor path as before), so reads never block on
nmcli.Compatibility
The app (
device_status.dart) already parses this superset and falls back to the flat keys, so this is a forward-compatible rollout. Field names are locked against the app in BLE-BOARD-PROFILE.md §5.1.Test plan
py_compilecleanimprov_provision.py info --json: confirmed nestednet+ flat mirror +time{source:ntp,synced:true}+sec{secure_element:ele,...}improv.serviceafter verificationNotes
Branched off
main(PR #38 watchdog). Independent, parallel "ghost-advertising bounce" watchdog WIP exists on another branch and is not included here.Made with Cursor