device-protocol-sdk 1.2.3__tar.gz → 1.2.5__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 (18) hide show
  1. {device_protocol_sdk-1.2.3 → device_protocol_sdk-1.2.5}/PKG-INFO +2 -2
  2. {device_protocol_sdk-1.2.3 → device_protocol_sdk-1.2.5}/device_protocol_sdk/abstract_device.py +5 -0
  3. {device_protocol_sdk-1.2.3 → device_protocol_sdk-1.2.5}/device_protocol_sdk/pusher.py +200 -54
  4. {device_protocol_sdk-1.2.3 → device_protocol_sdk-1.2.5}/device_protocol_sdk.egg-info/PKG-INFO +2 -2
  5. {device_protocol_sdk-1.2.3 → device_protocol_sdk-1.2.5}/device_protocol_sdk.egg-info/requires.txt +1 -1
  6. {device_protocol_sdk-1.2.3 → device_protocol_sdk-1.2.5}/setup.py +2 -2
  7. {device_protocol_sdk-1.2.3 → device_protocol_sdk-1.2.5}/README.md +0 -0
  8. {device_protocol_sdk-1.2.3 → device_protocol_sdk-1.2.5}/device_protocol_sdk/__init__.py +0 -0
  9. {device_protocol_sdk-1.2.3 → device_protocol_sdk-1.2.5}/device_protocol_sdk/device_pb2.py +0 -0
  10. {device_protocol_sdk-1.2.3 → device_protocol_sdk-1.2.5}/device_protocol_sdk/device_pb2_grpc.py +0 -0
  11. {device_protocol_sdk-1.2.3 → device_protocol_sdk-1.2.5}/device_protocol_sdk/model/__init__.py +0 -0
  12. {device_protocol_sdk-1.2.3 → device_protocol_sdk-1.2.5}/device_protocol_sdk/model/action_item.py +0 -0
  13. {device_protocol_sdk-1.2.3 → device_protocol_sdk-1.2.5}/device_protocol_sdk/model/device_key.py +0 -0
  14. {device_protocol_sdk-1.2.3 → device_protocol_sdk-1.2.5}/device_protocol_sdk/model/device_status.py +0 -0
  15. {device_protocol_sdk-1.2.3 → device_protocol_sdk-1.2.5}/device_protocol_sdk.egg-info/SOURCES.txt +0 -0
  16. {device_protocol_sdk-1.2.3 → device_protocol_sdk-1.2.5}/device_protocol_sdk.egg-info/dependency_links.txt +0 -0
  17. {device_protocol_sdk-1.2.3 → device_protocol_sdk-1.2.5}/device_protocol_sdk.egg-info/top_level.txt +0 -0
  18. {device_protocol_sdk-1.2.3 → device_protocol_sdk-1.2.5}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: device_protocol_sdk
3
- Version: 1.2.3
3
+ Version: 1.2.5
4
4
  Summary: 无人设备协议开发SDK
5
5
  Author: fuhl
6
6
  Requires-Python: >=3.8
@@ -10,7 +10,7 @@ Requires-Dist: grpcio-tools>=1.48.2
10
10
  Requires-Dist: paho-mqtt>=1.6.1
11
11
  Requires-Dist: pydantic>=1.9.0
12
12
  Requires-Dist: websockets>=10.0
13
- Requires-Dist: coord-convert>=0.2.1
13
+ Requires-Dist: shapely>=2.1.2
14
14
 
15
15
  # Device Protocol SDK
16
16
 
@@ -138,6 +138,11 @@ class AbstractDevice(ABC):
138
138
  is_connect,client = self._create_client(device_key.device_id,device_key.connection_str)
139
139
  if is_connect:
140
140
  self._connection_pool[device_key] = client
141
+ return is_connect,client
142
+ else:
143
+ client = self._connection_pool[device_key]
144
+ return True,client
145
+
141
146
 
142
147
  def disconnect(self, device_key: DeviceKey):
143
148
  with self._lock:
