violet-poolController-api 0.0.24__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.24/violet_poolController_api.egg-info → violet_poolcontroller_api-0.0.26}/PKG-INFO +69 -3
  2. {violet_poolcontroller_api-0.0.24 → violet_poolcontroller_api-0.0.26}/README.md +66 -0
  3. {violet_poolcontroller_api-0.0.24 → violet_poolcontroller_api-0.0.26}/pyproject.toml +5 -5
  4. {violet_poolcontroller_api-0.0.24 → violet_poolcontroller_api-0.0.26}/setup.py +1 -1
  5. violet_poolcontroller_api-0.0.26/tests/conftest.py +40 -0
  6. violet_poolcontroller_api-0.0.26/tests/mock_server.py +684 -0
  7. violet_poolcontroller_api-0.0.26/tests/test_api_smoke.py +607 -0
  8. violet_poolcontroller_api-0.0.26/tests/test_mock_server.py +231 -0
  9. {violet_poolcontroller_api-0.0.24 → violet_poolcontroller_api-0.0.26/violet_poolController_api.egg-info}/PKG-INFO +69 -3
  10. {violet_poolcontroller_api-0.0.24 → violet_poolcontroller_api-0.0.26}/violet_poolController_api.egg-info/SOURCES.txt +4 -0
  11. violet_poolcontroller_api-0.0.26/violet_poolController_api.egg-info/requires.txt +6 -0
  12. {violet_poolcontroller_api-0.0.24 → violet_poolcontroller_api-0.0.26}/violet_poolcontroller_api/__init__.py +22 -1
  13. {violet_poolcontroller_api-0.0.24 → violet_poolcontroller_api-0.0.26}/violet_poolcontroller_api/api.py +25 -17
  14. {violet_poolcontroller_api-0.0.24 → violet_poolcontroller_api-0.0.26}/violet_poolcontroller_api/const_api.py +0 -7
  15. {violet_poolcontroller_api-0.0.24 → violet_poolcontroller_api-0.0.26}/violet_poolcontroller_api/const_devices.py +10 -0
  16. {violet_poolcontroller_api-0.0.24 → violet_poolcontroller_api-0.0.26}/violet_poolcontroller_api/utils_rate_limiter.py +3 -8
  17. violet_poolcontroller_api-0.0.24/violet_poolController_api.egg-info/requires.txt +0 -6
  18. {violet_poolcontroller_api-0.0.24 → violet_poolcontroller_api-0.0.26}/LICENSE +0 -0
  19. {violet_poolcontroller_api-0.0.24 → violet_poolcontroller_api-0.0.26}/setup.cfg +0 -0
  20. {violet_poolcontroller_api-0.0.24 → violet_poolcontroller_api-0.0.26}/tests/__init__.py +0 -0
  21. {violet_poolcontroller_api-0.0.24 → violet_poolcontroller_api-0.0.26}/tests/test_api.py +0 -0
  22. {violet_poolcontroller_api-0.0.24 → violet_poolcontroller_api-0.0.26}/violet_poolController_api.egg-info/dependency_links.txt +0 -0
  23. {violet_poolcontroller_api-0.0.24 → violet_poolcontroller_api-0.0.26}/violet_poolController_api.egg-info/top_level.txt +0 -0
  24. {violet_poolcontroller_api-0.0.24 → violet_poolcontroller_api-0.0.26}/violet_poolcontroller_api/circuit_breaker.py +0 -0
  25. {violet_poolcontroller_api-0.0.24 → 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.24
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
@@ -158,6 +158,72 @@ print(profile)
158
158
  ```
159
159
  This detection parses `get_readings()` to check for the presence of certain internal status parameters (`SYSTEM_dosagemodule_cpu_temperature`, `EXT1_1`, `EXT2_1`), allowing your application to dynamically adapt to the connected modules (Base Module, Dosing Module, Relay Extension 1 and 2). By utilizing this detection, developers and integrations can accurately filter out features for missing hardware, ensuring that only supported options are exposed to the user.
160
160
 
161
+ ## Mock Server (Testing Without Hardware)
162
+
163
+ The project includes a full mock server that simulates the Violet Pool Controller. This allows you to develop and test without needing the physical controller.
164
+
165
+ ### Start the Mock Server
166
+
167
+ ```bash
168
+ # Without authentication (default port 8480)
169
+ python tests/mock_server.py
170
+
171
+ # With Basic Auth (like the real controller)
172
+ python tests/mock_server.py --user admin --password secret
173
+
174
+ # With simulated network latency (300ms)
175
+ python tests/mock_server.py --user admin --password secret --delay 0.3
176
+
177
+ # Dosing-standalone mode (list format responses)
178
+ python tests/mock_server.py --standalone
179
+ ```
180
+
181
+ ### Connect Your Code
182
+
183
+ ```python
184
+ import asyncio, aiohttp
185
+ from violet_poolcontroller_api import VioletPoolAPI
186
+
187
+ async def main():
188
+ async with aiohttp.ClientSession() as session:
189
+ api = VioletPoolAPI(
190
+ host="localhost:8480",
191
+ session=session,
192
+ username="admin",
193
+ password="secret",
194
+ )
195
+ readings = await api.get_readings()
196
+ print(f"pH={readings['pH_value']}, PUMP={readings['PUMP']}")
197
+
198
+ asyncio.run(main())
199
+ ```
200
+
201
+ ### Run the Smoke Test
202
+
203
+ The smoke test automatically starts the mock server, tests every public API method, and prints a detailed report:
204
+
205
+ ```bash
206
+ python tests/test_api_smoke.py --user admin --password secret
207
+ ```
208
+
209
+ ### Mock Server Control Endpoints
210
+
211
+ These endpoints exist only on the mock server (not the real controller):
212
+
213
+ | Endpoint | Description |
214
+ |---|---|
215
+ | `GET /mock/state` | View internal state (outputs, sensors, config) as JSON |
216
+ | `GET /mock/error?code=500&count=3` | Force next 3 requests to return HTTP 500 |
217
+ | `GET /mock/reset` | Reset all state to defaults |
218
+
219
+ ### Mock Server Features
220
+
221
+ - **Stateful:** Switch/dosing changes are reflected in `getReadings` (e.g. PUMP ON -> PUMP=4)
222
+ - **Sensor drift:** pH, ORP, chlorine, and CPU temperature change slowly over time
223
+ - **Config persistence:** Values set via `setConfig` are returned by `getConfig`
224
+ - **Log history:** Actions are logged and returned by `getLog`
225
+ - **Error simulation:** Test your error handling with forced HTTP errors
226
+
161
227
  ## License
162
228
  GNU Affero General Public License v3.0 or later (AGPLv3+)
163
229
 
@@ -124,6 +124,72 @@ print(profile)
124
124
  ```
125
125
  This detection parses `get_readings()` to check for the presence of certain internal status parameters (`SYSTEM_dosagemodule_cpu_temperature`, `EXT1_1`, `EXT2_1`), allowing your application to dynamically adapt to the connected modules (Base Module, Dosing Module, Relay Extension 1 and 2). By utilizing this detection, developers and integrations can accurately filter out features for missing hardware, ensuring that only supported options are exposed to the user.
126
126
 
127
+ ## Mock Server (Testing Without Hardware)
128
+
129
+ The project includes a full mock server that simulates the Violet Pool Controller. This allows you to develop and test without needing the physical controller.
130
+
131
+ ### Start the Mock Server
132
+
133
+ ```bash
134
+ # Without authentication (default port 8480)
135
+ python tests/mock_server.py
136
+
137
+ # With Basic Auth (like the real controller)
138
+ python tests/mock_server.py --user admin --password secret
139
+
140
+ # With simulated network latency (300ms)
141
+ python tests/mock_server.py --user admin --password secret --delay 0.3
142
+
143
+ # Dosing-standalone mode (list format responses)
144
+ python tests/mock_server.py --standalone
145
+ ```
146
+
147
+ ### Connect Your Code
148
+
149
+ ```python
150
+ import asyncio, aiohttp
151
+ from violet_poolcontroller_api import VioletPoolAPI
152
+
153
+ async def main():
154
+ async with aiohttp.ClientSession() as session:
155
+ api = VioletPoolAPI(
156
+ host="localhost:8480",
157
+ session=session,
158
+ username="admin",
159
+ password="secret",
160
+ )
161
+ readings = await api.get_readings()
162
+ print(f"pH={readings['pH_value']}, PUMP={readings['PUMP']}")
163
+
164
+ asyncio.run(main())
165
+ ```
166
+
167
+ ### Run the Smoke Test
168
+
169
+ The smoke test automatically starts the mock server, tests every public API method, and prints a detailed report:
170
+
171
+ ```bash
172
+ python tests/test_api_smoke.py --user admin --password secret
173
+ ```
174
+
175
+ ### Mock Server Control Endpoints
176
+
177
+ These endpoints exist only on the mock server (not the real controller):
178
+
179
+ | Endpoint | Description |
180
+ |---|---|
181
+ | `GET /mock/state` | View internal state (outputs, sensors, config) as JSON |
182
+ | `GET /mock/error?code=500&count=3` | Force next 3 requests to return HTTP 500 |
183
+ | `GET /mock/reset` | Reset all state to defaults |
184
+
185
+ ### Mock Server Features
186
+
187
+ - **Stateful:** Switch/dosing changes are reflected in `getReadings` (e.g. PUMP ON -> PUMP=4)
188
+ - **Sensor drift:** pH, ORP, chlorine, and CPU temperature change slowly over time
189
+ - **Config persistence:** Values set via `setConfig` are returned by `getConfig`
190
+ - **Log history:** Actions are logged and returned by `getLog`
191
+ - **Error simulation:** Test your error handling with forced HTTP errors
192
+
127
193
  ## License
128
194
  GNU Affero General Public License v3.0 or later (AGPLv3+)
129
195
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "violet-poolController-api"
7
- version = "0.0.24"
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.24"
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.24"
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.24",
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