From 7be34abfa8d0566a86b93e079c41ec7680b175a7 Mon Sep 17 00:00:00 2001 From: SukramJ Date: Wed, 18 Dec 2024 19:20:03 +0100 Subject: [PATCH] Support markers for sysvar/program selection (#1928) --- .github/workflows/codeql.yml | 6 +- .github/workflows/lock.yml | 2 +- .github/workflows/pylint.yml | 5 -- .github/workflows/python-publish.yml | 56 ++++++++++++------ .github/workflows/test-run.yaml | 5 -- changelog.md | 1 + example_local.py | 2 +- hahomematic/central/__init__.py | 6 ++ hahomematic/client/__init__.py | 28 +++++---- hahomematic/client/json_rpc.py | 37 ++++++++++-- hahomematic/const.py | 5 +- hahomematic/model/hub/__init__.py | 6 +- hahomematic/model/hub/data_point.py | 6 ++ hahomematic_support/client_local.py | 6 +- requirements_test.txt | 2 +- tests/const.py | 2 +- tests/helper.py | 2 + tests/test_central.py | 6 +- tests/test_central_pydevccu.py | 22 +++---- tests/test_climate.py | 1 + tests/test_light.py | 88 ++++++++++++++++------------ tests/test_support.py | 1 + 22 files changed, 187 insertions(+), 108 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 1f845ad7..2fc2fc8e 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -2,11 +2,7 @@ name: "CodeQL" # yamllint disable-line rule:truthy on: - push: - branches: ["devel"] - pull_request: - # The branches below must be a subset of the branches above - branches: ["devel"] + pull_request: ~ schedule: - cron: "44 3 * * 2" diff --git a/.github/workflows/lock.yml b/.github/workflows/lock.yml index dd2dc2f8..651e51df 100644 --- a/.github/workflows/lock.yml +++ b/.github/workflows/lock.yml @@ -8,7 +8,7 @@ on: jobs: lock: - if: github.repository_owner == 'danielperna84' + if: github.repository_owner == 'SukramJ' runs-on: ubuntu-latest steps: - uses: dessant/lock-threads@v5.0.1 diff --git a/.github/workflows/pylint.yml b/.github/workflows/pylint.yml index 44999eba..0eb1dfac 100644 --- a/.github/workflows/pylint.yml +++ b/.github/workflows/pylint.yml @@ -2,11 +2,6 @@ name: Pylint # yamllint disable-line rule:truthy on: - push: - branches: - - "dev**" - - devel - - master pull_request: ~ workflow_dispatch: jobs: diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml index 7a3ed47d..07c7b25e 100644 --- a/.github/workflows/python-publish.yml +++ b/.github/workflows/python-publish.yml @@ -1,4 +1,4 @@ -# This workflow will upload a Python Package using Twine when a release is created +# This workflow will upload a Python Package to PyPI when a release is created # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#publishing-to-package-registries # This workflow uses actions that are not certified by GitHub. @@ -17,26 +17,48 @@ permissions: contents: read jobs: - deploy: + release-build: runs-on: ubuntu-latest - strategy: - matrix: - python-version: ["3.12"] + steps: - uses: actions/checkout@v4 - - name: Set up Python - uses: actions/setup-python@v5 + + - uses: actions/setup-python@v5 with: - python-version: ${{ matrix.python-version }} - - name: Install dependencies + python-version: "3.12" + + - name: Build release distributions run: | - python -m pip install --upgrade pip + # NOTE: put your own distribution build steps here. + python -m pip install build pip install -r requirements_test.txt - pip install build setuptools wheel - - name: Build package - run: python -m build - - name: Publish package - uses: pypa/gh-action-pypi-publish@67339c736fd9354cd4f8cb0b744f2b82a74b5c70 + python -m build + + - name: Upload distributions + uses: actions/upload-artifact@v4 + with: + name: release-dists + path: dist/ + + pypi-publish: + runs-on: ubuntu-latest + needs: + - release-build + permissions: + # IMPORTANT: this permission is mandatory for trusted publishing + id-token: write + + environment: + name: pypi + + steps: + - name: Retrieve release distributions + uses: actions/download-artifact@v4 + with: + name: release-dists + path: dist/ + + - name: Publish release distributions to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 with: - user: __token__ - password: ${{ secrets.PYPI_API_TOKEN }} + packages-dir: dist/ diff --git a/.github/workflows/test-run.yaml b/.github/workflows/test-run.yaml index 854477af..57fdbb1c 100644 --- a/.github/workflows/test-run.yaml +++ b/.github/workflows/test-run.yaml @@ -2,11 +2,6 @@ name: "Test-Run" # yamllint disable-line rule:truthy on: - push: - branches: - - "dev**" - - devel - - master pull_request: ~ workflow_dispatch: diff --git a/changelog.md b/changelog.md index ade7458c..553bec7b 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,6 @@ # Version 2024.12.6 (2024-12-18) +- Support markers for sysvar/program selection - Remove danielperna84 from links after repository transfer to sukramj #Version 2024.12.5 (2024-12-15) diff --git a/example_local.py b/example_local.py index 257f2cd9..066f64a8 100644 --- a/example_local.py +++ b/example_local.py @@ -215,7 +215,7 @@ async def example_run(self): "VCU0000045": "HM-LC-Bl1-FM.json", "VCU0000276": "ST6-SH.json", "VCU2128127": "HmIP-BSM.json", - "VCU3716619": "HmIP-BSL.json", + "VCU6985973": "HmIP-BSL.json", "VCU6153495": "HmIP-FCI1.json", "VCU0000265": "HM-Sen-LI-O.json", "VCU0000146": "HM-Sec-Key.json", diff --git a/hahomematic/central/__init__.py b/hahomematic/central/__init__.py index 325899c4..0e56764f 100644 --- a/hahomematic/central/__init__.py +++ b/hahomematic/central/__init__.py @@ -37,8 +37,10 @@ DEFAULT_INCLUDE_INTERNAL_SYSVARS, DEFAULT_MAX_READ_WORKERS, DEFAULT_PERIODIC_REFRESH_INTERVAL, + DEFAULT_PROGRAM_MARKERS, DEFAULT_PROGRAM_SCAN_ENABLED, DEFAULT_SYS_SCAN_INTERVAL, + DEFAULT_SYSVAR_MARKERS, DEFAULT_SYSVAR_SCAN_ENABLED, DEFAULT_TLS, DEFAULT_UN_IGNORES, @@ -1675,9 +1677,11 @@ def __init__( listen_port: int | None = None, max_read_workers: int = DEFAULT_MAX_READ_WORKERS, periodic_refresh_interval: int = DEFAULT_PERIODIC_REFRESH_INTERVAL, + program_markers: tuple[str, ...] = DEFAULT_PROGRAM_MARKERS, program_scan_enabled: bool = DEFAULT_PROGRAM_SCAN_ENABLED, start_direct: bool = False, sys_scan_interval: int = DEFAULT_SYS_SCAN_INTERVAL, + sysvar_markers: tuple[str, ...] = DEFAULT_SYSVAR_MARKERS, sysvar_scan_enabled: bool = DEFAULT_SYSVAR_SCAN_ENABLED, tls: bool = DEFAULT_TLS, un_ignore_list: tuple[str, ...] = DEFAULT_UN_IGNORES, @@ -1707,10 +1711,12 @@ def __init__( self.name: Final = name self.password: Final = password self.periodic_refresh_interval = periodic_refresh_interval + self.program_markers: Final = program_markers self.program_scan_enabled: Final = program_scan_enabled self.start_direct: Final = start_direct self.storage_folder: Final = storage_folder self.sys_scan_interval: Final = sys_scan_interval + self.sysvar_markers: Final = sysvar_markers self.sysvar_scan_enabled: Final = sysvar_scan_enabled self.tls: Final = tls self.un_ignore_list: Final = un_ignore_list diff --git a/hahomematic/client/__init__.py b/hahomematic/client/__init__.py index 41eb3aa6..8e3979ab 100644 --- a/hahomematic/client/__init__.py +++ b/hahomematic/client/__init__.py @@ -381,12 +381,14 @@ async def get_system_variable(self, name: str) -> Any: @abstractmethod async def get_all_system_variables( - self, include_internal: bool + self, sysvar_markers: tuple[str, ...], include_internal: bool ) -> tuple[SystemVariableData, ...]: """Get all system variables from CCU / Homegear.""" @abstractmethod - async def get_all_programs(self, include_internal: bool) -> tuple[ProgramData, ...]: + async def get_all_programs( + self, program_markers: tuple[str, ...], include_internal: bool + ) -> tuple[ProgramData, ...]: """Get all programs, if available.""" @abstractmethod @@ -1164,17 +1166,21 @@ async def get_system_variable(self, name: str) -> Any: @service(re_raise=False, no_raise_return=()) async def get_all_system_variables( - self, include_internal: bool + self, sysvar_markers: tuple[str, ...], include_internal: bool ) -> tuple[SystemVariableData, ...]: - """Get all system variables from CCU / Homegear.""" + """Get all system variables from CCU.""" return await self._json_rpc_client.get_all_system_variables( - include_internal=include_internal + sysvar_markers=sysvar_markers, include_internal=include_internal ) @service(re_raise=False, no_raise_return=()) - async def get_all_programs(self, include_internal: bool) -> tuple[ProgramData, ...]: + async def get_all_programs( + self, program_markers: tuple[str, ...], include_internal: bool + ) -> tuple[ProgramData, ...]: """Get all programs, if available.""" - return await self._json_rpc_client.get_all_programs(include_internal=include_internal) + return await self._json_rpc_client.get_all_programs( + program_markers=program_markers, include_internal=include_internal + ) @service(re_raise=False, no_raise_return={}) async def get_all_rooms(self) -> dict[str, set[str]]: @@ -1496,9 +1502,9 @@ async def get_system_variable(self, name: str) -> Any: @service(re_raise=False, no_raise_return=()) async def get_all_system_variables( - self, include_internal: bool + self, sysvar_markers: tuple[str, ...], include_internal: bool ) -> tuple[SystemVariableData, ...]: - """Get all system variables from CCU / Homegear.""" + """Get all system variables from Homegear.""" variables: list[SystemVariableData] = [] if hg_variables := await self._proxy.getAllSystemVariables(): for name, value in hg_variables.items(): @@ -1506,7 +1512,9 @@ async def get_all_system_variables( return tuple(variables) @service(re_raise=False, no_raise_return=()) - async def get_all_programs(self, include_internal: bool) -> tuple[ProgramData, ...]: + async def get_all_programs( + self, program_markers: tuple[str, ...], include_internal: bool + ) -> tuple[ProgramData, ...]: """Get all programs, if available.""" return () diff --git a/hahomematic/client/json_rpc.py b/hahomematic/client/json_rpc.py index e81a130f..05bff367 100644 --- a/hahomematic/client/json_rpc.py +++ b/hahomematic/client/json_rpc.py @@ -53,6 +53,7 @@ from hahomematic.model.support import convert_value from hahomematic.support import ( cleanup_text_from_html_tags, + element_matches_key, get_tls_context, parse_sys_var, reduce_args, @@ -538,7 +539,7 @@ async def get_system_variable(self, name: str) -> Any: return response[_JsonKey.RESULT] async def get_all_system_variables( - self, include_internal: bool + self, sysvar_markers: tuple[str, ...], include_internal: bool ) -> tuple[SystemVariableData, ...]: """Get all system variables from CCU / Homegear.""" variables: list[SystemVariableData] = [] @@ -551,11 +552,22 @@ async def get_all_system_variables( if json_result := response[_JsonKey.RESULT]: descriptions = await self._get_system_variable_descriptions() for var in json_result: + has_markers = False + extended_sysvar = False is_internal = var[_JsonKey.IS_INTERNAL] if include_internal is False and is_internal is True: continue - extended_sysvar = False var_id = var[_JsonKey.ID] + description = descriptions.get(var_id) + if not is_internal and sysvar_markers: + if not element_matches_key( + search_elements=sysvar_markers, + compare_with=description, + do_wildcard_search=True, + ): + continue + has_markers = True + name = var[_JsonKey.NAME] org_data_type = var[_JsonKey.TYPE] raw_value = var[_JsonKey.VALUE] @@ -563,10 +575,9 @@ async def get_all_system_variables( data_type = SysvarType.FLOAT if "." in raw_value else SysvarType.INTEGER else: data_type = org_data_type - if (description := descriptions.get(var_id)) and ( - extended_sysvar := EXTENDED_SYSVAR_MARKER in description - ): + if description and (extended_sysvar := EXTENDED_SYSVAR_MARKER in description): description = description.replace(EXTENDED_SYSVAR_MARKER, "").strip() + has_markers = True unit = var[_JsonKey.UNIT] values: tuple[str, ...] | None = None if val_list := var.get(_JsonKey.VALUE_LIST): @@ -591,6 +602,7 @@ async def get_all_system_variables( max_value=max_value, min_value=min_value, extended_sysvar=extended_sysvar, + has_markers=has_markers, ) ) except (ValueError, TypeError) as vterr: @@ -927,7 +939,9 @@ async def get_all_device_data(self, interface: Interface) -> dict[str, Any]: return all_device_data - async def get_all_programs(self, include_internal: bool) -> tuple[ProgramData, ...]: + async def get_all_programs( + self, program_markers: tuple[str, ...], include_internal: bool + ) -> tuple[ProgramData, ...]: """Get the all programs of the backend.""" all_programs: list[ProgramData] = [] @@ -939,11 +953,21 @@ async def get_all_programs(self, include_internal: bool) -> tuple[ProgramData, . if json_result := response[_JsonKey.RESULT]: descriptions = await self._get_program_descriptions() for prog in json_result: + has_markers = False is_internal = prog[_JsonKey.IS_INTERNAL] if include_internal is False and is_internal is True: continue pid = prog[_JsonKey.ID] description = descriptions.get(pid) + if not is_internal and program_markers: + if not element_matches_key( + search_elements=program_markers, + compare_with=description, + do_wildcard_search=True, + ): + continue + has_markers = True + name = prog[_JsonKey.NAME] is_active = prog[_JsonKey.IS_ACTIVE] last_execute_time = prog[_JsonKey.LAST_EXECUTE_TIME] @@ -956,6 +980,7 @@ async def get_all_programs(self, include_internal: bool) -> tuple[ProgramData, . is_active=is_active, is_internal=is_internal, last_execute_time=last_execute_time, + has_markers=has_markers, ) ) diff --git a/hahomematic/const.py b/hahomematic/const.py index 5b44c890..7c03efe4 100644 --- a/hahomematic/const.py +++ b/hahomematic/const.py @@ -9,7 +9,7 @@ import re from typing import Any, Final, Required, TypedDict -VERSION: Final = "2024.12.5" +VERSION: Final = "2024.12.6" DEFAULT_CONNECTION_CHECKER_INTERVAL: Final = 15 # check if connection is available via rpc ping DEFAULT_CUSTOM_ID: Final = "custom_id" @@ -22,8 +22,10 @@ DEFAULT_PERIODIC_REFRESH_INTERVAL: Final = 15 DEFAULT_PING_PONG_MISMATCH_COUNT: Final = 15 DEFAULT_PING_PONG_MISMATCH_COUNT_TTL: Final = 300 +DEFAULT_PROGRAM_MARKERS: Final[tuple[str, ...]] = () DEFAULT_PROGRAM_SCAN_ENABLED: Final = True DEFAULT_RECONNECT_WAIT: Final = 120 # wait with reconnect after a first ping was successful +DEFAULT_SYSVAR_MARKERS: Final[tuple[str, ...]] = () DEFAULT_SYSVAR_SCAN_ENABLED: Final = True DEFAULT_SYS_SCAN_INTERVAL: Final = 30 DEFAULT_TIMEOUT: Final = 60 # default timeout for a connection @@ -605,6 +607,7 @@ class HubData: """Dataclass for hub data points.""" name: str + has_markers: bool = False @dataclass(frozen=True, kw_only=True, slots=True) diff --git a/hahomematic/model/hub/__init__.py b/hahomematic/model/hub/__init__.py index 516bed7a..9def9110 100644 --- a/hahomematic/model/hub/__init__.py +++ b/hahomematic/model/hub/__init__.py @@ -89,7 +89,8 @@ async def _update_program_data_points(self) -> None: programs: tuple[ProgramData, ...] = () if client := self._central.primary_client: programs = await client.get_all_programs( - include_internal=self._config.include_internal_programs + program_markers=self._config.program_markers, + include_internal=self._config.include_internal_programs, ) if not programs: _LOGGER.debug( @@ -125,7 +126,8 @@ async def _update_sysvar_data_points(self) -> None: variables: tuple[SystemVariableData, ...] = () if client := self._central.primary_client: variables = await client.get_all_system_variables( - include_internal=self._config.include_internal_sysvars + sysvar_markers=self._config.sysvar_markers, + include_internal=self._config.include_internal_sysvars, ) if not variables: _LOGGER.debug( diff --git a/hahomematic/model/hub/data_point.py b/hahomematic/model/hub/data_point.py index 5f4259c3..a56e73a5 100644 --- a/hahomematic/model/hub/data_point.py +++ b/hahomematic/model/hub/data_point.py @@ -35,6 +35,7 @@ def __init__( self._name: Final = self.get_name(data=data) super().__init__(central=central, unique_id=unique_id) self._full_name: Final = f"{self._central.name}_{self._name}" + self._has_markers: Final = data.has_markers @abstractmethod def get_name(self, data: HubData) -> str: @@ -45,6 +46,11 @@ def full_name(self) -> str: """Return the fullname of the data_point.""" return self._full_name + @property + def has_markers(self) -> bool: + """Return if the data_point has markers.""" + return self._has_markers + @config_property def name(self) -> str | None: """Return the name of the data_point.""" diff --git a/hahomematic_support/client_local.py b/hahomematic_support/client_local.py index bc0a9bd5..66ed05ea 100644 --- a/hahomematic_support/client_local.py +++ b/hahomematic_support/client_local.py @@ -136,12 +136,14 @@ async def get_system_variable(self, name: str) -> str: return "Empty" async def get_all_system_variables( - self, include_internal: bool + self, sysvar_markers: tuple[str, ...], include_internal: bool ) -> tuple[SystemVariableData, ...]: """Get all system variables from CCU / Homegear.""" return () - async def get_all_programs(self, include_internal: bool) -> tuple[ProgramData, ...]: + async def get_all_programs( + self, program_markers: tuple[str, ...], include_internal: bool + ) -> tuple[ProgramData, ...]: """Get all programs, if available.""" return () diff --git a/requirements_test.txt b/requirements_test.txt index 16ce4868..6ef497f5 100644 --- a/requirements_test.txt +++ b/requirements_test.txt @@ -8,7 +8,7 @@ pip==24.3.1 pre-commit==4.0.1 pur==7.3.3 pydantic==2.10.3 -pydevccu==0.1.8 +pydevccu==0.1.9 pylint-per-file-ignores==1.3.2 pylint-strict-informational==0.1 pylint==3.3.2 diff --git a/tests/const.py b/tests/const.py index 0a708616..e85e92ea 100644 --- a/tests/const.py +++ b/tests/const.py @@ -334,7 +334,7 @@ "VCU0000045": "HM-LC-Bl1-FM.json", "VCU0000276": "ST6-SH.json", "VCU2128127": "HmIP-BSM.json", - "VCU3716619": "HmIP-BSL.json", + "VCU6985973": "HmIP-BSL.json", "VCU6153495": "HmIP-FCI1.json", "VCU0000265": "HM-Sen-LI-O.json", "VCU0000146": "HM-Sec-Key.json", diff --git a/tests/helper.py b/tests/helper.py index e4ba1a02..4a868604 100644 --- a/tests/helper.py +++ b/tests/helper.py @@ -236,6 +236,8 @@ def systemcallback(system_event, *args, **kwargs): interface_configs=interface_configs, default_callback_port=54321, client_session=client_session, + program_markers=None, + sysvar_markers=None, ).create_central() central.register_backend_system_callback(systemcallback) await central.start() diff --git a/tests/test_central.py b/tests/test_central.py index 7d02a42e..ec578057 100644 --- a/tests/test_central.py +++ b/tests/test_central.py @@ -680,6 +680,7 @@ async def test_virtual_remote_delete( await central.delete_device(interface_id=const.INTERFACE_ID, device_address="NOT_A_DEVICE_ID") +@pytest.mark.enable_socket @pytest.mark.asyncio async def test_central_not_alive(factory: helper.Factory) -> None: """Test central other methods.""" @@ -755,12 +756,12 @@ async def test_central_services( central, mock_client, _ = central_client_factory await central.fetch_program_data(scheduled=True) assert mock_client.method_calls[-1] == call.get_all_programs( - include_internal=DEFAULT_INCLUDE_INTERNAL_PROGRAMS + program_markers=(), include_internal=DEFAULT_INCLUDE_INTERNAL_PROGRAMS ) await central.fetch_sysvar_data(scheduled=True) assert mock_client.method_calls[-1] == call.get_all_system_variables( - include_internal=DEFAULT_INCLUDE_INTERNAL_SYSVARS + sysvar_markers=(), include_internal=DEFAULT_INCLUDE_INTERNAL_SYSVARS ) assert len(mock_client.method_calls) == 42 @@ -843,6 +844,7 @@ async def test_central_services( ) +@pytest.mark.enable_socket @pytest.mark.asyncio async def test_central_direct(factory: helper.Factory) -> None: """Test central other methods.""" diff --git a/tests/test_central_pydevccu.py b/tests/test_central_pydevccu.py index 1ef1eb52..0c354166 100644 --- a/tests/test_central_pydevccu.py +++ b/tests/test_central_pydevccu.py @@ -20,6 +20,7 @@ # pylint: disable=protected-access +@pytest.mark.enable_socket @pytest.mark.asyncio async def test_central_mini(central_unit_mini) -> None: """Test the central.""" @@ -32,6 +33,7 @@ async def test_central_mini(central_unit_mini) -> None: assert len(central_unit_mini.get_data_points(exclude_no_create=False)) == 63 +@pytest.mark.enable_socket @pytest.mark.asyncio async def test_central_full(central_unit_full) -> None: """Test the central.""" @@ -60,7 +62,7 @@ async def test_central_full(central_unit_full) -> None: for channel in device.channels.values(): channel_type_names.add(channel.type_name) channel_type_names = sorted(channel_type_names) - assert len(channel_type_names) == 538 + assert len(channel_type_names) == 541 ce_channels = {} for cdp in custom_dps: if cdp.device.model not in ce_channels: @@ -119,22 +121,22 @@ async def test_central_full(central_unit_full) -> None: ) as fptr: fptr.write(orjson.dumps(addresses, option=orjson.OPT_INDENT_2 | orjson.OPT_NON_STR_KEYS)) - assert usage_types[DataPointUsage.NO_CREATE] == 3172 - assert usage_types[DataPointUsage.CDP_PRIMARY] == 208 - assert usage_types[DataPointUsage.DATA_POINT] == 3639 - assert usage_types[DataPointUsage.CDP_VISIBLE] == 125 - assert usage_types[DataPointUsage.CDP_SECONDARY] == 146 + assert usage_types[DataPointUsage.NO_CREATE] == 4090 + assert usage_types[DataPointUsage.CDP_PRIMARY] == 261 + assert usage_types[DataPointUsage.DATA_POINT] == 3688 + assert usage_types[DataPointUsage.CDP_VISIBLE] == 133 + assert usage_types[DataPointUsage.CDP_SECONDARY] == 154 - assert len(ce_channels) == 121 + assert len(ce_channels) == 124 assert len(data_point_types) == 6 - assert len(parameters) == 220 + assert len(parameters) == 221 - assert len(central_unit_full._devices) == 383 + assert len(central_unit_full._devices) == 386 virtual_remotes = ["VCU4264293", "VCU0000057", "VCU0000001"] await central_unit_full.delete_devices( interface_id=const.INTERFACE_ID, addresses=virtual_remotes ) - assert len(central_unit_full._devices) == 380 + assert len(central_unit_full._devices) == 383 del_addresses = list( central_unit_full.device_descriptions.get_device_descriptions(const.INTERFACE_ID) ) diff --git a/tests/test_climate.py b/tests/test_climate.py index 32f22bdd..0d1ec3f9 100644 --- a/tests/test_climate.py +++ b/tests/test_climate.py @@ -528,6 +528,7 @@ async def test_ceipthermostat( assert call_count == len(mock_client.method_calls) +@pytest.mark.enable_socket @pytest.mark.asyncio async def test_climate_ip_with_pydevccu(central_unit_mini) -> None: """Test the central.""" diff --git a/tests/test_light.py b/tests/test_light.py index c58467ef..7b68cae7 100644 --- a/tests/test_light.py +++ b/tests/test_light.py @@ -28,7 +28,7 @@ "VCU0000115": "HM-LC-DW-WM.json", "VCU0000122": "HM-LC-Dim1L-CV.json", "VCU1399816": "HmIP-BDT.json", - "VCU3716619": "HmIP-BSL.json", + "VCU6985973": "HmIP-BSL.json", "VCU3747418": "HM-LC-RGBW-WM.json", "VCU4704397": "HmIPW-WRC6.json", "VCU5629873": "HmIP-RGBW.json", @@ -430,18 +430,29 @@ async def test_ceipfixedcolorlight( """Test CustomDpIpFixedColorLight.""" central, mock_client, _ = central_client_factory light: CustomDpIpFixedColorLight = cast( - CustomDpIpFixedColorLight, helper.get_prepared_custom_data_point(central, "VCU3716619", 8) + CustomDpIpFixedColorLight, helper.get_prepared_custom_data_point(central, "VCU6985973", 8) ) assert light.usage == DataPointUsage.CDP_PRIMARY assert light.color_temp_kelvin is None assert light.hs_color == (0.0, 0.0) assert light.supports_brightness is True assert light.supports_color_temperature is False - assert light.supports_effects is False + assert light.supports_effects is True assert light.supports_hs_color is True assert light.supports_transition is True assert light.effect is None - assert light.effects == () + assert light.effects == ( + "ON", + "BLINKING_SLOW", + "BLINKING_MIDDLE", + "BLINKING_FAST", + "FLASH_SLOW", + "FLASH_MIDDLE", + "FLASH_FAST", + "BILLOW_SLOW", + "BILLOW_MIDDLE", + "BILLOW_FAST", + ) assert light.brightness == 0 assert light.is_on is False assert light.color_name == _FixedColor.BLACK @@ -450,24 +461,23 @@ async def test_ceipfixedcolorlight( assert light.channel_hs_color is None await light.turn_on() assert mock_client.method_calls[-1] == call.put_paramset( - channel_address="VCU3716619:8", + channel_address="VCU6985973:8", paramset_key="VALUES", - values={"COLOR": 7, "LEVEL": 1.0}, + values={"COLOR": 7, "COLOR_BEHAVIOUR": 1, "LEVEL": 1.0}, wait_for_callback=WAIT_FOR_CALLBACK, ) assert light.brightness == 255 await light.turn_on(brightness=28) - assert mock_client.method_calls[-1] == call.set_value( - channel_address="VCU3716619:8", + assert mock_client.method_calls[-1] == call.put_paramset( + channel_address="VCU6985973:8", paramset_key="VALUES", - parameter="LEVEL", - value=0.10980392156862745, + values={"COLOR_BEHAVIOUR": 1, "LEVEL": 0.10980392156862745}, wait_for_callback=WAIT_FOR_CALLBACK, ) assert light.brightness == 28 await light.turn_off() assert mock_client.method_calls[-1] == call.set_value( - channel_address="VCU3716619:8", + channel_address="VCU6985973:8", paramset_key="VALUES", parameter="LEVEL", value=0.0, @@ -478,71 +488,71 @@ async def test_ceipfixedcolorlight( await light.turn_on(hs_color=(350, 50)) assert mock_client.method_calls[-1] == call.put_paramset( - channel_address="VCU3716619:8", + channel_address="VCU6985973:8", paramset_key="VALUES", - values={"COLOR": 4, "LEVEL": 1.0}, + values={"COLOR": 4, "COLOR_BEHAVIOUR": 1, "LEVEL": 1.0}, wait_for_callback=WAIT_FOR_CALLBACK, ) assert light.color_name == _FixedColor.RED await light.turn_on(hs_color=(0.0, 0.0)) assert mock_client.method_calls[-1] == call.put_paramset( - channel_address="VCU3716619:8", + channel_address="VCU6985973:8", paramset_key="VALUES", - values={"COLOR": 7, "LEVEL": 1.0}, + values={"COLOR": 7, "COLOR_BEHAVIOUR": 1, "LEVEL": 1.0}, wait_for_callback=WAIT_FOR_CALLBACK, ) assert light.color_name == _FixedColor.WHITE await light.turn_on(hs_color=(60.0, 50.0)) assert mock_client.method_calls[-1] == call.put_paramset( - channel_address="VCU3716619:8", + channel_address="VCU6985973:8", paramset_key="VALUES", - values={"COLOR": 6, "LEVEL": 1.0}, + values={"COLOR": 6, "COLOR_BEHAVIOUR": 1, "LEVEL": 1.0}, wait_for_callback=WAIT_FOR_CALLBACK, ) assert light.color_name == _FixedColor.YELLOW await light.turn_on(hs_color=(120, 50)) assert mock_client.method_calls[-1] == call.put_paramset( - channel_address="VCU3716619:8", + channel_address="VCU6985973:8", paramset_key="VALUES", - values={"COLOR": 2, "LEVEL": 1.0}, + values={"COLOR": 2, "COLOR_BEHAVIOUR": 1, "LEVEL": 1.0}, wait_for_callback=WAIT_FOR_CALLBACK, ) assert light.color_name == _FixedColor.GREEN await light.turn_on(hs_color=(180, 50)) assert mock_client.method_calls[-1] == call.put_paramset( - channel_address="VCU3716619:8", + channel_address="VCU6985973:8", paramset_key="VALUES", - values={"COLOR": 3, "LEVEL": 1.0}, + values={"COLOR": 3, "COLOR_BEHAVIOUR": 1, "LEVEL": 1.0}, wait_for_callback=WAIT_FOR_CALLBACK, ) assert light.color_name == _FixedColor.TURQUOISE await light.turn_on(hs_color=(240, 50)) assert mock_client.method_calls[-1] == call.put_paramset( - channel_address="VCU3716619:8", + channel_address="VCU6985973:8", paramset_key="VALUES", - values={"COLOR": 1, "LEVEL": 1.0}, + values={"COLOR": 1, "COLOR_BEHAVIOUR": 1, "LEVEL": 1.0}, wait_for_callback=WAIT_FOR_CALLBACK, ) assert light.color_name == _FixedColor.BLUE await light.turn_on(hs_color=(300, 50)) assert mock_client.method_calls[-1] == call.put_paramset( - channel_address="VCU3716619:8", + channel_address="VCU6985973:8", paramset_key="VALUES", - values={"COLOR": 5, "LEVEL": 1.0}, + values={"COLOR": 5, "COLOR_BEHAVIOUR": 1, "LEVEL": 1.0}, wait_for_callback=WAIT_FOR_CALLBACK, ) assert light.color_name == _FixedColor.PURPLE - await central.data_point_event(const.INTERFACE_ID, "VCU3716619:7", "LEVEL", 0.5) + await central.data_point_event(const.INTERFACE_ID, "VCU6985973:7", "LEVEL", 0.5) assert light.channel_brightness == 127 - await central.data_point_event(const.INTERFACE_ID, "VCU3716619:7", "COLOR", 1) + await central.data_point_event(const.INTERFACE_ID, "VCU6985973:7", "COLOR", 1) assert light.channel_hs_color == (240.0, 100.0) assert light.channel_color_name == _FixedColor.BLUE @@ -550,9 +560,9 @@ async def test_ceipfixedcolorlight( light.set_timer_on_time(18) await light.turn_on() assert mock_client.method_calls[-1] == call.put_paramset( - channel_address="VCU3716619:8", + channel_address="VCU6985973:8", paramset_key="VALUES", - values={"DURATION_VALUE": 18, "LEVEL": 1.0}, + values={"DURATION_VALUE": 18, "COLOR_BEHAVIOUR": 1, "LEVEL": 1.0}, wait_for_callback=WAIT_FOR_CALLBACK, ) @@ -560,9 +570,9 @@ async def test_ceipfixedcolorlight( light.set_timer_on_time(17000) await light.turn_on() assert mock_client.method_calls[-1] == call.put_paramset( - channel_address="VCU3716619:8", + channel_address="VCU6985973:8", paramset_key="VALUES", - values={"DURATION_UNIT": 1, "DURATION_VALUE": 283, "LEVEL": 1.0}, + values={"COLOR_BEHAVIOUR": 1, "DURATION_UNIT": 1, "DURATION_VALUE": 283, "LEVEL": 1.0}, wait_for_callback=WAIT_FOR_CALLBACK, ) @@ -570,32 +580,32 @@ async def test_ceipfixedcolorlight( light.set_timer_on_time(1000000) await light.turn_on() assert mock_client.method_calls[-1] == call.put_paramset( - channel_address="VCU3716619:8", + channel_address="VCU6985973:8", paramset_key="VALUES", - values={"DURATION_UNIT": 2, "DURATION_VALUE": 277, "LEVEL": 1.0}, + values={"COLOR_BEHAVIOUR": 1, "DURATION_UNIT": 2, "DURATION_VALUE": 277, "LEVEL": 1.0}, wait_for_callback=WAIT_FOR_CALLBACK, ) await light.turn_on(ramp_time=18) assert mock_client.method_calls[-1] == call.put_paramset( - channel_address="VCU3716619:8", + channel_address="VCU6985973:8", paramset_key="VALUES", - values={"RAMP_TIME_VALUE": 18, "LEVEL": 1.0}, + values={"COLOR_BEHAVIOUR": 1, "RAMP_TIME_VALUE": 18, "LEVEL": 1.0}, wait_for_callback=WAIT_FOR_CALLBACK, ) await light.turn_on(ramp_time=17000) assert mock_client.method_calls[-1] == call.put_paramset( - channel_address="VCU3716619:8", + channel_address="VCU6985973:8", paramset_key="VALUES", - values={"RAMP_TIME_UNIT": 1, "RAMP_TIME_VALUE": 283, "LEVEL": 1.0}, + values={"COLOR_BEHAVIOUR": 1, "RAMP_TIME_UNIT": 1, "RAMP_TIME_VALUE": 283, "LEVEL": 1.0}, wait_for_callback=WAIT_FOR_CALLBACK, ) await light.turn_on(ramp_time=1000000) assert mock_client.method_calls[-1] == call.put_paramset( - channel_address="VCU3716619:8", + channel_address="VCU6985973:8", paramset_key="VALUES", - values={"RAMP_TIME_UNIT": 2, "RAMP_TIME_VALUE": 277, "LEVEL": 1.0}, + values={"COLOR_BEHAVIOUR": 1, "RAMP_TIME_UNIT": 2, "RAMP_TIME_VALUE": 277, "LEVEL": 1.0}, wait_for_callback=WAIT_FOR_CALLBACK, ) diff --git a/tests/test_support.py b/tests/test_support.py index 810bace7..efe4c008 100644 --- a/tests/test_support.py +++ b/tests/test_support.py @@ -481,6 +481,7 @@ async def test_value_from_dict_by_wildcard_key() -> None: ) +@pytest.mark.enable_socket @pytest.mark.asyncio async def test_others() -> None: """Test find_free_port."""