python-pooldose 0.5.0__tar.gz → 0.6.0__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 (33) hide show
  1. {python_pooldose-0.5.0 → python_pooldose-0.6.0}/PKG-INFO +326 -9
  2. {python_pooldose-0.5.0 → python_pooldose-0.6.0}/README.md +325 -8
  3. python_pooldose-0.6.0/pyproject.toml +88 -0
  4. {python_pooldose-0.5.0 → python_pooldose-0.6.0}/src/pooldose/__init__.py +1 -0
  5. python_pooldose-0.6.0/src/pooldose/__main__.py +205 -0
  6. {python_pooldose-0.5.0 → python_pooldose-0.6.0}/src/pooldose/client.py +6 -22
  7. python_pooldose-0.6.0/src/pooldose/constants.py +29 -0
  8. {python_pooldose-0.5.0 → python_pooldose-0.6.0}/src/pooldose/mappings/mapping_info.py +4 -2
  9. python_pooldose-0.6.0/src/pooldose/mappings/model_PDPR1H1HAR1V0_FW539224.json +110 -0
  10. python_pooldose-0.6.0/src/pooldose/mock_client.py +256 -0
  11. python_pooldose-0.6.0/src/pooldose/py.typed +0 -0
  12. {python_pooldose-0.5.0 → python_pooldose-0.6.0}/src/pooldose/request_handler.py +4 -3
  13. {python_pooldose-0.5.0 → python_pooldose-0.6.0}/src/pooldose/request_status.py +1 -0
  14. {python_pooldose-0.5.0 → python_pooldose-0.6.0}/src/pooldose/values/instant_values.py +1 -0
  15. {python_pooldose-0.5.0 → python_pooldose-0.6.0}/src/python_pooldose.egg-info/PKG-INFO +326 -9
  16. {python_pooldose-0.5.0 → python_pooldose-0.6.0}/src/python_pooldose.egg-info/SOURCES.txt +6 -0
  17. python_pooldose-0.6.0/src/python_pooldose.egg-info/entry_points.txt +2 -0
  18. python_pooldose-0.5.0/pyproject.toml +0 -38
  19. {python_pooldose-0.5.0 → python_pooldose-0.6.0}/LICENSE +0 -0
  20. {python_pooldose-0.5.0 → python_pooldose-0.6.0}/setup.cfg +0 -0
  21. {python_pooldose-0.5.0 → python_pooldose-0.6.0}/src/pooldose/mappings/__init__.py +0 -0
  22. {python_pooldose-0.5.0 → python_pooldose-0.6.0}/src/pooldose/mappings/model_PDPR1H1HAW100_FW539187.json +0 -0
  23. {python_pooldose-0.5.0 → python_pooldose-0.6.0}/src/pooldose/values/__init__.py +0 -0
  24. {python_pooldose-0.5.0 → python_pooldose-0.6.0}/src/pooldose/values/static_values.py +0 -0
  25. {python_pooldose-0.5.0 → python_pooldose-0.6.0}/src/python_pooldose.egg-info/dependency_links.txt +0 -0
  26. {python_pooldose-0.5.0 → python_pooldose-0.6.0}/src/python_pooldose.egg-info/requires.txt +0 -0
  27. {python_pooldose-0.5.0 → python_pooldose-0.6.0}/src/python_pooldose.egg-info/top_level.txt +0 -0
  28. {python_pooldose-0.5.0 → python_pooldose-0.6.0}/tests/test_client.py +0 -0
  29. {python_pooldose-0.5.0 → python_pooldose-0.6.0}/tests/test_instant_values.py +0 -0
  30. {python_pooldose-0.5.0 → python_pooldose-0.6.0}/tests/test_mapping_info.py +0 -0
  31. {python_pooldose-0.5.0 → python_pooldose-0.6.0}/tests/test_request_handler.py +0 -0
  32. {python_pooldose-0.5.0 → python_pooldose-0.6.0}/tests/test_ssl_support.py +0 -0
  33. {python_pooldose-0.5.0 → python_pooldose-0.6.0}/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.0
3
+ Version: 0.6.0
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,14 +17,19 @@ Requires-Dist: pytest-asyncio; extra == "dev"
17
17
  Dynamic: license-file
