sensor-sdk 0.0.13__tar.gz → 0.0.15__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.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: sensor-sdk
3
- Version: 0.0.13
3
+ Version: 0.0.15
4
4
  Summary: Python sdk for Synchroni
5
5
  Home-page: https://github.com/oymotion/SynchroniSDKPython
6
6
  Author: Martin Ye
@@ -1,382 +1,382 @@
1
- # sensor-sdk
2
-
3
- Synchroni sdk for Python
4
-
5
- ## Brief
6
-
7
- Synchroni SDK is the software development kit for developers to access Synchroni products.
8
-
9
- ## Contributing
10
-
11
- See the [contributing guide](CONTRIBUTING.md) to learn how to contribute to the repository and the development workflow.
12
-
13
- ## License
14
-
15
- MIT
16
-
17
- ---
18
-
19
- ## Installation
20
-
21
- ```sh
22
- pip install sensor-sdk
23
- ```
24
-
25
- ## 1. Permission
26
-
27
- Application will obtain bluetooth permission by itself.
28
-
29
- ## 2. Import SDK
30
-
31
- ```python
32
- from sensor import *
33
- ```
34
-
35
- ## SensorController methods
36
-
37
- ### 1. Initalize
38
-
39
- ```python
40
- SensorControllerInstance = SensorController()
41
-
42
- # register scan listener
43
- if not SensorControllerInstance.hasDeviceFoundCallback:
44
- def on_device_callback(deviceList: List[BLEDevice]):
45
- # return all devices doesn't connected
46
- pass
47
- SensorControllerInstance.onDeviceFoundCallback = on_device_callback
48
- ```
49
-
50
- ### 2. Start scan
51
-
52
- Use `def startScan(period_in_ms: int) -> bool` to start scan
53
-
54
- ```python
55
- success = SensorControllerInstance.startScan(6000)
56
- ```
57
-
58
- returns true if start scan success, periodInMS means onDeviceCallback will be called every periodInMS
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
-
66
- ### 3. Stop scan
67
-
68
- Use `def stopScan() -> None` to stop scan
69
-
70
- ```python
71
- SensorControllerInstance.stopScan()
72
- ```
73
-
74
- ### 4. Check scaning
75
-
76
- Use `property isScanning: bool` to check scanning status
77
-
78
- ```python
79
- isScanning = SensorControllerInstance.isScanning
80
- ```
81
-
82
- ### 5. Check if bluetooth is enabled
83
-
84
- Use `property isEnabled: bool` to check if bluetooth is enabled
85
-
86
- ```python
87
- isEnabled = SensorControllerInstance.isEnabled
88
- ```
89
-
90
- ### 6. Create SensorProfile
91
-
92
- Use `def requireSensor(device: BLEDevice) -> SensorProfile | None` to create SensorProfile.
93
-
94
- If bleDevice is invalid, result is None.
95
-
96
- ```python
97
- sensorProfile = SensorControllerInstance.requireSensor(bleDevice)
98
- ```
99
-
100
- ### 7. Get SensorProfile
101
-
102
- Use `def getSensor(device: BLEDevice) -> SensorProfile | None` to get SensorProfile.
103
-
104
- If SensorProfile didn't created, result is None.
105
-
106
- ```python
107
- sensorProfile = SensorControllerInstance.getSensor(bleDevice)
108
- ```
109
-
110
- ### 8. Get Connected SensorProfiles
111
-
112
- Use `def getConnectedSensors() -> list[SensorProfile]` to get connected SensorProfiles.
113
-
114
- ```python
115
- sensorProfiles = SensorControllerInstance.getConnectedSensors()
116
- ```
117
-
118
- ### 9. Get Connected BLE Devices
119
-
120
- Use `def getConnectedDevices() -> list[BLEDevice]` to get connected BLE Devices.
121
-
122
- ```python
123
- bleDevices = SensorControllerInstance.getConnectedDevices()
124
- ```
125
-
126
- ### 10. Terminate
127
-
128
- Use `def terminate()` to terminate sdk
129
-
130
- ```python
131
-
132
- def terminate():
133
- SensorControllerInstance.terminate()
134
- exit()
135
-
136
- def main():
137
- signal.signal(signal.SIGINT, lambda signal, frame: terminate())
138
- time.sleep(30)
139
- SensorControllerInstance.terminate()
140
-
141
- Please MAKE SURE to call terminate when exit main() or press Ctrl+C
142
- ```
143
-
144
- ## SensorProfile methods
145
-
146
- ### 11. Initalize
147
-
148
- Please register callbacks for SensorProfile
149
-
150
- ```python
151
- sensorProfile = SensorControllerInstance.requireSensor(bleDevice)
152
-
153
- # register callbacks
154
- def on_state_changed(sensor, newState):
155
- # please do logic when device disconnected unexpected
156
- pass
157
-
158
- def on_error_callback(sensor, reason):
159
- # called when error occurs
160
- pass
161
-
162
- def on_power_changed(sensor, power):
163
- # callback for get battery level of device, power from 0 - 100, -1 is invalid
164
- pass
165
-
166
- def on_data_callback(sensor, data):
167
- # called after start data transfer
168
- pass
169
-
170
- sensorProfile.onStateChanged = on_state_changed
171
- sensorProfile.onErrorCallback = on_error_callback
172
- sensorProfile.onPowerChanged = on_power_changed
173
- sensorProfile.onDataCallback = on_data_callback
174
- ```
175
-
176
- ### 12. Connect device
177
-
178
- Use `def connect() -> bool` to connect.
179
-
180
- ```python
181
- success = sensorProfile.connect()
182
- ```
183
-
184
- ### 13. Disconnect
185
-
186
- Use `def disconnect() -> bool` to disconnect.
187
-
188
- ```python
189
- success = sensorProfile.disconnect()
190
- ```
191
-
192
- ### 14. Get device status
193
-
194
- Use `property deviceState: DeviceStateEx` to get device status.
195
-
196
- Please send command in 'Ready' state, should be after connect() return True.
197
-
198
- ```python
199
- deviceStateEx = sensorProfile.deviceState
200
-
201
- # deviceStateEx has define:
202
- # class DeviceStateEx(Enum):
203
- # Disconnected = 0
204
- # Connecting = 1
205
- # Connected = 2
206
- # Ready = 3
207
- # Disconnecting = 4
208
- # Invalid = 5
209
- ```
210
-
211
- ### 15. Get BLE device of SensorProfile
212
-
213
- Use `property BLEDevice: BLEDevice` to get BLE device of SensorProfile.
214
-
215
- ```python
216
- bleDevice = sensorProfile.BLEDevice
217
- ```
218
-
219
- ### 16. Get device info of SensorProfile
220
-
221
- Use `def getDeviceInfo() -> dict | None` to get device info of SensorProfile.
222
-
223
- Please call after device in 'Ready' state, return None if it's not connected.
224
-
225
- ```python
226
- deviceInfo = sensorProfile.getDeviceInfo()
227
-
228
- # deviceInfo has defines:
229
- # deviceInfo = {
230
- # "deviceName": str,
231
- # "modelName": str,
232
- # "hardwareVersion": str,
233
- # "firmwareVersion": str,
234
- # "emgChannelCount": int,
235
- # "eegChannelCount": int,
236
- # "ecgChannelCount": int,
237
- # "accChannelCount": int,
238
- # "gyroChannelCount": int,
239
- # "brthChannelCount": int,
240
- # "mtuSize": int
241
- # }
242
- ```
243
-
244
- ### 17. Init data transfer
245
-
246
- Use `def init(packageSampleCount: int, powerRefreshInterval: int) -> bool`.
247
-
248
- Please call after device in 'Ready' state, return True if init succeed.
249
-
250
- ```python
251
- success = sensorProfile.init(5, 60*1000)
252
- ```
253
-
254
- packageSampleCount: set sample counts of SensorData.channelSamples in onDataCallback()
255
- powerRefreshInterval: callback period for onPowerChanged()
256
-
257
- ### 18. Check if init data transfer succeed
258
-
259
- Use `property hasInited: bool` to check if init data transfer succeed.
260
-
261
- ```python
262
- hasInited = sensorProfile.hasInited
263
- ```
264
-
265
- ### 19. DataNotify
266
-
267
- Use `def startDataNotification() -> bool` to start data notification.
268
-
269
- Please call if hasInited return True
270
-
271
- #### 19.1 Start data transfer
272
-
273
- ```python
274
- success = sensorProfile.startDataNotification()
275
- ```
276
-
277
- Data type list:
278
-
279
- ```python
280
- class DataType(Enum):
281
- NTF_ACC = 0x1 # unit is g
282
- NTF_GYRO = 0x2 # unit is degree/s
283
- NTF_EEG = 0x10 # unit is uV
284
- NTF_ECG = 0x11 # unit is uV
285
- NTF_BRTH = 0x15 # unit is uV
286
- ```
287
-
288
- Process data in onDataCallback.
289
-
290
- ```python
291
- def on_data_callback(sensor, data):
292
- if data.dataType == DataType.NTF_EEG:
293
- pass
294
- elif data.dataType == DataType.NTF_ECG:
295
- pass
296
-
297
- # process data as you wish
298
- for oneChannelSamples in data.channelSamples:
299
- for sample in oneChannelSamples:
300
- if sample.isLost:
301
- # do some logic
302
- pass
303
- else:
304
- # draw with sample.data & sample.channelIndex
305
- # print(f"{sample.channelIndex} | {sample.sampleIndex} | {sample.data} | {sample.impedance}")
306
- pass
307
-
308
- sensorProfile.onDataCallback = on_data_callback
309
- ```
310
-
311
- #### 19.2 Stop data transfer
312
-
313
- Use `def stopDataNotification() -> bool` to stop data transfer.
314
-
315
- ```python
316
- success = sensorProfile.stopDataNotification()
317
- ```
318
-
319
- #### 19.3 Check if it's data transfering
320
-
321
- Use `property isDataTransfering: bool` to check if it's data transfering.
322
-
323
- ```python
324
- isDataTransfering = sensorProfile.isDataTransfering
325
- ```
326
-
327
- ### 20. Get battery level
328
-
329
- Use `def getBatteryLevel() -> int` to get battery level. Please call after device in 'Ready' state.
330
-
331
- ```python
332
- batteryPower = sensorProfile.getBatteryLevel()
333
-
334
- # batteryPower is battery level returned, value ranges from 0 to 100, 0 means out of battery, while 100 means full.
335
- ```
336
-
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
344
-
345
- ### setParam method
346
-
347
- Use `def setParam(self, key: str, value: str) -> str` to set parameter of sensor profile. Please call after device in 'Ready' state.
348
-
349
- Below is available key and value:
350
-
351
- ```python
352
- result = sensorProfile.setParam("NTF_EMG", "ON")
353
- # set EMG data to ON or OFF, result is "OK" if succeed
354
-
355
- result = sensorProfile.setParam("NTF_EEG", "ON")
356
- # set EEG data to ON or OFF, result is "OK" if succeed
357
-
358
- result = sensorProfile.setParam("NTF_ECG", "ON")
359
- # set ECG data to ON or OFF, result is "OK" if succeed
360
-
361
- result = sensorProfile.setParam("NTF_IMU", "ON")
362
- # set IMU data to ON or OFF, result is "OK" if succeed
363
-
364
- result = sensorProfile.setParam("NTF_BRTH", "ON")
365
- # set BRTH data to ON or OFF, result is "OK" if succeed
366
-
367
- result = sensorProfile.setParam("FILTER_50Hz", "ON")
368
- # set 50Hz notch filter to ON or OFF, result is "OK" if succeed
369
-
370
- result = sensorProfile.setParam("FILTER_60Hz", "ON")
371
- # set 60Hz notch filter to ON or OFF, result is "OK" if succeed
372
-
373
- result = sensorProfile.setParam("FILTER_HPF", "ON")
374
- # set 0.5Hz hpf filter to ON or OFF, result is "OK" if succeed
375
-
376
- result = sensorProfile.setParam("FILTER_LPF", "ON")
377
- # set 80Hz lpf filter to ON or OFF, result is "OK" if succeed
378
-
379
- result = sensorProfile.setParam("DEBUG_BLE_DATA_PATH", "d:/temp/test.csv")
380
- # set debug ble data path, result is "OK" if succeed
381
- # please give an absolute path and make sure it is valid and writeable by yourself
382
- ```
1
+ # sensor-sdk
2
+
3
+ Synchroni sdk for Python
4
+
5
+ ## Brief
6
+
7
+ Synchroni SDK is the software development kit for developers to access Synchroni products.
8
+
9
+ ## Contributing
10
+
11
+ See the [contributing guide](CONTRIBUTING.md) to learn how to contribute to the repository and the development workflow.
12
+
13
+ ## License
14
+
15
+ MIT
16
+
17
+ ---
18
+
19
+ ## Installation
20
+
21
+ ```sh
22
+ pip install sensor-sdk
23
+ ```
24
+
25
+ ## 1. Permission
26
+
27
+ Application will obtain bluetooth permission by itself.
28
+
29
+ ## 2. Import SDK
30
+
31
+ ```python
32
+ from sensor import *
33
+ ```
34
+
35
+ ## SensorController methods
36
+
37
+ ### 1. Initalize
38
+
39
+ ```python
40
+ SensorControllerInstance = SensorController()
41
+
42
+ # register scan listener
43
+ if not SensorControllerInstance.hasDeviceFoundCallback:
44
+ def on_device_callback(deviceList: List[BLEDevice]):
45
+ # return all devices doesn't connected
46
+ pass
47
+ SensorControllerInstance.onDeviceFoundCallback = on_device_callback
48
+ ```
49
+
50
+ ### 2. Start scan
51
+
52
+ Use `def startScan(period_in_ms: int) -> bool` to start scan
53
+
54
+ ```python
55
+ success = SensorControllerInstance.startScan(6000)
56
+ ```
57
+
58
+ returns true if start scan success, periodInMS means onDeviceCallback will be called every periodInMS
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
+
66
+ ### 3. Stop scan
67
+
68
+ Use `def stopScan() -> None` to stop scan
69
+
70
+ ```python
71
+ SensorControllerInstance.stopScan()
72
+ ```
73
+
74
+ ### 4. Check scaning
75
+
76
+ Use `property isScanning: bool` to check scanning status
77
+
78
+ ```python
79
+ isScanning = SensorControllerInstance.isScanning
80
+ ```
81
+
82
+ ### 5. Check if bluetooth is enabled
83
+
84
+ Use `property isEnabled: bool` to check if bluetooth is enabled
85
+
86
+ ```python
87
+ isEnabled = SensorControllerInstance.isEnabled
88
+ ```
89
+
90
+ ### 6. Create SensorProfile
91
+
92
+ Use `def requireSensor(device: BLEDevice) -> SensorProfile | None` to create SensorProfile.
93
+
94
+ If bleDevice is invalid, result is None.
95
+
96
+ ```python
97
+ sensorProfile = SensorControllerInstance.requireSensor(bleDevice)
98
+ ```
99
+
100
+ ### 7. Get SensorProfile
101
+
102
+ Use `def getSensor(device: BLEDevice) -> SensorProfile | None` to get SensorProfile.
103
+
104
+ If SensorProfile didn't created, result is None.
105
+
106
+ ```python
107
+ sensorProfile = SensorControllerInstance.getSensor(bleDevice)
108
+ ```
109
+
110
+ ### 8. Get Connected SensorProfiles
111
+
112
+ Use `def getConnectedSensors() -> list[SensorProfile]` to get connected SensorProfiles.
113
+
114
+ ```python
115
+ sensorProfiles = SensorControllerInstance.getConnectedSensors()
116
+ ```
117
+
118
+ ### 9. Get Connected BLE Devices
119
+
120
+ Use `def getConnectedDevices() -> list[BLEDevice]` to get connected BLE Devices.
121
+
122
+ ```python
123
+ bleDevices = SensorControllerInstance.getConnectedDevices()
124
+ ```
125
+
126
+ ### 10. Terminate
127
+
128
+ Use `def terminate()` to terminate sdk
129
+
130
+ ```python
131
+
132
+ def terminate():
133
+ SensorControllerInstance.terminate()
134
+ exit()
135
+
136
+ def main():
137
+ signal.signal(signal.SIGINT, lambda signal, frame: terminate())
138
+ time.sleep(30)
139
+ SensorControllerInstance.terminate()
140
+
141
+ Please MAKE SURE to call terminate when exit main() or press Ctrl+C
142
+ ```
143
+
144
+ ## SensorProfile methods
145
+
146
+ ### 11. Initalize
147
+
148
+ Please register callbacks for SensorProfile
149
+
150
+ ```python
151
+ sensorProfile = SensorControllerInstance.requireSensor(bleDevice)
152
+
153
+ # register callbacks
154
+ def on_state_changed(sensor, newState):
155
+ # please do logic when device disconnected unexpected
156
+ pass
157
+
158
+ def on_error_callback(sensor, reason):
159
+ # called when error occurs
160
+ pass
161
+
162
+ def on_power_changed(sensor, power):
163
+ # callback for get battery level of device, power from 0 - 100, -1 is invalid
164
+ pass
165
+
166
+ def on_data_callback(sensor, data):
167
+ # called after start data transfer
168
+ pass
169
+
170
+ sensorProfile.onStateChanged = on_state_changed
171
+ sensorProfile.onErrorCallback = on_error_callback
172
+ sensorProfile.onPowerChanged = on_power_changed
173
+ sensorProfile.onDataCallback = on_data_callback
174
+ ```
175
+
176
+ ### 12. Connect device
177
+
178
+ Use `def connect() -> bool` to connect.
179
+
180
+ ```python
181
+ success = sensorProfile.connect()
182
+ ```
183
+
184
+ ### 13. Disconnect
185
+
186
+ Use `def disconnect() -> bool` to disconnect.
187
+
188
+ ```python
189
+ success = sensorProfile.disconnect()
190
+ ```
191
+
192
+ ### 14. Get device status
193
+
194
+ Use `property deviceState: DeviceStateEx` to get device status.
195
+
196
+ Please send command in 'Ready' state, should be after connect() return True.
197
+
198
+ ```python
199
+ deviceStateEx = sensorProfile.deviceState
200
+
201
+ # deviceStateEx has define:
202
+ # class DeviceStateEx(Enum):
203
+ # Disconnected = 0
204
+ # Connecting = 1
205
+ # Connected = 2
206
+ # Ready = 3
207
+ # Disconnecting = 4
208
+ # Invalid = 5
209
+ ```
210
+
211
+ ### 15. Get BLE device of SensorProfile
212
+
213
+ Use `property BLEDevice: BLEDevice` to get BLE device of SensorProfile.
214
+
215
+ ```python
216
+ bleDevice = sensorProfile.BLEDevice
217
+ ```
218
+
219
+ ### 16. Get device info of SensorProfile
220
+
221
+ Use `def getDeviceInfo() -> dict | None` to get device info of SensorProfile.
222
+
223
+ Please call after device in 'Ready' state, return None if it's not connected.
224
+
225
+ ```python
226
+ deviceInfo = sensorProfile.getDeviceInfo()
227
+
228
+ # deviceInfo has defines:
229
+ # deviceInfo = {
230
+ # "deviceName": str,
231
+ # "modelName": str,
232
+ # "hardwareVersion": str,
233
+ # "firmwareVersion": str,
234
+ # "emgChannelCount": int,
235
+ # "eegChannelCount": int,
236
+ # "ecgChannelCount": int,
237
+ # "accChannelCount": int,
238
+ # "gyroChannelCount": int,
239
+ # "brthChannelCount": int,
240
+ # "mtuSize": int
241
+ # }
242
+ ```
243
+
244
+ ### 17. Init data transfer
245
+
246
+ Use `def init(packageSampleCount: int, powerRefreshInterval: int) -> bool`.
247
+
248
+ Please call after device in 'Ready' state, return True if init succeed.
249
+
250
+ ```python
251
+ success = sensorProfile.init(5, 60*1000)
252
+ ```
253
+
254
+ packageSampleCount: set sample counts of SensorData.channelSamples in onDataCallback()
255
+ powerRefreshInterval: callback period for onPowerChanged()
256
+
257
+ ### 18. Check if init data transfer succeed
258
+
259
+ Use `property hasInited: bool` to check if init data transfer succeed.
260
+
261
+ ```python
262
+ hasInited = sensorProfile.hasInited
263
+ ```
264
+
265
+ ### 19. DataNotify
266
+
267
+ Use `def startDataNotification() -> bool` to start data notification.
268
+
269
+ Please call if hasInited return True
270
+
271
+ #### 19.1 Start data transfer
272
+
273
+ ```python
274
+ success = sensorProfile.startDataNotification()
275
+ ```
276
+
277
+ Data type list:
278
+
279
+ ```python
280
+ class DataType(Enum):
281
+ NTF_ACC = 0x1 # unit is g
282
+ NTF_GYRO = 0x2 # unit is degree/s
283
+ NTF_EEG = 0x10 # unit is uV
284
+ NTF_ECG = 0x11 # unit is uV
285
+ NTF_BRTH = 0x15 # unit is uV
286
+ ```
287
+
288
+ Process data in onDataCallback.
289
+
290
+ ```python
291
+ def on_data_callback(sensor, data):
292
+ if data.dataType == DataType.NTF_EEG:
293
+ pass
294
+ elif data.dataType == DataType.NTF_ECG:
295
+ pass
296
+
297
+ # process data as you wish
298
+ for oneChannelSamples in data.channelSamples:
299
+ for sample in oneChannelSamples:
300
+ if sample.isLost:
301
+ # do some logic
302
+ pass
303
+ else:
304
+ # draw with sample.data & sample.channelIndex
305
+ # print(f"{sample.channelIndex} | {sample.sampleIndex} | {sample.data} | {sample.impedance}")
306
+ pass
307
+
308
+ sensorProfile.onDataCallback = on_data_callback
309
+ ```
310
+
311
+ #### 19.2 Stop data transfer
312
+
313
+ Use `def stopDataNotification() -> bool` to stop data transfer.
314
+
315
+ ```python
316
+ success = sensorProfile.stopDataNotification()
317
+ ```
318
+
319
+ #### 19.3 Check if it's data transfering
320
+
321
+ Use `property isDataTransfering: bool` to check if it's data transfering.
322
+
323
+ ```python
324
+ isDataTransfering = sensorProfile.isDataTransfering
325
+ ```
326
+
327
+ ### 20. Get battery level
328
+
329
+ Use `def getBatteryLevel() -> int` to get battery level. Please call after device in 'Ready' state.
330
+
331
+ ```python
332
+ batteryPower = sensorProfile.getBatteryLevel()
333
+
334
+ # batteryPower is battery level returned, value ranges from 0 to 100, 0 means out of battery, while 100 means full.
335
+ ```
336
+
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
344
+
345
+ ### setParam method
346
+
347
+ Use `def setParam(self, key: str, value: str) -> str` to set parameter of sensor profile. Please call after device in 'Ready' state.
348
+
349
+ Below is available key and value:
350
+
351
+ ```python
352
+ result = sensorProfile.setParam("NTF_EMG", "ON")
353
+ # set EMG data to ON or OFF, result is "OK" if succeed
354
+
355
+ result = sensorProfile.setParam("NTF_EEG", "ON")
356
+ # set EEG data to ON or OFF, result is "OK" if succeed
357
+
358
+ result = sensorProfile.setParam("NTF_ECG", "ON")
359
+ # set ECG data to ON or OFF, result is "OK" if succeed
360
+
361
+ result = sensorProfile.setParam("NTF_IMU", "ON")
362
+ # set IMU data to ON or OFF, result is "OK" if succeed
363
+
364
+ result = sensorProfile.setParam("NTF_BRTH", "ON")
365
+ # set BRTH data to ON or OFF, result is "OK" if succeed
366
+
367
+ result = sensorProfile.setParam("FILTER_50Hz", "ON")
368
+ # set 50Hz notch filter to ON or OFF, result is "OK" if succeed
369
+
370
+ result = sensorProfile.setParam("FILTER_60Hz", "ON")
371
+ # set 60Hz notch filter to ON or OFF, result is "OK" if succeed
372
+
373
+ result = sensorProfile.setParam("FILTER_HPF", "ON")
374
+ # set 0.5Hz hpf filter to ON or OFF, result is "OK" if succeed
375
+
376
+ result = sensorProfile.setParam("FILTER_LPF", "ON")
377
+ # set 80Hz lpf filter to ON or OFF, result is "OK" if succeed
378
+
379
+ result = sensorProfile.setParam("DEBUG_BLE_DATA_PATH", "d:/temp/test.csv")
380
+ # set debug ble data path, result is "OK" if succeed
381
+ # please give an absolute path and make sure it is valid and writeable by yourself
382
+ ```
@@ -853,10 +853,10 @@ class GForce:
853
853
 
