Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@ accessory. One bridge, one pairing, however many devices.
something this plugin can change.
- **Apple Home only, as a claim.** Alexa, Google Home and SmartThings are untested and
unclaimed; nothing here says they will or won't work.
- **A second npm package** (`indigo-matter-bridge`), installed from its own menu item.
Note it is **not on the npm registry yet**, so export cannot be brought up until it is.
- **A second npm package** (`indigo-matter-bridge`), on the npm registry and installed
from its own menu item.

Setup, pairing, recovery and troubleshooting:
[full install guide](https://simons-plugins.github.io/indigo-matter/INSTALL.html). How it
Expand Down
143 changes: 134 additions & 9 deletions docs/HANDOVER.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,139 @@
# indigo-matter — Build Handover

**Last updated:** 2026-08-06 11:01 UTC
**Active work:** `fix/141-restore-endpoints-at-startup` — issue #141, the
empty-aggregator restart bug. See the section immediately below; the `main`
summary in this header describes the last merge, not that branch.
**Branch:** `main` — PRs #106, #107, #108 all merged.
**Version:** `2026.7.13`
**Tests:** 1005 passing (`cd indigo-matter && /Library/Frameworks/Python.framework/Versions/Current/bin/python3 -m pytest -q`)
**Deployed:** jarvis is running the #103-era plugin (v2026.7.10) plus **E5's export half, deployed 2026-08-05 with 3 accessories live in Apple Home**. **Nothing from #106/#107/#108, and no part of E6 or E7, has been deployed** — so the #104 supervision fixes are NOT yet live on jarvis.
**Status:** **Wi-Fi AND Thread validated with real hardware**, and the **export half's E0 pairing gate PASSED on 2026-08-04** with live two-way control on 2026-08-05 (see *Live validation on jarvis*). #104's three server-supervision faults are fixed and merged (#107). #105's diagnostic is merged (#108) but **#105 stays open** — the bridged-endpoint path still has no real-bridge validation. `domio-code` #236 is fixed and closed (domio-code PR #237). Known-open: #105, plus the older #43, #46, #21–#24.
**Last updated:** 2026-08-06 14:05 UTC
**Active work:** `feat/134-menu-sections` — **PR #144 OPEN**, CI green, awaiting
Simon's go-ahead. Menu grouping only; see the §#134 section below.
**Branch:** `main` — **PR #142 MERGED** (`3e1229d`, merge commit, `[no-release]`
so **no GitHub release was cut** — Simon is cutting that himself). Latest
release remains v2026.7.23.
**Version:** plugin `2026.8.5` on the open branch (`2026.8.4` on `main`),
bridge-node `0.7.0` (**published to npm**; `DEFAULT_INSTALL_SPEC` pins it).
**Tests:** **2256 Python** (2252 on `main`), **383 TS** — both green.
(`python3 -m pytest -q` · `cd bridge-node && npm run build && npm test`)
**Deployed:** jarvis runs plugin `2026.8.4` + bridge-node `0.7.0`, paired to
**Apple Home AND Alexa simultaneously** (3 fabrics: 2 Apple, 1 Alexa).
**Status:** export v1 feature-complete and live. #141 **fixed and confirmed**
(below). **#143 is the open one** — see the 2026-08-06 §#143 section; its
defect B was investigated hard today and the leading theory was **withdrawn**,
so read that before touching it.

**NEXT UP (Simon, 2026-08-06):** ~~tidy `MenuItems.xml` into groups~~ — **done**,
see the §#134 section immediately below. The constraint it warned about was
wrong in the useful direction: **separators do exist**.

---

## 2026-08-06 — issue #134: the menu, and the separator the docs deny

Plugin `2026.8.5`. Suites: **2256 Python** (from 2252), pylint **9.42**
unchanged. Branch `feat/134-menu-sections`. TS untouched.

**An empty, self-closing `<MenuItem id="…"/>` renders as a menu separator.**
The canonical `MenuItems.xml` reference lists `<Name>` as *required* and
documents neither separators nor submenus, which is why the note this replaces
said grouping could only be ordering plus name prefixes. It is wrong — or at
least incomplete. Perceptive Automation's own bundled plugins use the form
(**Timers and Pesters**, **Timed Devices**, **Virtual Devices**, **Alexa**),
`Actions.xml` takes it too (`<Action id="sep1" uiPath="DeviceActions"/>`), and
**15 of the plugins installed on jarvis** rely on it. Simon knew from the
Timers and Pesters *action* list that sections were possible; the docs alone
would never have said so.

Worth generalising: the canonical docs are the authority on what is
*supported*, not on what *works*. When a UI affordance is missing from them,
grep the installed plugins before concluding it does not exist —
`grep -rlE "<MenuItem[^>]*/>" …/Plugins/*/Contents/Server\ Plugin/MenuItems.xml`
answered this in one command.

**Five sections**, everyday first, destructive last: devices Indigo controls ·
devices Indigo publishes · matter-server plumbing · export-bridge plumbing ·
backup and recovery. The two `Install/update` items — #134's actual complaint,
clicked for one another live — now sit in **different** sections rather than
merely adjacent, because they are separately versioned, separately installed
npm packages.

**`Export fabric backup…` → `Back up the Matter fabric…`** (and `Restore
fabric backup…` → `Restore a fabric backup…`). "Export" meant save-to-disk in
one item and the outbound bridge in eight others. Menu **ids and callback
methods are unchanged**, so nothing in `plugin.py`, `bridge_agent.py` or
`server_process.py` moved; `spec.install_menu_name` still matches a real
`<Name>`, which `test_bridge_agent.py` pins.

**The tests assert the ORDER**, for the same reason #141's do: a membership
check passes just as happily with all sixteen items back in one flat list.
Mutation-verified both ways — deleting the four separators, and deleting only
`sepServerFromBridge` so the two install sections merge, each fail exactly the
three layout tests and nothing else.

**Not done here, deliberately:** #132 (the Rebuild Endpoint Map warning
overstates what the action does) is dialog *text* in the same file and a
separate bug — reordering it and rewriting it in one commit would have made
the diff unreviewable. #131 (sort exported devices to the top of the picker)
is untouched.

