Merge pull request #99 from mbillow/claude/device-support-issue-83-fridge-detection

Catch the 'Nothing(SVC)' placeholder serial in both fallback sites (i…
This commit is contained in:
Marc Billow authored and GitHub committed 2026-07-26 21:55:33 -05:00
commit d0e03b026c
4 files changed
+69 -2

No files matched your search

+13 -1
View File
@@ -197,6 +197,18 @@ def _find_live_ports(host: str, ports: list[int], timeout: float) -> list[int]:
return _order_candidates(live)
def _is_placeholder_serial(serial: str) -> bool:
"""True for a non-empty serialNum that isn't actually a real identity.
The ARTIK051_DONGLE_REF firmware family reports the literal string
'Nothing(SVC)' for every unit -- non-empty, so the plain `if not
serial` check here (and the equivalent one in coordinator.py's
`_run_discovery`) doesn't catch it, and two such units get the same
config-entry unique_id / entity unique_ids and collide (issue #83).
"""
return serial.strip().lower().startswith('nothing')
def _probe_and_validate(host: str, ca_cert_pem: str, ca_key_pem: str) -> dict:
"""Fetch UUID, mint leaf cert, probe each port. Returns config entry data dict."""
import cbor2
@@ -261,7 +273,7 @@ def _probe_and_validate(host: str, ca_cert_pem: str, ca_key_pem: str) -> dict:
.get('/information/vs/0', {})
.get('x.com.samsung.da.serialNum', '')
)
if not serial:
if not serial or _is_placeholder_serial(serial):
serial = f"{host}:{port}"
one_ui_version = (
resources
+17 -1
View File
@@ -53,6 +53,22 @@ class _NoOpDescriptor:
_RECOVERY_RETRY_S = 600.0 # re-attempt observe mode this often while polling
def _is_placeholder_serial(serial: str) -> bool:
"""True for a non-empty serialNum that isn't actually a real identity.
The ARTIK051_DONGLE_REF firmware family reports the literal string
'Nothing(SVC)' for every unit -- non-empty, so the plain `if not
serial` check below doesn't catch it, and `device_serial` feeds both
the HA device-registry identifier and every entity's unique_id
(entity.py), so two such units on the same install silently collide
and the second one's entities get dropped (issue #83). Mirrors the
identical helper in config_flow.py's `_probe_and_validate` -- kept
separate rather than imported to avoid pulling the config-flow module
into the runtime coordinator's import graph for a two-line check.
"""
return serial.strip().lower().startswith('nothing')
class LocalThingsCoordinator(DataUpdateCoordinator[dict[str, Any]]):
"""Manages one Samsung appliance: session, discovery, polling."""
@@ -316,7 +332,7 @@ class LocalThingsCoordinator(DataUpdateCoordinator[dict[str, Any]]):
self._unbound_hrefs = unbound
serial = info.get('x.com.samsung.da.serialNum', '')
if not serial:
if not serial or _is_placeholder_serial(serial):
serial = self._entry.data[CONF_HOST]
self.device_serial = serial