python-selve-new 2.3.4__tar.gz → 2.3.6__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 (101) hide show
  1. python_selve_new-2.3.6/.github/workflows/python-publish.yml +82 -0
  2. {python_selve_new-2.3.4/python_selve_new.egg-info → python_selve_new-2.3.6}/PKG-INFO +2 -7
  3. python_selve_new-2.3.6/debug_response.py +56 -0
  4. python_selve_new-2.3.6/debug_test.bat +61 -0
  5. python_selve_new-2.3.6/direct_hardware_test.bat +70 -0
  6. python_selve_new-2.3.6/direct_hardware_test.py +236 -0
  7. {python_selve_new-2.3.4 → python_selve_new-2.3.6}/pyproject.toml +21 -7
  8. {python_selve_new-2.3.4 → python_selve_new-2.3.6/python_selve_new.egg-info}/PKG-INFO +2 -7
  9. python_selve_new-2.3.6/python_selve_new.egg-info/SOURCES.txt +96 -0
  10. python_selve_new-2.3.6/release.py +106 -0
  11. python_selve_new-2.3.6/run_all_tests.bat +120 -0
  12. python_selve_new-2.3.6/run_hardware_tests.bat +53 -0
  13. python_selve_new-2.3.6/run_integration_tests.bat +8 -0
  14. python_selve_new-2.3.6/run_mock_tests.bat +55 -0
  15. python_selve_new-2.3.6/run_single_test.bat +81 -0
  16. python_selve_new-2.3.6/run_tests.bat +94 -0
  17. {python_selve_new-2.3.4 → python_selve_new-2.3.6}/selve/__init__.py +35 -11
  18. python_selve_new-2.3.6/selve/_version.py +21 -0
  19. {python_selve_new-2.3.4 → python_selve_new-2.3.6}/selve/commands/group.py +1 -1
  20. {python_selve_new-2.3.4 → python_selve_new-2.3.6}/selve/util/errors.py +8 -0
  21. {python_selve_new-2.3.4 → python_selve_new-2.3.6}/selve/util/protocol.py +2 -0
  22. {python_selve_new-2.3.4 → python_selve_new-2.3.6}/setup.py +5 -6
  23. python_selve_new-2.3.6/setup_and_test.bat +145 -0
  24. python_selve_new-2.3.6/tests/conftest.py +83 -0
  25. python_selve_new-2.3.6/tests/integration/README.md +51 -0
  26. python_selve_new-2.3.6/tests/integration/conftest.py +103 -0
  27. python_selve_new-2.3.6/tests/integration/test_device_integration.py +315 -0
  28. python_selve_new-2.3.6/tests/integration/test_selve_gateway_integration.py +98 -0
  29. python_selve_new-2.3.6/tests/integration/test_selve_hardware.py +206 -0
  30. python_selve_new-2.3.6/tests/integration/test_selve_integration.py +141 -0
  31. python_selve_new-2.3.6/tests/test_import.py +43 -0
  32. python_selve_new-2.3.6/tests/test_replacement.py +168 -0
  33. python_selve_new-2.3.6/tests/unit/mock_utils.py +10 -0
  34. python_selve_new-2.3.6/tests/unit/test_command_coverage.py +139 -0
  35. python_selve_new-2.3.6/tests/unit/test_commands.py +87 -0
  36. python_selve_new-2.3.6/tests/unit/test_device.py +50 -0
  37. python_selve_new-2.3.6/tests/unit/test_device_classes_coverage.py +118 -0
  38. python_selve_new-2.3.6/tests/unit/test_device_commands_extended.py +190 -0
  39. python_selve_new-2.3.6/tests/unit/test_gateway_configuration_issues.py +335 -0
  40. python_selve_new-2.3.6/tests/unit/test_gateway_error_handling_fixed.py +270 -0
  41. python_selve_new-2.3.6/tests/unit/test_group.py +30 -0
  42. python_selve_new-2.3.6/tests/unit/test_group_commands.py +108 -0
  43. python_selve_new-2.3.6/tests/unit/test_missing_components.py +213 -0
  44. python_selve_new-2.3.6/tests/unit/test_mock_commands.py +235 -0
  45. python_selve_new-2.3.6/tests/unit/test_mock_devices_and_groups.py +385 -0
  46. python_selve_new-2.3.6/tests/unit/test_mock_sensors_and_senders.py +317 -0
  47. python_selve_new-2.3.6/tests/unit/test_param_commands_extended.py +122 -0
  48. python_selve_new-2.3.6/tests/unit/test_port_discovery.py +228 -0
  49. python_selve_new-2.3.6/tests/unit/test_selve_advanced_coverage.py +284 -0
  50. python_selve_new-2.3.6/tests/unit/test_selve_core_coverage.py +214 -0
  51. python_selve_new-2.3.6/tests/unit/test_selve_edge_cases.py +265 -0
  52. python_selve_new-2.3.6/tests/unit/test_selve_gateway.py +279 -0
  53. python_selve_new-2.3.6/tests/unit/test_selve_init_comprehensive.py +423 -0
  54. python_selve_new-2.3.6/tests/unit/test_selve_init_response_coverage.py +147 -0
  55. python_selve_new-2.3.6/tests/unit/test_selve_init_simple.py +179 -0
  56. python_selve_new-2.3.6/tests/unit/test_selve_main_class_extensive.py +219 -0
  57. python_selve_new-2.3.6/tests/unit/test_sender_commands_extended.py +141 -0
  58. python_selve_new-2.3.6/tests/unit/test_sensim_commands_extended.py +201 -0
  59. python_selve_new-2.3.6/tests/unit/test_sensor_commands_extended.py +151 -0
  60. python_selve_new-2.3.6/tests/unit/test_service_command_errors.py +241 -0
  61. python_selve_new-2.3.6/tests/unit/test_service_commands.py +88 -0
  62. python_selve_new-2.3.6/tests/unit/test_util.py +55 -0
  63. python_selve_new-2.3.6/tests/unit/test_utility_coverage.py +298 -0
  64. python_selve_new-2.3.4/.github/workflows/python-publish.yml +0 -41
  65. python_selve_new-2.3.4/python_selve_new.egg-info/SOURCES.txt +0 -44
  66. python_selve_new-2.3.4/test.py +0 -46
  67. {python_selve_new-2.3.4 → python_selve_new-2.3.6}/.github/FUNDING.yml +0 -0
  68. {python_selve_new-2.3.4 → python_selve_new-2.3.6}/.gitignore +0 -0
  69. {python_selve_new-2.3.4 → python_selve_new-2.3.6}/.idea/.gitignore +0 -0
  70. {python_selve_new-2.3.4 → python_selve_new-2.3.6}/.idea/inspectionProfiles/profiles_settings.xml +0 -0
  71. {python_selve_new-2.3.4 → python_selve_new-2.3.6}/.idea/misc.xml +0 -0
  72. {python_selve_new-2.3.4 → python_selve_new-2.3.6}/.idea/modules.xml +0 -0
  73. {python_selve_new-2.3.4 → python_selve_new-2.3.6}/.idea/python-selve-new.iml +0 -0
  74. {python_selve_new-2.3.4 → python_selve_new-2.3.6}/.idea/vcs.xml +0 -0
  75. {python_selve_new-2.3.4 → python_selve_new-2.3.6}/.vscode/settings.json +0 -0
  76. {python_selve_new-2.3.4 → python_selve_new-2.3.6}/LICENSE +0 -0
  77. {python_selve_new-2.3.4 → python_selve_new-2.3.6}/README.md +0 -0
  78. {python_selve_new-2.3.4 → python_selve_new-2.3.6}/package.sh +0 -0
  79. {python_selve_new-2.3.4 → python_selve_new-2.3.6}/python_selve_new.egg-info/dependency_links.txt +0 -0
  80. {python_selve_new-2.3.4 → python_selve_new-2.3.6}/python_selve_new.egg-info/entry_points.txt +0 -0
  81. {python_selve_new-2.3.4 → python_selve_new-2.3.6}/python_selve_new.egg-info/requires.txt +0 -0
  82. {python_selve_new-2.3.4 → python_selve_new-2.3.6}/python_selve_new.egg-info/top_level.txt +0 -0
  83. {python_selve_new-2.3.4 → python_selve_new-2.3.6}/selve/commands/__init__.py +0 -0
  84. {python_selve_new-2.3.4 → python_selve_new-2.3.6}/selve/commands/command.py +0 -0
  85. {python_selve_new-2.3.4 → python_selve_new-2.3.6}/selve/commands/device.py +0 -0
  86. {python_selve_new-2.3.4 → python_selve_new-2.3.6}/selve/commands/event.py +0 -0
  87. {python_selve_new-2.3.4 → python_selve_new-2.3.6}/selve/commands/iveo.py +0 -0
  88. {python_selve_new-2.3.4 → python_selve_new-2.3.6}/selve/commands/param.py +0 -0
  89. {python_selve_new-2.3.4 → python_selve_new-2.3.6}/selve/commands/senSim.py +0 -0
  90. {python_selve_new-2.3.4 → python_selve_new-2.3.6}/selve/commands/sender.py +0 -0
  91. {python_selve_new-2.3.4 → python_selve_new-2.3.6}/selve/commands/sensor.py +0 -0
  92. {python_selve_new-2.3.4 → python_selve_new-2.3.6}/selve/commands/service.py +0 -0
  93. {python_selve_new-2.3.4 → python_selve_new-2.3.6}/selve/device.py +0 -0
  94. {python_selve_new-2.3.4 → python_selve_new-2.3.6}/selve/gateway.py +0 -0
  95. {python_selve_new-2.3.4 → python_selve_new-2.3.6}/selve/group.py +0 -0
  96. {python_selve_new-2.3.4 → python_selve_new-2.3.6}/selve/iveo.py +0 -0
  97. {python_selve_new-2.3.4 → python_selve_new-2.3.6}/selve/senSim.py +0 -0
  98. {python_selve_new-2.3.4 → python_selve_new-2.3.6}/selve/sender.py +0 -0
  99. {python_selve_new-2.3.4 → python_selve_new-2.3.6}/selve/sensor.py +0 -0
  100. {python_selve_new-2.3.4 → python_selve_new-2.3.6}/selve/util/__init__.py +0 -0
  101. {python_selve_new-2.3.4 → python_selve_new-2.3.6}/setup.cfg +0 -0