**Stale, spotted in passing, not fixed:** `docs/INSTALL.md` §Overview still
says the bridge package "is not on the npm registry yet, so this half cannot
be installed today". `indigo-matter-bridge@0.7.0` is published. That sentence
belongs to the E8 docs pass, along with #137/#138.

---

## 2026-08-06 (late) — issue #143: state wrong in Alexa. READ THIS BEFORE RESUMING IT

**Status: unresolved, parked for beta testers. The node is EXONERATED.**

Two halves, one root shape — we lean on matter.js's **attribute-change**
machinery for things that are not changes:

* **Defect A (inbound), still the substantive half.** Ecosystem commands are
emitted from `onOff$Changed` listeners, so an invoke matching the endpoint's
current state changes nothing and reaches Indigo never. Suspected, **not
proven**. Untouched by today's work.
* **Defect B (outbound).** New exports show stale, then *unresponsive*, in
**Alexa only** (Apple is fine) — then **come right on their own after minutes
with no intervention**. Best current reading: **Alexa-side convergence lag**,
probably not our bug.

**Do NOT re-assert the "born-vs-changed" theory as proven.** It is real in code
(`createEndpoint` bakes spec states into `initialState`, so an attribute born
`true` emits no change report) and the fix is cheap — construct from role
defaults, then `applyStates` after `aggregator.add()`, exactly as `update()`
already does. But it does **not** explain what was observed: a genuine write
also failed to move Alexa, and Alexa then fixed itself with no write at all.
I posted a "B2 CONFIRMED" verdict on the issue and then **withdrew it**; both
comments are there, read to the end.

**Measured, so don't re-measure it:** a controlled toggle produced `I/ReportData`
on all three live sessions (1 Apple, 2 Alexa Echo hubs), each acked in ~15ms.
Alexa = fabric index 4, **two wildcard subscriptions**, maxInterval ≈188s.
Outbound reporting to Alexa works, *including* for endpoints added after the
subscription existed.

**Three blind alleys — do not re-walk:**
1. matter.js does **not** flush a constructor-supplied `initialState` to its
store, so `…/indigo-matter-bridge/root.parts.aggregator.parts.<id>.onOff.onOff`
is **NOT** a reading of the live attribute. Two said `false` for accessories
that were on and correct in both apps. Cost about an hour.
2. "the node resurrects a stale persisted value on re-export" — tested three
ways (in-process, across a restart, via `upsert_endpoint`); **all pass**.
Those tests are committed (`e22e861`, `bridge-node/test/restore.test.ts`) and
they are what exonerate the node. The stored value was always right; the bug
was an *unreported* one, which no assertion on `stateOf` can catch.
3. **Never credit the last thing you did.** Something here fixes itself on its
own timescale. "The plugin restart fixed it" was claimed twice and was wrong
both times. Any intervention needs a control before causation is claimed.

