Compare commits
8 Commits
d90f2b28fa
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2f52febf38 | ||
|
|
d8476e9fdf | ||
|
|
43beb1e950 | ||
|
|
81b5d5afa5 | ||
|
|
b33016089f | ||
|
|
25892e1de8 | ||
|
|
05bad81571 | ||
|
|
697b09a7a1 |
@@ -6,4 +6,4 @@ class HelloWorld(Hass):
|
|||||||
self.log('Hello from AppDaemon')
|
self.log('Hello from AppDaemon')
|
||||||
self.log('You are now ready to run Apps!')
|
self.log('You are now ready to run Apps!')
|
||||||
|
|
||||||
self.get_history('ball1')
|
# self.get_history('ball1')
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
bar_lights:
|
bar_lights:
|
||||||
module: light
|
module: light
|
||||||
class: StagedLight
|
class: StagedLight
|
||||||
|
activate-at-start: true
|
||||||
|
transition: 3
|
||||||
stages:
|
stages:
|
||||||
- start: '03:00 am'
|
- start: '03:00 am'
|
||||||
scene:
|
scene:
|
||||||
@@ -8,18 +10,32 @@ bar_lights:
|
|||||||
state: on
|
state: on
|
||||||
color_temp_kelvin: 4500
|
color_temp_kelvin: 4500
|
||||||
brightness: 25
|
brightness: 25
|
||||||
|
light.server_lamp:
|
||||||
|
state: off
|
||||||
- start: '07:00 am'
|
- start: '07:00 am'
|
||||||
scene:
|
scene:
|
||||||
light.bar:
|
light.bar:
|
||||||
state: on
|
state: on
|
||||||
color_temp_kelvin: 3500
|
color_temp_kelvin: 3500
|
||||||
brightness: 100
|
brightness: 75
|
||||||
- start: '13:00'
|
light.server_lamp:
|
||||||
|
state: off
|
||||||
|
- start: '09:00 am'
|
||||||
scene:
|
scene:
|
||||||
light.bar:
|
light.bar:
|
||||||
state: on
|
state: on
|
||||||
color_temp_kelvin: 2500
|
color_temp_kelvin: 3500
|
||||||
|
brightness: 125
|
||||||
|
light.server_lamp:
|
||||||
|
state: off
|
||||||
|
- start: '01:00 pm'
|
||||||
|
scene:
|
||||||
|
light.bar:
|
||||||
|
state: on
|
||||||
|
color_temp_kelvin: 3000
|
||||||
brightness: 150
|
brightness: 150
|
||||||
|
light.server_lamp:
|
||||||
|
state: off
|
||||||
- start: 'sunset'
|
- start: 'sunset'
|
||||||
scene:
|
scene:
|
||||||
light.bar:
|
light.bar:
|
||||||
@@ -46,3 +62,5 @@ bar_lights:
|
|||||||
state: on
|
state: on
|
||||||
color_temp_kelvin: 2202
|
color_temp_kelvin: 2202
|
||||||
brightness: 30
|
brightness: 30
|
||||||
|
light.server_lamp:
|
||||||
|
state: off
|
||||||
|
|||||||
@@ -12,10 +12,19 @@ from stages import Stage
|
|||||||
|
|
||||||
|
|
||||||
class StagedControlEvent(str, Enum):
|
class StagedControlEvent(str, Enum):
|
||||||
|
"""Enum to define the different types of valid stage control events"""
|
||||||
|
|
||||||
ACTIVATE = 'activate'
|
ACTIVATE = 'activate'
|
||||||
DEACTIVATE = 'deactivate'
|
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):
|
class StagedLight(Hass):
|
||||||
def initialize(self):
|
def initialize(self):
|
||||||
self.set_log_level('DEBUG')
|
self.set_log_level('DEBUG')
|
||||||
@@ -24,7 +33,13 @@ class StagedLight(Hass):
|
|||||||
|
|
||||||
self.log(f'Initialized Motion Sensor with {len(self._stages)} stages')
|
self.log(f'Initialized Motion Sensor with {len(self._stages)} stages')
|
||||||
self.listen_event(self.handle_event, 'stage_control', app=self.name)
|
self.listen_event(self.handle_event, 'stage_control', app=self.name)
|
||||||
self.activate()
|
|
||||||
|
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
|
### Stages
|
||||||
|
|
||||||
@@ -52,30 +67,74 @@ class StagedLight(Hass):
|
|||||||
def current_scene(self):
|
def current_scene(self):
|
||||||
return self.current_stage().scene_json()
|
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
|
### Events
|
||||||
|
|
||||||
def handle_event(self, event_type: str, data: dict[str, Any], **kwargs: Any) -> None:
|
def handle_event(self, event_type: str, data: dict[str, Any], **kwargs: Any) -> None:
|
||||||
self.log(f'Event handler: {event_type}', level='DEBUG')
|
self.log(f'Event handler: {event_type}', level='DEBUG')
|
||||||
stage = self.current_stage()
|
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:
|
match data:
|
||||||
case {'action': StagedControlEvent.ACTIVATE}:
|
case {'action': StagedControlEvent.ACTIVATE}:
|
||||||
self.log(f'Activating current stage: {start_time_str}')
|
self.activate(stage)
|
||||||
self.activate(scene=stage.scene_json())
|
|
||||||
case {'action': StagedControlEvent.DEACTIVATE}:
|
case {'action': StagedControlEvent.DEACTIVATE}:
|
||||||
self.log(f'Deactivating current stage: {start_time_str}')
|
self.deactivate(stage)
|
||||||
self.deactivate()
|
|
||||||
case _:
|
case _:
|
||||||
self.log(str(data), level='DEBUG')
|
self.log(str(data), level='DEBUG')
|
||||||
self.log(str(kwargs), level='DEBUG')
|
self.log(str(kwargs), level='DEBUG')
|
||||||
|
|
||||||
### Actions
|
### Actions
|
||||||
|
|
||||||
def activate(self, scene: dict | None = None, **kwargs):
|
def activate(self, stage: Stage | None = None, **kwargs: Any):
|
||||||
scene = scene if scene is not None else self.current_scene()
|
if stage is None:
|
||||||
return self.call_service('scene/apply', entities=scene, transition=5)
|
stage = self.current_stage()
|
||||||
|
kwargs['entities'] = stage.scene_json()
|
||||||
|
else:
|
||||||
|
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):
|
def deactivate(self, stage: Stage | None = None, **kwargs):
|
||||||
stage = stage if stage is not None else self.current_stage()
|
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:
|
for entity in stage.scene:
|
||||||
self.turn_off(entity)
|
self.turn_off(entity)
|
||||||
|
|||||||
@@ -23,8 +23,9 @@ class EntityState(BaseModel, extra='allow'):
|
|||||||
class Stage(BaseModel):
|
class Stage(BaseModel):
|
||||||
# start: Annotated[time, BeforeValidator(lambda v: parser(v).time())]
|
# start: Annotated[time, BeforeValidator(lambda v: parser(v).time())]
|
||||||
start: str
|
start: str
|
||||||
_start: datetime = PrivateAttr()
|
|
||||||
scene: dict[str, EntityState]
|
scene: dict[str, EntityState]
|
||||||
|
_start: datetime = PrivateAttr()
|
||||||
|
transition: int | None = None
|
||||||
|
|
||||||
def assign_start(self, dt: datetime):
|
def assign_start(self, dt: datetime):
|
||||||
self._start = dt
|
self._start = dt
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ upper_stairs:
|
|||||||
state: "on"
|
state: "on"
|
||||||
color_temp_kelvin: 2202
|
color_temp_kelvin: 2202
|
||||||
brightness: 60
|
brightness: 60
|
||||||
- start: '11:00'
|
- start: '11:00 pm'
|
||||||
scene:
|
scene:
|
||||||
light.bathroom_stairs:
|
light.bathroom_stairs:
|
||||||
state: "on"
|
state: "on"
|
||||||
|
|||||||
@@ -2,8 +2,11 @@ services:
|
|||||||
appdaemon:
|
appdaemon:
|
||||||
container_name: appdaemon
|
container_name: appdaemon
|
||||||
image: acockburn/appdaemon:dev
|
image: acockburn/appdaemon:dev
|
||||||
|
# image: acockburn/appdaemon:local-dev
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
tty: true
|
tty: true
|
||||||
|
dns:
|
||||||
|
- 192.168.1.150
|
||||||
volumes:
|
volumes:
|
||||||
- /etc/localtime:/etc/localtime:ro
|
- /etc/localtime:/etc/localtime:ro
|
||||||
- /etc/timezone:/etc/timezone:ro
|
- /etc/timezone:/etc/timezone:ro
|
||||||
|
|||||||
Reference in New Issue
Block a user