Skip to content

feat(q7): local bootstrap for sc05 / B01 devices - #96

Draft
Lash-L wants to merge 1 commit into
mainfrom
feat/q7-b01-local-bootstrap
Draft

Lash-L wants to merge 1 commit into
mainfrom
feat/q7-b01-local-bootstrap

Conversation

@Lash-L

@Lash-L Lash-L commented Sep 23, 2026

Copy link
Copy Markdown
Contributor

What

Adds local-server support for the Roborock Q7 family that speaks the B01
bootstrap protocol (roborock.vacuum.sc05).

Unlike the V1 flow, the Q7 authenticates its bootstrap requests with an HMAC over
the device's per-device secret and expects an AES-encrypted response, so the
server must know that secret to answer in a form the firmware accepts.

Changes

  • b01_bootstrap.py — request-signature verification, AES /b/region and
    /b/nc responses, and MQTT credential derivation, all from the firmware contract.
  • b01_import.py — import a device's secret/DUID into state/b01_devices.json
    (refuses to overwrite a different secret for an existing DID; data/ stays git-ignored).
  • server.py — route /b/region and /b/nc to the B01 handler.
  • runtime_credentials.py — resolve rr/d/i/{duid}/… topics by DUID rather
    than DID, so B01 MQTT frames decode with the correct localkey. (One-line fix; the
    old code matched a DUID string against the DID field and returned the wrong key.)
  • Tests (test_b01_bootstrap.py, test_b01_import.py) and docs/q7_b01.md.

Validation

Verified end to end on a real Q7 M5+: onboarding → /b/region + /b/nc
(AES) → MQTT TLS connect → inbound B01 frames decode via python-roborock
(create_mqtt_decoder, e.g. OTA version and consumable status).

tests/test_b01_bootstrap.py tests/test_b01_import.py — 25 passed.

Scope / follow-ups

  • Outbound B01 command + map/datapoint handling in Home Assistant is not in
    this PR; the inbound decode path is wired, outbound encoding is the next step.
  • The alternate RSA-4096 (v: v2) request branch is out of scope and returns 501.

🤖 Generated with Claude Code

Add HMAC + AES bootstrap so Q7 (roborock.vacuum.sc05, B01) devices can
onboard against the local server. The firmware signs /b/region and /b/nc
with its per-device secret and expects an AES-encrypted response, so the
server must hold that secret to reply in a form the firmware accepts.

- b01_bootstrap: request-signature verification, AES region/NC responses,
  and MQTT credential derivation, from the firmware contract
- b01_import: import a device's secret/DUID into state/b01_devices.json
- server: route /b/region and /b/nc to the B01 handler
- runtime_credentials: resolve rr/d/i/{duid}/... topics by DUID (not DID)
  so B01 MQTT frames decode with the correct localkey
- tests + docs

Validated end to end on a Q7 M5+: onboarding, region/NC, MQTT connect,
and inbound B01 frame decode via python-roborock. Outbound command/map
handling is the next step; the RSA-4096 (v2) request branch is out of scope
and returns 501.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@Lash-L
Lash-L force-pushed the feat/q7-b01-local-bootstrap branch from ae53821 to f47d062 Compare September 23, 2026 17:45
@Lash-L
Lash-L marked this pull request as draft September 26, 2026 00:47
Comment thread docs/q7_b01.md
@@ -0,0 +1,64 @@
# Q7 (sc05 / B01) local bootstrap

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

del

This branch has not been deployed

No deployments
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