From c588a7c66b375e9a6b93374a5a5d0230bd10f0fd Mon Sep 17 00:00:00 2001 From: James Mackay Date: Sat, 10 Oct 2026 21:29:46 +0100 Subject: [PATCH] docs(readme): record the MAC-less discovery contract (t37 D3, t39) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit t37 made MAC-less zeroconf discovery honour Home Assistant's own `_async_handle_discovery_without_unique_id` contract — the helper is a coroutine and its dedup (abort `already_configured` when ANY entry exists for this domain, abort `already_in_progress` when another flow runs) only happens when it is awaited. That is stricter than the accidental host-equality guard it replaced, so it changes what a user can expect: * with a MAC, discovery still aborts duplicates and updates a moved device's hosts; * without a MAC, a second (or third) Shield must be added MANUALLY — discovery will abort as "already configured". Someone with two Shields would otherwise read that abort as a bug. The README now has a "Discovery (zeroconf)" section under Configuration stating the rule and the manual route, and the drift sweep's docstring carries the same note next to the D3 entry, so the decision is discoverable from wherever you meet it. Verified: 289 passed, 2 skipped; ruff clean. --- README.md | 18 ++++++++++++++++++ tests/ha_api_drift.py | 6 ++++++ 2 files changed, 24 insertions(+) diff --git a/README.md b/README.md index 7a0e9ae..bdd7988 100644 --- a/README.md +++ b/README.md @@ -182,6 +182,24 @@ device page in HA. Requirements: Settings > Developer options > Network debugging enabled on the Shield. +### Discovery (zeroconf) + +Home Assistant can discover a Shield through the `_androidtvremote2._tcp` +service, and the discovered address is pre-filled on the setup form. The dedup +rules are Home Assistant's own, and they differ with what the discovery carries: + +- **with** the device MAC, a duplicate aborts as "already configured", and an + existing entry's hosts are updated when the address changed; +- **without** a MAC, the flow follows HA's stricter + `_async_handle_discovery_without_unique_id` contract: **any** existing entry + for this integration aborts the discovery, and only one discovery flow runs at + a time. + +So a second (or third) Shield that advertises no MAC has to be added **manually** +— Settings > Devices & Services > Add Integration > "NVIDIA Shield" — rather than +by discovery. That is a deliberate, tested contract (t37 D3), not a bug: the +helper the flow calls is a coroutine and its dedup only runs when awaited. + ### Options - **Jellyfin Media Player** — auto-detected or manually selected diff --git a/tests/ha_api_drift.py b/tests/ha_api_drift.py index c163d6b..e958b0a 100644 --- a/tests/ha_api_drift.py +++ b/tests/ha_api_drift.py @@ -47,6 +47,12 @@ interpreter floor Home Assistant itself declares lives here too (``HOMEASSISTANT_PYTHON_FLOOR``), where CI's guard reads it instead of repeating the number. +Behaviour note for users (t37 D3): MAC-less zeroconf discovery now follows Home +Assistant's stricter contract — the awaited +``_async_handle_discovery_without_unique_id`` aborts ``already_configured`` as +soon as ANY entry exists for this domain, so a second Shield that advertises no +MAC is added manually. See README "Discovery (zeroconf)". + Without homeassistant installed the sweep cannot resolve anything: ``scan()`` returns a single ``no-homeassistant`` finding, the counters stay at zero (so the floors fail on purpose) and nothing is ever reported green. The pytest wrapper