python-selve-new 2.5.2__tar.gz → 2.5.4__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.5.2 → python_selve_new-2.5.4}/PKG-INFO +1 -1
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/pyproject.toml +4 -1
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/python_selve_new.egg-info/PKG-INFO +1 -1
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/selve/__init__.py +94 -26
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/selve/_version.py +3 -3
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/tests/integration/test_selve_gateway_integration.py +1 -1
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/tests/unit/test_selve_edge_cases.py +3 -2
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/tests/unit/test_selve_init_comprehensive.py +2 -1
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/.github/FUNDING.yml +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/.github/architect.chatmode.md +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/.github/ask.chatmode.md +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/.github/code.chatmode.md +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/.github/debug.chatmode.md +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/.github/workflows/python-publish.yml +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/.github/workflows/tests.yml +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/.gitignore +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/.idea/.gitignore +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/.idea/inspectionProfiles/profiles_settings.xml +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/.idea/misc.xml +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/.idea/modules.xml +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/.idea/python-selve-new.iml +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/.idea/vcs.xml +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/CHANGELOG.md +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/LICENSE +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/README.md +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/coverage_xdist_example.txt +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/debug_response.py +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/debug_test.bat +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/direct_hardware_test.bat +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/direct_hardware_test.py +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/generate_coverage.bat +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/package.sh +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/python_selve_new.egg-info/SOURCES.txt +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/python_selve_new.egg-info/dependency_links.txt +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/python_selve_new.egg-info/requires.txt +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/python_selve_new.egg-info/top_level.txt +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/release.py +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/run_all_tests.bat +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/run_hardware_tests.bat +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/run_integration_tests.bat +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/run_mock_tests.bat +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/run_single_test.bat +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/run_tests.bat +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/selve/commands/__init__.py +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/selve/commands/command.py +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/selve/commands/device.py +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/selve/commands/event.py +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/selve/commands/firmware.py +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/selve/commands/group.py +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/selve/commands/iveo.py +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/selve/commands/param.py +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/selve/commands/senSim.py +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/selve/commands/sender.py +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/selve/commands/sensor.py +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/selve/commands/service.py +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/selve/device.py +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/selve/gateway.py +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/selve/group.py +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/selve/iveo.py +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/selve/senSim.py +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/selve/sender.py +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/selve/sensor.py +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/selve/util/__init__.py +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/selve/util/errors.py +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/selve/util/protocol.py +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/selve/util/serial_transport.py +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/setup.cfg +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/setup.py +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/setup_and_test.bat +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/tests/__init__.py +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/tests/conftest.py +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/tests/integration/README.md +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/tests/integration/__init__.py +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/tests/integration/conftest.py +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/tests/integration/test_device_integration.py +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/tests/integration/test_selve_hardware.py +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/tests/integration/test_selve_integration.py +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/tests/test_import.py +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/tests/test_replacement.py +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/tests/unit/__init__.py +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/tests/unit/mock_utils.py +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/tests/unit/test_command_coverage.py +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/tests/unit/test_commands.py +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/tests/unit/test_device.py +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/tests/unit/test_device_classes_coverage.py +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/tests/unit/test_device_commands_extended.py +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/tests/unit/test_gateway_configuration_issues.py +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/tests/unit/test_gateway_error_handling_fixed.py +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/tests/unit/test_group.py +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/tests/unit/test_group_commands.py +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/tests/unit/test_missing_components.py +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/tests/unit/test_mock_commands.py +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/tests/unit/test_mock_devices_and_groups.py +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/tests/unit/test_mock_sensors_and_senders.py +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/tests/unit/test_param_commands_extended.py +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/tests/unit/test_port_discovery.py +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/tests/unit/test_selve_advanced_coverage.py +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/tests/unit/test_selve_core_coverage.py +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/tests/unit/test_selve_gateway.py +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/tests/unit/test_selve_init_response_coverage.py +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/tests/unit/test_selve_init_simple.py +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/tests/unit/test_selve_main_class_extensive.py +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/tests/unit/test_sender_commands_extended.py +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/tests/unit/test_sensim_commands_extended.py +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/tests/unit/test_sensor_commands_extended.py +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/tests/unit/test_service_command_errors.py +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/tests/unit/test_service_commands.py +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/tests/unit/test_util.py +0 -0
- {python_selve_new-2.5.2 → python_selve_new-2.5.4}/tests/unit/test_utility_coverage.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-selve-new
|
|
3
|
-
Version: 2.5.
|
|
3
|
+
Version: 2.5.4
|
|
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
|
|
@@ -59,4 +59,7 @@ markers = [
|
|
|
59
59
|
"unit: marks tests as unit tests",
|
|
60
60
|
]
|
|
61
61
|
asyncio_mode = "auto"
|
|
62
|
-
asyncio_default_fixture_loop_scope = "function"
|
|
62
|
+
asyncio_default_fixture_loop_scope = "function"
|
|
63
|
+
filterwarnings = [
|
|
64
|
+
"ignore:coroutine 'Selve._movement_poll_loop' was never awaited:RuntimeWarning",
|
|
65
|
+
]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-selve-new
|
|
3
|
-
Version: 2.5.
|
|
3
|
+
Version: 2.5.4
|
|
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,6 +12,7 @@ except ImportError:
|
|
|
12
12
|
__version__ = "unknown"
|
|
13
13
|
|
|
14
14
|
import asyncio
|
|
15
|
+
import logging
|
|
15
16
|
import time
|
|
16
17
|
from collections import deque
|
|
17
18
|
from itertools import chain
|
|
@@ -50,7 +51,7 @@ from selve.sensor import SelveSensor
|
|
|
50
51
|
from selve.util import *
|
|
51
52
|
from selve.util import Command
|
|
52
53
|
from selve.util.errors import *
|
|
53
|
-
from selve.util.protocol import ParameterType
|
|
54
|
+
from selve.util.protocol import ParameterType, SelveTypes, MovementState
|
|
54
55
|
from selve.util.serial_transport import SerialTransport
|
|
55
56
|
|
|
56
57
|
|
|
@@ -105,11 +106,14 @@ class Selve:
|
|
|
105
106
|
self._pending_futures = deque()
|
|
106
107
|
self._event_queue = None
|
|
107
108
|
|
|
109
|
+
# Active movement polling tasks keyed by device id
|
|
110
|
+
self._movement_tasks: dict = {}
|
|
111
|
+
|
|
108
112
|
#Options
|
|
109
113
|
self.reversedStopPosition = 0
|
|
110
114
|
|
|
111
115
|
#Logger
|
|
112
|
-
self._LOGGER = logger
|
|
116
|
+
self._LOGGER: logging.Logger = logger or logging.getLogger(__name__)
|
|
113
117
|
|
|
114
118
|
|
|
115
119
|
# Legacy worker was removed in favor of dedicated TX/RX tasks.
|
|
@@ -211,16 +215,19 @@ class Selve:
|
|
|
211
215
|
await asyncio.sleep(5)
|
|
212
216
|
self._LOGGER.debug("(Selve Worker): " + "Recovering")
|
|
213
217
|
|
|
218
|
+
# Tear down the broken transport, then rebuild it directly without calling
|
|
219
|
+
# _probe_port / stopWorker, which would kill the running TX/dispatch tasks.
|
|
214
220
|
await self._teardown_transport()
|
|
215
221
|
|
|
216
222
|
if self._port is not None:
|
|
217
223
|
try:
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
224
|
+
await self._build_transport(self._port)
|
|
225
|
+
if self.rxQ is not None and self._transport is not None:
|
|
226
|
+
await self._transport.start_reader(self.rxQ)
|
|
227
|
+
self._LOGGER.info("(Selve Worker): Recovery successful on " + str(self._port))
|
|
228
|
+
return
|
|
222
229
|
except (OSError, IOError) as e:
|
|
223
|
-
self._LOGGER.debug("(Selve Worker): " + "Configured port not valid, maybe it has changed, trying other ports...")
|
|
230
|
+
self._LOGGER.debug("(Selve Worker): " + "Configured port not valid, maybe it has changed, trying other ports... " + str(e))
|
|
224
231
|
except Exception as e:
|
|
225
232
|
self._LOGGER.error("(Selve Worker): " + "Unknown exception: " + str(e))
|
|
226
233
|
|
|
@@ -235,10 +242,12 @@ class Selve:
|
|
|
235
242
|
|
|
236
243
|
for p in available_ports:
|
|
237
244
|
try:
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
245
|
+
await self._build_transport(p.device)
|
|
246
|
+
self._port = p.device
|
|
247
|
+
if self.rxQ is not None and self._transport is not None:
|
|
248
|
+
await self._transport.start_reader(self.rxQ)
|
|
249
|
+
self._LOGGER.info("(Selve Worker): Recovery successful on " + str(p.device))
|
|
250
|
+
return
|
|
242
251
|
except Exception as e:
|
|
243
252
|
self._LOGGER.error("(Selve Worker): " + "Error at com port: " + str(e))
|
|
244
253
|
else:
|
|
@@ -1004,6 +1013,8 @@ class Selve:
|
|
|
1004
1013
|
device.device_type = response.deviceType
|
|
1005
1014
|
|
|
1006
1015
|
self.addOrUpdateDevice(device, SelveTypes.DEVICE)
|
|
1016
|
+
if device.state == MovementState.STOPPED_OFF:
|
|
1017
|
+
self._stop_movement_polling(device.id)
|
|
1007
1018
|
|
|
1008
1019
|
if isinstance(response, SensorEventResponse):
|
|
1009
1020
|
if self.is_id_registered(response.id, SelveTypes.SENSOR):
|
|
@@ -1057,20 +1068,39 @@ class Selve:
|
|
|
1057
1068
|
callback(response)
|
|
1058
1069
|
|
|
1059
1070
|
|
|
1060
|
-
def _handleCommandResult(self, response
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1071
|
+
def _handleCommandResult(self, response):
|
|
1072
|
+
if isinstance(response, IveoResultResponse):
|
|
1073
|
+
for id in response.executedIds:
|
|
1074
|
+
dev = self.getDevice(id, SelveTypes.IVEO)
|
|
1075
|
+
if dev is None:
|
|
1076
|
+
continue
|
|
1077
|
+
if response.command is DriveCommandIveo.DOWN:
|
|
1078
|
+
dev.state = MovementState.DOWN_ON
|
|
1079
|
+
elif response.command is DriveCommandIveo.UP:
|
|
1080
|
+
dev.state = MovementState.UP_ON
|
|
1081
|
+
elif response.command is DriveCommandIveo.STOP:
|
|
1082
|
+
dev.state = MovementState.STOPPED_OFF
|
|
1083
|
+
self.addOrUpdateDevice(dev, SelveTypes.IVEO)
|
|
1084
|
+
|
|
1085
|
+
elif isinstance(response, CommandResultResponse):
|
|
1086
|
+
for id in response.successIds:
|
|
1087
|
+
dev = self.getDevice(id, SelveTypes.DEVICE)
|
|
1088
|
+
if dev is None:
|
|
1089
|
+
continue
|
|
1090
|
+
dev.unreachable = False
|
|
1091
|
+
if response.command is DriveCommandCommeo.DRIVEDOWN:
|
|
1092
|
+
dev.state = MovementState.DOWN_ON
|
|
1093
|
+
elif response.command is DriveCommandCommeo.DRIVEUP:
|
|
1094
|
+
dev.state = MovementState.UP_ON
|
|
1095
|
+
elif response.command is DriveCommandCommeo.STOP:
|
|
1096
|
+
dev.state = MovementState.STOPPED_OFF
|
|
1097
|
+
self.addOrUpdateDevice(dev, SelveTypes.DEVICE)
|
|
1098
|
+
for id in response.failedIds:
|
|
1099
|
+
dev = self.getDevice(id, SelveTypes.DEVICE)
|
|
1100
|
+
if dev is None:
|
|
1101
|
+
continue
|
|
1102
|
+
dev.unreachable = True
|
|
1103
|
+
self.addOrUpdateDevice(dev, SelveTypes.DEVICE)
|
|
1074
1104
|
|
|
1075
1105
|
for callback in self._callbacks:
|
|
1076
1106
|
callback()
|
|
@@ -1350,7 +1380,7 @@ class Selve:
|
|
|
1350
1380
|
else:
|
|
1351
1381
|
dev.targetValue = 100 - response.targetValue if response.targetValue else 0
|
|
1352
1382
|
|
|
1353
|
-
dev.unreachable = response.unreachable
|
|
1383
|
+
dev.unreachable = response.unreachable
|
|
1354
1384
|
dev.overload = response.overload if response.overload else False
|
|
1355
1385
|
dev.obstructed = response.obstructed if response.obstructed else False
|
|
1356
1386
|
dev.alarm = response.alarm if response.alarm else False
|
|
@@ -1362,6 +1392,8 @@ class Selve:
|
|
|
1362
1392
|
dev.freezingAlarm = response.freezingAlarm if response.freezingAlarm else False
|
|
1363
1393
|
dev.dayMode = response.dayMode if response.dayMode else False
|
|
1364
1394
|
self.addOrUpdateDevice(dev, SelveTypes.DEVICE)
|
|
1395
|
+
if dev is not None and dev.state == MovementState.STOPPED_OFF:
|
|
1396
|
+
self._stop_movement_polling(id)
|
|
1365
1397
|
|
|
1366
1398
|
def setDeviceValue(self, id: int, value: int, type: SelveTypes):
|
|
1367
1399
|
dev = self.getDevice(id, type)
|
|
@@ -1385,12 +1417,41 @@ class Selve:
|
|
|
1385
1417
|
dev.state = state
|
|
1386
1418
|
self.addOrUpdateDevice(dev, type)
|
|
1387
1419
|
|
|
1420
|
+
def _start_movement_polling(self, device_id: int) -> None:
|
|
1421
|
+
"""Start a background task that polls device values every 0.5 s during movement."""
|
|
1422
|
+
self._stop_movement_polling(device_id)
|
|
1423
|
+
try:
|
|
1424
|
+
asyncio.get_running_loop()
|
|
1425
|
+
except RuntimeError:
|
|
1426
|
+
return # no running event loop (unit tests, etc.)
|
|
1427
|
+
task = asyncio.create_task(self._movement_poll_loop(device_id))
|
|
1428
|
+
self._movement_tasks[device_id] = task
|
|
1429
|
+
|
|
1430
|
+
def _stop_movement_polling(self, device_id: int) -> None:
|
|
1431
|
+
"""Cancel movement polling task for a device if one is active."""
|
|
1432
|
+
task = self._movement_tasks.pop(device_id, None)
|
|
1433
|
+
if task and not task.done():
|
|
1434
|
+
task.cancel()
|
|
1435
|
+
|
|
1436
|
+
async def _movement_poll_loop(self, device_id: int, interval: float = 0.5, timeout: float = 60.0) -> None:
|
|
1437
|
+
"""Poll DeviceGetValues every *interval* seconds until movement stops or timeout."""
|
|
1438
|
+
elapsed = 0.0
|
|
1439
|
+
while not self._stopThread.is_set() and elapsed < timeout:
|
|
1440
|
+
await asyncio.sleep(interval)
|
|
1441
|
+
elapsed += interval
|
|
1442
|
+
dev = self.getDevice(device_id, SelveTypes.DEVICE)
|
|
1443
|
+
if dev is None or dev.state == MovementState.STOPPED_OFF:
|
|
1444
|
+
break
|
|
1445
|
+
await self.updateCommeoDeviceValuesAsync(device_id)
|
|
1446
|
+
self._movement_tasks.pop(device_id, None)
|
|
1447
|
+
|
|
1388
1448
|
async def moveDeviceUp(self, device: SelveDevice | IveoDevice, type=DeviceCommandType.MANUAL):
|
|
1389
1449
|
if device.communicationType is CommunicationType.COMMEO:
|
|
1390
1450
|
await self.executeCommand(CommandDriveUp(device.id, type))
|
|
1391
1451
|
device.state = MovementState.UP_ON
|
|
1392
1452
|
self.addOrUpdateDevice(device, SelveTypes.DEVICE)
|
|
1393
1453
|
await self.updateCommeoDeviceValuesAsync(device.id)
|
|
1454
|
+
self._start_movement_polling(device.id)
|
|
1394
1455
|
else:
|
|
1395
1456
|
self.setDeviceState(device.id, MovementState.UP_ON, SelveTypes.IVEO)
|
|
1396
1457
|
await self.executeCommand(IveoManual(device.id, DriveCommandIveo.UP))
|
|
@@ -1404,6 +1465,7 @@ class Selve:
|
|
|
1404
1465
|
device.state = MovementState.DOWN_ON
|
|
1405
1466
|
self.addOrUpdateDevice(device, SelveTypes.DEVICE)
|
|
1406
1467
|
await self.updateCommeoDeviceValuesAsync(device.id)
|
|
1468
|
+
self._start_movement_polling(device.id)
|
|
1407
1469
|
else:
|
|
1408
1470
|
self.setDeviceState(device.id, MovementState.DOWN_ON, SelveTypes.IVEO)
|
|
1409
1471
|
await self.executeCommand(IveoManual(device.id, DriveCommandIveo.DOWN))
|
|
@@ -1415,6 +1477,7 @@ class Selve:
|
|
|
1415
1477
|
if device.communicationType is CommunicationType.COMMEO:
|
|
1416
1478
|
await self.executeCommand(CommandDrivePos1(device.id, type))
|
|
1417
1479
|
await self.updateCommeoDeviceValuesAsync(device.id)
|
|
1480
|
+
self._start_movement_polling(device.id)
|
|
1418
1481
|
else:
|
|
1419
1482
|
self.setDeviceState(device.id, MovementState.UP_ON, SelveTypes.IVEO)
|
|
1420
1483
|
await self.executeCommand(IveoManual(device.id, DriveCommandIveo.POS1))
|
|
@@ -1426,6 +1489,7 @@ class Selve:
|
|
|
1426
1489
|
if device.communicationType is CommunicationType.COMMEO:
|
|
1427
1490
|
await self.executeCommand(CommandDrivePos2(device.id, type))
|
|
1428
1491
|
await self.updateCommeoDeviceValuesAsync(device.id)
|
|
1492
|
+
self._start_movement_polling(device.id)
|
|
1429
1493
|
else:
|
|
1430
1494
|
self.setDeviceState(device.id, MovementState.DOWN_ON, SelveTypes.IVEO)
|
|
1431
1495
|
await self.executeCommand(IveoManual(device.id, DriveCommandIveo.POS2))
|
|
@@ -1436,17 +1500,21 @@ class Selve:
|
|
|
1436
1500
|
async def moveDevicePos(self, device: SelveDevice, pos: int = 0, type=DeviceCommandType.MANUAL):
|
|
1437
1501
|
await self.executeCommand(CommandDrivePos(device.id, type, param=Util.percentageToValue(pos)))
|
|
1438
1502
|
await self.updateCommeoDeviceValuesAsync(device.id)
|
|
1503
|
+
self._start_movement_polling(device.id)
|
|
1439
1504
|
|
|
1440
1505
|
async def moveDeviceStepUp(self, device: SelveDevice, degrees: int = 0, type=DeviceCommandType.MANUAL):
|
|
1441
1506
|
await self.executeCommand(CommandDriveStepUp(device.id, type, param=Util.degreesToValue(degrees)))
|
|
1442
1507
|
await self.updateCommeoDeviceValuesAsync(device.id)
|
|
1508
|
+
self._start_movement_polling(device.id)
|
|
1443
1509
|
|
|
1444
1510
|
async def moveDeviceStepDown(self, device: SelveDevice, degrees: int = 0, type=DeviceCommandType.MANUAL):
|
|
1445
1511
|
await self.executeCommand(CommandDriveStepDown(device.id, type, param=Util.degreesToValue(degrees)))
|
|
1446
1512
|
await self.updateCommeoDeviceValuesAsync(device.id)
|
|
1513
|
+
self._start_movement_polling(device.id)
|
|
1447
1514
|
|
|
1448
1515
|
async def stopDevice(self, device: SelveDevice | IveoDevice, type=DeviceCommandType.MANUAL):
|
|
1449
1516
|
if device.communicationType is CommunicationType.COMMEO:
|
|
1517
|
+
self._stop_movement_polling(device.id)
|
|
1450
1518
|
await self.executeCommand(CommandStop(device.id, type))
|
|
1451
1519
|
await self.updateCommeoDeviceValuesAsync(device.id)
|
|
1452
1520
|
else:
|
|
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
|
|
|
18
18
|
commit_id: str | None
|
|
19
19
|
__commit_id__: str | None
|
|
20
20
|
|
|
21
|
-
__version__ = version = '2.5.
|
|
22
|
-
__version_tuple__ = version_tuple = (2, 5,
|
|
21
|
+
__version__ = version = '2.5.4'
|
|
22
|
+
__version_tuple__ = version_tuple = (2, 5, 4)
|
|
23
23
|
|
|
24
|
-
__commit_id__ = commit_id = '
|
|
24
|
+
__commit_id__ = commit_id = 'g5d6793713'
|
|
@@ -90,6 +90,6 @@ class TestSelveGatewayIntegration:
|
|
|
90
90
|
await mock_selve_instance.recover()
|
|
91
91
|
|
|
92
92
|
# Verify logger was called (indicating recover ran)
|
|
93
|
-
mock_logger.info.
|
|
93
|
+
mock_logger.info.assert_any_call("(Selve Worker): Recover serial connection")
|
|
94
94
|
mock_logger.debug.assert_any_call("(Selve Worker): Waiting 5 seconds before trying...")
|
|
95
95
|
mock_logger.debug.assert_any_call("(Selve Worker): Recovering")
|
|
@@ -18,8 +18,9 @@ class TestSelveEdgeCases:
|
|
|
18
18
|
def test_init_with_none_logger(self):
|
|
19
19
|
"""Test initialization with None logger."""
|
|
20
20
|
selve = Selve(logger=None)
|
|
21
|
-
# None logger
|
|
22
|
-
|
|
21
|
+
# None logger falls back to a module-level logger, never stays None
|
|
22
|
+
import logging
|
|
23
|
+
assert isinstance(selve._LOGGER, logging.Logger)
|
|
23
24
|
|
|
24
25
|
def test_init_with_invalid_port(self):
|
|
25
26
|
"""Test initialization with invalid port."""
|
{python_selve_new-2.5.2 → python_selve_new-2.5.4}/tests/unit/test_selve_init_comprehensive.py
RENAMED
|
@@ -60,7 +60,8 @@ class TestSelveInit:
|
|
|
60
60
|
selve = Selve()
|
|
61
61
|
|
|
62
62
|
assert selve._port is None
|
|
63
|
-
|
|
63
|
+
import logging
|
|
64
|
+
assert isinstance(selve._LOGGER, logging.Logger)
|
|
64
65
|
assert selve.loop is None
|
|
65
66
|
assert isinstance(selve._callbacks, set)
|
|
66
67
|
assert isinstance(selve._eventCallbacks, set)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_selve_new-2.5.2 → python_selve_new-2.5.4}/.idea/inspectionProfiles/profiles_settings.xml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_selve_new-2.5.2 → python_selve_new-2.5.4}/python_selve_new.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_selve_new-2.5.2 → python_selve_new-2.5.4}/tests/integration/test_device_integration.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_selve_new-2.5.2 → python_selve_new-2.5.4}/tests/integration/test_selve_integration.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_selve_new-2.5.2 → python_selve_new-2.5.4}/tests/unit/test_device_classes_coverage.py
RENAMED
|
File without changes
|
{python_selve_new-2.5.2 → python_selve_new-2.5.4}/tests/unit/test_device_commands_extended.py
RENAMED
|
File without changes
|
{python_selve_new-2.5.2 → python_selve_new-2.5.4}/tests/unit/test_gateway_configuration_issues.py
RENAMED
|
File without changes
|
{python_selve_new-2.5.2 → python_selve_new-2.5.4}/tests/unit/test_gateway_error_handling_fixed.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_selve_new-2.5.2 → python_selve_new-2.5.4}/tests/unit/test_mock_devices_and_groups.py
RENAMED
|
File without changes
|
{python_selve_new-2.5.2 → python_selve_new-2.5.4}/tests/unit/test_mock_sensors_and_senders.py
RENAMED
|
File without changes
|
{python_selve_new-2.5.2 → python_selve_new-2.5.4}/tests/unit/test_param_commands_extended.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_selve_new-2.5.2 → python_selve_new-2.5.4}/tests/unit/test_selve_advanced_coverage.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_selve_new-2.5.2 → python_selve_new-2.5.4}/tests/unit/test_selve_init_response_coverage.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_selve_new-2.5.2 → python_selve_new-2.5.4}/tests/unit/test_selve_main_class_extensive.py
RENAMED
|
File without changes
|
{python_selve_new-2.5.2 → python_selve_new-2.5.4}/tests/unit/test_sender_commands_extended.py
RENAMED
|
File without changes
|
{python_selve_new-2.5.2 → python_selve_new-2.5.4}/tests/unit/test_sensim_commands_extended.py
RENAMED
|
File without changes
|
{python_selve_new-2.5.2 → python_selve_new-2.5.4}/tests/unit/test_sensor_commands_extended.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|