Skip to content

Fix/matter - #28

Closed
khlam wants to merge 68 commits into
mainfrom
fix/matter
Closed

khlam wants to merge 68 commits into
mainfrom
fix/matter

Conversation

@khlam

@khlam khlam commented Sep 19, 2026 •

Copy link
Copy Markdown
Owner

Overview

Matter boards now get their pairing credentials when they are flashed, not when the firmware compiles, so one build can flash many boards and a saved key reproduces a board's codes. The radar sensor's dashboard moves from the in-repo httpd package to Microdot, with hard limits on connections and memory, and the page now works without internet access. The PR also adds agent skills with a CI link check, and updates two locked dependencies to clear the vulnerability scan.

What’s New

  • matter.generate_pairing(passcode) in firmware-packages/matter/matter/pairing.py derives the Matter setup passcode, discriminator, and manual pairing code from one secret key. A key needs at least 24 characters and 12 distinct ones. With no key, it draws a random 256-bit key and returns it, so the codes can be rebuilt later.
  • tools/matter-build/pairing_code.py rebuilds a board's QR image and manual code from its key, with no hardware attached.
  • Microdot 2.6.2 as a frozen firmware dependency. A new firmware-dependencies stage in Dockerfile.host installs it from uv.lock with hash checks. Every firmware build stage copies it in. manifest.py freezes it into firmware that imports it, and fails the build if it is missing.
  • projects/matter-radar-sensor/firmware/webserver.py serves the dashboard page and WebSocket through Microdot. Its own socket layer caps every resource a browser can grow; the limits are listed in the radar README.
  • reports.py (dead zone, occupancy hold, telemetry pacing) and status.py (commissioning state, pixel colors) are split out of the radar main.py.
  • Agent skills under skills/: new-skill, talking-to-a-user, and tidy-pr. skills/link-skills.sh links every skill into .claude/skills and .agents/skills, and caps each SKILL.md and AGENTS.md at 600 words. make skills runs it; the CI "Repo guards" job runs it with --check.

What Has Changed

  • Compile and flash are separate steps for both Matter projects, in build.py:
flowchart LR
    compile["esp32-compile"] --> image["app.esp32-s3.bin<br/>empty factory partition"]
    key["PASSCODE key<br/>(random if unset)"] --> flash["esp32-flash"]
    image --> flash
    flash --> provision["insert factory partition,<br/>validate, flash"]
    provision --> publish["publish image, QR,<br/>setup.txt"]
Loading
  • esp32-compile publishes only outputs/app.esp32-s3.bin and deletes any old QR and setup files.
  • esp32-flash now runs build.py --flash. It takes PASSCODE, MANUFACTURER, and SERIAL_NUMBER (moved from the compile service), writes the factory partition into the image, validates it, flashes, and then publishes that board's image, QR, and setup.txt. A failed flash leaves the previous files in place. Add --no-deps to flash another board without recompiling.
  • setup.txt now also holds the board's passcode key. Keep it secret: the key alone gives away the pairing code of every board flashed with it.
  • Radar dashboard page (viz/static/index.html) draws its four charts as inline SVG instead of loading Plotly from cdn.plot.ly. One browser connects at a time (was three); a second one sees a Take connection button that replaces the current viewer. Hiding the tab closes the socket, and the page reconnects only when that button is clicked (it used to retry every 250 ms).
  • Radar telemetry goes out only when the filtered targets change, still at most every 500 ms. Occupancy still uses every report, and the web server queues telemetry only while a viewer is connected.
  • Radar board config (sdkconfig.board) turns on BLE modem sleep on the main crystal, and lowers logging from INFO to WARN, with CHIP at ERROR.
  • Docs: firmware-packages/matter/ARCHITECTURE.md is folded into a shorter package README with a new Pairing section. The radar README is rewritten for the new server, build flow, and wiring. The routing tables in AGENTS.md, projects/AGENTS.md, and tools/AGENTS.md are gone.
  • Removed: the firmware-packages/httpd package, which nothing imports anymore, and .github/pull_request_template.md. The template now lives in the tidy-pr skill, so GitHub no longer prefills new PRs.
  • Versions: root 0.19.1 → 0.22.5, matter 0.2.0 → 0.2.2, matter-example 0.2.0 → 0.2.3, matter-radar-sensor 0.3.0 → 0.5.5, and a patch bump for every other project, whose compose file gained the firmware-dependencies build context.

What’s Fixed

  • uv.lock moves anyio 4.13.0 → 4.15.1 and typing-extensions 4.15.0 → 4.16.0, which clears the vuln-check job.
  • The radar README's factory-reset command called node.factory_reset(), but the firmware has no global node. It now sends import _matter; _matter.factory_reset().

Testing

New:

Updated: the radar conftest.py, test_boot_status.py, test_occupancy.py, test_radar.py, and test_matter_poll.py; the build-tool tests test_artifact_checks.py, test_factory_data.py, test_toolchain_commands.py, test_board_config.py, and test_onboarding.py. Removed: the radar test_dashboard.py (replaced by test_webserver.py) and the httpd package tests.

Full suite: 707 passed, 94.64% coverage (gate: 90%).

docker compose up pytest --build --exit-code-from pytest

Additional Information

  • The power and thermal effect of the BLE sleep and logging change is not measured. To check on hardware, compare temperature, current draw, and person-to-controller response time with the dashboard open and closed.
  • Native Wi-Fi/lwIP memory use and responsiveness under sustained network load are not yet tested on the board alongside Matter.
  • A stale or missing skill link, or an over-long SKILL.md or AGENTS.md, now fails the Repo guards job, which every other job depends on. Fix it with make skills and commit the result. The script never removes a real file or folder where a link belongs; it reports it for manual removal.
  • The radar firmware work is three commits, so each can be read alone: the module split (no behavior change), the telemetry change, and the server swap.

@khlam
khlam force-pushed the fix/matter branch 2 times, most recently from b3b774d to 13daced Compare September 21, 2026 20:28
Each skill has one copy under skills/. link-skills.sh links it into
.claude/skills and .agents/skills, because an agent cannot see a skill
missing from its own tree. The PR template now lives in the tidy-pr skill.
Microdot comes from PyPI, not firmware-packages/, so the new
firmware-dependencies stage in Dockerfile.host installs it from uv.lock
with hash checks and keeps only its sources and license. Every firmware
build stage copies that stage in, and manifest.py fails the build when
firmware imports Microdot but the sources are missing.
Compilation now yields one image with an empty factory partition, so a
single build can flash many boards. esp32-flash derives each board's
credentials from a PASSCODE key (random when unset), writes the factory
partition into the image, validates it, flashes it, and only then
publishes that board's QR code and setup file.
The modem now sleeps between commissioning events, and routine INFO lines
are no longer formatted and written over USB. WARN, with CHIP at ERROR,
still reports commissioning failures.
reports.py holds the dead zone, hold timer, and telemetry pacing as pure
functions of each report's time, and status.py owns commissioning state
and pixel priority, so tests reach both without booting the application.
Behavior is unchanged.
An unchanged scene, empty or not, is no longer serialized every 500 ms.
Every report that falls due restarts the interval, sent or not, so the
last timestamp stays within ticks_diff's range while the scene is idle.
webserver.py bounds connections, request sizes, deadlines, socket writes,
and heap use, and shuts the dashboard down when memory runs low, so
network traffic cannot starve the radar or Matter tasks. The page draws
its charts in inline SVG instead of loading Plotly from a CDN, so the
viewing device needs no internet access. A second browser gets a Take
connection button rather than a second slot.
@khlam khlam closed this Sep 30, 2026
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