python-pooldose 0.6.6__tar.gz → 0.6.8__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.
Files changed (35) hide show
  1. {python_pooldose-0.6.6 → python_pooldose-0.6.8}/PKG-INFO +6 -3
  2. {python_pooldose-0.6.6 → python_pooldose-0.6.8}/README.md +4 -2
  3. {python_pooldose-0.6.6 → python_pooldose-0.6.8}/pyproject.toml +6 -11
  4. {python_pooldose-0.6.6 → python_pooldose-0.6.8}/src/pooldose/__init__.py +1 -1
  5. {python_pooldose-0.6.6 → python_pooldose-0.6.8}/src/pooldose/__main__.py +4 -0
  6. {python_pooldose-0.6.6 → python_pooldose-0.6.8}/src/pooldose/client.py +11 -2
  7. {python_pooldose-0.6.6 → python_pooldose-0.6.8}/src/pooldose/device_analyzer.py +4 -3
  8. {python_pooldose-0.6.6 → python_pooldose-0.6.8}/src/pooldose/mappings/model_PDPR1H1HAR1V0_FW539224.json +12 -4
  9. {python_pooldose-0.6.6 → python_pooldose-0.6.8}/src/pooldose/mock_client.py +5 -2
  10. {python_pooldose-0.6.6 → python_pooldose-0.6.8}/src/pooldose/values/instant_values.py +9 -5
  11. {python_pooldose-0.6.6 → python_pooldose-0.6.8}/src/python_pooldose.egg-info/PKG-INFO +6 -3
  12. {python_pooldose-0.6.6 → python_pooldose-0.6.8}/src/python_pooldose.egg-info/requires.txt +1 -0
  13. {python_pooldose-0.6.6 → python_pooldose-0.6.8}/tests/test_client.py +1 -0
  14. {python_pooldose-0.6.6 → python_pooldose-0.6.8}/tests/test_instant_values.py +2 -1
  15. {python_pooldose-0.6.6 → python_pooldose-0.6.8}/LICENSE +0 -0
  16. {python_pooldose-0.6.6 → python_pooldose-0.6.8}/setup.cfg +0 -0
  17. {python_pooldose-0.6.6 → python_pooldose-0.6.8}/src/pooldose/constants.py +0 -0
  18. {python_pooldose-0.6.6 → python_pooldose-0.6.8}/src/pooldose/mappings/__init__.py +0 -0
  19. {python_pooldose-0.6.6 → python_pooldose-0.6.8}/src/pooldose/mappings/mapping_info.py +0 -0
  20. {python_pooldose-0.6.6 → python_pooldose-0.6.8}/src/pooldose/mappings/model_PDPR1H1HAW100_FW539187.json +0 -0
  21. {python_pooldose-0.6.6 → python_pooldose-0.6.8}/src/pooldose/py.typed +0 -0
  22. {python_pooldose-0.6.6 → python_pooldose-0.6.8}/src/pooldose/request_handler.py +0 -0
  23. {python_pooldose-0.6.6 → python_pooldose-0.6.8}/src/pooldose/request_status.py +0 -0
  24. {python_pooldose-0.6.6 → python_pooldose-0.6.8}/src/pooldose/values/__init__.py +0 -0
  25. {python_pooldose-0.6.6 → python_pooldose-0.6.8}/src/pooldose/values/static_values.py +0 -0
  26. {python_pooldose-0.6.6 → python_pooldose-0.6.8}/src/python_pooldose.egg-info/SOURCES.txt +0 -0
  27. {python_pooldose-0.6.6 → python_pooldose-0.6.8}/src/python_pooldose.egg-info/dependency_links.txt +0 -0
  28. {python_pooldose-0.6.6 → python_pooldose-0.6.8}/src/python_pooldose.egg-info/entry_points.txt +0 -0
  29. {python_pooldose-0.6.6 → python_pooldose-0.6.8}/src/python_pooldose.egg-info/top_level.txt +0 -0
  30. {python_pooldose-0.6.6 → python_pooldose-0.6.8}/tests/test_device_analyzer.py +0 -0
  31. {python_pooldose-0.6.6 → python_pooldose-0.6.8}/tests/test_device_analyzer_integration.py +0 -0
  32. {python_pooldose-0.6.6 → python_pooldose-0.6.8}/tests/test_mapping_info.py +0 -0
  33. {python_pooldose-0.6.6 → python_pooldose-0.6.8}/tests/test_request_handler.py +0 -0
  34. {python_pooldose-0.6.6 → python_pooldose-0.6.8}/tests/test_ssl_support.py +0 -0
  35. {python_pooldose-0.6.6 → python_pooldose-0.6.8}/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.6.6
