sensor-sdk 0.0.4__tar.gz → 0.0.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.
- {sensor-sdk-0.0.4 → sensor-sdk-0.0.6}/PKG-INFO +14 -2
- {sensor-sdk-0.0.4 → sensor-sdk-0.0.6}/README.md +13 -1
- {sensor-sdk-0.0.4 → sensor-sdk-0.0.6}/sensor/gforce.py +73 -46
- {sensor-sdk-0.0.4 → sensor-sdk-0.0.6}/sensor/sensor_controller.py +76 -47
- {sensor-sdk-0.0.4 → sensor-sdk-0.0.6}/sensor/sensor_data_context.py +69 -61
- {sensor-sdk-0.0.4 → sensor-sdk-0.0.6}/sensor/sensor_profile.py +147 -113
- sensor-sdk-0.0.6/sensor/utils.py +73 -0
- {sensor-sdk-0.0.4 → sensor-sdk-0.0.6}/sensor_sdk.egg-info/PKG-INFO +14 -2
- {sensor-sdk-0.0.4 → sensor-sdk-0.0.6}/setup.py +1 -1
- sensor-sdk-0.0.4/sensor/utils.py +0 -30
- {sensor-sdk-0.0.4 → sensor-sdk-0.0.6}/LICENSE.txt +0 -0
- {sensor-sdk-0.0.4 → sensor-sdk-0.0.6}/sensor/__init__.py +0 -0
- {sensor-sdk-0.0.4 → sensor-sdk-0.0.6}/sensor/sensor_data.py +0 -0
- {sensor-sdk-0.0.4 → sensor-sdk-0.0.6}/sensor/sensor_device.py +0 -0
- {sensor-sdk-0.0.4 → sensor-sdk-0.0.6}/sensor_sdk.egg-info/SOURCES.txt +0 -0
- {sensor-sdk-0.0.4 → sensor-sdk-0.0.6}/sensor_sdk.egg-info/dependency_links.txt +0 -0
- {sensor-sdk-0.0.4 → sensor-sdk-0.0.6}/sensor_sdk.egg-info/requires.txt +0 -0
- {sensor-sdk-0.0.4 → sensor-sdk-0.0.6}/sensor_sdk.egg-info/top_level.txt +0 -0
- {sensor-sdk-0.0.4 → sensor-sdk-0.0.6}/sensor_sdk.egg-info/zip-safe +0 -0
- {sensor-sdk-0.0.4 → sensor-sdk-0.0.6}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: sensor-sdk
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.6
|
|
4
4
|
Summary: Python sdk for Synchroni
|
|
5
5
|
Home-page: https://github.com/oymotion/SynchroniSDKPython
|
|
6
6
|
Author: Martin Ye
|
|
@@ -68,6 +68,12 @@ success = SensorControllerInstance.startScan(6000)
|
|
|
68
68
|
|
|
69
69
|
returns true if start scan success, periodInMS means onDeviceCallback will be called every periodInMS
|
|
70
70
|
|
|
71
|
+
Use `def scan(period_in_ms: int) -> list[BLEDevice]` to scan once time
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
bleDevices = SensorControllerInstance.scan(6000)
|
|
75
|
+
```
|
|
76
|
+
|
|
71
77
|
### 3. Stop scan
|
|
72
78
|
|
|
73
79
|
Use `def stopScan() -> None` to stop scan
|
|
@@ -122,7 +128,7 @@ sensorProfiles = SensorControllerInstance.getConnectedSensors()
|
|
|
122
128
|
|
|
123
129
|
### 9. Get Connected BLE Devices
|
|
124
130
|
|
|
125
|
-
Use `def getConnectedDevices() -> list[
|
|
131
|
+
Use `def getConnectedDevices() -> list[BLEDevice]` to get connected BLE Devices.
|
|
126
132
|
|
|
127
133
|
```python
|
|
128
134
|
bleDevices = SensorControllerInstance.getConnectedDevices()
|
|
@@ -340,3 +346,9 @@ batteryPower = sensorProfile.getBatteryLevel()
|
|
|
340
346
|
```
|
|
341
347
|
|
|
342
348
|
Please check console.py in examples directory
|
|
349
|
+
|
|
350
|
+
## Async methods
|
|
351
|
+
|
|
352
|
+
all methods start with async is async methods, they has same params and return result as sync methods.
|
|
353
|
+
|
|
354
|
+
Please check async_console.py in examples directory
|
|
@@ -57,6 +57,12 @@ success = SensorControllerInstance.startScan(6000)
|
|
|
57
57
|
|
|
58
58
|
returns true if start scan success, periodInMS means onDeviceCallback will be called every periodInMS
|
|
59
59
|
|
|
60
|
+
Use `def scan(period_in_ms: int) -> list[BLEDevice]` to scan once time
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
bleDevices = SensorControllerInstance.scan(6000)
|
|
64
|
+
```
|
|
65
|
+
|
|
60
66
|
### 3. Stop scan
|
|
61
67
|
|
|
62
68
|
Use `def stopScan() -> None` to stop scan
|
|
@@ -111,7 +117,7 @@ sensorProfiles = SensorControllerInstance.getConnectedSensors()
|
|
|
111
117
|
|
|
112
118
|
### 9. Get Connected BLE Devices
|
|
113
119
|
|
|
114
|
-
Use `def getConnectedDevices() -> list[
|
|
120
|
+
Use `def getConnectedDevices() -> list[BLEDevice]` to get connected BLE Devices.
|
|
115
121
|
|
|
116
122
|
```python
|
|
117
123
|
bleDevices = SensorControllerInstance.getConnectedDevices()
|
|
@@ -329,3 +335,9 @@ batteryPower = sensorProfile.getBatteryLevel()
|
|
|
329
335
|
```
|
|
330
336
|
|
|
331
337
|
Please check console.py in examples directory
|
|
338
|
+
|
|
339
|
+
## Async methods
|
|
340
|
+
|
|
341
|
+
all methods start with async is async methods, they has same params and return result as sync methods.
|
|
342
|
+
|
|
343
|
+
Please check async_console.py in examples directory
|
|
@@ -16,6 +16,8 @@ from bleak import (
|
|
|
16
16
|
BleakGATTCharacteristic,
|
|
17
17
|
)
|
|
18
18
|
|
|
19
|
+
from sensor import utils
|
|
20
|
+
|
|
19
21
|
|
|
20
22
|
@dataclass
|
|
21
23
|
class Characteristic:
|
|
@@ -146,15 +148,15 @@ class DataSubscription(IntEnum):
|
|
|
146
148
|
LOG = (0x00000800,)
|
|
147
149
|
|
|
148
150
|
DNF_EEG = (0x00010000,)
|
|
149
|
-
|
|
151
|
+
|
|
150
152
|
DNF_ECG = (0x00020000,)
|
|
151
|
-
|
|
153
|
+
|
|
152
154
|
DNF_IMPEDANCE = (0x00040000,)
|
|
153
|
-
|
|
155
|
+
|
|
154
156
|
DNF_IMU = (0x00080000,)
|
|
155
|
-
|
|
157
|
+
|
|
156
158
|
DNF_ADS = (0x00100000,)
|
|
157
|
-
|
|
159
|
+
|
|
158
160
|
DNF_BRTH = (0x00200000,)
|
|
159
161
|
|
|
160
162
|
DNF_CONCAT_BLE = (0x80000000,)
|
|
@@ -181,8 +183,8 @@ class DataType(IntEnum):
|
|
|
181
183
|
|
|
182
184
|
class SampleResolution(IntEnum):
|
|
183
185
|
BITS_8 = (8,)
|
|
184
|
-
BITS_12 = 12,
|
|
185
|
-
BITS_16 = 16,
|
|
186
|
+
BITS_12 = (12,)
|
|
187
|
+
BITS_16 = (16,)
|
|
186
188
|
BITS_24 = 24
|
|
187
189
|
|
|
188
190
|
|
|
@@ -215,6 +217,7 @@ class EmgRawDataConfig:
|
|
|
215
217
|
)
|
|
216
218
|
return cls(fs, channel_mask, batch_len, resolution)
|
|
217
219
|
|
|
220
|
+
|
|
218
221
|
@dataclass
|
|
219
222
|
class EegRawDataConfig:
|
|
220
223
|
fs: SamplingRate = 0
|
|
@@ -240,6 +243,7 @@ class EegRawDataConfig:
|
|
|
240
243
|
)
|
|
241
244
|
return cls(fs, channel_mask, batch_len, resolution, K)
|
|
242
245
|
|
|
246
|
+
|
|
243
247
|
@dataclass
|
|
244
248
|
class EegRawDataCap:
|
|
245
249
|
fs: SamplingRate = 0
|
|
@@ -262,7 +266,8 @@ class EegRawDataCap:
|
|
|
262
266
|
data,
|
|
263
267
|
)
|
|
264
268
|
return cls(fs, channel_count, batch_len, resolution)
|
|
265
|
-
|
|
269
|
+
|
|
270
|
+
|
|
266
271
|
@dataclass
|
|
267
272
|
class EcgRawDataConfig:
|
|
268
273
|
fs: SamplingRate = SamplingRate.HZ_250
|
|
@@ -287,7 +292,8 @@ class EcgRawDataConfig:
|
|
|
287
292
|
data,
|
|
288
293
|
)
|
|
289
294
|
return cls(fs, channel_mask, batch_len, resolution, K)
|
|
290
|
-
|
|
295
|
+
|
|
296
|
+
|
|
291
297
|
@dataclass
|
|
292
298
|
class ImuRawDataConfig:
|
|
293
299
|
channel_count: int = 0
|
|
@@ -295,6 +301,7 @@ class ImuRawDataConfig:
|
|
|
295
301
|
batch_len: int = 0
|
|
296
302
|
accK: float = 0
|
|
297
303
|
gyroK: float = 0
|
|
304
|
+
|
|
298
305
|
def to_bytes(self) -> bytes:
|
|
299
306
|
body = b""
|
|
300
307
|
body += struct.pack("<i", self.channel_count)
|
|
@@ -311,7 +318,8 @@ class ImuRawDataConfig:
|
|
|
311
318
|
data,
|
|
312
319
|
)
|
|
313
320
|
return cls(channel_count, fs, batch_len, accK, gyroK)
|
|
314
|
-
|
|
321
|
+
|
|
322
|
+
|
|
315
323
|
@dataclass
|
|
316
324
|
class BrthRawDataConfig:
|
|
317
325
|
fs: SamplingRate = 0
|
|
@@ -336,7 +344,8 @@ class BrthRawDataConfig:
|
|
|
336
344
|
data,
|
|
337
345
|
)
|
|
338
346
|
return cls(fs, channel_mask, batch_len, resolution, K)
|
|
339
|
-
|
|
347
|
+
|
|
348
|
+
|
|
340
349
|
@dataclass
|
|
341
350
|
class Request:
|
|
342
351
|
cmd: Command
|
|
@@ -361,7 +370,9 @@ class Response:
|
|
|
361
370
|
|
|
362
371
|
|
|
363
372
|
class GForce:
|
|
364
|
-
def __init__(
|
|
373
|
+
def __init__(
|
|
374
|
+
self, device: BLEDevice, cmd_char: str, data_char: str, isUniversalStream: bool
|
|
375
|
+
):
|
|
365
376
|
self.device_name = ""
|
|
366
377
|
self.client = None
|
|
367
378
|
self.cmd_char = cmd_char
|
|
@@ -371,21 +382,33 @@ class GForce:
|
|
|
371
382
|
self._num_channels = 8
|
|
372
383
|
self._device = device
|
|
373
384
|
self._is_universal_stream = isUniversalStream
|
|
374
|
-
self._raw_data_buf:queue.Queue[bytes] = None
|
|
385
|
+
self._raw_data_buf: queue.Queue[bytes] = None
|
|
375
386
|
self.packet_id = 0
|
|
376
387
|
self.data_packet = []
|
|
377
388
|
|
|
378
389
|
async def connect(self, disconnect_cb, buf: queue.Queue[bytes]):
|
|
379
390
|
client = BleakClient(self._device, disconnected_callback=disconnect_cb)
|
|
380
|
-
await client.connect()
|
|
381
|
-
|
|
382
391
|
self.client = client
|
|
383
392
|
self.device_name = self._device.name
|
|
384
393
|
self._raw_data_buf = buf
|
|
385
|
-
|
|
386
|
-
|
|
394
|
+
|
|
395
|
+
try:
|
|
396
|
+
await asyncio.wait_for(client.connect(), utils._TIMEOUT)
|
|
397
|
+
except Exception as e:
|
|
398
|
+
return
|
|
399
|
+
|
|
400
|
+
if not client.is_connected:
|
|
401
|
+
return
|
|
402
|
+
if not self._is_universal_stream:
|
|
403
|
+
await asyncio.wait_for(
|
|
404
|
+
client.start_notify(self.cmd_char, self._on_cmd_response),
|
|
405
|
+
utils._TIMEOUT,
|
|
406
|
+
)
|
|
387
407
|
else:
|
|
388
|
-
await
|
|
408
|
+
await asyncio.wait_for(
|
|
409
|
+
client.start_notify(self.data_char, self._on_universal_response),
|
|
410
|
+
utils._TIMEOUT,
|
|
411
|
+
)
|
|
389
412
|
|
|
390
413
|
def _on_data_response(self, q: Queue[bytes], bs: bytearray):
|
|
391
414
|
bs = bytes(bs)
|
|
@@ -537,6 +560,7 @@ class GForce:
|
|
|
537
560
|
num_channels = 6
|
|
538
561
|
|
|
539
562
|
return emg_gesture_data.reshape(-1, num_channels)
|
|
563
|
+
|
|
540
564
|
def _on_universal_response(self, _: BleakGATTCharacteristic, bs: bytearray):
|
|
541
565
|
self._raw_data_buf.put_nowait(bytes(bs))
|
|
542
566
|
|
|
@@ -675,7 +699,6 @@ class GForce:
|
|
|
675
699
|
)
|
|
676
700
|
)
|
|
677
701
|
|
|
678
|
-
|
|
679
702
|
async def system_reset(self):
|
|
680
703
|
await self._send_request(
|
|
681
704
|
Request(
|
|
@@ -684,11 +707,8 @@ class GForce:
|
|
|
684
707
|
)
|
|
685
708
|
)
|
|
686
709
|
|
|
687
|
-
|
|
688
710
|
async def set_motor(self, switchStatus):
|
|
689
|
-
body = [
|
|
690
|
-
switchStatus == True
|
|
691
|
-
]
|
|
711
|
+
body = [switchStatus == True]
|
|
692
712
|
body = bytes(body)
|
|
693
713
|
ret = await self._send_request(
|
|
694
714
|
Request(
|
|
@@ -699,9 +719,7 @@ class GForce:
|
|
|
699
719
|
)
|
|
700
720
|
|
|
701
721
|
async def set_led(self, switchStatus):
|
|
702
|
-
body = [
|
|
703
|
-
switchStatus == True
|
|
704
|
-
]
|
|
722
|
+
body = [switchStatus == True]
|
|
705
723
|
body = bytes(body)
|
|
706
724
|
ret = await self._send_request(
|
|
707
725
|
Request(
|
|
@@ -712,9 +730,7 @@ class GForce:
|
|
|
712
730
|
)
|
|
713
731
|
|
|
714
732
|
async def set_log_level(self, logLevel):
|
|
715
|
-
body = [
|
|
716
|
-
0xFF & logLevel
|
|
717
|
-
]
|
|
733
|
+
body = [0xFF & logLevel]
|
|
718
734
|
body = bytes(body)
|
|
719
735
|
ret = await self._send_request(
|
|
720
736
|
Request(
|
|
@@ -724,7 +740,6 @@ class GForce:
|
|
|
724
740
|
)
|
|
725
741
|
)
|
|
726
742
|
|
|
727
|
-
|
|
728
743
|
async def set_emg_raw_data_config(self, cfg=EmgRawDataConfig()):
|
|
729
744
|
body = cfg.to_bytes()
|
|
730
745
|
await self._send_request(
|
|
@@ -757,7 +772,7 @@ class GForce:
|
|
|
757
772
|
)
|
|
758
773
|
)
|
|
759
774
|
return EmgRawDataConfig.from_bytes(buf)
|
|
760
|
-
|
|
775
|
+
|
|
761
776
|
async def get_eeg_raw_data_config(self) -> EegRawDataConfig:
|
|
762
777
|
buf = await self._send_request(
|
|
763
778
|
Request(
|
|
@@ -766,7 +781,7 @@ class GForce:
|
|
|
766
781
|
)
|
|
767
782
|
)
|
|
768
783
|
return EegRawDataConfig.from_bytes(buf)
|
|
769
|
-
|
|
784
|
+
|
|
770
785
|
async def get_eeg_raw_data_cap(self) -> EegRawDataCap:
|
|
771
786
|
buf = await self._send_request(
|
|
772
787
|
Request(
|
|
@@ -784,7 +799,7 @@ class GForce:
|
|
|
784
799
|
)
|
|
785
800
|
)
|
|
786
801
|
return EcgRawDataConfig.from_bytes(buf)
|
|
787
|
-
|
|
802
|
+
|
|
788
803
|
async def get_imu_raw_data_config(self) -> ImuRawDataConfig:
|
|
789
804
|
buf = await self._send_request(
|
|
790
805
|
Request(
|
|
@@ -792,8 +807,8 @@ class GForce:
|
|
|
792
807
|
has_res=True,
|
|
793
808
|
)
|
|
794
809
|
)
|
|
795
|
-
return ImuRawDataConfig.from_bytes(buf)
|
|
796
|
-
|
|
810
|
+
return ImuRawDataConfig.from_bytes(buf)
|
|
811
|
+
|
|
797
812
|
async def get_brth_raw_data_config(self) -> BrthRawDataConfig:
|
|
798
813
|
buf = await self._send_request(
|
|
799
814
|
Request(
|
|
@@ -801,8 +816,8 @@ class GForce:
|
|
|
801
816
|
has_res=True,
|
|
802
817
|
)
|
|
803
818
|
)
|
|
804
|
-
return BrthRawDataConfig.from_bytes(buf)
|
|
805
|
-
|
|
819
|
+
return BrthRawDataConfig.from_bytes(buf)
|
|
820
|
+
|
|
806
821
|
async def set_subscription(self, subscription: DataSubscription):
|
|
807
822
|
body = [
|
|
808
823
|
0xFF & subscription,
|
|
@@ -819,20 +834,27 @@ class GForce:
|
|
|
819
834
|
)
|
|
820
835
|
)
|
|
821
836
|
|
|
822
|
-
async def start_streaming(self, q:queue.Queue):
|
|
823
|
-
await
|
|
824
|
-
self.
|
|
825
|
-
|
|
837
|
+
async def start_streaming(self, q: queue.Queue):
|
|
838
|
+
await asyncio.wait_for(
|
|
839
|
+
self.client.start_notify(
|
|
840
|
+
self.data_char,
|
|
841
|
+
lambda _, data: self._on_data_response(q, data),
|
|
842
|
+
),
|
|
843
|
+
utils._TIMEOUT,
|
|
826
844
|
)
|
|
827
845
|
|
|
828
846
|
async def stop_streaming(self):
|
|
829
847
|
exceptions = []
|
|
830
848
|
try:
|
|
831
|
-
await
|
|
849
|
+
await asyncio.wait_for(
|
|
850
|
+
self.set_subscription(DataSubscription.OFF), utils._TIMEOUT
|
|
851
|
+
)
|
|
832
852
|
except Exception as e:
|
|
833
853
|
exceptions.append(e)
|
|
834
854
|
try:
|
|
835
|
-
await
|
|
855
|
+
await asyncio.wait_for(
|
|
856
|
+
self.client.stop_notify(self.data_char), utils._TIMEOUT
|
|
857
|
+
)
|
|
836
858
|
except Exception as e:
|
|
837
859
|
exceptions.append(e)
|
|
838
860
|
|
|
@@ -841,7 +863,10 @@ class GForce:
|
|
|
841
863
|
|
|
842
864
|
async def disconnect(self):
|
|
843
865
|
with suppress(asyncio.CancelledError):
|
|
844
|
-
|
|
866
|
+
try:
|
|
867
|
+
await asyncio.wait_for(self.client.disconnect(), utils._TIMEOUT)
|
|
868
|
+
except Exception as e:
|
|
869
|
+
pass
|
|
845
870
|
|
|
846
871
|
def _get_response_channel(self, cmd: Command) -> Queue:
|
|
847
872
|
q = Queue()
|
|
@@ -856,9 +881,11 @@ class GForce:
|
|
|
856
881
|
bs = bytes([req.cmd])
|
|
857
882
|
if req.body is not None:
|
|
858
883
|
bs += req.body
|
|
859
|
-
await
|
|
884
|
+
await asyncio.wait_for(
|
|
885
|
+
self.client.write_gatt_char(self.cmd_char, bs), utils._TIMEOUT
|
|
886
|
+
)
|
|
860
887
|
|
|
861
888
|
if not req.has_res:
|
|
862
889
|
return None
|
|
863
890
|
|
|
864
|
-
return await asyncio.wait_for(q.get(),
|
|
891
|
+
return await asyncio.wait_for(q.get(), utils._TIMEOUT)
|
|
@@ -5,10 +5,11 @@ from typing import Callable, Dict, List, Optional, Tuple
|
|
|
5
5
|
import bleak
|
|
6
6
|
|
|
7
7
|
from sensor import sensor_profile
|
|
8
|
+
from sensor import utils
|
|
8
9
|
from sensor.sensor_profile import DeviceStateEx, SensorProfile
|
|
9
10
|
import asyncio
|
|
10
11
|
|
|
11
|
-
from sensor.utils import start_loop,
|
|
12
|
+
from sensor.utils import async_call, start_loop, sync_call, async_exec, timer
|
|
12
13
|
from bleak import (
|
|
13
14
|
BleakScanner,
|
|
14
15
|
AdvertisementData,
|
|
@@ -37,16 +38,12 @@ class SensorController:
|
|
|
37
38
|
初始化 SensorController 实例。
|
|
38
39
|
"""
|
|
39
40
|
self._event_loop = asyncio.new_event_loop()
|
|
40
|
-
self._event_thread = threading.Thread(
|
|
41
|
-
target=start_loop, args=(self._event_loop,)
|
|
42
|
-
)
|
|
41
|
+
self._event_thread = threading.Thread(target=start_loop, args=(self._event_loop,))
|
|
43
42
|
self._event_thread.daemon = True
|
|
44
43
|
self._event_thread.name = "SensorController event"
|
|
45
44
|
self._event_thread.start()
|
|
46
45
|
self._gforce_event_loop = asyncio.new_event_loop()
|
|
47
|
-
self._gforce_event_thread = threading.Thread(
|
|
48
|
-
target=start_loop, args=(self._gforce_event_loop,)
|
|
49
|
-
)
|
|
46
|
+
self._gforce_event_thread = threading.Thread(target=start_loop, args=(self._gforce_event_loop,))
|
|
50
47
|
self._gforce_event_thread.daemon = True
|
|
51
48
|
self._gforce_event_thread.name = "BLE operation"
|
|
52
49
|
self._gforce_event_thread.start()
|
|
@@ -69,11 +66,9 @@ class SensorController:
|
|
|
69
66
|
self._gforce_event_loop.close()
|
|
70
67
|
|
|
71
68
|
def terminate(self):
|
|
69
|
+
utils._terminated = True
|
|
72
70
|
for sensor in self._sensor_profiles.values():
|
|
73
|
-
if
|
|
74
|
-
sensor.deviceState == DeviceStateEx.Connected
|
|
75
|
-
or sensor.deviceState == DeviceStateEx.Ready
|
|
76
|
-
):
|
|
71
|
+
if sensor.deviceState == DeviceStateEx.Connected or sensor.deviceState == DeviceStateEx.Ready:
|
|
77
72
|
sensor._destroy()
|
|
78
73
|
|
|
79
74
|
def _match_device(self, _device: bleak.BLEDevice, adv: AdvertisementData):
|
|
@@ -123,9 +118,7 @@ class SensorController:
|
|
|
123
118
|
return self._device_callback != None
|
|
124
119
|
|
|
125
120
|
@hasDeviceFoundCallback.setter
|
|
126
|
-
def onDeviceFoundCallback(
|
|
127
|
-
self, callback: Callable[[List[sensor_profile.BLEDevice]], None]
|
|
128
|
-
):
|
|
121
|
+
def onDeviceFoundCallback(self, callback: Callable[[List[sensor_profile.BLEDevice]], None]):
|
|
129
122
|
"""
|
|
130
123
|
设置扫描设备回调。
|
|
131
124
|
|
|
@@ -133,33 +126,77 @@ class SensorController:
|
|
|
133
126
|
"""
|
|
134
127
|
self._device_callback = callback
|
|
135
128
|
|
|
136
|
-
|
|
129
|
+
def _process_ble_devices(
|
|
137
130
|
self, found_devices: Dict[str, Tuple[bleak.BLEDevice, AdvertisementData]]
|
|
138
|
-
):
|
|
131
|
+
) -> List[sensor_profile.BLEDevice]:
|
|
132
|
+
devices: List[sensor_profile.BLEDevice] = list()
|
|
133
|
+
deviceMap: Dict[str, SensorProfile] = self._sensor_profiles.copy()
|
|
134
|
+
for uuid in found_devices:
|
|
135
|
+
device = found_devices[uuid][0]
|
|
136
|
+
if device.name == None:
|
|
137
|
+
continue
|
|
138
|
+
adv = found_devices[uuid][1]
|
|
139
|
+
if SERVICE_GUID in adv.service_uuids:
|
|
140
|
+
mac = None
|
|
141
|
+
if adv.service_data.get(SERVICE_GUID) != None:
|
|
142
|
+
bytes_val = adv.service_data[SERVICE_GUID]
|
|
143
|
+
mac = ":".join(f"{byte:02X}" for byte in bytes_val)
|
|
144
|
+
elif adv.service_data.get(RFSTAR_SERVICE_GUID) != None:
|
|
145
|
+
bytes_val = adv.service_data[RFSTAR_SERVICE_GUID]
|
|
146
|
+
mac = ":".join(f"{byte:02X}" for byte in reversed(bytes_val))
|
|
147
|
+
|
|
148
|
+
if mac == None:
|
|
149
|
+
continue
|
|
150
|
+
if deviceMap.get(mac) != None:
|
|
151
|
+
devices.append(self._sensor_profiles[mac].BLEDevice)
|
|
152
|
+
else:
|
|
153
|
+
newSensor = SensorProfile(device, adv, mac, self._gforce_event_loop)
|
|
154
|
+
deviceMap[mac] = newSensor
|
|
155
|
+
devices.append(newSensor.BLEDevice)
|
|
156
|
+
|
|
157
|
+
self._sensor_profiles = deviceMap
|
|
158
|
+
return devices
|
|
159
|
+
|
|
160
|
+
async def _async_scan(self, period):
|
|
161
|
+
self._is_scanning = True
|
|
162
|
+
found_devices = await self._scanner.discover(timeout=period / 1000, return_adv=True)
|
|
163
|
+
self._is_scanning = False
|
|
164
|
+
return self._process_ble_devices(found_devices)
|
|
165
|
+
|
|
166
|
+
def scan(self, period) -> List[sensor_profile.BLEDevice]:
|
|
167
|
+
"""
|
|
168
|
+
扫描一段时间后返回BLEDevice列表。
|
|
169
|
+
|
|
170
|
+
:param periodInMs (int): 扫描时长(毫秒)
|
|
171
|
+
|
|
172
|
+
:return: List[sensor_profile.BLEDevice]: BLEDevice列表
|
|
173
|
+
"""
|
|
174
|
+
return sync_call(self._gforce_event_loop, self._async_scan(period))
|
|
175
|
+
|
|
176
|
+
async def asyncScan(self, period) -> List[sensor_profile.BLEDevice]:
|
|
177
|
+
"""
|
|
178
|
+
扫描一段时间后返回BLEDevice列表。
|
|
179
|
+
|
|
180
|
+
:param periodInMs (int): 扫描时长(毫秒)
|
|
181
|
+
|
|
182
|
+
:return: List[sensor_profile.BLEDevice]: BLEDevice列表
|
|
183
|
+
"""
|
|
184
|
+
return await async_call(self._gforce_event_loop, self._async_scan(period))
|
|
185
|
+
|
|
186
|
+
async def _device_scan_callback(self, devices: List[sensor_profile.BLEDevice]):
|
|
139
187
|
if self._device_callback:
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
adv = found_devices[mac][1]
|
|
145
|
-
if SERVICE_GUID in adv.service_uuids:
|
|
146
|
-
if deviceMap.get(mac) != None:
|
|
147
|
-
devices.append(self._sensor_profiles[mac].BLEDevice)
|
|
148
|
-
else:
|
|
149
|
-
newSensor = SensorProfile(device, adv, self._gforce_event_loop)
|
|
150
|
-
deviceMap[mac] = newSensor
|
|
151
|
-
devices.append(newSensor.BLEDevice)
|
|
152
|
-
self._sensor_profiles = deviceMap
|
|
153
|
-
self._device_callback(devices)
|
|
188
|
+
try:
|
|
189
|
+
self._device_callback(devices)
|
|
190
|
+
except Exception as e:
|
|
191
|
+
print(e)
|
|
154
192
|
|
|
155
193
|
if self._is_scanning:
|
|
156
|
-
|
|
194
|
+
async_exec(self._gforce_event_loop, self._startScan())
|
|
157
195
|
|
|
158
196
|
async def _startScan(self) -> bool:
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
)
|
|
162
|
-
timer(self._event_loop, 0, self._device_scan_callback(devices))
|
|
197
|
+
found_devices = await self._scanner.discover(timeout=self._device_callback_period / 1000, return_adv=True)
|
|
198
|
+
devices = self._process_ble_devices(found_devices)
|
|
199
|
+
async_exec(self._event_loop, self._device_scan_callback(devices))
|
|
163
200
|
|
|
164
201
|
def startScan(self, periodInMs: int) -> bool:
|
|
165
202
|
"""
|
|
@@ -175,7 +212,7 @@ class SensorController:
|
|
|
175
212
|
self._is_scanning = True
|
|
176
213
|
self._device_callback_period = periodInMs
|
|
177
214
|
|
|
178
|
-
|
|
215
|
+
async_exec(self._gforce_event_loop, self._startScan())
|
|
179
216
|
return True
|
|
180
217
|
|
|
181
218
|
def stopScan(self) -> None:
|
|
@@ -187,9 +224,7 @@ class SensorController:
|
|
|
187
224
|
|
|
188
225
|
self._is_scanning = False
|
|
189
226
|
|
|
190
|
-
def requireSensor(
|
|
191
|
-
self, device: sensor_profile.BLEDevice
|
|
192
|
-
) -> Optional[SensorProfile]:
|
|
227
|
+
def requireSensor(self, device: sensor_profile.BLEDevice) -> Optional[SensorProfile]:
|
|
193
228
|
"""
|
|
194
229
|
根据设备信息获取或创建SensorProfile。
|
|
195
230
|
|
|
@@ -221,10 +256,7 @@ class SensorController:
|
|
|
221
256
|
"""
|
|
222
257
|
sensors: List[SensorProfile] = list()
|
|
223
258
|
for sensor in self._sensor_profiles.values():
|
|
224
|
-
if
|
|
225
|
-
sensor.deviceState == DeviceStateEx.Connected
|
|
226
|
-
or sensor.deviceState == DeviceStateEx.Ready
|
|
227
|
-
):
|
|
259
|
+
if sensor.deviceState == DeviceStateEx.Connected or sensor.deviceState == DeviceStateEx.Ready:
|
|
228
260
|
sensors.append(sensor)
|
|
229
261
|
|
|
230
262
|
return sensors
|
|
@@ -237,10 +269,7 @@ class SensorController:
|
|
|
237
269
|
"""
|
|
238
270
|
devices: List[sensor_profile.BLEDevice] = list()
|
|
239
271
|
for sensor in self._sensor_profiles.values():
|
|
240
|
-
if
|
|
241
|
-
sensor.deviceState == DeviceStateEx.Connected
|
|
242
|
-
or sensor.deviceState == DeviceStateEx.Ready
|
|
243
|
-
):
|
|
272
|
+
if sensor.deviceState == DeviceStateEx.Connected or sensor.deviceState == DeviceStateEx.Ready:
|
|
244
273
|
devices.append(sensor.BLEDevice)
|
|
245
274
|
|
|
246
275
|
return devices
|