18
18
 
19
19
  # python-pooldose
20
- 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.
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
27
30
  - **Structured data API** with type-based organization
31
+ - **PEP-561 compliant** with full type hints for Home Assistant integrations
32
+ - **Command-line interface** for direct device interaction and testing
28
33
  - **Secure by default** - WiFi passwords excluded unless explicitly requested
29
34
  - **Comprehensive error handling** with detailed logging
30
35
  - **SSL/HTTPS support** for secure communication
@@ -95,6 +100,7 @@ This client uses an undocumented local HTTP API. It provides live readings for p
95
100
  ```
96
101
 
97
102
  ## Prerequisites
103
+
98
104
  1. Install and set-up the PoolDose devices according to the user manual.
99
105
  1. In particular, connect the device to your WiFi network.
100
106
  2. Identify the IP address or hostname of the device.
@@ -165,9 +171,265 @@ client = PooldoseClient("192.168.1.100", use_ssl=True, port=8443, ssl_verify=Fal
165
171
  pip install python-pooldose
166
172
  ```
167
173
 
174
+ ## Command Line Usage
175
+
176
+ After installation, you can use python-pooldose directly from the command line:
177
+
178
+ ### Connect to Real Device
179
+
180
+ ```bash
181
+ # Basic connection
182
+ pooldose --host 192.168.1.100
183
+
184
+ # With HTTPS
185
+ pooldose --host 192.168.1.100 --ssl
186
+
187
+ # Custom port
188
+ pooldose --host 192.168.1.100 --ssl --port 8443
189
+ ```
190
+
191
+ ### Mock Mode with JSON Files
192
+
193
+ ```bash
194
+ # Use JSON file for testing
195
+ pooldose --mock path/to/your/data.json
196
+ ```
197
+
198
+ ### Alternative Module Execution
199
+
200
+ You can also run it as a Python module:
201
+
202
+ ```bash
203
+ # Real device
204
+ python -m pooldose --host 192.168.1.100
205
+
206
+ # Mock mode
207
+ python -m pooldose --mock data.json
208
+
209
+ # Show help
210
+ python -m pooldose --help
211
+ ```
212
+
213
+ ## Examples
214
+
215
+ The `examples/` directory contains demonstration scripts that show how to use the python-pooldose library:
216
+
217
+ ### 1. Real Device Demo (`examples/demo.py`)
218
+
219
+ Demonstrates connecting to a real PoolDose device and accessing all types of data:
220
+
221
+ ```bash
222
+ # Edit the HOST variable in the file first
223
+ python examples/demo.py
224
+ ```
225
+
226
+ **Features:**
227
+
228
+ - Connects to actual hardware
229
+ - Shows device information and static values
230
+ - Displays all sensor readings, alarms, setpoints, and settings
231
+ - Demonstrates error handling
232
+
233
+ ### Benefits of the Examples
234
+
235
+ - **Learning**: Step-by-step progression from simple to advanced usage
236
+ - **Development**: Mock client allows development without hardware
237
+ - **Testing**: JSON-based testing for CI/CD pipelines
238
+ - **Reference**: Real-world code patterns and best practices
239
+
240
+ ## Mock Client System
241
+
242
+ The **MockPooldoseClient** system allows using JSON files instead of real Pooldose hardware for testing and development. This is particularly useful for:
243
+
244
+ - **Development without hardware**
245
+ - **Unit tests**
246
+ - **Data analysis with real device data**
247
+ - **CI/CD pipeline tests**
248
+
249
+ ### Mock Client Quick Start
250
+
251
+ ```python
252
+ import asyncio
253
+ from pathlib import Path
254
+ from pooldose.mock_client import MockPooldoseClient
255
+
256
+ async def simple_test():
257
+ # Load data file
258
+ json_file = Path("path/to/your/data.json")
259
+
260
+ # Create mock client
261
+ client = MockPooldoseClient(json_file_path=json_file)
262
+
263
+ # Connect (loads mapping data)
264
+ status = await client.connect()
265
+ if status.name != "SUCCESS":
266
+ print(f"Connection failed: {status}")
267
+ return
268
+
269
+ # Get sensor values
270
+ status, instant_values = await client.instant_values()
271
+ if status.name == "SUCCESS" and instant_values:
272
+ print(f"Temperature: {instant_values['temperature']}")
273
+ print(f"pH Value: {instant_values['ph']}")
274
+ print(f"ORP: {instant_values['orp']}")
275
+
276
+ # Get structured data
277
+ status, data = await client.instant_values_structured()
278
+ if status.name == "SUCCESS":
279
+ sensors = data.get('sensor', {})
280
+ for name, info in sensors.items():
281
+ value = info.get('value', 'N/A')
282
+ unit = info.get('unit', '')
283
+ print(f"{name}: {value} {unit}")
284
+
285
+ # Run demo
286
+ asyncio.run(simple_test())
287
+ ```
288
+
289
+ ### Mock Client Command Line Usage
290
+
291
+ You can use the mock client with custom JSON files via the command line:
292
+
293
+ ```bash
294
+ # Use mock client with JSON file
295
+ pooldose --mock path/to/your/data.json
296
+
297
+ # Or as Python module
298
+ python -m pooldose --mock path/to/your/data.json
299
+ ```
300
+
301
+ ### JSON Data Format
302
+
303
+ The JSON file must have the following structure:
304
+
305
+ ```json
306
+ {
307
+ "devicedata": {
308
+ "SERIALNUMBER_DEVICE": {
309
+ "MODEL_FW_w_key1": {
310
+ "current": 25.5,
311
+ "magnitude": ["°C"]
312
+ },
313
+ "MODEL_FW_w_key2": {
314
+ "current": 7.2,
315
+ "magnitude": ["pH"]
316
+ }
317
+ }
318
+ }
319
+ }
320
+ ```
321
+
322
+ ### Mock Client API Methods
323
+
324
+ #### Initialization
325
+
326
+ ```python
327
+ client = MockPooldoseClient(
328
+ json_file_path="path/to/data.json",
329
+ timeout=30, # Ignored (compatibility)
330
+ include_sensitive_data=True # Include WiFi keys etc.
331
+ )
332
+ ```
333
+
334
+ #### Connection
335
+
336
+ ```python
337
+ status = await client.connect() # Loads mapping configuration
338
+ is_connected = client.is_connected # Check status
339
+ ```
340
+
341
+ #### Data Retrieval
342
+
343
+ ```python
344
+ # Static device information
345
+ status, static_values = client.static_values()
346
+
347
+ # Live sensor values
348
+ status, instant_values = await client.instant_values()
349
+
350
+ # Structured data (grouped by types)
351
+ status, structured_data = await client.instant_values_structured()
352
+ ```
353
+
354
+ #### Utility Methods
355
+
356
+ ```python
357
+ # Get raw data
358
+ raw_data = client.get_raw_data()
359
+ device_data = client.get_device_data()
360
+
361
+ # Reload JSON file
362
+ success = client.reload_data()
363
+ ```
364
+
365
+ ### Available Sample Files
366
+
367
+ The following sample JSON files are available in the repository:
368
+
369
+ - `references/testdaten/tscherno/instantvalues.json` - Sample device data for testing
370
+
371
+ ### Mock Client Use Cases
372
+
373
+ #### Unit Tests
374
+
375
+ ```python
376
+ def test_temperature_reading():
377
+ client = MockPooldoseClient("sample_data.json")
378
+ asyncio.run(client.connect())
379
+
380
+ status, values = asyncio.run(client.instant_values())
381
+ assert status.name == "SUCCESS"
382
+ assert values['temperature'][0] == 23.0 # Expected value
383
+ ```
384
+
385
+ #### Data Analysis
386
+
387
+ ```python
388
+ # Analyze all sensor values
389
+ client = MockPooldoseClient("production_data.json")
390
+ await client.connect()
391
+
392
+ status, data = await client.instant_values_structured()
393
+ sensors = data.get('sensor', {})
394
+
395
+ for sensor_name, sensor_data in sensors.items():
396
+ value = sensor_data.get('value')
397
+ unit = sensor_data.get('unit', '')
398
+ print(f"{sensor_name}: {value} {unit}")
399
+ ```
400
+
401
+ #### Integration Tests
402
+
403
+ ```python
404
+ async def test_full_integration():
405
+ client = MockPooldoseClient("integration_sample_data.json")
406
+
407
+ # Test connection
408
+ assert await client.connect() == RequestStatus.SUCCESS
409
+
410
+ # Test static values
411
+ status, static = client.static_values()
412
+ assert status == RequestStatus.SUCCESS
413
+ assert static.sensor_name is not None
414
+
415
+ # Test live values
416
+ status, instant = await client.instant_values()
417
+ assert status == RequestStatus.SUCCESS
418
+ assert 'temperature' in instant
419
+ ```
420
+
421
+ ### Benefits of the Mock System
422
+
423
+ - **Fast**: No network latency
424
+ - **Reliable**: No hardware dependencies
425
+ - **Flexible**: Different scenarios testable
426
+ - **Realistic**: Real device data structures
427
+ - **Compatible**: Same API as real client
428
+
168
429
  ## Example Usage
