python-pooldose 0.8.0__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.0 → python_pooldose-0.8.2}/PKG-INFO +4 -3
- {python_pooldose-0.8.0 → python_pooldose-0.8.2}/README.md +3 -2
- {python_pooldose-0.8.0 → python_pooldose-0.8.2}/src/pooldose/__init__.py +1 -1
- {python_pooldose-0.8.0 → python_pooldose-0.8.2}/src/pooldose/mappings/mapping_info.py +12 -5
- {python_pooldose-0.8.0 → python_pooldose-0.8.2}/src/pooldose/mappings/model_PDHC1H1HAR1V1_FW539224.json +4 -4
- {python_pooldose-0.8.0 → python_pooldose-0.8.2}/src/pooldose/type_definitions.py +12 -8
- {python_pooldose-0.8.0 → python_pooldose-0.8.2}/src/pooldose/values/instant_values.py +33 -20
- {python_pooldose-0.8.0 → python_pooldose-0.8.2}/src/python_pooldose.egg-info/PKG-INFO +4 -3
- {python_pooldose-0.8.0 → python_pooldose-0.8.2}/tests/test_instant_values.py +15 -0
- {python_pooldose-0.8.0 → python_pooldose-0.8.2}/LICENSE +0 -0
- {python_pooldose-0.8.0 → python_pooldose-0.8.2}/pyproject.toml +0 -0
- {python_pooldose-0.8.0 → python_pooldose-0.8.2}/setup.cfg +0 -0
- {python_pooldose-0.8.0 → python_pooldose-0.8.2}/src/pooldose/__main__.py +0 -0
- {python_pooldose-0.8.0 → python_pooldose-0.8.2}/src/pooldose/client.py +0 -0
- {python_pooldose-0.8.0 → python_pooldose-0.8.2}/src/pooldose/constants.py +0 -0
- {python_pooldose-0.8.0 → python_pooldose-0.8.2}/src/pooldose/device_analyzer.py +0 -0
- {python_pooldose-0.8.0 → python_pooldose-0.8.2}/src/pooldose/mappings/__init__.py +0 -0
- {python_pooldose-0.8.0 → python_pooldose-0.8.2}/src/pooldose/mappings/model_PDPR1H1HAR1V0_FW539224.json +0 -0
- {python_pooldose-0.8.0 → python_pooldose-0.8.2}/src/pooldose/mappings/model_PDPR1H1HAW100_FW539187.json +0 -0
- {python_pooldose-0.8.0 → python_pooldose-0.8.2}/src/pooldose/mock_client.py +0 -0
- {python_pooldose-0.8.0 → python_pooldose-0.8.2}/src/pooldose/py.typed +0 -0
- {python_pooldose-0.8.0 → python_pooldose-0.8.2}/src/pooldose/request_handler.py +0 -0
- {python_pooldose-0.8.0 → python_pooldose-0.8.2}/src/pooldose/request_status.py +0 -0
- {python_pooldose-0.8.0 → python_pooldose-0.8.2}/src/pooldose/values/__init__.py +0 -0
- {python_pooldose-0.8.0 → python_pooldose-0.8.2}/src/pooldose/values/static_values.py +0 -0
- {python_pooldose-0.8.0 → python_pooldose-0.8.2}/src/python_pooldose.egg-info/SOURCES.txt +0 -0
- {python_pooldose-0.8.0 → python_pooldose-0.8.2}/src/python_pooldose.egg-info/dependency_links.txt +0 -0
- {python_pooldose-0.8.0 → python_pooldose-0.8.2}/src/python_pooldose.egg-info/entry_points.txt +0 -0
- {python_pooldose-0.8.0 → python_pooldose-0.8.2}/src/python_pooldose.egg-info/requires.txt +0 -0
- {python_pooldose-0.8.0 → python_pooldose-0.8.2}/src/python_pooldose.egg-info/top_level.txt +0 -0
- {python_pooldose-0.8.0 → python_pooldose-0.8.2}/tests/test_client.py +0 -0
- {python_pooldose-0.8.0 → python_pooldose-0.8.2}/tests/test_device_analyzer.py +0 -0
- {python_pooldose-0.8.0 → python_pooldose-0.8.2}/tests/test_device_analyzer_integration.py +0 -0
- {python_pooldose-0.8.0 → python_pooldose-0.8.2}/tests/test_mapping_info.py +0 -0
- {python_pooldose-0.8.0 → python_pooldose-0.8.2}/tests/test_mock_client_set_value.py +0 -0
- {python_pooldose-0.8.0 → python_pooldose-0.8.2}/tests/test_request_handler.py +0 -0
- {python_pooldose-0.8.0 → python_pooldose-0.8.2}/tests/test_ssl_support.py +0 -0
- {python_pooldose-0.8.0 → 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,6 +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
|
+
- **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,6 +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
|
+
- **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"],
|
|
@@ -119,22 +119,22 @@
|
|
|
119
119
|
"type": "number",
|
|
120
120
|
"field": "maxT"
|
|
121
121
|
},
|
|
122
|
-
"
|
|
122
|
+
"ofa_orp_lower": {
|
|
123
123
|
"key": "w_1g1l13bkn",
|
|
124
124
|
"type": "number",
|
|
125
125
|
"field": "minT"
|
|
126
126
|
},
|
|
127
|
-
"
|
|
127
|
+
"ofa_orp_upper": {
|
|
128
128
|
"key": "w_1g1l13bkn",
|
|
129
129
|
"type": "number",
|
|
130
130
|
"field": "maxT"
|
|
131
131
|
},
|
|
132
|
-
"
|
|
132
|
+
"ofa_cl_lower": {
|
|
133
133
|
"key": "w_1g1l13dke",
|
|
134
134
|
"type": "number",
|
|
135
135
|
"field": "minT"
|
|
136
136
|
},
|
|
137
|
-
"
|
|
137
|
+
"ofa_cl_upper": {
|
|
138
138
|
"key": "w_1g1l13dke",
|
|
139
139
|
"type": "number",
|
|
140
140
|
"field": "maxT"
|
|
@@ -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)
|
|
@@ -251,6 +258,9 @@ class InstantValues:
|
|
|
251
258
|
# Get unit
|
|
252
259
|
units = raw_entry.get("magnitude", [""])
|
|
253
260
|
unit = units[0] if units and units[0].lower() not in ("undefined", "ph") else None
|
|
261
|
+
# Convert CL2/Chlorine to ppm
|
|
262
|
+
if unit and unit.lower() in ("cl2", "chlorine"):
|
|
263
|
+
unit = "ppm"
|
|
254
264
|
|
|
255
265
|
return (value, unit)
|
|
256
266
|
|
|
@@ -318,6 +328,9 @@ class InstantValues:
|
|
|
318
328
|
# Get unit
|
|
319
329
|
units = raw_entry.get("magnitude", [""])
|
|
320
330
|
unit = units[0] if isinstance(units, (list, tuple)) and units and str(units[0]).lower() not in ("undefined", "ph") else None
|
|
331
|
+
# Convert CL2/Chlorine to ppm
|
|
332
|
+
if unit and str(unit).lower() in ("cl2", "chlorine"):
|
|
333
|
+
unit = "ppm"
|
|
321
334
|
|
|
322
335
|
return (value, unit, abs_min, abs_max, resolution)
|
|
323
336
|
|
|
@@ -351,7 +364,7 @@ class InstantValues:
|
|
|
351
364
|
|
|
352
365
|
async def set_number(self, key: str, value: Any) -> bool:
|
|
353
366
|
"""Set number value with validation and device update."""
|
|
354
|
-
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:
|
|
355
368
|
_LOGGER.warning("Key '%s' is not a valid number", key)
|
|
356
369
|
return False
|
|
357
370
|
|
|
@@ -399,7 +412,7 @@ class InstantValues:
|
|
|
399
412
|
|
|
400
413
|
async def set_switch(self, key: str, value: bool) -> bool:
|
|
401
414
|
"""Set switch value with validation and device update."""
|
|
402
|
-
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:
|
|
403
416
|
_LOGGER.warning("Key '%s' is not a valid switch", key)
|
|
404
417
|
return False
|
|
405
418
|
try:
|
|
@@ -420,7 +433,7 @@ class InstantValues:
|
|
|
420
433
|
|
|
421
434
|
async def set_select(self, key: str, value: Any) -> bool:
|
|
422
435
|
"""Set select value with validation and device update."""
|
|
423
|
-
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:
|
|
424
437
|
_LOGGER.warning("Key '%s' is not a valid select", key)
|
|
425
438
|
return False
|
|
426
439
|
try:
|
|
@@ -462,7 +475,7 @@ class InstantValues:
|
|
|
462
475
|
corresponding_field = "maxT" if field == "minT" else "minT"
|
|
463
476
|
# Search for the mapping entry with the corresponding field
|
|
464
477
|
for k, v in self._mapping.items():
|
|
465
|
-
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"):
|
|
466
479
|
val = self[k]
|
|
467
480
|
return val[0] if isinstance(val, tuple) else val
|
|
468
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,6 +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
|
+
- **Type Constants**: centralized runtime constants for platform types
|
|
@@ -20,6 +20,12 @@ class TestInstantValues: # pylint: disable=too-many-public-methods
|
|
|
20
20
|
assert value == 25.5
|
|
21
21
|
assert unit == "°C"
|
|
22
22
|
|
|
23
|
+
def test_getitem_sensor_chlorine_unit(self, instant_values_fixture):
|
|
24
|
+
"""Test getting chlorine sensor values with ppm unit conversion."""
|
|
25
|
+
value, unit = instant_values_fixture["chlorine"]
|
|
26
|
+
assert value == 0.5
|
|
27
|
+
assert unit == "ppm"
|
|
28
|
+
|
|
23
29
|
def test_getitem_sensor_with_conversion(self, instant_values_fixture):
|
|
24
30
|
"""Test getting sensor values with string conversion."""
|
|
25
31
|
value, unit = instant_values_fixture["ph_type_dosing"]
|
|
@@ -35,6 +41,15 @@ class TestInstantValues: # pylint: disable=too-many-public-methods
|
|
|
35
41
|
assert max_val == 8.0
|
|
36
42
|
assert step == 0.1
|
|
37
43
|
|
|
44
|
+
def test_getitem_number_chlorine_unit(self, instant_values_fixture):
|
|
45
|
+
"""Test getting chlorine number values with ppm unit conversion."""
|
|
46
|
+
value, unit, min_val, max_val, step = instant_values_fixture["chlorine_target"]
|
|
47
|
+
assert value == 0.6
|
|
48
|
+
assert unit == "ppm"
|
|
49
|
+
assert min_val == 0.3
|
|
50
|
+
assert max_val == 3.0
|
|
51
|
+
assert step == 0.1
|
|
52
|
+
|
|
38
53
|
def test_getitem_switch(self, instant_values_fixture):
|
|
39
54
|
"""Test getting switch values."""
|
|
40
55
|
value = instant_values_fixture["pump_switch"]
|
|
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.0 → python_pooldose-0.8.2}/src/python_pooldose.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{python_pooldose-0.8.0 → 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
|