Skip to content

Commit

Permalink
- Centralized openHAB datatype conversion
Browse files Browse the repository at this point in the history
- Reworked conversions
- Reworked ColorItem
  • Loading branch information
spacemanspiff2007 committed Jan 16, 2025
1 parent 1833257 commit c7c7c15
Show file tree
Hide file tree
Showing 76 changed files with 2,454 additions and 1,195 deletions.
5 changes: 2 additions & 3 deletions docs/advanced_usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -246,10 +246,9 @@ any internal item.

import HABApp
from HABApp.openhab.items import SwitchItem
from HABApp.openhab.definitions import OnOffValue

item = SwitchItem('my_switch', 'ON')
HABApp.core.Items.add_item(item)

item.set_value(OnOffValue.ON) # without bus event
item.post_value(OnOffValue.OFF) # with bus event
item.set_value('ON') # without bus event
item.post_value('OFF') # with bus event
43 changes: 0 additions & 43 deletions docs/parameters.rst
Original file line number Diff line number Diff line change
Expand Up @@ -74,49 +74,6 @@ Created file:
Changes in the file will be automatically picked up through :class:`~HABApp.parameters.Parameter`.


Validation
------------------------------
Since parameters used to provide flexible configuration for automation classes they can get quite complex and
error prone. Thus it is possible to provide a validator for a file which will check the files for constraints,
missing keys etc. when the file is loaded.

.. autofunction:: HABApp.parameters.set_file_validator

Example

.. exec_code::
:hide_output:

# ------------ hide: start ------------
from pathlib import Path

import HABApp
from HABApp.core.files.folders import add_folder
from HABApp.parameters.parameters import _PARAMETERS
from HABApp.parameters.parameter_files import PARAM_PREFIX

add_folder(PARAM_PREFIX, Path('/params'), 0)
_PARAMETERS['param_file_testrule'] = {'min_value': 10, 'Rule A': {'subkey1': {'subkey2': ['a', 'b', 'c']}}}
# ------------ hide: stop -------------
import HABApp
import voluptuous

# Validator can even and should be specified before loading rules

# allows a dict e.g. { 'key1': {'key2': '5}}
HABApp.parameters.set_file_validator('file1', {str: {str: int}})

# More complex example with an optional key:
validator = {
'Test': int,
'Key': {
'mandatory_key': str,
voluptuous.Optional('optional'): int
}
}
HABApp.parameters.set_file_validator('file1', validator)


Create rules from Parameters
------------------------------
Parameteres are not bound to rule instance and thus work everywhere in the rule file.
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
# Packages for source formatting
# -----------------------------------------------------------------------------
pre-commit == 4.0.1
ruff == 0.8.6
ruff == 0.9.1
autotyping == 24.9.0
# -----------------------------------------------------------------------------
# Packages for other developement tasks
Expand Down
6 changes: 3 additions & 3 deletions requirements_setup.txt
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
aiohttp == 3.11.11
pydantic == 2.10.4
pydantic == 2.10.5
bidict == 0.23.1
watchfiles == 1.0.3
watchfiles == 1.0.4
ujson == 5.10.0
aiomqtt == 2.3.0

eascheduler == 0.2.1
eascheduler == 0.2.2

immutables == 0.21
easyconfig == 0.4.0
Expand Down
2 changes: 1 addition & 1 deletion requirements_tests.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@
# -----------------------------------------------------------------------------
packaging == 24.2
pytest == 8.3.4
pytest-asyncio == 0.25.1
pytest-asyncio == 0.25.2
2 changes: 1 addition & 1 deletion run/conf_testing/lib/HABAppTests/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from .test_data import get_openhab_test_events, get_openhab_test_states, get_openhab_test_types
from .test_data import get_openhab_test_commands, get_openhab_test_states, get_openhab_item_names
from .utils import find_astro_sun_thing, get_random_name, get_random_string


Expand Down
4 changes: 2 additions & 2 deletions run/conf_testing/lib/HABAppTests/compare_values.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@


