sensor-sdk 0.2.1__tar.gz → 0.2.2__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.
Files changed (29) hide show
  1. {sensor_sdk-0.2.1/sensor_sdk.egg-info → sensor_sdk-0.2.2}/PKG-INFO +1 -1
  2. {sensor_sdk-0.2.1 → sensor_sdk-0.2.2}/sensor/bleak_process.py +26 -4
  3. {sensor_sdk-0.2.1 → sensor_sdk-0.2.2}/sensor/sensor_data_context.py +11 -1
  4. {sensor_sdk-0.2.1 → sensor_sdk-0.2.2}/sensor/sensor_profile.py +34 -1
  5. {sensor_sdk-0.2.1 → sensor_sdk-0.2.2/sensor_sdk.egg-info}/PKG-INFO +1 -1
  6. {sensor_sdk-0.2.1 → sensor_sdk-0.2.2}/setup.py +1 -1
  7. {sensor_sdk-0.2.1 → sensor_sdk-0.2.2}/LICENSE.txt +0 -0
  8. {sensor_sdk-0.2.1 → sensor_sdk-0.2.2}/README.md +0 -0
  9. {sensor_sdk-0.2.1 → sensor_sdk-0.2.2}/sensor/__init__.py +0 -0
  10. {sensor_sdk-0.2.1 → sensor_sdk-0.2.2}/sensor/bleak_host.py +0 -0
  11. {sensor_sdk-0.2.1 → sensor_sdk-0.2.2}/sensor/bleak_no_ack_patch.py +0 -0
  12. {sensor_sdk-0.2.1 → sensor_sdk-0.2.2}/sensor/fb/DataType.py +0 -0
  13. {sensor_sdk-0.2.1 → sensor_sdk-0.2.2}/sensor/fb/Sample.py +0 -0
  14. {sensor_sdk-0.2.1 → sensor_sdk-0.2.2}/sensor/fb/SensorData.py +0 -0
  15. {sensor_sdk-0.2.1 → sensor_sdk-0.2.2}/sensor/fb/__init__.py +0 -0
  16. {sensor_sdk-0.2.1 → sensor_sdk-0.2.2}/sensor/gforce.py +0 -0
  17. {sensor_sdk-0.2.1 → sensor_sdk-0.2.2}/sensor/sdk_log.py +0 -0
  18. {sensor_sdk-0.2.1 → sensor_sdk-0.2.2}/sensor/sensor_controller.py +0 -0
  19. {sensor_sdk-0.2.1 → sensor_sdk-0.2.2}/sensor/sensor_data.py +0 -0
  20. {sensor_sdk-0.2.1 → sensor_sdk-0.2.2}/sensor/sensor_data_pool.py +0 -0
  21. {sensor_sdk-0.2.1 → sensor_sdk-0.2.2}/sensor/sensor_device.py +0 -0
  22. {sensor_sdk-0.2.1 → sensor_sdk-0.2.2}/sensor/sensor_utils.py +0 -0
  23. {sensor_sdk-0.2.1 → sensor_sdk-0.2.2}/sensor/winrt_high_throughput.py +0 -0
  24. {sensor_sdk-0.2.1 → sensor_sdk-0.2.2}/sensor_sdk.egg-info/SOURCES.txt +0 -0
  25. {sensor_sdk-0.2.1 → sensor_sdk-0.2.2}/sensor_sdk.egg-info/dependency_links.txt +0 -0
  26. {sensor_sdk-0.2.1 → sensor_sdk-0.2.2}/sensor_sdk.egg-info/requires.txt +0 -0
  27. {sensor_sdk-0.2.1 → sensor_sdk-0.2.2}/sensor_sdk.egg-info/top_level.txt +0 -0
  28. {sensor_sdk-0.2.1 → sensor_sdk-0.2.2}/sensor_sdk.egg-info/zip-safe +0 -0
  29. {sensor_sdk-0.2.1 → sensor_sdk-0.2.2}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sensor-sdk
3
- Version: 0.2.1
3
+ Version: 0.2.2
4
4
  Summary: Python sdk for Synchroni
