python-pooldose 0.5.0__tar.gz → 0.5.1__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.
- {python_pooldose-0.5.0 → python_pooldose-0.5.1}/PKG-INFO +259 -7
- {python_pooldose-0.5.0 → python_pooldose-0.5.1}/README.md +258 -6
- {python_pooldose-0.5.0 → python_pooldose-0.5.1}/pyproject.toml +1 -1
- {python_pooldose-0.5.0 → python_pooldose-0.5.1}/src/pooldose/client.py +3 -19
- python_pooldose-0.5.1/src/pooldose/constants.py +29 -0
- python_pooldose-0.5.1/src/pooldose/mappings/model_PDPR1H1HAR1V0_FW539224.json +110 -0
- python_pooldose-0.5.1/src/pooldose/mock_client.py +256 -0
- {python_pooldose-0.5.0 → python_pooldose-0.5.1}/src/python_pooldose.egg-info/PKG-INFO +259 -7
- {python_pooldose-0.5.0 → python_pooldose-0.5.1}/src/python_pooldose.egg-info/SOURCES.txt +3 -0
- {python_pooldose-0.5.0 → python_pooldose-0.5.1}/LICENSE +0 -0
- {python_pooldose-0.5.0 → python_pooldose-0.5.1}/setup.cfg +0 -0
- {python_pooldose-0.5.0 → python_pooldose-0.5.1}/src/pooldose/__init__.py +0 -0
- {python_pooldose-0.5.0 → python_pooldose-0.5.1}/src/pooldose/mappings/__init__.py +0 -0
- {python_pooldose-0.5.0 → python_pooldose-0.5.1}/src/pooldose/mappings/mapping_info.py +0 -0
- {python_pooldose-0.5.0 → python_pooldose-0.5.1}/src/pooldose/mappings/model_PDPR1H1HAW100_FW539187.json +0 -0
- {python_pooldose-0.5.0 → python_pooldose-0.5.1}/src/pooldose/request_handler.py +0 -0
- {python_pooldose-0.5.0 → python_pooldose-0.5.1}/src/pooldose/request_status.py +0 -0
- {python_pooldose-0.5.0 → python_pooldose-0.5.1}/src/pooldose/values/__init__.py +0 -0
- {python_pooldose-0.5.0 → python_pooldose-0.5.1}/src/pooldose/values/instant_values.py +0 -0
- {python_pooldose-0.5.0 → python_pooldose-0.5.1}/src/pooldose/values/static_values.py +0 -0
- {python_pooldose-0.5.0 → python_pooldose-0.5.1}/src/python_pooldose.egg-info/dependency_links.txt +0 -0
- {python_pooldose-0.5.0 → python_pooldose-0.5.1}/src/python_pooldose.egg-info/requires.txt +0 -0
- {python_pooldose-0.5.0 → python_pooldose-0.5.1}/src/python_pooldose.egg-info/top_level.txt +0 -0
- {python_pooldose-0.5.0 → python_pooldose-0.5.1}/tests/test_client.py +0 -0
- {python_pooldose-0.5.0 → python_pooldose-0.5.1}/tests/test_instant_values.py +0 -0
- {python_pooldose-0.5.0 → python_pooldose-0.5.1}/tests/test_mapping_info.py +0 -0
- {python_pooldose-0.5.0 → python_pooldose-0.5.1}/tests/test_request_handler.py +0 -0
- {python_pooldose-0.5.0 → python_pooldose-0.5.1}/tests/test_ssl_support.py +0 -0
- {python_pooldose-0.5.0 → python_pooldose-0.5.1}/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.5.
|
|
3
|
+
Version: 0.5.1
|
|
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
|
|
@@ -17,10 +17,13 @@ Requires-Dist: pytest-asyncio; extra == "dev"
|
|
|
17
17
|
Dynamic: license-file
|
|
18
18
|
|
|
19
19
|
# python-pooldose
|
|
20
|
-
|
|
20
|
+
|
|
21
|
+
Unofficial async Python client for [SEKO](https://www.seko.com/) Pooldosing systems. SEKO is a manufacturer of various monitoring and control devices for pools and spas.
|
|
22
|
+
|
|
21
23
|
This client uses an undocumented local HTTP API. It provides live readings for pool sensors such as temperature, pH, ORP/Redox, as well as status information and control over the dosing logic.
|
|
22
24
|
|
|
23
25
|
## Features
|
|
26
|
+
|
|
24
27
|
- **Async/await support** for non-blocking operations
|
|
25
28
|
- **Dynamic sensor discovery** based on device model and firmware
|
|
26
29
|
- **Dictionary-style access** to instant values
|
|
@@ -95,6 +98,7 @@ This client uses an undocumented local HTTP API. It provides live readings for p
|
|
|
95
98
|
```
|
|
96
99
|
|
|
97
100
|
## Prerequisites
|
|
101
|
+
|
|
98
102
|
1. Install and set-up the PoolDose devices according to the user manual.
|
|
99
103
|
1. In particular, connect the device to your WiFi network.
|
|
100
104
|
2. Identify the IP address or hostname of the device.
|
|
@@ -165,9 +169,246 @@ client = PooldoseClient("192.168.1.100", use_ssl=True, port=8443, ssl_verify=Fal
|
|
|
165
169
|
pip install python-pooldose
|
|
166
170
|
```
|
|
167
171
|
|
|
172
|
+
## Examples
|
|
173
|
+
|
|
174
|
+
The `examples/` directory contains demonstration scripts that show how to use the python-pooldose library:
|
|
175
|
+
|
|
176
|
+
### 1. Real Device Demo (`examples/demo.py`)
|
|
177
|
+
|
|
178
|
+
Demonstrates connecting to a real PoolDose device and accessing all types of data:
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
# Edit the HOST variable in the file first
|
|
182
|
+
python examples/demo.py
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
**Features:**
|
|
186
|
+
|
|
187
|
+
- Connects to actual hardware
|
|
188
|
+
- Shows device information and static values
|
|
189
|
+
- Displays all sensor readings, alarms, setpoints, and settings
|
|
190
|
+
- Demonstrates error handling
|
|
191
|
+
|
|
192
|
+
### 2. Mock Client Demo (`examples/demo_mock.py`)
|
|
193
|
+
|
|
194
|
+
Shows how to use the mock client with JSON files for development and testing:
|
|
195
|
+
|
|
196
|
+
```bash
|
|
197
|
+
# Run with sample data
|
|
198
|
+
python examples/demo_mock.py references/testdaten/suplere/instantvalues.json
|
|
199
|
+
|
|
200
|
+
# Use custom JSON file
|
|
201
|
+
python examples/demo_mock.py path/to/your/data.json
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
**Features:**
|
|
205
|
+
|
|
206
|
+
- No hardware required
|
|
207
|
+
- Uses real device data from JSON files
|
|
208
|
+
- Same API as real client
|
|
209
|
+
- Perfect for development and CI/CD
|
|
210
|
+
|
|
211
|
+
### Benefits of the Examples
|
|
212
|
+
|
|
213
|
+
- **Learning**: Step-by-step progression from simple to advanced usage
|
|
214
|
+
- **Development**: Mock client allows development without hardware
|
|
215
|
+
- **Testing**: JSON-based testing for CI/CD pipelines
|
|
216
|
+
- **Reference**: Real-world code patterns and best practices
|
|
217
|
+
|
|
218
|
+
## Mock Client System
|
|
219
|
+
|
|
220
|
+
The **MockPooldoseClient** system allows using JSON files instead of real Pooldose hardware for testing and development. This is particularly useful for:
|
|
221
|
+
|
|
222
|
+
- **Development without hardware**
|
|
223
|
+
- **Unit tests**
|
|
224
|
+
- **Data analysis with real device data**
|
|
225
|
+
- **CI/CD pipeline tests**
|
|
226
|
+
|
|
227
|
+
### Mock Client Quick Start
|
|
228
|
+
|
|
229
|
+
```python
|
|
230
|
+
import asyncio
|
|
231
|
+
from pathlib import Path
|
|
232
|
+
from pooldose.mock_client import MockPooldoseClient
|
|
233
|
+
|
|
234
|
+
async def simple_test():
|
|
235
|
+
# Load data file
|
|
236
|
+
json_file = Path("path/to/your/data.json")
|
|
237
|
+
|
|
238
|
+
# Create mock client
|
|
239
|
+
client = MockPooldoseClient(json_file_path=json_file)
|
|
240
|
+
|
|
241
|
+
# Connect (loads mapping data)
|
|
242
|
+
status = await client.connect()
|
|
243
|
+
if status.name != "SUCCESS":
|
|
244
|
+
print(f"Connection failed: {status}")
|
|
245
|
+
return
|
|
246
|
+
|
|
247
|
+
# Get sensor values
|
|
248
|
+
status, instant_values = await client.instant_values()
|
|
249
|
+
if status.name == "SUCCESS" and instant_values:
|
|
250
|
+
print(f"Temperature: {instant_values['temperature']}")
|
|
251
|
+
print(f"pH Value: {instant_values['ph']}")
|
|
252
|
+
print(f"ORP: {instant_values['orp']}")
|
|
253
|
+
|
|
254
|
+
# Get structured data
|
|
255
|
+
status, data = await client.instant_values_structured()
|
|
256
|
+
if status.name == "SUCCESS":
|
|
257
|
+
sensors = data.get('sensor', {})
|
|
258
|
+
for name, info in sensors.items():
|
|
259
|
+
value = info.get('value', 'N/A')
|
|
260
|
+
unit = info.get('unit', '')
|
|
261
|
+
print(f"{name}: {value} {unit}")
|
|
262
|
+
|
|
263
|
+
# Run demo
|
|
264
|
+
asyncio.run(simple_test())
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
### Mock Client Command Line Usage
|
|
268
|
+
|
|
269
|
+
You can run the demo script with custom JSON files:
|
|
270
|
+
|
|
271
|
+
```bash
|
|
272
|
+
# Run with sample data
|
|
273
|
+
python examples/demo_mock.py references/testdaten/suplere/instantvalues.json
|
|
274
|
+
|
|
275
|
+
# Use custom JSON file
|
|
276
|
+
python examples/demo_mock.py path/to/your/data.json
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
### JSON Data Format
|
|
280
|
+
|
|
281
|
+
The JSON file must have the following structure:
|
|
282
|
+
|
|
283
|
+
```json
|
|
284
|
+
{
|
|
285
|
+
"devicedata": {
|
|
286
|
+
"SERIALNUMBER_DEVICE": {
|
|
287
|
+
"MODEL_FW_w_key1": {
|
|
288
|
+
"current": 25.5,
|
|
289
|
+
"magnitude": ["°C"]
|
|
290
|
+
},
|
|
291
|
+
"MODEL_FW_w_key2": {
|
|
292
|
+
"current": 7.2,
|
|
293
|
+
"magnitude": ["pH"]
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
### Mock Client API Methods
|
|
301
|
+
|
|
302
|
+
#### Initialization
|
|
303
|
+
|
|
304
|
+
```python
|
|
305
|
+
client = MockPooldoseClient(
|
|
306
|
+
json_file_path="path/to/data.json",
|
|
307
|
+
timeout=30, # Ignored (compatibility)
|
|
308
|
+
include_sensitive_data=True # Include WiFi keys etc.
|
|
309
|
+
)
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
#### Connection
|
|
313
|
+
|
|
314
|
+
```python
|
|
315
|
+
status = await client.connect() # Loads mapping configuration
|
|
316
|
+
is_connected = client.is_connected # Check status
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
#### Data Retrieval
|
|
320
|
+
|
|
321
|
+
```python
|
|
322
|
+
# Static device information
|
|
323
|
+
status, static_values = client.static_values()
|
|
324
|
+
|
|
325
|
+
# Live sensor values
|
|
326
|
+
status, instant_values = await client.instant_values()
|
|
327
|
+
|
|
328
|
+
# Structured data (grouped by types)
|
|
329
|
+
status, structured_data = await client.instant_values_structured()
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
#### Utility Methods
|
|
333
|
+
|
|
334
|
+
```python
|
|
335
|
+
# Get raw data
|
|
336
|
+
raw_data = client.get_raw_data()
|
|
337
|
+
device_data = client.get_device_data()
|
|
338
|
+
|
|
339
|
+
# Reload JSON file
|
|
340
|
+
success = client.reload_data()
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
### Available Sample Files
|
|
344
|
+
|
|
345
|
+
The following sample JSON files are available in the repository:
|
|
346
|
+
|
|
347
|
+
- `references/testdaten/suplere/instantvalues.json` - PDPR1H1HAR1V0_FW539224 device
|
|
348
|
+
- `references/testdaten/instantvalues_poolforum_1.json` - Additional sample data
|
|
349
|
+
|
|
350
|
+
### Mock Client Use Cases
|
|
351
|
+
|
|
352
|
+
#### Unit Tests
|
|
353
|
+
|
|
354
|
+
```python
|
|
355
|
+
def test_temperature_reading():
|
|
356
|
+
client = MockPooldoseClient("sample_data.json")
|
|
357
|
+
asyncio.run(client.connect())
|
|
358
|
+
|
|
359
|
+
status, values = asyncio.run(client.instant_values())
|
|
360
|
+
assert status.name == "SUCCESS"
|
|
361
|
+
assert values['temperature'][0] == 23.0 # Expected value
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
#### Data Analysis
|
|
365
|
+
|
|
366
|
+
```python
|
|
367
|
+
# Analyze all sensor values
|
|
368
|
+
client = MockPooldoseClient("production_data.json")
|
|
369
|
+
await client.connect()
|
|
370
|
+
|
|
371
|
+
status, data = await client.instant_values_structured()
|
|
372
|
+
sensors = data.get('sensor', {})
|
|
373
|
+
|
|
374
|
+
for sensor_name, sensor_data in sensors.items():
|
|
375
|
+
value = sensor_data.get('value')
|
|
376
|
+
unit = sensor_data.get('unit', '')
|
|
377
|
+
print(f"{sensor_name}: {value} {unit}")
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
#### Integration Tests
|
|
381
|
+
|
|
382
|
+
```python
|
|
383
|
+
async def test_full_integration():
|
|
384
|
+
client = MockPooldoseClient("integration_sample_data.json")
|
|
385
|
+
|
|
386
|
+
# Test connection
|
|
387
|
+
assert await client.connect() == RequestStatus.SUCCESS
|
|
388
|
+
|
|
389
|
+
# Test static values
|
|
390
|
+
status, static = client.static_values()
|
|
391
|
+
assert status == RequestStatus.SUCCESS
|
|
392
|
+
assert static.sensor_name is not None
|
|
393
|
+
|
|
394
|
+
# Test live values
|
|
395
|
+
status, instant = await client.instant_values()
|
|
396
|
+
assert status == RequestStatus.SUCCESS
|
|
397
|
+
assert 'temperature' in instant
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
### Benefits of the Mock System
|
|
401
|
+
|
|
402
|
+
- **Fast**: No network latency
|
|
403
|
+
- **Reliable**: No hardware dependencies
|
|
404
|
+
- **Flexible**: Different scenarios testable
|
|
405
|
+
- **Realistic**: Real device data structures
|
|
406
|
+
- **Compatible**: Same API as real client
|
|
407
|
+
|
|
168
408
|
## Example Usage
|
|
169
409
|
|
|
170
410
|
### Basic Example
|
|
411
|
+
|
|
171
412
|
```python
|
|
172
413
|
import asyncio
|
|
173
414
|
import json
|
|
@@ -292,6 +533,7 @@ if __name__ == "__main__":
|
|
|
292
533
|
### Advanced Usage
|
|
293
534
|
|
|
294
535
|
#### Connection Management
|
|
536
|
+
|
|
295
537
|
```python
|
|
296
538
|
from pooldose.client import PooldoseClient
|
|
297
539
|
from pooldose.request_status import RequestStatus
|
|
@@ -316,6 +558,7 @@ else:
|
|
|
316
558
|
```
|
|
317
559
|
|
|
318
560
|
#### Error Handling
|
|
561
|
+
|
|
319
562
|
```python
|
|
320
563
|
from pooldose.client import PooldoseClient
|
|
321
564
|
|
|
@@ -335,6 +578,7 @@ else:
|
|
|
335
578
|
```
|
|
336
579
|
|
|
337
580
|
#### Working with Structured Data
|
|
581
|
+
|
|
338
582
|
```python
|
|
339
583
|
# Get all data types at once
|
|
340
584
|
status, structured_data = await client.instant_values_structured()
|
|
@@ -364,6 +608,7 @@ if status == RequestStatus.SUCCESS:
|
|
|
364
608
|
```
|
|
365
609
|
|
|
366
610
|
#### Working with Mappings
|
|
611
|
+
|
|
367
612
|
```
|
|
368
613
|
Mapping Discovery Process:
|
|
369
614
|
┌─────────────────┐
|
|
@@ -399,11 +644,13 @@ Mapping Discovery Process:
|
|
|
399
644
|
### PooldoseClient Class
|
|
400
645
|
|
|
401
646
|
#### Constructor
|
|
647
|
+
|
|
402
648
|
```python
|
|
403
649
|
PooldoseClient(host, timeout=30, include_sensitive_data=False, use_ssl=False, port=None, ssl_verify=True)
|
|
404
650
|
```
|
|
405
651
|
|
|
406
652
|
**Parameters:**
|
|
653
|
+
|
|
407
654
|
- `host` (str): The hostname or IP address of the device
|
|
408
655
|
- `timeout` (int): Request timeout in seconds (default: 30)
|
|
409
656
|
- `include_sensitive_data` (bool): Whether to include sensitive data like WiFi passwords (default: False)
|
|
@@ -412,6 +659,7 @@ PooldoseClient(host, timeout=30, include_sensitive_data=False, use_ssl=False, po
|
|
|
412
659
|
- `ssl_verify` (bool): Whether to verify SSL certificates when using HTTPS (default: True)
|
|
413
660
|
|
|
414
661
|
#### Methods
|
|
662
|
+
|
|
415
663
|
- `async connect()` → `RequestStatus` - Connect to device and initialize all components
|
|
416
664
|
- `static_values()` → `tuple[RequestStatus, StaticValues | None]` - Get static device information
|
|
417
665
|
- `async instant_values()` → `tuple[RequestStatus, InstantValues | None]` - Get current sensor readings and device state
|
|
@@ -419,6 +667,7 @@ PooldoseClient(host, timeout=30, include_sensitive_data=False, use_ssl=False, po
|
|
|
419
667
|
- `check_apiversion_supported()` → `tuple[RequestStatus, dict]` - Check API version compatibility
|
|
420
668
|
|
|
421
669
|
#### Properties
|
|
670
|
+
|
|
422
671
|
- `is_connected: bool` - Check if client is connected to device
|
|
423
672
|
- `device_info: dict` - Dictionary containing device information
|
|
424
673
|
|
|
@@ -491,6 +740,7 @@ The `instant_values_structured()` method returns data organized by type:
|
|
|
491
740
|
## Supported Devices
|
|
492
741
|
|
|
493
742
|
This client has been tested with:
|
|
743
|
+
|
|
494
744
|
- **PoolDose Double/Dual WiFi** (Model: PDPR1H1HAW100, FW: 539187)
|
|
495
745
|
|
|
496
746
|
Other SEKO PoolDose models may work but are untested. The client uses JSON mapping files to adapt to different device models and firmware versions (see e.g. `src/pooldose/mappings/model_PDPR1H1HAW100_FW539187.json`).
|
|
@@ -510,6 +760,7 @@ status = await client.connect()
|
|
|
510
760
|
```
|
|
511
761
|
|
|
512
762
|
### Security Model
|
|
763
|
+
|
|
513
764
|
```
|
|
514
765
|
Data Classification:
|
|
515
766
|
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
|
@@ -531,8 +782,9 @@ Data Classification:
|
|
|
531
782
|
|
|
532
783
|
For detailed release notes and version history, please see [CHANGELOG.md](CHANGELOG.md).
|
|
533
784
|
|
|
534
|
-
### Latest Release (0.5.
|
|
535
|
-
|
|
536
|
-
-
|
|
537
|
-
-
|
|
538
|
-
-
|
|
785
|
+
### Latest Release (0.5.1)
|
|
786
|
+
|
|
787
|
+
- **Examples**: Demo scripts for real and mock clients (`examples/` directory)
|
|
788
|
+
- **Device Support**: Added mapping for model `PDPR1H1HAR1V0_FW539224`
|
|
789
|
+
- **Mock Client**: JSON-based testing framework for development without hardware
|
|
790
|
+
- **Fixed**: Removed deprecated references and improved consistency
|