@@ -8,8 +8,8 @@ import paho.mqtt.client as mqtt
8
8
  from . import device_pb2
9
9
  from . import device_pb2_grpc
10
10
  from .model.device_key import DeviceKey
11
- from coord_convert import transform
12
11
  import math
12
+ from shapely.geometry import Point, Polygon
13
13
 
14
14
  logger = logging.getLogger(__name__)
15
15
 
@@ -223,6 +223,52 @@ class DevicePusher:
223
223
  logger.warning("MQTT连接断开,尝试重新连接...")
224
224
  return await self.setup_mqtt()
225
225
  return True
226
+
227
+ def is_in_china_shapely(self,lon, lat):
228
+ """
229
+ 使用更精确的中国边界判断经纬度是否在中国范围内
230
+ """
231
+ # 更精确的中国边界坐标(包含主要陆地和主要岛屿)
232
+ china_coords = [
233
+ # 中国大陆主要边界点(逆时针)
234
+ (121.612, 25.288), # 台湾东北
235
+ (123.508, 24.445), # 钓鱼岛附近
236
+ (125.341, 24.787), # 东海
237
+ (129.664, 32.792), # 日本海附近
238
+ (130.667, 42.266), # 吉林延边
239
+ (131.283, 44.893), # 吉林珲春
240
+ (134.773, 48.446), # 黑龙江抚远
241
+ (135.092, 47.733), # 黑龙江同江
242
+ (137.437, 53.571), # 外兴安岭附近
243
+ (119.931, 52.117), # 内蒙古满洲里
244
+ (97.234, 42.812), # 甘肃敦煌
245
+ (80.260, 42.215), # 新疆喀什
246
+ (75.996, 39.468), # 新疆塔什库尔干
247
+ (74.890, 37.235), # 新疆红其拉甫
248
+ (78.367, 35.427), # 新疆和田
249
+ (79.722, 34.468), # 西藏阿里
250
+ (81.111, 32.493), # 西藏狮泉河
251
+ (82.567, 31.779), # 西藏改则
252
+ (85.152, 28.547), # 西藏聂拉木
253
+ (86.827, 27.866), # 西藏定结
254
+ (88.916, 27.799), # 西藏亚东
255
+ (91.681, 27.498), # 西藏错那
256
+ (97.352, 28.262), # 云南贡山
257
+ (98.494, 24.846), # 云南瑞丽
258
+ (101.152, 21.485), # 云南西双版纳
259
+ (105.444, 21.531), # 广西那坡
260
+ (108.320, 21.573), # 广西北海
261
+ (110.355, 20.098), # 广东湛江
262
+ (113.823, 22.448), # 香港
263
+ (114.296, 22.808), # 深圳
264
+ (117.367, 23.752), # 台湾海峡
265
+ (121.612, 25.288), # 回到起点
266
+ ]
267
+
268
+ china_polygon = Polygon(china_coords)
269
+ point = Point(lon, lat)
270
+
271
+ return china_polygon.contains(point)
226
272
  async def _report_status_continuously(self,protocol_name, device: 'AbstractDevice', deviceKey: DeviceKey, report_interval=1):
227
273
  """通过MQTT持续上报设备状态"""
228
274
  """通过MQTT持续上报设备状态,状态为空时停止并清理"""
@@ -244,15 +290,32 @@ class DevicePusher:
244
290
  # if not status:
245
291
  # logger.warning(f"设备 {deviceKey} 状态为空")
246
292
  # break
293
+ if status is None:
294
+ logger.warning(f"设备 {deviceKey} 返回状态为 None")
295
+ continue # 跳过这个设备的处理
296
+
297
+ # 添加对 status 是否为可迭代对象的检查
298
+ if not isinstance(status, (list, tuple)):
299
+ logger.warning(f"设备 {deviceKey} 状态格式错误: {type(status)}")
300
+ continue
247
301
 
248
302
  #将status中的gps坐标系转换 WGS84坐标转换为GCJ02坐标
