python-pooldose 0.8.1__tar.gz → 0.8.2__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.
- {python_pooldose-0.8.1 → python_pooldose-0.8.2}/PKG-INFO +4 -4
- {python_pooldose-0.8.1 → python_pooldose-0.8.2}/README.md +3 -3
- {python_pooldose-0.8.1 → python_pooldose-0.8.2}/src/pooldose/__init__.py +1 -1
- {python_pooldose-0.8.1 → python_pooldose-0.8.2}/src/pooldose/mappings/mapping_info.py +12 -5
- {python_pooldose-0.8.1 → python_pooldose-0.8.2}/src/pooldose/type_definitions.py +12 -8
- {python_pooldose-0.8.1 → python_pooldose-0.8.2}/src/pooldose/values/instant_values.py +27 -20
- {python_pooldose-0.8.1 → python_pooldose-0.8.2}/src/python_pooldose.egg-info/PKG-INFO +4 -4
- {python_pooldose-0.8.1 → python_pooldose-0.8.2}/LICENSE +0 -0
- {python_pooldose-0.8.1 → python_pooldose-0.8.2}/pyproject.toml +0 -0
- {python_pooldose-0.8.1 → python_pooldose-0.8.2}/setup.cfg +0 -0
- {python_pooldose-0.8.1 → python_pooldose-0.8.2}/src/pooldose/__main__.py +0 -0
- {python_pooldose-0.8.1 → python_pooldose-0.8.2}/src/pooldose/client.py +0 -0
- {python_pooldose-0.8.1 → python_pooldose-0.8.2}/src/pooldose/constants.py +0 -0
- {python_pooldose-0.8.1 → python_pooldose-0.8.2}/src/pooldose/device_analyzer.py +0 -0
- {python_pooldose-0.8.1 → python_pooldose-0.8.2}/src/pooldose/mappings/__init__.py +0 -0
- {python_pooldose-0.8.1 → python_pooldose-0.8.2}/src/pooldose/mappings/model_PDHC1H1HAR1V1_FW539224.json +0 -0
- {python_pooldose-0.8.1 → python_pooldose-0.8.2}/src/pooldose/mappings/model_PDPR1H1HAR1V0_FW539224.json +0 -0
- {python_pooldose-0.8.1 → python_pooldose-0.8.2}/src/pooldose/mappings/model_PDPR1H1HAW100_FW539187.json +0 -0
- {python_pooldose-0.8.1 → python_pooldose-0.8.2}/src/pooldose/mock_client.py +0 -0
- {python_pooldose-0.8.1 → python_pooldose-0.8.2}/src/pooldose/py.typed +0 -0
- {python_pooldose-0.8.1 → python_pooldose-0.8.2}/src/pooldose/request_handler.py +0 -0
- {python_pooldose-0.8.1 → python_pooldose-0.8.2}/src/pooldose/request_status.py +0 -0
- {python_pooldose-0.8.1 → python_pooldose-0.8.2}/src/pooldose/values/__init__.py +0 -0
- {python_pooldose-0.8.1 → python_pooldose-0.8.2}/src/pooldose/values/static_values.py +0 -0
- {python_pooldose-0.8.1 → python_pooldose-0.8.2}/src/python_pooldose.egg-info/SOURCES.txt +0 -0
- {python_pooldose-0.8.1 → python_pooldose-0.8.2}/src/python_pooldose.egg-info/dependency_links.txt +0 -0
- {python_pooldose-0.8.1 → python_pooldose-0.8.2}/src/python_pooldose.egg-info/entry_points.txt +0 -0
- {python_pooldose-0.8.1 → python_pooldose-0.8.2}/src/python_pooldose.egg-info/requires.txt +0 -0
- {python_pooldose-0.8.1 → python_pooldose-0.8.2}/src/python_pooldose.egg-info/top_level.txt +0 -0
- {python_pooldose-0.8.1 → python_pooldose-0.8.2}/tests/test_client.py +0 -0
- {python_pooldose-0.8.1 → python_pooldose-0.8.2}/tests/test_device_analyzer.py +0 -0
- {python_pooldose-0.8.1 → python_pooldose-0.8.2}/tests/test_device_analyzer_integration.py +0 -0
- {python_pooldose-0.8.1 → python_pooldose-0.8.2}/tests/test_instant_values.py +0 -0
- {python_pooldose-0.8.1 → python_pooldose-0.8.2}/tests/test_mapping_info.py +0 -0
- {python_pooldose-0.8.1 → python_pooldose-0.8.2}/tests/test_mock_client_set_value.py +0 -0
- {python_pooldose-0.8.1 → python_pooldose-0.8.2}/tests/test_request_handler.py +0 -0
- {python_pooldose-0.8.1 → python_pooldose-0.8.2}/tests/test_ssl_support.py +0 -0
- {python_pooldose-0.8.1 → python_pooldose-0.8.2}/tests/test_static_values.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-pooldose
|
|
3
|
-
Version: 0.8.
|
|
3
|
+
Version: 0.8.2
|
|
4
4
|
Summary: Unoffical async Python client for SEKO PoolDose devices
|
|
5
5
|
Author-email: Lukas Maertin <pypi@lukas-maertin.de>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -918,6 +918,7 @@ This package is **PEP-561 compliant** and fully typed for use in Home Assistant
|
|
|
918
918
|
|
|
919
919
|
**PEP-561 Compliance**: Package includes `py.typed` file marking it as fully typed
|
|
920
920
|
**Comprehensive Type Annotations**: All public API methods have complete type hints
|
|
921
|
+
**Type Constants**: Centralized `VALUE_TYPE_*` constants eliminate string literals for entity types
|
|
921
922
|
**mypy Support**: Built-in mypy configuration for static type checking
|
|
922
923
|
**Home Assistant Ready**: Compatible with Home Assistant's strict typing requirements
|
|
923
924
|
|
|
@@ -985,7 +986,6 @@ Data Classification:
|
|
|
985
986
|
|
|
986
987
|
For detailed release notes and version history, please see [CHANGELOG.md](CHANGELOG.md).
|
|
987
988
|
|
|
988
|
-
### Latest Release (0.8.
|
|
989
|
+
### Latest Release (0.8.2)
|
|
989
990
|
|
|
990
|
-
- **
|
|
991
|
-
- **Mapping Consistency**: OFA threshold mappings renamed for consistency (`ofa_orp_*`, `ofa_cl_*`)
|
|
991
|
+
- **Type Constants**: centralized runtime constants for platform types
|
|
@@ -899,6 +899,7 @@ This package is **PEP-561 compliant** and fully typed for use in Home Assistant
|
|
|
899
899
|
|
|
900
900
|
**PEP-561 Compliance**: Package includes `py.typed` file marking it as fully typed
|
|
901
901
|
**Comprehensive Type Annotations**: All public API methods have complete type hints
|
|
902
|
+
**Type Constants**: Centralized `VALUE_TYPE_*` constants eliminate string literals for entity types
|
|
902
903
|
**mypy Support**: Built-in mypy configuration for static type checking
|
|
903
904
|
**Home Assistant Ready**: Compatible with Home Assistant's strict typing requirements
|
|
904
905
|
|
|
@@ -966,7 +967,6 @@ Data Classification:
|
|
|
966
967
|
|
|
967
968
|
For detailed release notes and version history, please see [CHANGELOG.md](CHANGELOG.md).
|
|
968
969
|
|
|
969
|
-
### Latest Release (0.8.
|
|
970
|
+
### Latest Release (0.8.2)
|
|
970
971
|
|
|
971
|
-
- **
|
|
972
|
-
- **Mapping Consistency**: OFA threshold mappings renamed for consistency (`ofa_orp_*`, `ofa_cl_*`)
|
|
972
|
+
- **Type Constants**: centralized runtime constants for platform types
|
|
@@ -9,6 +9,13 @@ from typing import Any, Dict, List, Optional
|
|
|
9
9
|
import aiofiles
|
|
10
10
|
|
|
11
11
|
from pooldose.request_handler import RequestStatus
|
|
12
|
+
from pooldose.type_definitions import (
|
|
13
|
+
VALUE_TYPE_SENSOR,
|
|
14
|
+
VALUE_TYPE_BINARY_SENSOR,
|
|
15
|
+
VALUE_TYPE_NUMBER,
|
|
16
|
+
VALUE_TYPE_SWITCH,
|
|
17
|
+
VALUE_TYPE_SELECT,
|
|
18
|
+
)
|
|
12
19
|
|
|
13
20
|
# pylint: disable=line-too-long
|
|
14
21
|
|
|
@@ -139,7 +146,7 @@ class MappingInfo:
|
|
|
139
146
|
return {}
|
|
140
147
|
result = {}
|
|
141
148
|
for name, entry in self.mapping.items():
|
|
142
|
-
if entry.get("type") ==
|
|
149
|
+
if entry.get("type") == VALUE_TYPE_SENSOR:
|
|
143
150
|
result[name] = SensorMapping(
|
|
144
151
|
key=entry["key"],
|
|
145
152
|
type=entry["type"],
|
|
@@ -158,7 +165,7 @@ class MappingInfo:
|
|
|
158
165
|
return {}
|
|
159
166
|
result = {}
|
|
160
167
|
for name, entry in self.mapping.items():
|
|
161
|
-
if entry.get("type") ==
|
|
168
|
+
if entry.get("type") == VALUE_TYPE_BINARY_SENSOR:
|
|
162
169
|
result[name] = BinarySensorMapping(
|
|
163
170
|
key=entry["key"],
|
|
164
171
|
type=entry["type"],
|
|
@@ -176,7 +183,7 @@ class MappingInfo:
|
|
|
176
183
|
return {}
|
|
177
184
|
result = {}
|
|
178
185
|
for name, entry in self.mapping.items():
|
|
179
|
-
if entry.get("type") ==
|
|
186
|
+
if entry.get("type") == VALUE_TYPE_NUMBER:
|
|
180
187
|
result[name] = NumberMapping(
|
|
181
188
|
key=entry["key"],
|
|
182
189
|
type=entry["type"],
|
|
@@ -194,7 +201,7 @@ class MappingInfo:
|
|
|
194
201
|
return {}
|
|
195
202
|
result = {}
|
|
196
203
|
for name, entry in self.mapping.items():
|
|
197
|
-
if entry.get("type") ==
|
|
204
|
+
if entry.get("type") == VALUE_TYPE_SWITCH:
|
|
198
205
|
result[name] = SwitchMapping(
|
|
199
206
|
key=entry["key"],
|
|
200
207
|
type=entry["type"],
|
|
@@ -214,7 +221,7 @@ class MappingInfo:
|
|
|
214
221
|
return {}
|
|
215
222
|
result = {}
|
|
216
223
|
for name, entry in self.mapping.items():
|
|
217
|
-
if entry.get("type") ==
|
|
224
|
+
if entry.get("type") == VALUE_TYPE_SELECT:
|
|
218
225
|
result[name] = SelectMapping(
|
|
219
226
|
key=entry["key"],
|
|
220
227
|
type=entry["type"],
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""Type definitions for the pooldose package."""
|
|
2
2
|
|
|
3
|
-
from typing import Any, Dict, Final, List,
|
|
3
|
+
from typing import Any, Dict, Final, List, Optional, TypedDict
|
|
4
4
|
|
|
5
5
|
# Device information types
|
|
6
6
|
class DeviceInfoDict(TypedDict, total=False):
|
|
@@ -39,14 +39,14 @@ class MappingDict(TypedDict):
|
|
|
39
39
|
class ValueDict(TypedDict, total=False):
|
|
40
40
|
"""Type definition for a value entry."""
|
|
41
41
|
type: str
|
|
42
|
-
value:
|
|
42
|
+
value: float | int | str
|
|
43
43
|
unit: str
|
|
44
|
-
raw_value:
|
|
44
|
+
raw_value: float | int | str
|
|
45
45
|
status: str
|
|
46
46
|
timestamp: int
|
|
47
|
-
min:
|
|
48
|
-
max:
|
|
49
|
-
step:
|
|
47
|
+
min: float | int
|
|
48
|
+
max: float | int
|
|
49
|
+
step: float | int
|
|
50
50
|
|
|
51
51
|
# Structured values by type
|
|
52
52
|
class StructuredValuesDict(TypedDict, total=False):
|
|
@@ -93,5 +93,9 @@ class NetworkInfoDict(TypedDict, total=False):
|
|
|
93
93
|
OWNERID: str
|
|
94
94
|
GROUPNAME: str
|
|
95
95
|
|
|
96
|
-
#
|
|
97
|
-
|
|
96
|
+
# Platform type constants
|
|
97
|
+
VALUE_TYPE_SENSOR: Final[str] = "sensor"
|
|
98
|
+
VALUE_TYPE_SWITCH: Final[str] = "switch"
|
|
99
|
+
VALUE_TYPE_NUMBER: Final[str] = "number"
|
|
100
|
+
VALUE_TYPE_BINARY_SENSOR: Final[str] = "binary_sensor"
|
|
101
|
+
VALUE_TYPE_SELECT: Final[str] = "select"
|
|
@@ -3,7 +3,14 @@
|
|
|
3
3
|
import logging
|
|
4
4
|
from typing import Any, Dict, Tuple, Union
|
|
5
5
|
|
|
6
|
-
from pooldose.type_definitions import
|
|
6
|
+
from pooldose.type_definitions import (
|
|
7
|
+
StructuredValuesDict,
|
|
8
|
+
VALUE_TYPE_SENSOR,
|
|
9
|
+
VALUE_TYPE_SWITCH,
|
|
10
|
+
VALUE_TYPE_NUMBER,
|
|
11
|
+
VALUE_TYPE_BINARY_SENSOR,
|
|
12
|
+
VALUE_TYPE_SELECT,
|
|
13
|
+
)
|
|
7
14
|
|
|
8
15
|
|
|
9
16
|
# pylint: disable=line-too-long,too-many-arguments,too-many-positional-arguments,too-many-locals,too-many-return-statements,too-many-branches,no-else-return,too-many-public-methods
|
|
@@ -109,19 +116,19 @@ class InstantValues:
|
|
|
109
116
|
continue
|
|
110
117
|
|
|
111
118
|
# Initialize type section if needed - use string literals for TypedDict
|
|
112
|
-
if entry_type ==
|
|
119
|
+
if entry_type == VALUE_TYPE_SENSOR:
|
|
113
120
|
if "sensor" not in structured_data:
|
|
114
121
|
structured_data["sensor"] = {}
|
|
115
|
-
elif entry_type ==
|
|
122
|
+
elif entry_type == VALUE_TYPE_SWITCH:
|
|
116
123
|
if "switch" not in structured_data:
|
|
117
124
|
structured_data["switch"] = {}
|
|
118
|
-
elif entry_type ==
|
|
125
|
+
elif entry_type == VALUE_TYPE_NUMBER:
|
|
119
126
|
if "number" not in structured_data:
|
|
120
127
|
structured_data["number"] = {}
|
|
121
|
-
elif entry_type ==
|
|
128
|
+
elif entry_type == VALUE_TYPE_BINARY_SENSOR:
|
|
122
129
|
if "binary_sensor" not in structured_data:
|
|
123
130
|
structured_data["binary_sensor"] = {}
|
|
124
|
-
elif entry_type ==
|
|
131
|
+
elif entry_type == VALUE_TYPE_SELECT:
|
|
125
132
|
if "select" not in structured_data:
|
|
126
133
|
structured_data["select"] = {}
|
|
127
134
|
|
|
@@ -132,24 +139,24 @@ class InstantValues:
|
|
|
132
139
|
continue
|
|
133
140
|
|
|
134
141
|
# Structure the data based on type - use string literals for TypedDict
|
|
135
|
-
if entry_type ==
|
|
142
|
+
if entry_type == VALUE_TYPE_SENSOR:
|
|
136
143
|
if isinstance(value_data, tuple) and len(value_data) >= 2:
|
|
137
144
|
structured_data["sensor"][mapping_key] = {
|
|
138
145
|
"value": value_data[0],
|
|
139
146
|
"unit": value_data[1]
|
|
140
147
|
}
|
|
141
148
|
|
|
142
|
-
elif entry_type ==
|
|
149
|
+
elif entry_type == VALUE_TYPE_BINARY_SENSOR:
|
|
143
150
|
structured_data["binary_sensor"][mapping_key] = {
|
|
144
151
|
"value": value_data
|
|
145
152
|
}
|
|
146
153
|
|
|
147
|
-
elif entry_type ==
|
|
154
|
+
elif entry_type == VALUE_TYPE_SWITCH:
|
|
148
155
|
structured_data["switch"][mapping_key] = {
|
|
149
156
|
"value": value_data
|
|
150
157
|
}
|
|
151
158
|
|
|
152
|
-
elif entry_type ==
|
|
159
|
+
elif entry_type == VALUE_TYPE_NUMBER:
|
|
153
160
|
if isinstance(value_data, tuple) and len(value_data) >= 5:
|
|
154
161
|
structured_data["number"][mapping_key] = {
|
|
155
162
|
"value": value_data[0],
|
|
@@ -159,7 +166,7 @@ class InstantValues:
|
|
|
159
166
|
"step": value_data[4]
|
|
160
167
|
}
|
|
161
168
|
|
|
162
|
-
elif entry_type ==
|
|
169
|
+
elif entry_type == VALUE_TYPE_SELECT:
|
|
163
170
|
structured_data["select"][mapping_key] = {
|
|
164
171
|
"value": value_data
|
|
165
172
|
}
|
|
@@ -216,15 +223,15 @@ class InstantValues:
|
|
|
216
223
|
return None
|
|
217
224
|
|
|
218
225
|
# Process based on entry type
|
|
219
|
-
if entry_type ==
|
|
226
|
+
if entry_type == VALUE_TYPE_SENSOR:
|
|
220
227
|
return self._process_sensor_value(raw_entry, attributes, name)
|
|
221
|
-
elif entry_type ==
|
|
228
|
+
elif entry_type == VALUE_TYPE_BINARY_SENSOR:
|
|
222
229
|
return self._process_binary_sensor_value(raw_entry, attributes, name)
|
|
223
|
-
elif entry_type ==
|
|
230
|
+
elif entry_type == VALUE_TYPE_SWITCH:
|
|
224
231
|
return self._process_switch_value(raw_entry, name)
|
|
225
|
-
elif entry_type ==
|
|
232
|
+
elif entry_type == VALUE_TYPE_NUMBER:
|
|
226
233
|
return self._process_number_value(raw_entry, name)
|
|
227
|
-
elif entry_type ==
|
|
234
|
+
elif entry_type == VALUE_TYPE_SELECT:
|
|
228
235
|
return self._process_select_value(raw_entry, attributes)
|
|
229
236
|
else:
|
|
230
237
|
_LOGGER.warning("Unknown type '%s' for key '%s'", entry_type, name)
|
|
@@ -357,7 +364,7 @@ class InstantValues:
|
|
|
357
364
|
|
|
358
365
|
async def set_number(self, key: str, value: Any) -> bool:
|
|
359
366
|
"""Set number value with validation and device update."""
|
|
360
|
-
if key not in self._mapping or self._mapping[key].get("type") !=
|
|
367
|
+
if key not in self._mapping or self._mapping[key].get("type") != VALUE_TYPE_NUMBER:
|
|
361
368
|
_LOGGER.warning("Key '%s' is not a valid number", key)
|
|
362
369
|
return False
|
|
363
370
|
|
|
@@ -405,7 +412,7 @@ class InstantValues:
|
|
|
405
412
|
|
|
406
413
|
async def set_switch(self, key: str, value: bool) -> bool:
|
|
407
414
|
"""Set switch value with validation and device update."""
|
|
408
|
-
if key not in self._mapping or self._mapping[key].get("type") !=
|
|
415
|
+
if key not in self._mapping or self._mapping[key].get("type") != VALUE_TYPE_SWITCH:
|
|
409
416
|
_LOGGER.warning("Key '%s' is not a valid switch", key)
|
|
410
417
|
return False
|
|
411
418
|
try:
|
|
@@ -426,7 +433,7 @@ class InstantValues:
|
|
|
426
433
|
|
|
427
434
|
async def set_select(self, key: str, value: Any) -> bool:
|
|
428
435
|
"""Set select value with validation and device update."""
|
|
429
|
-
if key not in self._mapping or self._mapping[key].get("type") !=
|
|
436
|
+
if key not in self._mapping or self._mapping[key].get("type") != VALUE_TYPE_SELECT:
|
|
430
437
|
_LOGGER.warning("Key '%s' is not a valid select", key)
|
|
431
438
|
return False
|
|
432
439
|
try:
|
|
@@ -468,7 +475,7 @@ class InstantValues:
|
|
|
468
475
|
corresponding_field = "maxT" if field == "minT" else "minT"
|
|
469
476
|
# Search for the mapping entry with the corresponding field
|
|
470
477
|
for k, v in self._mapping.items():
|
|
471
|
-
if v.get("type") ==
|
|
478
|
+
if v.get("type") == VALUE_TYPE_NUMBER and v.get("field") == corresponding_field and v.get("key") == attributes.get("key"):
|
|
472
479
|
val = self[k]
|
|
473
480
|
return val[0] if isinstance(val, tuple) else val
|
|
474
481
|
# Fallback: get from raw device entry if not found in mapping
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-pooldose
|
|
3
|
-
Version: 0.8.
|
|
3
|
+
Version: 0.8.2
|
|
4
4
|
Summary: Unoffical async Python client for SEKO PoolDose devices
|
|
5
5
|
Author-email: Lukas Maertin <pypi@lukas-maertin.de>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -918,6 +918,7 @@ This package is **PEP-561 compliant** and fully typed for use in Home Assistant
|
|
|
918
918
|
|
|
919
919
|
**PEP-561 Compliance**: Package includes `py.typed` file marking it as fully typed
|
|
920
920
|
**Comprehensive Type Annotations**: All public API methods have complete type hints
|
|
921
|
+
**Type Constants**: Centralized `VALUE_TYPE_*` constants eliminate string literals for entity types
|
|
921
922
|
**mypy Support**: Built-in mypy configuration for static type checking
|
|
922
923
|
**Home Assistant Ready**: Compatible with Home Assistant's strict typing requirements
|
|
923
924
|
|
|
@@ -985,7 +986,6 @@ Data Classification:
|
|
|
985
986
|
|
|
986
987
|
For detailed release notes and version history, please see [CHANGELOG.md](CHANGELOG.md).
|
|
987
988
|
|
|
988
|
-
### Latest Release (0.8.
|
|
989
|
+
### Latest Release (0.8.2)
|
|
989
990
|
|
|
990
|
-
- **
|
|
991
|
-
- **Mapping Consistency**: OFA threshold mappings renamed for consistency (`ofa_orp_*`, `ofa_cl_*`)
|
|
991
|
+
- **Type Constants**: centralized runtime constants for platform types
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_pooldose-0.8.1 → python_pooldose-0.8.2}/src/python_pooldose.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{python_pooldose-0.8.1 → python_pooldose-0.8.2}/src/python_pooldose.egg-info/entry_points.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|