python-selve-new 2.2.14__tar.gz → 2.2.16__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 (46) hide show
  1. {python_selve_new-2.2.14 → python_selve_new-2.2.16}/.github/workflows/python-publish.yml +2 -2
  2. {python_selve_new-2.2.14/python_selve_new.egg-info → python_selve_new-2.2.16}/PKG-INFO +1 -1
  3. {python_selve_new-2.2.14 → python_selve_new-2.2.16/python_selve_new.egg-info}/PKG-INFO +1 -1
  4. {python_selve_new-2.2.14 → python_selve_new-2.2.16}/selve/__init__.py +162 -16
  5. {python_selve_new-2.2.14 → python_selve_new-2.2.16}/setup.py +1 -1
  6. {python_selve_new-2.2.14 → python_selve_new-2.2.16}/test.py +11 -6
  7. {python_selve_new-2.2.14 → python_selve_new-2.2.16}/.github/FUNDING.yml +0 -0
  8. {python_selve_new-2.2.14 → python_selve_new-2.2.16}/.gitignore +0 -0
  9. {python_selve_new-2.2.14 → python_selve_new-2.2.16}/.idea/.gitignore +0 -0
  10. {python_selve_new-2.2.14 → python_selve_new-2.2.16}/.idea/inspectionProfiles/profiles_settings.xml +0 -0
  11. {python_selve_new-2.2.14 → python_selve_new-2.2.16}/.idea/misc.xml +0 -0
  12. {python_selve_new-2.2.14 → python_selve_new-2.2.16}/.idea/modules.xml +0 -0
  13. {python_selve_new-2.2.14 → python_selve_new-2.2.16}/.idea/python-selve-new.iml +0 -0
  14. {python_selve_new-2.2.14 → python_selve_new-2.2.16}/.idea/vcs.xml +0 -0
  15. {python_selve_new-2.2.14 → python_selve_new-2.2.16}/.vscode/settings.json +0 -0
  16. {python_selve_new-2.2.14 → python_selve_new-2.2.16}/LICENSE +0 -0
  17. {python_selve_new-2.2.14 → python_selve_new-2.2.16}/README.md +0 -0
  18. {python_selve_new-2.2.14 → python_selve_new-2.2.16}/package.sh +0 -0
  19. {python_selve_new-2.2.14 → python_selve_new-2.2.16}/pyproject.toml +0 -0
  20. {python_selve_new-2.2.14 → python_selve_new-2.2.16}/python_selve_new.egg-info/SOURCES.txt +0 -0
  21. {python_selve_new-2.2.14 → python_selve_new-2.2.16}/python_selve_new.egg-info/dependency_links.txt +0 -0
  22. {python_selve_new-2.2.14 → python_selve_new-2.2.16}/python_selve_new.egg-info/entry_points.txt +0 -0
  23. {python_selve_new-2.2.14 → python_selve_new-2.2.16}/python_selve_new.egg-info/requires.txt +0 -0
  24. {python_selve_new-2.2.14 → python_selve_new-2.2.16}/python_selve_new.egg-info/top_level.txt +0 -0
  25. {python_selve_new-2.2.14 → python_selve_new-2.2.16}/selve/commands/__init__.py +0 -0
  26. {python_selve_new-2.2.14 → python_selve_new-2.2.16}/selve/commands/command.py +0 -0
  27. {python_selve_new-2.2.14 → python_selve_new-2.2.16}/selve/commands/device.py +0 -0
  28. {python_selve_new-2.2.14 → python_selve_new-2.2.16}/selve/commands/event.py +0 -0
  29. {python_selve_new-2.2.14 → python_selve_new-2.2.16}/selve/commands/group.py +0 -0
  30. {python_selve_new-2.2.14 → python_selve_new-2.2.16}/selve/commands/iveo.py +0 -0
  31. {python_selve_new-2.2.14 → python_selve_new-2.2.16}/selve/commands/param.py +0 -0
  32. {python_selve_new-2.2.14 → python_selve_new-2.2.16}/selve/commands/senSim.py +0 -0
  33. {python_selve_new-2.2.14 → python_selve_new-2.2.16}/selve/commands/sender.py +0 -0
  34. {python_selve_new-2.2.14 → python_selve_new-2.2.16}/selve/commands/sensor.py +0 -0
  35. {python_selve_new-2.2.14 → python_selve_new-2.2.16}/selve/commands/service.py +0 -0
  36. {python_selve_new-2.2.14 → python_selve_new-2.2.16}/selve/device.py +0 -0
  37. {python_selve_new-2.2.14 → python_selve_new-2.2.16}/selve/gateway.py +0 -0
  38. {python_selve_new-2.2.14 → python_selve_new-2.2.16}/selve/group.py +0 -0
  39. {python_selve_new-2.2.14 → python_selve_new-2.2.16}/selve/iveo.py +0 -0
  40. {python_selve_new-2.2.14 → python_selve_new-2.2.16}/selve/senSim.py +0 -0
  41. {python_selve_new-2.2.14 → python_selve_new-2.2.16}/selve/sender.py +0 -0
  42. {python_selve_new-2.2.14 → python_selve_new-2.2.16}/selve/sensor.py +0 -0
  43. {python_selve_new-2.2.14 → python_selve_new-2.2.16}/selve/util/__init__.py +0 -0
  44. {python_selve_new-2.2.14 → python_selve_new-2.2.16}/selve/util/errors.py +0 -0
  45. {python_selve_new-2.2.14 → python_selve_new-2.2.16}/selve/util/protocol.py +0 -0
  46. {python_selve_new-2.2.14 → python_selve_new-2.2.16}/setup.cfg +0 -0