249
303
  for st in status:
250
- if 'lat' in st and 'lon' in st:
251
- lat_wgs84 = st['lat']
252
- lon_wgs84 = st['lon']
253
- lon_gcj02, lat_gcj02 = self.wgs84_to_gcj02(lon_wgs84, lat_wgs84)
254
- st['lat'] = lat_gcj02
255
- st['lon'] = lon_gcj02
304
+ if device.is_connected:
305
+ st['is_connect'] = True
306
+ else:
307
+ st['is_connect'] = False
308
+ if st and 'lat' in st and 'lon' in st:
309
+ if st:
310
+ lat_wgs84 = st['lat']
311
+ lon_wgs84 = st['lon']
312
+ if self.is_in_china_shapely(lon_wgs84,lat_wgs84):
313
+ lon_gcj02, lat_gcj02 = self.wgs84_to_gcj02(lon_wgs84, lat_wgs84)
314
+ st['lat'] = lat_gcj02
315
+ st['lon'] = lon_gcj02
316
+ else:
317
+ st['lat'] = None
318
+ st['lon'] = None
256
319
 
257
320
 
258
321
  payload = json.dumps({
@@ -404,40 +467,45 @@ class DevicePusher:
404
467
  mission_id = command_request.mission_id
405
468
  selected_devices = json.loads(command_request.params)
406
469
  result = ""
407
-
408
- for selected_device in selected_devices:
409
- # 解析参数
410
- device_id = selected_device['device_id']
411
- connection_str = selected_device['connection_str']
412
- deviceKey = DeviceKey(device_id=device_id, connection_str=connection_str)
413
- if mission_id == 'connect':
414
- # 获取或创建设备实例
415
- if deviceKey not in self.devices:
416
- logger.info(f"创建新设备实例: {deviceKey}")
417
- device = self.device_factory()
418
- self.devices[deviceKey] = device
419
- result = "创建连接成功"
420
- # 连接设备
421
- try:
422
- device.connect(deviceKey)
423
- if deviceKey not in self.status_tasks:
424
- self.status_tasks[deviceKey] = asyncio.create_task(
425
- self._report_status_continuously(self.protocol_name,device, deviceKey))
426
- logger.info(f"为设备 {deviceKey} 启动状态上报任务")
427
- except Exception as e:
428
- result = "创建连接失败"
429
- raise ValueError(f"设备连接失败: {e}")
430
- else:
431
- actions = selected_device['actions']
432
- for action in actions:
433
- command_type = action['command_type']
434
- params = action['parameters']
470
+
471
+ # 添加执行模式控制,可以根据需要配置
472
+ execute_parallel = False # 可以改为从配置或命令参数中获取
473
+
474
+ if execute_parallel:
475
+ #并行
476
+ tasks = []
477
+ for selected_device in selected_devices:
478
+ task = self._process_single_device(selected_device, mission_id, command_request.command_id)
479
+ tasks.append(task)
480
+
481
+ # 等待所有设备处理完成
482
+ results = await asyncio.gather(*tasks, return_exceptions=True)
483
+
484
+ # 处理结果
485
+ success_results = []
486
+ for i, result in enumerate(results):
487
+ if isinstance(result, Exception):
488
+ logger.error(f"设备 {selected_devices[i]['device_id']} 处理失败: {result}")
489
+ # 可以根据需要决定是否继续处理其他设备
490
+ else:
491
+ success_results.append(result)
492
+
493
+ # 合并成功的结果
494
+ result = success_results[0] if success_results else ""
495
+ else:
496
+ #串行
497
+ for selected_device in selected_devices:
498
+ # 解析参数
499
+ device_id = selected_device['device_id']
500
+ connection_str = selected_device['connection_str']
501
+ deviceKey = DeviceKey(device_id=device_id, connection_str=connection_str)
502
+ if mission_id == 'connect':
435
503
  # 获取或创建设备实例
436
504
  if deviceKey not in self.devices:
437
505
  logger.info(f"创建新设备实例: {deviceKey}")
438
506
  device = self.device_factory()
439
- device.set_grpc_stub(self.grpc_stub)
440
507
  self.devices[deviceKey] = device
508
+ result = "创建连接成功"
441
509
  # 连接设备
442
510
  try:
443
511
  device.connect(deviceKey)
@@ -446,25 +514,46 @@ class DevicePusher:
446
514
  self._report_status_continuously(self.protocol_name,device, deviceKey))
447
515
  logger.info(f"为设备 {deviceKey} 启动状态上报任务")
448
516
  except Exception as e:
517
+ result = "创建连接失败"
449
518
  raise ValueError(f"设备连接失败: {e}")
450
-
451
- device = self.devices[deviceKey]
452
- device.set_grpc_stub(self.grpc_stub)
453
- # 执行命令
454
- try:
455
- result = device.excute_command(device_id, connection_str, command_type, params, mission_id)
456
- except Exception as e:
457
- raise ValueError(f"命令执行失败: {e}")
458
-
459
- # 发送成功确认
460
- ack = device_pb2.CommandAck(
461
- command_id=command_request.command_id,
462
- mission_id=mission_id,
463
- success=True,
464
- data=json.dumps(result) if result else ""
465
- )
466
- await command_stream.write(ack)
467
- logger.info(f"命令执行成功: {command_request.command_id}")
519
+ else:
520
+ actions = selected_device['actions']
521
+ for action in actions:
522
+ command_type = action['command_type']
523
+ params = action['parameters']
524
+ # 获取或创建设备实例
525
+ if deviceKey not in self.devices:
526
+ logger.info(f"创建新设备实例: {deviceKey}")
527
+ device = self.device_factory()
528
+ device.set_grpc_stub(self.grpc_stub)
529
+ self.devices[deviceKey] = device
530
+ # 连接设备
531
+ try:
532
+ device.connect(deviceKey)
533
+ if deviceKey not in self.status_tasks:
534
+ self.status_tasks[deviceKey] = asyncio.create_task(
535
+ self._report_status_continuously(self.protocol_name,device, deviceKey))
536
+ logger.info(f"为设备 {deviceKey} 启动状态上报任务")
537
+ except Exception as e:
538
+ raise ValueError(f"设备连接失败: {e}")
539
+
540
+ device = self.devices[deviceKey]
541
+ device.set_grpc_stub(self.grpc_stub)
542
+ # 执行命令
543
+ try:
544
+ result = device.excute_command(device_id, connection_str, command_type, params, mission_id)
545
+ except Exception as e:
546
+ raise ValueError(f"命令执行失败: {e}")
547
+
548
+ # 发送成功确认
549
+ ack = device_pb2.CommandAck(
550
+ command_id=command_request.command_id,
551
+ mission_id=mission_id,
552
+ success=True,
553
+ data=json.dumps(result) if result else ""
554
+ )
555
+ await command_stream.write(ack)
556
+ logger.info(f"命令执行成功: {command_request.command_id}")
468
557
 
469
558
  except Exception as e:
470
559
  logger.error(f"处理命令失败: {e}")
@@ -484,6 +573,63 @@ class DevicePusher:
484
573
  logger.error(f"命令流处理异常: {e}")
485
574
  raise
486
575
 
576
+ async def _process_single_device(self, selected_device, mission_id, command_id):
577
+ """处理单个设备的通用逻辑"""
578
+ # 解析参数
579
+ device_id = selected_device['device_id']
580
+ connection_str = selected_device['connection_str']
581
+ deviceKey = DeviceKey(device_id=device_id, connection_str=connection_str)
582
+
583
+ if mission_id == 'connect':
584
+ # 获取或创建设备实例
585
+ if deviceKey not in self.devices:
586
+ logger.info(f"创建新设备实例: {deviceKey}")
587
+ device = self.device_factory()
588
+ self.devices[deviceKey] = device
589
+ result = "创建连接成功"
590
+ # 连接设备
591
+ try:
592
+ device.connect(deviceKey)
593
+ if deviceKey not in self.status_tasks:
594
+ self.status_tasks[deviceKey] = asyncio.create_task(
595
+ self._report_status_continuously(self.protocol_name, device, deviceKey))
596
+ logger.info(f"为设备 {deviceKey} 启动状态上报任务")
597
+ except Exception as e:
598
+ result = "创建连接失败"
599
+ raise ValueError(f"设备连接失败: {e}")
600
+ return result
601
+ else:
602
+ actions = selected_device['actions']
603
+ final_result = ""
604
+ for action in actions:
605
+ command_type = action['command_type']
606
+ params = action['parameters']
607
+ # 获取或创建设备实例
608
+ if deviceKey not in self.devices:
609
+ logger.info(f"创建新设备实例: {deviceKey}")
610
+ device = self.device_factory()
611
+ device.set_grpc_stub(self.grpc_stub)
612
+ self.devices[deviceKey] = device
613
+ # 连接设备
614
+ try:
615
+ device.connect(deviceKey)
616
+ if deviceKey not in self.status_tasks:
617
+ self.status_tasks[deviceKey] = asyncio.create_task(
618
+ self._report_status_continuously(self.protocol_name, device, deviceKey))
619
+ logger.info(f"为设备 {deviceKey} 启动状态上报任务")
620
+ except Exception as e:
621
+ raise ValueError(f"设备连接失败: {e}")
622
+
623
+ device = self.devices[deviceKey]
624
+ device.set_grpc_stub(self.grpc_stub)
625
+ # 执行命令
626
+ try:
627
+ result = device.excute_command(device_id, connection_str, command_type, params, mission_id)
628
+ final_result = result
629
+ except Exception as e:
630
+ raise ValueError(f"命令执行失败: {e}")
631
+ return final_result
632
+
487
633
  def _update_all_devices_grpc_stub(self):
488
634
  """更新所有设备实例的grpc_stub"""
489
635
  for device_key, device in self.devices.items():
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: device_protocol_sdk
3
- Version: 1.2.3
3
+ Version: 1.2.5
4
4
  Summary: 无人设备协议开发SDK
5
5
  Author: fuhl
6
6
  Requires-Python: >=3.8
@@ -10,7 +10,7 @@ Requires-Dist: grpcio-tools>=1.48.2
10
10
  Requires-Dist: paho-mqtt>=1.6.1
11
11
  Requires-Dist: pydantic>=1.9.0
12
12
  Requires-Dist: websockets>=10.0
13
- Requires-Dist: coord-convert>=0.2.1
13
+ Requires-Dist: shapely>=2.1.2
14
14
 
15
15
  # Device Protocol SDK
16
16
 
@@ -3,4 +3,4 @@ grpcio-tools>=1.48.2
3
3
  paho-mqtt>=1.6.1
4
4
  pydantic>=1.9.0
5
5
  websockets>=10.0
6
- coord-convert>=0.2.1
6
+ shapely>=2.1.2
@@ -7,7 +7,7 @@ long_description = readme_path.read_text(encoding="utf-8")
7
7
 
8
8
  setup(
9
9
  name="device_protocol_sdk",
10
- version="1.2.3",
10
+ version="1.2.5",
11
11
  packages=find_packages(include=["sdk*", "device_protocol_sdk*"]),
12
12
  install_requires=[
13
13
  "grpcio>=1.48.2", # gRPC 运行时依赖
@@ -15,7 +15,7 @@ setup(
15
15
  "paho-mqtt>=1.6.1", # MQTT 客户端
16
16
  "pydantic>=1.9.0", # 数据验证和设置管理
17
17
  "websockets>=10.0", # Websocket 支持
18
- "coord-convert>=0.2.1",
18
+ "shapely>=2.1.2",
19
19
  ],
20
20
  python_requires=">=3.8",
21
21
  author="fuhl",