3
+ Version: 0.6.8
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
@@ -11,6 +11,7 @@ Description-Content-Type: text/markdown
11
11
  License-File: LICENSE
12
12
  Requires-Dist: aiohttp
13
13
  Requires-Dist: aiofiles
14
+ Requires-Dist: getmac
14
15
  Provides-Extra: dev
15
16
  Requires-Dist: pytest; extra == "dev"
16
17
  Requires-Dist: pytest-asyncio; extra == "dev"
@@ -942,6 +943,8 @@ Data Classification:
942
943
 
943
944
  For detailed release notes and version history, please see [CHANGELOG.md](CHANGELOG.md).
944
945
 
945
- ### Latest Release (0.6.6)
946
+ ### Latest Release (0.6.8)
946
947
 
947
- - **Mapping**: Fixed for PDPR1H1HAR1V0_FW539224**
948
+ - **Client**: Implemented alternate method to retrieve MAC address of device
949
+ - **Mapping**: Further fixes for PDPR1H1HAR1V0_FW539224
950
+ - **Values**: Added conversion for binary sensors
@@ -924,6 +924,8 @@ Data Classification:
924
924
 
925
925
  For detailed release notes and version history, please see [CHANGELOG.md](CHANGELOG.md).
926
926
 
927
- ### Latest Release (0.6.6)
927
+ ### Latest Release (0.6.8)
928
928
 
929
- - **Mapping**: Fixed for PDPR1H1HAR1V0_FW539224**
929
+ - **Client**: Implemented alternate method to retrieve MAC address of device
930
+ - **Mapping**: Further fixes for PDPR1H1HAR1V0_FW539224
931
+ - **Values**: Added conversion for binary sensors
@@ -2,16 +2,11 @@
2
2
  name = "python-pooldose"
3
3
  dynamic = ["version"]
4
4
  description = "Unoffical async Python client for SEKO PoolDose devices"
5
- authors = [
6
- { name = "Lukas Maertin", email = "pypi@lukas-maertin.de" }
7
- ]
5
+ authors = [{ name = "Lukas Maertin", email = "pypi@lukas-maertin.de" }]
8
6
  license = "MIT"
9
7
  readme = "README.md"
10
8
  requires-python = ">=3.11"
11
- dependencies = [
12
- "aiohttp",
13
- "aiofiles"
14
- ]
9
+ dependencies = ["aiohttp", "aiofiles", "getmac"]
15
10
 
16
11
  [project.urls]
17
12
  Homepage = "https://github.com/lmaertin/python-pooldose"
@@ -28,10 +23,10 @@ build-backend = "setuptools.build_meta"
28
23
  dev = ["pytest", "pytest-asyncio"]
29
24
 
30
25
  [tool.setuptools]
31
- package-dir = {"" = "src"}
26
+ package-dir = { "" = "src" }
32
27
 
33
28
  [tool.setuptools.dynamic]
34
- version = {attr = "pooldose.__version__"}
29
+ version = { attr = "pooldose.__version__" }
35
30
 
36
31
  [tool.setuptools.packages.find]
37
32
  where = ["src"]
