From b33016089f40bac98d513a69779aa10ba551b708 Mon Sep 17 00:00:00 2001 From: John Lancaster <32917998+jsl12@users.noreply.github.com> Date: Sun, 30 Nov 2025 23:05:21 -0600 Subject: [PATCH] added conditions and transtions --- apps/stages/light.py | 63 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 55 insertions(+), 8 deletions(-) diff --git a/apps/stages/light.py b/apps/stages/light.py index ca81557..7e94cc5 100644 --- a/apps/stages/light.py +++ b/apps/stages/light.py @@ -18,6 +18,13 @@ class StagedControlEvent(str, Enum): DEACTIVATE = 'deactivate' +class StageCondition(str, Enum): + """Enum to define the different types of conditions for an event""" + + ANY_ON = 'any_on' + ALL_OFF = 'all_off' + + class StagedLight(Hass): def initialize(self): self.set_log_level('DEBUG') @@ -30,6 +37,10 @@ class StagedLight(Hass): if self.args.get('activate-at-start', False): self.activate() + # self._check_transition() + self.schedule_transition_checks() + self.run_daily(self.schedule_transition_checks, start='00:00:00') + ### Stages def _stage_starts(self) -> Generator[datetime]: @@ -56,38 +67,74 @@ class StagedLight(Hass): def current_scene(self): return self.current_stage().scene_json() + ### Transitions + + def schedule_transition_checks(self, **kwargs: Any): + now = self.get_now() + for stage in self._stages: + dt = self.parse_datetime(stage.start, aware=True, today=True) + if dt > now: + self.log(f'Scehduling transition at: {dt.isoformat()}', level='DEBUG') + self.run_at(self._check_transition, start=dt) + + def _check_transition(self, **kwargs: Any): + self.log('Firing transition event', level='DEBUG') + self.fire_event( + 'stage_control', + app=self.name, + condition=StageCondition.ANY_ON, + action=StagedControlEvent.ACTIVATE, + ) + ### Events def handle_event(self, event_type: str, data: dict[str, Any], **kwargs: Any) -> None: self.log(f'Event handler: {event_type}', level='DEBUG') stage = self.current_stage() - start_time_str = stage.formatted_start('%I:%M %p') + scene = stage.scene_json() + + match data: + case {'condition': StageCondition.ANY_ON}: + any_on = any(self.get_state(e) == 'on' for e in scene) + if not any_on: + self.log('Nothing is on, skipping', level='DEBUG') + return + case {'condition': StageCondition.ALL_OFF}: + all_off = all(self.get_state(e) == 'off' for e in scene) + if not all_off: + self.log('Everything is not off, skipping', level='DEBUG') + return + match data: case {'action': StagedControlEvent.ACTIVATE}: - self.log(f'Activating current stage: {start_time_str}') - self.activate(scene=stage.scene_json()) + self.activate(stage) case {'action': StagedControlEvent.DEACTIVATE}: - self.log(f'Deactivating current stage: {start_time_str}') - self.deactivate() + self.deactivate(stage) case _: self.log(str(data), level='DEBUG') self.log(str(kwargs), level='DEBUG') ### Actions - def activate(self, scene: dict | None = None, **kwargs: Any): - if scene is None: + def activate(self, stage: Stage | None = None, **kwargs: Any): + if stage is None: stage = self.current_stage() kwargs['entities'] = stage.scene_json() else: - kwargs['entities'] = scene + kwargs['entities'] = stage.scene_json() if t := self.args.get('transition'): kwargs['transition'] = t + start_time_str = stage.formatted_start('%I:%M %p') + self.log(f'Activating current stage: {start_time_str}') return self.call_service('scene/apply', **kwargs) def deactivate(self, stage: Stage | None = None, **kwargs): stage = stage if stage is not None else self.current_stage() + + start_time_str = stage.formatted_start('%I:%M %p') + self.log(f'Deactivating current stage: {start_time_str}') + for entity in stage.scene: self.turn_off(entity)