169
430
 
170
431
  ### Basic Example
432
+
171
433
  ```python
172
434
  import asyncio
173
435
  import json
@@ -292,6 +554,7 @@ if __name__ == "__main__":
292
554
  ### Advanced Usage
293
555
 
294
556
  #### Connection Management
557
+
295
558
  ```python
296
559
  from pooldose.client import PooldoseClient
297
560
  from pooldose.request_status import RequestStatus
@@ -316,6 +579,7 @@ else:
316
579
  ```
317
580
 
318
581
  #### Error Handling
582
+
319
583
  ```python
320
584
  from pooldose.client import PooldoseClient
321
585
 
@@ -335,6 +599,7 @@ else:
335
599
  ```
336
600
 
337
601
  #### Working with Structured Data
602
+
338
603
  ```python
339
604
  # Get all data types at once
340
605
  status, structured_data = await client.instant_values_structured()
@@ -364,6 +629,7 @@ if status == RequestStatus.SUCCESS:
364
629
  ```
365
630
 
366
631
  #### Working with Mappings
632
+
367
633
  ```
368
634
  Mapping Discovery Process:
369
635
  ┌─────────────────┐
@@ -399,11 +665,13 @@ Mapping Discovery Process:
399
665
  ### PooldoseClient Class
400
666
 