@@ -67,7 +62,7 @@ module = "examples.*"
67
62
  ignore_errors = true
68
63
 
69
64
  [[tool.mypy.overrides]]
70
- module = "tests.*"
65
+ module = "tests.*"
71
66
  ignore_errors = true
72
67
 
73
68
  # Strict typing for core public API modules
@@ -85,4 +80,4 @@ warn_return_any = false
85
80
  [[tool.mypy.overrides]]
86
81
  module = "pooldose.request_status"
87
82
  disallow_untyped_defs = true
88
- disallow_incomplete_defs = true
83
+ disallow_incomplete_defs = true
@@ -1,5 +1,5 @@
1
1
  """Async API client for SEKO Pooldose."""
2
2
  from .client import PooldoseClient
3
3
 
4
- __version__ = "0.6.6"
4
+ __version__ = "0.6.8"
5
5
  __all__ = ["PooldoseClient"]
@@ -12,6 +12,8 @@ from pooldose.device_analyzer import DeviceAnalyzer
12
12
  from pooldose.mock_client import MockPooldoseClient
13
13
  from pooldose.request_handler import RequestHandler
14
14
 
15
+ # pylint: disable=line-too-long
16
+
15
17
  # Import demo utilities if available
16
18
  try:
17
19
  from examples.demo_utils import (display_static_values,
@@ -25,6 +27,8 @@ except ImportError:
25
27
  ("Serial", static_values.sensor_serial_number),
26
28
  ("Model", static_values.sensor_model),
27
29
  ("Firmware", static_values.sensor_fw_version),
30
+ ("IP", static_values.sensor_ip),
31
+ ("MAC", static_values.sensor_mac)
28
32
  ]
29
33
  print("\nDevice Information:")
30
34
  for label, value in device_info:
@@ -5,6 +5,7 @@ from __future__ import annotations
5
5
  import asyncio
6
6
  import logging
7
7
  from typing import Any, Dict, Optional, Tuple
8
+ from getmac import get_mac_address
8
9
 
9
10
  from pooldose.constants import get_default_device_info
10
11
  from pooldose.mappings.mapping_info import MappingInfo
@@ -121,7 +122,7 @@ class PooldoseClient:
121
122
 
122
123
  return RequestStatus.SUCCESS, result
123
124
 
