violet-poolController-api 0.0.26__tar.gz → 0.0.27__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.
- {violet_poolcontroller_api-0.0.26/violet_poolController_api.egg-info → violet_poolcontroller_api-0.0.27}/PKG-INFO +4 -9
- {violet_poolcontroller_api-0.0.26 → violet_poolcontroller_api-0.0.27}/pyproject.toml +6 -6
- {violet_poolcontroller_api-0.0.26 → violet_poolcontroller_api-0.0.27}/tests/test_api.py +153 -2
- {violet_poolcontroller_api-0.0.26 → violet_poolcontroller_api-0.0.27}/tests/test_mock_server.py +49 -6
- {violet_poolcontroller_api-0.0.26 → violet_poolcontroller_api-0.0.27/violet_poolController_api.egg-info}/PKG-INFO +4 -9
- {violet_poolcontroller_api-0.0.26 → violet_poolcontroller_api-0.0.27}/violet_poolController_api.egg-info/SOURCES.txt +0 -4
- {violet_poolcontroller_api-0.0.26 → violet_poolcontroller_api-0.0.27}/violet_poolController_api.egg-info/top_level.txt +0 -1
- {violet_poolcontroller_api-0.0.26 → violet_poolcontroller_api-0.0.27}/violet_poolcontroller_api/__init__.py +78 -72
- {violet_poolcontroller_api-0.0.26 → violet_poolcontroller_api-0.0.27}/violet_poolcontroller_api/api.py +125 -34
- {violet_poolcontroller_api-0.0.26 → violet_poolcontroller_api-0.0.27}/violet_poolcontroller_api/circuit_breaker.py +205 -196
- {violet_poolcontroller_api-0.0.26 → violet_poolcontroller_api-0.0.27}/violet_poolcontroller_api/const_api.py +594 -594
- {violet_poolcontroller_api-0.0.26 → violet_poolcontroller_api-0.0.27}/violet_poolcontroller_api/const_devices.py +420 -351
- violet_poolcontroller_api-0.0.26/setup.py +0 -36
- violet_poolcontroller_api-0.0.26/tests/__init__.py +0 -1
- violet_poolcontroller_api-0.0.26/tests/conftest.py +0 -40
- violet_poolcontroller_api-0.0.26/tests/mock_server.py +0 -684
- {violet_poolcontroller_api-0.0.26 → violet_poolcontroller_api-0.0.27}/LICENSE +0 -0
- {violet_poolcontroller_api-0.0.26 → violet_poolcontroller_api-0.0.27}/README.md +0 -0
- {violet_poolcontroller_api-0.0.26 → violet_poolcontroller_api-0.0.27}/setup.cfg +0 -0
- {violet_poolcontroller_api-0.0.26 → violet_poolcontroller_api-0.0.27}/tests/test_api_smoke.py +0 -0
- {violet_poolcontroller_api-0.0.26 → violet_poolcontroller_api-0.0.27}/violet_poolController_api.egg-info/dependency_links.txt +0 -0
- {violet_poolcontroller_api-0.0.26 → violet_poolcontroller_api-0.0.27}/violet_poolController_api.egg-info/requires.txt +0 -0
- {violet_poolcontroller_api-0.0.26 → violet_poolcontroller_api-0.0.27}/violet_poolcontroller_api/utils_rate_limiter.py +0 -0
- {violet_poolcontroller_api-0.0.26 → violet_poolcontroller_api-0.0.27}/violet_poolcontroller_api/utils_sanitizer.py +0 -0
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: violet-poolController-api
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.27
|
|
4
4
|
Summary: Asynchronous Python client for the Violet Pool Controller.
|
|
5
|
-
Home-page: https://github.com/Xerolux/violet-poolController-api
|
|
6
|
-
Author: Basti (Xerolux)
|
|
7
5
|
Author-email: "Basti (Xerolux)" <git@xerolux.de>
|
|
8
6
|
License: AGPL-3.0-or-later
|
|
9
|
-
Project-URL: Homepage, https://github.com/Xerolux/violet-
|
|
10
|
-
Project-URL: Bug Tracker, https://github.com/Xerolux/violet-
|
|
7
|
+
Project-URL: Homepage, https://github.com/Xerolux/violet-hass
|
|
8
|
+
Project-URL: Bug Tracker, https://github.com/Xerolux/violet-hass/issues
|
|
11
9
|
Project-URL: License, https://www.gnu.org/licenses/agpl-3.0.html
|
|
12
|
-
Project-URL: Changelog, https://github.com/Xerolux/violet-
|
|
10
|
+
Project-URL: Changelog, https://github.com/Xerolux/violet-hass/blob/main/violet_poolcontroller_api/CHANGELOG.md
|
|
13
11
|
Keywords: pool,violet,controller,home-assistant,async
|
|
14
12
|
Classifier: Programming Language :: Python :: 3
|
|
15
13
|
Classifier: Programming Language :: Python :: 3.12
|
|
@@ -27,10 +25,7 @@ Provides-Extra: test
|
|
|
27
25
|
Requires-Dist: aioresponses>=0.7.8; extra == "test"
|
|
28
26
|
Requires-Dist: pytest>=8.3; extra == "test"
|
|
29
27
|
Requires-Dist: pytest-asyncio>=0.24; extra == "test"
|
|
30
|
-
Dynamic: author
|
|
31
|
-
Dynamic: home-page
|
|
32
28
|
Dynamic: license-file
|
|
33
|
-
Dynamic: requires-python
|
|
34
29
|
|
|
35
30
|
# Violet Pool Controller API
|
|
36
31
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "violet-poolController-api"
|
|
7
|
-
version = "0.0.
|
|
7
|
+
version = "0.0.27"
|
|
8
8
|
authors = [
|
|
9
9
|
{ name="Basti (Xerolux)", email="git@xerolux.de" },
|
|
10
10
|
]
|
|
@@ -35,23 +35,23 @@ test = [
|
|
|
35
35
|
]
|
|
36
36
|
|
|
37
37
|
[project.urls]
|
|
38
|
-
"Homepage" = "https://github.com/Xerolux/violet-
|
|
39
|
-
"Bug Tracker" = "https://github.com/Xerolux/violet-
|
|
38
|
+
"Homepage" = "https://github.com/Xerolux/violet-hass"
|
|
39
|
+
"Bug Tracker" = "https://github.com/Xerolux/violet-hass/issues"
|
|
40
40
|
"License" = "https://www.gnu.org/licenses/agpl-3.0.html"
|
|
41
|
-
"Changelog" = "https://github.com/Xerolux/violet-
|
|
41
|
+
"Changelog" = "https://github.com/Xerolux/violet-hass/blob/main/violet_poolcontroller_api/CHANGELOG.md"
|
|
42
42
|
|
|
43
43
|
[tool.pytest.ini_options]
|
|
44
44
|
asyncio_mode = "auto"
|
|
45
45
|
|
|
46
46
|
[tool.ruff]
|
|
47
47
|
line-length = 100
|
|
48
|
-
target-version = "
|
|
48
|
+
target-version = "py312"
|
|
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 = "
|
|
55
|
+
python_version = "3.12"
|
|
56
56
|
warn_return_any = true
|
|
57
57
|
warn_unused_configs = true
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# violet-poolController-api - API
|
|
1
|
+
# violet-poolController-api - API f├╝r Violet Pool Controller
|
|
2
2
|
# Copyright (C) 2024-2026 Xerolux
|
|
3
3
|
#
|
|
4
4
|
# This program is free software: you can redistribute it and/or modify
|
|
@@ -26,6 +26,7 @@ import aiohttp
|
|
|
26
26
|
import pytest
|
|
27
27
|
import pytest_asyncio
|
|
28
28
|
from aioresponses import aioresponses
|
|
29
|
+
from yarl import URL
|
|
29
30
|
|
|
30
31
|
from violet_poolcontroller_api.api import VioletPoolAPI, VioletPoolAPIError
|
|
31
32
|
from violet_poolcontroller_api.circuit_breaker import CircuitBreakerOpenError
|
|
@@ -483,7 +484,7 @@ async def test_ext1_readings_filtered_when_not_detected(mock_aioresponse, api_cl
|
|
|
483
484
|
payload={
|
|
484
485
|
"getReadings": {
|
|
485
486
|
"PUMPSTATE": "2",
|
|
486
|
-
# No SYSTEM_ext1module_alive_count
|
|
487
|
+
# No SYSTEM_ext1module_alive_count  module not connected
|
|
487
488
|
"EXT1_1": 0,
|
|
488
489
|
"EXT1_2": 0,
|
|
489
490
|
}
|
|
@@ -1179,6 +1180,35 @@ async def test_manual_dosing_stop(
|
|
|
1179
1180
|
assert "MANDOS_STOPPED" in result["response"]
|
|
1180
1181
|
|
|
1181
1182
|
|
|
1183
|
+
@pytest.mark.asyncio
|
|
1184
|
+
async def test_dosing_auto_action_sends_dosstop(
|
|
1185
|
+
mock_aioresponse: aioresponses,
|
|
1186
|
+
api_client: VioletPoolAPI,
|
|
1187
|
+
) -> None:
|
|
1188
|
+
"""AUTO on a dosing output must stop the run, never start one.
|
|
1189
|
+
|
|
1190
|
+
setFunctionManually does not work for DOS_* outputs (PoolDigital forum),
|
|
1191
|
+
so AUTO maps to DOSSTOP via /triggerManualDosing - stopping the manual
|
|
1192
|
+
run returns the channel to automatic mode.
|
|
1193
|
+
"""
|
|
1194
|
+
url = "http://192.168.1.100/triggerManualDosing"
|
|
1195
|
+
mock_aioresponse.post(url, body="MANDOS_STOPPED\nOK", status=200)
|
|
1196
|
+
|
|
1197
|
+
result = await api_client.set_switch_state("DOS_6_FLOC", "AUTO")
|
|
1198
|
+
|
|
1199
|
+
assert result["success"] is True
|
|
1200
|
+
request_key = ("POST", URL(url))
|
|
1201
|
+
sent = mock_aioresponse.requests[request_key][0].kwargs["data"]
|
|
1202
|
+
assert sent["action"] == "DOSSTOP"
|
|
1203
|
+
|
|
1204
|
+
|
|
1205
|
+
@pytest.mark.asyncio
|
|
1206
|
+
async def test_dosing_unknown_action_rejected(api_client: VioletPoolAPI) -> None:
|
|
1207
|
+
"""Unknown dosing actions raise instead of defaulting to DOSSTART."""
|
|
1208
|
+
with pytest.raises(VioletPoolAPIError, match="Unsupported dosing action"):
|
|
1209
|
+
await api_client.set_switch_state("DOS_1_CL", "PUSH")
|
|
1210
|
+
|
|
1211
|
+
|
|
1182
1212
|
@pytest.mark.asyncio
|
|
1183
1213
|
async def test_pv_surplus_with_speed(
|
|
1184
1214
|
mock_aioresponse: aioresponses,
|
|
@@ -1235,3 +1265,124 @@ async def test_pump_off_with_duration(
|
|
|
1235
1265
|
|
|
1236
1266
|
assert result["success"] is True
|
|
1237
1267
|
assert result["message"] == "MANUELL AUS\n600 Sekunden"
|
|
1268
|
+
|
|
1269
|
+
|
|
1270
|
+
@pytest.mark.asyncio
|
|
1271
|
+
async def test_pv_surplus_auto_is_mapped_to_off(
|
|
1272
|
+
mock_aioresponse: aioresponses,
|
|
1273
|
+
api_client: VioletPoolAPI,
|
|
1274
|
+
) -> None:
|
|
1275
|
+
"""PVSURPLUS supports only ON/OFF (manual 26.3); AUTO is sent as OFF."""
|
|
1276
|
+
url = "http://192.168.1.100/setFunctionManually?PVSURPLUS,OFF,0,0"
|
|
1277
|
+
mock_aioresponse.get(url, body="OK\nPVSURPLUS\nOFF", status=200)
|
|
1278
|
+
|
|
1279
|
+
result = await api_client.set_switch_state("PVSURPLUS", "AUTO")
|
|
1280
|
+
|
|
1281
|
+
assert result["success"] is True
|
|
1282
|
+
assert result["output"] == "PVSURPLUS"
|
|
1283
|
+
|
|
1284
|
+
|
|
1285
|
+
@pytest.mark.asyncio
|
|
1286
|
+
async def test_pv_surplus_rejects_unknown_action(
|
|
1287
|
+
api_client: VioletPoolAPI,
|
|
1288
|
+
) -> None:
|
|
1289
|
+
"""PVSURPLUS rejects actions that cannot be mapped to ON/OFF."""
|
|
1290
|
+
with pytest.raises(VioletPoolAPIError, match="manual section 26.3"):
|
|
1291
|
+
await api_client.set_switch_state("PVSURPLUS", "PUSH")
|
|
1292
|
+
|
|
1293
|
+
|
|
1294
|
+
@pytest.mark.asyncio
|
|
1295
|
+
async def test_pv_surplus_speed_is_clamped(
|
|
1296
|
+
mock_aioresponse: aioresponses,
|
|
1297
|
+
api_client: VioletPoolAPI,
|
|
1298
|
+
) -> None:
|
|
1299
|
+
"""Pump speed for PVSURPLUS is clamped to the documented 1-3 range."""
|
|
1300
|
+
url = "http://192.168.1.100/setFunctionManually?PVSURPLUS,ON,3,0"
|
|
1301
|
+
mock_aioresponse.get(url, body="OK\nPVSURPLUS\nON", status=200)
|
|
1302
|
+
|
|
1303
|
+
result = await api_client.set_pv_surplus(active=True, pump_speed=5)
|
|
1304
|
+
|
|
1305
|
+
assert result["success"] is True
|
|
1306
|
+
|
|
1307
|
+
|
|
1308
|
+
@pytest.mark.asyncio
|
|
1309
|
+
async def test_client_error_fails_fast_without_retry(
|
|
1310
|
+
mock_aioresponse: aioresponses,
|
|
1311
|
+
api_client: VioletPoolAPI,
|
|
1312
|
+
) -> None:
|
|
1313
|
+
"""A 4xx response raises immediately instead of being retried."""
|
|
1314
|
+
url = "http://192.168.1.100/getReadings?ALL"
|
|
1315
|
+
mock_aioresponse.get(url, status=401, body="Unauthorized")
|
|
1316
|
+
|
|
1317
|
+
with pytest.raises(VioletPoolAPIError, match="HTTP 401"):
|
|
1318
|
+
await api_client.get_readings()
|
|
1319
|
+
|
|
1320
|
+
|
|
1321
|
+
@pytest.mark.asyncio
|
|
1322
|
+
async def test_client_error_does_not_trip_circuit_breaker(
|
|
1323
|
+
mock_aioresponse: aioresponses,
|
|
1324
|
+
api_client: VioletPoolAPI,
|
|
1325
|
+
) -> None:
|
|
1326
|
+
"""Deterministic 4xx errors must not count as circuit breaker failures."""
|
|
1327
|
+
url = "http://192.168.1.100/getReadings?ALL"
|
|
1328
|
+
threshold = api_client._circuit_breaker.failure_threshold
|
|
1329
|
+
|
|
1330
|
+
for _ in range(threshold + 1):
|
|
1331
|
+
mock_aioresponse.get(url, status=401, body="Unauthorized")
|
|
1332
|
+
with pytest.raises(VioletPoolAPIError, match="HTTP 401"):
|
|
1333
|
+
await api_client.get_readings()
|
|
1334
|
+
|
|
1335
|
+
stats = api_client._circuit_breaker.get_stats()
|
|
1336
|
+
assert stats["failure_count"] == 0
|
|
1337
|
+
assert stats["state"] == "CLOSED"
|
|
1338
|
+
|
|
1339
|
+
|
|
1340
|
+
@pytest.mark.asyncio
|
|
1341
|
+
async def test_server_error_still_counts_for_circuit_breaker(
|
|
1342
|
+
mock_aioresponse: aioresponses,
|
|
1343
|
+
api_client: VioletPoolAPI,
|
|
1344
|
+
) -> None:
|
|
1345
|
+
"""5xx errors keep counting as circuit breaker failures."""
|
|
1346
|
+
url = "http://192.168.1.100/getReadings?ALL"
|
|
1347
|
+
mock_aioresponse.get(url, status=500, body="boom")
|
|
1348
|
+
|
|
1349
|
+
with pytest.raises(VioletPoolAPIError):
|
|
1350
|
+
await api_client.get_readings()
|
|
1351
|
+
|
|
1352
|
+
stats = api_client._circuit_breaker.get_stats()
|
|
1353
|
+
assert stats["failure_count"] == 1
|
|
1354
|
+
|
|
1355
|
+
|
|
1356
|
+
def test_command_result_error_first_line() -> None:
|
|
1357
|
+
"""Line 1 of the response decides success per manual section 26.2."""
|
|
1358
|
+
result = VioletPoolAPI._command_result("ERROR\nPUMP\nUNKNOWN OUTPUT")
|
|
1359
|
+
assert result["success"] is False
|
|
1360
|
+
|
|
1361
|
+
result = VioletPoolAPI._command_result("OK\nPUMP\nInfo about error handling")
|
|
1362
|
+
assert result["success"] is True
|
|
1363
|
+
|
|
1364
|
+
|
|
1365
|
+
def test_state_translation_language_switch() -> None:
|
|
1366
|
+
"""Display texts are language-configurable instead of hardwired German."""
|
|
1367
|
+
from violet_poolcontroller_api.const_devices import (
|
|
1368
|
+
VioletState,
|
|
1369
|
+
get_state_translation_language,
|
|
1370
|
+
set_state_translation_language,
|
|
1371
|
+
)
|
|
1372
|
+
|
|
1373
|
+
assert get_state_translation_language() == "de"
|
|
1374
|
+
state = VioletState("0")
|
|
1375
|
+
assert state.display_mode == "Automatik (Bereit)"
|
|
1376
|
+
assert state.display_mode_for("en") == "Auto (Ready)"
|
|
1377
|
+
|
|
1378
|
+
english_state = VioletState("0", language="en")
|
|
1379
|
+
assert english_state.display_mode == "Auto (Ready)"
|
|
1380
|
+
|
|
1381
|
+
set_state_translation_language("en")
|
|
1382
|
+
try:
|
|
1383
|
+
assert VioletState("4").display_mode == "Manual On"
|
|
1384
|
+
finally:
|
|
1385
|
+
set_state_translation_language("de")
|
|
1386
|
+
|
|
1387
|
+
with pytest.raises(ValueError, match="Unsupported language"):
|
|
1388
|
+
set_state_translation_language("fr")
|
{violet_poolcontroller_api-0.0.26 → violet_poolcontroller_api-0.0.27}/tests/test_mock_server.py
RENAMED
|
@@ -7,11 +7,15 @@ credentials, and verifies that authentication is enforced properly.
|
|
|
7
7
|
from __future__ import annotations
|
|
8
8
|
|
|
9
9
|
import asyncio
|
|
10
|
+
import socket
|
|
10
11
|
import subprocess
|
|
11
12
|
import sys
|
|
12
13
|
import time
|
|
14
|
+
from collections.abc import Iterator
|
|
15
|
+
from pathlib import Path
|
|
13
16
|
|
|
14
17
|
import aiohttp
|
|
18
|
+
import pytest
|
|
15
19
|
|
|
16
20
|
from violet_poolcontroller_api.api import VioletPoolAPI, VioletPoolAPIError
|
|
17
21
|
|
|
@@ -20,6 +24,50 @@ PORT = 8499
|
|
|
20
24
|
USER = "admin"
|
|
21
25
|
PASS = "secret"
|
|
22
26
|
|
|
27
|
+
_MOCK_SERVER_PATH = Path(__file__).parent / "mock_server.py"
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _start_mock_server() -> subprocess.Popen[bytes]:
|
|
31
|
+
"""Start the mock server subprocess and wait until it accepts connections."""
|
|
32
|
+
proc = subprocess.Popen(
|
|
33
|
+
[
|
|
34
|
+
sys.executable,
|
|
35
|
+
str(_MOCK_SERVER_PATH),
|
|
36
|
+
"--port",
|
|
37
|
+
str(PORT),
|
|
38
|
+
"--user",
|
|
39
|
+
USER,
|
|
40
|
+
"--password",
|
|
41
|
+
PASS,
|
|
42
|
+
],
|
|
43
|
+
stdout=subprocess.DEVNULL,
|
|
44
|
+
stderr=subprocess.DEVNULL,
|
|
45
|
+
)
|
|
46
|
+
deadline = time.monotonic() + 10
|
|
47
|
+
while time.monotonic() < deadline:
|
|
48
|
+
if proc.poll() is not None:
|
|
49
|
+
msg = f"Mock server exited early with code {proc.returncode}"
|
|
50
|
+
raise RuntimeError(msg)
|
|
51
|
+
try:
|
|
52
|
+
with socket.create_connection((HOST, PORT), timeout=0.5):
|
|
53
|
+
return proc
|
|
54
|
+
except OSError:
|
|
55
|
+
time.sleep(0.1)
|
|
56
|
+
proc.terminate()
|
|
57
|
+
msg = f"Mock server did not start listening on port {PORT} within 10s"
|
|
58
|
+
raise RuntimeError(msg)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
@pytest.fixture(scope="module", autouse=True)
|
|
62
|
+
def mock_server() -> Iterator[subprocess.Popen[bytes]]:
|
|
63
|
+
"""Run the mock server for all tests in this module."""
|
|
64
|
+
proc = _start_mock_server()
|
|
65
|
+
try:
|
|
66
|
+
yield proc
|
|
67
|
+
finally:
|
|
68
|
+
proc.terminate()
|
|
69
|
+
proc.wait(timeout=5)
|
|
70
|
+
|
|
23
71
|
|
|
24
72
|
async def _request(url: str, auth: aiohttp.BasicAuth | None = None) -> tuple[int, str]:
|
|
25
73
|
async with aiohttp.ClientSession() as session:
|
|
@@ -211,12 +259,7 @@ async def test_api_client() -> None:
|
|
|
211
259
|
|
|
212
260
|
def main() -> None:
|
|
213
261
|
print(f"Starting mock server on port {PORT} with auth ({USER}:{PASS})...")
|
|
214
|
-
proc =
|
|
215
|
-
[sys.executable, "tests/mock_server.py", "--port", str(PORT), "--user", USER, "--password", PASS],
|
|
216
|
-
stdout=subprocess.DEVNULL,
|
|
217
|
-
stderr=subprocess.DEVNULL,
|
|
218
|
-
)
|
|
219
|
-
time.sleep(2)
|
|
262
|
+
proc = _start_mock_server()
|
|
220
263
|
|
|
221
264
|
try:
|
|
222
265
|
asyncio.run(test_raw_auth())
|
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: violet-poolController-api
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.27
|
|
4
4
|
Summary: Asynchronous Python client for the Violet Pool Controller.
|
|
5
|
-
Home-page: https://github.com/Xerolux/violet-poolController-api
|
|
6
|
-
Author: Basti (Xerolux)
|
|
7
5
|
Author-email: "Basti (Xerolux)" <git@xerolux.de>
|
|
8
6
|
License: AGPL-3.0-or-later
|
|
9
|
-
Project-URL: Homepage, https://github.com/Xerolux/violet-
|
|
10
|
-
Project-URL: Bug Tracker, https://github.com/Xerolux/violet-
|
|
7
|
+
Project-URL: Homepage, https://github.com/Xerolux/violet-hass
|
|
8
|
+
Project-URL: Bug Tracker, https://github.com/Xerolux/violet-hass/issues
|
|
11
9
|
Project-URL: License, https://www.gnu.org/licenses/agpl-3.0.html
|
|
12
|
-
Project-URL: Changelog, https://github.com/Xerolux/violet-
|
|
10
|
+
Project-URL: Changelog, https://github.com/Xerolux/violet-hass/blob/main/violet_poolcontroller_api/CHANGELOG.md
|
|
13
11
|
Keywords: pool,violet,controller,home-assistant,async
|
|
14
12
|
Classifier: Programming Language :: Python :: 3
|
|
15
13
|
Classifier: Programming Language :: Python :: 3.12
|
|
@@ -27,10 +25,7 @@ Provides-Extra: test
|
|
|
27
25
|
Requires-Dist: aioresponses>=0.7.8; extra == "test"
|
|
28
26
|
Requires-Dist: pytest>=8.3; extra == "test"
|
|
29
27
|
Requires-Dist: pytest-asyncio>=0.24; extra == "test"
|
|
30
|
-
Dynamic: author
|
|
31
|
-
Dynamic: home-page
|
|
32
28
|
Dynamic: license-file
|
|
33
|
-
Dynamic: requires-python
|
|
34
29
|
|
|
35
30
|
# Violet Pool Controller API
|
|
36
31
|
|
|
@@ -1,72 +1,78 @@
|
|
|
1
|
-
# violet-poolController-api - API
|
|
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
|
-
"""Violet Pool Controller API client library."""
|
|
18
|
-
|
|
19
|
-
from .api import VioletPoolAPI, VioletPoolAPIError
|
|
20
|
-
from .circuit_breaker import CircuitBreaker, CircuitBreakerOpenError
|
|
21
|
-
from .const_api import ( # noqa: F401
|
|
22
|
-
ACTION_ALLAUTO,
|
|
23
|
-
ACTION_ALLOFF,
|
|
24
|
-
ACTION_ALLON,
|
|
25
|
-
ACTION_AUTO,
|
|
26
|
-
ACTION_COLOR,
|
|
27
|
-
ACTION_LOCK,
|
|
28
|
-
ACTION_OFF,
|
|
29
|
-
ACTION_ON,
|
|
30
|
-
ACTION_PUSH,
|
|
31
|
-
ACTION_UNLOCK,
|
|
32
|
-
ERROR_CODES,
|
|
33
|
-
ERROR_SEVERITY_ALARM,
|
|
34
|
-
ERROR_SEVERITY_INFO,
|
|
35
|
-
ERROR_SEVERITY_WARNING,
|
|
36
|
-
)
|
|
37
|
-
from .const_devices import ( # noqa: F401
|
|
38
|
-
COVER_FUNCTIONS,
|
|
39
|
-
COVER_STATE_MAP,
|
|
40
|
-
DEVICE_PARAMETERS,
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
"
|
|
51
|
-
"
|
|
52
|
-
"
|
|
53
|
-
"
|
|
54
|
-
"
|
|
55
|
-
"
|
|
56
|
-
"
|
|
57
|
-
"
|
|
58
|
-
"
|
|
59
|
-
"
|
|
60
|
-
"
|
|
61
|
-
"
|
|
62
|
-
"
|
|
63
|
-
"
|
|
64
|
-
"
|
|
65
|
-
"
|
|
66
|
-
"
|
|
67
|
-
"
|
|
68
|
-
"
|
|
69
|
-
"
|
|
70
|
-
"
|
|
71
|
-
"
|
|
72
|
-
|
|
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
|
+
"""Violet Pool Controller API client library."""
|
|
18
|
+
|
|
19
|
+
from .api import VioletPoolAPI, VioletPoolAPIError
|
|
20
|
+
from .circuit_breaker import CircuitBreaker, CircuitBreakerOpenError
|
|
21
|
+
from .const_api import ( # noqa: F401
|
|
22
|
+
ACTION_ALLAUTO,
|
|
23
|
+
ACTION_ALLOFF,
|
|
24
|
+
ACTION_ALLON,
|
|
25
|
+
ACTION_AUTO,
|
|
26
|
+
ACTION_COLOR,
|
|
27
|
+
ACTION_LOCK,
|
|
28
|
+
ACTION_OFF,
|
|
29
|
+
ACTION_ON,
|
|
30
|
+
ACTION_PUSH,
|
|
31
|
+
ACTION_UNLOCK,
|
|
32
|
+
ERROR_CODES,
|
|
33
|
+
ERROR_SEVERITY_ALARM,
|
|
34
|
+
ERROR_SEVERITY_INFO,
|
|
35
|
+
ERROR_SEVERITY_WARNING,
|
|
36
|
+
)
|
|
37
|
+
from .const_devices import ( # noqa: F401
|
|
38
|
+
COVER_FUNCTIONS,
|
|
39
|
+
COVER_STATE_MAP,
|
|
40
|
+
DEVICE_PARAMETERS,
|
|
41
|
+
STATE_TRANSLATIONS,
|
|
42
|
+
VioletState,
|
|
43
|
+
get_state_translation_language,
|
|
44
|
+
set_state_translation_language,
|
|
45
|
+
)
|
|
46
|
+
from .utils_rate_limiter import RateLimiter, get_global_rate_limiter
|
|
47
|
+
from .utils_sanitizer import InputSanitizer
|
|
48
|
+
|
|
49
|
+
__all__ = [
|
|
50
|
+
"VioletPoolAPI",
|
|
51
|
+
"VioletPoolAPIError",
|
|
52
|
+
"CircuitBreaker",
|
|
53
|
+
"CircuitBreakerOpenError",
|
|
54
|
+
"VioletState",
|
|
55
|
+
"InputSanitizer",
|
|
56
|
+
"RateLimiter",
|
|
57
|
+
"get_global_rate_limiter",
|
|
58
|
+
"get_state_translation_language",
|
|
59
|
+
"set_state_translation_language",
|
|
60
|
+
"STATE_TRANSLATIONS",
|
|
61
|
+
"ACTION_ALLAUTO",
|
|
62
|
+
"ACTION_ALLOFF",
|
|
63
|
+
"ACTION_ALLON",
|
|
64
|
+
"ACTION_AUTO",
|
|
65
|
+
"ACTION_COLOR",
|
|
66
|
+
"ACTION_LOCK",
|
|
67
|
+
"ACTION_OFF",
|
|
68
|
+
"ACTION_ON",
|
|
69
|
+
"ACTION_PUSH",
|
|
70
|
+
"ACTION_UNLOCK",
|
|
71
|
+
"COVER_FUNCTIONS",
|
|
72
|
+
"COVER_STATE_MAP",
|
|
73
|
+
"DEVICE_PARAMETERS",
|
|
74
|
+
"ERROR_CODES",
|
|
75
|
+
"ERROR_SEVERITY_ALARM",
|
|
76
|
+
"ERROR_SEVERITY_INFO",
|
|
77
|
+
"ERROR_SEVERITY_WARNING",
|
|
78
|
+
]
|