From e124fca8ba1ad729d32a91c5feff2b8c7a1cb613 Mon Sep 17 00:00:00 2001 From: spacemanspiff2007 Date: Sun, 5 Jul 2020 06:21:05 +0200 Subject: [PATCH] 0.14.1 (#158) 0.14.1 - Added Number:Dimensionless as a unit of measurement (closes #157 ) - made z-wave table more robust --- HABApp/__version__.py | 2 +- HABApp/openhab/connection_handler/func_sync.py | 4 ++-- .../connection_logic/plugin_thing_overview.py | 12 ++++++++---- HABApp/openhab/definitions/__init__.py | 2 +- HABApp/openhab/definitions/definitions.py | 2 +- HABApp/openhab/definitions/values.py | 4 +++- HABApp/openhab/map_items.py | 2 +- HABApp/rule/scheduler/base.py | 12 +++++++----- conf_testing/rules/test_openhab_event_types.py | 4 ++-- tests/test_openhab/test_items/test_mapping.py | 11 +++++++++++ tests/test_openhab/test_values.py | 7 ++++--- 11 files changed, 41 insertions(+), 21 deletions(-) diff --git a/HABApp/__version__.py b/HABApp/__version__.py index 7eba0360..a134b77b 100644 --- a/HABApp/__version__.py +++ b/HABApp/__version__.py @@ -1 +1 @@ -__version__ = '0.14.0' +__version__ = '0.14.1' diff --git a/HABApp/openhab/connection_handler/func_sync.py b/HABApp/openhab/connection_handler/func_sync.py index f7055170..976754b5 100644 --- a/HABApp/openhab/connection_handler/func_sync.py +++ b/HABApp/openhab/connection_handler/func_sync.py @@ -73,8 +73,8 @@ def validate(_in): # limit values to special entries and validate parameters if ':' in item_type: __type, __unit = item_type.split(':') - assert __unit in definitions.ITEM_DIMENSION, \ - f'{__unit} is not a valid Openhab unit: {", ".join(definitions.ITEM_DIMENSION)}' + assert __unit in definitions.ITEM_DIMENSIONS, \ + f'{__unit} is not a valid Openhab unit: {", ".join(definitions.ITEM_DIMENSIONS)}' assert __type in definitions.ITEM_TYPES, \ f'{__type} is not a valid OpenHAB type: {", ".join(definitions.ITEM_TYPES)}' else: diff --git a/HABApp/openhab/connection_logic/plugin_thing_overview.py b/HABApp/openhab/connection_logic/plugin_thing_overview.py index d8db0d78..fe135685 100644 --- a/HABApp/openhab/connection_logic/plugin_thing_overview.py +++ b/HABApp/openhab/connection_logic/plugin_thing_overview.py @@ -64,19 +64,23 @@ async def on_connect_function(self): if not is_zw: continue + # optional properties which can be set props = node['properties'] channels = node.get('channels', []) - zw_node.add(int(props['zwave_nodeid'])) + # Node-ID, e.g. 5 + node_id = props.get('zwave_nodeid') + zw_node.add(int(node_id) if node_id is not None else '') - # optional properties zw_model.add(props.get('modelId', '')) zw_fw.add(props.get('zwave_version', '')) zw_l_channels.add( - ', '.join(map(lambda x: x.get('channelTypeUID', ''), filter(lambda x: x.get('linkedItems'), channels)))) + ', '.join(map(lambda x: x.get('channelTypeUID', ''), filter(lambda x: x.get('linkedItems'), channels))) + ) zw_u_channels.add(', '.join( - map(lambda x: x.get('channelTypeUID', ''), filter(lambda x: not x.get('linkedItems'), channels)))) + map(lambda x: x.get('channelTypeUID', ''), filter(lambda x: not x.get('linkedItems'), channels))) + ) log = logging.getLogger('HABApp.openhab.things') for line in thing_table.get_lines(sort_columns=[thing_uid]): diff --git a/HABApp/openhab/definitions/__init__.py b/HABApp/openhab/definitions/__init__.py index 9dd42ee3..ca77ced4 100644 --- a/HABApp/openhab/definitions/__init__.py +++ b/HABApp/openhab/definitions/__init__.py @@ -1,3 +1,3 @@ -from .definitions import ITEM_TYPES, ITEM_DIMENSION, GROUP_FUNCTIONS +from .definitions import ITEM_TYPES, ITEM_DIMENSIONS, GROUP_FUNCTIONS from .values import OnOffValue, PercentValue, UpDownValue, HSBValue, QuantityValue, OpenClosedValue, RawValue from . import rest diff --git a/HABApp/openhab/definitions/definitions.py b/HABApp/openhab/definitions/definitions.py index 8bf6765e..c2c4698d 100644 --- a/HABApp/openhab/definitions/definitions.py +++ b/HABApp/openhab/definitions/definitions.py @@ -3,6 +3,6 @@ 'Color', 'DateTime', 'Location', 'Player', 'Group', 'Image', } -ITEM_DIMENSION = {'Length', 'Temperature', 'Pressure', 'Speed', 'Intensity', 'Angle'} +ITEM_DIMENSIONS = {'Length', 'Temperature', 'Pressure', 'Speed', 'Intensity', 'Angle', 'Dimensionless'} GROUP_FUNCTIONS = {'AND', 'OR', 'NAND', 'NOR', 'AVG', 'MAX', 'MIN', 'SUM'} diff --git a/HABApp/openhab/definitions/values.py b/HABApp/openhab/definitions/values.py index 44b927d9..dc592cbb 100644 --- a/HABApp/openhab/definitions/values.py +++ b/HABApp/openhab/definitions/values.py @@ -66,7 +66,9 @@ class QuantityValue(ComplexEventValue): @staticmethod def split_unit(value: str) -> typing.Tuple[str, str]: p = value.rfind(' ') - assert p >= 0, f'No unit separator found for QuantityValue in "{value}"' + # dimensionless has no unit + if p < 0: + return value, '' val = value[0:p] unit = value[p + 1:] return val, unit diff --git a/HABApp/openhab/map_items.py b/HABApp/openhab/map_items.py index 09b7ebb2..bf86f2f0 100644 --- a/HABApp/openhab/map_items.py +++ b/HABApp/openhab/map_items.py @@ -23,7 +23,7 @@ def map_items(name, openhab_type: str, openhab_value: str) -> typing.Optional[Ba # Quantity types are like this: Number:Temperature and have a unit set: "12.3 °C". # We have to remove the dimension from the type and remove the unit from the value if ':' in openhab_type: - openhab_type = openhab_type[:openhab_type.find(':')] + openhab_type, dimension = openhab_type.split(':') # if the item is not initialized its None and has no dimension if value is not None: value, _ = QuantityValue.split_unit(value) diff --git a/HABApp/rule/scheduler/base.py b/HABApp/rule/scheduler/base.py index bc75b9ff..e043b1fe 100644 --- a/HABApp/rule/scheduler/base.py +++ b/HABApp/rule/scheduler/base.py @@ -70,7 +70,7 @@ def _calculate_next_call(self): raise NotImplementedError() def earliest(self, time_obj: typing.Optional[time]) -> 'ScheduledCallbackBase': - """Set earliest boundary as time of day + """Set earliest boundary as time of day. ``None`` will disable boundary. :param time_obj: time obj, scheduler will not run earlier """ @@ -82,7 +82,7 @@ def earliest(self, time_obj: typing.Optional[time]) -> 'ScheduledCallbackBase': return self def latest(self, time_obj: typing.Optional[time]) -> 'ScheduledCallbackBase': - """Set earliest boundary as time of day + """Set earliest boundary as time of day. ``None`` will disable boundary. :param time_obj: time obj, scheduler will not run later """ @@ -94,7 +94,7 @@ def latest(self, time_obj: typing.Optional[time]) -> 'ScheduledCallbackBase': return self def offset(self, timedelta_obj: typing.Optional[timedelta]) -> 'ScheduledCallbackBase': - """Set a constant offset to the calculation of the next run + """Set a constant offset to the calculation of the next run. ``None`` will disable the offset. :param timedelta_obj: constant offset """ @@ -106,7 +106,8 @@ def offset(self, timedelta_obj: typing.Optional[timedelta]) -> 'ScheduledCallbac return self def jitter(self, secs: typing.Optional[int]) -> 'ScheduledCallbackBase': - """Add a random jitter per call in the intervall [(-1) * secs ... secs] to the next run + """Add a random jitter per call in the intervall [(-1) * secs ... secs] to the next run. + ``None`` will disable jitter. :param secs: jitter in secs """ @@ -118,7 +119,8 @@ def jitter(self, secs: typing.Optional[int]) -> 'ScheduledCallbackBase': return self def boundary_func(self, func: typing.Optional[typing.Callable[[datetime], datetime]]): - """Add a function which will be called when the datetime changes. Use this to implement custom boundaries + """Add a function which will be called when the datetime changes. Use this to implement custom boundaries. + Use ``None`` to disable the boundary function. :param func: Function which returns a datetime obj, arg is a datetime with the next call time """ diff --git a/conf_testing/rules/test_openhab_event_types.py b/conf_testing/rules/test_openhab_event_types.py index e924d8ff..ad6f60de 100644 --- a/conf_testing/rules/test_openhab_event_types.py +++ b/conf_testing/rules/test_openhab_event_types.py @@ -1,5 +1,5 @@ from HABApp.core.events import ValueUpdateEvent -from HABApp.openhab.definitions import ITEM_DIMENSION +from HABApp.openhab.definitions.definitions import ITEM_DIMENSIONS from HABAppTests import TestBaseRule, EventWaiter, OpenhabTmpItem, get_openhab_test_events, \ get_openhab_test_types, get_openhab_test_states, ItemWaiter @@ -15,7 +15,7 @@ def __init__(self): for oh_type in get_openhab_test_types(): self.add_test( f'{oh_type} events', self.test_events, oh_type, get_openhab_test_events(oh_type)) - for dimension in ITEM_DIMENSION: + for dimension in ITEM_DIMENSIONS: self.add_test(f'Quantity {dimension} events', self.test_quantity_type_events, dimension) def test_events(self, item_type, test_values): diff --git a/tests/test_openhab/test_items/test_mapping.py b/tests/test_openhab/test_items/test_mapping.py index 636c5a39..9877be4e 100644 --- a/tests/test_openhab/test_items/test_mapping.py +++ b/tests/test_openhab/test_items/test_mapping.py @@ -1,5 +1,16 @@ from HABApp.openhab.map_items import map_items +from HABApp.openhab.items import NumberItem def test_exception(): assert map_items('test', 'Number', 'asdf') is None + + +def test_number_unit_of_measurement(): + assert map_items('test1', 'Number:Length', '1.0 m') == NumberItem('test', 1) + assert map_items('test2', 'Number:Temperature', '2.0 °C') == NumberItem('test', 2) + assert map_items('test3', 'Number:Pressure', '3.0 hPa') == NumberItem('test', 3) + assert map_items('test4', 'Number:Speed', '4.0 km/h') == NumberItem('test', 4) + assert map_items('test5', 'Number:Intensity', '5.0 W/m2') == NumberItem('test', 5) + assert map_items('test6', 'Number:Dimensionless', '6.0') == NumberItem('test', 6) + assert map_items('test7', 'Number:Angle', '7.0 °') == NumberItem('test', 7) diff --git a/tests/test_openhab/test_values.py b/tests/test_openhab/test_values.py index 763eac72..6b3de89a 100644 --- a/tests/test_openhab/test_values.py +++ b/tests/test_openhab/test_values.py @@ -2,7 +2,7 @@ from HABApp.openhab.definitions import HSBValue, OnOffValue, OpenClosedValue, PercentValue, QuantityValue, RawValue, \ UpDownValue -from HABApp.openhab.definitions import ITEM_DIMENSION +from HABApp.openhab.definitions import ITEM_DIMENSIONS @pytest.mark.parametrize( @@ -33,10 +33,11 @@ def test_val_convert(cls, values): def test_quantity_value(): unit_of_dimension = { - 'Length': 'm', 'Temperature': '°C', 'Pressure': 'hPa', 'Speed': 'km/h', 'Intensity': 'W/m²', 'Angle': '°' + 'Length': 'm', 'Temperature': '°C', 'Pressure': 'hPa', 'Speed': 'km/h', 'Intensity': 'W/m²', 'Angle': '°', + 'Dimensionless': '', } - for dimension in ITEM_DIMENSION: + for dimension in ITEM_DIMENSIONS: for val in (-103.3, -3, 0, 0.33535, 5, 55.5, 105.5): unit = unit_of_dimension[dimension] v = QuantityValue(f'{val} {unit}')