5
5
  Home-page: https://github.com/oymotion/SynchroniSDKPython
6
6
  Author: Martin Ye
@@ -30,6 +30,16 @@ _MAX_RECONNECT_ATTEMPTS = 5
30
30
  _RECONNECT_DELAY_SECONDS = 1.0
31
31
 
32
32
 
33
+ def _is_core_bluetooth(client) -> bool:
34
+ """判断 bleak 当前是否使用 macOS CoreBluetooth 后端。"""
35
+ if client is None:
36
+ return False
37
+ backend = getattr(client, "_backend", None)
38
+ if backend is None:
39
+ return False
40
+ return "corebluetooth" in type(backend).__module__.lower()
41
+
42
+
33
43
  def _extract_mac(_device: bleak.BLEDevice, adv: AdvertisementData) -> str:
34
44
 
35
45
  mac = None
@@ -98,6 +108,7 @@ class BleakProcess(multiprocessing.Process):
98
108
  self._data_tasks: dict = {} # mac -> asyncio.Task
99
109
  self._battery_tasks: dict = {} # mac -> asyncio.Task
100
110
  self._reconnect_info: dict = {} # mac -> {cmd, attempts, task, normal_disconnect}
111
+ self._restore_info: dict = {} # mac -> {package_sample_count, power_refresh_interval, streaming}
101
112
  self._main_event_loop = None # BleakProcess 主事件循环
102
113
 
103
114
  # Per-device event loops and threads
@@ -1341,15 +1352,26 @@ class BleakProcess(multiprocessing.Process):
1341
1352
 
1342
1353
  if needs_restart or oym_needs_subscribe:
1343
1354
  try:
1344
- if was_streaming:
1355
+ is_oym = ctx.getChipType() == BLEChipType.OYM
1356
+ # macOS CoreBluetooth 在流传输中 stop_notify 容易导致设备断开,
1357
+ # 因此 OYM 设备在 CoreBluetooth 后端上直接更新订阅掩码,不启停通知。
1358
+ oym_skip_stop_start = is_oym and _is_core_bluetooth(ctx.gForce.client)
1359
+ if oym_skip_stop_start:
1360
+ SdkLog.d(_TAG, f"OYM CoreBluetooth: skip stop/start, set subscription directly for {device_mac}")
1361
+ if was_streaming and not oym_skip_stop_start:
1345
1362
  await ctx.stop_streaming()
1346
- if oym_needs_subscribe and ctx.getChipType() == BLEChipType.OYM:
1363
+ if oym_needs_subscribe and is_oym:
1347
1364
  await ctx.gForce.set_subscription(ctx.notifyDataFlag)
1348
- if was_streaming:
1365
+ if was_streaming and not oym_skip_stop_start:
1349
1366
  await ctx.start_streaming()
1350
1367
  except Exception as e:
1368
+ err_msg = str(e)
1351
1369
  SdkLog.exception(_TAG, f"_do_set_param restart stream failed: {device_mac}")
1352
- result = "ERROR: restart stream fail: " + str(e)
1370
+ result = "ERROR: restart stream fail: " + err_msg
1371
+ # 如果是因为设备已经断开,直接触发自动重连
1372
+ if "disconnected" in err_msg.lower() or "not connected" in err_msg.lower():
1373
+ SdkLog.w(_TAG, f"Device disconnected during setParam restart, scheduling reconnect for {device_mac}")
1374
+ self._schedule_reconnect(device_mac)
1353
1375
 
1354
1376
  if key == "DEBUG_LOG_PATH":
1355
1377
  try:
@@ -714,7 +714,9 @@ class SensorProfileDataCtx:
714
714
  data.clear()
715
715
  self.sensorDatas[SensorDataType.DATA_TYPE_EULER] = data
716
716
 
717
- self.notifyDataFlag |= DataSubscription.DNF_IMU
717
+ # EEG + OYM 设备默认不订阅 IMU
718
+ if not (self._chip_type == BLEChipType.OYM and self.hasEEG()):
719
+ self.notifyDataFlag |= DataSubscription.DNF_IMU
718
720
  if self._device_info is not None:
