feat(catalog): say whether a driver needs the internet, and who has to unlock it - #56
Merged
Merged
Conversation
…o unlock it protocol names a transport and answers neither question an owner asks first. 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. The catalog could not tell them apart. Two fields, orthogonal to protocol rather than folded into it. Splitting protocol into http_local/http_online was the obvious move and the wrong one: protocol feeds PROTOCOL_PERMISSIONS, so new values change what a package build grants, and it does not generalise -- MQTT can be a cloud broker too. connectivity: local | cloud where the driver talks while running setup: [...] what a human must obtain first, and from whom Backfilled across all 80 drivers from what the sources do. 77 local, 3 cloud: myuplink, easee_cloud and tibber are the only drivers that hardcode a vendor endpoint. Every other HTTP driver builds its base URL from config, and the Modbus, MQTT and serial drivers name a vendor only as homepage. setup is the second axis, and a driver can be local and still locked until somebody unlocks the interface: nibe_local is enabled in the pump's own installer menu -- no app, no account -- while sonnen and CTEK are enabled in the device's web UI, sma_pv needs an installer, and eight drivers need a bridge in between. 17 have a recorded gate; 63 do not, and absent means unrecorded. The page renders that as "Not recorded", never "Nothing to set up", and only setup: [none] claims a device needs nothing but an address. tests/test_connectivity.py stops connectivity being decorative. A cloud endpoint must be hardcoded -- there is nowhere else for it to come from -- while a LAN address comes from config, so the test reads that asymmetry in both directions and separates exactly the three from the other 77. Neither field reaches the signed artifact: _load_channel copies an explicit allowlist and these are not in it. So no driver version moves, unlike the ders correction in srcfl#53 that srcfl#55 had to version. Signed-off-by: Hugo Karlsson <48095810+HuggeK@users.noreply.github.com> Co-authored-by: HuggeK <48095810+HuggeK@users.noreply.github.com>
HuggeK
marked this pull request as ready for review
July 31, 2026 10:30
This branch was cut before srcfl#48, srcfl#57, srcfl#62 and srcfl#63 landed. Five files conflicted; all five were additions on both sides and keep both: CHANGELOG.md both wrote under the same ### Added heading spec/manifest-v2.md Connectivity/Setup beside main's DER Types, and the numbered validation list renumbered so the upstream_docs rule survives manifests/myuplink.yaml connectivity/setup from here, ders [heatpump] and 1.1.1 from srcfl#63 -- the empty ders this branch was written against no longer exists tools/generate_site.py Reach labels beside the vendor-document labels index.yaml regenerated rather than hand-merged Also records V2.4 in the migration ledger. The branch adds two manifest fields and updated the field table and validation rules, but never recorded the version the way V2.3 did for upstream_docs. The claim that neither field reaches the signed artifact is checked rather than trusted: with all 80 manifests carrying connectivity, stripping both fields back out moves no artifact digest, so no driver needs a version bump. Signed-off-by: HuggeK <48095810+HuggeK@users.noreply.github.com> Co-authored-by: HuggeK <48095810+HuggeK@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
protocolnames a transport, and answers neither question an owner asks first: does this need the internet, and what do I have to get from the manufacturer before it works at all?nibe_localandmyuplinkare bothprotocol: http, and both read a NIBE heat pump. They are opposites — one reads the pump over the LAN, the other reads NIBE's cloud. The catalog could not tell them apart.Why not
http_local/http_onlineThat was the obvious move and the wrong one.
protocolfeedsPROTOCOL_PERMISSIONS, so new values change what permissions a package build grants; it doesn't generalise (MQTT can be a cloud broker); and it doubles the Protocol filter. Orthogonal fields compose on the page instead — "HTTP · Local · Enable on the device screen".The backfill, from what the sources actually do
77 local, 3 cloud.
myuplink,easee_cloudandtibberare the only drivers that hardcode a vendor endpoint. Every other HTTP driver builds its base URL from config, and the 51 Modbus, 8 MQTT and 4 serial drivers name a vendor only ashomepage.setupis the second axis, and the more interesting one — a driver can belocaland still be locked until somebody unlocks the interface:device_screennibe_local— the pump's own installer menu; no app, no accountdevice_uisonnen(JSON API + token),ctek,ctek_v2,ctek_hybrid(ModbusTCPEnable)installersma_pv— "one-time installer step in the WebUI / Sunny Portal"vendor_portalmyuplink,easee_cloud,tibberbridgeheishamon,opendtu,opendtu_mqtt,esphome_dsmr,esphome-dsmr,tesla_vehicle,zuidwijk_p1,goodwe17 have a recorded gate. 63 do not, and absent means unrecorded — the page 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. Same principle asverification_status: report what is known, not what looks complete.It is checkable, not decorative
tests/test_connectivity.pyreads an asymmetry that is hard to fake: a cloud endpoint must be hardcoded, because there is nowhere else for it to come from, while a LAN address arrives from config. So a driver claiminglocalmust build no request against a public hostname, and one claimingcloudmust name the service it needs. On the current catalog it separates exactly the three from the other 77 — verified in both directions. A cloud driver must also record what its vendor demands, so nobody meets the account requirement only after installing.No driver version moves — and why that is not the same call as #53
#55 had to version the
derscorrection from #53 becausedersreaches the published bytes. These two fields do not:ftw_repository._load_channelcopies an explicit allowlist into the artifact metadata (ders,protocol,manufacturer,model_family, and theDRIVERtable), andconnectivity/setupare not in it. So the channel republishes nothing and the release check has nothing to refuse.spec/manifest-v2.mdrecords that, next to the CONTRIBUTING rule it qualifies.If a host should ever see these fields at install time, that is a deliberate follow-up which does cost a version bump per driver.
Where a bridge ends and a device begins
bridgeis a translator that is neither the device nor the vendor's own gateway product: a HeishaMon board, OpenDTU, an ESPHome build, TeslaBleHttpProxy, a serial-to-Ethernet bridge. A gateway the customer buys as part of the system — the Sourceful Zap, a Ferroamp EnergyHub — is the device.esphome_dsmr's own header draws exactly this line againstzap.lua, so the rule is the repository's, not mine.Ferroamp's local MQTT is granted per site on request, which is what
vendor_approvalexists for, but nothing in the repo states it — so it stays unrecorded rather than asserted.Verification
validate_manifest.py: 80 manifests, 0 errorspytest tests/: 614 passed, 60 skipped (was 293 before this branch; +321 new parametrised cases). One pre-existing Windows-only failure intest_blueprint.py, which invokesbashwith a Windows path and fails identically on an untouched treegenerate_site.pyand inspected in the built output: Reach column present, both filter groups rendered (Local only/Needs the internet, and the five gates present), badges and the "To set up" card row in place.devices.yamland the support status regenerate unchanged🤖 Generated with Claude Code