started stages logic
This commit is contained in:
@@ -1,3 +1,33 @@
|
|||||||
hello_world:
|
# hello_world:
|
||||||
module: hello
|
# module: hello
|
||||||
class: HelloWorld
|
# class: HelloWorld
|
||||||
|
|
||||||
|
|
||||||
|
bar_lights:
|
||||||
|
module: motion
|
||||||
|
class: StagedMotionLight
|
||||||
|
stages:
|
||||||
|
- start: '06:00 am'
|
||||||
|
scene:
|
||||||
|
light.bar:
|
||||||
|
state: on
|
||||||
|
color_temp_kelvin: 4500
|
||||||
|
brightness: 25
|
||||||
|
- start: '09:00 am'
|
||||||
|
scene:
|
||||||
|
light.bar:
|
||||||
|
state: on
|
||||||
|
color_temp_kelvin: 3500
|
||||||
|
brightness: 100
|
||||||
|
- start: '13:00'
|
||||||
|
scene:
|
||||||
|
light.bar:
|
||||||
|
state: on
|
||||||
|
color_temp_kelvin: 2500
|
||||||
|
brightness: 150
|
||||||
|
- start: 'sunset'
|
||||||
|
scene:
|
||||||
|
light.bar:
|
||||||
|
state: on
|
||||||
|
color_temp_kelvin: 2000
|
||||||
|
brightness: 100
|
||||||
|
|||||||
55
apps/motion.py
Normal file
55
apps/motion.py
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
import json
|
||||||
|
from collections.abc import Generator
|
||||||
|
from datetime import datetime
|
||||||
|
from itertools import count, cycle, pairwise
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from appdaemon.adapi import ADAPI
|
||||||
|
from pydantic import BaseModel, TypeAdapter
|
||||||
|
|
||||||
|
from stages import Stage
|
||||||
|
|
||||||
|
adapter = TypeAdapter(list[Stage])
|
||||||
|
|
||||||
|
|
||||||
|
class StagedMotionLight(ADAPI):
|
||||||
|
def initialize(self):
|
||||||
|
self.set_log_level("DEBUG")
|
||||||
|
self._stages = adapter.validate_python(self.args["stages"])
|
||||||
|
|
||||||
|
self.log(f"Initialized Motion Sensor with {len(self._stages)} stages")
|
||||||
|
self.activate()
|
||||||
|
|
||||||
|
def _stage_starts(self) -> Generator[datetime]:
|
||||||
|
for offset in count(start=-1):
|
||||||
|
for stage in self._stages:
|
||||||
|
dt = self.parse_datetime(
|
||||||
|
stage.start,
|
||||||
|
days_offset=offset,
|
||||||
|
aware=True,
|
||||||
|
today=True,
|
||||||
|
)
|
||||||
|
dt = dt.replace(microsecond=0)
|
||||||
|
yield dt
|
||||||
|
|
||||||
|
def start_pairs(self):
|
||||||
|
yield from pairwise(self._stage_starts())
|
||||||
|
|
||||||
|
def current_stage(self) -> Stage:
|
||||||
|
for stage, (t1, t2) in zip(cycle(self._stages), self.start_pairs()):
|
||||||
|
start, end = sorted([t1, t2])
|
||||||
|
if self.now_is_between(start, end):
|
||||||
|
self.log(f"Current stage start time: {stage.start}")
|
||||||
|
return stage
|
||||||
|
else:
|
||||||
|
raise ValueError
|
||||||
|
|
||||||
|
def current_scene(self):
|
||||||
|
return self.current_stage().model_dump(mode="json")["scene"]
|
||||||
|
|
||||||
|
def activate(self, **kwargs):
|
||||||
|
return self.call_service("scene/apply", entities=self.current_scene())
|
||||||
|
|
||||||
|
# @property
|
||||||
|
# def stages(self) -> GeneratorExit:
|
||||||
|
# yield from pairwise(self._stage_starts)
|
||||||
36
apps/stages.py
Normal file
36
apps/stages.py
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
import functools
|
||||||
|
from datetime import datetime, time
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Annotated, Any
|
||||||
|
|
||||||
|
from appdaemon.adapi import ADAPI
|
||||||
|
from pydantic import (
|
||||||
|
BaseModel,
|
||||||
|
BeforeValidator,
|
||||||
|
Field,
|
||||||
|
PrivateAttr,
|
||||||
|
TypeAdapter,
|
||||||
|
field_serializer,
|
||||||
|
field_validator,
|
||||||
|
)
|
||||||
|
from rich import print as rprint
|
||||||
|
|
||||||
|
|
||||||
|
class EntityState(BaseModel):
|
||||||
|
state: bool = True
|
||||||
|
color_temp_kelvin: int
|
||||||
|
brightness: int
|
||||||
|
|
||||||
|
@field_serializer("state")
|
||||||
|
def convert_state(self, val: Any):
|
||||||
|
if val:
|
||||||
|
return "on"
|
||||||
|
else:
|
||||||
|
return "off"
|
||||||
|
|
||||||
|
|
||||||
|
class Stage(BaseModel):
|
||||||
|
# start: Annotated[time, BeforeValidator(lambda v: parser(v).time())]
|
||||||
|
start: str
|
||||||
|
_start: time = PrivateAttr()
|
||||||
|
scene: dict[str, EntityState]
|
||||||
Reference in New Issue
Block a user