854
854
  async def stop_streaming(self):
855
855
  exceptions = []
856
- try:
857
- await asyncio.wait_for(self.set_subscription(DataSubscription.OFF), utils._TIMEOUT)
858
- except Exception as e:
859
- exceptions.append(e)
856
+ # try:
857
+ # await asyncio.wait_for(self.set_subscription(DataSubscription.OFF), utils._TIMEOUT)
858
+ # except Exception as e:
859
+ # exceptions.append(e)
860
860
  try:
861
861
  await asyncio.wait_for(self.client.stop_notify(self.data_char), utils._TIMEOUT)
862
862
  except Exception as e:
@@ -274,12 +274,15 @@ class SensorProfileDataCtx:
274
274
  return True
275
275
  self._is_data_transfering = True
276
276
  self._rawDataBuffer.queue.clear()
277
+ self._concatDataBuffer.clear()
278
+ self.clear()
279
+
277
280
  if not self.isUniversalStream:
278
281
  await self.gForce.start_streaming(self._rawDataBuffer)
279
- return True
280
282
  else:
281
283
  await self.gForce.set_subscription(self.notifyDataFlag)
282
- return True
284
+
285
+ return True
283
286
 
284
287
  async def stop_streaming(self) -> bool:
285
288
  if not self._is_data_transfering:
@@ -287,12 +290,21 @@ class SensorProfileDataCtx:
287
290
 
288
291
  self._is_data_transfering = False
289
292
 
290
- if not self.isUniversalStream:
291
- await self.gForce.stop_streaming()
292
- return True
293
- else:
294
- await self.gForce.set_subscription(0)
295
- return True
293
+ try:
294
+
295
+ if not self.isUniversalStream:
296
+ await self.gForce.stop_streaming()
297
+ else:
298
+ await self.gForce.set_subscription(0)
299
+
300
+ while self._is_running and not self._rawDataBuffer.empty():
301
+ await asyncio.sleep(0.1)
302
+
303
+ except Exception as e:
304
+ print(e)
305
+ return False
306
+
307
+ return True
296
308
 
297
309
  async def setFilter(self, filter: str, value: str) -> str:
298
310
  self.filter_map[filter] = value
@@ -313,6 +325,7 @@ class SensorProfileDataCtx:
313
325
  switch |= 8
314
326
  try:
315
327
  await self.gForce.set_firmware_filter_switch(switch)
328
+ await asyncio.sleep(0.1)
316
329
  return "OK"
317
330
  except Exception as e:
318
331
  return "ERROR: " + str(e)
@@ -342,22 +355,23 @@ class SensorProfileDataCtx:
342
355
  except Exception as e:
