From 494ba80e887adc24f2dc350eea43056d2584c8cf Mon Sep 17 00:00:00 2001 From: martin Date: Tue, 17 Dec 2024 20:48:00 +0100 Subject: [PATCH] improved trigger code --- config.py | 3 +++ cpu_governor_auto_adjust.xml | 3 +++ schedule.py | 18 +++++++++++++--- trigger.py | 22 +++++++++++++++----- triggers/roon.py | 40 +++++++++++++++++++++--------------- triggers/test_trigger1.py | 6 ++++-- 6 files changed, 66 insertions(+), 26 deletions(-) diff --git a/config.py b/config.py index a8eaa4e..f364c73 100644 --- a/config.py +++ b/config.py @@ -10,6 +10,7 @@ import xmltodict class TriggerTuple(NamedTuple): name: str + type: str interval_in_seconds: int governor: str custom_config: OrderedDict[str, Any] @@ -68,6 +69,7 @@ class Config: _trigger_elements = self._get_multiple_elements_by_xpath('triggers/trigger') for trigger_elem in _trigger_elements: 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) governor = self._get_single_text_value_from_xpath('governor', trigger_elem) try: @@ -78,6 +80,7 @@ class Config: custom_config = OrderedDict({}) _new_trigger = TriggerTuple( name=name, + type=type, interval_in_seconds=int(interval_in_seconds), governor=governor, custom_config=custom_config diff --git a/cpu_governor_auto_adjust.xml b/cpu_governor_auto_adjust.xml index 2760b18..b90245b 100644 --- a/cpu_governor_auto_adjust.xml +++ b/cpu_governor_auto_adjust.xml @@ -5,16 +5,19 @@ test_trigger1 + run_once 1 ondemand test_trigger2 + run_once 3 conservative roon + callback 2 performance diff --git a/schedule.py b/schedule.py index 9293683..60334ae 100644 --- a/schedule.py +++ b/schedule.py @@ -10,16 +10,28 @@ class TriggerScheduler(AppClass): super().__init__(_config) 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.""" while True: - self.log.debug("Trigger %s is running", _trigger.name) _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) def start_trigger(self, _trigger: Trigger) -> None: """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) async def stop_triggers(self) -> None: diff --git a/trigger.py b/trigger.py index ba073d1..8240b91 100644 --- a/trigger.py +++ b/trigger.py @@ -6,6 +6,7 @@ from exceptions import MissingConfig, TriggerImportError class Trigger(AppClass): def __init__(self, _config: Config) -> None: super().__init__(_config) + self.active: bool = False @property def name(self) -> str: @@ -23,8 +24,19 @@ class Trigger(AppClass): raise MissingConfig(f"Trigger {self.name} hasn't been properly configured") return _config - def run(self) -> bool: - # return True if Trigger is valid - raise TriggerImportError( - "the Trigger class can't used directly, but must be inherited in a trigger specific class" - ) + def run(self) -> None: + # this is the main function of the trigger class and has to stay active by using a while True loop + + while True: + raise TriggerImportError( + "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" + ) + \ No newline at end of file diff --git a/triggers/roon.py b/triggers/roon.py index b88ba1e..9e8df84 100644 --- a/triggers/roon.py +++ b/triggers/roon.py @@ -2,7 +2,7 @@ from trigger import Trigger from config import Config from roonapi import RoonApi, RoonDiscovery # type: ignore from functools import cached_property -from typing import Any, NamedTuple +from typing import Any, NamedTuple, Union from pathlib import Path @@ -16,11 +16,22 @@ class RoonServer(NamedTuple): class RoonTrigger(Trigger): def __init__(self, _config: Config) -> None: super().__init__(_config) + self.set_status() - @property - def playing(self) -> bool: - return False - + def set_status(self) -> None: + zones_state = list() + + 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 def appinfo(self) -> dict[str, Any]: _appinfo = { @@ -69,15 +80,12 @@ class RoonTrigger(Trigger): _roonapi = RoonApi(self.appinfo, self.token, self.server.ip, self.server.port, True) 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.""" - self.log.info("my_state_callback event:%s changed_ids: %s" % (event, changed_ids)) - for zone_id in changed_ids: - zone = self.roonapi.zones[zone_id] - self.log.info("zone_id:%s zone_info: %s" % (zone_id, zone)) - - def run(self) -> bool: - self.roonapi.register_state_callback(self.my_state_callback) - - return False - \ No newline at end of file + self.log.debug( + "%s event: %s changed_ids: %s" , RoonTrigger.roon_state_callback.__qualname__, event, changed_ids + ) + self.set_status() + + async def async_run(self) -> None: + self.roonapi.register_state_callback(self.roon_state_callback, "zones_changed") \ No newline at end of file diff --git a/triggers/test_trigger1.py b/triggers/test_trigger1.py index 397f25f..6bb6b9e 100644 --- a/triggers/test_trigger1.py +++ b/triggers/test_trigger1.py @@ -1,10 +1,12 @@ from trigger import Trigger from config import Config +import random class TestTrigger1(Trigger): def __init__(self, _config: Config) -> None: 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__) - return False + self.active = random.choice(choices)