@@ -0,0 +1,82 @@
1
+ # This workflow will upload a Python Package using Twine when a release is created
2
+ # For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries
3
+
4
+ name: Test and Publish Python Package
5
+
6
+ on:
7
+ push:
8
+ branches:
9
+ - main
10
+ tags:
11
+ - 'v*' # Trigger on version tags
12
+ pull_request:
13
+ branches:
14
+ - main
15
+
16
+ permissions:
17
+ contents: read
18
+
19
+ jobs:
20
+ test:
21
+ runs-on: ubuntu-latest
22
+ strategy:
23
+ matrix:
24
+ python-version: ['3.9', '3.10', '3.11', '3.12']
25
+
26
+ steps:
27
+ - uses: actions/checkout@v4
28
+ with:
29
+ fetch-depth: 0 # Fetch all history for setuptools_scm
30
+
31
+ - name: Set up Python ${{ matrix.python-version }}
32
+ uses: actions/setup-python@v4
33
+ with:
34
+ python-version: ${{ matrix.python-version }}
35
+
36
+ - name: Install dependencies
37
+ run: |
38
+ python -m pip install --upgrade pip
39
+ pip install setuptools-scm
40
+ pip install -e .
41
+ pip install pytest pytest-cov pytest-asyncio
42
+
43
+ - name: Run tests
44
+ run: |
45
+ pytest -m "not integration" --cov=selve --cov-report=xml --cov-report=html --junitxml=test-results.xml
46
+
47
+ - name: Upload test results
48
+ uses: actions/upload-artifact@v4
49
+ if: always() && matrix.python-version == '3.11'
50
+ with:
51
+ name: test-results
52
+ path: |
53
+ test-results.xml
54
+ htmlcov/
55
+ coverage.xml
56
+
57
+ deploy:
58
+ needs: test
59
+ runs-on: ubuntu-latest
60
+ if: startsWith(github.ref, 'refs/tags/v') # Only run on version tags
61
+
62
+ steps:
63
+ - uses: actions/checkout@v4
64
+ with:
65
+ fetch-depth: 0 # Fetch all history for setuptools_scm
66
+ - name: Set up Python
67
+ uses: actions/setup-python@v4
68
+ with:
69
+ python-version: '3.x'
70
+ - name: Install dependencies
71
+ run: |
72
+ python -m pip install --upgrade pip
73
+ pip install build setuptools-scm
74
+ - name: Build package
75
+ run: |
76
+ python -m build
77
+ - name: Publish package
78
+ if: startsWith(github.ref, 'refs/tags/v')
79
+ uses: pypa/gh-action-pypi-publish@27b31702a0e7fc50959f5ad993c78deac1bdfc29
80
+ with:
81
+ user: __token__
82
+ password: ${{ secrets.PYPI_API_TOKEN }}
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-selve-new
3
- Version: 2.3.4
3
+ Version: 2.3.6
4
4
  Summary: Python library for interfacing with selve devices using the USB-RF controller. Written completely new.