343
356
  continue
344
357
 
345
- self._processDataPackage(data, buf, sensor)
358
+ if self.isDataTransfering:
359
+ self._processDataPackage(data, buf, sensor)
346
360
  self._rawDataBuffer.task_done()
347
361
 
348
- while self._is_running and self.isDataTransfering and not buf.empty():
349
- sensorData: SensorData = None
362
+ while self._is_running and self.isDataTransfering and not buf.empty():
363
+ sensorData: SensorData = None
364
+ try:
365
+ sensorData = buf.get_nowait()
366
+ except Exception as e:
367
+ break
368
+ if sensorData != None and callback != None:
350
369
  try:
351
- sensorData = buf.get_nowait()
370
+ asyncio.get_event_loop().run_in_executor(self.dataPool, callback, sensor, sensorData)
352
371
  except Exception as e:
353
- break
354
- if sensorData != None and callback != None:
355
- try:
356
- asyncio.get_event_loop().run_in_executor(self.dataPool, callback, sensor, sensorData)
357
- except Exception as e:
358
- print(e)
359
-
360
- buf.task_done()
372
+ print(e)
373
+
374
+ buf.task_done()
361
375
 
362
376
  def _processDataPackage(self, data: bytes, buf: Queue[SensorData], sensor):
363
377
  v = data[0]
