Updated matter decoder to show more info, and added a homekit decoder.
This commit is contained in:
1 parent
548f2e701f
commit
27ebf13f6f
8 files changed
+831
-6
No files matched your search
@@ -21,6 +21,25 @@ flow, discovery capabilities, discriminator, passcode). Three artifacts:
|
||||
another URL or a local XML file; passing `matter-qr-decoder.html` uses the
|
||||
embedded `<map>` block as an offline fallback. Reproduces the committed TSV
|
||||
byte-for-byte.
|
||||
- `products.tsv` — 3-column `vendor ID → product ID → name` table, consumed by
|
||||
`matter-decode.sh`'s `get_product_name()`: when the decoded vendor ID (or an
|
||||
equivalent, see `vendor-equivalents.tsv`) is present, the product ID is
|
||||
resolved to a name and printed on the Product ID line. LIFX's rows are keyed
|
||||
under `4870`. Optional — a missing file only drops the product-name lookup.
|
||||
- `vendor-equivalents.tsv` — 2-column `alias vendor ID → canonical vendor ID`
|
||||
table, hand-edited, recording companies that are the same after a
|
||||
merger/acquisition (e.g. Feit `5155` → LIFX `4870`). Used by
|
||||
`matter-decode.sh` so a product resolves under either ID and the vendor name
|
||||
is annotated `(a.k.a. ...)`. `#`-comment lines are ignored. Optional.
|
||||
- `gen-lifx-products.py` — Python 3 stdlib script that regenerates LIFX's rows
|
||||
(vendor `4870`) in `products.tsv`. Default source is LIFX's upstream
|
||||
`products.json` **fetched over the network** (via `curl`, falling back to
|
||||
`urllib`); a positional arg overrides with another URL or a local `.json`
|
||||
file. It **merges** LIFX's rows into `products.tsv` (dropping LIFX's old
|
||||
rows, preserving every other vendor's), so re-running it is safe alongside
|
||||
other vendors' generators. Caveat: `products.json` carries only a `pid` per
|
||||
product (no separate Matter/CHIP product-id field), so the lookup assumes
|
||||
LIFX's Matter product ID equals their `pid`.
|
||||
- `README.md` — user-facing docs; this file documents the internals.
|
||||
|
||||
## Commands
|
||||
@@ -74,6 +93,64 @@ Everything lives in `matter-qr-decoder.html` (~1500 lines). Two regions matter:
|
||||
`parseInt(code, 16)`. It is exposed reactively through the `vendorName` `computed`, so
|
||||
the lookup re-runs when the decoded vendor ID changes.
|
||||
|
||||
### Product name lookup + vendor equivalences (bash only)
|
||||
|
||||
Unlike the vendor-name lookup, the product-name lookup and the vendor-equivalence
|
||||
table live **only in `matter-decode.sh`** — the browser app has neither. This is
|
||||
a deliberate, documented divergence from the usual "keep the two in lockstep"
|
||||
rule, chosen because the product catalog and the equivalence list change more
|
||||
often than the vendor map and are not yet worth embedding in the static HTML.
|
||||
|
||||
`matter-decode.sh` defines two helpers:
|
||||
|
||||
- `equivalent_vendor_ids VENDOR` — resolves VENDOR to its whole equivalence class
|
||||
via `vendor-equivalents.tsv` (2 cols `alias \t canonical`, `#` lines ignored,
|
||||
canonical-form: the canonical id never appears in col 1). It prints the vendor
|
||||
itself plus every alias sharing its canonical id, sorted. A missing
|
||||
`vendor-equivalents.tsv` yields just the vendor.
|
||||
- `get_product_name VENDOR PRODUCT` — checks `products.tsv` (3 cols `vendor \t
|
||||
product \t name`) for the exact vendor first, then every equivalent; first
|
||||
match wins. A missing `products.tsv` yields no name. It must `return 0` on a
|
||||
miss: under `set -e`, a non-zero status in the `pname=$(...)` substitution
|
||||
would abort the script before anything prints.
|
||||
|
||||
In `main()`, the product name (`pname`) is printed on the Product ID line via the
|
||||
same `[[ -n $pname ]] && printf` pattern the vendor name uses. The vendor
|
||||
name is annotated with its equivalents: the *other* class members' names (from
|
||||
`manufacturers.tsv`) are joined and appended as `(a.k.a. X, ...)`, so a Feit
|
||||
(`5155`) device reads `Feit Electric Company, Inc. (a.k.a. Lifi Labs INC. dba
|
||||
LIFX)` and a LIFX (`4870`) device reads the mirror image. Both `products.tsv` and
|
||||
`vendor-equivalents.tsv` are optional; a missing file only drops its extra.
|
||||
|
||||
`gen-lifx-products.py` regenerates LIFX's rows into `products.tsv` by merging
|
||||
(dropping only vendor `4870`'s rows, preserving others). To add another vendor,
|
||||
write a sibling `gen-<vendor>-products.py` that parses that vendor's catalog and
|
||||
merges its rows — keyed under its own vendor ID — into the same `products.tsv`;
|
||||
then add that vendor's equivalences (if any) to `vendor-equivalents.tsv`.
|
||||
Mirroring this into the HTML app is the natural next step if it is wanted.
|
||||
|
||||
### Manual pairing code (bash only)
|
||||
|
||||
`matter-decode.sh` also prints a **Pairing Code:** line: the Matter *manual
|
||||
pairing code* — the PIN a commissioning app (Apple Home, Google Home, the Matter
|
||||
app) asks you to type. It is **not** a raw payload field; it is *derived* from
|
||||
the passcode and discriminator and, for non-standard commissioning flows, the
|
||||
vendor/product IDs, then guarded by a Verhoeff check digit. This is a port of
|
||||
`generateManualPairingCode()` from the standalone "Matter QR Code Tool"
|
||||
(`chill-uk/matter-qr-app`, `web/app.js`); the browser app in this repo has
|
||||
neither this nor the product/equivalence lookups, so like them it is bash-only.
|
||||
|
||||
Two helpers, defined just above `main()`:
|
||||
|
||||
- `verhoeff_check_digit DIGITS` — the Verhoeff check digit over a decimal string
|
||||
(the three standard Verhoeff tables are inlined; digits are processed
|
||||
right-to-left, as the reference does).
|
||||
- `compute_pairing_code VENDOR PRODUCT FLOW DISCRIMINATOR PASSCODE` — assembles
|
||||
the code. The 12-bit discriminator contributes its top 4 bits; the 27-bit
|
||||
passcode is split into its low 14 and high 13 bits; non-standard flows
|
||||
(user-intent `1`, custom `2`) append 5-digit vendor and product groups. Result:
|
||||
11 digits for the standard flow, 21 otherwise, plus the check digit.
|
||||
|
||||
## Gotchas
|
||||
|
||||
- The `BarcodeDetector` scanner polls the camera via `setInterval` every 200ms and
|
||||
@@ -86,8 +163,9 @@ the lookup re-runs when the decoded vendor ID changes.
|
||||
- `matter-decode.sh` is a bash port of the HTML app's decode pipeline, kept in lockstep
|
||||
with it — the base38 charset/chunking, little-endian byte extraction, and the 84-bit
|
||||
LSB-first field layout are identical. When you change the decode logic in the HTML app,
|
||||
mirror it in the script (and vice versa). The script's only extra is a `manufacturers.tsv`
|
||||
lookup for the vendor name; without that file it still decodes everything else.
|
||||
mirror it in the script (and vice versa). The script's extras are the optional `manufacturers.tsv` (vendor name),
|
||||
`products.tsv` (product name), and `vendor-equivalents.tsv` (vendor
|
||||
equivalences); without any of them it still decodes everything else.
|
||||
- `manufacturers.tsv` is regenerated with `gen-manufacturers.py` (Python 3
|
||||
stdlib). Default source is the **upstream `manufacturers.xml` fetched over the
|
||||
network** (via `curl`; a GitHub `blob/` URL is auto-rewritten to its
|
||||
@@ -99,3 +177,12 @@ the lookup re-runs when the decoded vendor ID changes.
|
||||
`<script type="text/xml">` block in the HTML app has the same upstream
|
||||
provenance and a "do not edit manually" note, so refreshing the TSV from new
|
||||
upstream XML leaves the HTML copy stale. Refresh both from the same source.
|
||||
- The product-name lookup and vendor equivalences are **bash-only** —
|
||||
`matter-decode.sh` has them, the browser app does not, so this is one place the
|
||||
two are *not* in lockstep (deliberate, for now). `products.tsv` and
|
||||
`vendor-equivalents.tsv` are optional and degrade silently (a missing file means
|
||||
no name / no equivalent, never an error). `vendor-equivalents.tsv` is
|
||||
canonical-form, one hop: the canonical id must not itself appear in col 1.
|
||||
`get_product_name` must `return 0` on a miss or `set -e` aborts the decode.
|
||||
Mirror these into the HTML app (a second embedded map plus a `productName` /
|
||||
`equivalentVendorName` computed) only if that is wanted.
|
||||
Reference in new issue
Block a user