diff --git a/custom_components/localthings/coordinator.py b/custom_components/localthings/coordinator.py index d1b6576..44695e4 100644 --- a/custom_components/localthings/coordinator.py +++ b/custom_components/localthings/coordinator.py @@ -246,6 +246,10 @@ class LocalThingsCoordinator(DataUpdateCoordinator[dict[str, Any]]): try: resources = await self.hass.async_add_executor_job(self._poll_once) except Exception as e2: + _LOGGER.error("poll failed after reconnect: %s", e2) + if self._last_resources: + _LOGGER.debug("Full error:", exc_info=e2) + return flatten(self.bound, self._last_resources) raise UpdateFailed(f"poll failed after reconnect: {e2}") from e2 self._last_resources = resources diff --git a/custom_components/localthings/ocf/registry/capabilities/common.py b/custom_components/localthings/ocf/registry/capabilities/common.py index d449520..867fc04 100644 --- a/custom_components/localthings/ocf/registry/capabilities/common.py +++ b/custom_components/localthings/ocf/registry/capabilities/common.py @@ -11,7 +11,7 @@ against live device dumps: /filter/waterfilter/vs/0 -> x.com.samsung.da.filterUsage / filterStatus """ from ..capability import Capability -from ..entities import BinarySensorDesc, SensorDesc, SwitchDesc +from ..entities import SensorDesc, SwitchDesc def _num(v): @@ -46,19 +46,25 @@ def _active_alarm_codes(items): KIDS_LOCK = Capability( href='/kidslock/vs/0', entities=( - BinarySensorDesc(key='child_lock', field='x.com.samsung.da.kidsLock', - name='Child lock', device_class='lock', - value_fn=lambda v: v != 'Ready'), + SwitchDesc(key='child_lock', field='x.com.samsung.da.kidsLock', + name='Child lock', device_class='lock', + value_fn=lambda v: v != 'Ready', + write_fn=lambda p, rep, href=None: ( + ['kidslock', 'vs', '0'], + {'x.com.samsung.da.kidsLock': 'Enable' if p == 'On' else 'Ready'})), ), ) REMOTE_CONTROL = Capability( href='/remotectrl/vs/0', entities=( - BinarySensorDesc(key='remote_control', - field='x.com.samsung.da.remoteControlEnabled', - name='Remote control', device_class='connectivity', - value_fn=lambda v: str(v).lower() == 'true'), + SwitchDesc(key='remote_control', + field='x.com.samsung.da.remoteControlEnabled', + name='Remote control', device_class='connectivity', + value_fn=lambda v: str(v).lower() == 'true', + write_fn=lambda p, rep, href=None: ( + ['remotectrl', 'vs', '0'], + {'x.com.samsung.da.remoteControlEnabled': 'true' if p == 'On' else 'false'})), ), ) diff --git a/custom_components/localthings/ocf/registry/capabilities/operational.py b/custom_components/localthings/ocf/registry/capabilities/operational.py index 4af8f16..cf70e54 100644 --- a/custom_components/localthings/ocf/registry/capabilities/operational.py +++ b/custom_components/localthings/ocf/registry/capabilities/operational.py @@ -2,10 +2,10 @@ Shared by dryer/dishwasher/oven/washer families. """ -from datetime import datetime, timezone, timedelta +from datetime import datetime, timezone, timedelta, time as dt_time from ..capability import Capability -from ..entities import BinarySensorDesc, ButtonDesc, SensorDesc +from ..entities import BinarySensorDesc, ButtonDesc, SensorDesc, TimeDesc _SAMSUNG_STATE_TO_OCF = { 'Ready': 'idle', 'Run': 'active', 'Running': 'active', @@ -32,6 +32,16 @@ def _active_when(rep): return _SAMSUNG_STATE_TO_OCF.get(rep.get('x.com.samsung.da.state')) == 'active' +def _parse_hms(v): + if not v: + return None + try: + h, m, s = v.split(':') + return dt_time(int(h) % 24, int(m), int(s)) + except Exception: + return None + + def _finish_time(remaining_str): if not remaining_str: return None @@ -66,8 +76,12 @@ OPERATIONAL_STATE = Capability( SensorDesc(key='finish_time', field='x.com.samsung.da.remainingTime', name='Estimated finish', device_class='timestamp', value_fn=_finish_time), - SensorDesc(key='delay_start_time', field='x.com.samsung.da.delayStartTime', - name='Delay start time', icon='mdi:timer-pause'), + TimeDesc(key='delay_start_time', field='x.com.samsung.da.delayStartTime', + name='Delay start', + value_fn=_parse_hms, + write_fn=lambda p, rep, href=None: ( + ['operational', 'state', 'vs', '0'], + {'x.com.samsung.da.delayStartTime': f'{p.hour}:{p.minute:02d}:{p.second:02d}'})), ButtonDesc(key='start', field='', name='Start cycle', payload='Run', icon='mdi:play', write_fn=lambda p, rep, href=None: (