added some services
This commit is contained in:
@@ -5,7 +5,7 @@ import logging.config
|
|||||||
import traceback
|
import traceback
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
from typing import Any, Dict, List
|
from typing import Any, Dict, List, Set
|
||||||
|
|
||||||
from appdaemon.entity import Entity
|
from appdaemon.entity import Entity
|
||||||
from appdaemon.plugins.hass.hassapi import Hass
|
from appdaemon.plugins.hass.hassapi import Hass
|
||||||
@@ -25,6 +25,14 @@ class RoomController(Hass):
|
|||||||
- `handle_on`
|
- `handle_on`
|
||||||
- `handle_off`
|
- `handle_off`
|
||||||
- When the light comes on, check if it's attributes match what they should, given the time.
|
- When the light comes on, check if it's attributes match what they should, given the time.
|
||||||
|
|
||||||
|
|
||||||
|
## Services
|
||||||
|
|
||||||
|
- <name>/activate
|
||||||
|
- <name>/activate_all_off
|
||||||
|
- <name>/deactivate
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@@ -43,39 +51,51 @@ class RoomController(Hass):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def state_entity(self) -> Entity:
|
def state_entity(self) -> Entity:
|
||||||
return self.get_entity(f'{self.name}.state')
|
return self.get_entity(f'{self.name}.state', namespace='controller')
|
||||||
|
|
||||||
def initialize(self):
|
def initialize(self):
|
||||||
self.set_namespace('controller')
|
|
||||||
|
|
||||||
self.logger = console.load_rich_config(self.name)
|
self.logger = console.load_rich_config(self.name)
|
||||||
self.set_log_level('DEBUG')
|
self.set_log_level('DEBUG')
|
||||||
|
|
||||||
self.register_service(f'{self.name}/activate', self.service_activate)
|
|
||||||
self.register_service(f'{self.name}/deactivate', self.service_deactivate)
|
|
||||||
|
|
||||||
self.refresh_state_times()
|
self.refresh_state_times()
|
||||||
self.run_daily(callback=self.refresh_state_times, start='00:00:00')
|
self.run_daily(callback=self.refresh_state_times, start='00:00:00')
|
||||||
|
|
||||||
self.app_entities = set(self.gather_app_entities())
|
self.register_service(
|
||||||
|
f'{self.name}/activate', self._service_activate, namespace='controller'
|
||||||
|
)
|
||||||
|
self.register_service(
|
||||||
|
f'{self.name}/activate_all_off', self._service_activate_all_off, namespace='controller'
|
||||||
|
)
|
||||||
|
self.register_service(
|
||||||
|
f'{self.name}/deactivate', self._service_deactivate, namespace='controller'
|
||||||
|
)
|
||||||
|
|
||||||
|
# This needs to come after this first call of refresh_state_times
|
||||||
|
self.app_entities = self.get_app_entities()
|
||||||
self.log(f'entities: {self.app_entities}', level='DEBUG')
|
self.log(f'entities: {self.app_entities}', level='DEBUG')
|
||||||
|
|
||||||
self.log(f'Initialized [bold green]{type(self).__name__}[/]')
|
self.log(f'Initialized [bold green]{type(self).__name__}[/]')
|
||||||
|
self.activate_all_off(test_kwarg='abc123')
|
||||||
|
|
||||||
def terminate(self):
|
def terminate(self):
|
||||||
self.log('[bold red]Terminating[/]', level='DEBUG')
|
self.log('[bold red]Terminating[/]', level='DEBUG')
|
||||||
|
|
||||||
def gather_app_entities(self):
|
def get_app_entities(self) -> Set[str]:
|
||||||
"""Yields all the entities involved in any of the states"""
|
"""Gets a set of all the entities referenced by any of the state definitions"""
|
||||||
|
|
||||||
|
def gen():
|
||||||
for state in self._room_config.states:
|
for state in self._room_config.states:
|
||||||
if isinstance(state.scene, str):
|
if isinstance(state.scene, str):
|
||||||
assert state.scene.startswith('scene.'), "Scene definition must start with 'scene.'"
|
assert state.scene.startswith(
|
||||||
entities = self.get_state(state.scene, namespace='default', attribute='entity_id')
|
'scene.'
|
||||||
|
), "Scene definition must start with 'scene.'"
|
||||||
|
entities = self.get_state(state.scene, attribute='entity_id')
|
||||||
yield from entities
|
yield from entities
|
||||||
else:
|
else:
|
||||||
yield from state.scene.keys()
|
yield from state.scene.keys()
|
||||||
|
|
||||||
|
return set(gen())
|
||||||
|
|
||||||
def refresh_state_times(self, *args, **kwargs):
|
def refresh_state_times(self, *args, **kwargs):
|
||||||
"""Resets the `self.states` attribute to a newly parsed version of the states.
|
"""Resets the `self.states` attribute to a newly parsed version of the states.
|
||||||
|
|
||||||
@@ -123,25 +143,50 @@ class RoomController(Hass):
|
|||||||
else:
|
else:
|
||||||
return ControllerStateConfig()
|
return ControllerStateConfig()
|
||||||
else:
|
else:
|
||||||
|
try:
|
||||||
attrs = self.state_entity.get_state('all')['attributes']
|
attrs = self.state_entity.get_state('all')['attributes']
|
||||||
return ControllerStateConfig.model_validate(attrs)
|
state = ControllerStateConfig.model_validate(attrs)
|
||||||
|
except Exception:
|
||||||
|
state = ControllerStateConfig()
|
||||||
|
finally:
|
||||||
|
# self.log(f'Current state: {state.model_dump(exclude_none=True)}', level='DEBUG')
|
||||||
|
return state
|
||||||
|
|
||||||
def current_scene(self, transition: int = None) -> Dict[str, Any]:
|
# def current_scene(self, transition: int = None) -> Dict[str, Any]:
|
||||||
|
# state = self.current_state()
|
||||||
|
# if isinstance(state.scene, str):
|
||||||
|
# return state.scene
|
||||||
|
# elif isinstance(state.scene, dict):
|
||||||
|
# return state.to_apply_kwargs(transition)
|
||||||
|
|
||||||
|
def activate(self, **kwargs):
|
||||||
|
self.call_service(f'{self.name}/activate', namespace='controller', **kwargs)
|
||||||
|
|
||||||
|
def _service_activate(self, namespace: str, domain: str, service: str, kwargs: Dict[str, Any]):
|
||||||
|
self.log(f'Custom kwargs: {kwargs}', level='DEBUG')
|
||||||
state = self.current_state()
|
state = self.current_state()
|
||||||
if isinstance(state.scene, str):
|
if isinstance(state.scene, str):
|
||||||
return state.scene
|
self.turn_on(state.scene)
|
||||||
|
# self.turn_on(state.scene, transition=0)
|
||||||
elif isinstance(state.scene, dict):
|
elif isinstance(state.scene, dict):
|
||||||
return state.to_apply_kwargs(transition)
|
scene = state.to_apply_kwargs()
|
||||||
|
self.call_service('scene/apply', **scene)
|
||||||
|
# scene = state.to_apply_kwargs(transition=0)
|
||||||
|
|
||||||
def service_activate(self, namespace: str, domain: str, service: str, kwargs: Dict[str, Any]):
|
def activate_all_off(self, **kwargs):
|
||||||
scene = self.current_scene(transition=0)
|
"""Activate if all of the entities are off. Args and kwargs are passed directly to self.activate()"""
|
||||||
|
self.call_service(f'{self.name}/activate_all_off', namespace='controller', **kwargs)
|
||||||
|
|
||||||
if isinstance(scene, str):
|
def _service_activate_all_off(self, namespace: str, domain: str, service: str, kwargs: Dict[str, Any]):
|
||||||
self.turn_on(scene)
|
if self.all_off():
|
||||||
elif isinstance(scene, dict):
|
self.activate(**kwargs)
|
||||||
self.call_service('scene/apply', namespace='default', **scene)
|
|
||||||
|
|
||||||
def service_deactivate(self, namespace: str, domain: str, service: str, kwargs: Dict[str, Any]):
|
def deactivate(self, **kwargs):
|
||||||
|
self.call_service(f'{self.name}/deactivate', namespace='controller', **kwargs)
|
||||||
|
|
||||||
|
def _service_deactivate(
|
||||||
|
self, namespace: str, domain: str, service: str, kwargs: Dict[str, Any]
|
||||||
|
):
|
||||||
for e in self.app_entities:
|
for e in self.app_entities:
|
||||||
self.turn_off(e)
|
self.turn_off(e)
|
||||||
|
|
||||||
@@ -207,36 +252,29 @@ class RoomController(Hass):
|
|||||||
now = now or self.get_now().time()
|
now = now or self.get_now().time()
|
||||||
return self._room_config.current_off_duration(now)
|
return self._room_config.current_off_duration(now)
|
||||||
|
|
||||||
def activate(self, entity=None, attribute=None, old=None, new=None, kwargs=None):
|
# def activate(self, entity=None, attribute=None, old=None, new=None, kwargs=None):
|
||||||
if kwargs is not None:
|
# if kwargs is not None:
|
||||||
cause = kwargs.get('cause', 'unknown')
|
# cause = kwargs.get('cause', 'unknown')
|
||||||
else:
|
# else:
|
||||||
cause = 'unknown'
|
# cause = 'unknown'
|
||||||
|
|
||||||
self.log(f'Activating: {cause}')
|
# self.log(f'Activating: {cause}')
|
||||||
scene_kwargs = self.current_state().to_apply_kwargs(transition=0)
|
# scene_kwargs = self.current_state().to_apply_kwargs(transition=0)
|
||||||
|
|
||||||
if isinstance(scene_kwargs, str):
|
# if isinstance(scene_kwargs, str):
|
||||||
self.turn_on(scene_kwargs)
|
# self.turn_on(scene_kwargs)
|
||||||
self.log(f'Turned on scene: {scene_kwargs}')
|
# self.log(f'Turned on scene: {scene_kwargs}')
|
||||||
|
|
||||||
elif isinstance(scene_kwargs, dict):
|
# elif isinstance(scene_kwargs, dict):
|
||||||
self.call_service('scene/apply', **scene_kwargs)
|
# self.call_service('scene/apply', **scene_kwargs)
|
||||||
self.log(f'Applied scene:\n{json.dumps(scene_kwargs, indent=2)}', level='DEBUG')
|
# self.log(f'Applied scene:\n{json.dumps(scene_kwargs, indent=2)}', level='DEBUG')
|
||||||
|
|
||||||
elif scene_kwargs is None:
|
# elif scene_kwargs is None:
|
||||||
self.log('No scene, ignoring...')
|
# self.log('No scene, ignoring...')
|
||||||
# Need to act as if the light had just turned off to reset the motion (and maybe other things?)
|
# # Need to act as if the light had just turned off to reset the motion (and maybe other things?)
|
||||||
# self.callback_light_off()
|
# # self.callback_light_off()
|
||||||
else:
|
# else:
|
||||||
self.log(f'ERROR: unknown scene: {scene_kwargs}')
|
# self.log(f'ERROR: unknown scene: {scene_kwargs}')
|
||||||
|
|
||||||
def activate_all_off(self, *args, **kwargs):
|
|
||||||
"""Activate if all of the entities are off. Args and kwargs are passed directly to self.activate()"""
|
|
||||||
if self.all_off():
|
|
||||||
self.activate(*args, **kwargs)
|
|
||||||
else:
|
|
||||||
self.log('Skipped activating - everything is not off')
|
|
||||||
|
|
||||||
def activate_any_on(self, *args, **kwargs):
|
def activate_any_on(self, *args, **kwargs):
|
||||||
"""Activate if any of the entities are on. Args and kwargs are passed directly to self.activate()"""
|
"""Activate if any of the entities are on. Args and kwargs are passed directly to self.activate()"""
|
||||||
|
|||||||
Reference in New Issue
Block a user