sensor-sdk 0.0.10__py3-none-any.whl → 0.0.13__py3-none-any.whl

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/gforce.py CHANGED
@@ -103,6 +103,8 @@ class Command(IntEnum):
103
103
  CMD_GET_BLE_MTU_INFO = (0xAE,)
104
104
  CMD_GET_BRT_CONFIG = (0xB3,)
105
105
 
106
+ CMD_SET_FRIMWARE_FILTER_SWITCH = (0xAA,)
107
+ CMD_GET_FRIMWARE_FILTER_SWITCH = (0xA9,)
106
108
  # Partial command packet, format: [CMD_PARTIAL_DATA, packet number in reverse order, packet content]
107
109
  MD_PARTIAL_DATA = 0xFF
108
110
 
@@ -737,6 +739,15 @@ class GForce:
737
739
  )
738
740
  )
739
741
 
742
+ async def set_firmware_filter_switch(self, switchStatus: int):
743
+ body = [0xFF & switchStatus]
744
+ body = bytes(body)
745
+ await self._send_request(Request(cmd=Command.CMD_SET_FRIMWARE_FILTER_SWITCH, body=body, has_res=True))
746
+
747
+ async def get_firmware_filter_switch(self):
748
+ buf = await self._send_request(Request(cmd=Command.CMD_GET_FRIMWARE_FILTER_SWITCH, has_res=True))
749
+ return buf[0]
750
+
740
751
  async def set_emg_raw_data_config(self, cfg=EmgRawDataConfig()):
741
752
  body = cfg.to_bytes()
