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.
- {device_protocol_sdk-1.2.3 → device_protocol_sdk-1.2.5}/PKG-INFO +2 -2
- {device_protocol_sdk-1.2.3 → device_protocol_sdk-1.2.5}/device_protocol_sdk/abstract_device.py +5 -0
- {device_protocol_sdk-1.2.3 → device_protocol_sdk-1.2.5}/device_protocol_sdk/pusher.py +200 -54
- {device_protocol_sdk-1.2.3 → device_protocol_sdk-1.2.5}/device_protocol_sdk.egg-info/PKG-INFO +2 -2
- {device_protocol_sdk-1.2.3 → device_protocol_sdk-1.2.5}/device_protocol_sdk.egg-info/requires.txt +1 -1
- {device_protocol_sdk-1.2.3 → device_protocol_sdk-1.2.5}/setup.py +2 -2
- {device_protocol_sdk-1.2.3 → device_protocol_sdk-1.2.5}/README.md +0 -0
- {device_protocol_sdk-1.2.3 → device_protocol_sdk-1.2.5}/device_protocol_sdk/__init__.py +0 -0
- {device_protocol_sdk-1.2.3 → device_protocol_sdk-1.2.5}/device_protocol_sdk/device_pb2.py +0 -0
- {device_protocol_sdk-1.2.3 → device_protocol_sdk-1.2.5}/device_protocol_sdk/device_pb2_grpc.py +0 -0
- {device_protocol_sdk-1.2.3 → device_protocol_sdk-1.2.5}/device_protocol_sdk/model/__init__.py +0 -0
- {device_protocol_sdk-1.2.3 → device_protocol_sdk-1.2.5}/device_protocol_sdk/model/action_item.py +0 -0
- {device_protocol_sdk-1.2.3 → device_protocol_sdk-1.2.5}/device_protocol_sdk/model/device_key.py +0 -0
- {device_protocol_sdk-1.2.3 → device_protocol_sdk-1.2.5}/device_protocol_sdk/model/device_status.py +0 -0
- {device_protocol_sdk-1.2.3 → device_protocol_sdk-1.2.5}/device_protocol_sdk.egg-info/SOURCES.txt +0 -0
- {device_protocol_sdk-1.2.3 → device_protocol_sdk-1.2.5}/device_protocol_sdk.egg-info/dependency_links.txt +0 -0
- {device_protocol_sdk-1.2.3 → device_protocol_sdk-1.2.5}/device_protocol_sdk.egg-info/top_level.txt +0 -0
- {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
|
+
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:
|
|
13
|
+
Requires-Dist: shapely>=2.1.2
|
|
14
14
|
|
|
15
15
|
# Device Protocol SDK
|
|
16
16
|
|
{device_protocol_sdk-1.2.3 → device_protocol_sdk-1.2.5}/device_protocol_sdk/abstract_device.py
RENAMED
|
@@ -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
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
st
|
|
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
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
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
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
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():
|
{device_protocol_sdk-1.2.3 → device_protocol_sdk-1.2.5}/device_protocol_sdk.egg-info/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: device_protocol_sdk
|
|
3
|
-
Version: 1.2.
|
|
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:
|
|
13
|
+
Requires-Dist: shapely>=2.1.2
|
|
14
14
|
|
|
15
15
|
# Device Protocol SDK
|
|
16
16
|
|
|
@@ -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.
|
|
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
|
-
"
|
|
18
|
+
"shapely>=2.1.2",
|
|
19
19
|
],
|
|
20
20
|
python_requires=">=3.8",
|
|
21
21
|
author="fuhl",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{device_protocol_sdk-1.2.3 → device_protocol_sdk-1.2.5}/device_protocol_sdk/device_pb2_grpc.py
RENAMED
|
File without changes
|
{device_protocol_sdk-1.2.3 → device_protocol_sdk-1.2.5}/device_protocol_sdk/model/__init__.py
RENAMED
|
File without changes
|
{device_protocol_sdk-1.2.3 → device_protocol_sdk-1.2.5}/device_protocol_sdk/model/action_item.py
RENAMED
|
File without changes
|
{device_protocol_sdk-1.2.3 → device_protocol_sdk-1.2.5}/device_protocol_sdk/model/device_key.py
RENAMED
|
File without changes
|
{device_protocol_sdk-1.2.3 → device_protocol_sdk-1.2.5}/device_protocol_sdk/model/device_status.py
RENAMED
|
File without changes
|
{device_protocol_sdk-1.2.3 → device_protocol_sdk-1.2.5}/device_protocol_sdk.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
{device_protocol_sdk-1.2.3 → device_protocol_sdk-1.2.5}/device_protocol_sdk.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|