Merge remote-tracking branch 'origin/main' into claude/device-support-issue-56-shy2vg

# Conflicts:
#	tests/test_golden_regression.py
This commit is contained in:
Marc Billow committed 2026-07-23 23:47:42 +00:00
commit 7b155aabc2
8 files changed
+392 -19

No files matched your search

@@ -127,6 +127,11 @@ def for_device_by_model(model_num: str, description: str) -> Optional[DeviceRegi
# and don't match the washer/dryer/dishwasher consumer-prefix map either.
if key is None and '-RANGE-' in (model_num or '').upper():
key = 'range'
# Wall ovens (e.g. TP1X_DA-KS-OVEN-0107X, issue #55) -- same board-family
# naming as the range combo above, minus the burners; also reports no
# oneUiVersion and doesn't match the washer/dryer/dishwasher prefix map.
if key is None and '-OVEN-' in (model_num or '').upper():
key = 'oven'
return _REGISTRY_BY_KEY.get(key) if key else None
@@ -70,6 +70,15 @@ def _finish_time(remaining_str):
return None
# Shared by dryer/dishwasher/oven/washer -- oven.py imports this directly
# rather than keeping its own copy, since both wrote the identical
# state='Ready' RMW.
STOP_BUTTON = ButtonDesc(key='stop', field='', name='Stop', payload='Ready',
icon='mdi:stop',
write_fn=lambda p, rep, href=None: (
['operational', 'state', 'vs', '0'],
{'x.com.samsung.da.state': p}))
OPERATIONAL_STATE = Capability(
href='/operational/state/vs/0',
poll_tier='hot',
@@ -83,8 +92,12 @@ OPERATIONAL_STATE = Capability(
# Harmless for non-oven appliances — just an extra bool in state.
# Samsung firmware keeps state='Run' after progress reaches 'Finish',
# so we also gate on progress to avoid a stuck 'Running' indication.
# Named 'Running' rather than 'Cycle active' -- this href (and the
# start/pause/stop buttons below) is shared across the dryer/
# dishwasher/oven/washer families, and 'cycle' is laundry-specific
# vocabulary that doesn't fit an oven's bake/roast/etc.
BinarySensorDesc(key='cycle_active', device_class='running',
name='Cycle active',
name='Running',
rep_fn=lambda rep: (
_SAMSUNG_STATE_TO_OCF.get(rep.get('x.com.samsung.da.state')) == 'active'
and rep.get('x.com.samsung.da.progress') != 'Finish'
@@ -119,20 +132,16 @@ OPERATIONAL_STATE = Capability(
write_fn=lambda p, rep, href=None: (
['operational', 'state', 'vs', '0'],
{_delay_field(rep): _format_delay(p)})),
ButtonDesc(key='start', field='', name='Start cycle', payload='Run',
ButtonDesc(key='start', field='', name='Start', payload='Run',
icon='mdi:play',
write_fn=lambda p, rep, href=None: (
['operational', 'state', 'vs', '0'],
{'x.com.samsung.da.state': p})),
ButtonDesc(key='pause', field='', name='Pause cycle', payload='Pause',
ButtonDesc(key='pause', field='', name='Pause', payload='Pause',
icon='mdi:pause',
write_fn=lambda p, rep, href=None: (
['operational', 'state', 'vs', '0'],
{'x.com.samsung.da.state': p})),
ButtonDesc(key='stop', field='', name='Stop cycle', payload='Ready',
icon='mdi:stop',
write_fn=lambda p, rep, href=None: (
['operational', 'state', 'vs', '0'],
{'x.com.samsung.da.state': p})),
STOP_BUTTON,
),
)
@@ -26,10 +26,10 @@ from datetime import datetime, timezone, timedelta
from ..capability import Capability
from ..entities import (
BinarySensorDesc, ButtonDesc, NumberDesc, SelectDesc, SensorDesc,
SwitchDesc,
BinarySensorDesc, NumberDesc, SelectDesc, SensorDesc, SwitchDesc,
)
from .common import normalize_temp_unit
from .operational import STOP_BUTTON
# ---------------------------------------------------------------------------
# Constants
@@ -166,12 +166,6 @@ def _cook_time_write(p, rep, href=None):
}
def _stop_write(p, rep, href=None):
return ['operational', 'state', 'vs', '0'], {
'x.com.samsung.da.state': 'Ready',
}
def _oven_mode_write(p, rep, href=None):
if p not in _OVEN_MODES:
return None
@@ -237,7 +231,7 @@ OVEN_OPERATIONAL_STATE = Capability(
device_class='enum', options=('idle', 'active', 'pause'),
translation_key='machine_state', value_fn=_to_ocf),
BinarySensorDesc(key='cycle_active', field='x.com.samsung.da.state',
name='Cycle active', device_class='running',
name='Running', device_class='running',
value_fn=lambda v: _SAMSUNG_STATE_TO_OCF.get(v) == 'active'),
SensorDesc(key='progress_percentage',
field='x.com.samsung.da.progressPercentage',
@@ -254,8 +248,7 @@ OVEN_OPERATIONAL_STATE = Capability(
name='Cook time', unit='min', native_min=0, native_max=1439,
step=1.0, icon='mdi:timer', value_fn=_op_minutes,
write_fn=_cook_time_write),
ButtonDesc(key='stop', field='', name='Stop cycle', icon='mdi:stop',
payload='Stop', write_fn=_stop_write),
STOP_BUTTON,
),
)