python-selve-new 2.5.3__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.
Files changed (109) hide show
  1. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/PKG-INFO +1 -1
  2. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/pyproject.toml +4 -1
  3. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/python_selve_new.egg-info/PKG-INFO +1 -1
  4. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/selve/__init__.py +44 -1
  5. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/selve/_version.py +3 -3
  6. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/.github/FUNDING.yml +0 -0
  7. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/.github/architect.chatmode.md +0 -0
  8. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/.github/ask.chatmode.md +0 -0
  9. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/.github/code.chatmode.md +0 -0
  10. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/.github/debug.chatmode.md +0 -0
  11. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/.github/workflows/python-publish.yml +0 -0
  12. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/.github/workflows/tests.yml +0 -0
  13. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/.gitignore +0 -0
  14. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/.idea/.gitignore +0 -0
  15. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/.idea/inspectionProfiles/profiles_settings.xml +0 -0
  16. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/.idea/misc.xml +0 -0
  17. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/.idea/modules.xml +0 -0
  18. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/.idea/python-selve-new.iml +0 -0
  19. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/.idea/vcs.xml +0 -0
  20. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/CHANGELOG.md +0 -0
  21. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/LICENSE +0 -0
  22. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/README.md +0 -0
  23. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/coverage_xdist_example.txt +0 -0
  24. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/debug_response.py +0 -0
  25. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/debug_test.bat +0 -0
  26. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/direct_hardware_test.bat +0 -0
  27. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/direct_hardware_test.py +0 -0
  28. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/generate_coverage.bat +0 -0
  29. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/package.sh +0 -0
  30. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/python_selve_new.egg-info/SOURCES.txt +0 -0
  31. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/python_selve_new.egg-info/dependency_links.txt +0 -0
  32. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/python_selve_new.egg-info/requires.txt +0 -0
  33. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/python_selve_new.egg-info/top_level.txt +0 -0
  34. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/release.py +0 -0
  35. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/run_all_tests.bat +0 -0
  36. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/run_hardware_tests.bat +0 -0
  37. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/run_integration_tests.bat +0 -0
  38. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/run_mock_tests.bat +0 -0
  39. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/run_single_test.bat +0 -0
  40. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/run_tests.bat +0 -0
  41. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/selve/commands/__init__.py +0 -0
  42. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/selve/commands/command.py +0 -0
  43. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/selve/commands/device.py +0 -0
  44. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/selve/commands/event.py +0 -0
  45. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/selve/commands/firmware.py +0 -0
  46. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/selve/commands/group.py +0 -0
  47. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/selve/commands/iveo.py +0 -0
  48. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/selve/commands/param.py +0 -0
  49. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/selve/commands/senSim.py +0 -0
  50. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/selve/commands/sender.py +0 -0
  51. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/selve/commands/sensor.py +0 -0
  52. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/selve/commands/service.py +0 -0
  53. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/selve/device.py +0 -0
  54. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/selve/gateway.py +0 -0
  55. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/selve/group.py +0 -0
  56. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/selve/iveo.py +0 -0
  57. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/selve/senSim.py +0 -0
  58. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/selve/sender.py +0 -0
  59. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/selve/sensor.py +0 -0
  60. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/selve/util/__init__.py +0 -0
  61. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/selve/util/errors.py +0 -0
  62. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/selve/util/protocol.py +0 -0
  63. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/selve/util/serial_transport.py +0 -0
  64. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/setup.cfg +0 -0
  65. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/setup.py +0 -0
  66. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/setup_and_test.bat +0 -0
  67. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/tests/__init__.py +0 -0
  68. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/tests/conftest.py +0 -0
  69. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/tests/integration/README.md +0 -0
  70. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/tests/integration/__init__.py +0 -0
  71. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/tests/integration/conftest.py +0 -0
  72. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/tests/integration/test_device_integration.py +0 -0
  73. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/tests/integration/test_selve_gateway_integration.py +0 -0
  74. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/tests/integration/test_selve_hardware.py +0 -0
  75. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/tests/integration/test_selve_integration.py +0 -0
  76. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/tests/test_import.py +0 -0
  77. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/tests/test_replacement.py +0 -0
  78. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/tests/unit/__init__.py +0 -0
  79. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/tests/unit/mock_utils.py +0 -0
  80. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/tests/unit/test_command_coverage.py +0 -0
  81. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/tests/unit/test_commands.py +0 -0
  82. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/tests/unit/test_device.py +0 -0
  83. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/tests/unit/test_device_classes_coverage.py +0 -0
  84. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/tests/unit/test_device_commands_extended.py +0 -0
  85. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/tests/unit/test_gateway_configuration_issues.py +0 -0
  86. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/tests/unit/test_gateway_error_handling_fixed.py +0 -0
  87. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/tests/unit/test_group.py +0 -0
  88. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/tests/unit/test_group_commands.py +0 -0
  89. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/tests/unit/test_missing_components.py +0 -0
  90. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/tests/unit/test_mock_commands.py +0 -0
  91. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/tests/unit/test_mock_devices_and_groups.py +0 -0
  92. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/tests/unit/test_mock_sensors_and_senders.py +0 -0
  93. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/tests/unit/test_param_commands_extended.py +0 -0
  94. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/tests/unit/test_port_discovery.py +0 -0
  95. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/tests/unit/test_selve_advanced_coverage.py +0 -0
  96. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/tests/unit/test_selve_core_coverage.py +0 -0
  97. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/tests/unit/test_selve_edge_cases.py +0 -0
  98. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/tests/unit/test_selve_gateway.py +0 -0
  99. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/tests/unit/test_selve_init_comprehensive.py +0 -0
  100. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/tests/unit/test_selve_init_response_coverage.py +0 -0
  101. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/tests/unit/test_selve_init_simple.py +0 -0
  102. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/tests/unit/test_selve_main_class_extensive.py +0 -0
  103. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/tests/unit/test_sender_commands_extended.py +0 -0
  104. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/tests/unit/test_sensim_commands_extended.py +0 -0
  105. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/tests/unit/test_sensor_commands_extended.py +0 -0
  106. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/tests/unit/test_service_command_errors.py +0 -0
  107. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/tests/unit/test_service_commands.py +0 -0
  108. {python_selve_new-2.5.3 → python_selve_new-2.5.4}/tests/unit/test_util.py +0 -0
  109. {python_selve_new-2.5.3 → 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
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
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
@@ -51,7 +51,7 @@ from selve.sensor import SelveSensor
51
51
  from selve.util import *
52
52
  from selve.util import Command
53
53
  from selve.util.errors import *
54
- from selve.util.protocol import ParameterType
54
+ from selve.util.protocol import ParameterType, SelveTypes, MovementState
55
55
  from selve.util.serial_transport import SerialTransport
56
56
 
57
57
 
@@ -106,6 +106,9 @@ class Selve:
106
106
  self._pending_futures = deque()
107
107
  self._event_queue = None
108
108
 
109
+ # Active movement polling tasks keyed by device id
110
+ self._movement_tasks: dict = {}
111
+
109
112
  #Options
110
113
  self.reversedStopPosition = 0
111
114
 
@@ -1010,6 +1013,8 @@ class Selve:
1010
1013
  device.device_type = response.deviceType
1011
1014
 
1012
1015
  self.addOrUpdateDevice(device, SelveTypes.DEVICE)
1016
+ if device.state == MovementState.STOPPED_OFF:
1017
+ self._stop_movement_polling(device.id)
1013
1018
 
1014
1019
  if isinstance(response, SensorEventResponse):
1015
1020
  if self.is_id_registered(response.id, SelveTypes.SENSOR):
@@ -1387,6 +1392,8 @@ class Selve:
1387
1392
  dev.freezingAlarm = response.freezingAlarm if response.freezingAlarm else False
1388
1393
  dev.dayMode = response.dayMode if response.dayMode else False
1389
1394
  self.addOrUpdateDevice(dev, SelveTypes.DEVICE)
1395
+ if dev is not None and dev.state == MovementState.STOPPED_OFF:
1396
+ self._stop_movement_polling(id)
1390
1397
 
1391
1398
  def setDeviceValue(self, id: int, value: int, type: SelveTypes):
1392
1399
  dev = self.getDevice(id, type)
@@ -1410,12 +1417,41 @@ class Selve:
1410
1417
  dev.state = state
1411
1418
  self.addOrUpdateDevice(dev, type)
1412
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
+
1413
1448
  async def moveDeviceUp(self, device: SelveDevice | IveoDevice, type=DeviceCommandType.MANUAL):
1414
1449
  if device.communicationType is CommunicationType.COMMEO:
1415
1450
  await self.executeCommand(CommandDriveUp(device.id, type))
1416
1451
  device.state = MovementState.UP_ON
1417
1452
  self.addOrUpdateDevice(device, SelveTypes.DEVICE)
1418
1453
  await self.updateCommeoDeviceValuesAsync(device.id)
1454
+ self._start_movement_polling(device.id)
1419
1455
  else:
1420
1456
  self.setDeviceState(device.id, MovementState.UP_ON, SelveTypes.IVEO)
1421
1457
  await self.executeCommand(IveoManual(device.id, DriveCommandIveo.UP))
@@ -1429,6 +1465,7 @@ class Selve:
1429
1465
  device.state = MovementState.DOWN_ON
1430
1466
  self.addOrUpdateDevice(device, SelveTypes.DEVICE)
1431
1467
  await self.updateCommeoDeviceValuesAsync(device.id)
1468
+ self._start_movement_polling(device.id)
1432
1469
  else:
1433
1470
  self.setDeviceState(device.id, MovementState.DOWN_ON, SelveTypes.IVEO)
1434
1471
  await self.executeCommand(IveoManual(device.id, DriveCommandIveo.DOWN))
@@ -1440,6 +1477,7 @@ class Selve:
1440
1477
  if device.communicationType is CommunicationType.COMMEO:
1441
1478
  await self.executeCommand(CommandDrivePos1(device.id, type))
1442
1479
  await self.updateCommeoDeviceValuesAsync(device.id)
1480
+ self._start_movement_polling(device.id)
1443
1481
  else:
1444
1482
  self.setDeviceState(device.id, MovementState.UP_ON, SelveTypes.IVEO)
1445
1483
  await self.executeCommand(IveoManual(device.id, DriveCommandIveo.POS1))
@@ -1451,6 +1489,7 @@ class Selve:
1451
1489
  if device.communicationType is CommunicationType.COMMEO:
1452
1490
  await self.executeCommand(CommandDrivePos2(device.id, type))
1453
1491
  await self.updateCommeoDeviceValuesAsync(device.id)
1492
+ self._start_movement_polling(device.id)
1454
1493
  else:
1455
1494
  self.setDeviceState(device.id, MovementState.DOWN_ON, SelveTypes.IVEO)
1456
1495
  await self.executeCommand(IveoManual(device.id, DriveCommandIveo.POS2))
@@ -1461,17 +1500,21 @@ class Selve:
1461
1500
  async def moveDevicePos(self, device: SelveDevice, pos: int = 0, type=DeviceCommandType.MANUAL):
1462
1501
  await self.executeCommand(CommandDrivePos(device.id, type, param=Util.percentageToValue(pos)))
1463
1502
  await self.updateCommeoDeviceValuesAsync(device.id)
1503
+ self._start_movement_polling(device.id)
1464
1504
 
1465
1505
  async def moveDeviceStepUp(self, device: SelveDevice, degrees: int = 0, type=DeviceCommandType.MANUAL):
1466
1506
  await self.executeCommand(CommandDriveStepUp(device.id, type, param=Util.degreesToValue(degrees)))
1467
1507
  await self.updateCommeoDeviceValuesAsync(device.id)
1508
+ self._start_movement_polling(device.id)
1468
1509
 
1469
1510
  async def moveDeviceStepDown(self, device: SelveDevice, degrees: int = 0, type=DeviceCommandType.MANUAL):
1470
1511
  await self.executeCommand(CommandDriveStepDown(device.id, type, param=Util.degreesToValue(degrees)))
1471
1512
  await self.updateCommeoDeviceValuesAsync(device.id)
1513
+ self._start_movement_polling(device.id)
1472
1514
 
1473
1515
  async def stopDevice(self, device: SelveDevice | IveoDevice, type=DeviceCommandType.MANUAL):
1474
1516
  if device.communicationType is CommunicationType.COMMEO:
1517
+ self._stop_movement_polling(device.id)
1475
1518
  await self.executeCommand(CommandStop(device.id, type))
1476
1519
  await self.updateCommeoDeviceValuesAsync(device.id)
1477
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.3'
22
- __version_tuple__ = version_tuple = (2, 5, 3)
21
+ __version__ = version = '2.5.4'
22
+ __version_tuple__ = version_tuple = (2, 5, 4)
23
23
 
24
- __commit_id__ = commit_id = 'ge708968d7'
24
+ __commit_id__ = commit_id = 'g5d6793713'