PyPlumIO 0.5.47__tar.gz → 0.5.48__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pyplumio-0.5.47 → pyplumio-0.5.48}/PKG-INFO +2 -2
- {pyplumio-0.5.47 → pyplumio-0.5.48}/PyPlumIO.egg-info/PKG-INFO +2 -2
- {pyplumio-0.5.47 → pyplumio-0.5.48}/PyPlumIO.egg-info/SOURCES.txt +10 -1
- {pyplumio-0.5.47 → pyplumio-0.5.48}/PyPlumIO.egg-info/requires.txt +1 -1
- {pyplumio-0.5.47 → pyplumio-0.5.48}/docs/source/callbacks.rst +14 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/pyplumio/_version.py +2 -2
- {pyplumio-0.5.47 → pyplumio-0.5.48}/pyplumio/devices/ecomax.py +2 -2
- {pyplumio-0.5.47 → pyplumio-0.5.48}/pyplumio/devices/mixer.py +2 -2
- {pyplumio-0.5.47 → pyplumio-0.5.48}/pyplumio/devices/thermostat.py +2 -2
- {pyplumio-0.5.47 → pyplumio-0.5.48}/pyplumio/filters.py +62 -7
- {pyplumio-0.5.47 → pyplumio-0.5.48}/pyplumio/helpers/async_cache.py +3 -2
- {pyplumio-0.5.47 → pyplumio-0.5.48}/pyplumio/helpers/factory.py +9 -13
- {pyplumio-0.5.47 → pyplumio-0.5.48}/pyplumio/parameters/__init__.py +3 -60
- pyplumio-0.5.48/pyplumio/parameters/custom/__init__.py +111 -0
- pyplumio-0.5.48/pyplumio/parameters/custom/ecomax_860d3_hb.py +38 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/pyplumio/parameters/ecomax.py +7 -54
- {pyplumio-0.5.47 → pyplumio-0.5.48}/pyproject.toml +1 -1
- {pyplumio-0.5.47 → pyplumio-0.5.48}/requirements_test.txt +1 -1
- {pyplumio-0.5.47 → pyplumio-0.5.48}/tests/conftest.py +2 -2
- pyplumio-0.5.48/tests/devices/__init__.py +1 -0
- pyplumio-0.5.48/tests/devices/test_ecomax.py +553 -0
- pyplumio-0.5.48/tests/devices/test_ecoster.py +12 -0
- pyplumio-0.5.48/tests/devices/test_init.py +188 -0
- pyplumio-0.5.48/tests/devices/test_mixer.py +118 -0
- pyplumio-0.5.48/tests/devices/test_thermostat.py +134 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/tests/frames/test_init.py +1 -1
- pyplumio-0.5.48/tests/parameters/custom/__init__.py +1 -0
- pyplumio-0.5.48/tests/parameters/custom/test_init.py +89 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/tests/parameters/test_ecomax.py +3 -3
- pyplumio-0.5.48/tests/parameters/test_init.py +552 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/tests/test_connection.py +5 -6
- {pyplumio-0.5.47 → pyplumio-0.5.48}/tests/test_filters.py +20 -4
- {pyplumio-0.5.47 → pyplumio-0.5.48}/tests/test_protocol.py +8 -10
- {pyplumio-0.5.47 → pyplumio-0.5.48}/tests/test_stream.py +32 -18
- pyplumio-0.5.47/tests/parameters/test_init.py +0 -413
- pyplumio-0.5.47/tests/test_devices.py +0 -836
- {pyplumio-0.5.47 → pyplumio-0.5.48}/.gitattributes +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/.github/CODE_OF_CONDUCT.md +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/.github/dependabot.yml +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/.github/workflows/ci.yml +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/.github/workflows/codeql.yml +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/.github/workflows/deploy.yml +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/.github/workflows/documentation.yml +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/.gitignore +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/.pre-commit-config.yaml +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/.qlty/qlty.toml +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/.vscode/settings.json +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/LICENSE +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/MANIFEST.in +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/PyPlumIO.egg-info/dependency_links.txt +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/PyPlumIO.egg-info/top_level.txt +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/README.md +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/docs/Makefile +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/docs/make.bat +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/docs/source/conf.py +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/docs/source/connecting.rst +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/docs/source/frames.rst +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/docs/source/index.rst +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/docs/source/mixers_thermostats.rst +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/docs/source/protocol.rst +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/docs/source/reading.rst +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/docs/source/schedules.rst +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/docs/source/writing.rst +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/images/ecomax.png +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/images/rs485.png +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/pyplumio/__init__.py +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/pyplumio/__main__.py +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/pyplumio/connection.py +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/pyplumio/const.py +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/pyplumio/data_types.py +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/pyplumio/devices/__init__.py +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/pyplumio/devices/ecoster.py +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/pyplumio/exceptions.py +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/pyplumio/frames/__init__.py +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/pyplumio/frames/messages.py +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/pyplumio/frames/requests.py +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/pyplumio/frames/responses.py +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/pyplumio/helpers/__init__.py +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/pyplumio/helpers/event_manager.py +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/pyplumio/helpers/schedule.py +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/pyplumio/helpers/task_manager.py +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/pyplumio/helpers/timeout.py +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/pyplumio/helpers/uid.py +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/pyplumio/parameters/mixer.py +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/pyplumio/parameters/thermostat.py +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/pyplumio/protocol.py +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/pyplumio/py.typed +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/pyplumio/stream.py +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/pyplumio/structures/__init__.py +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/pyplumio/structures/alerts.py +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/pyplumio/structures/boiler_load.py +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/pyplumio/structures/boiler_power.py +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/pyplumio/structures/ecomax_parameters.py +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/pyplumio/structures/fan_power.py +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/pyplumio/structures/frame_versions.py +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/pyplumio/structures/fuel_consumption.py +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/pyplumio/structures/fuel_level.py +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/pyplumio/structures/lambda_sensor.py +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/pyplumio/structures/mixer_parameters.py +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/pyplumio/structures/mixer_sensors.py +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/pyplumio/structures/modules.py +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/pyplumio/structures/network_info.py +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/pyplumio/structures/output_flags.py +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/pyplumio/structures/outputs.py +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/pyplumio/structures/pending_alerts.py +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/pyplumio/structures/product_info.py +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/pyplumio/structures/program_version.py +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/pyplumio/structures/regulator_data.py +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/pyplumio/structures/regulator_data_schema.py +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/pyplumio/structures/schedules.py +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/pyplumio/structures/statuses.py +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/pyplumio/structures/temperatures.py +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/pyplumio/structures/thermostat_parameters.py +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/pyplumio/structures/thermostat_sensors.py +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/pyplumio/utils.py +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/requirements.txt +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/requirements_docs.txt +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/setup.cfg +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/tests/__init__.py +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/tests/frames/test_messages.py +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/tests/frames/test_requests.py +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/tests/frames/test_responses.py +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/tests/helpers/__init__.py +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/tests/helpers/test_async_cache.py +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/tests/helpers/test_event_manager.py +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/tests/helpers/test_factory.py +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/tests/helpers/test_schedule.py +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/tests/helpers/test_task_manager.py +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/tests/helpers/test_timeout.py +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/tests/helpers/test_uid.py +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/tests/parameters/__init__.py +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/tests/parameters/test_mixers.py +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/tests/parameters/test_thermostats.py +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/tests/ruff.toml +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/tests/test_data_types.py +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/tests/test_init.py +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/tests/test_main.py +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/tests/test_utils.py +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/tests/testdata/messages/regulator_data.json +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/tests/testdata/messages/sensor_data.json +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/tests/testdata/requests/alerts.json +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/tests/testdata/requests/ecomax_control.json +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/tests/testdata/requests/ecomax_parameters.json +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/tests/testdata/requests/mixer_parameters.json +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/tests/testdata/requests/set_ecomax_parameter.json +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/tests/testdata/requests/set_mixer_parameter.json +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/tests/testdata/requests/set_schedule.json +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/tests/testdata/requests/set_thermostat_parameter.json +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/tests/testdata/requests/thermostat_parameters.json +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/tests/testdata/responses/alerts.json +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/tests/testdata/responses/device_available.json +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/tests/testdata/responses/ecomax_parameters.json +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/tests/testdata/responses/mixer_parameters.json +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/tests/testdata/responses/password.json +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/tests/testdata/responses/program_version.json +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/tests/testdata/responses/regulator_data_schema.json +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/tests/testdata/responses/schedules.json +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/tests/testdata/responses/thermostat_parameters.json +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/tests/testdata/responses/uid.json +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/tests/testdata/unknown/unknown_ecomax_parameter.json +0 -0
- {pyplumio-0.5.47 → pyplumio-0.5.48}/tests/testdata/unknown/unknown_mixer_parameter.json +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: PyPlumIO
|
3
|
-
Version: 0.5.
|
3
|
+
Version: 0.5.48
|
4
4
|
Summary: PyPlumIO is a native ecoNET library for Plum ecoMAX controllers.
|
5
5
|
Author-email: Denis Paavilainen <denpa@denpa.pro>
|
6
6
|
License: MIT License
|
@@ -35,7 +35,7 @@ Requires-Dist: numpy<3.0.0,>=2.0.0; extra == "test"
|
|
35
35
|
Requires-Dist: pyserial-asyncio-fast==0.16; extra == "test"
|
36
36
|
Requires-Dist: pytest==8.3.5; extra == "test"
|
37
37
|
Requires-Dist: pytest-asyncio==0.26.0; extra == "test"
|
38
|
-
Requires-Dist: ruff==0.11.
|
38
|
+
Requires-Dist: ruff==0.11.9; extra == "test"
|
39
39
|
Requires-Dist: tox==4.25.0; extra == "test"
|
40
40
|
Requires-Dist: types-pyserial==3.5.0.20250326; extra == "test"
|
41
41
|
Provides-Extra: docs
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: PyPlumIO
|
3
|
-
Version: 0.5.
|
3
|
+
Version: 0.5.48
|
4
4
|
Summary: PyPlumIO is a native ecoNET library for Plum ecoMAX controllers.
|
5
5
|
Author-email: Denis Paavilainen <denpa@denpa.pro>
|
6
6
|
License: MIT License
|
@@ -35,7 +35,7 @@ Requires-Dist: numpy<3.0.0,>=2.0.0; extra == "test"
|
|
35
35
|
Requires-Dist: pyserial-asyncio-fast==0.16; extra == "test"
|
36
36
|
Requires-Dist: pytest==8.3.5; extra == "test"
|
37
37
|
Requires-Dist: pytest-asyncio==0.26.0; extra == "test"
|
38
|
-
Requires-Dist: ruff==0.11.
|
38
|
+
Requires-Dist: ruff==0.11.9; extra == "test"
|
39
39
|
Requires-Dist: tox==4.25.0; extra == "test"
|
40
40
|
Requires-Dist: types-pyserial==3.5.0.20250326; extra == "test"
|
41
41
|
Provides-Extra: docs
|
@@ -70,6 +70,8 @@ pyplumio/parameters/__init__.py
|
|
70
70
|
pyplumio/parameters/ecomax.py
|
71
71
|
pyplumio/parameters/mixer.py
|
72
72
|
pyplumio/parameters/thermostat.py
|
73
|
+
pyplumio/parameters/custom/__init__.py
|
74
|
+
pyplumio/parameters/custom/ecomax_860d3_hb.py
|
73
75
|
pyplumio/structures/__init__.py
|
74
76
|
pyplumio/structures/alerts.py
|
75
77
|
pyplumio/structures/boiler_load.py
|
@@ -101,13 +103,18 @@ tests/conftest.py
|
|
101
103
|
tests/ruff.toml
|
102
104
|
tests/test_connection.py
|
103
105
|
tests/test_data_types.py
|
104
|
-
tests/test_devices.py
|
105
106
|
tests/test_filters.py
|
106
107
|
tests/test_init.py
|
107
108
|
tests/test_main.py
|
108
109
|
tests/test_protocol.py
|
109
110
|
tests/test_stream.py
|
110
111
|
tests/test_utils.py
|
112
|
+
tests/devices/__init__.py
|
113
|
+
tests/devices/test_ecomax.py
|
114
|
+
tests/devices/test_ecoster.py
|
115
|
+
tests/devices/test_init.py
|
116
|
+
tests/devices/test_mixer.py
|
117
|
+
tests/devices/test_thermostat.py
|
111
118
|
tests/frames/test_init.py
|
112
119
|
tests/frames/test_messages.py
|
113
120
|
tests/frames/test_requests.py
|
@@ -125,6 +132,8 @@ tests/parameters/test_ecomax.py
|
|
125
132
|
tests/parameters/test_init.py
|
126
133
|
tests/parameters/test_mixers.py
|
127
134
|
tests/parameters/test_thermostats.py
|
135
|
+
tests/parameters/custom/__init__.py
|
136
|
+
tests/parameters/custom/test_init.py
|
128
137
|
tests/testdata/messages/regulator_data.json
|
129
138
|
tests/testdata/messages/sensor_data.json
|
130
139
|
tests/testdata/requests/alerts.json
|
@@ -79,6 +79,20 @@ value is changed.
|
|
79
79
|
# last call.
|
80
80
|
ecomax.subscribe("heating_temp", filters.on_change(my_callback))
|
81
81
|
|
82
|
+
.. autofunction:: pyplumio.filters.deadband
|
83
|
+
|
84
|
+
This filter await the callback on signifacant changes only.
|
85
|
+
Significance is defined by ``tolerance`` argument (i. e. tolerance=0.1
|
86
|
+
will only await callback when value is changed by more that 0.1).
|
87
|
+
|
88
|
+
.. code-block:: python
|
89
|
+
|
90
|
+
from pyplumio import filters
|
91
|
+
|
92
|
+
# Await the callback once heating_temp value is changed by more
|
93
|
+
# than 0.1 since last call.
|
94
|
+
ecomax.subscribe("heating_temp", filters.deadband(my_callback, tolerance=0.1))
|
95
|
+
|
82
96
|
.. autofunction:: pyplumio.filters.debounce
|
83
97
|
|
84
98
|
This filter will only await the callback once value is settled across
|
@@ -260,10 +260,10 @@ class EcoMAX(PhysicalDevice):
|
|
260
260
|
"""Update ecoMAX parameters and dispatch the events."""
|
261
261
|
_LOGGER.info("Received device parameters")
|
262
262
|
product_info: ProductInfo = await self.get(ATTR_PRODUCT)
|
263
|
+
parameter_types = await get_ecomax_parameter_types(product_info)
|
263
264
|
|
264
|
-
def _ecomax_parameter_events() -> Generator[Coroutine
|
265
|
+
def _ecomax_parameter_events() -> Generator[Coroutine]:
|
265
266
|
"""Get dispatch calls for ecoMAX parameter events."""
|
266
|
-
parameter_types = get_ecomax_parameter_types(product_info)
|
267
267
|
for index, values in parameters:
|
268
268
|
try:
|
269
269
|
description = parameter_types[index]
|
@@ -42,10 +42,10 @@ class Mixer(VirtualDevice):
|
|
42
42
|
"""Update mixer parameters and dispatch the events."""
|
43
43
|
_LOGGER.info("Received mixer %i parameters", self.index)
|
44
44
|
product_info: ProductInfo = await self.parent.get(ATTR_PRODUCT)
|
45
|
+
parameter_types = get_mixer_parameter_types(product_info)
|
45
46
|
|
46
|
-
def _mixer_parameter_events() -> Generator[Coroutine
|
47
|
+
def _mixer_parameter_events() -> Generator[Coroutine]:
|
47
48
|
"""Get dispatch calls for mixer parameter events."""
|
48
|
-
parameter_types = get_mixer_parameter_types(product_info)
|
49
49
|
for index, values in parameters:
|
50
50
|
try:
|
51
51
|
description = parameter_types[index]
|
@@ -40,10 +40,10 @@ class Thermostat(VirtualDevice):
|
|
40
40
|
) -> bool:
|
41
41
|
"""Update thermostat parameters and dispatch the events."""
|
42
42
|
_LOGGER.info("Received thermostat %i parameters", self.index)
|
43
|
+
parameter_types = get_thermostat_parameter_types()
|
43
44
|
|
44
|
-
def _thermostat_parameter_events() -> Generator[Coroutine
|
45
|
+
def _thermostat_parameter_events() -> Generator[Coroutine]:
|
45
46
|
"""Get dispatch calls for thermostat parameter events."""
|
46
|
-
parameter_types = get_thermostat_parameter_types()
|
47
47
|
for index, values in parameters:
|
48
48
|
description = parameter_types[index]
|
49
49
|
handler = (
|
@@ -36,7 +36,6 @@ with suppress(ImportError):
|
|
36
36
|
|
37
37
|
|
38
38
|
UNDEFINED: Final = "undefined"
|
39
|
-
TOLERANCE: Final = 0.1
|
40
39
|
|
41
40
|
|
42
41
|
@runtime_checkable
|
@@ -63,26 +62,34 @@ class SupportsComparison(Protocol):
|
|
63
62
|
|
64
63
|
Comparable = TypeVar("Comparable", Parameter, SupportsFloat, SupportsComparison)
|
65
64
|
|
65
|
+
DEFAULT_TOLERANCE: Final = 1e-6
|
66
|
+
|
66
67
|
|
67
68
|
@overload
|
68
|
-
def is_close(old: Parameter, new: Parameter) -> bool: ...
|
69
|
+
def is_close(old: Parameter, new: Parameter, tolerance: None = None) -> bool: ...
|
69
70
|
|
70
71
|
|
71
72
|
@overload
|
72
|
-
def is_close(
|
73
|
+
def is_close(
|
74
|
+
old: SupportsFloat, new: SupportsFloat, tolerance: float = DEFAULT_TOLERANCE
|
75
|
+
) -> bool: ...
|
73
76
|
|
74
77
|
|
75
78
|
@overload
|
76
|
-
def is_close(
|
79
|
+
def is_close(
|
80
|
+
old: SupportsComparison, new: SupportsComparison, tolerance: None = None
|
81
|
+
) -> bool: ...
|
77
82
|
|
78
83
|
|
79
|
-
def is_close(
|
84
|
+
def is_close(
|
85
|
+
old: Comparable, new: Comparable, tolerance: float | None = DEFAULT_TOLERANCE
|
86
|
+
) -> bool:
|
80
87
|
"""Check if value is significantly changed."""
|
81
88
|
if isinstance(old, Parameter) and isinstance(new, Parameter):
|
82
89
|
return new.pending_update or old.values.__ne__(new.values)
|
83
90
|
|
84
|
-
if isinstance(old, SupportsFloat) and isinstance(new, SupportsFloat):
|
85
|
-
return not math.isclose(old, new, abs_tol=
|
91
|
+
if tolerance and isinstance(old, SupportsFloat) and isinstance(new, SupportsFloat):
|
92
|
+
return not math.isclose(old, new, abs_tol=tolerance)
|
86
93
|
|
87
94
|
return old.__ne__(new)
|
88
95
|
|
@@ -293,6 +300,53 @@ def custom(callback: Callback, filter_fn: _FilterT) -> _Custom:
|
|
293
300
|
return _Custom(callback, filter_fn)
|
294
301
|
|
295
302
|
|
303
|
+
class _Deadband(Filter):
|
304
|
+
"""Represents a deadband filter.
|
305
|
+
|
306
|
+
Calls a callback only when value is significantly changed from the
|
307
|
+
previous callback call.
|
308
|
+
"""
|
309
|
+
|
310
|
+
__slots__ = ("_tolerance",)
|
311
|
+
|
312
|
+
_tolerance: float
|
313
|
+
|
314
|
+
def __init__(self, callback: Callback, tolerance: float) -> None:
|
315
|
+
"""Initialize a new value changed filter."""
|
316
|
+
self._tolerance = tolerance
|
317
|
+
super().__init__(callback)
|
318
|
+
|
319
|
+
async def __call__(self, new_value: Any) -> Any:
|
320
|
+
"""Set a new value for the callback."""
|
321
|
+
if not isinstance(new_value, (float, int, Decimal)):
|
322
|
+
raise TypeError(
|
323
|
+
"Deadband filter can only be used with numeric values, got "
|
324
|
+
f"{type(new_value).__name__}: {new_value}"
|
325
|
+
)
|
326
|
+
|
327
|
+
if self._value == UNDEFINED or is_close(
|
328
|
+
self._value, new_value, tolerance=self._tolerance
|
329
|
+
):
|
330
|
+
self._value = new_value
|
331
|
+
return await self._callback(new_value)
|
332
|
+
|
333
|
+
|
334
|
+
def deadband(callback: Callback, tolerance: float) -> _Deadband:
|
335
|
+
"""Create a new deadband filter.
|
336
|
+
|
337
|
+
A callback function will only be called when the value is significantly changed
|
338
|
+
from the previous callback call.
|
339
|
+
|
340
|
+
:param callback: A callback function to be awaited on significant value change
|
341
|
+
:type callback: Callback
|
342
|
+
:param tolerance: The minimum difference required to trigger the callback
|
343
|
+
:type tolerance: float
|
344
|
+
:return: An instance of callable filter
|
345
|
+
:rtype: _Deadband
|
346
|
+
"""
|
347
|
+
return _Deadband(callback, tolerance)
|
348
|
+
|
349
|
+
|
296
350
|
class _Debounce(Filter):
|
297
351
|
"""Represents a debounce filter.
|
298
352
|
|
@@ -468,6 +522,7 @@ __all__ = [
|
|
468
522
|
"aggregate",
|
469
523
|
"clamp",
|
470
524
|
"custom",
|
525
|
+
"deadband",
|
471
526
|
"debounce",
|
472
527
|
"delta",
|
473
528
|
"on_change",
|
@@ -4,10 +4,11 @@ from collections.abc import Awaitable
|
|
4
4
|
from functools import wraps
|
5
5
|
from typing import Any, Callable, TypeVar, cast
|
6
6
|
|
7
|
-
from typing_extensions import ParamSpec
|
7
|
+
from typing_extensions import ParamSpec, TypeAlias
|
8
8
|
|
9
9
|
T = TypeVar("T")
|
10
10
|
P = ParamSpec("P")
|
11
|
+
_CallableT: TypeAlias = Callable[..., Awaitable[Any]]
|
11
12
|
|
12
13
|
|
13
14
|
class AsyncCache:
|
@@ -21,7 +22,7 @@ class AsyncCache:
|
|
21
22
|
"""Initialize the cache."""
|
22
23
|
self.cache = {}
|
23
24
|
|
24
|
-
async def get(self, key: str, coro:
|
25
|
+
async def get(self, key: str, coro: _CallableT) -> Any:
|
25
26
|
"""Get a value from the cache or compute and store it."""
|
26
27
|
if key not in self.cache:
|
27
28
|
self.cache[key] = await coro()
|
@@ -25,19 +25,15 @@ async def import_module(name: str) -> ModuleType:
|
|
25
25
|
async def create_instance(class_path: str, /, cls: type[T], **kwargs: Any) -> T:
|
26
26
|
"""Return a class instance from the class path."""
|
27
27
|
module_name, class_name = class_path.rsplit(".", 1)
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
return instance
|
38
|
-
except Exception:
|
39
|
-
_LOGGER.exception("Failed to create instance for class path '%s'", class_path)
|
40
|
-
raise
|
28
|
+
module = await import_module(module_name)
|
29
|
+
instance = getattr(module, class_name)(**kwargs)
|
30
|
+
if not isinstance(instance, cls):
|
31
|
+
raise TypeError(
|
32
|
+
f"Expected instance of '{cls.__name__}', but got "
|
33
|
+
f"'{type(instance).__name__}' from '{class_name}'"
|
34
|
+
)
|
35
|
+
|
36
|
+
return instance
|
41
37
|
|
42
38
|
|
43
39
|
__all__ = ["create_instance"]
|
@@ -4,7 +4,6 @@ from __future__ import annotations
|
|
4
4
|
|
5
5
|
from abc import ABC, abstractmethod
|
6
6
|
import asyncio
|
7
|
-
from collections.abc import Sequence
|
8
7
|
from dataclasses import dataclass
|
9
8
|
import logging
|
10
9
|
from typing import TYPE_CHECKING, Any, Literal, TypeVar, Union, get_args
|
@@ -12,16 +11,8 @@ from typing import TYPE_CHECKING, Any, Literal, TypeVar, Union, get_args
|
|
12
11
|
from dataslots import dataslots
|
13
12
|
from typing_extensions import TypeAlias
|
14
13
|
|
15
|
-
from pyplumio.const import
|
16
|
-
BYTE_UNDEFINED,
|
17
|
-
STATE_OFF,
|
18
|
-
STATE_ON,
|
19
|
-
ProductModel,
|
20
|
-
State,
|
21
|
-
UnitOfMeasurement,
|
22
|
-
)
|
14
|
+
from pyplumio.const import BYTE_UNDEFINED, STATE_OFF, STATE_ON, State, UnitOfMeasurement
|
23
15
|
from pyplumio.frames import Request
|
24
|
-
from pyplumio.structures.product_info import ProductInfo
|
25
16
|
from pyplumio.utils import is_divisible
|
26
17
|
|
27
18
|
if TYPE_CHECKING:
|
@@ -120,8 +111,8 @@ class Parameter(ABC):
|
|
120
111
|
other = other.values
|
121
112
|
|
122
113
|
if isinstance(other, ParameterValues):
|
123
|
-
handler = getattr(self.values, method_to_call)
|
124
|
-
return handler(other)
|
114
|
+
handler = getattr(self.values.value, method_to_call)
|
115
|
+
return handler(other.value)
|
125
116
|
|
126
117
|
if isinstance(other, (int, float, bool)) or other in get_args(State):
|
127
118
|
handler = getattr(self.values.value, method_to_call)
|
@@ -486,53 +477,6 @@ class Switch(Parameter):
|
|
486
477
|
return STATE_ON
|
487
478
|
|
488
479
|
|
489
|
-
@dataclass
|
490
|
-
class ParameterOverride:
|
491
|
-
"""Represents a parameter override."""
|
492
|
-
|
493
|
-
__slot__ = ("original", "replacement", "product_model", "product_id")
|
494
|
-
|
495
|
-
original: str
|
496
|
-
replacement: ParameterDescription
|
497
|
-
product_model: ProductModel
|
498
|
-
product_id: int
|
499
|
-
|
500
|
-
|
501
|
-
_DescriptorT = TypeVar("_DescriptorT", bound=ParameterDescription)
|
502
|
-
|
503
|
-
|
504
|
-
def patch_parameter_types(
|
505
|
-
product_info: ProductInfo,
|
506
|
-
parameter_types: list[_DescriptorT],
|
507
|
-
parameter_overrides: Sequence[ParameterOverride],
|
508
|
-
) -> list[_DescriptorT]:
|
509
|
-
"""Patch the parameter types based on the provided overrides.
|
510
|
-
|
511
|
-
Note:
|
512
|
-
The `# type: ignore[assignment]` comment is used to suppress a
|
513
|
-
type-checking error caused by mypy bug. For more details, see:
|
514
|
-
https://github.com/python/mypy/issues/13596
|
515
|
-
|
516
|
-
"""
|
517
|
-
replacements = {
|
518
|
-
override.original: override.replacement
|
519
|
-
for override in parameter_overrides
|
520
|
-
if override.product_model.value == product_info.model
|
521
|
-
and override.product_id == product_info.id
|
522
|
-
}
|
523
|
-
for index, description in enumerate(parameter_types):
|
524
|
-
if description.name in replacements:
|
525
|
-
_LOGGER.info(
|
526
|
-
"Replacing parameter description for '%s' with '%s' (%s)",
|
527
|
-
description.name,
|
528
|
-
replacements[description.name],
|
529
|
-
product_info.model,
|
530
|
-
)
|
531
|
-
parameter_types[index] = replacements[description.name] # type: ignore[assignment]
|
532
|
-
|
533
|
-
return parameter_types
|
534
|
-
|
535
|
-
|
536
480
|
__all__ = [
|
537
481
|
"Number",
|
538
482
|
"NumberDescription",
|
@@ -542,7 +486,6 @@ __all__ = [
|
|
542
486
|
"Parameter",
|
543
487
|
"ParameterDescription",
|
544
488
|
"ParameterValues",
|
545
|
-
"patch_parameter_types",
|
546
489
|
"State",
|
547
490
|
"Switch",
|
548
491
|
"SwitchDescription",
|
@@ -0,0 +1,111 @@
|
|
1
|
+
"""Custom parameters for products."""
|
2
|
+
|
3
|
+
from __future__ import annotations
|
4
|
+
|
5
|
+
from collections.abc import Sequence
|
6
|
+
from dataclasses import dataclass
|
7
|
+
import logging
|
8
|
+
from typing import ClassVar, TypeVar, cast
|
9
|
+
|
10
|
+
from pyplumio.helpers.factory import create_instance
|
11
|
+
from pyplumio.parameters import ParameterDescription
|
12
|
+
from pyplumio.structures.product_info import ProductInfo
|
13
|
+
from pyplumio.utils import to_camelcase
|
14
|
+
|
15
|
+
_LOGGER = logging.getLogger(__name__)
|
16
|
+
|
17
|
+
|
18
|
+
@dataclass
|
19
|
+
class Signature:
|
20
|
+
"""Represents a product signature."""
|
21
|
+
|
22
|
+
__slots__ = ("id", "model")
|
23
|
+
|
24
|
+
id: int
|
25
|
+
model: str
|
26
|
+
|
27
|
+
|
28
|
+
@dataclass
|
29
|
+
class CustomParameter:
|
30
|
+
"""Represents a custom parameter."""
|
31
|
+
|
32
|
+
__slot__ = ("original", "replacement")
|
33
|
+
|
34
|
+
original: str
|
35
|
+
replacement: ParameterDescription
|
36
|
+
|
37
|
+
|
38
|
+
class CustomParameters:
|
39
|
+
"""Represents a custom parameters."""
|
40
|
+
|
41
|
+
__slots__ = ("signature", "replacements")
|
42
|
+
|
43
|
+
signature: ClassVar[Signature]
|
44
|
+
replacements: ClassVar[Sequence[CustomParameter]]
|
45
|
+
|
46
|
+
def validate(self, product_info: ProductInfo) -> bool:
|
47
|
+
"""Validate the product info."""
|
48
|
+
return (
|
49
|
+
self.signature.id == product_info.id
|
50
|
+
and self.signature.model == product_info.model
|
51
|
+
)
|
52
|
+
|
53
|
+
|
54
|
+
async def _load_custom_parameters(
|
55
|
+
product_info: ProductInfo,
|
56
|
+
) -> dict[str, ParameterDescription] | None:
|
57
|
+
"""Load custom parameters."""
|
58
|
+
module_name = product_info.model.replace("-", "_").replace(" ", "_").lower()
|
59
|
+
module_path = f"parameters.custom.{module_name}"
|
60
|
+
class_name = to_camelcase(module_name).upper().replace("ECOMAX", "EcoMAX")
|
61
|
+
class_path = f"{module_path}.{class_name}"
|
62
|
+
try:
|
63
|
+
_LOGGER.debug(
|
64
|
+
"Trying to load custom parameters for %s from %s",
|
65
|
+
product_info.model,
|
66
|
+
class_path,
|
67
|
+
)
|
68
|
+
custom_parameters = await create_instance(class_path, cls=CustomParameters)
|
69
|
+
if not custom_parameters.validate(product_info):
|
70
|
+
raise ValueError
|
71
|
+
except (ImportError, TypeError, ValueError):
|
72
|
+
_LOGGER.debug("No custom parameters found for %s", product_info.model)
|
73
|
+
return None
|
74
|
+
|
75
|
+
return {
|
76
|
+
custom_parameter.original: custom_parameter.replacement
|
77
|
+
for custom_parameter in custom_parameters.replacements
|
78
|
+
}
|
79
|
+
|
80
|
+
|
81
|
+
_DescriptionT = TypeVar("_DescriptionT", bound=ParameterDescription)
|
82
|
+
|
83
|
+
|
84
|
+
async def inject_custom_parameters(
|
85
|
+
product_info: ProductInfo, parameter_types: list[_DescriptionT]
|
86
|
+
) -> list[_DescriptionT]:
|
87
|
+
"""Patch the parameter types based on the provided overrides."""
|
88
|
+
if custom_parameters := await _load_custom_parameters(product_info):
|
89
|
+
_LOGGER.debug("Custom parameters found for %s", product_info.model)
|
90
|
+
return cast(
|
91
|
+
list[_DescriptionT],
|
92
|
+
[
|
93
|
+
replacement
|
94
|
+
if original.name in custom_parameters
|
95
|
+
and (replacement := custom_parameters[original.name])
|
96
|
+
and (base_class := original.__class__.__bases__[0])
|
97
|
+
and isinstance(replacement, base_class)
|
98
|
+
else original
|
99
|
+
for original in parameter_types
|
100
|
+
],
|
101
|
+
)
|
102
|
+
|
103
|
+
return parameter_types
|
104
|
+
|
105
|
+
|
106
|
+
__all__ = (
|
107
|
+
"inject_custom_parameters",
|
108
|
+
"CustomParameters",
|
109
|
+
"CustomParameter",
|
110
|
+
"Signature",
|
111
|
+
)
|
@@ -0,0 +1,38 @@
|
|
1
|
+
"""Contains patch for ecoMAX 860D3-HB."""
|
2
|
+
|
3
|
+
from pyplumio.const import UnitOfMeasurement
|
4
|
+
from pyplumio.parameters.custom import CustomParameter, CustomParameters, Signature
|
5
|
+
from pyplumio.parameters.ecomax import EcomaxNumberDescription
|
6
|
+
|
7
|
+
|
8
|
+
class EcoMAX860D3HB(CustomParameters):
|
9
|
+
"""Replacements for ecoMAX 860D3-HB."""
|
10
|
+
|
11
|
+
__slots__ = ()
|
12
|
+
|
13
|
+
signature = Signature(model="ecoMAX 860D3-HB", id=48)
|
14
|
+
|
15
|
+
replacements = (
|
16
|
+
CustomParameter(
|
17
|
+
original="summer_mode_disable_temp",
|
18
|
+
replacement=EcomaxNumberDescription(name="__unknown_parameter_1"),
|
19
|
+
),
|
20
|
+
CustomParameter(
|
21
|
+
original="water_heater_target_temp",
|
22
|
+
replacement=EcomaxNumberDescription(name="summer_mode"),
|
23
|
+
),
|
24
|
+
CustomParameter(
|
25
|
+
original="min_water_heater_target_temp",
|
26
|
+
replacement=EcomaxNumberDescription(
|
27
|
+
name="summer_mode_enable_temp",
|
28
|
+
unit_of_measurement=UnitOfMeasurement.CELSIUS,
|
29
|
+
),
|
30
|
+
),
|
31
|
+
CustomParameter(
|
32
|
+
original="max_water_heater_target_temp",
|
33
|
+
replacement=EcomaxNumberDescription(
|
34
|
+
name="summer_mode_disable_temp",
|
35
|
+
unit_of_measurement=UnitOfMeasurement.CELSIUS,
|
36
|
+
),
|
37
|
+
),
|
38
|
+
)
|
@@ -3,7 +3,7 @@
|
|
3
3
|
from __future__ import annotations
|
4
4
|
|
5
5
|
from dataclasses import dataclass
|
6
|
-
from functools import
|
6
|
+
from functools import partial
|
7
7
|
from typing import TYPE_CHECKING
|
8
8
|
|
9
9
|
from dataslots import dataslots
|
@@ -15,21 +15,20 @@ from pyplumio.const import (
|
|
15
15
|
ATTR_VALUE,
|
16
16
|
PERCENTAGE,
|
17
17
|
FrameType,
|
18
|
-
ProductModel,
|
19
18
|
ProductType,
|
20
19
|
UnitOfMeasurement,
|
21
20
|
)
|
22
21
|
from pyplumio.frames import Request
|
22
|
+
from pyplumio.helpers.async_cache import acache
|
23
23
|
from pyplumio.parameters import (
|
24
24
|
OffsetNumber,
|
25
25
|
OffsetNumberDescription,
|
26
26
|
Parameter,
|
27
27
|
ParameterDescription,
|
28
|
-
ParameterOverride,
|
29
28
|
Switch,
|
30
29
|
SwitchDescription,
|
31
|
-
patch_parameter_types,
|
32
30
|
)
|
31
|
+
from pyplumio.parameters.custom import inject_custom_parameters
|
33
32
|
from pyplumio.structures.ecomax_parameters import ATTR_ECOMAX_CONTROL
|
34
33
|
from pyplumio.structures.product_info import ProductInfo
|
35
34
|
from pyplumio.structures.thermostat_parameters import ATTR_THERMOSTAT_PROFILE
|
@@ -798,58 +797,13 @@ ECOMAX_CONTROL_PARAMETER = EcomaxSwitchDescription(
|
|
798
797
|
THERMOSTAT_PROFILE_PARAMETER = EcomaxNumberDescription(name=ATTR_THERMOSTAT_PROFILE)
|
799
798
|
|
800
799
|
|
801
|
-
@
|
802
|
-
|
803
|
-
"""Represents an ecoMAX parameter override."""
|
804
|
-
|
805
|
-
__slots__ = ()
|
806
|
-
|
807
|
-
replacement: EcomaxParameterDescription
|
808
|
-
|
809
|
-
|
810
|
-
PARAMETER_OVERRIDES: tuple[EcomaxParameterOverride, ...] = (
|
811
|
-
EcomaxParameterOverride(
|
812
|
-
original="summer_mode_disable_temp",
|
813
|
-
replacement=EcomaxNumberDescription(name="__unknown_parameter_1"),
|
814
|
-
product_model=ProductModel.ECOMAX_860D3_HB,
|
815
|
-
product_id=48,
|
816
|
-
),
|
817
|
-
EcomaxParameterOverride(
|
818
|
-
original="water_heater_target_temp",
|
819
|
-
replacement=EcomaxNumberDescription(name="summer_mode"),
|
820
|
-
product_model=ProductModel.ECOMAX_860D3_HB,
|
821
|
-
product_id=48,
|
822
|
-
),
|
823
|
-
EcomaxParameterOverride(
|
824
|
-
original="min_water_heater_target_temp",
|
825
|
-
replacement=EcomaxNumberDescription(
|
826
|
-
name="summer_mode_enable_temp",
|
827
|
-
unit_of_measurement=UnitOfMeasurement.CELSIUS,
|
828
|
-
),
|
829
|
-
product_model=ProductModel.ECOMAX_860D3_HB,
|
830
|
-
product_id=48,
|
831
|
-
),
|
832
|
-
EcomaxParameterOverride(
|
833
|
-
original="max_water_heater_target_temp",
|
834
|
-
replacement=EcomaxNumberDescription(
|
835
|
-
name="summer_mode_disable_temp",
|
836
|
-
unit_of_measurement=UnitOfMeasurement.CELSIUS,
|
837
|
-
),
|
838
|
-
product_model=ProductModel.ECOMAX_860D3_HB,
|
839
|
-
product_id=48,
|
840
|
-
),
|
841
|
-
)
|
842
|
-
|
843
|
-
|
844
|
-
@cache
|
845
|
-
def get_ecomax_parameter_types(
|
800
|
+
@acache
|
801
|
+
async def get_ecomax_parameter_types(
|
846
802
|
product_info: ProductInfo,
|
847
803
|
) -> list[EcomaxParameterDescription]:
|
848
804
|
"""Return ecoMAX parameter types for specific product."""
|
849
|
-
return
|
850
|
-
product_info,
|
851
|
-
parameter_types=PARAMETER_TYPES[product_info.type],
|
852
|
-
parameter_overrides=PARAMETER_OVERRIDES,
|
805
|
+
return await inject_custom_parameters(
|
806
|
+
product_info, parameter_types=PARAMETER_TYPES[product_info.type]
|
853
807
|
)
|
854
808
|
|
855
809
|
|
@@ -862,7 +816,6 @@ __all__ = [
|
|
862
816
|
"EcomaxSwitch",
|
863
817
|
"EcomaxSwitchDescription",
|
864
818
|
"get_ecomax_parameter_types",
|
865
|
-
"PARAMETER_OVERRIDES",
|
866
819
|
"PARAMETER_TYPES",
|
867
820
|
"THERMOSTAT_PROFILE_PARAMETER",
|
868
821
|
]
|