@@ -61,6 +61,8 @@ class SensorProfile:
61
61
  self._gforce: GForce = None
62
62
  self._data_event_loop: asyncio.AbstractEventLoop = None
63
63
  self._event_loop: asyncio.AbstractEventLoop = None
64
+ self._is_starting = False
65
+ self._is_setting_param = False
64
66
 
65
67
  def __del__(self) -> None:
66
68
  """
@@ -239,6 +241,8 @@ class SensorProfile:
239
241
  self._data_ctx = SensorProfileDataCtx(self._gforce, self._device.Address, self._raw_data_buf)
240
242
  if self._data_ctx.isUniversalStream:
241
243
  async_exec(self._process_universal_data())
244
+ else:
245
+ async_exec(self._process_data())
242
246
 
243
247
  if self.deviceState == DeviceStateEx.Connected or self.deviceState == DeviceStateEx.Ready:
244
248
  return True
@@ -288,7 +292,7 @@ class SensorProfile:
288
292
  return await async_call(self._connect())
289
293
 
290
294
  async def _waitForDisconnect(self) -> bool:
291
- while self.deviceState != DeviceStateEx.Disconnected:
295
+ while not utils._terminated and self.deviceState != DeviceStateEx.Disconnected:
292
296
  await asyncio.sleep(1)
293
297
  return True
294
298
 
@@ -341,11 +345,13 @@ class SensorProfile:
341
345
  if self._data_event_loop == None:
342
346
  self._data_event_loop = asyncio.new_event_loop()
343
347
 
344
- result = await self._data_ctx.start_streaming()
348
+ self._raw_data_buf.queue.clear()
345
349
  self._data_buffer.queue.clear()
346
- self._data_ctx.clear()
347
- if not self._data_ctx.isUniversalStream:
348
- async_exec(self._process_data())
350
+
351
+ result = await self._data_ctx.start_streaming()
352
+ await asyncio.sleep(0.2)
353
+
354
+ self._is_starting = False
349
355
  return result
350
356
 
351
357
  def startDataNotification(self) -> bool:
@@ -355,6 +361,10 @@ class SensorProfile:
355
361
  :return: bool: 如果开始数据通知成功,返回 True;否则返回 False。
356
362
 
357
363
  """
