Skip to content

Commit

Permalink
stop timer of StateMachineRule
Browse files Browse the repository at this point in the history
  • Loading branch information
nobbi1991 committed Nov 20, 2023
1 parent ff204f5 commit 56d9759
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 1 deletion.
1 change: 1 addition & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
## Bugfix

- only use items (instead item names) for ``habapp_rules.core.helper.send_if_different``
- cancel timer / timeouts of replaced rules

# Version 5.2.1 - 17.10.2023

Expand Down
10 changes: 10 additions & 0 deletions habapp_rules/core/state_machine_rule.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import inspect
import os
import pathlib
import threading

import HABApp
import HABApp.openhab.connection.handler.func_sync
Expand Down Expand Up @@ -34,6 +35,7 @@ def __init__(self, state_item_name: str | None = None, state_item_label: str | N
:param state_item_name: name of the item to hold the state
:param state_item_label: OpenHAB label of the state_item; This will be used if the state_item will be created by HABApp
"""
self.state_machine: transitions.Machine | None = None
HABApp.Rule.__init__(self)

# get prefix for items
Expand Down Expand Up @@ -83,3 +85,11 @@ def _set_state(self, state_name: str) -> None:
def _update_openhab_state(self) -> None:
"""Update OpenHAB state item. This should method should be set to "after_state_change" of the state machine."""
self._item_state.oh_send_command(self.state)

def on_rule_removed(self) -> None:
"""Override this to implement logic that will be called when the rule has been unloaded."""
# stop timeout timer of current state
if self.state_machine:
for itm in self.state_machine.states[self.state].runner.values():
if isinstance(itm, threading.Timer) and itm.is_alive():
itm.cancel()
8 changes: 8 additions & 0 deletions habapp_rules/system/presence.py
Original file line number Diff line number Diff line change
Expand Up @@ -193,3 +193,11 @@ def __set_leaving_through_phone(self) -> None:
self._instance_logger.debug("Leaving was set, because last phone left some time ago.")
self.leaving_detected()
self.__phone_absence_timer = None

def on_rule_removed(self) -> None:
habapp_rules.core.state_machine_rule.StateMachineRule.on_rule_removed(self)

# stop phone absence timer
if self.__phone_absence_timer:
self.__phone_absence_timer.cancel()
self.__phone_absence_timer = None
32 changes: 32 additions & 0 deletions tests/core/state_machine_rule.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""Unit-test for state_machine."""
import collections
import time
import unittest
import unittest.mock

Expand Down Expand Up @@ -62,3 +63,34 @@ def test_update_openhab_state(self):
with unittest.mock.patch.object(self._state_machine, "_item_state") as state_item:
self._state_machine._update_openhab_state()
state_item.oh_send_command.assert_called_once_with("some_state")

def test_on_rule_removed(self):
"""Test on_rule_removed."""
# check if 'on_rule_removed' is still available in HABApp
getattr(HABApp.rule.Rule, "on_rule_removed")

# check if timer is stopped correctly
states = [
{"name": "stopped"},
{"name": "running", "timeout": 99, "on_timeout": "trigger_stop"}
]

with unittest.mock.patch("habapp_rules.core.helper.create_additional_item", return_value=HABApp.openhab.items.string_item.StringItem("rules_common_state_machine_rule_StateMachineRule_state", "")):
for initial_state in ["stopped", "running"]:
state_machine_rule = habapp_rules.core.state_machine_rule.StateMachineRule()

state_machine_rule.state_machine = habapp_rules.core.state_machine_rule.StateMachineWithTimeout(
model=state_machine_rule,
states=states,
ignore_invalid_triggers=True)

state_machine_rule._set_state(initial_state)

if initial_state == "running":
self.assertTrue(list(state_machine_rule.state_machine.states["running"].runner.values())[0].is_alive())

state_machine_rule.on_rule_removed()

if initial_state == "running":
time.sleep(0.001)
self.assertFalse(list(state_machine_rule.state_machine.states["running"].runner.values())[0].is_alive())
20 changes: 19 additions & 1 deletion tests/system/presence.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ def setUp(self) -> None:
tests.helper.oh_item.add_mock_item(HABApp.openhab.items.StringItem, "H_Presence_Unittest_Presence_state", "")
tests.helper.oh_item.add_mock_item(HABApp.openhab.items.SwitchItem, "Unittest_Presence", "ON")

self._presence = habapp_rules.system.presence.Presence("Unittest_Presence", outside_door_names=["Unittest_Door1", "Unittest_Door2"], leaving_name="Unittest_Leaving", phone_names=["Unittest_Phone1", "Unittest_Phone2"], name_state="CustomState")
self._presence = habapp_rules.system.presence.Presence("Unittest_Presence", outside_door_names=["Unittest_Door1", "Unittest_Door2"], leaving_name="Unittest_Leaving", phone_names=["Unittest_Phone1", "Unittest_Phone2"],
name_state="CustomState")

@unittest.skipIf(sys.platform != "win32", "Should only run on windows when graphviz is installed")
def test_create_graph(self): # pragma: no cover
Expand Down Expand Up @@ -392,3 +393,20 @@ def test_phones(self):
# timeout is over -> absence expected
tests.helper.timer.call_timeout(self.transitions_timer_mock)
self.assertEqual(self._presence.state, "absence")

def test_on_rule_removed(self):
"""Test on_rule_removed."""
# timer NOT running
with unittest.mock.patch("habapp_rules.core.state_machine_rule.StateMachineRule.on_rule_removed") as parent_on_remove:
self._presence.on_rule_removed()

parent_on_remove.assert_called_once()

# timer running
self._presence._Presence__phone_absence_timer = threading.Timer(42, unittest.mock.MagicMock())
self._presence._Presence__phone_absence_timer.start()
with unittest.mock.patch("habapp_rules.core.state_machine_rule.StateMachineRule.on_rule_removed") as parent_on_remove:
self._presence.on_rule_removed()

parent_on_remove.assert_called_once()
self.assertIsNone(self._presence._Presence__phone_absence_timer)

0 comments on commit 56d9759

Please sign in to comment.