5
5
  Home-page: https://github.com/Kannix2005/python-selve-new
6
6
  Author: Stefan Altheimer
@@ -12,16 +12,11 @@ Classifier: Intended Audience :: Information Technology
12
12
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
13
13
  Classifier: License :: OSI Approved :: GNU General Public License v2 or later (GPLv2+)
14
14
  Classifier: Programming Language :: Python :: 3
15
- Classifier: Programming Language :: Python :: 3.4
16
- Classifier: Programming Language :: Python :: 3.5
17
- Classifier: Programming Language :: Python :: 3.6
18
- Classifier: Programming Language :: Python :: 3.7
19
- Classifier: Programming Language :: Python :: 3.8
20
15
  Classifier: Programming Language :: Python :: 3.9
21
16
  Classifier: Programming Language :: Python :: 3.10
22
17
  Classifier: Programming Language :: Python :: 3.11
23
18
  Classifier: Programming Language :: Python :: 3.12
24
- Requires-Python: >=3.8
19
+ Requires-Python: >=3.9
25
20
  Description-Content-Type: text/markdown
26
21
  License-File: LICENSE
27
22
  Requires-Dist: requests
@@ -0,0 +1,56 @@
1
+ #!/usr/bin/env python3
2
+
3
+ from unittest.mock import Mock, patch
4
+ from selve import Selve
5
+ from selve.util import CommeoServiceCommand, CommeoParamCommand
6
+
7
+ # Test what happens when we create a response
8
+ selve = Selve(logger=Mock())
9
+
10
+ print("=== Testing ServiceGetVersionResponse ===")
11
+ mock_array = Mock()
12
+ mock_array.string = [Mock() for _ in range(7)]
13
+ mock_array.string[0].cdata = "12345"
14
+ mock_array.string[1].cdata = "1"
15
+ mock_array.string[2].cdata = "0"
16
+ mock_array.string[3].cdata = "0"
17
+ mock_array.string[4].cdata = "2"
18
+ mock_array.string[5].cdata = "1"
19
+ mock_array.string[6].cdata = "100"
20
+
21
+ # Mock hasattr properly to only return True for 'string'
22
+ def mock_hasattr_func(obj, attr):
23
+ return attr == 'string'
24
+
25
+ try:
26
+ with patch('builtins.hasattr', side_effect=mock_hasattr_func):
27
+ response = selve._create_response(mock_array, "selve.GW." + str(CommeoServiceCommand.GETVERSION.value))
28
+ print(f"Response created: {response}")
29
+ print(f"Response type: {type(response)}")
30
+ print(f"Response attributes: {[a for a in dir(response) if not a.startswith('_')]}")
31
+ if hasattr(response, 'serial'):
32
+ print(f"Serial: {response.serial}")
33
+ if hasattr(response, 'version'):
34
+ print(f"Version: {response.version}")
35
+ except Exception as e:
36
+ print(f"Error: {e}")
37
+ import traceback
38
+ traceback.print_exc()
39
+
40
+ print("\n=== Testing ParamGetForwardResponse ===")
41
+ mock_array2 = Mock()
42
+ mock_array2.string = [Mock()]
43
+ mock_array2.string[0].cdata = "1" # forwarding value
44
+
45
+ try:
46
+ with patch('builtins.hasattr', side_effect=mock_hasattr_func):
47
+ response2 = selve._create_response(mock_array2, "selve.GW." + str(CommeoParamCommand.GETFORWARD.value))
48
+ print(f"Response created: {response2}")
49
+ print(f"Response type: {type(response2)}")
50
+ print(f"Response attributes: {[a for a in dir(response2) if not a.startswith('_')]}")
51
+ if hasattr(response2, 'forwarding'):
52
+ print(f"Forwarding: {response2.forwarding}")
53
+ except Exception as e:
54
+ print(f"Error: {e}")
55
+ import traceback
56
+ traceback.print_exc()
@@ -0,0 +1,61 @@
1
+ @echo off
2
+ echo =============================================
3
+ echo Python-Selve Debug Test with Real Hardware
4
+ echo =============================================
5
+ echo WARNING: This test requires actual Selve hardware connected!
6
+ echo.
7
+
8
+ :: Check if Python is installed and get the Python command
9
+ python --version > nul 2>&1
10
+ if %ERRORLEVEL% NEQ 0 (
11
+ py --version > nul 2>&1
12
+ if %ERRORLEVEL% NEQ 0 (
13
+ echo Python is not installed or not in PATH. Please install Python first.
14
+ exit /b 1
15
+ ) else (
16
+ set PYTHON_CMD=py
17
+ )
18
+ ) else (
19
+ set PYTHON_CMD=python
20
+ )
21
+
22
+ :: Check if virtual environment exists
23
+ if not exist venv (
24
+ echo Creating virtual environment...
25
+ %PYTHON_CMD% -m venv venv
26
+ ) else (
27
+ echo Found existing virtual environment.
28
+ )
29
+
30
+ :: Activate virtual environment
31
+ echo Activating virtual environment...
32
+ call venv\Scripts\activate
33
+
34
+ :: Install requirements if needed
35
+ echo Installing required packages...
36
+ %PYTHON_CMD% -m pip install --upgrade pip
37
+ %PYTHON_CMD% -m pip install -e .
38
+
39
+ :: Ask for COM port
40
+ echo.
41
+ set /p COM_PORT=Enter COM port number (e.g., '16' for COM16):
42
+
43
+ :: Edit the test_com16.py file to use the specified COM port
44
+ echo.
45
+ echo Setting up test for COM%COM_PORT%...
46
+ powershell -Command "(Get-Content test_com16.py) | ForEach-Object { $_ -replace 'COM\d+', 'COM%COM_PORT%' } | Set-Content test_com16.py"
47
+
48
+ :: Run the debug test
49
+ echo.
50
+ echo Running debug test with COM%COM_PORT%...
51
+ %PYTHON_CMD% test_com16.py
52
+
53
+ :: Deactivate virtual environment
54
+ echo.
55
+ echo Deactivating virtual environment...
56
+ call venv\Scripts\deactivate
57
+
58
+ echo.
59
+ echo Debug test completed.
60
+ echo.
61
+ pause
@@ -0,0 +1,70 @@
1
+ @echo off
2
+ echo =============================================
3
+ echo Python-Selve Direct Hardware Test
4
+ echo =============================================
5
+ echo This script will run a direct hardware test with interactive controls.
6
+ echo.
7
+
8
+ :: Check if Python is installed and get the Python command
9
+ python --version > nul 2>&1
10
+ if %ERRORLEVEL% NEQ 0 (
11
+ py --version > nul 2>&1
12
+ if %ERRORLEVEL% NEQ 0 (
13
+ echo Python is not installed or not in PATH. Please install Python first.
14
+ exit /b 1
15
+ ) else (
16
+ set PYTHON_CMD=py
17
+ )
18
+ ) else (
19
+ set PYTHON_CMD=python
20
+ )
21
+
22
+ :: Check if virtual environment exists
23
+ if not exist venv (
24
+ echo Creating virtual environment...
25
+ %PYTHON_CMD% -m venv venv
26
+ ) else (
27
+ echo Found existing virtual environment.
28
+ )
29
+
30
+ :: Activate virtual environment
31
+ echo Activating virtual environment...
32
+ call venv\Scripts\activate
33
+
34
+ :: Install requirements if needed
35
+ echo Installing required packages...
36
+ %PYTHON_CMD% -m pip install --upgrade pip
37
+ %PYTHON_CMD% -m pip install -e .
38
+
39
+ :: Ask for test mode
40
+ echo.
41
+ echo Choose test mode:
42
+ echo 1. Auto-discover port (recommended)
43
+ echo 2. Specify COM port
44
+ echo.
45
+ set /p TEST_MODE=Enter choice (1 or 2):
46
+
47
+ if "%TEST_MODE%"=="1" (
48
+ echo.
49
+ echo Running direct hardware test with auto-discovery...
50
+ %PYTHON_CMD% direct_hardware_test.py --discover --verbose
51
+ ) else if "%TEST_MODE%"=="2" (
52
+ echo.
53
+ set /p COM_PORT=Enter COM port number (e.g., '3' for COM3):
54
+ echo.
55
+ echo Running direct hardware test with COM%COM_PORT%...
56
+ %PYTHON_CMD% direct_hardware_test.py --port COM%COM_PORT% --verbose
57
+ ) else (
58
+ echo Invalid choice. Using auto-discovery...
59
+ %PYTHON_CMD% direct_hardware_test.py --discover --verbose
60
+ )
61
+
62
+ :: Deactivate virtual environment
63
+ echo.
64
+ echo Deactivating virtual environment...
65
+ call venv\Scripts\deactivate
66
+
67
+ echo.
68
+ echo Test completed.
69
+ echo.
70
+ pause
@@ -0,0 +1,236 @@
1
+ import logging
2
+ import sys
3
+ import asyncio
4
+ import os
5
+ import argparse
6
+ from serial.tools import list_ports
7
+
8
+ # Add the project root directory to the path so we can import the selve package
9
+ sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '.')))
10
+
11
+ # Import the selve package
12
+ from selve import Selve
13
+ from selve.util.protocol import ServiceState, DeviceType, SelveTypes
14
+
15
+
16
+ async def direct_hardware_test(port=None, discover=True):
17
+ """Direct hardware test with the Selve gateway."""
18
+ # Set up logging
19
+ logger = logging.getLogger("DirectHardwareTestLogger")
20
+ logger.setLevel(logging.DEBUG)
21
+ handler = logging.StreamHandler(sys.stdout)
22
+ handler.setLevel(logging.DEBUG)
23
+ formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
24
+ handler.setFormatter(formatter)
25
+ logger.addHandler(handler)
26
+
27
+ # Create a new event loop
28
+ loop = asyncio.get_event_loop()
29
+
30
+ try:
31
+ # Check for available ports
32
+ available_ports = []
33
+ for port_info in list_ports.comports():
34
+ available_ports.append(port_info.device)
35
+
36
+ print(f"Available COM ports: {available_ports}")
37
+
38
+ # Create the Selve instance
39
+ print(f"Creating Selve instance with port={port}, discover={discover}")
40
+ selve_instance = Selve(port=port, discover=discover, develop=True, logger=logger, loop=loop)
41
+
42
+ # Setup the connection
43
+ print("Setting up connection...")
44
+ await selve_instance.setup()
45
+
46
+ # Test ping
47
+ print("\nTesting ping...")
48
+ result = await selve_instance.pingGatewayFromWorker()
49
+ print(f"Ping result: {result}")
50
+
51
+ if not result:
52
+ print("Failed to ping gateway. Check connection and try again.")
53
+ await selve_instance.stopWorker()
54
+ return
55
+
56
+ # Get gateway state
57
+ print("\nGetting gateway state...")
58
+ state = await selve_instance.gatewayState()
59
+ print(f"Gateway state: {state}")
60
+
61
+ # Check if gateway is ready
62
+ print("\nChecking if gateway is ready...")
63
+ is_ready = await selve_instance.gatewayReady()
64
+ print(f"Gateway ready: {is_ready}")
65
+
66
+ # Get gateway version
67
+ print("\nGetting gateway version...")
68
+ version = await selve_instance.getGatewayFirmwareVersion()
69
+ print(f"Gateway firmware version: {version}")
70
+
71
+ # Get gateway serial number
72
+ print("\nGetting gateway serial number...")
73
+ serial = await selve_instance.getGatewaySerial()
74
+ print(f"Gateway serial number: {serial}")
75
+
76
+ # Discover devices
77
+ print("\nDiscovering devices...")
78
+ await selve_instance.discover()
79
+
80
+ # Print discovered devices
81
+ devices = getattr(selve_instance, 'devices', {})
82
+
83
+ if 'device' in devices and devices['device']:
84
+ print(f"\nFound {len(devices['device'])} devices:")
85
+ for device_id, device in devices['device'].items():
86
+ print(f" Device {device_id}: {device}")
87
+ print(f" Name: {device.name}")
88
+ print(f" Type: {device.device_type.name}")
89
+ print(f" Sub-type: {device.device_sub_type.name}")
90
+ print(f" State: {device.state}")
91
+ print(f" Value: {device.value}")
92
+ print(f" Target: {device.targetValue}")
93
+
94
+ # Ask if user wants to control a device
95
+ print("\nDo you want to control a device? (y/n)")
96
+ choice = input().strip().lower()
97
+ if choice == 'y':
98
+ # Ask which device to control
99
+ print("\nEnter the device ID to control:")
100
+ device_id_str = input().strip()
101
+ try:
102
+ device_id = int(device_id_str)
103
+ if device_id in devices['device']:
104
+ device = devices['device'][device_id]
105
+ print(f"Controlling device {device_id}: {device.name}")
106
+
107
+ # Control loop
108
+ while True:
109
+ print("\nActions:")
110
+ print("1. Move Up")
111
+ print("2. Move Down")
112
+ print("3. Stop")
113
+ print("4. Get Device Info")
114
+ print("5. Back to main menu")
115
+
116
+ action = input("Select action (1-5): ").strip()
117
+
118
+ if action == '1':
119
+ print("Moving up...")
120
+ await selve_instance.moveDeviceUp(device)
121
+ elif action == '2':
122
+ print("Moving down...")
123
+ await selve_instance.moveDeviceDown(device)
124
+ elif action == '3':
125
+ print("Stopping...")
126
+ await selve_instance.moveDeviceStop(device)
127
+ elif action == '4':
128
+ print("\nDevice Info:")
129
+ print(f" Name: {device.name}")
130
+ print(f" Type: {device.device_type.name}")
131
+ print(f" Sub-type: {device.device_sub_type.name}")
132
+ print(f" State: {device.state}")
133
+ print(f" Value: {device.value}")
134
+ print(f" Target: {device.targetValue}")
135
+ elif action == '5':
136
+ break
137
+ else:
138
+ print("Invalid choice. Please try again.")
139
+ else:
140
+ print(f"No device with ID {device_id} found.")
141
+ except ValueError:
142
+ print("Invalid device ID. Please enter a number.")
143
+ else:
144
+ print("\nNo devices found.")
145
+
146
+ if 'group' in devices and devices['group']:
147
+ print(f"\nFound {len(devices['group'])} groups:")
148
+ for group_id, group in devices['group'].items():
149
+ print(f" Group {group_id}: {group}")
150
+ print(f" Name: {group.name}")
151
+
152
+ # Ask if user wants to control a group
153
+ print("\nDo you want to control a group? (y/n)")
154
+ choice = input().strip().lower()
155
+ if choice == 'y':
156
+ # Ask which group to control
157
+ print("\nEnter the group ID to control:")
158
+ group_id_str = input().strip()
159
+ try:
160
+ group_id = int(group_id_str)
161
+ if group_id in devices['group']:
162
+ group = devices['group'][group_id]
163
+ print(f"Controlling group {group_id}: {group.name}")
164
+
165
+ # Control loop
166
+ while True:
167
+ print("\nActions:")
168
+ print("1. Move Up")
169
+ print("2. Move Down")
170
+ print("3. Stop")
171
+ print("4. Get Group Info")
172
+ print("5. Back to main menu")
173
+
174
+ action = input("Select action (1-5): ").strip()
175
+
176
+ if action == '1':
177
+ print("Moving up...")
178
+ await selve_instance.moveGroupUp(group)
179
+ elif action == '2':
180
+ print("Moving down...")
181
+ await selve_instance.moveGroupDown(group)
182
+ elif action == '3':
183
+ print("Stopping...")
184
+ await selve_instance.moveGroupStop(group)
185
+ elif action == '4':
186
+ print("\nGroup Info:")
187
+ print(f" Name: {group.name}")
188
+ print(f" Type: {group.device_type.name}")
189
+ print(f" Sub-type: {group.device_sub_type.name}")
190
+ elif action == '5':
191
+ break
192
+ else:
193
+ print("Invalid choice. Please try again.")
194
+ else:
195
+ print(f"No group with ID {group_id} found.")
196
+ except ValueError:
197
+ print("Invalid group ID. Please enter a number.")
198
+ else:
199
+ print("\nNo groups found.")
200
+
201
+ # Clean up
202
+ print("\nCleaning up...")
203
+ await selve_instance.stopWorker()
204
+
205
+ except Exception as e:
206
+ print(f"Error: {e}")
207
+ import traceback
208
+ traceback.print_exc()
209
+
210
+ print("\nTest completed!")
211
+
212
+
213
+ if __name__ == "__main__":
214
+ # Parse command line arguments
215
+ parser = argparse.ArgumentParser(description='Direct hardware test with the Selve gateway.')
216
+ parser.add_argument('-p', '--port', help='COM port to use (e.g., COM3)')
217
+ parser.add_argument('-d', '--discover', action='store_true', help='Enable auto-discovery of port')
218
+ parser.add_argument('-v', '--verbose', action='store_true', help='Enable verbose logging')
219
+
220
+ args = parser.parse_args()
221
+
222
+ # Configure logging
223
+ log_level = logging.DEBUG if args.verbose else logging.INFO
224
+ logging.basicConfig(level=log_level)
225
+
226
+ try:
227
+ # Use port if specified, otherwise use auto-discovery
228
+ port = args.port
229
+ discover = True if port is None or args.discover else False
230
+
231
+ asyncio.run(direct_hardware_test(port, discover))
232
+ except KeyboardInterrupt:
233
+ print("Test interrupted by user.")
234
+ except Exception as e:
235
+ print(f"Test failed with error: {e}")
236
+ sys.exit(1)
@@ -9,7 +9,7 @@ authors = [
9
9
  ]