401
667
  #### Constructor
668
+
402
669
  ```python
403
670
  PooldoseClient(host, timeout=30, include_sensitive_data=False, use_ssl=False, port=None, ssl_verify=True)
404
671
  ```
405
672
 
406
673
  **Parameters:**
674
+
407
675
  - `host` (str): The hostname or IP address of the device
408
676
  - `timeout` (int): Request timeout in seconds (default: 30)
409
677
  - `include_sensitive_data` (bool): Whether to include sensitive data like WiFi passwords (default: False)
@@ -412,6 +680,7 @@ PooldoseClient(host, timeout=30, include_sensitive_data=False, use_ssl=False, po
412
680
  - `ssl_verify` (bool): Whether to verify SSL certificates when using HTTPS (default: True)
413
681
 
414
682
  #### Methods
683
+
415
684
  - `async connect()` → `RequestStatus` - Connect to device and initialize all components
416
685
  - `static_values()` → `tuple[RequestStatus, StaticValues | None]` - Get static device information
417
686
  - `async instant_values()` → `tuple[RequestStatus, InstantValues | None]` - Get current sensor readings and device state
@@ -419,6 +688,7 @@ PooldoseClient(host, timeout=30, include_sensitive_data=False, use_ssl=False, po
419
688
  - `check_apiversion_supported()` → `tuple[RequestStatus, dict]` - Check API version compatibility
420
689
 
421
690
  #### Properties
691
+
422
692
  - `is_connected: bool` - Check if client is connected to device
423
693
  - `device_info: dict` - Dictionary containing device information
424
694
 
@@ -491,12 +761,55 @@ The `instant_values_structured()` method returns data organized by type:
491
761
  ## Supported Devices
492
762
 
493
763
  This client has been tested with:
494
- - **PoolDose Double/Dual WiFi** (Model: PDPR1H1HAW100, FW: 539187)
764
+
765
+ - **SEKO PoolDose Double/Dual WiFi** (Model: PDPR1H1HAW100, FW: 539187)
766
+ - **VA dos BASIC Chlor - pH/ORP Wi-Fi** (Model: PDPR1H1HAR1V0, FW: 539224)
495
767
 
496
768
  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`).
497
769
 
498
770
  > **Note:** The JSON files in the mappings directory define the device-specific data keys and their human-readable names for different PoolDose models and firmware versions.
499
771
 
772
+ ## Type Hints & Home Assistant Integration
773
+
774
+ This package is **PEP-561 compliant** and fully typed for use in Home Assistant integrations:
775
+
776
+ ### Type Safety Features
777
+
778
+ **PEP-561 Compliance**: Package includes `py.typed` file marking it as fully typed
779
+ **Comprehensive Type Annotations**: All public API methods have complete type hints
780
+ **mypy Support**: Built-in mypy configuration for static type checking
781
+ **Home Assistant Ready**: Compatible with Home Assistant's strict typing requirements
782
+
783
+ ### Type-Safe Usage
784
+
785
+ ```python
786
+ from pooldose import PooldoseClient
787
+ from pooldose.request_status import RequestStatus
788
+
789
+ # Type checkers will infer all types automatically
790
+ client: PooldoseClient = PooldoseClient("192.168.1.100")
791
+ status: RequestStatus = await client.connect()
792
+
793
+ # Dictionary-style access with proper typing
794
+ status, instant_values = await client.instant_values()
795
+ if status == RequestStatus.SUCCESS and instant_values:
796
+ temperature = instant_values["temperature"] # Typed as tuple[float, str]
797
+ ph_value = instant_values.get("ph", "N/A") # Safe access with default
798
+
799
+ # Structured data with full type safety
800
+ status, structured_data = await client.instant_values_structured()
801
+ sensors = structured_data.get("sensor", {}) # Type: dict[str, dict[str, Any]]
802
+ ```
803
+
804
+ ### Integration Benefits
805
+
806
+ - **IDE Support**: Full autocomplete and type checking in VS Code, PyCharm, etc.
807
+ - **Runtime Safety**: Catch type errors before deployment
808
+ - **Documentation**: Self-documenting code through type annotations
809
+ - **Maintenance**: Easier refactoring with type-guided development
810
+
811
+ For Home Assistant integrations, add this package to your integration's dependencies and enjoy full type safety throughout your integration code.
812
+
500
813
  ## Security
501
814
 
502
815
  By default, the client excludes sensitive information like WiFi passwords from device info. To include sensitive data:
@@ -510,7 +823,8 @@ status = await client.connect()
510
823
  ```
511
824
 
512
825
  ### Security Model
513
- ```
826
+
827
+ ```text
514
828
  Data Classification:
515
829
  ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
516
830
  │ Public Data │ │ Sensitive Data │ │ Never Exposed │
@@ -531,8 +845,11 @@ Data Classification:
531
845
 
532
846
  For detailed release notes and version history, please see [CHANGELOG.md](CHANGELOG.md).
533
847
 
534
- ### Latest Release (0.5.0)
535
- - **BREAKING**: Redesigned API with dictionary-style access (`instant_values["key"]`)
536
- - New structured data method `instant_values_structured()` grouped by type
537
- - Removed deprecated getter methods, enhanced validation, improved error handling
538
- - Complete code modernization and comprehensive test
848
+ ### Latest Release (0.6.0)
849
+
850
+ - **Command Line Interface**: Complete CLI with `--host`, `--mock`, `--ssl`, and `--port` options
851
+ - **Pip Installation**: Install as console script via `pip install python-pooldose`
852
+ - **PEP-561 Type Compliance**: Full typing support for Home Assistant integrations
853
+ - **Documentation Modernization**: Centralized CLI documentation
854
+ - **Code Quality**: Pylint 10.00/10 score with strict typing and enhanced error handling
855
+ - **Simplified Structure**: Removed deprecated demo scripts, integrated mock functionality into CLI