Skip to content

Commit

Permalink
feat(controller): add mode parameter
Browse files Browse the repository at this point in the history
adds the possibility to user to define what to do in case of an action still being executed. Based on HA automation modes.

related to #242
  • Loading branch information
xaviml committed Feb 7, 2021
1 parent 173304c commit ab9dfce
Show file tree
Hide file tree
Showing 9 changed files with 92 additions and 17 deletions.
40 changes: 37 additions & 3 deletions apps/controllerx/cx_core/controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@
DEFAULT_MULTIPLE_CLICK_DELAY = 500 # In milliseconds
MULTIPLE_CLICK_TOKEN = "$"

MODE_SINGLE = "single"
MODE_RESTART = "restart"
MODE_QUEUED = "queued"
MODE_PARALLEL = "parallel"

T = TypeVar("T")


Expand Down Expand Up @@ -151,6 +156,11 @@ async def init(self) -> None:
self.click_counter = Counter()
self.multiple_click_action_delay_tasks = defaultdict(lambda: None)

# Mode
self.mode = self.get_mapping_per_action(
self.actions_mapping, custom=self.args.get("mode"), default=MODE_SINGLE
)

# Listen for device changes
for controller_id in controllers_ids:
self.integration.listen_changes(controller_id)
Expand Down Expand Up @@ -348,14 +358,38 @@ async def call_action(
else:
await self.action_timer_callback({"action_key": action_key, "extra": extra})

async def _apply_mode_strategy(self, action_key: ActionEvent) -> bool:
previous_task = self.action_handles[action_key]
if previous_task is None:
return False
if self.mode[action_key] == MODE_SINGLE:
self.log(
"There is already an action executing for `action_key`. "
"If you want a different behaviour change `mode` parameter.",
level="WARNING",
)
return True
elif self.mode[action_key] == MODE_RESTART:
previous_task.cancel()
elif self.mode[action_key] == MODE_QUEUED:
await previous_task
elif self.mode[action_key] == MODE_PARALLEL:
pass
else:
raise ValueError(
f"`{self.mode[action_key]}` is not a possible value for `mode` parameter."
"Possible values: `single`, `restart`, `queued` and `parallel`."
)
return False

async def action_timer_callback(self, kwargs: Dict[str, Any]):
action_key: ActionEvent = kwargs["action_key"]
extra: EventData = kwargs["extra"]
self.action_delay_handles[action_key] = None
skip = await self._apply_mode_strategy(action_key)
if skip:
return
action_types = self.actions_mapping[action_key]
previous_task = self.action_handles[action_key]
if previous_task is not None:
previous_task.cancel()
task = asyncio.ensure_future(self.call_action_types(action_types, extra))
self.action_handles[action_key] = task
try:
Expand Down
9 changes: 0 additions & 9 deletions tests/integ_tests/action-types/brightness_down_hold_test.yaml

This file was deleted.

4 changes: 0 additions & 4 deletions tests/integ_tests/action-types/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,4 @@ livingroom_controller:
- action: toggle
- delay: 1
- scene: scene.my_other_scene
- service: my_other_service
brightness_down_hold:
- service: my_service
- delay: 1
- service: my_other_service
27 changes: 27 additions & 0 deletions tests/integ_tests/controller-modes/config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
livingroom_controller:
module: controllerx
class: Controller
controller: my_controller
integration: z2m
mode:
action_single: single
action_restart: restart
action_queued: queued
action_parallel: parallel
mapping:
action_single:
- service: my_service
- delay: 1
- service: my_other_service
action_restart:
- service: my_service
- delay: 1
- service: my_other_service
action_queued:
- service: my_service
- delay: 1
- service: my_other_service
action_parallel:
- service: my_service
- delay: 1
- service: my_other_service
7 changes: 7 additions & 0 deletions tests/integ_tests/controller-modes/parallel_mode_test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Testing the parallel mode task functionality
fired_actions: [action_parallel, 0.4, action_parallel]
expected_calls:
- service: my_service
- service: my_service
- service: my_other_service
- service: my_other_service
7 changes: 7 additions & 0 deletions tests/integ_tests/controller-modes/queued_mode_test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Testing the queued mode task functionality
fired_actions: [action_queued, 0.4, action_queued]
expected_calls:
- service: my_service
- service: my_other_service
- service: my_service
- service: my_other_service
6 changes: 6 additions & 0 deletions tests/integ_tests/controller-modes/restart_mode_test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Testing the restart mode task functionality
fired_actions: [action_restart, 0.4, action_restart]
expected_calls:
- service: my_service
- service: my_service
- service: my_other_service
5 changes: 5 additions & 0 deletions tests/integ_tests/controller-modes/single_mode_test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Testing the single mode task functionality
fired_actions: [action_single, 0.4, action_single]
expected_calls:
- service: my_service
- service: my_other_service
4 changes: 3 additions & 1 deletion tests/integ_tests/integ_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import pytest
import yaml
from appdaemon.plugins.hass.hassapi import Hass # type: ignore
from cx_core.type_controller import TypeController
from pytest_mock.plugin import MockerFixture

from tests.test_utils import get_controller
Expand Down Expand Up @@ -59,7 +60,8 @@ async def test_integ_configs(
controller.args = config

fake_entity_states = get_fake_entity_states(entity_state, entity_state_attributes)
mocker.patch.object(controller, "get_entity_state", fake_entity_states)
if isinstance(controller, TypeController):
mocker.patch.object(controller, "get_entity_state", fake_entity_states)
call_service_stub = mocker.patch.object(Hass, "call_service")

await controller.initialize()
Expand Down

0 comments on commit ab9dfce

Please sign in to comment.