python-selve-new 2.3.3__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.
- python_selve_new-2.3.6/.github/workflows/python-publish.yml +82 -0
- {python_selve_new-2.3.3/python_selve_new.egg-info → python_selve_new-2.3.6}/PKG-INFO +2 -7
- python_selve_new-2.3.6/debug_response.py +56 -0
- python_selve_new-2.3.6/debug_test.bat +61 -0
- python_selve_new-2.3.6/direct_hardware_test.bat +70 -0
- python_selve_new-2.3.6/direct_hardware_test.py +236 -0
- {python_selve_new-2.3.3 → python_selve_new-2.3.6}/pyproject.toml +21 -7
- {python_selve_new-2.3.3 → python_selve_new-2.3.6/python_selve_new.egg-info}/PKG-INFO +2 -7
- python_selve_new-2.3.6/python_selve_new.egg-info/SOURCES.txt +96 -0
- python_selve_new-2.3.6/release.py +106 -0
- python_selve_new-2.3.6/run_all_tests.bat +120 -0
- python_selve_new-2.3.6/run_hardware_tests.bat +53 -0
- python_selve_new-2.3.6/run_integration_tests.bat +8 -0
- python_selve_new-2.3.6/run_mock_tests.bat +55 -0
- python_selve_new-2.3.6/run_single_test.bat +81 -0
- python_selve_new-2.3.6/run_tests.bat +94 -0
- {python_selve_new-2.3.3 → python_selve_new-2.3.6}/selve/__init__.py +38 -12
- python_selve_new-2.3.6/selve/_version.py +21 -0
- {python_selve_new-2.3.3 → python_selve_new-2.3.6}/selve/commands/group.py +1 -1
- {python_selve_new-2.3.3 → python_selve_new-2.3.6}/selve/util/errors.py +8 -0
- {python_selve_new-2.3.3 → python_selve_new-2.3.6}/selve/util/protocol.py +2 -0
- {python_selve_new-2.3.3 → python_selve_new-2.3.6}/setup.py +5 -6
- python_selve_new-2.3.6/setup_and_test.bat +145 -0
- python_selve_new-2.3.6/tests/conftest.py +83 -0
- python_selve_new-2.3.6/tests/integration/README.md +51 -0
- python_selve_new-2.3.6/tests/integration/conftest.py +103 -0
- python_selve_new-2.3.6/tests/integration/test_device_integration.py +315 -0
- python_selve_new-2.3.6/tests/integration/test_selve_gateway_integration.py +98 -0
- python_selve_new-2.3.6/tests/integration/test_selve_hardware.py +206 -0
- python_selve_new-2.3.6/tests/integration/test_selve_integration.py +141 -0
- python_selve_new-2.3.6/tests/test_import.py +43 -0
- python_selve_new-2.3.6/tests/test_replacement.py +168 -0
- python_selve_new-2.3.6/tests/unit/mock_utils.py +10 -0
- python_selve_new-2.3.6/tests/unit/test_command_coverage.py +139 -0
- python_selve_new-2.3.6/tests/unit/test_commands.py +87 -0
- python_selve_new-2.3.6/tests/unit/test_device.py +50 -0
- python_selve_new-2.3.6/tests/unit/test_device_classes_coverage.py +118 -0
- python_selve_new-2.3.6/tests/unit/test_device_commands_extended.py +190 -0
- python_selve_new-2.3.6/tests/unit/test_gateway_configuration_issues.py +335 -0
- python_selve_new-2.3.6/tests/unit/test_gateway_error_handling_fixed.py +270 -0
- python_selve_new-2.3.6/tests/unit/test_group.py +30 -0
- python_selve_new-2.3.6/tests/unit/test_group_commands.py +108 -0
- python_selve_new-2.3.6/tests/unit/test_missing_components.py +213 -0
- python_selve_new-2.3.6/tests/unit/test_mock_commands.py +235 -0
- python_selve_new-2.3.6/tests/unit/test_mock_devices_and_groups.py +385 -0
- python_selve_new-2.3.6/tests/unit/test_mock_sensors_and_senders.py +317 -0
- python_selve_new-2.3.6/tests/unit/test_param_commands_extended.py +122 -0
- python_selve_new-2.3.6/tests/unit/test_port_discovery.py +228 -0
- python_selve_new-2.3.6/tests/unit/test_selve_advanced_coverage.py +284 -0
- python_selve_new-2.3.6/tests/unit/test_selve_core_coverage.py +214 -0
- python_selve_new-2.3.6/tests/unit/test_selve_edge_cases.py +265 -0
- python_selve_new-2.3.6/tests/unit/test_selve_gateway.py +279 -0
- python_selve_new-2.3.6/tests/unit/test_selve_init_comprehensive.py +423 -0
- python_selve_new-2.3.6/tests/unit/test_selve_init_response_coverage.py +147 -0
- python_selve_new-2.3.6/tests/unit/test_selve_init_simple.py +179 -0
- python_selve_new-2.3.6/tests/unit/test_selve_main_class_extensive.py +219 -0
- python_selve_new-2.3.6/tests/unit/test_sender_commands_extended.py +141 -0
- python_selve_new-2.3.6/tests/unit/test_sensim_commands_extended.py +201 -0
- python_selve_new-2.3.6/tests/unit/test_sensor_commands_extended.py +151 -0
- python_selve_new-2.3.6/tests/unit/test_service_command_errors.py +241 -0
- python_selve_new-2.3.6/tests/unit/test_service_commands.py +88 -0
- python_selve_new-2.3.6/tests/unit/test_util.py +55 -0
- python_selve_new-2.3.6/tests/unit/test_utility_coverage.py +298 -0
- python_selve_new-2.3.3/.github/workflows/python-publish.yml +0 -41
- python_selve_new-2.3.3/python_selve_new.egg-info/SOURCES.txt +0 -44
- python_selve_new-2.3.3/test.py +0 -46
- {python_selve_new-2.3.3 → python_selve_new-2.3.6}/.github/FUNDING.yml +0 -0
- {python_selve_new-2.3.3 → python_selve_new-2.3.6}/.gitignore +0 -0
- {python_selve_new-2.3.3 → python_selve_new-2.3.6}/.idea/.gitignore +0 -0
- {python_selve_new-2.3.3 → python_selve_new-2.3.6}/.idea/inspectionProfiles/profiles_settings.xml +0 -0
- {python_selve_new-2.3.3 → python_selve_new-2.3.6}/.idea/misc.xml +0 -0
- {python_selve_new-2.3.3 → python_selve_new-2.3.6}/.idea/modules.xml +0 -0
- {python_selve_new-2.3.3 → python_selve_new-2.3.6}/.idea/python-selve-new.iml +0 -0
- {python_selve_new-2.3.3 → python_selve_new-2.3.6}/.idea/vcs.xml +0 -0
- {python_selve_new-2.3.3 → python_selve_new-2.3.6}/.vscode/settings.json +0 -0
- {python_selve_new-2.3.3 → python_selve_new-2.3.6}/LICENSE +0 -0
- {python_selve_new-2.3.3 → python_selve_new-2.3.6}/README.md +0 -0
- {python_selve_new-2.3.3 → python_selve_new-2.3.6}/package.sh +0 -0
- {python_selve_new-2.3.3 → python_selve_new-2.3.6}/python_selve_new.egg-info/dependency_links.txt +0 -0
- {python_selve_new-2.3.3 → python_selve_new-2.3.6}/python_selve_new.egg-info/entry_points.txt +0 -0
- {python_selve_new-2.3.3 → python_selve_new-2.3.6}/python_selve_new.egg-info/requires.txt +0 -0
- {python_selve_new-2.3.3 → python_selve_new-2.3.6}/python_selve_new.egg-info/top_level.txt +0 -0
- {python_selve_new-2.3.3 → python_selve_new-2.3.6}/selve/commands/__init__.py +0 -0
- {python_selve_new-2.3.3 → python_selve_new-2.3.6}/selve/commands/command.py +0 -0
- {python_selve_new-2.3.3 → python_selve_new-2.3.6}/selve/commands/device.py +0 -0
- {python_selve_new-2.3.3 → python_selve_new-2.3.6}/selve/commands/event.py +0 -0
- {python_selve_new-2.3.3 → python_selve_new-2.3.6}/selve/commands/iveo.py +0 -0
- {python_selve_new-2.3.3 → python_selve_new-2.3.6}/selve/commands/param.py +0 -0
- {python_selve_new-2.3.3 → python_selve_new-2.3.6}/selve/commands/senSim.py +0 -0
- {python_selve_new-2.3.3 → python_selve_new-2.3.6}/selve/commands/sender.py +0 -0
- {python_selve_new-2.3.3 → python_selve_new-2.3.6}/selve/commands/sensor.py +0 -0
- {python_selve_new-2.3.3 → python_selve_new-2.3.6}/selve/commands/service.py +0 -0
- {python_selve_new-2.3.3 → python_selve_new-2.3.6}/selve/device.py +0 -0
- {python_selve_new-2.3.3 → python_selve_new-2.3.6}/selve/gateway.py +0 -0
- {python_selve_new-2.3.3 → python_selve_new-2.3.6}/selve/group.py +0 -0
- {python_selve_new-2.3.3 → python_selve_new-2.3.6}/selve/iveo.py +0 -0
- {python_selve_new-2.3.3 → python_selve_new-2.3.6}/selve/senSim.py +0 -0
- {python_selve_new-2.3.3 → python_selve_new-2.3.6}/selve/sender.py +0 -0
- {python_selve_new-2.3.3 → python_selve_new-2.3.6}/selve/sensor.py +0 -0
- {python_selve_new-2.3.3 → python_selve_new-2.3.6}/selve/util/__init__.py +0 -0
- {python_selve_new-2.3.3 → 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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
19
|
+
Requires-Python: >=3.9
|
|
25
20
|
Description-Content-Type: text/markdown
|
|
26
21
|
License-File: LICENSE
|
|
27
22
|
Requires-Dist: requests
|