@@ -22,9 +22,9 @@ jobs:
22
22
  runs-on: ubuntu-latest
23
23
 
24
24
  steps:
25
- - uses: actions/checkout@v3
25
+ - uses: actions/checkout@v4
26
26
  - name: Set up Python
27
- uses: actions/setup-python@v3
27
+ uses: actions/setup-python@v4
28
28
  with:
29
29
  python-version: '3.x'
30
30
  - name: Install dependencies
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: python-selve-new
3
- Version: 2.2.14
3
+ Version: 2.2.16
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
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: python-selve-new
3
- Version: 2.2.14
3
+ Version: 2.2.16
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
@@ -42,6 +42,7 @@ class Selve:
42
42
  def __init__(self, port=None, discover=True, develop=False, logger=None):
43
43
  # Gateway state
44
44
  self._callbacks = set()
45
+ self._eventCallbacks = set()
45
46
  self.lastLogEvent = None
46
47
  self.state = None
47
48
 
@@ -74,9 +75,14 @@ class Selve:
74
75
  self._writeLock = asyncio.Lock()
75
76
  self._readLock = asyncio.Lock()
76
77
 
78
+ # Trasmit and Recieve Queue init
77
79
  self.txQ = None
78
80
  self.rxQ = None
79
81
 
82
+ #Options
83
+ self.reversedStopPosition = 0
84
+
85
+ #Logger
80
86
  self._LOGGER = logger
81
87
 
82
88
 
@@ -84,8 +90,9 @@ class Selve:
84
90
  # Infinite loop to collect all incoming data
85
91
  self._LOGGER.debug("(Selve Worker): " + "Worker started")
86
92
 
87
- try:
88
- while True:
93
+
94
+ while True:
95
+ try:
89
96
  if not self._pauseWorker.is_set():
90
97
  if not self._serial.is_open:
91
98
  self._serial.open()
@@ -98,6 +105,7 @@ class Selve:
98
105
  async with self._writeLock:
99
106
  async with self._readLock:
100
107
  if self._serial.in_waiting > 0:
108
+ self._LOGGER.debug(f'(Selve Worker): Recieved Serial Data')
101
109
  msg = ""
102
110
  while True:
103
111
  response = self._serial.readline().strip()
@@ -113,13 +121,22 @@ class Selve:
113
121
  if self._stopThread.is_set():
114
122
  self._LOGGER.debug("(Selve Worker): " + 'Exiting worker loop...')
115
123
  break
124
+
116
125
  await asyncio.sleep(0.1)