**To settle it** (needs beta testers, more than one Alexa setup): export a
device that is **on**; record Alexa at t+0/+1/+5/+15 min **without touching
anything**; watch `root.subscriptions.subscriptions` for a re-subscribe at the
moment it comes right. Then repeat with the create-path fix applied — if Alexa
is right at t+0 the fix matters, if the curve is unchanged it is cosmetic.

**Also open, adjacent:** #140 — the drift line
(`indigo-459564566 expected 5, got 2`) now fires on **every** attach after the
factory reset, and `endpoint-map.json` records number `5` twice (Hallway Lamp
and Georges Pendant). Harmless — live numbers are unique — but it is the reset's
fingerprint and belongs in #140.

---

Expand Down
35 changes: 26 additions & 9 deletions docs/INSTALL.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ npm package**. This guide covers both:
managed-LaunchAgent bring-up on the reference Indigo server.
- **the Matter export bridge** — the optional outbound half, which publishes
selected *Indigo* devices to Apple Home as Matter accessories. **Steps E1–E4**.
**It cannot be installed today**: its npm package has not been published — see
Its npm package (`indigo-matter-bridge`) is on the registry and installs from
its own menu item — see
[Exporting Indigo devices](#exporting-indigo-devices-indigo-as-a-matter-bridge).

If you just installed the plugin and Indigo is logging
Expand All @@ -18,7 +19,8 @@ running but matter-server is not.

## Contents

- [Overview](#overview)
- [Overview](#overview) — including
[the Plugins ▸ Matter menu](#the-plugins--matter-menu)
- [Prerequisites](#prerequisites)
- [Step 1 — Install Node.js 22](#step-1--install-nodejs-22)
- [Step 2 — Install matter-server](#step-2--install-matter-server)
Expand Down Expand Up @@ -89,12 +91,27 @@ A few things to know before you start:
occasional rough edges.
- **There is a second, optional half.** The plugin can also work the other way round and
publish selected *Indigo* devices to Apple Home as Matter accessories, from a separate
bridge process with its own npm package. **That package is not on the npm registry yet,
so this half cannot be installed today.** When it is: nothing is exported and no bridge
process runs until you add a device to the export list, and it needs Node (Step 1) and
a storage path (Step 3) — *not* a working matter-server. See
bridge process with its own npm package (`indigo-matter-bridge`), installed from
**Plugins ▸ Matter ▸ Install/update the Matter export bridge**. Nothing is exported
and no bridge process runs until you add a device to the export list, and it needs
Node (Step 1) and a storage path (Step 3) — *not* a working matter-server. See
[Exporting Indigo devices](#exporting-indigo-devices-indigo-as-a-matter-bridge).

### The Plugins ▸ Matter menu

The menu is grouped into five sections, separated by dividers. Both halves of the
plugin have their own install item, and they are **not** interchangeable: they are
separately versioned npm packages, and running the wrong one restarts a half you
did not mean to touch.

| Section | Items | What it covers |
|---|---|---|
| 1 | *Commission device by setup code (advanced)…*, *Decommission Matter device…* | Matter devices Indigo **controls** — the everyday actions |
| 2 | *Manage Matter Exports…*, *Pair Matter Bridge…*, *Unpair an Ecosystem…* | Indigo devices Indigo **publishes** — the everyday actions |
| 3 | *Install/update matter-server*, *Restart…*, *Reinstall (clean)…*, *Open matter-server log…* | The inbound controller's own plumbing |
| 4 | *Install/update the Matter export bridge*, *Reinstall… (clean)…*, *Stop…* | The outbound bridge node's own plumbing |
| 5 | *Back up the Matter fabric…*, *Restore a fabric backup…*, *Rebuild Matter Endpoint Map…*, *Reset Matter Export Pairings…* | Backup and recovery. The last two are destructive — see [the two destructive recovery actions](#the-two-destructive-recovery-actions) |
Comment thread
coderabbitai[bot] marked this conversation as resolved.

---

## Prerequisites
Expand Down Expand Up @@ -571,9 +588,9 @@ This directory holds the fabric root CA private key and every device's operation
**Losing it means re-commissioning every Matter device from scratch.** Indigo's own
database backup does **not** cover it.

Use **Plugins ▸ Matter ▸ Export fabric backup…**. It writes a timestamped zip into a
Use **Plugins ▸ Matter ▸ Back up the Matter fabric…**. It writes a timestamped zip into a
`backups/` directory beside the storage dir and prunes old ones, and
**Restore fabric backup…** puts one back (moving the current fabric aside first, so a
**Restore a fabric backup…** puts one back (moving the current fabric aside first, so a
bad restore is reversible). Copy the zips somewhere off-machine as well — a backup on
the same disk is not a backup.

Expand Down Expand Up @@ -607,7 +624,7 @@ Losing *that* is the number-one real-world cause of duplicated accessories: ever
ecosystem re-creates every accessory, and their names, rooms and automations go
with the old ones.

**Export fabric backup…** includes this directory in the zip. **Restore does not
**Back up the Matter fabric…** includes this directory in the zip. **Restore does not
yet put it back** — it reports the bridge files it found and skips them, because
restoring them safely needs the bridge node stopped and that wiring is a
follow-up. So for now, if you need to restore the bridge side, copy
Expand Down
4 changes: 2 additions & 2 deletions docs/MATTER.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ leaves the others untouched; only a factory reset wipes them all.
The plugin's fabric lives inside matter-server's storage directory. It is the
single point of total loss — if it's destroyed, every device must be
re-commissioned — which is why the plugin ships fabric **backup and restore**
(menu items: *Export fabric backup…* / *Restore fabric backup…*).
(menu items: *Back up the Matter fabric…* / *Restore a fabric backup…*).

> **Why Apple Home calls our fabric "Matter Test" — this is expected.** When the
> plugin joins a device, Apple Home shows a "joined a new network" notification
Expand Down Expand Up @@ -576,7 +576,7 @@ Common failure modes, in rough order of likelihood:
- **Capability missing (no energy states, no colour, …).** Firmware (see
above), then diagnostics to inspect advertised clusters.

**Backups.** Export a fabric backup after commissioning anything you'd hate to
**Backups.** Back up the fabric after commissioning anything you'd hate to
re-pair. The plugin keeps rotating zips and a restore is menu-driven and
reversible.

Expand Down
6 changes: 3 additions & 3 deletions docs/matter.html
Original file line number Diff line number Diff line change
Expand Up @@ -148,8 +148,8 @@ <h2>Fabrics &amp; multi-admin: one device, many controllers</h2>
others untouched; only a factory reset wipes them all.</p>
<p>The plugin’s fabric lives inside matter-server’s storage directory. It is the single
point of total loss — destroyed, every device must be re-commissioned — which is why the
plugin ships fabric <strong>backup and restore</strong> (menu items: <em>Export fabric
backup…</em> / <em>Restore fabric backup…</em>).</p>
plugin ships fabric <strong>backup and restore</strong> (menu items: <em>Back up the
Matter fabric…</em> / <em>Restore a fabric backup…</em>).</p>
<div class="aside">
<span class="tag">Expected behaviour</span>
<strong>Why Apple Home calls our fabric “Matter Test”.</strong> When the plugin joins a
Expand Down Expand Up @@ -364,7 +364,7 @@ <h2>Troubleshooting</h2>
Persistently dead usually means a factory reset wiped the fabric — re-commission.</li>
<li><strong>Capability missing.</strong> Firmware first (§ 10), then diagnostics.</li>
</ul>
<p><strong>Backups.</strong> Export a fabric backup after commissioning anything you’d hate
<p><strong>Backups.</strong> Back up the fabric after commissioning anything you’d hate
to re-pair. The plugin keeps rotating zips; restore is menu-driven and reversible.</p>
</div>
</section>
Expand Down
2 changes: 1 addition & 1 deletion indigo-matter.indigoPlugin/Contents/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
<key>IwsApiVersion</key>
<string>1.0.0</string>
<key>PluginVersion</key>
<string>2026.8.4</string>
<string>2026.8.5</string>
<key>ServerApiVersion</key>
<string>3.6</string>
</dict>
Expand Down
Loading
Loading