Fix ARTIK051_DONGLE_REF freezer type detection and door sensor (issue #77)

RZ32M713EWW/EE (an ARTIK051-dongle standalone freezer) reports no
oneUiVersion and a pipe-delimited modelNum
('ARTIK051_DONGLE_REF|<rest>') -- REF is the last underscore segment
before the pipe, not wrapped in underscores on both sides like the
'..._REF_...' shape for_device_by_model's substring check expected, so
the device fell through to 'unknown' with only common capabilities:
no door sensor, no temperature sensors, nothing fridge-specific.

Replace the substring check with a segment-based one
(_model_num_segments splits the pipe-delimited prefix on '_') that
catches both shapes. Same root cause, same fix, and same device family
independently reported and root-caused in issue #83 (which also covers
two further bugs -- config-flow/coordinator serial collisions on a
second symptom of this firmware, 'Nothing(SVC)' as a literal serial --
not needed here since this reporter has a single unit; left for #83).

Once routed to the refrigerator registry, fridge.py's existing pattern
capabilities pick up /temperature/current/freezer/0 and
/temperature/desired/freezer/0 for free -- they were never the actual
problem, just unreachable under the 'unknown' fallback (which never
tries pattern capabilities at all). The door sensor needed one more
fix: /door/onedoorfreezer/vs/0 reports the vendor-prefixed
x.com.samsung.da.openState, not the bare openState DOOR_GENERIC read,
so the entity existed but stayed permanently unavailable. Check both
field names via rep_fn.
This commit is contained in:
Marc Billow committed 2026-07-27 00:39:33 +00:00
1 parent aff7647460
commit 8194ea9e87
7 files changed
+348 -4

No files matched your search

@@ -87,6 +87,22 @@ _CONSUMER_PREFIX_TO_KEY: dict[str, str] = {
}
def _model_num_segments(model_num: str) -> list[str]:
"""Underscore-delimited segments of modelNum's pipe-prefix.
Most boards wrap a token in underscores on both sides ('..._REF_...'),
which a plain substring check catches fine. But the ARTIK051_DONGLE_REF
family (issues #77, #83) reports modelNum as
'<board>_DONGLE_REF|<rest...>' -- REF is the *last* segment before the
pipe, with no trailing underscore, so '_REF_' never matches and the
device silently fell back to 'unknown'. Splitting on '_' and checking
segment membership catches both shapes without caring which side (if
either) has a delimiter.
"""
prefix = (model_num or '').split('|', 1)[0]
return prefix.split('_')
def for_device_by_model(model_num: str, description: str) -> Optional[DeviceRegistry]:
"""Fallback device-type detection for hardware that never reports
oneUiVersion (confirmed for washers -- their /otninformation/vs/0 has
@@ -102,7 +118,7 @@ def for_device_by_model(model_num: str, description: str) -> Optional[DeviceRegi
"""
token = (description or '').split('/', 1)[0].rsplit('_', 1)[-1]
key = _CONSUMER_PREFIX_TO_KEY.get(token[:2].upper())
if key is None and '_REF_' in (model_num or ''):
if key is None and 'REF' in _model_num_segments(model_num):
key = 'refrigerator'
# Room air conditioners (e.g. ARTIK051_PRAC_20K) report no oneUiVersion and
# a modelNum carrying the '_PRAC_' (Package Room Air Conditioner) token.
@@ -573,15 +573,27 @@ FLEX_ZONE = Capability(
# Generic door pattern capability (href=None — use as pattern_cap only)
# ---------------------------------------------------------------------------
def _door_open_state(rep):
"""Most /door/* resources report bare `openState`, but the
ARTIK051_DONGLE_REF family's /door/onedoorfreezer/vs/0 (issues #77, #83)
reports the vendor-prefixed `x.com.samsung.da.openState` instead. This
capability still binds either way (href_prefix match doesn't care about
field names), but a plain `field=` lookup against the wrong key means
the entity exists and is permanently unavailable -- check both."""
v = rep.get('openState')
if v is None:
v = rep.get('x.com.samsung.da.openState')
return v == 'Open'
DOOR_GENERIC = Capability(
href=None,
href_prefix='/door/',
poll_tier='hot',
entities=(
BinarySensorDesc(key='open', field='openState',
BinarySensorDesc(key='open', rep_fn=_door_open_state,
translation_key='instance_open',
use_instance_name=True, device_class='door',
value_fn=lambda v: v == 'Open'),
use_instance_name=True, device_class='door'),
),
)