10
10
  description = "Python library for interfacing with selve devices using the USB-RF controller. Written completely new."
11
11
  readme = "README.md"
12
- requires-python = ">=3.8"
12
+ requires-python = ">=3.9"
13
13
  keywords = ["selve", "blind", "awning", "shutter", "usb", "rf"]
14
14
  license = {text = "GNU General Public License v2 or later (GPLv2+)"}
15
15
  classifiers = [
@@ -23,11 +23,6 @@ classifiers = [
23
23
  # Specify the Python versions you support here. In particular, ensure
24
24
  # that you indicate whether you support Python 2, Python 3 or both.
25
25
  "Programming Language :: Python :: 3",
26
- "Programming Language :: Python :: 3.4",
27
- "Programming Language :: Python :: 3.5",
28
- "Programming Language :: Python :: 3.6",
29
- "Programming Language :: Python :: 3.7",
30
- "Programming Language :: Python :: 3.8",
31
26
  "Programming Language :: Python :: 3.9",
32
27
  "Programming Language :: Python :: 3.10",
33
28
  "Programming Language :: Python :: 3.11",
@@ -47,4 +42,23 @@ dynamic = ["version"]
47
42
  my-script = "my_package.module:function"
48
43
 
49
44
  # ... other project metadata fields as listed in:
50
- # https://packaging.python.org/en/latest/guides/writing-pyproject-toml/
45
+ # https://packaging.python.org/en/latest/guides/writing-pyproject-toml/
46
+
47
+ [tool.setuptools_scm]
48
+ write_to = "selve/_version.py"
49
+ version_scheme = "post-release"
50
+ local_scheme = "no-local-version"
51
+
52
+ [tool.pytest.ini_options]
53
+ minversion = "6.0"
54
+ addopts = "-ra -q --strict-markers"
55
+ testpaths = [
56
+ "tests",
57
+ ]
58
+ markers = [
59
+ "asyncio: marks tests as async tests",
60
+ "integration: marks tests as integration tests",
61
+ "unit: marks tests as unit tests",
62
+ ]
63
+ asyncio_mode = "auto"
64
+ asyncio_default_fixture_loop_scope = "function"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-selve-new
3
- Version: 2.3.4
3
+ Version: 2.3.6
4
4
  Summary: Python library for interfacing with selve devices using the USB-RF controller. Written completely new.
5
5
  Home-page: https://github.com/Kannix2005/python-selve-new
6
6
  Author: Stefan Altheimer
@@ -12,16 +12,11 @@ Classifier: Intended Audience :: Information Technology
12
12
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
13
13
  Classifier: License :: OSI Approved :: GNU General Public License v2 or later (GPLv2+)
14
14
  Classifier: Programming Language :: Python :: 3
15
- Classifier: Programming Language :: Python :: 3.4
16
- Classifier: Programming Language :: Python :: 3.5
17
- Classifier: Programming Language :: Python :: 3.6
18
- Classifier: Programming Language :: Python :: 3.7
19
- Classifier: Programming Language :: Python :: 3.8
20
15
  Classifier: Programming Language :: Python :: 3.9
21
16
  Classifier: Programming Language :: Python :: 3.10
22
17
  Classifier: Programming Language :: Python :: 3.11
23
18
  Classifier: Programming Language :: Python :: 3.12
24
- Requires-Python: >=3.8
19
+ Requires-Python: >=3.9
25
20
  Description-Content-Type: text/markdown
26
21
  License-File: LICENSE
27
22
  Requires-Dist: requests