fix: restore AtomHeart Eclair BLE reliability - #639
Conversation
|
[P1] The new readiness gate can accept a truncated frame as “valid.” In lib/src/models/device/impl/atomheart/atomheart_scale.dart:195, parseFrame() rejects only data.length < 9. But the parser consumes: byte 0: 0x57 header That requires at least 10 bytes. With a 9-byte input, data[8] becomes both the fourth timer byte and data.last, which is treated as the checksum. A concrete malformed frame that passes today is: 57 00 00 00 00 00 00 00 00 The XOR of bytes 1–7 is 0, and byte 8 is also 0, so parseFrame() returns a zero-weight snapshot. The newly added _parseNotification() then completes _firstValidFrame, causing onConnect() to declare the scale connected. That defeats this PR's core guarantee that readiness requires a checksummed Eclair weight frame. I'd change the guard to at least: if (data.length < 10) return null; If the Eclair notification is specified as fixed-width, data.length != 10 would be stronger. I'd also add a regression case emitting the 9-byte all-zero frame before the good frame and asserting the scale remains connecting. Everything else I checked looks consistent: the UUID replacement propagates through DeviceMatcher, the reset/start/stop opcodes match the hardware-tested de1app change, production resetSubscription() genuinely disables/re-enables notifications rather than merely reattaching the Dart listener, and the Actions run passed format, analyze, tests, and Linux build. |
|
@ODevStudio requesting re-review |
|
No further code-review findings. Prior P1 is resolved. |
Use the current Eclair GATT and timer protocol, and only report readiness after valid scale data. Retry a silent notification subscription twice before disconnecting for normal recovery.
The readiness gate accepted a 9-byte notification. The parser consumes a 0x57 header, four weight bytes, four timer bytes, and a trailing XOR checksum, so 9 bytes let the fourth timer byte double as the checksum. 57 00 00 00 00 00 00 00 00 therefore XOR-validated as a zero-weight snapshot and completed the first-valid-frame gate, marking the scale connected without usable data. Require the exact 10-byte Eclair frame that de1app's hardware-tested parser scans, and cover both the truncated and over-long cases plus the readiness boundary.
75c342d to
65ab1ed
Compare
Summary
What changed, and why?
data/status, and command characteristics, and update scale discovery.
connectinguntil a valid checksummed weight frame arrives.Reset a silent notification subscription at most twice, then disconnect so
normal ConnectionManager recovery can retry.
Change Type (select all)
Scope (select all touched areas)
Linked Issues
Fixes #629
Root Cause (if bug fix)
opcodes and marked the link ready before receiving a valid Eclair frame.
nor the first-valid-frame readiness boundary.
outside the protocol layer; hardware validation remains mandatory.
Regression Test Plan (if bug fix or refactor)
simulate=1+ curl/websocat)test/unit/models/atomheart_scale_reliability_test.dartand
test/unit/services/device_matcher_test.dart.checksummed first-frame readiness, bounded notification reset, and disconnect.
Documentation Obligations (required)
assets/api/rest_v1.ymlorassets/api/websocket_v1.yml(if REST/WebSocket changed)doc/Api.md(if user-facing endpoint changed)doc/Plugins.md(if events/API changed)doc/Skins.md(if skin behavior changed)doc/Profiles.md(if profile handling changed)doc/DeviceManagement.md(if device flows changed)doc/AI_BLE_NOTES.mdis also updated with the protocol constraint.Security Impact (required)
No.No.No.Yes, Eclair UUIDs, timer writes, and readinessrecovery changed.
No.No.notification recovery is checksummed, bounded to two resets, then fails
closed through normal disconnect recovery.
User-Visible Changes
reported connected only after usable scale data arrives.
fails closed after three 800 ms windows instead of appearing ready.
Verification
Local gates (run before pushing)
dart format lib test- no remaining candidate changesflutter analyze- cleanflutter test- 3,186 passed, 1 skipped./scripts/fetch_dye2_plugin.sh- not rerun for this local draftManual verification (if applicable)
simulate=1):No.No; no Eclair was available.recovery behavior through focused tests.
reset/start/stop, and disconnect.
reporter's Android tablet. This PR has no meaningful changed visual surface,
so desktop Computer Use cannot validate its BLE protocol behavior.
Evidence
Detailed evidence:
timer opcodes, immediate-ready behavior, and missing silent-link recovery.
dart format --output=none --set-exit-if-changed lib/src/models/device/impl/atomheart/atomheart_scale.dart test/unit/models/atomheart_scale_reliability_test.dart test/unit/services/device_matcher_test.dartflutter analyze --no-pub(no issues).flutter test --no-pubwith the package-matched QuickJS DLL onPATH(3,186 passed, 1 skipped).
reporter's Android tablet remain required to validate native connection,
service discovery, notification recovery, and timer controls end to end.
Compatibility & Migration
Yesfor supported current Eclair firmware; devicesadvertising only the obsolete Decenza-style UUID are no longer misidentified.
No.No.Risks & Mitigations
current device may behave differently from the captured protocol.
notifications, recovery, and timer controls on an Eclair before publishing.
Contributor Responsibility
AI-assisted development is allowed. The submitter remains responsible for the submitted work.