sensor-sdk 0.0.11__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,11 +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
8
-
9
+ import csv
9
10
  from sensor import utils
10
11
  from sensor.gforce import DataSubscription, GForce
11
12
  from sensor.sensor_data import DataType, Sample, SensorData
@@ -58,9 +59,15 @@ class SensorProfileDataCtx:
58
59
  self.impedanceData: List[float] = list()
59
60
  self.saturationData: List[float] = list()
60
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
61
66
 
62
67
  def close(self):
63
68
  self._is_running = False
69
+ if self.debugCSVWriter != None:
70
+ self.debugCSVWriter = None
64
71
 
65
72
  def clear(self):
66
73
  for sensorData in self.sensorDatas:
@@ -227,22 +234,22 @@ class SensorProfileDataCtx:
227
234
  if self.hasImpedance():
228
235
  self.notifyDataFlag |= DataSubscription.DNF_IMPEDANCE
229
236
 
230
- if self.hasEEG():
237
+ if self.hasEEG() & (self.init_map["NTF_EEG"] == "ON"):
231
238
  # print("initEEG")
232
239
  info.EegChannelCount = await self.initEEG(packageCount)
233
240
  info.EegSampleRate = self.sensorDatas[SensorDataType.DATA_TYPE_EEG].sampleRate
234
241
 
235
- if self.hasECG():
242
+ if self.hasECG() & (self.init_map["NTF_ECG"] == "ON"):
236
243
  # print("initECG")
237
244
  info.EcgChannelCount = await self.initECG(packageCount)
238
245
  info.EcgSampleRate = self.sensorDatas[SensorDataType.DATA_TYPE_ECG].sampleRate
239
246
 
240
- if self.hasBrth():
247
+ if self.hasBrth() & (self.init_map["NTF_BRTH"] == "ON"):
241
248
  # print("initBrth")
242
249
  info.BrthChannelCount = await self.initBrth(packageCount)
243
250
  info.BrthSampleRate = self.sensorDatas[SensorDataType.DATA_TYPE_BRTH].sampleRate
244
251
 
245
- if self.hasIMU():
252
+ if self.hasIMU() & (self.init_map["NTF_IMU"] == "ON"):
246
253
  # print("initIMU")
247
254
  imuChannelCount = await self.initIMU(packageCount)
248
255
  info.AccChannelCount = imuChannelCount
@@ -287,9 +294,47 @@ class SensorProfileDataCtx:
287
294
  await self.gForce.set_subscription(0)
288
295
  return True
289
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
+
290
335
  async def process_data(self, buf: Queue[SensorData], sensor, callback):
291
336
  while self._is_running and self._rawDataBuffer.empty():
292
- await asyncio.sleep(0.01)
337
+ await asyncio.sleep(0.1)
293
338
 
294
339
  while self._is_running and not self._rawDataBuffer.empty():
295
340
  try:
@@ -527,6 +572,31 @@ class SensorProfileDataCtx:
527
572
  sensorDataResult.minPackageSampleCount = sensorData.minPackageSampleCount
528
573
  sensorDataList.append(sensorDataResult)
529
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
+
530
600
  startIndex += sensorData.minPackageSampleCount
531
601
 
532
602
  leftChannelSamples = []
@@ -547,7 +617,7 @@ class SensorProfileDataCtx:
547
617
 
548
618
  while self._is_running:
549
619
  while self._is_running and self._rawDataBuffer.empty():
550
- await asyncio.sleep(0.01)
620
+ await asyncio.sleep(0.1)
551
621
  continue
552
622
 
553
623
  try:
@@ -611,7 +681,7 @@ class SensorProfileDataCtx:
611
681
  index += 1
612
682
  continue
613
683
  data_package = bytes(self._concatDataBuffer[index + 2 : index + 2 + n])
614
- asyncio.get_event_loop().run_in_executor(self.dataPool, self.gForce._on_cmd_response, None, data_package)
684
+ asyncio.get_event_loop().run_in_executor(None, self.gForce._on_cmd_response, None, data_package)
615
685
  last_cut = index = index + 2 + n
616
686
 
617
687
  else:
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.11
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=Mlq0Bflnf6Lmj9cf7ccXYnjKldKD4pM9_x1GcgFynEs,25166
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.11.dist-info/LICENSE.txt,sha256=8CSivOpub3IuXODTyqBRI91AxouJZk02YrcKuOAkWu8,1111
10
- sensor_sdk-0.0.11.dist-info/METADATA,sha256=VMpmAjRXMlk8u-UnHu_QrXULi0-YMxSdRSGDwPmCdPs,8375
11
- sensor_sdk-0.0.11.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
12
- sensor_sdk-0.0.11.dist-info/top_level.txt,sha256=Ftq49B6bH0Ffdc7c8LkcyakHo6lsg_snlBbpEUoILSk,7
13
- sensor_sdk-0.0.11.dist-info/zip-safe,sha256=frcCV1k9oG9oKj3dpUqdJg1PxRT2RSN_XKdLCPjaYaY,2
14
- sensor_sdk-0.0.11.dist-info/RECORD,,