sensor-sdk 0.0.3__tar.gz → 0.0.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.
Potentially problematic release.
This version of sensor-sdk might be problematic. Click here for more details.
- {sensor-sdk-0.0.3 → sensor-sdk-0.0.4}/PKG-INFO +1 -1
- {sensor-sdk-0.0.3 → sensor-sdk-0.0.4}/sensor/sensor_controller.py +52 -26
- sensor-sdk-0.0.4/sensor/sensor_data.py +94 -0
- {sensor-sdk-0.0.3 → sensor-sdk-0.0.4}/sensor/sensor_data_context.py +376 -93
- {sensor-sdk-0.0.3 → sensor-sdk-0.0.4}/sensor/sensor_device.py +34 -34
- {sensor-sdk-0.0.3 → sensor-sdk-0.0.4}/sensor/sensor_profile.py +121 -66
- {sensor-sdk-0.0.3 → sensor-sdk-0.0.4}/sensor/utils.py +7 -5
- {sensor-sdk-0.0.3 → sensor-sdk-0.0.4}/sensor_sdk.egg-info/PKG-INFO +1 -1
- sensor-sdk-0.0.4/setup.py +23 -0
- sensor-sdk-0.0.3/sensor/sensor_data.py +0 -91
- sensor-sdk-0.0.3/setup.py +0 -29
- {sensor-sdk-0.0.3 → sensor-sdk-0.0.4}/LICENSE.txt +0 -0
- {sensor-sdk-0.0.3 → sensor-sdk-0.0.4}/README.md +0 -0
- {sensor-sdk-0.0.3 → sensor-sdk-0.0.4}/sensor/__init__.py +0 -0
- {sensor-sdk-0.0.3 → sensor-sdk-0.0.4}/sensor/gforce.py +0 -0
- {sensor-sdk-0.0.3 → sensor-sdk-0.0.4}/sensor_sdk.egg-info/SOURCES.txt +0 -0
- {sensor-sdk-0.0.3 → sensor-sdk-0.0.4}/sensor_sdk.egg-info/dependency_links.txt +0 -0
- {sensor-sdk-0.0.3 → sensor-sdk-0.0.4}/sensor_sdk.egg-info/requires.txt +0 -0
- {sensor-sdk-0.0.3 → sensor-sdk-0.0.4}/sensor_sdk.egg-info/top_level.txt +0 -0
- {sensor-sdk-0.0.3 → sensor-sdk-0.0.4}/sensor_sdk.egg-info/zip-safe +0 -0
- {sensor-sdk-0.0.3 → sensor-sdk-0.0.4}/setup.cfg +0 -0
|
@@ -13,16 +13,19 @@ from bleak import (
|
|
|
13
13
|
BleakScanner,
|
|
14
14
|
AdvertisementData,
|
|
15
15
|
)
|
|
16
|
+
|
|
16
17
|
SERVICE_GUID = "0000ffd0-0000-1000-8000-00805f9b34fb"
|
|
17
18
|
RFSTAR_SERVICE_GUID = "00001812-0000-1000-8000-00805f9b34fb"
|
|
18
19
|
|
|
20
|
+
|
|
19
21
|
class SensorController:
|
|
20
22
|
_instance_lock = threading.Lock()
|
|
23
|
+
|
|
21
24
|
def __new__(cls, *args, **kwargs):
|
|
22
25
|
if not hasattr(SensorController, "_instance"):
|
|
23
26
|
with SensorController._instance_lock:
|
|
24
27
|
if not hasattr(SensorController, "_instance"):
|
|
25
|
-
SensorController._instance = object.__new__(cls)
|
|
28
|
+
SensorController._instance = object.__new__(cls)
|
|
26
29
|
return SensorController._instance
|
|
27
30
|
|
|
28
31
|
"""
|
|
@@ -34,16 +37,23 @@ class SensorController:
|
|
|
34
37
|
初始化 SensorController 实例。
|
|
35
38
|
"""
|
|
36
39
|
self._event_loop = asyncio.new_event_loop()
|
|
37
|
-
self._event_thread = threading.Thread(
|
|
40
|
+
self._event_thread = threading.Thread(
|
|
41
|
+
target=start_loop, args=(self._event_loop,)
|
|
42
|
+
)
|
|
38
43
|
self._event_thread.daemon = True
|
|
39
44
|
self._event_thread.name = "SensorController event"
|
|
40
45
|
self._event_thread.start()
|
|
41
46
|
self._gforce_event_loop = asyncio.new_event_loop()
|
|
42
|
-
self._gforce_event_thread = threading.Thread(
|
|
47
|
+
self._gforce_event_thread = threading.Thread(
|
|
48
|
+
target=start_loop, args=(self._gforce_event_loop,)
|
|
49
|
+
)
|
|
43
50
|
self._gforce_event_thread.daemon = True
|
|
44
51
|
self._gforce_event_thread.name = "BLE operation"
|
|
45
52
|
self._gforce_event_thread.start()
|
|
46
|
-
self._scanner = BleakScanner(
|
|
53
|
+
self._scanner = BleakScanner(
|
|
54
|
+
detection_callback=self._match_device,
|
|
55
|
+
service_uuids=[SERVICE_GUID, RFSTAR_SERVICE_GUID],
|
|
56
|
+
)
|
|
47
57
|
self._is_scanning = False
|
|
48
58
|
self._device_callback: Callable[[List[sensor_profile.BLEDevice]], None] = None
|
|
49
59
|
self._device_callback_period = 0
|
|
@@ -60,17 +70,17 @@ class SensorController:
|
|
|
60
70
|
|
|
61
71
|
def terminate(self):
|
|
62
72
|
for sensor in self._sensor_profiles.values():
|
|
63
|
-
if
|
|
73
|
+
if (
|
|
74
|
+
sensor.deviceState == DeviceStateEx.Connected
|
|
75
|
+
or sensor.deviceState == DeviceStateEx.Ready
|
|
76
|
+
):
|
|
64
77
|
sensor._destroy()
|
|
65
|
-
|
|
66
78
|
|
|
67
79
|
def _match_device(self, _device: bleak.BLEDevice, adv: AdvertisementData):
|
|
68
80
|
if _device.name == None:
|
|
69
81
|
return False
|
|
70
82
|
|
|
71
|
-
if
|
|
72
|
-
SERVICE_GUID in adv.service_uuids
|
|
73
|
-
):
|
|
83
|
+
if SERVICE_GUID in adv.service_uuids:
|
|
74
84
|
print("Device found: {0}, RSSI: {1}".format(_device.name, adv.rssi))
|
|
75
85
|
return True
|
|
76
86
|
|
|
@@ -113,7 +123,9 @@ class SensorController:
|
|
|
113
123
|
return self._device_callback != None
|
|
114
124
|
|
|
115
125
|
@hasDeviceFoundCallback.setter
|
|
116
|
-
def onDeviceFoundCallback(
|
|
126
|
+
def onDeviceFoundCallback(
|
|
127
|
+
self, callback: Callable[[List[sensor_profile.BLEDevice]], None]
|
|
128
|
+
):
|
|
117
129
|
"""
|
|
118
130
|
设置扫描设备回调。
|
|
119
131
|
|
|
@@ -121,10 +133,12 @@ class SensorController:
|
|
|
121
133
|
"""
|
|
122
134
|
self._device_callback = callback
|
|
123
135
|
|
|
124
|
-
async def _device_scan_callback(
|
|
136
|
+
async def _device_scan_callback(
|
|
137
|
+
self, found_devices: Dict[str, Tuple[bleak.BLEDevice, AdvertisementData]]
|
|
138
|
+
):
|
|
125
139
|
if self._device_callback:
|
|
126
|
-
devices:List[sensor_profile.BLEDevice] = list()
|
|
127
|
-
deviceMap
|
|
140
|
+
devices: List[sensor_profile.BLEDevice] = list()
|
|
141
|
+
deviceMap: Dict[str, SensorProfile] = self._sensor_profiles.copy()
|
|
128
142
|
for mac in found_devices:
|
|
129
143
|
device = found_devices[mac][0]
|
|
130
144
|
adv = found_devices[mac][1]
|
|
@@ -132,7 +146,7 @@ class SensorController:
|
|
|
132
146
|
if deviceMap.get(mac) != None:
|
|
133
147
|
devices.append(self._sensor_profiles[mac].BLEDevice)
|
|
134
148
|
else:
|
|
135
|
-
newSensor = SensorProfile(device, adv,self._gforce_event_loop)
|
|
149
|
+
newSensor = SensorProfile(device, adv, self._gforce_event_loop)
|
|
136
150
|
deviceMap[mac] = newSensor
|
|
137
151
|
devices.append(newSensor.BLEDevice)
|
|
138
152
|
self._sensor_profiles = deviceMap
|
|
@@ -142,8 +156,11 @@ class SensorController:
|
|
|
142
156
|
timer(self._gforce_event_loop, 0, self._startScan())
|
|
143
157
|
|
|
144
158
|
async def _startScan(self) -> bool:
|
|
145
|
-
devices = await self._scanner.discover(
|
|
159
|
+
devices = await self._scanner.discover(
|
|
160
|
+
timeout=self._device_callback_period / 1000, return_adv=True
|
|
161
|
+
)
|
|
146
162
|
timer(self._event_loop, 0, self._device_scan_callback(devices))
|
|
163
|
+
|
|
147
164
|
def startScan(self, periodInMs: int) -> bool:
|
|
148
165
|
"""
|
|
149
166
|
开始扫描。
|
|
@@ -152,12 +169,12 @@ class SensorController:
|
|
|
152
169
|
|
|
153
170
|
:return: bool: 扫描是否成功启动
|
|
154
171
|
"""
|
|
155
|
-
if
|
|
172
|
+
if self._is_scanning:
|
|
156
173
|
return True
|
|
157
|
-
|
|
174
|
+
|
|
158
175
|
self._is_scanning = True
|
|
159
176
|
self._device_callback_period = periodInMs
|
|
160
|
-
|
|
177
|
+
|
|
161
178
|
timer(self._gforce_event_loop, 0, self._startScan())
|
|
162
179
|
return True
|
|
163
180
|
|
|
@@ -165,12 +182,14 @@ class SensorController:
|
|
|
165
182
|
"""
|
|
166
183
|
停止扫描。
|
|
167
184
|
"""
|
|
168
|
-
if
|
|
169
|
-
return
|
|
170
|
-
|
|
185
|
+
if not self._is_scanning:
|
|
186
|
+
return
|
|
187
|
+
|
|
171
188
|
self._is_scanning = False
|
|
172
189
|
|
|
173
|
-
def requireSensor(
|
|
190
|
+
def requireSensor(
|
|
191
|
+
self, device: sensor_profile.BLEDevice
|
|
192
|
+
) -> Optional[SensorProfile]:
|
|
174
193
|
"""
|
|
175
194
|
根据设备信息获取或创建SensorProfile。
|
|
176
195
|
|
|
@@ -200,9 +219,12 @@ class SensorController:
|
|
|
200
219
|
|
|
201
220
|
:return: List[SensorProfile]: 已连接的SensorProfile列表
|
|
202
221
|
"""
|
|
203
|
-
sensors:List[SensorProfile] = list()
|
|
222
|
+
sensors: List[SensorProfile] = list()
|
|
204
223
|
for sensor in self._sensor_profiles.values():
|
|
205
|
-
if
|
|
224
|
+
if (
|
|
225
|
+
sensor.deviceState == DeviceStateEx.Connected
|
|
226
|
+
or sensor.deviceState == DeviceStateEx.Ready
|
|
227
|
+
):
|
|
206
228
|
sensors.append(sensor)
|
|
207
229
|
|
|
208
230
|
return sensors
|
|
@@ -213,11 +235,15 @@ class SensorController:
|
|
|
213
235
|
|
|
214
236
|
:return: List[BLEDevice]: 已连接的蓝牙设备列表
|
|
215
237
|
"""
|
|
216
|
-
devices:List[sensor_profile.BLEDevice] = list()
|
|
238
|
+
devices: List[sensor_profile.BLEDevice] = list()
|
|
217
239
|
for sensor in self._sensor_profiles.values():
|
|
218
|
-
if
|
|
240
|
+
if (
|
|
241
|
+
sensor.deviceState == DeviceStateEx.Connected
|
|
242
|
+
or sensor.deviceState == DeviceStateEx.Ready
|
|
243
|
+
):
|
|
219
244
|
devices.append(sensor.BLEDevice)
|
|
220
245
|
|
|
221
246
|
return devices
|
|
222
247
|
|
|
248
|
+
|
|
223
249
|
SensorControllerInstance = SensorController()
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
from enum import Enum, IntEnum
|
|
2
|
+
from typing import Dict, List
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
# 一个采样数据
|
|
6
|
+
# 该类用于存储单个采样数据的相关信息,包括数据值、阻抗、饱和度、采样索引和是否丢包的标志
|
|
7
|
+
class Sample:
|
|
8
|
+
# """
|
|
9
|
+
# Initialize a Sample instance.
|
|
10
|
+
|
|
11
|
+
# :param data: 数据值,单位为 uV
|
|
12
|
+
# :param impedance: 阻抗值,单位为 Ω
|
|
13
|
+
# :param saturation: 饱和度值,单位为 % ,值 0-100
|
|
14
|
+
# :param sample_index: 采样索引,用于标识采样的顺序
|
|
15
|
+
# :param is_lost: 是否丢包的标志,True 表示丢包,False 表示正常
|
|
16
|
+
# """
|
|
17
|
+
# def __init__(self, data: int, impedance: int, saturation: int, sample_index: int, is_lost: bool):
|
|
18
|
+
# self.data = data
|
|
19
|
+
# self.impedance = impedance
|
|
20
|
+
# self.saturation = saturation
|
|
21
|
+
# self.sampleIndex = sample_index
|
|
22
|
+
# self.isLost = is_lost
|
|
23
|
+
|
|
24
|
+
def __init__(self):
|
|
25
|
+
self.rawData = 0
|
|
26
|
+
self.data = 0
|
|
27
|
+
self.impedance = 0
|
|
28
|
+
self.saturation = 0
|
|
29
|
+
self.sampleIndex = 0
|
|
30
|
+
self.isLost = False
|
|
31
|
+
self.timeStampInMs = 0
|
|
32
|
+
self.channelIndex = 0
|
|
33
|
+
self.sampleIndex = 0
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
# 对应 DataType 枚举
|
|
37
|
+
# 该枚举类定义了不同类型的数据,用于区分传感器采集的不同类型的数据
|
|
38
|
+
class DataType(IntEnum):
|
|
39
|
+
NTF_ACC = 0x1 # 加速度,用于标识加速度传感器采集的数据
|
|
40
|
+
NTF_GYRO = 0x2 # 陀螺仪,用于标识陀螺仪传感器采集的数据
|
|
41
|
+
NTF_EEG = 0x10 # EEG,用于标识脑电传感器采集的数据
|
|
42
|
+
NTF_ECG = 0x11 # ECG,用于标识心电传感器采集的数据
|
|
43
|
+
NTF_IMPEDANCE = (0x12,) # 阻抗数据
|
|
44
|
+
NTF_IMU = (0x13,) # 包含ACC和GYRO数据
|
|
45
|
+
NTF_ADS = (0x14,) # 无单位ads数据
|
|
46
|
+
NTF_BRTH = 0x15 # 呼吸,用于标识呼吸传感器采集的数据
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
# 一次采样的数据,包含多个通道的数据,channal_samples 为一个二维数组, 第一个维度为通道索引,第二个维度为采样索引
|
|
50
|
+
# 该类用于存储一次采样的完整数据,包括设备 MAC 地址、数据类型、采样率、通道数量、包中采样数量以及通道采样数据
|
|
51
|
+
class SensorData:
|
|
52
|
+
# """
|
|
53
|
+
# Initialize a SensorData instance.
|
|
54
|
+
|
|
55
|
+
# :param device_mac: The MAC address of the device.
|
|
56
|
+
# :param data_type: The type of data being collected.
|
|
57
|
+
# :param sample_rate: The rate at which samples are collected.
|
|
58
|
+
# :param channel_count: The number of channels in the data.
|
|
59
|
+
# :param package_sample_count: The number of samples in the package.
|
|
60
|
+
# :param channel_samples: A list of lists containing the sample data for each channel.
|
|
61
|
+
# """
|
|
62
|
+
# def __init__(self, device_mac: str, data_type: DataType, sample_rate: int, channel_count: int,
|
|
63
|
+
# package_sample_count: int, channel_samples: List[List[Sample]]):
|
|
64
|
+
# self.deviceMac = device_mac
|
|
65
|
+
# self.dataType = data_type
|
|
66
|
+
# self.sampleRate = sample_rate
|
|
67
|
+
# self.channelCount = channel_count
|
|
68
|
+
# self.packageSampleCount = package_sample_count
|
|
69
|
+
# self.channelSamples = channel_samples
|
|
70
|
+
# self.lastPackageCounter = 0
|
|
71
|
+
# self.lastPackageIndex = 0
|
|
72
|
+
# self.resolutionBits = 0
|
|
73
|
+
# self.channelMask = 0
|
|
74
|
+
# self.minPackageSampleCount = 0
|
|
75
|
+
# self.K = 0
|
|
76
|
+
|
|
77
|
+
def __init__(self):
|
|
78
|
+
self.deviceMac = ""
|
|
79
|
+
self.dataType = DataType.NTF_EEG
|
|
80
|
+
self.sampleRate = 0
|
|
81
|
+
self.channelCount = 0
|
|
82
|
+
self.packageSampleCount = 0
|
|
83
|
+
self.channelSamples: List[List[Sample]] = list()
|
|
84
|
+
self.lastPackageCounter = 0
|
|
85
|
+
self.lastPackageIndex = 0
|
|
86
|
+
self.resolutionBits = 0
|
|
87
|
+
self.channelMask = 0
|
|
88
|
+
self.minPackageSampleCount = 0
|
|
89
|
+
self.K = 0
|
|
90
|
+
|
|
91
|
+
def clear(self):
|
|
92
|
+
self.channelSamples.clear()
|
|
93
|
+
self.lastPackageCounter = 0
|
|
94
|
+
self.lastPackageIndex = 0
|