def get_bytes_text(value: object) -> object:
if isinstance(value, bytes) and len(value) > 300:
return b2a_hex(value[:40]).decode() + ' ... ' + b2a_hex(value[-40:]).decode()
if isinstance(value, bytes) and len(value) > 100:
return b2a_hex(value[:20]).decode() + ' ... ' + b2a_hex(value[-20:]).decode()
return value


Expand Down
4 changes: 3 additions & 1 deletion run/conf_testing/lib/HABAppTests/openhab_tmp_item.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
from functools import wraps
from time import monotonic
from types import TracebackType
from typing import Any, NotRequired, Self, TypedDict, Unpack
from typing import Any, NotRequired, TypedDict, Unpack

from typing_extensions import Self

import HABApp
from HABApp.core.asyncio import AsyncContextError, thread_context
Expand Down
259 changes: 222 additions & 37 deletions run/conf_testing/lib/HABAppTests/test_data.py

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion run/conf_testing/lib/HABAppTests/test_rule/test_rule.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import logging
from collections.abc import Callable, Coroutine
from enum import Enum, auto
from typing import Any, Self, overload
from typing import Any, overload

from typing_extensions import Self

import HABApp
from HABAppTests.test_rule.test_case import TestCase, TestResult, run_test_cases
Expand Down
2 changes: 1 addition & 1 deletion run/conf_testing/lib/HABAppTests/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

__RAND_PREFIX = {
'String': 'Str', 'Number': 'Num', 'Switch': 'Sw', 'Contact': 'Con', 'Dimmer': 'Dim', 'Rollershutter': 'Rol',
'Color': 'Col', 'DateTime': 'Dt', 'Location': 'Loc', 'Player': 'Pl', 'Group': 'Grp', 'Image': 'Img',
'Color': 'Col', 'DateTime': 'Dt', 'Location': 'Loc', 'Player': 'Pl', 'Group': 'Grp', 'Image': 'Img', 'Call': 'Call',
'HABApp': 'Ha'
}

Expand Down
2 changes: 1 addition & 1 deletion run/conf_testing/rules/habapp/test_habapp.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ def tear_down(self) -> None:
self.listener.cancel()