117
- return True
118
- # serial port exceptions, all of these notify that we are in some
119
- # serious trouble
120
- except serial.SerialException:
121
- # log message
122
- self._LOGGER.error("(Selve Worker): " + 'Serial Port RX error')
126
+
127
+ except serial.SerialException:
128
+ # log message
129
+ self._LOGGER.error("(Selve Worker): " + 'Serial Port RX error')
130
+ self._LOGGER.error("(Selve Worker): " + 'trying to reconnect...')
131
+ await self.recover()
132
+
133
+ #await asyncio.sleep(0.1)
134
+ return True
135
+ # serial port exceptions, all of these notify that we are in some
136
+ # serious trouble
137
+
138
+
139
+
123
140
 
124
141
 
125
142
  async def setup(self, discover=False, fromConfigFlow=False):
@@ -194,6 +211,68 @@ class Selve:
194
211
  self._LOGGER.error("No gateway on comports found!")
195
212
  raise PortError
196
213
 
214
+ async def recover(self):
215
+ self._LOGGER.info("(Selve Worker): " + "Recover serial connection")
216
+ self._LOGGER.debug("(Selve Worker): " + "Waiting 5 seconds before trying...")
217
+ await asyncio.sleep(5)
218
+ self._LOGGER.debug("(Selve Worker): " + "Recovering")
219
+
220
+
221
+
222
+ if self._port is not None:
223
+ try:
224
+ self._serial = serial.Serial(
225
+ port=self._port,
226
+ baudrate=115200,
227
+ bytesize=serial.EIGHTBITS,
228
+ parity=serial.PARITY_NONE,
229
+ stopbits=serial.STOPBITS_ONE,
230
+ xonxoff=False,
231
+ rtscts=False,
232
+ dsrdtr=False)
233
+
234
+ if await self.pingGatewayFromWorker():
235
+ return
236
+ except serial.SerialException as e:
237
+ self._LOGGER.debug("(Selve Worker): " + "Configured port not valid, maybe it has changed, trying other ports...")
238
+ except Exception as e:
239
+ self._LOGGER.error("(Selve Worker): " + "Unknown exception: " + str(e))
240
+
241
+
242
+ available_ports = list_ports.comports()
243
+ self._LOGGER.debug("(Selve Worker): " + "available comports: " + str(available_ports))
244
+
245
+ if len(available_ports) == 0:
246
+ self._LOGGER.error("(Selve Worker): " + "No available comports!")
247
+ return False
248
+
249
+ for p in available_ports:
250
+ try:
251
+ self._serial = serial.Serial(
252
+ port=p.device,
253
+ baudrate=115200,
254
+ bytesize=serial.EIGHTBITS,
255
+ parity=serial.PARITY_NONE,
256
+ stopbits=serial.STOPBITS_ONE,
257
+ xonxoff=False,
258
+ rtscts=False,
259
+ dsrdtr=False)
260
+ except Exception as e:
261
+ self._LOGGER.error("(Selve Worker): " + "Error at com port: " + str(e))
262
+ try:
263
+ self._serial.close()
264
+ except:
265
+ self._LOGGER.debug("(Selve Worker): " + "Cannot close com port")
266
+ pass
267
+ if await self.pingGatewayFromWorker():
268
+ self._port = p.device
269
+ return
270
+ else:
271
+ self._serial.close()
272
+ self._serial = None
273
+ else:
274
+ self._LOGGER.error("(Selve Worker): " + "No gateway on comports found!")
275
+ raise PortError
197
276
 
198
277
 
199
278
  async def startWorker(self):
@@ -246,6 +325,19 @@ class Selve:
246
325
  """Remove previously registered callback."""
247
326
  self._callbacks.discard(callback)
248
327
 
328
+ def register_event_callback(self, callback: Callable[[], None]) -> None:
329
+ """Register callback, called when other events take place."""
330
+ self._eventCallbacks.add(callback)
331
+
332
+ def remove_event_callback(self, callback: Callable[[], None]) -> None:
333
+ """Remove previously registered callback."""
334
+ self._eventCallbacks.discard(callback)
335
+
336
+
337
+ def updateOptions(self, reversedStopPosition = 0):
338
+ self.reversedStopPosition = reversedStopPosition
339
+
340
+
249
341
  async def _sendCommandToGateway(self, command: Command):