719
721
  self._device_info.AccChannelCount = 3
720
722
  self._device_info.GyroChannelCount = 3
@@ -870,6 +872,14 @@ class SensorProfileDataCtx:
870
872
  self._device_info = info
871
873
  await self.initDataTransfer(True)
872
874
 
875
+ # EEG + OYM 设备默认关闭 IMU
876
+ if self._chip_type == BLEChipType.OYM and self.hasEEG():
877
+ self.notify_map["NTF_IMU"] = "OFF"
878
+ self.notify_map["NTF_GFORCE_ACC"] = "OFF"
879
+ self.notify_map["NTF_GFORCE_GYRO"] = "OFF"
880
+ self.notify_map["NTF_GFORCE_QUAT"] = "OFF"
881
+ self.notify_map["NTF_GFORCE_EULER"] = "OFF"
882
+
873
883
  if self.hasConcatBLE():
874
884
  self.notifyDataFlag |= DataSubscription.DNF_CONCAT_BLE
875
885
 
@@ -93,6 +93,11 @@ class SensorProfile:
93
93
  self._device_info: Optional[DeviceInfo] = None
94
94
  self._chip_type: BLEChipType = BLEChipType.Unknown
95
95
 
96
+ # 异常断开后自动恢复流状态所需信息
97
+ self._last_init_args: Optional[tuple] = None # (packageSampleCount, powerRefreshInterval)
98
+ self._was_streaming_before_disconnect = False
99
+ self._auto_restoring = False
100
+
96
101
  # 用于在独立线程中执行用户回调,避免阻塞 BLE/数据解析线程
97
102
  # onDataCallback 使用单线程池,保证数据回调严格按到达顺序执行
98
103
  self._callback_executor = ThreadPoolExecutor(max_workers=4)
@@ -222,7 +227,8 @@ class SensorProfile:
222
227
  return self._device_state
223
228
 
224
229
  def _set_device_state(self, newState: DeviceStateEx):
225
- if self._device_state != newState:
230
+ old_state = self._device_state
231
+ if old_state != newState:
226
232
  self._device_state = newState
227
233
  if newState == DeviceStateEx.Disconnected:
228
234
  self._has_inited = False
@@ -235,6 +241,33 @@ class SensorProfile:
235
241
  SdkLog.e(_TAG, f"Error occurred while processing state change: {e}")
236
242
  raise RuntimeError("Set device state %s fail: %s" % (self.BLEDevice.Name , e))
237
243
 
244
+ # 异常断开后重连成功,自动恢复 init + 数据流
245
+ if (newState == DeviceStateEx.Connected
246
+ and old_state == DeviceStateEx.Disconnected
247
+ and self._last_init_args is not None
248
+ and self._was_streaming_before_disconnect
249
+ and not self._auto_restoring):
250
+ SdkLog.i(_TAG, f"Auto-restoring stream state for {self._device_mac}")
251
+ threading.Thread(target=self._auto_restore, daemon=True).start()
252
+
253
+ def _auto_restore(self):
254
+ """在异常断开后自动恢复 init 和数据流。"""
255
+ if self._auto_restoring:
256
+ return
257
+ self._auto_restoring = True
258
+ try:
259
+ package_sample_count, power_refresh_interval = self._last_init_args
260
+ SdkLog.i(_TAG, f"Auto-restore init for {self._device_mac}")
261
+ if self.init(package_sample_count, power_refresh_interval):
262
+ SdkLog.i(_TAG, f"Auto-restore start data notification for {self._device_mac}")
263
+ self.startDataNotification()
264
+ else:
265
+ SdkLog.w(_TAG, f"Auto-restore init failed for {self._device_mac}")
266
+ except Exception as e:
267
+ SdkLog.exception(_TAG, f"Auto-restore failed for {self._device_mac}: {e}")
268
+ finally:
269
+ self._auto_restoring = False
270
+
238
271
  @property
239
272
  def hasInited(self) -> bool:
240
273
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sensor-sdk
3
- Version: 0.2.1
3
+ Version: 0.2.2
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.2.1",
11
+ version="0.2.2",
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
File without changes
File without changes