fix(config_flow): per-host zeroconf updates — blank auto-detect hosts self-heal from the discovery address, a deliberately-different ADB host is never clobbered, same-IP with both hosts current is a no-op (F2)
This commit is contained in:
1 parent
b37a14b920
commit
f03ef1f531
2 files changed
+78
-14
No files matched your search
@@ -280,21 +280,25 @@ class NvidiaShieldConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
|||||||
for entry in self._async_current_entries():
|
for entry in self._async_current_entries():
|
||||||
if getattr(entry, "unique_id", None) != mac:
|
if getattr(entry, "unique_id", None) != mac:
|
||||||
continue
|
continue
|
||||||
# Known device — update hosts only on a real IP change
|
# Known device — per-host updates (t21 F2): each host is
|
||||||
# (core androidtv_remote pattern, simplified): an explicitly
|
# tracked independently against the discovery address.
|
||||||
# configured host that moved to the discovery address.
|
# - a blank (auto-detect) host self-heals from the address;
|
||||||
|
# - a stale protocol host is the IP change and is updated;
|
||||||
|
# - a deliberately-different ADB host (an explicit override
|
||||||
|
# that differs from both the address and the stored
|
||||||
|
# protocol host) is never clobbered.
|
||||||
protocol_host = entry.options.get(CONF_PROTOCOL_HOST, "")
|
protocol_host = entry.options.get(CONF_PROTOCOL_HOST, "")
|
||||||
adb_host = entry.options.get(CONF_ADB_HOST, "")
|
adb_host = entry.options.get(CONF_ADB_HOST, "")
|
||||||
if (protocol_host and protocol_host != host) or (
|
options = dict(entry.options)
|
||||||
adb_host and adb_host != host
|
if protocol_host != host:
|
||||||
):
|
options[CONF_PROTOCOL_HOST] = host
|
||||||
|
if not adb_host or adb_host == protocol_host:
|
||||||
|
# blank (self-heal) or auto-synced alongside the protocol
|
||||||
|
# host — safe to follow the device address on discovery
|
||||||
|
options[CONF_ADB_HOST] = host
|
||||||
|
if options != entry.options:
|
||||||
self.hass.config_entries.async_update_entry(
|
self.hass.config_entries.async_update_entry(
|
||||||
entry,
|
entry, options=options
|
||||||
options={
|
|
||||||
**entry.options,
|
|
||||||
CONF_PROTOCOL_HOST: host,
|
|
||||||
CONF_ADB_HOST: host,
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
self.hass.config_entries.async_schedule_reload(entry.entry_id)
|
self.hass.config_entries.async_schedule_reload(entry.entry_id)
|
||||||
return self.async_abort(reason="already_configured")
|
return self.async_abort(reason="already_configured")
|
||||||
|
|||||||
@@ -436,6 +436,34 @@ class TestZeroconfDiscovery:
|
|||||||
hass = FakeHass(str(tmp_path))
|
hass = FakeHass(str(tmp_path))
|
||||||
flow.hass = hass
|
flow.hass = hass
|
||||||
|
|
||||||
|
# both hosts already hold the discovered address: nothing changes
|
||||||
|
entry = SimpleNamespace(
|
||||||
|
unique_id="aa:bb:cc:dd:ee:ff",
|
||||||
|
options={
|
||||||
|
CONF_PROTOCOL_ENABLED: True,
|
||||||
|
CONF_PROTOCOL_HOST: "192.168.1.50",
|
||||||
|
"adb_host": "192.168.1.50",
|
||||||
|
},
|
||||||
|
entry_id="e1",
|
||||||
|
title="Shield",
|
||||||
|
)
|
||||||
|
sys.modules[__name__]._zc_holder.entries[:] = [entry]
|
||||||
|
|
||||||
|
result = await flow.async_step_zeroconf(
|
||||||
|
self._discovery(props={"mac": "aa:bb:cc:dd:ee:ff"})
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result == {"type": "abort", "reason": "already_configured"}
|
||||||
|
assert hass.config_entries.updating_entry_calls == [] # no IP change
|
||||||
|
assert hass.config_entries.reloaded_entry_ids == []
|
||||||
|
|
||||||
|
async def test_blank_adb_host_self_heals_from_the_discovery_address(self, tmp_path):
|
||||||
|
"""F2: a blank (auto-detect) adb host follows a same-IP rediscovery."""
|
||||||
|
module = _form_module()
|
||||||
|
flow = module.NvidiaShieldConfigFlow()
|
||||||
|
hass = FakeHass(str(tmp_path))
|
||||||
|
flow.hass = hass
|
||||||
|
|
||||||
entry = SimpleNamespace(
|
entry = SimpleNamespace(
|
||||||
unique_id="aa:bb:cc:dd:ee:ff",
|
unique_id="aa:bb:cc:dd:ee:ff",
|
||||||
options={CONF_PROTOCOL_ENABLED: True, CONF_PROTOCOL_HOST: "192.168.1.50"},
|
options={CONF_PROTOCOL_ENABLED: True, CONF_PROTOCOL_HOST: "192.168.1.50"},
|
||||||
@@ -449,8 +477,40 @@ class TestZeroconfDiscovery:
|
|||||||
)
|
)
|
||||||
|
|
||||||
assert result == {"type": "abort", "reason": "already_configured"}
|
assert result == {"type": "abort", "reason": "already_configured"}
|
||||||
assert hass.config_entries.updating_entry_calls == [] # no IP change
|
# only the adb host was filled (self-heal), protocol already current:
|
||||||
assert hass.config_entries.reloaded_entry_ids == []
|
update = hass.config_entries.updating_entry_calls[0][1]["options"]
|
||||||
|
assert update["adb_host"] == "192.168.1.50"
|
||||||
|
assert update["protocol_host"] == "192.168.1.50"
|
||||||
|
assert hass.config_entries.reloaded_entry_ids == ["e1"]
|
||||||
|
|
||||||
|
async def test_deliberately_different_adb_host_is_never_clobbered(self, tmp_path):
|
||||||
|
"""F2: an explicit ADB override survives a protocol-host IP change."""
|
||||||
|
module = _form_module()
|
||||||
|
flow = module.NvidiaShieldConfigFlow()
|
||||||
|
hass = FakeHass(str(tmp_path))
|
||||||
|
flow.hass = hass
|
||||||
|
|
||||||
|
entry = SimpleNamespace(
|
||||||
|
unique_id="aa:bb:cc:dd:ee:ff",
|
||||||
|
options={
|
||||||
|
CONF_PROTOCOL_ENABLED: True,
|
||||||
|
CONF_PROTOCOL_HOST: "10.0.0.1", # stale (IP moved)
|
||||||
|
"adb_host": "10.0.0.9", # deliberate ADB override
|
||||||
|
},
|
||||||
|
entry_id="e1",
|
||||||
|
title="Shield",
|
||||||
|
)
|
||||||
|
sys.modules[__name__]._zc_holder.entries[:] = [entry]
|
||||||
|
|
||||||
|
result = await flow.async_step_zeroconf(
|
||||||
|
self._discovery(props={"mac": "aa:bb:cc:dd:ee:ff"})
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result == {"type": "abort", "reason": "already_configured"}
|
||||||
|
update = hass.config_entries.updating_entry_calls[0][1]["options"]
|
||||||
|
assert update["protocol_host"] == "192.168.1.50" # protocol followed
|
||||||
|
assert update["adb_host"] == "10.0.0.9" # override untouched
|
||||||
|
assert hass.config_entries.reloaded_entry_ids == ["e1"]
|
||||||
|
|
||||||
|
|
||||||
class TestAppsMapOptionsEditor:
|
class TestAppsMapOptionsEditor:
|
||||||
|
|||||||
Reference in new issue
Block a user