Skip to content

Commit

Permalink
fix(action-type): restart actions when called again
Browse files Browse the repository at this point in the history
  • Loading branch information
xaviml committed Jan 9, 2021
1 parent 5f04958 commit 9c01a8f
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,15 @@ def initialize(self, **kwargs) -> None:
self.predefined_actions_mapping = (
self.controller.get_predefined_actions_mapping()
)
if not self.predefined_actions_mapping:
raise ValueError(
f"Cannot use predefined actions for `{self.controller.__class__.__name__}` class."
)
if self.action_key not in self.predefined_actions_mapping:
raise ValueError(
f"`{self.action_key}` is not one of the predefined actions."
f"Available actions are: {list(self.predefined_actions_mapping.keys())}"
f"`{self.action_key}` is not one of the predefined actions. "
f"Available actions are: {list(self.predefined_actions_mapping.keys())}."
"See more in: https://xaviml.github.io/controllerx/others/custom-controllers"
)

async def run(self, extra: Optional[EventData] = None) -> None:
Expand Down
24 changes: 23 additions & 1 deletion apps/controllerx/cx_core/controller.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import asyncio
import time
from asyncio import CancelledError
from asyncio.futures import Future
from collections import defaultdict
from functools import wraps
Expand Down Expand Up @@ -29,6 +30,7 @@
)
from cx_core import integration as integration_module
from cx_core.action_type import ActionsMapping, parse_actions
from cx_core.action_type.base import ActionType
from cx_core.integration import EventData, Integration

Service = Tuple[str, Dict]
Expand Down Expand Up @@ -76,13 +78,14 @@ class Controller(Hass, Mqtt):

integration: Integration
actions_mapping: ActionsMapping
action_handles: Dict[ActionEvent, Optional[Future]]
action_delay_handles: Dict[ActionEvent, Optional[float]]
multiple_click_actions: Set[ActionEvent]
action_delay: Dict[ActionEvent, int]
action_delta: int
action_times: Dict[str, float]
multiple_click_action_times: Dict[str, float]
click_counter: Counter[ActionEvent]
action_delay_handles: Dict[ActionEvent, Optional[float]]
multiple_click_action_delay_tasks: Dict[ActionEvent, Optional[Future]]
multiple_click_delay: int

Expand Down Expand Up @@ -129,6 +132,7 @@ async def init(self) -> None:
**self.args.get("action_delay", {}),
}
self.action_delay_handles = defaultdict(lambda: None)
self.action_handles = defaultdict(lambda: None)

# Action delta
self.action_delta = self.args.get("action_delta", DEFAULT_ACTION_DELTA)
Expand Down Expand Up @@ -333,6 +337,24 @@ async def action_timer_callback(self, kwargs: Dict[str, Any]):
extra: EventData = kwargs["extra"]
self.action_delay_handles[action_key] = None
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:
await task
except CancelledError:
self.log(
f"Task(s) from `{action_key}` was/were cancelled and executed again",
level="DEBUG",
)
else:
self.action_handles[action_key] = None

async def call_action_types(
self, action_types: List[ActionType], extra: Optional[EventData] = None
) -> None:
for action_type in action_types:
self.log(
f"🏃 Running `{action_type}` now",
Expand Down
9 changes: 9 additions & 0 deletions tests/integ_tests/action-types/brightness_down_hold_test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Testing the restart task functionality
entity_state_attributes:
supported_features: 191
entity_state: "off"
fired_actions: [brightness_down_hold, 0.4, brightness_down_hold]
expected_calls:
- service: my_service
- service: my_service
- service: my_other_service
4 changes: 4 additions & 0 deletions tests/integ_tests/action-types/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,7 @@ livingroom_controller:
- delay: 1
- scene: scene.my_other_scene
- service: my_other_service
brightness_down_hold:
- service: my_service
- delay: 1
- service: my_other_service
9 changes: 2 additions & 7 deletions tests/unit_tests/cx_core/custom_controller_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,12 +151,7 @@ async def test_call_service_controller(
"integration": integration,
"mapping": {"action": services},
}
call_service_stub = mocker.stub()

async def fake_call_service(self, service, **data):
call_service_stub(service, **data)

monkeypatch.setattr(Hass, "call_service", fake_call_service)
call_service_stub = mocker.patch.object(Hass, "call_service")

# SUT
await sut.initialize()
Expand All @@ -166,4 +161,4 @@ async def fake_call_service(self, service, **data):
# Checks
assert call_service_stub.call_count == len(expected_calls)
for expected_service, expected_data in expected_calls:
call_service_stub.assert_any_call(expected_service, **expected_data)
call_service_stub.assert_any_call(sut, expected_service, **expected_data)

0 comments on commit 9c01a8f

Please sign in to comment.