From 618443db7bad3b62417a714f96545e68137bb158 Mon Sep 17 00:00:00 2001 From: Marc Billow Date: Thu, 23 Jul 2026 22:38:48 +0000 Subject: [PATCH] Use generic names for shared start/stop/pause entities The /operational/state/vs/0 href (and its start/pause/stop buttons and "cycle active" sensor) is shared across the dryer/dishwasher/oven/washer families, but the entity names hardcoded laundry vocabulary ("Start cycle", "Cycle active") that doesn't fit an oven's bake/roast session. Rename to generic "Start"/"Pause"/"Stop"/"Running". Also fold oven.py's duplicate stop button into a single STOP_BUTTON constant in operational.py -- both wrote the identical state='Ready' RMW, so there was no reason for two copies to maintain. --- .../registry/capabilities/operational.py | 25 +++++++++++++------ .../localthings/registry/capabilities/oven.py | 15 +++-------- 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/custom_components/localthings/registry/capabilities/operational.py b/custom_components/localthings/registry/capabilities/operational.py index bc9efb2..99d853d 100644 --- a/custom_components/localthings/registry/capabilities/operational.py +++ b/custom_components/localthings/registry/capabilities/operational.py @@ -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, ), ) diff --git a/custom_components/localthings/registry/capabilities/oven.py b/custom_components/localthings/registry/capabilities/oven.py index 2eadfc4..b8d8ea8 100644 --- a/custom_components/localthings/registry/capabilities/oven.py +++ b/custom_components/localthings/registry/capabilities/oven.py @@ -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, ), )