250
342
  commandstr = command.serializeToXML()
251
343
  self._LOGGER.debug('Gateway writing: ' + str(commandstr))
@@ -627,8 +719,18 @@ class Selve:
627
719
  self.addOrUpdateDevice(device, SelveTypes.DEVICE)
628
720
  config: DeviceGetValuesResponse = await self.executeCommandSyncWithResponse(DeviceGetValues(i))
629
721
  device.state = config.movementState
630
- device.value = config.value
631
- device.targetValue = config.targetValue
722
+
723
+ if self.reversedStopPosition is 0:
724
+ device.value = config.value if config.value else 0
725
+ else:
726
+ device.value = 100 - config.value if config.value else 0
727
+
728
+
729
+ if self.reversedStopPosition is 0:
730
+ device.targetValue = config.targetValue if config.targetValue else 0
731
+ else:
732
+ device.targetValue = 100 - config.targetValue if config.targetValue else 0
733
+
632
734
  device.unreachable = config.unreachable
633
735
  device.overload = config.overload
634
736
  device.obstructed = config.obstructed
@@ -798,8 +900,18 @@ class Selve:
798
900
  self._LOGGER.error("Id not found, creating")
799
901
 
800
902
  device.state = response.actorState
801
- device.value = response.value
802
- device.targetValue = response.targetValue
903
+
904
+ if self.reversedStopPosition is 0:
905
+ device.value = response.value if response.value else 0
906
+ else:
907
+ device.value = 100 - response.value if response.value else 0
908
+
909
+
910
+ if self.reversedStopPosition is 0:
911
+ device.targetValue = response.targetValue if response.targetValue else 0
912
+ else:
913
+ device.targetValue = 100 - response.targetValue if response.targetValue else 0
914
+
803
915
  device.unreachable = response.unreachable
804
916
  device.overload = response.overload
805
917
  device.obstructed = response.obstructed
@@ -845,6 +957,8 @@ class Selve:
845
957
  sender.lastEvent = response.event
846
958
  sender.name = response.senderName
847
959
  self.addOrUpdateDevice(sender, SelveTypes.SENSOR)
960
+ for callback in self._eventCallbacks:
961
+ callback(response)
848
962
 
849
963
  if isinstance(response, LogEventResponse):
850
964
  self.lastLogEvent = response
@@ -861,6 +975,9 @@ class Selve:
861
975
  if isinstance(response, DutyCycleResponse):
862
976
  self.sendingBlocked = response.mode
863
977
  self.utilization = response.traffic
978
+
979
+ for callback in self._eventCallbacks:
980
+ callback(response)
864
981
 
865
982
 
866
983
  def commandResult(self, response: IveoResultResponse | CommandResultResponse):
@@ -897,6 +1014,19 @@ class Selve:
897
1014
  self._LOGGER.debug("No ping")
898
1015
  return False
899
1016
 
1017
+ async def pingGatewayFromWorker(self, fromConfigFlow=False):
1018
+ cmd = ServicePing()
1019
+ methodResponse = await self.executeCommandSyncWithResponsefromWorker(cmd)
1020
+ try:
1021
+ if hasattr(methodResponse, "name"):
1022
+ if methodResponse.name == "selve.GW.service.ping":
1023
+ self._LOGGER.debug("Ping back")
1024
+ return True
1025
+ except:
1026
+ self._LOGGER.debug("Error in ping")
1027
+ self._LOGGER.debug("No ping")
1028
+ return False
1029
+
900
1030
 
901
1031
  async def gatewayState(self):
902
1032
  cmd = ServiceGetState()
@@ -1099,8 +1229,17 @@ class Selve:
1099
1229
  dev = self.getDevice(id, SelveTypes.DEVICE)
1100
1230
  dev.name = response.name if response.name else "None"
1101
1231
  dev.state = response.movementState if response.movementState else MovementState.UNKOWN.value