364
+ if self._is_starting:
365
+ return False
366
+
367
+ self._is_starting = True
358
368
  return sync_call(self._startDataNotification())
359
369
 
360
370
  async def asyncStartDataNotification(self) -> bool:
@@ -364,6 +374,10 @@ class SensorProfile:
364
374
  :return: bool: 如果开始数据通知成功,返回 True;否则返回 False。
365
375
 
366
376
  """
377
+ if self._is_starting:
378
+ return False
379
+
380
+ self._is_starting = True
367
381
  return await async_call(self._startDataNotification())
368
382
 
369
383
  async def _stopDataNotification(self) -> bool:
@@ -377,7 +391,9 @@ class SensorProfile:
377
391
  if not self._data_ctx.isDataTransfering:
378
392
  return True
379
393
 
380
- return not await self._data_ctx.stop_streaming()
394
+ result = await self._data_ctx.stop_streaming()
395
+ self._is_starting = False
396
+ return not result
381
397
 
382
398
  def stopDataNotification(self) -> bool:
383
399
  """
@@ -386,6 +402,10 @@ class SensorProfile:
386
402
  :return: bool: 如果停止数据通知成功,返回 True;否则返回 False。
387
403
 
388
404
  """
405
+ if self._is_starting:
406
+ return False
407
+
408
+ self._is_starting = True
389
409
  return sync_call(self._stopDataNotification())
390
410
 
391
411
  async def asyncStopDataNotification(self) -> bool:
@@ -395,6 +415,10 @@ class SensorProfile:
395
415
  :return: bool: 如果停止数据通知成功,返回 True;否则返回 False。
396
416
 
397
417
  """
