violet-poolController-api 0.0.25__tar.gz → 0.0.26__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 (25) hide show
  1. {violet_poolcontroller_api-0.0.25/violet_poolController_api.egg-info → violet_poolcontroller_api-0.0.26}/PKG-INFO +3 -3
  2. {violet_poolcontroller_api-0.0.25 → violet_poolcontroller_api-0.0.26}/pyproject.toml +5 -5
  3. {violet_poolcontroller_api-0.0.25 → violet_poolcontroller_api-0.0.26}/setup.py +1 -1
  4. violet_poolcontroller_api-0.0.26/tests/conftest.py +40 -0
  5. {violet_poolcontroller_api-0.0.25 → violet_poolcontroller_api-0.0.26/violet_poolController_api.egg-info}/PKG-INFO +3 -3
  6. {violet_poolcontroller_api-0.0.25 → violet_poolcontroller_api-0.0.26}/violet_poolController_api.egg-info/SOURCES.txt +1 -0
  7. violet_poolcontroller_api-0.0.26/violet_poolController_api.egg-info/requires.txt +6 -0
  8. {violet_poolcontroller_api-0.0.25 → violet_poolcontroller_api-0.0.26}/violet_poolcontroller_api/api.py +25 -17
  9. {violet_poolcontroller_api-0.0.25 → violet_poolcontroller_api-0.0.26}/violet_poolcontroller_api/utils_rate_limiter.py +3 -8
  10. violet_poolcontroller_api-0.0.25/violet_poolController_api.egg-info/requires.txt +0 -6
  11. {violet_poolcontroller_api-0.0.25 → violet_poolcontroller_api-0.0.26}/LICENSE +0 -0
  12. {violet_poolcontroller_api-0.0.25 → violet_poolcontroller_api-0.0.26}/README.md +0 -0
  13. {violet_poolcontroller_api-0.0.25 → violet_poolcontroller_api-0.0.26}/setup.cfg +0 -0
  14. {violet_poolcontroller_api-0.0.25 → violet_poolcontroller_api-0.0.26}/tests/__init__.py +0 -0
  15. {violet_poolcontroller_api-0.0.25 → violet_poolcontroller_api-0.0.26}/tests/mock_server.py +0 -0
  16. {violet_poolcontroller_api-0.0.25 → violet_poolcontroller_api-0.0.26}/tests/test_api.py +0 -0
  17. {violet_poolcontroller_api-0.0.25 → violet_poolcontroller_api-0.0.26}/tests/test_api_smoke.py +0 -0
  18. {violet_poolcontroller_api-0.0.25 → violet_poolcontroller_api-0.0.26}/tests/test_mock_server.py +0 -0
  19. {violet_poolcontroller_api-0.0.25 → violet_poolcontroller_api-0.0.26}/violet_poolController_api.egg-info/dependency_links.txt +0 -0
  20. {violet_poolcontroller_api-0.0.25 → violet_poolcontroller_api-0.0.26}/violet_poolController_api.egg-info/top_level.txt +0 -0
  21. {violet_poolcontroller_api-0.0.25 → violet_poolcontroller_api-0.0.26}/violet_poolcontroller_api/__init__.py +0 -0
  22. {violet_poolcontroller_api-0.0.25 → violet_poolcontroller_api-0.0.26}/violet_poolcontroller_api/circuit_breaker.py +0 -0
  23. {violet_poolcontroller_api-0.0.25 → violet_poolcontroller_api-0.0.26}/violet_poolcontroller_api/const_api.py +0 -0
  24. {violet_poolcontroller_api-0.0.25 → violet_poolcontroller_api-0.0.26}/violet_poolcontroller_api/const_devices.py +0 -0
  25. {violet_poolcontroller_api-0.0.25 → violet_poolcontroller_api-0.0.26}/violet_poolcontroller_api/utils_sanitizer.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: violet-poolController-api
3
- Version: 0.0.25
3
+ Version: 0.0.26
4
4
  Summary: Asynchronous Python client for the Violet Pool Controller.
5
5
  Home-page: https://github.com/Xerolux/violet-poolController-api
6
6
  Author: Basti (Xerolux)
@@ -22,9 +22,9 @@ Classifier: Topic :: Home Automation
22
22
  Requires-Python: >=3.12
23
23
  Description-Content-Type: text/markdown
24
24
  License-File: LICENSE
25
- Requires-Dist: aiohttp>=3.11.0
25
+ Requires-Dist: aiohttp<3.14,>=3.11.0
26
26
  Provides-Extra: test
27
- Requires-Dist: aioresponses>=0.7.7; extra == "test"
27
+ Requires-Dist: aioresponses>=0.7.8; extra == "test"
28
28
  Requires-Dist: pytest>=8.3; extra == "test"
29
29
  Requires-Dist: pytest-asyncio>=0.24; extra == "test"