1102
- dev.value = response.value if response.value else 0
1103
- dev.targetValue = response.targetValue if response.targetValue else 0
1232
+ if self.reversedStopPosition is 0:
1233
+ dev.value = response.value if response.value else 0
1234
+ else:
1235
+ dev.value = 100 - response.value if response.value else 0
1236
+
1237
+
1238
+ if self.reversedStopPosition is 0:
1239
+ dev.targetValue = response.targetValue if response.targetValue else 0
1240
+ else:
1241
+ dev.targetValue = 100 - response.targetValue if response.targetValue else 0
1242
+
1104
1243
  dev.unreachable = response.unreachable if response.unreachable else True
1105
1244
  dev.overload = response.overload if response.overload else False
1106
1245
  dev.obstructed = response.obstructed if response.obstructed else False
@@ -1116,12 +1255,19 @@ class Selve:
1116
1255
 
1117
1256
  def setDeviceValue(self, id: int, value: int, type: SelveTypes):
1118
1257
  dev = self.getDevice(id, type)
1119
- dev.value = value
1258
+ if self.reversedStopPosition is 0:
1259
+ dev.value = value
1260
+ else:
1261
+ dev.value = 100 - value
1262
+
1120
1263
  self.addOrUpdateDevice(dev, type)
1121
1264
 
1122
1265
  def setDeviceTargetValue(self, id: int, value: int, type: SelveTypes):
1123
1266
  dev = self.getDevice(id, type)
1124
- dev.targetValue = value
1267
+ if self.reversedStopPosition is 0:
1268
+ dev.targetValue = value
1269
+ else:
1270
+ dev.targetValue = 100 - value
1125
1271
  self.addOrUpdateDevice(dev, type)
1126
1272
 
1127
1273
  def setDeviceState(self, id: int, state: MovementState, type: SelveTypes):
@@ -15,7 +15,7 @@ with open(path.join(here, 'README.md'), encoding='utf-8') as f:
15
15
  setup(
16
16
 
17
17
  name='python-selve-new', # Required
18
- version='2.2.14', # Required
18
+ version='2.2.16', # Required
19
19
  description='Python library for interfacing with selve devices using the USB-RF controller. Written completely new.', # Required
20
20
  long_description=long_description, # Optional
21
21
  long_description_content_type="text/markdown",
@@ -8,7 +8,7 @@ import selve
8
8
 
9
9
  ## In HA this would be loop = self.hass.loop
10
10
  loop = asyncio.new_event_loop()
11
- portname = 'COM4'
11
+ portname = None
12
12
 
13
13
  logger = logging.getLogger("Logger")
14
14
  logger.setLevel(logging.DEBUG)
@@ -19,23 +19,28 @@ handler.setFormatter(formatter)
19
19
  logger.addHandler(handler)
20
20
 
21
21
 
22
- selve = selve.Selve(portname, loop, develop=False, discover=False, logger=logger)
22
+ selve = selve.Selve(portname, develop=True, discover=False, logger=logger)
23
+ loop.run_until_complete(selve.setup())
23
24
 
25
+ loop.run_until_complete(selve.discover())
24
26
 
27
+ loop.run_until_complete(selve.setEvents(1,1,1,1,1))
28
+ loop.run_until_complete(selve.getEvents())
25
29
 
26
30
  #try:
27
31
  # loop.run_until_complete()
28
32
  #except KeyboardInterrupt:
29
33
  # loop.close()
30
34
 
31
- threading.Thread(target=loop.run_forever, args=())
35
+ #threading.Thread(target=loop.run_forever, args=())
32
36
 
33
- selve.pingGateway()
37
+ #loop.run_until_complete(selve.pingGateway())
34
38
  #selve.resetGateway()
35
- selve.discover()
39
+ #loop.run_until_complete(selve.discover())
36
40
 
41
+ #print("Test")
37
42
 
38
43
  #selve.moveDeviceDown(selve.devices['device'][1])
39
- selve.moveGroupUp(selve.devices['group'][1])
44
+ #selve.moveGroupUp(selve.devices['group'][1])
40
45
 
41
46
  loop.run_forever()