742
753
  await self._send_request(
@@ -1,10 +1,12 @@
1
1
  import asyncio
2
2
  from collections import deque
3
+ import os
3
4
  import platform
4
5
  from queue import Queue
5
6
  import struct
6
7
  from typing import Deque, List
7
-
8
+ from concurrent.futures import ThreadPoolExecutor
9
+ import csv
8
10
  from sensor import utils
9
11
  from sensor.gforce import DataSubscription, GForce
10
12
  from sensor.sensor_data import DataType, Sample, SensorData
@@ -56,9 +58,16 @@ class SensorProfileDataCtx:
56
58
  self.sensorDatas.append(SensorData())
57
59
  self.impedanceData: List[float] = list()
58
60
  self.saturationData: List[float] = list()
61
+ self.dataPool = ThreadPoolExecutor(1, "data")
62
+ self.init_map = {"NTF_EMG": "ON", "NTF_EEG": "ON", "NTF_ECG": "ON", "NTF_IMU": "ON", "NTF_BRTH": "ON"}
63
+ self.filter_map = {"FILTER_50Hz": "ON", "FILTER_60Hz": "ON", "FILTER_HPF": "ON", "FILTER_LPF": "ON"}
64
+ self.debugCSVWriter = None
65
+ self.debugCSVPath = None
59
66
 
60
67
  def close(self):
61
68
  self._is_running = False
69
+ if self.debugCSVWriter != None:
70
+ self.debugCSVWriter = None
62
71
 
63
72
  def clear(self):
64
73
  for sensorData in self.sensorDatas:
@@ -225,22 +234,22 @@ class SensorProfileDataCtx:
225
234
  if self.hasImpedance():
226
235
  self.notifyDataFlag |= DataSubscription.DNF_IMPEDANCE
227
236
 
228
- if self.hasEEG():
237
+ if self.hasEEG() & (self.init_map["NTF_EEG"] == "ON"):
229
238
  # print("initEEG")
230
239
  info.EegChannelCount = await self.initEEG(packageCount)
231
240
  info.EegSampleRate = self.sensorDatas[SensorDataType.DATA_TYPE_EEG].sampleRate
232
241
 
233
- if self.hasECG():
242
+ if self.hasECG() & (self.init_map["NTF_ECG"] == "ON"):
234
243
  # print("initECG")
235
244
  info.EcgChannelCount = await self.initECG(packageCount)
236
245
  info.EcgSampleRate = self.sensorDatas[SensorDataType.DATA_TYPE_ECG].sampleRate
237
246
 
238
- if self.hasBrth():
247
+ if self.hasBrth() & (self.init_map["NTF_BRTH"] == "ON"):
239
248
  # print("initBrth")
240
249
  info.BrthChannelCount = await self.initBrth(packageCount)
241
250
  info.BrthSampleRate = self.sensorDatas[SensorDataType.DATA_TYPE_BRTH].sampleRate
242
251
 
243
- if self.hasIMU():
252
+ if self.hasIMU() & (self.init_map["NTF_IMU"] == "ON"):
244
253
  # print("initIMU")
245
254
  imuChannelCount = await self.initIMU(packageCount)
246
255
  info.AccChannelCount = imuChannelCount
@@ -285,9 +294,47 @@ class SensorProfileDataCtx:
285
294
  await self.gForce.set_subscription(0)
286
295
  return True
287
296
 
297
+ async def setFilter(self, filter: str, value: str) -> str:
298
+ self.filter_map[filter] = value
299
+ switch = 0
300
+ for filter in self.filter_map.keys():
301
+ value = self.filter_map[filter]
302
+ if filter == "FILTER_50Hz":
303
+ if value == "ON":
304
+ switch |= 1
305
+ elif filter == "FILTER_60Hz":
306
+ if value == "ON":
307
+ switch |= 2
308
+ elif filter == "FILTER_HPF":
309
+ if value == "ON":
310
+ switch |= 4
311
+ elif filter == "FILTER_LPF":
312
+ if value == "ON":
313
+ switch |= 8
314
+ try:
315
+ await self.gForce.set_firmware_filter_switch(switch)
316
+ return "OK"
317
+ except Exception as e:
318
+ return "ERROR: " + str(e)
319
+
320
+ async def setDebugCSV(self, debugFilePath) -> str:
321
+ if self.debugCSVWriter != None:
322
+ self.debugCSVWriter = None
323
+ if debugFilePath != None:
324
+ self.debugCSVPath = debugFilePath
325
+ try:
326
+ if self.debugCSVPath != "":
327
+ CSVWriter = csv.writer(open(self.debugCSVPath, "w", newline=""), delimiter=",")
328
+ CSVWriter = None
329
+ except Exception as e:
330
+ return "ERROR: " + str(e)
331
+ return "OK"
332
+
333
+ ####################################################################################
334
+
288
335
  async def process_data(self, buf: Queue[SensorData], sensor, callback):
289
336
  while self._is_running and self._rawDataBuffer.empty():
290
- await asyncio.sleep(0.01)
337
+ await asyncio.sleep(0.1)
291
338
 
292
339
  while self._is_running and not self._rawDataBuffer.empty():
293
340
  try:
@@ -306,7 +353,7 @@ class SensorProfileDataCtx:
306
353
  break
307
354
  if sensorData != None and callback != None:
308
355
  try:
309
- asyncio.get_event_loop().run_in_executor(None, callback, sensor, sensorData)
356
+ asyncio.get_event_loop().run_in_executor(self.dataPool, callback, sensor, sensorData)
310
357
  except Exception as e:
311
358
  print(e)
312
359
 
@@ -525,6 +572,31 @@ class SensorProfileDataCtx:
525
572
  sensorDataResult.minPackageSampleCount = sensorData.minPackageSampleCount
526
573
  sensorDataList.append(sensorDataResult)
527
574
 
575
+ if self.debugCSVPath != None and self.debugCSVPath != "" and self.debugCSVWriter == None:
576
+ try:
577
+ self.debugCSVWriter = csv.writer(open(self.debugCSVPath, "w", newline="", encoding="utf-8"))
578
+ header_append_keys = ["dataType", "sampleRate"]
579
+ channel_samples_header = list(vars(sensorDataResult.channelSamples[0][0]).keys())
580
+ for key_item in header_append_keys:
581
+ channel_samples_header.append(key_item)
582
+ self.debugCSVWriter.writerow(channel_samples_header)
583
+ except Exception as e:
584
+ print(e)
585
+
586
+ if self.debugCSVWriter != None:
587
+ try:
588
+ for i, channel_sample_list in enumerate(sensorDataResult.channelSamples):
589
+ for channel_sample in channel_sample_list:
590
+ row_data = []
591
+
592
+ for key in vars(channel_sample).keys():
593
+ row_data.append(getattr(channel_sample, key))
594
+ row_data.append(sensorDataResult.dataType)
595
+ row_data.append(sensorDataResult.sampleRate)
596
+ self.debugCSVWriter.writerow(row_data)
597
+ except Exception as e:
598
+ print(e)
599
+
528
600
  startIndex += sensorData.minPackageSampleCount
529
601
 
530
602
  leftChannelSamples = []
@@ -545,7 +617,7 @@ class SensorProfileDataCtx:
545
617
 
546
618
  while self._is_running:
547
619
  while self._is_running and self._rawDataBuffer.empty():
548
- await asyncio.sleep(0.01)
620
+ await asyncio.sleep(0.1)
549
621
  continue
550
622
 
551
623
  try:
@@ -588,7 +660,7 @@ class SensorProfileDataCtx:
588
660
  break
589
661
  if sensorData != None and callback != None:
590
662
  try:
591
- asyncio.get_event_loop().run_in_executor(None, callback, sensor, sensorData)
663
+ asyncio.get_event_loop().run_in_executor(self.dataPool, callback, sensor, sensorData)
592
664
  except Exception as e:
593
665
  print(e)
594
666
 
sensor/sensor_profile.py CHANGED
@@ -18,7 +18,7 @@ import asyncio
18
18
 
19
19
  from sensor.sensor_data_context import SensorProfileDataCtx
20
20
  from sensor.sensor_device import BLEDevice, DeviceInfo, DeviceStateEx
21
- from sensor.utils import async_call, sync_call, async_exec, timer
21
+ from sensor.utils import async_call, sync_call, async_exec
22
22
 
23
23
  SERVICE_GUID = "0000ffd0-0000-1000-8000-00805f9b34fb"
24
24
  OYM_CMD_NOTIFY_CHAR_UUID = "f000ffe1-0451-4000-b000-000000000000"
@@ -289,7 +289,7 @@ class SensorProfile:
289
289
 
290
290
  async def _waitForDisconnect(self) -> bool:
291
291
  while self.deviceState != DeviceStateEx.Disconnected:
292
- asyncio.sleep(1)
292
+ await asyncio.sleep(1)
293
293
  return True
294
294
 
295
295
  async def _disconnect(self) -> bool:
@@ -473,6 +473,23 @@ class SensorProfile:
473
473
  return self._data_ctx._device_info
474
474
  return None
475
475
 
476
+ async def _setParam(self, key: str, value: str) -> str:
477
+ if self.deviceState != DeviceStateEx.Ready:
478
+ return "Please connect first"
479
+
480
+ if key in ["NTF_EMG", "NTF_EEG", "NTF_ECG", "NTF_IMU", "NTF_BRTH"]:
481
+ if value in ["ON", "OFF"]:
482
+ self._data_ctx.init_map[key] = value
483
+ return "OK"
484
+
485
+ if key in ["FILTER_50Hz", "FILTER_60Hz", "FILTER_HPF", "FILTER_LPF"]:
486
+ if value in ["ON", "OFF"]:
487
+ return await self._data_ctx.setFilter(key, value)
488
+
489
+ if key == "DEBUG_BLE_DATA_PATH":
490
+ return await self._data_ctx.setDebugCSV(value)
491
+ return "Not supported"
492
+
476
493
  def setParam(self, key: str, value: str) -> str:
477
494
  """
478
495
  设置传感器的参数。
@@ -483,9 +500,12 @@ class SensorProfile:
483
500
  :return: str: 设置参数的结果。
484
501
 
485
502
  """
486
- return ""
503
+ return sync_call(
504
+ self._setParam(key, value),
505
+ 20,
506
+ )
487
507
 
488
- async def AsyncSetParam(self, key: str, value: str) -> str:
508
+ async def asyncSetParam(self, key: str, value: str) -> str:
489
509
  """
490
510
  设置传感器的参数。
491
511
 
@@ -495,4 +515,7 @@ class SensorProfile:
495
515
  :return: str: 设置参数的结果。
496
516
 
497
517
  """
498
- return ""
518
+ return await async_call(
519
+ self._setParam(key, value),
520
+ 20,
521
+ )
sensor/utils.py CHANGED
@@ -37,30 +37,6 @@ def Terminate():
37
37
  pass
38
38
 
39
39
 
40
- async def delay(_time: float, function) -> any:
41
- try:
42
- await asyncio.sleep(_time)
43
- except Exception as e:
44
- pass
45
-
46
- try:
47
- return await function
48
- except Exception as e:
49
- pass
50
-
51
-
52
- def timer(_delay: float, function):
53
- checkRunLoop()
54
- task: asyncio.Future = None
55
- try:
56
- task = asyncio.run_coroutine_threadsafe(delay(_delay, function), _runloop)
57
- running_tasks.add(task)
58
- task.add_done_callback(lambda t: running_tasks.remove(t))
59
- except Exception as e:
60
- print(e)
61
- pass
62
-
63
-
64
40
  def async_exec(function):
65
41
  checkRunLoop()
66
42
  task: asyncio.Future = None
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: sensor-sdk
3
- Version: 0.0.10
3
+ Version: 0.0.13
4
4
  Summary: Python sdk for Synchroni
5
5
  Home-page: https://github.com/oymotion/SynchroniSDKPython
6
6
  Author: Martin Ye
@@ -350,8 +350,47 @@ batteryPower = sensorProfile.getBatteryLevel()
350
350
 
351
351
  Please check console.py in examples directory
352
352
 
353
- ## Async methods
353
+ ### Async methods
354
354
 
355
355
  all methods start with async is async methods, they has same params and return result as sync methods.
356
356
 
357
357
  Please check async_console.py in examples directory
358
+
359
+ ### setParam method
360
+
361
+ Use `def setParam(self, key: str, value: str) -> str` to set parameter of sensor profile. Please call after device in 'Ready' state.
362
+
363
+ Below is available key and value:
364
+
365
+ ```python
366
+ result = sensorProfile.setParam("NTF_EMG", "ON")
367
+ # set EMG data to ON or OFF, result is "OK" if succeed
368
+
369
+ result = sensorProfile.setParam("NTF_EEG", "ON")
370
+ # set EEG data to ON or OFF, result is "OK" if succeed
371
+
372
+ result = sensorProfile.setParam("NTF_ECG", "ON")
373
+ # set ECG data to ON or OFF, result is "OK" if succeed
374
+
375
+ result = sensorProfile.setParam("NTF_IMU", "ON")
376
+ # set IMU data to ON or OFF, result is "OK" if succeed
377
+
378
+ result = sensorProfile.setParam("NTF_BRTH", "ON")
379
+ # set BRTH data to ON or OFF, result is "OK" if succeed
380
+
381
+ result = sensorProfile.setParam("FILTER_50Hz", "ON")
382
+ # set 50Hz notch filter to ON or OFF, result is "OK" if succeed
383
+
384
+ result = sensorProfile.setParam("FILTER_60Hz", "ON")
385
+ # set 60Hz notch filter to ON or OFF, result is "OK" if succeed
386
+
387
+ result = sensorProfile.setParam("FILTER_HPF", "ON")
388
+ # set 0.5Hz hpf filter to ON or OFF, result is "OK" if succeed
389
+
390
+ result = sensorProfile.setParam("FILTER_LPF", "ON")
391
+ # set 80Hz lpf filter to ON or OFF, result is "OK" if succeed
392
+
393
+ result = sensorProfile.setParam("DEBUG_BLE_DATA_PATH", "d:/temp/test.csv")
394
+ # set debug ble data path, result is "OK" if succeed
395
+ # please give an absolute path and make sure it is valid and writeable by yourself
396
+ ```
@@ -0,0 +1,14 @@
1
+ sensor/__init__.py,sha256=L1VyAP0EDEnJIMeMTzp4iXHSRUUHyHScF_GIl3iYKRI,123
2
+ sensor/gforce.py,sha256=QsbHhTieVKMJ_KHn7nEchh7sChZWL-iSP0LmfxhYYXw,25753
3
+ sensor/sensor_controller.py,sha256=qnM9mVwpJn9PCnxlvbgWFeaLktqVnmaquZgasYGEHqs,9451
4
+ sensor/sensor_data.py,sha256=Hu7Ql0LgQ7V24xYZhaLrKPwU4KWZeWE655v8Gy8xphY,3934
5
+ sensor/sensor_data_context.py,sha256=a45WJPE-8-CzzMn9BlCjjC39fiIxkjV-UQw2Rok-OyM,28536
6
+ sensor/sensor_device.py,sha256=eO1vaqjxCc2UCPBoKXqlk6o498uRyWt6IYs7r7wXSD0,3042
7
+ sensor/sensor_profile.py,sha256=qxjTYt7X45rmVcapI93ynB4dTFLLt0M-WKCp-cpqKrM,18167
8
+ sensor/utils.py,sha256=BudTD083ucGxcTXfmksF-2gLRi_i-k7tMytruLUUKJc,6503
9
+ sensor_sdk-0.0.13.dist-info/LICENSE.txt,sha256=8CSivOpub3IuXODTyqBRI91AxouJZk02YrcKuOAkWu8,1111
10
+ sensor_sdk-0.0.13.dist-info/METADATA,sha256=6hKH69-rbvoswQ9LGvPVcGiY0v8qKKN9rfiVXjX0hLs,9825
11
+ sensor_sdk-0.0.13.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
12
+ sensor_sdk-0.0.13.dist-info/top_level.txt,sha256=Ftq49B6bH0Ffdc7c8LkcyakHo6lsg_snlBbpEUoILSk,7
13
+ sensor_sdk-0.0.13.dist-info/zip-safe,sha256=frcCV1k9oG9oKj3dpUqdJg1PxRT2RSN_XKdLCPjaYaY,2
14
+ sensor_sdk-0.0.13.dist-info/RECORD,,
@@ -1,14 +0,0 @@
1
- sensor/__init__.py,sha256=L1VyAP0EDEnJIMeMTzp4iXHSRUUHyHScF_GIl3iYKRI,123
2
- sensor/gforce.py,sha256=mTw0VVQSxPiTzZmjK7I9knTlTkEeu4PISQdlAkMU6WE,25232
3
- sensor/sensor_controller.py,sha256=qnM9mVwpJn9PCnxlvbgWFeaLktqVnmaquZgasYGEHqs,9451
4
- sensor/sensor_data.py,sha256=Hu7Ql0LgQ7V24xYZhaLrKPwU4KWZeWE655v8Gy8xphY,3934
5
- sensor/sensor_data_context.py,sha256=9IvXAHhCSQGnkNW5nFNz4Rs6kVq1hEyxxu6ROKjb-Dk,25033
6
- sensor/sensor_device.py,sha256=eO1vaqjxCc2UCPBoKXqlk6o498uRyWt6IYs7r7wXSD0,3042
7
- sensor/sensor_profile.py,sha256=64MFNyLJajX6HeGS_tmN9R9wfEW1qjsP_MjH3ZRPq4s,17322
8
- sensor/utils.py,sha256=FuBEChpJYbXnUaDvlta3aT6dYGAK2fQdGbIB7BYMQp4,7077
9
- sensor_sdk-0.0.10.dist-info/LICENSE.txt,sha256=8CSivOpub3IuXODTyqBRI91AxouJZk02YrcKuOAkWu8,1111
10
- sensor_sdk-0.0.10.dist-info/METADATA,sha256=OjhjiuAo0t9cgFCyuIC-5PB_O7KTi8duBZz-H2RCTAw,8375
11
- sensor_sdk-0.0.10.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
12
- sensor_sdk-0.0.10.dist-info/top_level.txt,sha256=Ftq49B6bH0Ffdc7c8LkcyakHo6lsg_snlBbpEUoILSk,7
13
- sensor_sdk-0.0.10.dist-info/zip-safe,sha256=frcCV1k9oG9oKj3dpUqdJg1PxRT2RSN_XKdLCPjaYaY,2
14
- sensor_sdk-0.0.10.dist-info/RECORD,,