124
- async def _load_device_info(self) -> RequestStatus: # pylint: disable=too-many-branches
125
+ async def _load_device_info(self) -> RequestStatus: # pylint: disable=too-many-branches, too-many-statements
125
126
  """
126
127
  Load device information from the request handler.
127
128
  This method should be called after a successful connection.
@@ -164,7 +165,6 @@ class PooldoseClient:
164
165
  _LOGGER.warning("Failed to fetch WiFi station info: %s", status)
165
166
  else:
166
167
  self.device_info["WIFI_SSID"] = wifi_station.get("SSID")
167
- self.device_info["MAC"] = wifi_station.get("MAC")
168
168
  self.device_info["IP"] = wifi_station.get("IP")
169
169
  # Only include WiFi key if explicitly requested
170
170
  if self._include_sensitive_data:
@@ -193,6 +193,15 @@ class PooldoseClient:
193
193
  if self._include_sensitive_data:
194
194
  _LOGGER.info("Included WiFi and AP keys (use include_sensitive_data=False to exclude)")
195
195
 
196
+ # MAC address via getmac library
197
+ if self.device_info["IP"]:
198
+ self.device_info["MAC"] = get_mac_address(ip=self.device_info["IP"])
199
+ if not self.device_info["MAC"]:
200
+ _LOGGER.warning("Failed to fetch MAC address via getmac library for IP: %s", self.device_info["IP"])
201
+ else:
202
+ _LOGGER.warning("IP address not set, cannot fetch MAC address via getmac library")
203
+ self.device_info["MAC"] = None
204
+
196
205
  return RequestStatus.SUCCESS
197
206
 
198
207
  @property
@@ -67,7 +67,7 @@ class DeviceAnalyzer:
67
67
  if key in SKIP_KEYS:
68
68
  continue
69
69
 
70
- # Pattern: {MODEL}_{FW_CODE}_w_{SHORT_ID} or {MODEL}_{FW_CODE}_Elapsed_{...}
70
+ # Pattern: {MODEL}_{FW_CODE}_w_{SHORT_ID}
71
71
  match = re.match(r"^([A-Z0-9]+)_(FW[A-Z0-9]+)_", key)
72
72
  if match:
73
73
  model = match.group(1)
@@ -390,8 +390,9 @@ class DeviceAnalyzer:
390
390
 
391
391
  return detail_strings
392
392
 
393
- def _print_footer(self, widgets: List[WidgetInfo], filtered_widgets: List[WidgetInfo],
394
- show_all: bool) -> None:
393
+ def _print_footer(self, widgets: List[WidgetInfo],
394
+ filtered_widgets: List[WidgetInfo],
395
+ show_all: bool) -> None:
395
396
  """Print analysis footer."""
396
397
  print(f"\n{'='*SEPARATOR_LENGTH}")
397
398
  print("ANALYSIS COMPLETE")
@@ -60,8 +60,12 @@
60
60
  "type": "sensor"
61
61
  },
62
62
  "pump_running": {
63
- "key": "w_1f0iqe0vh",
64
- "type": "binary_sensor"
63
+ "key": "w_1f1fng00q",
64
+ "type": "binary_sensor",
65
+ "conversion": {
66
+ "|PDPR1H1HAR1V0_FW539224_LABEL_w_1f1fng00q_OFF|": "F",
67
+ "|PDPR1H1HAR1V0_FW539224_LABEL_w_1f1fng00q_ON|": "O"
68
+ }
65
69
  },
66
70
  "ph_level_ok": {
67
71
  "key": "w_1f0ioo093",
@@ -100,8 +104,12 @@
100
104
  "type": "switch"
101
105
  },
102
106
  "pump_detection": {
103
- "key": "w_1f2jpqa6e",
104
- "type": "switch"
107
+ "key": "w_1hn0vte5j",
108
+ "type": "binary_sensor",
109
+ "conversion": {
110
+ "|PDPR1H1HAR1V0_FW539224_LABEL_w_1hn0vte5j_DISABLED|": "F",
111
+ "|PDPR1H1HAR1V0_FW539224_LABEL_w_1hn0vte5j_ENABLED|": "O"
112
+ }
105
113
  },
106
114
  "water_meter_unit": {
107
115
  "key": "w_1f3dfp59r",
@@ -109,8 +109,11 @@ class MockPooldoseClient:
109
109
  "DEVICE_ID": self._device_key,
110
110
  "MODEL": model or "MOCK_MODEL",
111
111
  "MODEL_ID": model or "MOCK_MODEL",
112
- "FW_CODE": (fw_code.replace('FW', '') if fw_code and fw_code.startswith('FW')
113
- else fw_code or "MOCK_FW"),
112
+ "FW_CODE": (
113
+ fw_code.replace('FW', '')
114
+ if fw_code and fw_code.startswith('FW')
115
+ else fw_code or "MOCK_FW"
116
+ ),
114
117
  "API_VERSION": API_VERSION_SUPPORTED,
115
118
  "IP": "127.0.0.1", # Mock IP
116
119
  })
@@ -189,7 +189,7 @@ class InstantValues:
189
189
  if entry_type == "sensor":
190
190
  return self._process_sensor_value(raw_entry, attributes, name)
191
191
  elif entry_type == "binary_sensor":
192
- return self._process_binary_sensor_value(raw_entry, name)
192
+ return self._process_binary_sensor_value(raw_entry, attributes, name)
193
193
  elif entry_type == "switch":
194
194
  return self._process_switch_value(raw_entry, name)
195
195
  elif entry_type == "number":
@@ -224,15 +224,19 @@ class InstantValues:
224
224
 
225
225
  return (value, unit)
226
226
 
227
- def _process_binary_sensor_value(self, raw_entry: Dict[str, Any], name: str) -> Union[bool, None]:
228
- """Process binary sensor value and return bool."""
227
+ def _process_binary_sensor_value(self, raw_entry: Dict[str, Any], attributes: Dict[str, Any], name: str) -> Union[bool, None]:
228
+ """Process binary sensor value and return bool, with optional conversion mapping."""
229
229
  if not isinstance(raw_entry, dict):
230
230
  _LOGGER.warning("Invalid raw entry type for binary sensor '%s': expected dict, got %s", name, type(raw_entry))
231
231
  return None
232
232
 
233
233
  value = raw_entry.get("current")
234
- if value is None:
235
- return None
234
+
235
+ # Apply conversion mapping if defined in mapping
236
+ if value is not None and "conversion" in attributes:
237
+ conversion = attributes["conversion"]
238
+ if isinstance(conversion, dict) and str(value) in conversion:
239
+ value = conversion[str(value)]
236
240
 
237
241
  # Convert string values to boolean
238
242
  if isinstance(value, str):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-pooldose
3
- Version: 0.6.6
3
+ Version: 0.6.8
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
@@ -11,6 +11,7 @@ Description-Content-Type: text/markdown
11
11
  License-File: LICENSE
12
12
  Requires-Dist: aiohttp
13
13
  Requires-Dist: aiofiles
14
+ Requires-Dist: getmac
14
15
  Provides-Extra: dev
15
16
  Requires-Dist: pytest; extra == "dev"
16
17
  Requires-Dist: pytest-asyncio; extra == "dev"
@@ -942,6 +943,8 @@ Data Classification:
942
943
 
943
944
  For detailed release notes and version history, please see [CHANGELOG.md](CHANGELOG.md).
944
945
 
945
- ### Latest Release (0.6.6)
946
+ ### Latest Release (0.6.8)
946
947
 
947
- - **Mapping**: Fixed for PDPR1H1HAR1V0_FW539224**
948
+ - **Client**: Implemented alternate method to retrieve MAC address of device
949
+ - **Mapping**: Further fixes for PDPR1H1HAR1V0_FW539224
950
+ - **Values**: Added conversion for binary sensors
@@ -1,5 +1,6 @@
1
1
  aiohttp
2
2
  aiofiles
3
+ getmac
3
4
 
4
5
  [dev]
5
6
  pytest
@@ -8,6 +8,7 @@ from pooldose.request_status import RequestStatus
8
8
  from pooldose.values.instant_values import InstantValues
9
9
  from pooldose.values.static_values import StaticValues
10
10
 
11
+ # pylint: disable=line-too-long
11
12
 
12
13
  class TestPooldoseClient:
13
14
  """Test PooldoseClient functionality."""
@@ -2,6 +2,7 @@
2
2
 
3
3
  import pytest
4
4
 
5
+ # pylint: disable=line-too-long
5
6
 
6
7
  class TestInstantValues: # pylint: disable=too-many-public-methods
7
8
  """Test InstantValues functionality."""
@@ -158,7 +159,7 @@ class TestInstantValues: # pylint: disable=too-many-public-methods
158
159
  def test_process_binary_sensor_value_invalid_entry(self, instant_values_fixture):
159
160
  """Test processing binary sensor value with invalid entry."""
160
161
  # pylint: disable=protected-access
161
- value = instant_values_fixture._process_binary_sensor_value("invalid", "test")
162
+ value = instant_values_fixture._process_binary_sensor_value("invalid", {}, "test")
162
163
  assert value is None
163
164
 
164
165
  def test_process_switch_value_bool(self, instant_values_fixture):
File without changes