418
+ if self._is_starting:
419
+ return False
420
+
421
+ self._is_starting = True
398
422
  return await async_call(self._stopDataNotification())
399
423
 
400
424
  async def _refresh_power(self):
@@ -474,21 +498,35 @@ class SensorProfile:
474
498
  return None
475
499
 
476
500
  async def _setParam(self, key: str, value: str) -> str:
501
+ result = "Error: Not supported"
477
502
  if self.deviceState != DeviceStateEx.Ready:
478
- return "Please connect first"
503
+ result = "Error: Please connect first"
479
504
 
480
505
  if key in ["NTF_EMG", "NTF_EEG", "NTF_ECG", "NTF_IMU", "NTF_BRTH"]:
481
506
  if value in ["ON", "OFF"]:
482
507
  self._data_ctx.init_map[key] = value
483
- return "OK"
508
+ result = "OK"
484
509
 
485
510
  if key in ["FILTER_50Hz", "FILTER_60Hz", "FILTER_HPF", "FILTER_LPF"]:
486
511
  if value in ["ON", "OFF"]:
487
- return await self._data_ctx.setFilter(key, value)
512
+ needPauseTransfer = self.isDataTransfering
513
+ if needPauseTransfer:
514
+ if self._is_starting:
515
+ self._is_setting_param = False
516
+ return "Error: Please pause data transfer first"
517
+
518
+ self._is_starting = True
519
+ await self._stopDataNotification()
520
+ result = await self._data_ctx.setFilter(key, value)
521
+ if needPauseTransfer:
522
+ self._is_starting = True
523
+ await self._startDataNotification()
488
524
 
