feat(washer): add model-number-based device-type detection fallback

This commit is contained in:
Marc Billow committed 2026-07-11 12:49:08 -05:00
1 parent 779c2f9881
commit 2852a21c4a
2 files changed
+97 -1

No files matched your search

@@ -4,7 +4,7 @@ from typing import Optional
from ._base import DeviceRegistry
from . import dishwasher, dryer, oven, refrigerator, washer
__all__ = ['DeviceRegistry', '_type_key', 'for_device']
__all__ = ['DeviceRegistry', '_type_key', 'for_device', 'for_device_by_model']
_REGISTRY_BY_KEY: dict[str, DeviceRegistry] = {
@@ -56,3 +56,36 @@ def for_device(one_ui_version: str) -> Optional[DeviceRegistry]:
if key.endswith(f'_{rkey}'):
return reg
return None
# Consumer-model prefix (first two letters of the '_'-delimited token in
# `description` right before any '/board-info' suffix) -> registry key.
# NOT derived from `modelNum` -- washer and dryer share the same 'DA_WM_'
# internal board-family prefix there, and dishwasher's modelNum contains
# the substring 'WW', so a modelNum-only rule misroutes both.
_CONSUMER_PREFIX_TO_KEY: dict[str, str] = {
'WW': 'washer',
'WD': 'washer',
'DV': 'dryer',
'DW': 'dishwasher',
}
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
no swVersionInfo key at all).
Args:
model_num: x.com.samsung.da.modelNum from /information/vs/0.
description: x.com.samsung.da.description from /information/vs/0.
Returns:
DeviceRegistry if the consumer-model code or modelNum resolves to a
known type, None otherwise.
"""
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 ''):
key = 'refrigerator'
return _REGISTRY_BY_KEY.get(key) if key else None
+63
View File
@@ -99,3 +99,66 @@ class TestWasherRegistry:
'/diagnosis/vs/0', '/otninformation/vs/0',
):
assert href in registry.capabilities, f"{href} missing from washer registry"
class TestForDeviceByModel:
"""Fallback device-type detection for hardware without oneUiVersion."""
def test_washer_ww_prefix(self):
from custom_components.localthings.registry.by_type import for_device_by_model
reg = for_device_by_model(
'DA_WM_TP1_21_COMMON|20375141|20010002001811424AA30217008A0000',
'DA_WM_TP1_21_COMMON_WW5000C/DC92-03495A_B048',
)
assert reg is not None
assert reg.name == 'washer'
def test_washer_wd_prefix(self):
from custom_components.localthings.registry.by_type import for_device_by_model
reg = for_device_by_model(
'DA_WM_TP1_21_COMMON|20375141|20010002001811424AA30217008A0000',
'DA_WM_TP1_21_COMMON_WD7000B/DC92-03724A_004D',
)
assert reg is not None
assert reg.name == 'washer'
def test_dryer_not_misdetected_as_washer(self):
"""Dryer shares the DA_WM_ board prefix with washer -- must not
be misrouted despite the shared prefix."""
from custom_components.localthings.registry.by_type import for_device_by_model
reg = for_device_by_model(
'DA_WM_TP2_20_COMMON_DV5000T', 'DA_WM_TP2_20_COMMON_DV5000T',
)
assert reg is not None
assert reg.name == 'dryer'
def test_dishwasher_not_misdetected_as_washer(self):
"""Dishwasher's modelNum contains the substring 'WW' -- must not
be misrouted by a naive substring match."""
from custom_components.localthings.registry.by_type import for_device_by_model
reg = for_device_by_model(
'ADW-WW-RTL-24-AILITE|90000541|400002010019130059C1000500E10000',
'ADW-WW-RTL-24-AILITE_DW9000F/DD91-00002A_0002',
)
assert reg is not None
assert reg.name == 'dishwasher'
def test_refrigerator_via_modelnum_ref_token(self):
"""Refrigerator's description has no consumer-model suffix; falls
back to the '_REF_' token in modelNum."""
from custom_components.localthings.registry.by_type import for_device_by_model
reg = for_device_by_model(
'TP1X_REF_21K|00176141|00000850031813294103010041030000',
'TP1X_REF_21K',
)
assert reg is not None
assert reg.name == 'refrigerator'
def test_unknown_model_returns_none(self):
from custom_components.localthings.registry.by_type import for_device_by_model
reg = for_device_by_model('SOME-UNKNOWN-BOARD', 'SOME-UNKNOWN-BOARD')
assert reg is None
def test_empty_inputs_return_none(self):
from custom_components.localthings.registry.by_type import for_device_by_model
assert for_device_by_model('', '') is None