30
30
  Dynamic: author
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "violet-poolController-api"
7
- version = "0.0.25"
7
+ version = "0.0.26"
8
8
  authors = [
9
9
  { name="Basti (Xerolux)", email="git@xerolux.de" },
10
10
  ]
@@ -24,12 +24,12 @@ classifiers = [
24
24
  "Topic :: Home Automation",
25
25
  ]
26
26
  dependencies = [
27
- "aiohttp>=3.11.0",
27
+ "aiohttp>=3.11.0,<3.14",
28
28
  ]
29
29
 
30
30
  [project.optional-dependencies]
31
31
  test = [
32
- "aioresponses>=0.7.7",
32
+ "aioresponses>=0.7.8",
33
33
  "pytest>=8.3",
34
34
  "pytest-asyncio>=0.24",
35
35
  ]
@@ -45,13 +45,13 @@ asyncio_mode = "auto"
45
45
 
46
46
  [tool.ruff]
47
47
  line-length = 100
48
- target-version = "0.0.25"
48
+ target-version = "0.0.26"
49
49
 
50
50
  [tool.ruff.lint]
51
51
  select = ["E", "F", "W", "I", "UP"]
52
52
  ignore = ["E501"]
53
53
 
54
54
  [tool.mypy]
55
- python_version = "0.0.25"
55
+ python_version = "0.0.26"
56
56
  warn_return_any = true
57
57
  warn_unused_configs = true
@@ -2,7 +2,7 @@ from setuptools import find_packages, setup
2
2
 
