Skip to content

Commit

Permalink
Added command_value to the item
Browse files Browse the repository at this point in the history
  • Loading branch information
spacemanspiff2007 committed Oct 17, 2024
1 parent 534acc7 commit bb7c6d4
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 17 deletions.
3 changes: 2 additions & 1 deletion run/conf_testing/rules/openhab/test_item_funcs.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,8 @@ class TestOpenhabItemConvenience(TestBaseRule):
def __init__(self) -> None:
super().__init__()

for name in ('oh_post_update', 'oh_send_command'):
# oh_send_command and command_value is the same for openhab items
for name in ('oh_post_update', 'oh_send_command', 'command_value'):
for k in get_openhab_test_types():
if name == 'oh_send_command' and k == 'Contact':
continue
Expand Down
35 changes: 22 additions & 13 deletions src/HABApp/core/items/base_valueitem.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import logging
import typing
from datetime import datetime
from math import ceil, floor
from typing import TYPE_CHECKING, Any

from whenever import Instant

from HABApp.core.const import MISSING
from HABApp.core.events import ValueChangeEvent, ValueUpdateEvent
from HABApp.core.events import ValueChangeEvent, ValueCommandEvent, ValueUpdateEvent
from HABApp.core.internals import uses_post_event
from HABApp.core.items.base_item import BaseItem
from HABApp.core.lib.funcs import compare as _compare


if typing.TYPE_CHECKING:
if TYPE_CHECKING:
datetime = datetime


Expand All @@ -33,9 +33,9 @@ class BaseValueItem(BaseItem):
def __init__(self, name: str, initial_value=None) -> None:
super().__init__(name)

self.value: typing.Any = initial_value
self.value: Any = initial_value

def set_value(self, new_value) -> bool:
def set_value(self, new_value: Any) -> bool:
"""Set a new value without creating events on the event bus
:param new_value: new value of the item
Expand All @@ -51,7 +51,7 @@ def set_value(self, new_value) -> bool:
self.value = new_value
return state_changed

def post_value(self, new_value) -> bool:
def post_value(self, new_value: Any) -> bool:
"""Set a new value and post appropriate events on the HABApp event bus
(``ValueUpdateEvent``, ``ValueChangeEvent``)
Expand All @@ -69,7 +69,16 @@ def post_value(self, new_value) -> bool:
)
return state_changed

def post_value_if(self, new_value, *, equal=MISSING, eq=MISSING, not_equal=MISSING, ne=MISSING,
def command_value(self, value: Any) -> None:
"""Send a ``ValueCommandEvent`` for the item to the HABApp event bus. A ``ValueCommandEvent`` is typically
used to indicate that the item should change the value.
E.g. a command "ON" to a dimmer might result in a brightness value of 100%.
:param value: the commanded value
"""
post_event(self._name, ValueCommandEvent(self._name, value))

def post_value_if(self, new_value: Any, *, equal=MISSING, eq=MISSING, not_equal=MISSING, ne=MISSING,
lower_than=MISSING, lt=MISSING, lower_equal=MISSING, le=MISSING,
greater_than=MISSING, gt=MISSING, greater_equal=MISSING, ge=MISSING,
is_=MISSING, is_not=MISSING) -> bool:
Expand Down Expand Up @@ -103,7 +112,7 @@ def post_value_if(self, new_value, *, equal=MISSING, eq=MISSING, not_equal=MISSI
return True
return False

def get_value(self, default_value=None) -> typing.Any:
def get_value(self, default_value=None) -> Any:
"""Return the value of the item. This is a helper function that returns a default
in case the item value is None.
Expand All @@ -122,23 +131,23 @@ def __repr__(self) -> str:

# only support == and != operators by default
# __ne__ delegates to __eq__ and inverts the result so this is not overloaded separately
def __eq__(self, other):
def __eq__(self, other: Any) -> bool:
return self.value == other

def __bool__(self) -> bool:
return bool(self.value)

# rich comparisons
def __lt__(self, other):
def __lt__(self, other: Any) -> bool:
return self.value < other

def __le__(self, other):
def __le__(self, other: Any) -> bool:
return self.value <= other

def __ge__(self, other):
def __ge__(self, other: Any) -> bool:
return self.value >= other

def __gt__(self, other):
def __gt__(self, other: Any) -> bool:
return self.value > other

# https://docs.python.org/3/reference/datamodel.html#emulating-numeric-types
Expand Down
11 changes: 11 additions & 0 deletions src/HABApp/openhab/items/base_item.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from typing import Any, NamedTuple

from immutables import Map
from typing_extensions import override

from HABApp.core.const import MISSING
from HABApp.core.items import BaseValueItem
Expand Down Expand Up @@ -55,6 +56,16 @@ def oh_send_command(self, value: Any = MISSING) -> None:
"""
send_command(self.name, self.value if value is MISSING else value)

# For the openhab items HABApp internal commands make not much sense
# so we send the commands to openHAB
@override
def command_value(self, value: Any) -> None:
"""Send a command to the openHAB item, the same as oh_send_command
:param value: (optional) value to be sent. If not specified the current item value will be used.
"""
send_command(self.name, value)

def oh_post_update(self, value: Any = MISSING) -> None:
"""Post an update to the openHAB item
Expand Down
20 changes: 19 additions & 1 deletion tests/test_core/test_items/item_tests.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import time
from unittest.mock import MagicMock

from whenever import Instant, patch_current_time

from HABApp.core.events import NoEventFilter, ValueCommandEvent
from HABApp.core.internals import ItemRegistry
from HABApp.core.items import Item
from HABApp.core.items.base_valueitem import datetime
from tests.helpers import TestEventBus


class ItemTests:
Expand Down Expand Up @@ -99,3 +101,19 @@ def test_post_if(self) -> None:
assert i.post_value_if(0, is_=None)
assert i.post_value_if(1, eq=0)
assert not i.post_value_if(1, eq=0)

def test_post_command(self, sync_worker, eb: TestEventBus) -> None:
i = self.get_item()

mock = MagicMock()
eb.listen_events(i.name, mock, NoEventFilter())
mock.assert_not_called()

value = self.ITEM_VALUES[0]
i.command_value(value)
mock.assert_called()

update = mock.call_args_list[0][0][0]
assert isinstance(update, ValueCommandEvent)
assert update.name == i.name
assert update.value == value
3 changes: 1 addition & 2 deletions tests/test_core/test_items/test_item.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from HABApp.core.items import Item

from . import ItemTests
from tests.test_core.test_items import ItemTests


class TestItem(ItemTests):
Expand Down

0 comments on commit bb7c6d4

Please sign in to comment.