From e44fef7085ee43888993e7a5e8f7163132c69b7e Mon Sep 17 00:00:00 2001 From: Marc Billow Date: Mon, 27 Jul 2026 13:41:36 +0000 Subject: [PATCH] Route combi microwaves onto the existing oven registry (issue #121) TP1X_DA-KS-MICROWAVE-01041 (MW7300B) reports no oneUiVersion and an unrecognized consumer token, so it fell back to 'unknown' and only got common capabilities. It shares the same '/oven/vs/0' cavity resource and '/mode/vs/0' cook-mode shape (Convection/AirFryer/Grill/MicroWave*) as the wall oven already supported, so this reuses that registry via a new '-MICROWAVE-' modelNum fallback rather than adding a new device type. The only href it didn't already cover was /recipe/cook/vs/0, an empty quick-recipe-display blob bound with no entity per the 'don't guess' rule. --- .../localthings/registry/by_type/__init__.py | 9 + .../localthings/registry/by_type/oven.py | 1 + .../localthings/registry/capabilities/oven.py | 6 + tests/fixtures/golden/oven_mw7300b.json | 25 ++ tests/fixtures/oven_mw7300b_device.json | 278 ++++++++++++++++++ tests/test_by_type.py | 14 + tests/test_golden_regression.py | 20 ++ 7 files changed, 353 insertions(+) create mode 100644 tests/fixtures/golden/oven_mw7300b.json create mode 100644 tests/fixtures/oven_mw7300b_device.json diff --git a/custom_components/localthings/registry/by_type/__init__.py b/custom_components/localthings/registry/by_type/__init__.py index 8590dd7..9039566 100644 --- a/custom_components/localthings/registry/by_type/__init__.py +++ b/custom_components/localthings/registry/by_type/__init__.py @@ -231,6 +231,15 @@ def for_device_by_model(model_num: str, description: str) -> Optional[DeviceRegi # oneUiVersion and doesn't match the washer/dryer/dishwasher prefix map. if key is None and '-OVEN-' in (model_num or '').upper(): key = 'oven' + # Combi microwaves (e.g. TP1X_DA-KS-MICROWAVE-01041, issue #121) -- same + # board family as the wall oven above (an '/oven/vs/0' cavity resource + # with Convection/AirFryer/Grill/MicroWave modes on /mode/vs/0), just a + # different cavity. Reports no oneUiVersion and doesn't match the + # washer/dryer/dishwasher prefix map either. Binds cleanly against the + # existing oven registry once routed here (confirmed against the issue + # #121 dump) -- no microwave-specific device type needed. + if key is None and '-MICROWAVE-' in (model_num or '').upper(): + key = 'oven' # Standalone induction cooktops (e.g. TP1X_DA-KS-COOKTOP-01011, issue # #86) -- same board family and '/cooktop/status/vs/0' resource shape # as the range combo above, but no oven attached at all. Distinct from diff --git a/custom_components/localthings/registry/by_type/oven.py b/custom_components/localthings/registry/by_type/oven.py index c4028ce..252f1dc 100644 --- a/custom_components/localthings/registry/by_type/oven.py +++ b/custom_components/localthings/registry/by_type/oven.py @@ -15,5 +15,6 @@ REGISTRY = DeviceRegistry( oven.OVEN_DOOR, oven.OVEN_CONNECTED, oven.OVEN_SPEC, + oven.OVEN_RECIPE_COOK, ]), ) diff --git a/custom_components/localthings/registry/capabilities/oven.py b/custom_components/localthings/registry/capabilities/oven.py index c679fac..4b47a38 100644 --- a/custom_components/localthings/registry/capabilities/oven.py +++ b/custom_components/localthings/registry/capabilities/oven.py @@ -338,6 +338,12 @@ OVEN_CONNECTED = Capability( # fields worth exposing. OVEN_SPEC = Capability(href='/oven/spec/vs/0') +# Quick-recipe display blob (combi microwave, issue #121) -- a JSON-encoded +# string (language/menu/servingSize/option) with every field blank on the +# only dump seen, and no documented write contract. No entity to bind per +# the 'don't guess' rule; a bare Capability still marks the href covered. +OVEN_RECIPE_COOK = Capability(href='/recipe/cook/vs/0') + OVEN_MODE = Capability( href='/mode/vs/0', poll_tier='warm', diff --git a/tests/fixtures/golden/oven_mw7300b.json b/tests/fixtures/golden/oven_mw7300b.json new file mode 100644 index 0000000..435dec4 --- /dev/null +++ b/tests/fixtures/golden/oven_mw7300b.json @@ -0,0 +1,25 @@ +{ + "state_keys": [ + "alarm_code", + "child_lock", + "cloud_connected", + "cook_time", + "current_temp_c", + "cycle_active", + "door_open", + "energy_kwh", + "fast_preheat", + "finish_time", + "firmware_update", + "lamp", + "machine_state", + "natural_steam", + "operation_time_minutes", + "oven_mode", + "oven_setpoint", + "oven_state", + "progress_percentage", + "remote_control", + "sound" + ] +} \ No newline at end of file diff --git a/tests/fixtures/oven_mw7300b_device.json b/tests/fixtures/oven_mw7300b_device.json new file mode 100644 index 0000000..f5a4ded --- /dev/null +++ b/tests/fixtures/oven_mw7300b_device.json @@ -0,0 +1,278 @@ +{ + "device0": [ + { + "rt": [ + "x.com.samsung.devcol", + "oic.wk.col" + ], + "if": [ + "oic.if.baseline", + "oic.if.ll", + "oic.if.b" + ] + }, + { + "href": "/otninformation/vs/0", + "rep": { + "x.com.samsung.da.target": "", + "x.com.samsung.da.newVersionAvailable": "false", + "flashingProgress": "", + "otnStatus": "None", + "otnList": [ + { + "type": "WIFI", + "modelId": "AKS-WW-TP1-22-OVEN-2", + "versions": [ + "40241114" + ], + "visVersion": "241114" + }, + { + "type": "Micom", + "modelId": "074340475341FFFFFFFF", + "versions": [ + "23121600", + "FFFFFFFF" + ], + "visVersion": "231216" + }, + { + "type": "Micom", + "modelId": "074340460841FFFFFFFF", + "versions": [ + "22051300", + "FFFFFFFF" + ], + "visVersion": "220513" + } + ] + } + }, + { + "href": "/connected/vs/0", + "rep": { + "x.com.samsung.da.connected": "On" + } + }, + { + "href": "/doors/vs/0", + "rep": { + "x.com.samsung.da.items": [ + { + "x.com.samsung.da.id": "0", + "x.com.samsung.da.description": "Door", + "x.com.samsung.da.openState": "Close" + } + ], + "rt": [ + "x.com.samsung.da.doors" + ], + "if": [ + "oic.if.baseline", + "oic.if.s" + ] + } + }, + { + "href": "/information/vs/0", + "rep": { + "x.com.samsung.da.modelNum": "TP1X_DA-KS-MICROWAVE-01041|40475341|50040100021811000A00000000000000", + "x.com.samsung.da.description": "MW7300B-/EU1", + "x.com.samsung.da.serialNum": "**REDACTED**", + "x.com.samsung.da.otnDUID": "**REDACTED**", + "x.com.samsung.da.items": [ + { + "x.com.samsung.da.id": "0", + "x.com.samsung.da.description": "Version", + "x.com.samsung.da.type": "Software", + "x.com.samsung.da.number": "24111400", + "x.com.samsung.da.newVersionAvailable": "0" + }, + { + "x.com.samsung.da.id": "1", + "x.com.samsung.da.description": "Version", + "x.com.samsung.da.type": "Firmware", + "x.com.samsung.da.number": "04753A23121600", + "x.com.samsung.da.newVersionAvailable": "0" + }, + { + "x.com.samsung.da.id": "2", + "x.com.samsung.da.description": "Version", + "x.com.samsung.da.type": "Firmware", + "x.com.samsung.da.number": "04608A22051300", + "x.com.samsung.da.newVersionAvailable": "0" + } + ], + "x.com.samsung.da.diagProtocolType": "BLE_OCF", + "x.com.samsung.da.diagLogType": [ + "errCode", + "dump" + ], + "x.com.samsung.da.diagDumpType": "file", + "x.com.samsung.da.diagEndPoint": "SSM", + "x.com.samsung.da.diagMnid": "0AJT", + "x.com.samsung.da.diagSetupid": "KM6", + "x.com.samsung.da.diagMinVersion": "3.0", + "x.com.samsung.da.diagTsId": "DA01" + } + }, + { + "href": "/mode/vs/0", + "rep": { + "x.com.samsung.da.supportedModes": [ + "NoOperation", + "Autocook", + "AutocookCustom", + "Convection", + "AirFryer", + "Grill", + "MicroWave", + "MicroWaveGrill", + "MicroWaveConvection", + "Deodorization" + ], + "x.com.samsung.da.modes": [ + "NoOperation" + ], + "x.com.samsung.da.options": [ + "DeviceType_MW7300B-/EU1", + "TimeAutoSync_On", + "TimeSystem_24", + "Sound_Off" + ], + "x.com.samsung.da.defaultMode": "Convection", + "x.com.samsung.da.modeSpec": "[{\"mode\":\"NoOperation\",\"version\":\"0101\",\"default\":\"Normal\",\"control\":\"NotSupported\",\"cavity\":\"Single\",\"tempMinC\":\"NotSupported\",\"tempMaxC\":\"NotSupported\",\"tempDefaultC\":\"NotSupported\",\"tempListLengthC\":\"0\",\"tempMinF\":\"NotSupported\",\"tempMaxF\":\"NotSupported\",\"tempDefaultF\":\"NotSupported\",\"tempListLengthF\":\"0\",\"timeMin\":\"NotSupported\",\"timeMax\":\"NotSupported\",\"timeDefault\":\"NotSupported\",\"probeMinC\":\"NotSupported\",\"probeMaxC\":\"NotSupported\",\"probeDefaultC\":\"NotSupported\",\"probeMinF\":\"NotSupported\",\"probeMaxF\":\"NotSupported\",\"probeDefaultF\":\"NotSupported\",\"powerDefault\":\"NotSupported\",\"powerListLength\":\"0\",\"tempIntervalC\":\"NotSupported\",\"tempIntervalF\":\"NotSupported\",\"probeIntervalC\":\"NotSupported\",\"probeIntervalF\":\"NotSupported\"},{\"mode\":\"Autocook\",\"version\":\"0101\",\"default\":\"Normal\",\"control\":\"NotSupported\",\"cavity\":\"Single\",\"tempMinC\":\"NotSupported\",\"tempMaxC\":\"NotSupported\",\"tempDefaultC\":\"NotSupported\",\"tempListLengthC\":\"0\",\"tempMinF\":\"NotSupported\",\"tempMaxF\":\"NotSupported\",\"tempDefaultF\":\"NotSupported\",\"tempListLengthF\":\"0\",\"timeMin\":\"NotSupported\",\"timeMax\":\"NotSupported\",\"timeDefault\":\"NotSupported\",\"probeMinC\":\"NotSupported\",\"probeMaxC\":\"NotSupported\",\"probeDefaultC\":\"NotSupported\",\"probeMinF\":\"NotSupported\",\"probeMaxF\":\"NotSupported\",\"probeDefaultF\":\"NotSupported\",\"powerDefault\":\"NotSupported\",\"powerListLength\":\"0\",\"tempIntervalC\":\"NotSupported\",\"tempIntervalF\":\"NotSupported\",\"probeIntervalC\":\"NotSupported\",\"probeIntervalF\":\"NotSupported\"},{\"mode\":\"AutocookCustom\",\"version\":\"0101\",\"default\":\"Normal\",\"control\":\"NotSupported\",\"cavity\":\"Single\",\"tempMinC\":\"NotSupported\",\"tempMaxC\":\"NotSupported\",\"tempDefaultC\":\"NotSupported\",\"tempListLengthC\":\"0\",\"tempMinF\":\"NotSupported\",\"tempMaxF\":\"NotSupported\",\"tempDefaultF\":\"NotSupported\",\"tempListLengthF\":\"0\",\"timeMin\":\"NotSupported\",\"timeMax\":\"NotSupported\",\"timeDefault\":\"NotSupported\",\"probeMinC\":\"NotSupported\",\"probeMaxC\":\"NotSupported\",\"probeDefaultC\":\"NotSupported\",\"probeMinF\":\"NotSupported\",\"probeMaxF\":\"NotSupported\",\"probeDefaultF\":\"NotSupported\",\"powerDefault\":\"NotSupported\",\"powerListLength\":\"0\",\"tempIntervalC\":\"NotSupported\",\"tempIntervalF\":\"NotSupported\",\"probeIntervalC\":\"NotSupported\",\"probeIntervalF\":\"NotSupported\"},{\"mode\":\"Convection\",\"version\":\"0101\",\"default\":\"Default\",\"control\":\"Start&Setting\",\"cavity\":\"Single\",\"tempMinC\":\"40\",\"tempMaxC\":\"200\",\"tempDefaultC\":\"180\",\"tempListLengthC\":\"0\",\"tempMinF\":\"NotSupported\",\"tempMaxF\":\"NotSupported\",\"tempDefaultF\":\"NotSupported\",\"tempListLengthF\":\"0\",\"timeMin\":\"00:00:10\",\"timeMax\":\"01:00:00\",\"timeDefault\":\"01:00:00\",\"probeMinC\":\"NotSupported\",\"probeMaxC\":\"NotSupported\",\"probeDefaultC\":\"NotSupported\",\"probeMinF\":\"NotSupported\",\"probeMaxF\":\"NotSupported\",\"probeDefaultF\":\"NotSupported\",\"powerDefault\":\"NotSupported\",\"powerListLength\":\"0\",\"tempIntervalC\":\"5\",\"tempIntervalF\":\"NotSupported\",\"probeIntervalC\":\"NotSupported\",\"probeIntervalF\":\"NotSupported\"},{\"mode\":\"AirFryer\",\"version\":\"0101\",\"default\":\"Normal\",\"control\":\"Start&Setting\",\"cavity\":\"Single\",\"tempMinC\":\"100\",\"tempMaxC\":\"200\",\"tempDefaultC\":\"180\",\"tempListLengthC\":\"0\",\"tempMinF\":\"NotSupported\",\"tempMaxF\":\"NotSupported\",\"tempDefaultF\":\"NotSupported\",\"tempListLengthF\":\"0\",\"timeMin\":\"00:00:10\",\"timeMax\":\"01:00:00\",\"timeDefault\":\"01:00:00\",\"probeMinC\":\"NotSupported\",\"probeMaxC\":\"NotSupported\",\"probeDefaultC\":\"NotSupported\",\"probeMinF\":\"NotSupported\",\"probeMaxF\":\"NotSupported\",\"probeDefaultF\":\"NotSupported\",\"powerDefault\":\"NotSupported\",\"powerListLength\":\"0\",\"tempIntervalC\":\"5\",\"tempIntervalF\":\"NotSupported\",\"probeIntervalC\":\"NotSupported\",\"probeIntervalF\":\"NotSupported\"},{\"mode\":\"Grill\",\"version\":\"0101\",\"default\":\"Normal\",\"control\":\"Start&Setting\",\"cavity\":\"Single\",\"tempMinC\":\"NotSupported\",\"tempMaxC\":\"NotSupported\",\"tempDefaultC\":\"NotSupported\",\"tempListLengthC\":\"0\",\"tempMinF\":\"NotSupported\",\"tempMaxF\":\"NotSupported\",\"tempDefaultF\":\"NotSupported\",\"tempListLengthF\":\"0\",\"timeMin\":\"00:00:10\",\"timeMax\":\"01:00:00\",\"timeDefault\":\"00:01:00\",\"probeMinC\":\"NotSupported\",\"probeMaxC\":\"NotSupported\",\"probeDefaultC\":\"NotSupported\",\"probeMinF\":\"NotSupported\",\"probeMaxF\":\"NotSupported\",\"probeDefaultF\":\"NotSupported\",\"powerDefault\":\"NotSupported\",\"powerListLength\":\"0\",\"tempIntervalC\":\"NotSupported\",\"tempIntervalF\":\"NotSupported\",\"probeIntervalC\":\"NotSupported\",\"probeIntervalF\":\"NotSupported\"},{\"mode\":\"MicroWave\",\"version\":\"0101\",\"default\":\"Normal\",\"control\":\"Setting\",\"cavity\":\"Single\",\"tempMinC\":\"NotSupported\",\"tempMaxC\":\"NotSupported\",\"tempDefaultC\":\"NotSupported\",\"tempListLengthC\":\"0\",\"tempMinF\":\"NotSupported\",\"tempMaxF\":\"NotSupported\",\"tempDefaultF\":\"NotSupported\",\"tempListLengthF\":\"0\",\"timeMin\":\"00:00:10\",\"timeMax\":\"01:39:00\",\"timeDefault\":\"00:00:30\",\"probeMinC\":\"NotSupported\",\"probeMaxC\":\"NotSupported\",\"probeDefaultC\":\"NotSupported\",\"probeMinF\":\"NotSupported\",\"probeMaxF\":\"NotSupported\",\"probeDefaultF\":\"NotSupported\",\"powerDefault\":\"900W\",\"powerListLength\":\"7\",\"powerListData\":[\"100W\",\"180W\",\"300W\",\"450W\",\"600W\",\"700W\",\"900W\"],\"tempIntervalC\":\"NotSupported\",\"tempIntervalF\":\"NotSupported\",\"probeIntervalC\":\"NotSupported\",\"probeIntervalF\":\"NotSupported\"},{\"mode\":\"MicroWaveGrill\",\"version\":\"0101\",\"default\":\"Normal\",\"control\":\"Setting\",\"cavity\":\"Single\",\"tempMinC\":\"NotSupported\",\"tempMaxC\":\"NotSupported\",\"tempDefaultC\":\"NotSupported\",\"tempListLengthC\":\"0\",\"tempMinF\":\"NotSupported\",\"tempMaxF\":\"NotSupported\",\"tempDefaultF\":\"NotSupported\",\"tempListLengthF\":\"0\",\"timeMin\":\"00:00:10\",\"timeMax\":\"01:00:00\",\"timeDefault\":\"00:00:30\",\"probeMinC\":\"NotSupported\",\"probeMaxC\":\"NotSupported\",\"probeDefaultC\":\"NotSupported\",\"probeMinF\":\"NotSupported\",\"probeMaxF\":\"NotSupported\",\"probeDefaultF\":\"NotSupported\",\"powerDefault\":\"600W\",\"powerListLength\":\"5\",\"powerListData\":[\"100W\",\"180W\",\"300W\",\"450W\",\"600W\"],\"tempIntervalC\":\"NotSupported\",\"tempIntervalF\":\"NotSupported\",\"probeIntervalC\":\"NotSupported\",\"probeIntervalF\":\"NotSupported\"},{\"mode\":\"MicroWaveConvection\",\"version\":\"0101\",\"default\":\"Normal\",\"control\":\"Setting\",\"cavity\":\"Single\",\"tempMinC\":\"40\",\"tempMaxC\":\"200\",\"tempDefaultC\":\"180\",\"tempListLengthC\":\"0\",\"tempMinF\":\"NotSupported\",\"tempMaxF\":\"NotSupported\",\"tempDefaultF\":\"NotSupported\",\"tempListLengthF\":\"0\",\"timeMin\":\"00:00:10\",\"timeMax\":\"01:00:00\",\"timeDefault\":\"00:00:30\",\"probeMinC\":\"NotSupported\",\"probeMaxC\":\"NotSupported\",\"probeDefaultC\":\"NotSupported\",\"probeMinF\":\"NotSupported\",\"probeMaxF\":\"NotSupported\",\"probeDefaultF\":\"NotSupported\",\"powerDefault\":\"600W\",\"powerListLength\":\"5\",\"powerListData\":[\"100W\",\"180W\",\"300W\",\"450W\",\"600W\"],\"tempIntervalC\":\"5\",\"tempIntervalF\":\"NotSupported\",\"probeIntervalC\":\"NotSupported\",\"probeIntervalF\":\"NotSupported\"},{\"mode\":\"Deodorization\",\"version\":\"0101\",\"default\":\"Normal\",\"control\":\"Start&Setting\",\"cavity\":\"Single\",\"tempMinC\":\"NotSupported\",\"tempMaxC\":\"NotSupported\",\"tempDefaultC\":\"NotSupported\",\"tempListLengthC\":\"0\",\"tempMinF\":\"NotSupported\",\"tempMaxF\":\"NotSupported\",\"tempDefaultF\":\"NotSupported\",\"tempListLengthF\":\"0\",\"timeMin\":\"00:00:10\",\"timeMax\":\"00:15:00\",\"timeDefault\":\"00:05:00\",\"probeMinC\":\"NotSupported\",\"probeMaxC\":\"NotSupported\",\"probeDefaultC\":\"NotSupported\",\"probeMinF\":\"NotSupported\",\"probeMaxF\":\"NotSupported\",\"probeDefaultF\":\"NotSupported\",\"powerDefault\":\"NotSupported\",\"powerListLength\":\"0\",\"tempIntervalC\":\"NotSupported\",\"tempIntervalF\":\"NotSupported\",\"probeIntervalC\":\"NotSupported\",\"probeIntervalF\":\"NotSupported\"}]" + } + }, + { + "href": "/operational/state/vs/0", + "rep": { + "x.com.samsung.da.state": "Ready", + "causeSource.state": "SETB_Ready", + "x.com.samsung.da.operationTime": "00:00:00", + "x.com.samsung.da.remainingTime": "00:00:00", + "x.com.samsung.da.progressPercentage": "0", + "rt": [ + "x.com.samsung.da.operation" + ], + "if": [ + "oic.if.baseline", + "oic.if.a" + ] + } + }, + { + "href": "/alarms/vs/0", + "rep": { + "rt": [ + "x.com.samsung.da.alarms" + ], + "if": [ + "oic.if.baseline", + "oic.if.s" + ], + "x.com.samsung.da.items": [ + { + "x.com.samsung.da.id": "0", + "x.com.samsung.da.description": "Alarm", + "x.com.samsung.da.alarmType": "Device", + "x.com.samsung.da.code": "OV_E_OFF", + "x.com.samsung.da.triggeredTime": "2026-07-27T08:26:55" + } + ] + } + }, + { + "href": "/oven/vs/0", + "rep": { + "x.com.samsung.da.state": "Ready", + "x.com.samsung.da.recipe": "00000000000000", + "x.com.samsung.da.powerLevel": "0W", + "rt": [ + "x.com.samsung.da.oven" + ], + "if": [ + "oic.if.baseline", + "oic.if.s" + ] + } + }, + { + "href": "/temperatures/vs/0", + "rep": { + "x.com.samsung.da.items": [ + { + "x.com.samsung.da.id": "0", + "x.com.samsung.da.description": "Temperature", + "x.com.samsung.da.desired": "0", + "x.com.samsung.da.current": "1", + "x.com.samsung.da.increment": "5", + "x.com.samsung.da.unit": "Celsius" + } + ], + "rt": [ + "x.com.samsung.da.temperatures" + ], + "if": [ + "oic.if.baseline", + "oic.if.a" + ] + } + }, + { + "href": "/timezone/vs/0", + "rep": { + "timezoneid": "Europe/London", + "offset": "+01:00", + "DST": "ON" + } + }, + { + "href": "/energy/consumption/vs/0", + "rep": { + "x.com.samsung.da.instantaneousPower": "-500", + "x.com.samsung.da.instantaneousPowerUnit": "W", + "x.com.samsung.da.cumulativePower": "91800", + "x.com.samsung.da.cumulativeUnit": "Wh" + } + }, + { + "href": "/kidslock/vs/0", + "rep": { + "x.com.samsung.da.kidsLock": "Ready" + } + }, + { + "href": "/recipe/cook/vs/0", + "rep": { + "x.com.samsung.da.recipeDisplay": "{\"language\":\"None\",\"menu\":\"\",\"servingSize\":\"\",\"option\":\"\"}" + } + }, + { + "href": "/remotectrl/vs/0", + "rep": { + "x.com.samsung.da.remoteControlEnabled": "false", + "rt": [ + "x.com.samsung.da.configuration" + ], + "if": [ + "oic.if.baseline", + "oic.if.s" + ] + } + }, + { + "href": "/wirelessinfo/vs/0", + "rep": { + "macaddressWiFi": "**REDACTED**", + "macaddressBLE": "**REDACTED**" + } + }, + { + "href": "/quickcontrol/info/vs/0", + "rep": { + "supportedVersion": "1.0" + } + } + ] +} \ No newline at end of file diff --git a/tests/test_by_type.py b/tests/test_by_type.py index a291b10..b773098 100644 --- a/tests/test_by_type.py +++ b/tests/test_by_type.py @@ -329,6 +329,20 @@ class TestForDeviceByModel: assert reg is not None assert reg.name == 'airconditioner' + def test_oven_via_microwave_token(self): + """Issue #121: a combi microwave (MW7300B-/EU1) reports no + oneUiVersion and an unrecognized consumer token; falls back to the + '-MICROWAVE-' token in modelNum onto the *existing* oven registry + (same '/oven/vs/0' cavity + cook-mode shape), not a new device + type.""" + from custom_components.localthings.registry.by_type import for_device_by_model + reg = for_device_by_model( + 'TP1X_DA-KS-MICROWAVE-01041|40475341|50040100021811000A00000000000000', + 'MW7300B-/EU1', + ) + assert reg is not None + assert reg.name == 'oven' + def test_cooktop_via_legacy_model_description(self): """Older cooktops identify themselves as ARTIK051_GLOBAL_COOKTOP.""" from custom_components.localthings.registry.by_type import for_device_by_model diff --git a/tests/test_golden_regression.py b/tests/test_golden_regression.py index f56a9c4..b584075 100644 --- a/tests/test_golden_regression.py +++ b/tests/test_golden_regression.py @@ -568,6 +568,26 @@ def test_registry_reproduces_golden_state_keys_for_airconditioner_windfree_oscil ) +def test_registry_reproduces_golden_state_keys_for_oven_mw7300b(): + """TP1X_DA-KS-MICROWAVE-01041 combi microwave (model MW7300B, issue + #121) -- reports no oneUiVersion; resolved via the '-MICROWAVE-' + modelNum token fallback onto the *existing* oven registry rather than + a new device type, since it shares the same '/oven/vs/0' cavity and + '/mode/vs/0' cook-mode shape (Convection/AirFryer/Grill/MicroWave*). + The only href the oven registry didn't already cover was + /recipe/cook/vs/0 (oven.OVEN_RECIPE_COOK, an empty quick-recipe-display + blob with no entity).""" + from tests.conftest import _load_device + resources = _load_device('oven_mw7300b') + golden = json.loads((GOLDEN / 'oven_mw7300b.json').read_text()) + state_keys = _new_state_keys('oven_mw7300b', resources) + assert set(state_keys) == set(golden['state_keys']), ( + f"state_keys mismatch:\n" + f" extra: {sorted(set(state_keys) - set(golden['state_keys']))}\n" + f" missing: {sorted(set(golden['state_keys']) - set(state_keys))}" + ) + + def test_resources_from_batch_preferred_over_flat(): from tests.conftest import _resources_from_dump dump = {