3
3
  setup(
4
4
  name="violet-poolController-api",
5
- version="0.0.25",
5
+ version="0.0.26",
6
6
  author="Basti (Xerolux)",
7
7
  author_email="git@xerolux.de",
8
8
  description="Asynchronous Python client for the Violet Pool Controller.",
@@ -0,0 +1,40 @@
1
+ # violet-poolController-api - API für Violet Pool Controller
2
+ # Copyright (C) 2024-2026 Xerolux
3
+ #
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU Affero General Public License as published
6
+ # by the Free Software Foundation, either version 3 of the License, or
7
+ # (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU Affero General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU Affero General Public License
15
+ # along with this program. If not, see <https://www.gnu.org/licenses/>.
16
+
17
+ """Pytest configuration and fixtures."""
18
+
19
+ from __future__ import annotations
20
+
21
+ from inspect import signature
22
+
23
+ import aiohttp.client_reqrep
24
+
25
+ _original_client_response_init = aiohttp.client_reqrep.ClientResponse.__init__
26
+
27
+
28
+ def _patched_client_response_init(
29
+ self: aiohttp.client_reqrep.ClientResponse,
30
+ *args: object,
31
+ **kwargs: object,
32
+ ) -> None:
33
+ """Patched ClientResponse.__init__ that adds stream_writer if missing."""
34
+ sig = signature(_original_client_response_init)
35
+ if "stream_writer" in sig.parameters and "stream_writer" not in kwargs:
36
+ kwargs["stream_writer"] = None
37
+ _original_client_response_init(self, *args, **kwargs)
38
+
39
+
40
+ aiohttp.client_reqrep.ClientResponse.__init__ = _patched_client_response_init
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: violet-poolController-api
3
- Version: 0.0.25
3
+ Version: 0.0.26
4
4
  Summary: Asynchronous Python client for the Violet Pool Controller.
5
5
  Home-page: https://github.com/Xerolux/violet-poolController-api
6
6
  Author: Basti (Xerolux)
@@ -22,9 +22,9 @@ Classifier: Topic :: Home Automation
22
22
  Requires-Python: >=3.12
23
23
  Description-Content-Type: text/markdown
24
24
  License-File: LICENSE
25
- Requires-Dist: aiohttp>=3.11.0
25
+ Requires-Dist: aiohttp<3.14,>=3.11.0
26
26
  Provides-Extra: test
27
- Requires-Dist: aioresponses>=0.7.7; extra == "test"
27
+ Requires-Dist: aioresponses>=0.7.8; extra == "test"
28
28
  Requires-Dist: pytest>=8.3; extra == "test"
29
29
  Requires-Dist: pytest-asyncio>=0.24; extra == "test"
30
30
  Dynamic: author
@@ -3,6 +3,7 @@ README.md
3
3
  pyproject.toml
4
4
  setup.py
5
5
  tests/__init__.py
6
+ tests/conftest.py
6
7
  tests/mock_server.py
7
8
  tests/test_api.py
8
9
  tests/test_api_smoke.py
@@ -0,0 +1,6 @@
1
+ aiohttp<3.14,>=3.11.0
2
+
3
+ [test]
4
+ aioresponses>=0.7.8
5
+ pytest>=8.3
6
+ pytest-asyncio>=0.24
@@ -139,6 +139,7 @@ class VioletPoolAPI:
139
139
 
140
140
  # SSL/TLS security configuration
141
141
  self._verify_ssl = verify_ssl
142
+ self._use_ssl = use_ssl
142
143
  self._ssl_context = None
143
144
  if use_ssl and not verify_ssl:
144
145
  _LOGGER.warning(
@@ -190,6 +191,15 @@ class VioletPoolAPI:
190
191
  """Return whether dosing-standalone mode is enabled."""
191
192
  return self._dosing_standalone
192
193
 
194
+ @property
195
+ def _ssl_param(self) -> bool | None:
196
+ """Return the SSL parameter for aiohttp requests."""
197
+ if not self._use_ssl:
198
+ return None
199
+ if self._ssl_context is not None:
200
+ return self._ssl_context
201
+ return True
202
+
193
203
  # ---------------------------------------------------------------------
194
204
  # Generic helpers
195
205
  # ---------------------------------------------------------------------
@@ -292,7 +302,7 @@ class VioletPoolAPI:
292
302
  data=data,
293
303
  auth=self._auth,
294
304
  timeout=self._timeout,
295
- ssl=self._ssl_context, # type: ignore[arg-type]
305
+ ssl=self._ssl_param,
296
306
  ) as response:
297
307
  if (
298
308
  response.status >= _HTTP_SERVER_ERROR
@@ -570,14 +580,11 @@ class VioletPoolAPI:
570
580
  ext1_alive = "SYSTEM_ext1module_alive_count" in readings
571
581
  ext2_alive = "SYSTEM_ext2module_alive_count" in readings
572
582
 
573
- if ext1_alive and ext2_alive:
574
- return readings
575
-
576
- return {
577
- k: v
578
- for k, v in readings.items()
579
- if (ext1_alive or not k.startswith("EXT1")) and (ext2_alive or not k.startswith("EXT2"))
580
- }
583
+ if not ext1_alive:
584
+ readings = {k: v for k, v in readings.items() if not k.startswith("EXT1")}
585
+ if not ext2_alive:
586
+ readings = {k: v for k, v in readings.items() if not k.startswith("EXT2")}
587
+ return readings
581
588
 
582
589
  async def get_readings(self) -> dict[str, Any]:
583
590
  """Return the complete dataset from the controller.
@@ -1388,13 +1395,13 @@ class VioletPoolAPI:
1388
1395
 
1389
1396
  """
1390
1397
  if page < 0 and log_type == "actions":
1391
- url = f"{API_GET_LOG}?downloadActionsLog"
1398
+ query = "downloadActionsLog"
1392
1399
  else:
1393
- url = f"{API_GET_LOG}?{log_type}&{page}"
1400
+ query = f"{log_type}&{page}"
1394
1401
 
1395
- resp = await self._api_request(
1396
- "GET",
1397
- url,
1402
+ resp = await self._request(
1403
+ API_GET_LOG,
1404
+ query=query,
1398
1405
  priority=API_PRIORITY_NORMAL,
1399
1406
  )
1400
1407
  text = resp.strip() if resp else ""
@@ -1414,8 +1421,9 @@ class VioletPoolAPI:
1414
1421
  SENSOR_ID, TYPE, TEXT, MAIL_STATE, etc.
1415
1422
 
1416
1423
  """
1417
- return await self._api_request(
1418
- "GET",
1419
- f"{API_GET_NOTIFICATIONS}?ALL",
1424
+ return await self._request(
1425
+ API_GET_NOTIFICATIONS,
1426
+ query="ALL",
1427
+ expect_json=True,
1420
1428
  priority=API_PRIORITY_NORMAL,
1421
1429
  )
@@ -190,18 +190,13 @@ class RateLimiter:
190
190
  def get_stats(self) -> dict:
191
191
  """Hole Rate-Limiter-Statistiken."""
192
192
  current_time = time.monotonic()
193
-
194
- # Berechne Requests in letzter Minute
195
- recent_requests = [
196
- r for r in self.request_history if current_time - r["time"] <= _STATS_WINDOW_SECONDS
197
- ]
198
- recent_blocked = sum(1 for r in recent_requests if r["blocked"])
193
+ self._update_recent_stats(current_time)
199
194
 
200
195
  return {
201
196
  "total_requests": self.total_requests,
202
197
  "blocked_requests": self.blocked_requests,
203
- "recent_requests_1min": len(recent_requests),
204
- "recent_blocked_1min": recent_blocked,
198
+ "recent_requests_1min": self._recent_stats["requests_last_minute"],
199
+ "recent_blocked_1min": self._recent_stats["blocked_last_minute"],
205
200
  "current_tokens": self.tokens,
206
201
  "max_tokens": self.max_tokens,
207
202
  "block_rate": (
@@ -1,6 +0,0 @@
1
- aiohttp>=3.11.0
2
-
3
- [test]
4
- aioresponses>=0.7.7
5
- pytest>=8.3
6
- pytest-asyncio>=0.24