def trigger_event(self) -> None:
self.run.at(
self.run.once(
1, self.post_event, self.watch_item.name, ValueUpdateEvent(self.watch_item.name, 123)
)

Expand Down
58 changes: 0 additions & 58 deletions run/conf_testing/rules/openhab/test_event_types.py

This file was deleted.

39 changes: 21 additions & 18 deletions run/conf_testing/rules/openhab/test_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,14 @@
# ----------------------------------------------------------------------------------------------------------------------
import time

from HABApp.openhab.events import ItemCommandEvent, ItemCommandEventFilter
from HABAppTests import (
ItemWaiter,
OpenhabTmpItem,
TestBaseRule,
get_openhab_test_states,
get_openhab_test_types,
get_random_name,
get_openhab_item_names,
get_random_name, get_openhab_test_commands, EventWaiter,
)

import HABApp
Expand All @@ -35,8 +36,12 @@ def __init__(self) -> None:
self.add_test('Interface change type', self.test_item_change_type)

# test the states
for oh_type in get_openhab_test_types():
self.add_test(f'post_update {oh_type}', self.test_post_update, oh_type, get_openhab_test_states(oh_type))
for oh_type in get_openhab_item_names():
self.add_test(
f'update and commands {oh_type}', self.test_post_update, oh_type,
get_openhab_test_states(oh_type, only_generic_states=True),
get_openhab_test_commands(oh_type, only_generic_commands=True)
)

# test json post
self.add_test('post_update (by_json)', self.test_umlaute)
Expand All @@ -50,7 +55,7 @@ def test_item_exists(self) -> None:

def test_item_create_delete(self) -> None:
test_defs = []
for type in get_openhab_test_types():
for type in get_openhab_item_names():
test_defs.append((type, get_random_name(type)))
# test_defs.append(('Number', 'HABApp_Ping'))

Expand Down Expand Up @@ -103,19 +108,17 @@ def test_item_create_delete_group(self) -> None:
self.openhab.remove_item(test_group)
self.openhab.remove_item(test_item)

def test_post_update(self, oh_type, values) -> None:
if isinstance(values, str):
values = [values]
def test_post_update(self, oh_type, post_updates, send_commands) -> None:

with OpenhabTmpItem(oh_type) as item, ItemWaiter(item) as waiter:
for value in values:
self.openhab.post_update(item, value)
waiter.wait_for_state(value)

for value in values:
if oh_type != 'Contact':
self.openhab.send_command(item, value)
waiter.wait_for_state(value)
with OpenhabTmpItem(oh_type) as item:
with ItemWaiter(item) as waiter:
for post_value, receive_value in post_updates:
self.openhab.post_update(item, post_value)
waiter.wait_for_state(receive_value)
with EventWaiter(item, ItemCommandEventFilter()) as waiter:
for post_command, receive_command in send_commands:
self.openhab.send_command(item, post_command)
waiter.wait_for_event(value=receive_command)

@OpenhabTmpItem.use('String')
def test_umlaute(self, item: OpenhabTmpItem) -> None:
Expand Down Expand Up @@ -143,7 +146,7 @@ def test_async_oder(self) -> None:
with OpenhabTmpItem('String', 'AsyncOrderTest') as item, ItemWaiter(item) as waiter:
for _ in range(10):
for i in range(5):
item.oh_post_update(i)
item.oh_post_update(str(i))
waiter.wait_for_state('4')


Expand Down
68 changes: 68 additions & 0 deletions run/conf_testing/rules/openhab/test_item_events.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import time

from HABAppTests import (
EventWaiter,
ItemWaiter,
OpenhabTmpItem,
TestBaseRule,
get_openhab_item_names,
get_openhab_test_commands,
get_openhab_test_states,
)

from HABApp.core.events import ValueUpdateEventFilter
from HABApp.openhab.events import ItemCommandEventFilter


class TestOpenhabEventTypes(TestBaseRule):
"""This rule is testing the OpenHAB data types by posting values and checking the events"""

def __init__(self) -> None:
super().__init__()

for oh_type in get_openhab_item_names():
self.add_test(
f'{oh_type} updates', self.test_item, oh_type,
get_openhab_test_states(oh_type), get_openhab_test_commands(oh_type)
)

dimensions = {
'Length': 'm', 'Temperature': '°C', 'Pressure': 'hPa', 'Speed': 'km/h', 'Intensity': 'W/m²', 'Angle': '°',
'Dimensionless': '',
}
for name, unit in dimensions.items():
self.add_test(f'Quantity {name} events', self.test_quantity_type_events, name, unit)

def test_item(self, item_type: str, test_states: tuple, test_commands: tuple) -> None:
item_name = f'{item_type}_value_test'

with (OpenhabTmpItem(item_type, item_name) as item,
EventWaiter(item_name, ValueUpdateEventFilter()) as state_waiter,
EventWaiter(item_name, ItemCommandEventFilter()) as command_waiter):
for post_value, receive_value in test_states:
item.oh_post_update(post_value)
state_waiter.wait_for_event(value=receive_value)

for send_command, receive_value in test_commands:
item.oh_send_command(send_command)
command_waiter.wait_for_event(value=receive_value)

for send_command, receive_value in test_commands:
item.command_value(send_command)
command_waiter.wait_for_event(value=receive_value)

def test_quantity_type_events(self, dimension, unit) -> None:
item_name = f'{dimension}_event_test'
with OpenhabTmpItem(f'Number:{dimension}', item_name) as item, \
EventWaiter(item_name, ValueUpdateEventFilter()) as event_waiter, \
ItemWaiter(item) as item_waiter:

for state_send, state_receive in get_openhab_test_states('Number'):
if state_receive is None:
continue
self.openhab.post_update(item_name, f'{state_send} {unit}'.strip())
event_waiter.wait_for_event(value=state_receive)
item_waiter.wait_for_state(state_receive)


TestOpenhabEventTypes()
54 changes: 9 additions & 45 deletions run/conf_testing/rules/openhab/test_item_funcs.py

Large diffs are not rendered by default.

Loading

0 comments on commit c7c7c15

Please sign in to comment.