violet-poolController-api 0.0.12__tar.gz → 0.0.14__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.12 → violet_poolcontroller_api-0.0.14}/PKG-INFO +1 -1
- {violet_poolcontroller_api-0.0.12 → violet_poolcontroller_api-0.0.14}/pyproject.toml +1 -1
- {violet_poolcontroller_api-0.0.12 → violet_poolcontroller_api-0.0.14}/setup.py +1 -1
- {violet_poolcontroller_api-0.0.12 → violet_poolcontroller_api-0.0.14}/tests/test_api.py +75 -0
- {violet_poolcontroller_api-0.0.12 → violet_poolcontroller_api-0.0.14}/violet_poolController_api.egg-info/PKG-INFO +1 -1
- {violet_poolcontroller_api-0.0.12 → violet_poolcontroller_api-0.0.14}/violet_poolcontroller_api/api.py +5 -7
- {violet_poolcontroller_api-0.0.12 → violet_poolcontroller_api-0.0.14}/LICENSE +0 -0
- {violet_poolcontroller_api-0.0.12 → violet_poolcontroller_api-0.0.14}/README.md +0 -0
- {violet_poolcontroller_api-0.0.12 → violet_poolcontroller_api-0.0.14}/setup.cfg +0 -0
- {violet_poolcontroller_api-0.0.12 → violet_poolcontroller_api-0.0.14}/violet_poolController_api.egg-info/SOURCES.txt +0 -0
- {violet_poolcontroller_api-0.0.12 → violet_poolcontroller_api-0.0.14}/violet_poolController_api.egg-info/dependency_links.txt +0 -0
- {violet_poolcontroller_api-0.0.12 → violet_poolcontroller_api-0.0.14}/violet_poolController_api.egg-info/requires.txt +0 -0
- {violet_poolcontroller_api-0.0.12 → violet_poolcontroller_api-0.0.14}/violet_poolController_api.egg-info/top_level.txt +0 -0
- {violet_poolcontroller_api-0.0.12 → violet_poolcontroller_api-0.0.14}/violet_poolcontroller_api/__init__.py +0 -0
- {violet_poolcontroller_api-0.0.12 → violet_poolcontroller_api-0.0.14}/violet_poolcontroller_api/circuit_breaker.py +0 -0
- {violet_poolcontroller_api-0.0.12 → violet_poolcontroller_api-0.0.14}/violet_poolcontroller_api/const_api.py +0 -0
- {violet_poolcontroller_api-0.0.12 → violet_poolcontroller_api-0.0.14}/violet_poolcontroller_api/const_devices.py +0 -0
- {violet_poolcontroller_api-0.0.12 → violet_poolcontroller_api-0.0.14}/violet_poolcontroller_api/utils_rate_limiter.py +0 -0
- {violet_poolcontroller_api-0.0.12 → violet_poolcontroller_api-0.0.14}/violet_poolcontroller_api/utils_sanitizer.py +0 -0
|
@@ -316,6 +316,81 @@ async def test_get_hardware_profile(mock_aioresponse, api_client):
|
|
|
316
316
|
assert profile["extension_module_1"] is True
|
|
317
317
|
assert profile["extension_module_2"] is False
|
|
318
318
|
|
|
319
|
+
@pytest.mark.asyncio
|
|
320
|
+
async def test_set_switch_state_ext1_relay(mock_aioresponse, api_client):
|
|
321
|
+
"""Test set_switch_state sends correct URL for EXT1_2 ON, OFF, and AUTO."""
|
|
322
|
+
base = "http://192.168.1.100/setFunctionManually"
|
|
323
|
+
|
|
324
|
+
mock_aioresponse.get(f"{base}?EXT1_2,ON,0,0", body="OK", status=200)
|
|
325
|
+
result = await api_client.set_switch_state("EXT1_2", "ON")
|
|
326
|
+
assert result["success"] is True
|
|
327
|
+
|
|
328
|
+
mock_aioresponse.get(f"{base}?EXT1_2,OFF,0,0", body="OK", status=200)
|
|
329
|
+
result = await api_client.set_switch_state("EXT1_2", "OFF")
|
|
330
|
+
assert result["success"] is True
|
|
331
|
+
|
|
332
|
+
mock_aioresponse.get(f"{base}?EXT1_2,AUTO,0,0", body="OK", status=200)
|
|
333
|
+
result = await api_client.set_switch_state("EXT1_2", "AUTO")
|
|
334
|
+
assert result["success"] is True
|
|
335
|
+
|
|
336
|
+
|
|
337
|
+
@pytest.mark.asyncio
|
|
338
|
+
async def test_module_alive_on_zero_count(mock_aioresponse, api_client):
|
|
339
|
+
"""EXT1 module must be detected when alive_count key is present but value is 0.
|
|
340
|
+
|
|
341
|
+
The alive counter starts at 0 immediately after a controller restart. The
|
|
342
|
+
old code required value > 0, which caused EXT1_* readings to be filtered
|
|
343
|
+
and the relay switch to appear broken right after a restart.
|
|
344
|
+
"""
|
|
345
|
+
url = "http://192.168.1.100/getReadings?ALL"
|
|
346
|
+
mock_aioresponse.get(url, payload={"getReadings": {
|
|
347
|
+
"PUMPSTATE": "2",
|
|
348
|
+
"SYSTEM_ext1module_alive_count": "0",
|
|
349
|
+
"EXT1_1": 0,
|
|
350
|
+
"EXT1_2": 0,
|
|
351
|
+
}}, status=200)
|
|
352
|
+
|
|
353
|
+
result = await api_client.get_readings()
|
|
354
|
+
assert "EXT1_2" in result, (
|
|
355
|
+
"EXT1_2 must not be filtered when SYSTEM_ext1module_alive_count is present, "
|
|
356
|
+
"even if the counter is still 0 after a restart"
|
|
357
|
+
)
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
@pytest.mark.asyncio
|
|
361
|
+
async def test_ext1_readings_not_filtered_when_detected(mock_aioresponse, api_client):
|
|
362
|
+
"""EXT1_* readings are included when extension_module_1 is detected."""
|
|
363
|
+
url = "http://192.168.1.100/getReadings?ALL"
|
|
364
|
+
mock_aioresponse.get(url, payload={"getReadings": {
|
|
365
|
+
"PUMPSTATE": "2",
|
|
366
|
+
"SYSTEM_ext1module_alive_count": "12345",
|
|
367
|
+
"EXT1_1": 1,
|
|
368
|
+
"EXT1_2": 0,
|
|
369
|
+
"EXT1_3": 0,
|
|
370
|
+
}}, status=200)
|
|
371
|
+
|
|
372
|
+
result = await api_client.get_readings()
|
|
373
|
+
assert "EXT1_1" in result
|
|
374
|
+
assert "EXT1_2" in result
|
|
375
|
+
assert "EXT1_3" in result
|
|
376
|
+
|
|
377
|
+
|
|
378
|
+
@pytest.mark.asyncio
|
|
379
|
+
async def test_ext1_readings_filtered_when_not_detected(mock_aioresponse, api_client):
|
|
380
|
+
"""EXT1_* readings are stripped when extension_module_1 key is absent."""
|
|
381
|
+
url = "http://192.168.1.100/getReadings?ALL"
|
|
382
|
+
mock_aioresponse.get(url, payload={"getReadings": {
|
|
383
|
+
"PUMPSTATE": "2",
|
|
384
|
+
# No SYSTEM_ext1module_alive_count → module not connected
|
|
385
|
+
"EXT1_1": 0,
|
|
386
|
+
"EXT1_2": 0,
|
|
387
|
+
}}, status=200)
|
|
388
|
+
|
|
389
|
+
result = await api_client.get_readings()
|
|
390
|
+
assert "EXT1_1" not in result
|
|
391
|
+
assert "EXT1_2" not in result
|
|
392
|
+
|
|
393
|
+
|
|
319
394
|
@pytest.mark.asyncio
|
|
320
395
|
async def test_get_hardware_profile_standalone_dosing(mock_aioresponse, standalone_api_client):
|
|
321
396
|
"""Test get_hardware_profile with a standalone dosing configuration."""
|
|
@@ -513,13 +513,11 @@ class VioletPoolAPI:
|
|
|
513
513
|
A dictionary with boolean flags for connected hardware components.
|
|
514
514
|
"""
|
|
515
515
|
def _module_alive(alive_key: str) -> bool:
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
except (ValueError, TypeError):
|
|
522
|
-
return False
|
|
516
|
+
# Key presence means the module is connected; the counter starts at 0
|
|
517
|
+
# on boot and the controller only emits alive-count keys for modules
|
|
518
|
+
# that are physically attached, so checking value > 0 would produce
|
|
519
|
+
# false negatives immediately after a controller restart.
|
|
520
|
+
return alive_key in flattened
|
|
523
521
|
|
|
524
522
|
def _any_relay_used(prefix: str) -> bool:
|
|
525
523
|
for key, val in flattened.items():
|
|
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
|