improved trigger code
This commit is contained in:
@@ -10,6 +10,7 @@ import xmltodict
|
|||||||
|
|
||||||
class TriggerTuple(NamedTuple):
|
class TriggerTuple(NamedTuple):
|
||||||
name: str
|
name: str
|
||||||
|
type: str
|
||||||
interval_in_seconds: int
|
interval_in_seconds: int
|
||||||
governor: str
|
governor: str
|
||||||
custom_config: OrderedDict[str, Any]
|
custom_config: OrderedDict[str, Any]
|
||||||
@@ -68,6 +69,7 @@ class Config:
|
|||||||
_trigger_elements = self._get_multiple_elements_by_xpath('triggers/trigger')
|
_trigger_elements = self._get_multiple_elements_by_xpath('triggers/trigger')
|
||||||
for trigger_elem in _trigger_elements:
|
for trigger_elem in _trigger_elements:
|
||||||
name = self._get_single_text_value_from_xpath('name', trigger_elem)
|
name = self._get_single_text_value_from_xpath('name', trigger_elem)
|
||||||
|
type = self._get_single_text_value_from_xpath('type', trigger_elem)
|
||||||
interval_in_seconds = self._get_single_text_value_from_xpath('intervalInSeconds', trigger_elem)
|
interval_in_seconds = self._get_single_text_value_from_xpath('intervalInSeconds', trigger_elem)
|
||||||
governor = self._get_single_text_value_from_xpath('governor', trigger_elem)
|
governor = self._get_single_text_value_from_xpath('governor', trigger_elem)
|
||||||
try:
|
try:
|
||||||
@@ -78,6 +80,7 @@ class Config:
|
|||||||
custom_config = OrderedDict({})
|
custom_config = OrderedDict({})
|
||||||
_new_trigger = TriggerTuple(
|
_new_trigger = TriggerTuple(
|
||||||
name=name,
|
name=name,
|
||||||
|
type=type,
|
||||||
interval_in_seconds=int(interval_in_seconds),
|
interval_in_seconds=int(interval_in_seconds),
|
||||||
governor=governor,
|
governor=governor,
|
||||||
custom_config=custom_config
|
custom_config=custom_config
|
||||||
|
|||||||
@@ -5,16 +5,19 @@
|
|||||||
<triggers>
|
<triggers>
|
||||||
<trigger>
|
<trigger>
|
||||||
<name>test_trigger1</name>
|
<name>test_trigger1</name>
|
||||||
|
<type>run_once</type>
|
||||||
<intervalInSeconds>1</intervalInSeconds>
|
<intervalInSeconds>1</intervalInSeconds>
|
||||||
<governor>ondemand</governor>
|
<governor>ondemand</governor>
|
||||||
</trigger>
|
</trigger>
|
||||||
<trigger>
|
<trigger>
|
||||||
<name>test_trigger2</name>
|
<name>test_trigger2</name>
|
||||||
|
<type>run_once</type>
|
||||||
<intervalInSeconds>3</intervalInSeconds>
|
<intervalInSeconds>3</intervalInSeconds>
|
||||||
<governor>conservative</governor>
|
<governor>conservative</governor>
|
||||||
</trigger>
|
</trigger>
|
||||||
<trigger>
|
<trigger>
|
||||||
<name>roon</name>
|
<name>roon</name>
|
||||||
|
<type>callback</type>
|
||||||
<intervalInSeconds>2</intervalInSeconds>
|
<intervalInSeconds>2</intervalInSeconds>
|
||||||
<governor>performance</governor>
|
<governor>performance</governor>
|
||||||
<customConfig>
|
<customConfig>
|
||||||
|
|||||||
+15
-3
@@ -10,16 +10,28 @@ class TriggerScheduler(AppClass):
|
|||||||
super().__init__(_config)
|
super().__init__(_config)
|
||||||
self.tasks: list[Task] = []
|
self.tasks: list[Task] = []
|
||||||
|
|
||||||
async def trigger(self, _trigger: Trigger) -> None:
|
async def callback_trigger(self, _trigger: Trigger) -> None:
|
||||||
|
"""Run a callback_trigger with a specific name and check its status at a given interval."""
|
||||||
|
await _trigger.async_run()
|
||||||
|
while True:
|
||||||
|
trigger_state = "active" if _trigger.active else "not active"
|
||||||
|
self.log.debug("Checking state of trigger %s, state: %s", _trigger.name, trigger_state)
|
||||||
|
await asyncio.sleep(_trigger.config.interval_in_seconds)
|
||||||
|
|
||||||
|
async def run_once_trigger(self, _trigger: Trigger) -> None:
|
||||||
"""Run a trigger with a specific name at a given interval."""
|
"""Run a trigger with a specific name at a given interval."""
|
||||||
while True:
|
while True:
|
||||||
self.log.debug("Trigger %s is running", _trigger.name)
|
|
||||||
_trigger.run()
|
_trigger.run()
|
||||||
|
trigger_state = "active" if _trigger.active else "not active"
|
||||||
|
self.log.debug("Checking state of trigger %s, state: %s", _trigger.name, trigger_state)
|
||||||
await asyncio.sleep(_trigger.config.interval_in_seconds)
|
await asyncio.sleep(_trigger.config.interval_in_seconds)
|
||||||
|
|
||||||
def start_trigger(self, _trigger: Trigger) -> None:
|
def start_trigger(self, _trigger: Trigger) -> None:
|
||||||
"""Start a new trigger."""
|
"""Start a new trigger."""
|
||||||
task = asyncio.create_task(self.trigger(_trigger))
|
if _trigger.config.type == "callback":
|
||||||
|
task = asyncio.create_task(self.callback_trigger(_trigger))
|
||||||
|
else:
|
||||||
|
task = asyncio.create_task(self.run_once_trigger(_trigger))
|
||||||
self.tasks.append(task)
|
self.tasks.append(task)
|
||||||
|
|
||||||
async def stop_triggers(self) -> None:
|
async def stop_triggers(self) -> None:
|
||||||
|
|||||||
+14
-2
@@ -6,6 +6,7 @@ from exceptions import MissingConfig, TriggerImportError
|
|||||||
class Trigger(AppClass):
|
class Trigger(AppClass):
|
||||||
def __init__(self, _config: Config) -> None:
|
def __init__(self, _config: Config) -> None:
|
||||||
super().__init__(_config)
|
super().__init__(_config)
|
||||||
|
self.active: bool = False
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self) -> str:
|
def name(self) -> str:
|
||||||
@@ -23,8 +24,19 @@ class Trigger(AppClass):
|
|||||||
raise MissingConfig(f"Trigger {self.name} hasn't been properly configured")
|
raise MissingConfig(f"Trigger {self.name} hasn't been properly configured")
|
||||||
return _config
|
return _config
|
||||||
|
|
||||||
def run(self) -> bool:
|
def run(self) -> None:
|
||||||
# return True if Trigger is valid
|
# this is the main function of the trigger class and has to stay active by using a while True loop
|
||||||
|
|
||||||
|
while True:
|
||||||
raise TriggerImportError(
|
raise TriggerImportError(
|
||||||
"the Trigger class can't used directly, but must be inherited in a trigger specific class"
|
"the Trigger class can't used directly, but must be inherited in a trigger specific class"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
async def async_run(self) -> None:
|
||||||
|
# this is the main function of the trigger class and can be used to execute a callback function
|
||||||
|
|
||||||
|
while True:
|
||||||
|
raise TriggerImportError(
|
||||||
|
"the Trigger class can't used directly, but must be inherited in a trigger specific class"
|
||||||
|
)
|
||||||
|
|
||||||
+22
-14
@@ -2,7 +2,7 @@ from trigger import Trigger
|
|||||||
from config import Config
|
from config import Config
|
||||||
from roonapi import RoonApi, RoonDiscovery # type: ignore
|
from roonapi import RoonApi, RoonDiscovery # type: ignore
|
||||||
from functools import cached_property
|
from functools import cached_property
|
||||||
from typing import Any, NamedTuple
|
from typing import Any, NamedTuple, Union
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
@@ -16,10 +16,21 @@ class RoonServer(NamedTuple):
|
|||||||
class RoonTrigger(Trigger):
|
class RoonTrigger(Trigger):
|
||||||
def __init__(self, _config: Config) -> None:
|
def __init__(self, _config: Config) -> None:
|
||||||
super().__init__(_config)
|
super().__init__(_config)
|
||||||
|
self.set_status()
|
||||||
|
|
||||||
@property
|
def set_status(self) -> None:
|
||||||
def playing(self) -> bool:
|
zones_state = list()
|
||||||
return False
|
|
||||||
|
for zone_id in self.roonapi.zones:
|
||||||
|
self.log.debug(self.roonapi.zones[zone_id])
|
||||||
|
zone = self.roonapi.zones[zone_id]
|
||||||
|
self.log.debug("zone_id: %s zone_info: %s" , zone_id, zone)
|
||||||
|
zone_name = zone['display_name']
|
||||||
|
zone_state = zone['state']
|
||||||
|
self.log.info("zone_id: %s name: %s, state: %s" , zone_id, zone_name, zone_state)
|
||||||
|
zones_state.append(zone_state)
|
||||||
|
|
||||||
|
self.active = True if "playing" in zones_state else False
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def appinfo(self) -> dict[str, Any]:
|
def appinfo(self) -> dict[str, Any]:
|
||||||
@@ -69,15 +80,12 @@ class RoonTrigger(Trigger):
|
|||||||
_roonapi = RoonApi(self.appinfo, self.token, self.server.ip, self.server.port, True)
|
_roonapi = RoonApi(self.appinfo, self.token, self.server.ip, self.server.port, True)
|
||||||
return _roonapi
|
return _roonapi
|
||||||
|
|
||||||
def my_state_callback(self, event, changed_ids):
|
def roon_state_callback(self, event: str, changed_ids: Union[str, list[str]]) -> None:
|
||||||
"""Call when something changes in roon."""
|
"""Call when something changes in roon."""
|
||||||
self.log.info("my_state_callback event:%s changed_ids: %s" % (event, changed_ids))
|
self.log.debug(
|
||||||
for zone_id in changed_ids:
|
"%s event: %s changed_ids: %s" , RoonTrigger.roon_state_callback.__qualname__, event, changed_ids
|
||||||
zone = self.roonapi.zones[zone_id]
|
)
|
||||||
self.log.info("zone_id:%s zone_info: %s" % (zone_id, zone))
|
self.set_status()
|
||||||
|
|
||||||
def run(self) -> bool:
|
|
||||||
self.roonapi.register_state_callback(self.my_state_callback)
|
|
||||||
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
async def async_run(self) -> None:
|
||||||
|
self.roonapi.register_state_callback(self.roon_state_callback, "zones_changed")
|
||||||
@@ -1,10 +1,12 @@
|
|||||||
from trigger import Trigger
|
from trigger import Trigger
|
||||||
from config import Config
|
from config import Config
|
||||||
|
import random
|
||||||
|
|
||||||
class TestTrigger1(Trigger):
|
class TestTrigger1(Trigger):
|
||||||
def __init__(self, _config: Config) -> None:
|
def __init__(self, _config: Config) -> None:
|
||||||
super().__init__(_config)
|
super().__init__(_config)
|
||||||
|
|
||||||
def run(self) -> bool:
|
def run(self) -> None:
|
||||||
|
choices = [False, True]
|
||||||
self.log.info("run check code of %s", self.__class__.__name__)
|
self.log.info("run check code of %s", self.__class__.__name__)
|
||||||
return False
|
self.active = random.choice(choices)
|
||||||
|
|||||||
Reference in New Issue
Block a user