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
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ Driver versions follow [Semantic Versioning](https://semver.org/spec/v2.0.0.html
## [Unreleased]

### Added
- **Every manifest now states where its driver talks, and what a manufacturer demands before it will talk at all** — `connectivity: local | cloud` plus an optional `setup:` list. `protocol` answered neither question: `nibe_local` and `myuplink` are both `protocol: http` and both read a NIBE heat pump, and they are opposites — one reads the pump over the LAN, the other reads NIBE's cloud. Backfilled across all 80 drivers from what the sources do: **77 local, 3 cloud** (`myuplink`, `easee_cloud`, `tibber`, the only drivers that hardcode a vendor endpoint — every other HTTP driver builds its base URL from config, and all 51 Modbus, 8 MQTT and 4 serial drivers name a vendor only as `homepage`)
- `setup` is the second axis and the more interesting one, because a driver can be `local` and still locked until somebody unlocks the interface. `device_screen` (nibe_local, enabled in the pump's own installer menu — no app, no account, confirmed on an S735), `device_ui` (sonnen's JSON API and token, CTEK's `ModbusTCPEnable`), `installer` (sma_pv's "one-time installer step in the WebUI / Sunny Portal"), `vendor_portal` (the three cloud drivers), `bridge` (heishamon, opendtu ×2, esphome_dsmr ×2, tesla_vehicle's TeslaBleHttpProxy, zuidwijk_p1, and goodwe's required dongle). 17 drivers carry a recorded gate; 63 do not
- **An absent `setup` means unrecorded, and the page says exactly that.** It renders "Not recorded", never "Nothing to set up", and a driver with none drops out of the setup filter rather than passing as though it needed nothing. Only `setup: [none]` is a claim, and nothing claims it yet. The same reason `verification_status` is never flattened into a "verified" tick: the catalog reports what is known, not what would look complete
- `tests/test_connectivity.py` keeps `connectivity` checkable rather than decorative. A cloud endpoint has to be hardcoded — there is nowhere else for it to come from — while a LAN address arrives from config, so the test reads that asymmetry: a driver claiming `local` must build no request against a public hostname, and one claiming `cloud` must name the service it needs. On the current catalog it separates exactly the three cloud drivers from the other 77. It also requires a cloud driver to record what its vendor demands, so nobody meets the account requirement only after installing
- The catalog page gains a **Reach** column and two filter groups, putting "works without the internet" and "needs a bridge device" one click away. Neither field reaches the signed artifact — `_load_channel` copies an explicit allowlist and these are not in it — so unlike `ders`, correcting one costs no driver version
- **`upstream_docs`** — an optional manifest field (`url`, `title`, `kind`, `url_stability`) naming the vendor documents a driver was built against — a register map, a parameter changelog — at a semi-persistent URL. A driver decodes a device by following that document; when it moves upstream, the driver can fall behind and nobody notices for months. Recording the URL lets a watcher poll it and flag the driver for review. `url_stability` (`committed`/`stable`/`volatile`/`unknown`) records whether the manufacturer keeps the URL put, so a broken `stable` link reads as a real signal and a broken `volatile` one as routine. `nibe_local` and `myuplink` are the first to declare it, both pointing at NIBE's myUplink register changelog. `tools/validate_manifest.py` holds each entry to an `http(s)` URL and known `kind`/`url_stability` values; the field is descriptive metadata only and never reaches `index.yaml` or how a driver installs. Specified in `spec/manifest-v2.md` (V2.3), and `docs/WRITING-A-DRIVER.md` and `AGENTS.md` now tell a driver author to record it beside the older instruction to write down what they learned about the registers — where the knowledge came from is the half that was never asked for, and a field nobody is told to populate stays at two manifests out of 80. Both say what it cannot do: a document behind a login is not fetchable and belongs in a driver comment instead. Tested in `tests/test_upstream_docs.py`
- **`watch-upstream-docs`** — the automation half of `upstream_docs`. `tools/check_upstream_docs.py` fetches every watched URL, hashes it, and diffs it against a committed baseline (`upstream-docs-state.json`); the weekly `.github/workflows/watch-upstream-docs.yml` opens a tracking issue when a document changes (registers to review) or goes missing (link rotted), weighted by `url_stability`. It notifies **once** per event — a change updates the baseline so it can't re-fire, an outage alerts only on crossing a three-run failure threshold, and the workflow skips a title that already has an open issue. Detection is a raw-byte hash, so a flagged change is a prompt to look, not proof the registers moved — the issue says so. Tested in `tests/test_upstream_docs_watch.py`
- **The catalog page shows the vendor documents a driver was decoded from.** `upstream_docs` reached the manifests and the weekly watcher but never the page, so the one artefact most readers actually open still named 80 drivers without saying where any of them came from — and the field's whole purpose is to make that source findable again. Each declared document is now a link in the driver's card, under its title, with the kind (`Changelog`, `Register map`, …) and what `url_stability` claims. The stability wording is spelled out rather than printed as the bare enum: "stable" beside a link reads as a promise that the *registers* are settled, which is the opposite of why the field exists, so the page says "URL stable in practice". A short note explains that a flagged change is a prompt to review, not evidence the driver is wrong. Document titles join the search index, so the changelog a driver follows is findable by name. The generator re-checks the `http(s)` scheme it renders — `validate_manifest.py` holds the same line, but it is a different tool run at a different time, and this is the one place where the value becomes an `href` somebody clicks. `test_the_card_renders_the_documents_it_collects` guards the rendering rather than the payload, because collecting the documents and silently dropping them from the card is exactly the state that made this necessary
Expand Down
Loading