489
525
  if key == "DEBUG_BLE_DATA_PATH":
490
- return await self._data_ctx.setDebugCSV(value)
491
- return "Not supported"
526
+ result = await self._data_ctx.setDebugCSV(value)
527
+
528
+ self._is_setting_param = False
529
+ return result
492
530
 
493
531
  def setParam(self, key: str, value: str) -> str:
494
532
  """
@@ -500,6 +538,10 @@ class SensorProfile:
500
538
  :return: str: 设置参数的结果。
501
539
 
502
540
  """
541
+ if self._is_setting_param:
542
+ return "Error: Please wait for the previous operation to complete"
543
+
544
+ self._is_setting_param = True
503
545
  return sync_call(
504
546
  self._setParam(key, value),
505
547
  20,
@@ -515,6 +557,10 @@ class SensorProfile:
515
557
  :return: str: 设置参数的结果。
516
558
 
517
559
  """
560
+ if self._is_setting_param:
561
+ return "Error: Please wait for the previous operation to complete"
562
+
563
+ self._is_setting_param = True
518
564
  return await async_call(
519
565
  self._setParam(key, value),
520
566
  20,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: sensor-sdk
3
- Version: 0.0.13
3
+ Version: 0.0.15
4
4
  Summary: Python sdk for Synchroni
5
5
  Home-page: https://github.com/oymotion/SynchroniSDKPython
6
6
  Author: Martin Ye
@@ -8,7 +8,7 @@ with open(os.path.join(this_directory, "README.md"), "r", encoding="utf-8") as f
8
8
 
9
9
  setup(
10
10
  name="sensor-sdk",
11
- version="0.0.13",
11
+ version="0.0.15",
12
12
  description="Python sdk for Synchroni",
13
13
  long_description=long_description,
14
14
  long_description_content_type="text/markdown",
File without changes
File without changes
File without changes