Explorar o código

v-0.1.1-1:20240708测试版本

Casper hai 8 meses
pai
achega
ae6932c4e4
Modificáronse 100 ficheiros con 7530 adicións e 4745 borrados
  1. 259 0
      3rdparty/xapi/audio/api.py
  2. 91 0
      3rdparty/xapi/enfei/api.py
  3. 132 0
      3rdparty/xapi/google/api.py
  4. 123 0
      3rdparty/xapi/hik/api.py
  5. 92 0
      3rdparty/xapi/hik/read100.py
  6. BIN=BIN
      3rdparty/xapi/mccbts/1.txt
  7. 302 0
      3rdparty/xapi/mccbts/api.py
  8. 564 0
      3rdparty/xapi/nessus/api.py
  9. 124 0
      3rdparty/xapi/onvif/api.py
  10. 263 0
      3rdparty/xapi/ros1/api_for_hs.py
  11. 52 0
      3rdparty/xapi/ros1/cmd1001.txt
  12. 40 0
      3rdparty/xapi/ros1/cmd100101.txt
  13. 52 0
      3rdparty/xapi/ros1/s1-行驶-去e点
  14. 12 0
      3rdparty/xapi/ros1/s2-作业-叉包
  15. 11 0
      3rdparty/xapi/ros1/s3-作业-回e点
  16. 31 0
      3rdparty/xapi/ros1/s4-行驶-e点-到-倒渣口2
  17. 18 0
      3rdparty/xapi/ros1/s5-行驶-e点-到-倒渣口2
  18. 43 0
      3rdparty/xapi/ros1/s6-行驶-倒渣口2-到-n20的e点
  19. 12 0
      3rdparty/xapi/ros1/s7-作业-放包
  20. 4 0
      3rdparty/xapi/taiwuict/u1_for_aibox.py
  21. 4 0
      3rdparty/xapi/taiwuict/u2_for_aibox.py
  22. 833 0
      3rdparty/xapi/taiwuict/u3_for_cscec.py
  23. 222 0
      3rdparty/xclient/xinflux.py
  24. 93 0
      3rdparty/xclient/xmaria.py
  25. 508 0
      3rdparty/xclient/xmongo.py
  26. 110 0
      3rdparty/xclient/xmqtt.py
  27. 155 0
      3rdparty/xclient/xmysql.py
  28. 116 0
      3rdparty/xclient/xqcloudsms.py
  29. 310 0
      3rdparty/xclient/xredis.py
  30. 42 0
      3rdparty/xclient/xsmtp.py
  31. 76 0
      3rdparty/xclient/xsmtp_zl.py
  32. 198 0
      3rdparty/xclient/xssh.py
  33. 31 0
      3rdparty/xclient/xtcp.py
  34. 48 0
      3rdparty/xclient/xudp.py
  35. 39 0
      3rdparty/xdecorator.py
  36. 306 0
      3rdparty/xengine/cv_face_recognition/engine.py
  37. 10 0
      3rdparty/xlib/__init__.py
  38. 51 0
      3rdparty/xlib/xbase64.py
  39. 248 0
      3rdparty/xlib/xfile.py
  40. 26 0
      3rdparty/xlib/xipv4.py
  41. 28 0
      3rdparty/xlib/xlist.py
  42. 26 0
      3rdparty/xlib/xlog.py
  43. 93 0
      3rdparty/xlib/xpickle.py
  44. 21 0
      3rdparty/xlib/xsubprocess.py
  45. 44 0
      3rdparty/xlib/xthread.py
  46. 169 0
      3rdparty/xlib/xtime.py
  47. 16 0
      3rdparty/xlib/xuuid.py
  48. 406 0
      3rdparty/xpip/aes_by_crypto.py
  49. 65 0
      3rdparty/xpip/camera_by_cv2.py
  50. 40 0
      3rdparty/xpip/data_by_numpy.py
  51. 30 0
      3rdparty/xpip/show_by_prettytable.py
  52. 252 0
      3rdparty/xpip/xapscheduler.py
  53. 189 0
      3rdparty/xpip/zip_by_pyminizip.py
  54. 82 0
      3rdparty/xplugin/hydra/plugin.py
  55. 260 0
      3rdparty/xplugin/msscan/plugin.py
  56. 59 0
      3rdparty/xserver/xtcp.py
  57. 61 0
      3rdparty/xserver/xudp.py
  58. 0 29
      project-fastapi-hs/README-usage.bash
  59. 0 208
      project-fastapi-hs/api/api.py
  60. 0 151
      project-fastapi-hs/api/v5/hs2000.py
  61. 0 154
      project-fastapi-hs/api/v5/hs3000.py
  62. 0 38
      project-fastapi-hs/api/v5/hs4000.py
  63. 0 12
      project-fastapi-hs/api/v5/hs5000.py
  64. 0 457
      project-fastapi-hs/data/SRI2024032814-4point.py
  65. 0 5
      project-fastapi-hs/data/SRI2024032814-4point.txt
  66. 0 13
      project-fastapi-hs/data/倒渣口坐标数据.json
  67. 0 20
      project-fastapi-hs/data/圆心坐标数据.json
  68. 0 440
      project-fastapi-hs/data/渣罐坐标数据.json
  69. 0 54
      project-fastapi-hs/default_data.py
  70. 0 2
      project-fastapi-hs/test/HingeCarPath.msg
  71. 0 284
      project-fastapi-hs/test/SRI2024032514-机房端http接口文档.txt
  72. 0 32
      project-fastapi-hs/test/SRI2024032514-车端http接口文档.txt
  73. 0 8
      project-fastapi-hs/test/Segment.msg
  74. 0 14
      project-fastapi-hs/test/Segment.py
  75. 0 136
      project-fastapi-hs/test/test-2000.py
  76. 0 95
      project-fastapi-hs/test/test-3000.py
  77. 0 33
      project-fastapi-hs/test/test-4000.py
  78. 0 32
      project-fastapi-hs/test/test-5000.py
  79. 0 4
      project-fastapi-hs/test/test-enfei.py
  80. 0 30
      project-fastapi-hs/test/test_key_api.py
  81. 0 15
      project-fastapi-hs/test/test_sanyi.py
  82. 0 30
      project-fastapi-hs/test/test_token.py
  83. 0 264
      project-fastapi-hs/unit/Scheduler_a1.py
  84. 0 434
      project-fastapi-hs/unit/Scheduler_b1.py
  85. 0 604
      project-fastapi-hs/unit/Scheduler_c1.py
  86. 0 648
      project-fastapi-hs/unit/Scheduler_d1.py
  87. 0 12
      project-responder-hs/README-usage.bash
  88. 0 36
      project-responder-hs/api/url.py
  89. 0 162
      project-responder-hs/app.py
  90. 0 26
      project-responder-hs/main.py
  91. 0 25
      project-responder-hs/test/SRI2024032716-服务端mqtt话题接口文档.txt
  92. 0 11
      project-responder-hs/test/test_key_api.txt
  93. 0 31
      project-responder-hs/test/test_mqtt.py
  94. 0 41
      project-responder-hs/test/test_test_api.txt
  95. 0 60
      project-responder-hs/unit/PotDataMessageListener.py
  96. 0 94
      project-responder-hs/unit/VehicleStateMessageListener.py
  97. 1 1
      sri-server-bg01/Dockerfile
  98. 37 0
      sri-server-bg01/README-usage.bash
  99. 0 0
      sri-server-bg01/README-usage.md
  100. 0 0
      sri-server-bg01/README-usage.txt

+ 259 - 0
3rdparty/xapi/audio/api.py

@@ -0,0 +1,259 @@
+# update: 2021-10-15
+"""
+配置流程
+    1、禁用vbox虚拟机的网卡。
+    2、pc端安装客户端程序,打开“智能广播扫描工具”,扫描设备,并修改设备ip。(服务ip不能和设备ip一样,随意就可以)
+
+{
+    "sn": "iHciceH9A5",
+    "type": "req",
+    "name": "songs_queue_append",
+    "params": {
+        "tid": "134",
+        "vol": 100,
+        "urls": [
+            {
+                "name": "1",
+                # 只支持mp3格式 不支持wav格式
+                "uri": "http://websitecdn.gangganghao.com.cn/ls20/mp3/ei.mp3"
+            },
+            {
+                "name": "2",
+                "uri": "http://websitecdn.gangganghao.com.cn/ls20/mp3/jxy.mp3"
+            }
+        ]
+    }
+}
+"""
+import requests
+import time
+
+
+class Api(object):
+
+    def __init__(self, service_url='http://192.168.30.89:8888'):
+        """
+        port: 端口号 8888 安装目录下 ls20_mgrserver/ls20_mgrserver.ini 文件中进行配置
+
+        192.168.1.241 ls20://02029F15B65A
+        192.168.1.242 ls20://0203B0F822FC
+        192.168.1.243 ls20://02015790B99B
+        192.168.1.244 ls20://02006723C3BA
+        192.168.1.245 ls20://020099728112
+        """
+        # self.api_service_url = service_url
+
+        # --- 八局项目 第3现场设备 ---
+        # self.api_service_url = 'http://192.168.15.193:8888'
+        # self.file_service_url = 'http://192.168.15.195:9900'
+
+        # --- 八局项目 第4现场设备 ---
+        self.api_service_url = 'http://192.168.1.43:8888'
+        self.file_service_url = 'http://192.168.1.242:9900'
+
+        self.headers = dict()
+        self.headers['content-type'] = 'application/json'
+
+    def call_audio_make_sound_v2(self, file_name, url, sn):
+        """
+        url: http://sc.geemi.cn/smartSiteService/api/uploadLog/uploadLogCapture
+        """
+        data = {
+            # "sn": sn,
+            "sn": 'iHciceH9A5',
+            "type": "req",
+            "name": 'songs_queue_append',
+            "params": {
+                "tid": '1',
+                "vol": 50,
+                "urls": [
+                    {
+                        "name": "1",
+                        # "uri": f"http://127.0.0.1:5042/api?module=TEST&method=test011&mp3_name={file_name}",
+                        # "uri": "http://192.168.20.231:8802/api?mp3_name=2021-10-16-11-05-29-717030.mp3",
+                        # "uri": f"http://fra-component-trigger:5042/api?mp3_name={file_name}",
+                        # "uri": f"http://192.168.20.231:9900/{file_name}",
+                        # "uri": f"http://192.168.0.15:9900/{file_name}",
+                        # "uri": f"http://192.168.51.242:9900/{file_name}",
+                        # "uri": "http://192.168.51.242:9900/find-unknown-person.mp3",
+                        # "uri": "http://192.168.15.195:9900/find-unknown-person.mp3",
+                        "uri": f"{self.file_service_url}/find-unknown-person.mp3",
+                    }
+                ]
+            }
+        }
+        times = 0
+        while times < 10:
+
+            try:
+
+                print('Api:call_audio_make_sound_v2:url:', self.api_service_url)
+                print('Api:call_audio_make_sound_v2:uri:', data.get('params').get('urls')[0].get('uri'))
+                response = requests.post(self.api_service_url, json=data, headers=self.headers)
+                print('Api:call_audio_make_sound_v2:result:', response.status_code)
+                return True
+
+            except Exception as e:
+
+                print(e)
+                times += 1
+                time.sleep(1)
+
+        return False
+
+    def call_audio_make_sound_v3(self, result_type):
+        """
+        url: http://sc.geemi.cn/smartSiteService/api/uploadLog/uploadLogCapture
+        result_type: 结果类型 0 匹配到人员 1 人脸检测失败 2 提取特征失败 3 未匹配到人员
+        """
+        if result_type in [3]:
+            # uri = "http://192.168.15.195:9900/a1.mp3"  # 请登记 3
+            uri = f"{self.file_service_url}/a1.mp3"  # 请登记 3
+        elif result_type in [1, 2]:
+            # uri = "http://192.168.15.195:9900/a2.mp3"  # 请重试 1 2
+            uri = f"{self.file_service_url}/a2.mp3"  # 请重试 1 2
+        elif result_type in [0]:
+            # uri = "http://192.168.15.195:9900/a3.mp3"  # 欢迎 0
+            uri = f"{self.file_service_url}/a3.mp3"  # 欢迎 0
+        else:
+            return False
+        data = {
+            # "sn": sn,
+            "sn": 'iHciceH9A5',
+            "type": "req",
+            "name": 'songs_queue_append',
+            "params": {
+                "tid": '1',
+                # "vol": 50,
+                "vol": 100,
+                "urls": [
+                    {
+                        "name": "1",
+                        # "uri": f"http://127.0.0.1:5042/api?module=TEST&method=test011&mp3_name={file_name}",
+                        # "uri": "http://192.168.20.231:8802/api?mp3_name=2021-10-16-11-05-29-717030.mp3",
+                        # "uri": f"http://fra-component-trigger:5042/api?mp3_name={file_name}",
+                        # "uri": f"http://192.168.20.231:9900/{file_name}",
+                        # "uri": f"http://192.168.0.15:9900/{file_name}",
+                        # "uri": f"http://192.168.51.242:9900/{file_name}",
+                        # "uri": "http://192.168.51.242:9900/find-unknown-person.mp3",
+                        # "uri": "http://192.168.15.195:9900/a1.mp3",
+                        "uri": uri,
+                    }
+                ]
+            }
+        }
+        times = 0
+        while times < 10:
+
+            try:
+
+                # print('Api:call_audio_make_sound_v3:url:', url)
+                # print('Api:call_audio_make_sound_v3:uri:', data.get('params').get('urls')[0].get('uri'))
+                response = requests.post(self.api_service_url, json=data, headers=self.headers)
+                # print('Api:call_audio_make_sound_v3:result:', response.status_code)
+                return True
+
+            except Exception as e:
+
+                print(e)
+                times += 1
+                time.sleep(1)
+
+        return False
+
+    def file_download(self):
+        """
+        doc: https://documenter.getpostman.com/view/691989/TzRVdR6Q#70870504-1cb6-439b-9cf4-f1f786d9d3a1
+        """
+        data = {
+            # "sn": ["ls20://0201518F79D4"],
+            "sn": ["iHciceH9A5"],
+            "type": "req",
+            "name": "file_download",
+            "params": {
+                "urls": [
+                    {
+                        "uri": "http://192.168.20.231:9900/2021-10-16-11-05-29-717030.mp3",
+                        "target": "/root/2021-10-16-11-05-29-717030.mp3"
+                    }
+                ]
+            }
+        }
+        print('Api:file_download:url:', self.api_service_url)
+        response = requests.post(self.api_service_url, json=data, headers=self.headers)
+        print('Api:file_download:result:', response.status_code)
+        return response.status_code
+
+    def songs_queue_append(self):
+        """
+        url: http://sc.geemi.cn/smartSiteService/api/uploadLog/uploadLogCapture
+        """
+        from requests.exceptions import ConnectionError, ReadTimeout
+        import time
+        time.sleep(0.01)
+
+        # url = "http://192.168.20.189:8888"
+        # url = "http://192.168.51.193:8888"
+        # url = "http://192.168.15.193:8888"
+        data = {
+            # "sn": "iHciceH9A5",  # 第3现场设备
+            "sn": "ls20://02009EDCD48C",  # 第4现场设备
+            "type": "req",
+            "name": "songs_queue_append",
+            "params": {
+                "tid": "134",
+                "vol": 80,
+                # "vol": 10,  # 基本听不见
+                "urls": [
+                    {
+                        "name": "1",
+                        "uri": f"{self.file_service_url}/a2.mp3",
+
+                        # --- test ---
+                        # "uri": "http://websitecdn.gangganghao.com.cn/ls20/mp3/ei.mp3",
+                        # "uri": "http://192.168.20.231:8802/api?mp3_name=2021-10-16-11-05-29-717030.mp3",
+                        # "uri": "http://192.168.20.231:9900/2021-10-16-11-05-29-717030.mp3",
+                        # "uri": "/root/2021-10-16-11-05-29-717030.mp3",
+                        # "uri": "http://192.168.0.15:9900/2021-10-16-11-05-29-717030.mp3",
+                        # "uri": "http://192.168.51.242:9900/find-unknown-person.mp3",
+                        # "uri": "http://192.168.15.195:9900/find-unknown-person.mp3",
+                        # "uri": "http://192.168.15.195:9900/a1.mp3",
+
+                    },
+                    # {
+                    #     "name": "2",
+                    #     "uri": "http://websitecdn.gangganghao.com.cn/ls20/mp3/jxy.mp3"
+                    # }
+                ]
+            }
+        }
+        run_at = time.time()
+        times = 0
+        while times < 10:
+
+            try:
+
+                print('Api:songs_queue_append:url:', self.api_service_url)
+                # response = requests.post(url, json=data, headers=self.headers, timeout=1)
+                response = requests.post(self.api_service_url, json=data, headers=self.headers)
+                print('Api:songs_queue_append:result:', response.status_code)
+                return f"{round(time.time() - run_at, 2)}s"
+
+            # except ConnectionError as e:
+            except Exception as e:
+
+                print(e)
+                times += 1
+                time.sleep(1)
+
+        return f"{round(time.time() - run_at, 2)}s"
+
+
+if __name__ == '__main__':
+    # --- init ---
+    api = Api()
+
+    # --- test --- cd /home/server/projects/taiwuict/cscec-8bur-vms/supplement-python/apis/audio && python3 api.py
+    # out = api.file_download()
+    out = api.songs_queue_append()
+    print('use time:', out)

+ 91 - 0
3rdparty/xapi/enfei/api.py

@@ -0,0 +1,91 @@
+# update: 2024-3-23
+"""
+配置hosts
+10.10.4.103 cloudos.service.ob.local
+10.62.115.83 harbor.platform.dyys.com
+10.62.115.11 hyty-ifactory.platform.dyys.com
+10.62.115.83 harbor.platform.dyys.com
+10.62.115.11 qbee.platform.dyys.com
+10.62.115.208  mdm.platform.dyys.com
+10.62.107.11 paas.pre.platform.dyys.com
+10.62.107.11 qbee.pre.platform.dyys.com
+10.62.115.11 dacoo.platform.dyys.com
+10.62.115.11 data-assets-process.platform.dyys.com
+10.62.115.11 bitmagic.platform.dyys.com
+"""
+import requests
+
+import sys
+import importlib
+import traceback
+
+# sys.path.append(r'E:\casper\repositories\repositories\casperz.py-project\module-py')  # for pc
+sys.path.append('/home/ubuntu/repositories/repositories/casperz.py-project/module-py')
+methods = importlib.import_module(f"xlib")
+
+
+class API(object):
+
+    # def __init__(self, username='System001', password='Swdx@143',
+    def __init__(self, username='', password=''):
+        """
+        """
+        self.url = f"http://hyty-ifactory.platform.dyys.com/gongyi/ui/ResiduePackage/driver/getParamsSet"
+
+    def get_pot_list(self):
+        """
+        获取渣罐数据
+        return [
+            {
+                'id': '1427897186149990401',
+                'localNumber': '434',  # 渣位号
+                'packageNumber': None,  # 渣包号
+                'localX': None,  # 渣位坐标X
+                'localY': None,  # 渣位坐标Y
+                'localStatus': 0,  # 渣位水管开关转态 0 关闭 非0 开启
+                'packageStatus': 1,  # 渣包状态 1 空位 2 就绪 3 缓冷(空冷) 4 水冷 5 自冷(水冷) 6 待倒 7 故障
+                'weight': None,  # 渣包重量
+                'createBy': 'admin',
+                'createTime': '2021-08-18',
+                'updateBy': 'admin',
+                'updateTime': '2024-03-23'
+            }
+        ]
+        return dict(code=-1, data=[], message=f"something is wrong. [{exception.__class__.__name__}]",
+                    details=f"{methods.trace_log()}")
+
+        """
+        try:
+            response = requests.get(url=self.url)
+            print('API:get_pot_list:url:', self.url)
+            print('API:get_pot_list:status_code:', response.status_code)
+            result = response.json().get('result')
+
+            # --- check ---
+            if not result:
+                reason = '接口数据异常'
+                detail = f"请求地址: {self.url}, 请求方式: GET, 返回结果: {response.text}"
+                return reason, detail
+
+            # --- fill pot_list ---
+            pot_list = list()
+            for index in range(len(result)):
+                pot_list += result[index]
+
+            return pot_list
+        except Exception as exception:
+
+            print(f"API.get_pot_list.exception: {exception.__class__.__name__}")
+            print(f"API.get_pot_list.traceback: {traceback.format_exc()}")
+            reason = f"{exception.__class__.__name__}"
+            detail = f"{traceback.format_exc()}"
+            return reason, detail
+
+
+if __name__ == '__main__':
+    # --- init ---
+    api = API()
+
+    # --- test ---
+    out = api.get_pot_list()
+    print(len(out))

+ 132 - 0
3rdparty/xapi/google/api.py

@@ -0,0 +1,132 @@
+"""
+谷歌翻译接口
+"""
+from urllib.parse import quote
+import requests
+import execjs
+import logging
+
+logger = logging.getLogger(__name__)
+code = """
+function TL(a) {
+    var k = "";
+    var b = 406644;
+    var b1 = 3293161072;
+    var jd = ".";
+    var $b = "+-a^+6";
+    var Zb = "+-3^+b+-f";
+    for (var e = [], f = 0, g = 0; g < a.length; g++) {
+        var m = a.charCodeAt(g);
+        128 > m ? e[f++] = m : (2048 > m ? e[f++] = m >> 6 | 192 : (55296 == (m & 64512) && g + 1 < a.length && 56320 == (a.charCodeAt(g + 1) & 64512) ? (m = 65536 + ((m & 1023) << 10) + (a.charCodeAt(++g) & 1023),
+        e[f++] = m >> 18 | 240,
+        e[f++] = m >> 12 & 63 | 128) : e[f++] = m >> 12 | 224,
+        e[f++] = m >> 6 & 63 | 128),
+        e[f++] = m & 63 | 128)
+    }
+    a = b;
+    for (f = 0; f < e.length; f++) a += e[f],
+    a = RL(a, $b);
+    a = RL(a, Zb);
+    a ^= b1 || 0;
+    0 > a && (a = (a & 2147483647) + 2147483648);
+    a %= 1E6;
+    return a.toString() + jd + (a ^ b)
+};
+function RL(a, b) {
+    var t = "a";
+    var Yb = "+";
+    for (var c = 0; c < b.length - 2; c += 3) {
+        var d = b.charAt(c + 2),
+        d = d >= t ? d.charCodeAt(0) - 87 : Number(d),
+        d = b.charAt(c + 1) == Yb ? a >>> d: a << d;
+        a = b.charAt(c) == Yb ? a + d & 4294967295 : a ^ d
+    }
+    return a
+}
+"""
+
+
+class Api(object):
+
+    def __init__(self):
+        self.ctx = execjs.compile(code)
+        self.headers = {
+            'authority': 'translate.google.cn',
+            'method': 'GET',
+            'path': '',
+            'scheme': 'https',
+            'accept': '*/*',
+            'accept-encoding': 'gzip, deflate, br',
+            'accept-language': 'zh-CN,zh;q=0.9,ja;q=0.8',
+            # 'cookie': '_ga=GA1.3.110668007.1547438795; _gid=GA1.3.791931751.1548053917; 1P_JAR=2019-1-23-1; NID=156=biJbQQ3j2gPAJVBfdgBjWHjpC5m9vPqwJ6n6gxTvY8n1eyM8LY5tkYDRsYvacEnWNtMh3ux0-lUJr439QFquSoqEIByw7al6n_yrHqhFNnb5fKyIWMewmqoOJ2fyNaZWrCwl7MA8P_qqPDM5uRIm9SAc5ybSGZijsjalN8YDkxQ',
+            'cookie': '_ga=GA1.3.110668007.1547438795; _gid=GA1.3.1522575542.1548327032; 1P_JAR=2019-1-24-10; NID=156=ELGmtJHel1YG9Q3RxRI4HTgAc3l1n7Y6PAxGwvecTJDJ2ScgW2p-CXdvh88XFb9dTbYEBkoayWb-2vjJbB-Rhf6auRj-M-2QRUKdZG04lt7ybh8GgffGtepoA4oPN9OO9TeAoWDY0HJHDWCUwCpYzlaQK-gKCh5aVC4HVMeoppI',
+            'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64)  AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.108 Safari/537.36',
+            'x-client-data': 'CKi1yQEIhrbJAQijtskBCMG2yQEIqZ3KAQioo8oBCL+nygEI7KfKAQjiqMoBGPmlygE='
+        }
+
+    def get_tk(self, text):
+        return self.ctx.call("TL", text)
+
+    @staticmethod
+    def build_url(text, tk, tl='zh-CN'):
+        """
+        需要用转URLEncoder
+        :param text:
+        :param tk:
+        :param tl:
+        :return:
+        """
+        return f"https://translate.google.cn/translate_a/single?client=webapp&sl=auto&tl={tl}&hl=zh-CN&dt=at&dt=bd&dt=ex&dt=ld&dt=md&dt=qca&dt=rw&dt=rm&dt=ss&dt=t&source=btn&ssel=0&tsel=0&kc=0&tk={tk}&q={quote(text, encoding='utf-8')}"
+
+    def translate(self, text, output_type='zh-CN'):
+        """
+        language_type为要翻译的语言
+        de:德语
+        ja:日语
+        sv:瑞典语
+        nl:荷兰语
+        ar:阿拉伯语
+        ko:韩语
+        pt:葡萄牙语
+        zh-CN:中文简体
+        zh-TW:中文繁体
+        """
+        # url = 'https://translate.google.cn/translate_a/single'
+        # data = {
+        # 	'client': 'webapp',
+        # 	'sl': 'auto',
+        # 	'tl': output_type,
+        # 	'hl': 'zh-CN',
+        # 	'dt': 'at',
+        # 	'source': 'btn',
+        # 	'ssel': '0',
+        # 	'tsel': '0',
+        # 	'kc': '0',
+        # 	'tk': self.get_tk(text),
+        # 	'q': quote(text, encoding='utf-8'),
+        # }
+        url = self.build_url(text, self.get_tk(text), output_type)
+        try:
+            logger.info(f"GoogleApi.translate:request: {url}")
+            # response = requests.get(url=url, headers=self.headers, params=data)
+            response = requests.get(url=url, headers=self.headers)
+            logger.info(f"GoogleApi.translate:response: {response.status_code}")
+        except Exception as e:
+            import traceback
+            logger.info(f"GoogleApi.translate:error: {e.__class__.__name__}")
+            logger.info(f"GoogleApi.translate:details: {traceback.format_exc()}")
+            return ''
+        if response.status_code > 300:
+            logger.info(f"GoogleApi.translate:status: {response.status_code}")
+            logger.info(f"GoogleApi.translate:reason: {response.reason}")
+            logger.info(f"GoogleApi.translate:result: {response.text}")
+            return ''
+        else:
+            return response.json()[0][0][0]
+
+
+if __name__ == '__main__':
+    word = '** RESERVED ** This candidate has been reserved by an organization or individual that will use it when announcing a new security problem. When the candidate has been publicized, the details for this candidate will be provided.'
+    api = Api()
+    translate_result = api.translate(word)
+    print(translate_result)

+ 123 - 0
3rdparty/xapi/hik/api.py

@@ -0,0 +1,123 @@
+# update: 2022-6-24
+"""
+海康人脸摄像机接口
+
+    提供 read 1、read 100,两种方法
+"""
+import requests
+import datetime
+import time
+
+import sys
+import importlib
+
+# sys.path.append('/home/server/projects/taiwuict/cscec-8bur-vms/supplement-python')
+sys.path.append(r'D:\share\gitee\taiwuict.cscec-8bur-vms\supplement-python')  # for pc
+methods = importlib.import_module(f"libraries.base_original")
+
+
+class API(object):
+
+    def __init__(self):
+        self.camera_ipv4 = None
+        self.camera_user = None
+        self.camera_pass = None
+        self.client = None
+        self.last_receive_at = None
+
+    def connect_camera(self, camera_ipv4, camera_user, camera_pass):
+        """
+        连接摄像机
+        """
+        self.camera_ipv4 = camera_ipv4
+        self.camera_user = camera_user
+        self.camera_pass = camera_pass
+        session = requests.session()
+        request_url = f'http://{self.camera_ipv4}:80/ISAPI/Event/notification/alertStream'  # 设置认证信息
+        auth = requests.auth.HTTPDigestAuth(self.camera_user, self.camera_pass)  # 发送请求,获取响应
+        self.client = session.get(request_url, auth=auth, verify=False, stream=True)
+
+    def throw(self, backdata, image_hex):
+        """
+        回传数据
+        """
+        if backdata is None:
+            return
+        if self.camera_ipv4 not in backdata:
+            backdata[self.camera_ipv4] = dict()
+        object_id = str(time.time())
+        backdata[self.camera_ipv4][object_id] = dict()
+        backdata[self.camera_ipv4][object_id]['tracking_is'] = False
+        backdata[self.camera_ipv4][object_id]['hex_image'] = image_hex
+
+    def read1(self, backdata=None):
+        """
+        """
+        # --- define ---
+        image_hex = str()
+        start_is = False
+        print_is = False
+        hex_start = ''
+        hex_end = ''
+
+        while True:
+
+            # --- get ---
+            line = self.client.raw.read(1)
+            line = line.hex()
+
+            # --- fill ---
+            now_at = time.time()
+            if not self.last_receive_at:
+                self.last_receive_at = now_at
+            if line:
+                self.last_receive_at = now_at
+
+            # --- fill ---
+            hex_start += line
+
+            # --- check ---
+            if len(hex_start) > 8:
+                hex_start = hex_start[-8:]
+
+            # --- check ---
+            if '0d0affd8' == hex_start:
+                start_is = True
+                image_hex = 'ff'
+                methods.debug_log('hikvision_detector',
+                                  f"m-44: 0d0affd8 is {datetime.datetime.now().strftime('%H:%M:%S.%f')}")
+
+            # --- fill ---
+            if start_is:
+                image_hex += line
+
+            # --- check ---
+            if start_is:
+
+                hex_end += line
+
+                if len(hex_end) > 8:
+                    hex_end = hex_end[-8:]
+
+                if 'ffd90d0a' == hex_end:
+                    print_is = True
+                    image_hex = image_hex[:-4]
+                    methods.debug_log('hikvision_detector',
+                                      f"m-44: ffd90d0a is {datetime.datetime.now().strftime('%H:%M:%S.%f')}")
+
+            # --- fill ---
+            if print_is:
+                self.throw(backdata, image_hex)
+                image_hex = str()
+                hex_start = str()
+                hex_end = str()
+                start_is = False
+                print_is = False
+
+
+if __name__ == '__main__':
+    # --- init ---
+    middledata = {}
+    agent = API()
+    agent.connect_camera(camera_ipv4='192.168.0.181', camera_user='admin', camera_pass='DEVdev123')
+    agent.read1({})

+ 92 - 0
3rdparty/xapi/hik/read100.py

@@ -0,0 +1,92 @@
+from hub import methods, Global
+from middledata import Middledata
+
+import requests
+import time
+
+
+def main(args):
+
+    while True:
+        try:
+            camera_ipv4, camera_user, camera_pass = args[1], args[2], args[3]
+            request_url = f'http://{camera_ipv4}:80/ISAPI/Event/notification/alertStream'  # 设置认证信息
+            auth = requests.auth.HTTPDigestAuth(camera_user, camera_pass)  # 发送请求,获取响应
+            session = requests.session()
+            response = session.get(request_url, auth=auth, verify=False, stream=True)
+
+            print(response.headers)
+            print(response.headers.get('content-type'))
+
+            image_hex = str()
+            start_is = False
+            print_is = False
+
+            while True:
+
+                # --- check ---
+                # now_at = time.time()
+                # if (now_at - run_at) > 300.0:  # todo 5分钟检测一次
+                #     run_at = now_at
+                #     while True:
+                #         rtsp = f"rtsp://{camera_user}:{camera_pass}@{camera_ipv4}:554/h264/ch1/main/av_stream"
+                #         cap = cv2.VideoCapture(rtsp)
+                #         ret, _ = cap.read()
+                #         if ret:
+                #             break
+                #         else:
+                #             methods.debug_log('hikvision_detector', f"m-40: wait 1 minutes try again!")
+                #             time.sleep(60)
+
+                # --- get ---
+                line = response.raw.read(100)
+                # line = response.raw.read(1024*1024)
+                # line = response.raw.read(1024*256)
+                # methods.debug_log('hikvision_detector', f"m-52: check at {methods.now_string()}")
+                # methods.debug_log('hikvision_detector', f"m-52: line | {line} | {type(line)}")
+
+                # --- check ---
+                if not line:
+                    continue
+
+                line = line.hex()
+
+                # --- check ---
+                if '0d0affd8' in line:
+                    # methods.debug_log('hikvision_detector', f"m-52: check start at {methods.now_string()}")
+                    start_is = True
+                    line = 'ffd8' + line.split('0d0affd8')[1]
+
+                # --- check ---
+                if 'ffd90d0a' in line:
+                    # methods.debug_log('hikvision_detector', f"m-52: check end at {methods.now_string()}")
+                    print_is = True
+                    line = line.split('ffd90d0a')[0] + 'ffd9'
+
+                # --- fill ---
+                if start_is:
+                    image_hex += line
+
+                # --- save ---
+                if print_is:
+                    # --- fill ---
+                    object_id = str(time.time())
+                    Middledata.target_dict[object_id] = dict()
+                    Middledata.target_dict[object_id]['tracking_is'] = False
+                    Middledata.target_dict[object_id]['hex_image'] = image_hex  # base64.b16decode(image_hex.upper())
+
+                    # --- update ---
+                    image_hex = str()
+                    start_is = False
+                    print_is = False
+
+        except Exception as exception:
+            methods.debug_log('hikvision_detector', f"m-64: exception | {exception}")
+            methods.debug_log('hikvision_detector', f"m-64: wait 10 minutes try again!")
+            time.sleep(600)
+            continue
+
+
+if __name__ == '__main__':
+    _args = ['python3', '192.168.0.181', 'admin', 'DEVdev123']
+    main(_args)

BIN=BIN
3rdparty/xapi/mccbts/1.txt


+ 302 - 0
3rdparty/xapi/mccbts/api.py

@@ -0,0 +1,302 @@
+# update: 2023-11-11
+"""
+中冶宝钢智慧研究院接口
+"""
+from urllib import parse
+import requests
+import time
+import traceback
+
+import sys
+import importlib
+
+sys.path.append(r'C:\mccbts-ar-py\module-method-python')  # for 10.10.61.22
+# sys.path.append(r'D:\mccbts-ar-py\module-method-python')  # for 192.168.103.34
+methods = importlib.import_module(f"xlib")
+
+
+class API(object):
+
+    # def __init__(self, username='System001', password='Swdx@143',
+    def __init__(self, username='', password=''):
+        """
+        接口地址: https://eaiops.mccbts.com.cn/cigpf-gateway/cigpf-auth/login
+        接口说明: 用户认证接口,mcctest/Mcc@1234
+
+        接口地址: http://ycpx04.mccbts.com.cn/cnki-gw/expert/expert/getExpertList
+        接口说明:获取专家列表
+
+        接口地址: http://10.8.0.151:8000/datachange/release/interface
+        接口说明:该接口可以获取用户数据、部门数据
+        """
+
+        # --- define ---
+        self.cigpf_api_service = f"https://eaiops.mccbts.com.cn"
+        self.cnki_api_service = f"http://ycpx04.mccbts.com.cn"
+        self.datachange_api_service = f"http://10.8.0.151:8000"
+
+        self.LIST_USER_TOKEN = 'FA460AD97660475BBD8E1CF31BC7A49B'
+        self.LIST_DEPT_TOKEN = '4412B9724D254E38B57014CF99EB0312'
+
+    def get_user_info(self, username, password):
+        """
+        获取用户信息
+        return {
+            'success': True,
+            'message': '操作成功!',
+            'code': 200,
+            'result': {
+                'id': '1399259233832144898',
+                'username': 'mcctest',
+                'realname': '测试账号',
+                'avatar': '/cigpfupload/05a5b1ab84a446c4a2e126da89b0c0af.png',
+                'birthday': None,
+                'sex': None,
+                'thirdId': '',
+                'thirdType': 'qt',
+                'email': None,
+                'phone': '18210635895',
+                'orgCode': '1',
+                'orgCodeTxt': None,
+                'status': 1,
+                'delFlag': 0,
+                'workNo': '99999',
+                'post': None,
+                'telephone': None,
+                'createBy': '',
+                'createTime': None,
+                'updateBy': '张宇',
+                'updateTime': '2023-11-07 06:00:09',
+                'activitiSync': 1,
+                'userIdentity': 2,
+                'departIds': '1000051C',
+                'relTenantIds': None,
+                'clientId': None,
+                'userType': '2'
+            },
+            'timestamp': 1699666081555
+        }
+        """
+        url = f"{self.cigpf_api_service}/cigpf-gateway/cigpf-auth/login"
+        # data = {
+        #     'userName': 'mcctest',  # 用户
+        #     'passWord': 'Mcc@1234',  # 密码
+        # }
+        data = {
+            'userName': username,  # 用户
+            'passWord': password,  # 密码
+        }
+        # print(f"API.get_user_info:data: {data}")
+        print('API.get_user_info.url:', url)
+        response = requests.post(url, json=data)
+
+        if response.status_code > 300:
+            print('API.get_user_info.result:', response.status_code)
+            print('API.get_user_info.detail:', response.text)
+            return {}
+        else:
+            print('API.get_user_info.result:', response.status_code)
+            return response.json()
+
+    def get_expert_type_tree_list(self):
+        """
+        获取专家结构树
+        """
+        url = f"http://ycpx04.mccbts.com.cn/cnki-gw/expert/expertType/getExpertTypeTreeList"
+        data = {
+            'keyword': ''
+        }
+        response = requests.post(url, json=data)
+        print('API.test.url:', url)
+        print('API.test.data:', data)
+        print('API.test.code:', response.status_code)
+        print('API.test.text:', response.text)
+
+    def get_expert_list(self, page=1, rows=10):
+        """
+        获取专家列表
+        return {
+            'msg': '操作成功',
+            'code': 200,
+            'data': {
+                'total': 320,
+                'list': [
+                    {
+                        'id': 407880669122629,
+                        'expertId': 'b46f7f7e-2883-4281-ba92-0c72fb30a668',
+                        'expertCode': '40886',
+                        'expertName': '冯浩川',
+                        'expertLogo': '',
+                        'sex': 1,
+                        'birthday': '1974-08-12 00:00:00',
+                        'education': None,
+                        'degree': None,
+                        'colleges': '',
+                        'politicalOutlook': '',
+                        'academicTitle': '',
+                        'expertTypeId': 'a0846382-dc33-44f5-990d-ea042ab90cf4',
+                        'expertType': '工程机械组',
+                        'workUnitOrCurrentPosition': '',
+                        'professionalAndTechnicalFields': '',
+                        'mainSocialPositions': '',
+                        'personalHonors': '',
+                        'project': [],
+                        'brief': '',
+                        'createTime': '2023-04-17 15:30:43',
+                        'createUserId': '6867b1b3-024f-4065-b991-3ebd48df7b27',
+                        'type': '',
+                        'companyId': '45b9801f-d2ff-4886-8076-7f7d8b403e37',
+                        'company': '协力生产分公司',
+                        'departmentId': '301e6551-dfd6-4e3e-b7f5-be36e14f84a1',
+                        'department': '协力_机械维修中心_管理组'
+                    }
+                ]
+            }
+        }
+        """
+        url = f"{self.cnki_api_service}/cnki-gw/expert/expert/getExpertList"
+        data = {
+            'pageDto': {
+                'page': page,
+                'rows': rows
+            }
+        }
+        # print(f"API.get_user_info:data: {data}")
+        print('API.get_expert_list.url:', url)
+        response = requests.post(url, json=data)
+
+        # --- check ---
+        if response.status_code > 300:
+            print('API.get_expert_list.result:', response.status_code)
+            print('API.get_expert_list.detail:', response.text)
+            return []
+
+        # --- check ---
+        data = response.json()
+        if data.get('code') != 200:
+            return []
+
+        # --- check ---
+        if not data:
+            return []
+
+        return data.get('data').get('list')
+
+    def get_staff_list(self):
+        """
+        获取员工列表
+        return [
+            {
+                'STATUS': '1',
+                'ORG_CODE': '1603605',
+                'UPDATE_BY': 'HR',
+                'CREATE_BY': 'HR',
+                'DEPART_NAME': '山西_天车二区_硅钢班',
+                'DEL_FLAG': '0',
+                'CREATE_TIME': 1659117651000,
+                'UPDATE_TIME': 1659117651000,
+                'ID': '1001G1AR',
+                'DEPART_NAME_ABBR': '山西_天车二区_硅钢班',
+                'C1': '1',
+                'PARENT_ID': '1001G1AM'
+            }
+        ]
+        """
+        url = f"{self.datachange_api_service}/datachange/release/interface"
+        headers = {'Chinasofti-Access-Token': self.LIST_USER_TOKEN}
+        print('API.get_staff_list.url:', url)
+        print('API.get_staff_list.headers:', headers)
+        response = requests.get(url, headers=headers)
+
+        # --- check ---
+        if response.status_code > 300:
+            print('API.get_staff_list.result:', response.status_code)
+            print('API.get_staff_list.detail:', response.text)
+            return []
+
+        # --- check ---
+        data = response.json()
+        if data.get('code') != 0:
+            print('API.get_staff_list.detail:', response.text)
+            return []
+
+        return data.get('data')
+
+    def get_department_list(self):
+        """
+        获取部门列表
+        return [
+            {
+                'ORG_ID': '10012B4J',
+                'REALNAME': '张天勤',
+                'POST': '电焊工',
+                'PHONE': '15921009690',
+                'SEX': 1,
+                'UPDATE_BY': 'HR',
+                'DEL_FLAG': 0,
+                'UPDATE_TIME': 1661492148000,
+                'WORK_NO2': '983260',
+                'STATUS': '1',
+                'PKID': 'C1924F31EE850472E050080A5C00BCBA',
+                'ORG_CODE': '153420410',
+                'CREATE_BY': 'HR',
+                'CREATE_TIME': 1620205014000,
+                'ID': '10000RBZ',
+                'WORK_NO': '983260',
+                'BIRTHDAY': '1967-02-09'
+            }
+        ]
+        """
+        url = f"{self.datachange_api_service}/datachange/release/interface"
+        headers = {'Chinasofti-Access-Token': self.LIST_DEPT_TOKEN}
+        print('API.get_department_list.url:', url)
+        print('API.get_department_list.headers:', headers)
+        response = requests.get(url, headers=headers)
+
+        # --- check ---
+        if response.status_code > 300:
+            print('API.get_department_list.result:', response.status_code)
+            print('API.get_department_list.detail:', response.text)
+            return []
+
+        # --- check ---
+        data = response.json()
+        if data.get('code') != 0:
+            print('API.get_department_list.code:', data.get('code'))
+            print('API.get_department_list.data:', response.text)
+            return []
+
+        return data.get('data')
+
+    def test(self):
+        """
+        """
+        url = f"http://ycpx04.mccbts.com.cn/cnki-gw/expert/expertType/getExpertTypeList"
+        data = {
+            'keyword': 'xxx'
+        }
+        response = requests.post(url, json=data)
+        print('API.test.url:', url)
+        print('API.test.data:', data)
+        print('API.test.code:', response.status_code)
+        print('API.test.text:', response.text)
+        # res = res.json()
+        # data = {
+        #     'count': len(res['data']),
+        #     'data': res['data']
+        # }
+
+
+if __name__ == '__main__':
+    # --- init ---
+    api = API()
+
+    # --- test ---
+    items = api.get_department_list()
+    for item in items:
+        if len(item.get('ORG_CODE')) == 3 and item.get('ORG_CODE')[0] == '1':
+            print(item)
+
+    # --- test ---
+    # out = api.get_expert_type_tree_list()
+    # print(out)

+ 564 - 0
3rdparty/xapi/nessus/api.py

@@ -0,0 +1,564 @@
+# update: 2021-6-28-19
+import requests
+import logging
+import time
+import copy
+import re
+
+requests.packages.urllib3.disable_warnings()
+TEMPLATES = ['PCI Quarterly External Scan', 'Host Discovery', 'WannaCry Ransomware', 'Intel AMT Security Bypass',
+             'Basic Network Scan', 'Credentialed Patch Audit', 'Web Application Tests', 'Malware Scan',
+             'Mobile Device Scan', 'MDM Config Audit', 'Policy Compliance Auditing', 'Internal PCI Network Scan',
+             'Offline Config Audit', 'Audit Cloud Infrastructure', 'SCAP and OVAL Auditing', 'Custom Scan',
+             'Bash Shellshock Detection', 'GHOST (glibc) Detection', 'DROWN Detection', 'Badlock Detection',
+             'Shadow Brokers Scan', 'Spectre and Meltdown', 'Advanced Scan', 'Advanced Dynamic Scan']
+DefaultPolicyForAdvancedScan = {
+    "uuid": "ad629e16-03b6-8c1d-cef6-ef8c9dd3c658d24bd260ef5f9e66",
+    "plugins": {
+        "SMTP problems": {"status": "enabled"},
+        "Backdoors": {"status": "enabled"},
+        "Ubuntu Local Security Checks": {"status": "enabled"},
+        "Gentoo Local Security Checks": {"status": "enabled"},
+        "Oracle Linux Local Security Checks": {"status": "enabled"},
+        "RPC": {"status": "enabled"},
+        "Gain a shell remotely": {"status": "enabled"},
+        "Service detection": {"status": "enabled"},
+        "DNS": {"status": "enabled"},
+        "Mandriva Local Security Checks": {"status": "enabled"},
+        "Junos Local Security Checks": {"status": "enabled"},
+        "Misc.": {"status": "enabled"},
+        "FTP": {"status": "enabled"},
+        "Slackware Local Security Checks": {"status": "enabled"},
+        "Default Unix Accounts": {"status": "enabled"},
+        "AIX Local Security Checks": {"status": "enabled"},
+        "SNMP": {"status": "enabled"},
+        "OracleVM Local Security Checks": {"status": "enabled"},
+        "CGI abuses": {"status": "enabled"},
+        "Settings": {"status": "enabled"},
+        "CISCO": {"status": "enabled"},
+        "Firewalls": {"status": "enabled"},
+        "Databases": {"status": "enabled"},
+        "Debian Local Security Checks": {"status": "enabled"},
+        "Fedora Local Security Checks": {"status": "enabled"},
+        "Netware": {"status": "enabled"},
+        "Huawei Local Security Checks": {"status": "enabled"},
+        "Windows : User management": {"status": "enabled"},
+        "VMware ESX Local Security Checks": {"status": "enabled"},
+        "Virtuozzo Local Security Checks": {"status": "enabled"},
+        "CentOS Local Security Checks": {"status": "enabled"},
+        "Peer-To-Peer File Sharing": {"status": "enabled"},
+        "NewStart CGSL Local Security Checks": {"status": "enabled"},
+        "General": {"status": "enabled"},
+        "Policy Compliance": {"status": "enabled"},
+        "Amazon Linux Local Security Checks": {"status": "enabled"},
+        "Solaris Local Security Checks": {"status": "enabled"},
+        "F5 Networks Local Security Checks": {"status": "enabled"},
+        "Denial of Service": {"status": "enabled"},
+        "Windows : Microsoft Bulletins": {"status": "enabled"},
+        "SuSE Local Security Checks": {"status": "enabled"},
+        "Palo Alto Local Security Checks": {"status": "enabled"},
+        "Red Hat Local Security Checks": {"status": "enabled"},
+        "PhotonOS Local Security Checks": {"status": "enabled"},
+        "HP-UX Local Security Checks": {"status": "enabled"},
+        "CGI abuses : XSS": {"status": "enabled"},
+        "FreeBSD Local Security Checks": {"status": "enabled"},
+        "Windows": {"status": "enabled"},
+        "Scientific Linux Local Security Checks": {"status": "enabled"},
+        "MacOS X Local Security Checks": {"status": "enabled"},
+        "Web Servers": {"status": "enabled"},
+        "SCADA": {"status": "enabled"}
+    },
+    "credentials": {"add": {}, "edit": {}, "delete": []},
+    "settings": {
+        "patch_audit_over_telnet": "no", "patch_audit_over_rsh": "no", "patch_audit_over_rexec": "no",
+        "snmp_port": "161", "additional_snmp_port1": "161", "additional_snmp_port2": "161",
+        "additional_snmp_port3": "161", "http_login_method": "POST", "http_reauth_delay": "",
+        "http_login_max_redir": "0", "http_login_invert_auth_regex": "no", "http_login_auth_regex_on_headers": "no",
+        "http_login_auth_regex_nocase": "no", "never_send_win_creds_in_the_clear": "yes",
+        "dont_use_ntlmv1": "yes", "start_remote_registry": "no", "enable_admin_shares": "no", "ssh_known_hosts": "",
+        "ssh_port": "22", "ssh_client_banner": "OpenSSH_5.0", "attempt_least_privilege": "no",
+        "region_dfw_pref_name": "yes", "region_ord_pref_name": "yes", "region_iad_pref_name": "yes",
+        "region_lon_pref_name": "yes", "region_syd_pref_name": "yes", "region_hkg_pref_name": "yes",
+        "microsoft_azure_subscriptions_ids": "", "aws_ui_region_type": "Rest of the World",
+        "aws_us_east_1": "", "aws_us_east_2": "", "aws_us_west_1": "", "aws_us_west_2": "",
+        "aws_ca_central_1": "", "aws_eu_west_1": "", "aws_eu_west_2": "", "aws_eu_west_3": "",
+        "aws_eu_central_1": "", "aws_eu_north_1": "", "aws_ap_east_1": "", "aws_ap_northeast_1": "",
+        "aws_ap_northeast_2": "", "aws_ap_northeast_3": "", "aws_ap_southeast_1": "", "aws_ap_southeast_2": "",
+        "aws_ap_south_1": "", "aws_me_south_1": "", "aws_sa_east_1": "", "aws_use_https": "yes",
+        "aws_verify_ssl": "yes", "log_whole_attack": "no", "enable_plugin_debugging": "no",
+        "audit_trail": "use_scanner_default", "include_kb": "use_scanner_default", "enable_plugin_list": "no",
+        "custom_find_filepath_exclusions": "", "custom_find_filesystem_exclusions": "",
+        "reduce_connections_on_congestion": "no", "network_receive_timeout": "5", "max_checks_per_host": "5",
+        "max_hosts_per_scan": "100", "max_simult_tcp_sessions_per_host": "", "max_simult_tcp_sessions_per_scan": "",
+        "safe_checks": "yes", "stop_scan_on_disconnect": "no", "slice_network_addresses": "no",
+        "allow_post_scan_editing": "yes", "reverse_lookup": "no", "log_live_hosts": "no",
+        "display_unreachable_hosts": "no", "report_verbosity": "Normal", "report_superseded_patches": "yes",
+        "silent_dependencies": "yes", "scan_malware": "no", "samr_enumeration": "yes", "adsi_query": "yes",
+        "wmi_query": "yes", "rid_brute_forcing": "no", "request_windows_domain_info": "no",
+        "scan_webapps": "no", "test_default_oracle_accounts": "no", "provided_creds_only": "yes",
+        "smtp_domain": "example.com", "smtp_from": "nobody@example.com", "smtp_to": "postmaster@[AUTO_REPLACED_IP]",
+        "av_grace_period": "0", "report_paranoia": "Normal", "thorough_tests": "no",
+        "svc_detection_on_all_ports": "yes", "detect_ssl": "yes", "ssl_prob_ports": "Known SSL ports",
+        "cert_expiry_warning_days": "60", "enumerate_all_ciphers": "yes", "check_crl": "no",
+        "tcp_scanner": "no", "tcp_firewall_detection": "Automatic (normal)", "syn_scanner": "yes",
+        "syn_firewall_detection": "Automatic (normal)", "udp_scanner": "no", "ssh_netstat_scanner": "yes",
+        "wmi_netstat_scanner": "yes", "snmp_scanner": "yes", "only_portscan_if_enum_failed": "yes",
+        "verify_open_ports": "no", "unscanned_closed": "no", "portscan_range": "default",
+        "wol_mac_addresses": "", "wol_wait_time": "5", "scan_network_printers": "no", "scan_netware_hosts": "no",
+        "scan_ot_devices": "no", "ping_the_remote_host": "yes", "arp_ping": "yes", "tcp_ping": "yes",
+        "tcp_ping_dest_ports": "built-in", "icmp_ping": "yes", "icmp_unreach_means_host_down": "no",
+        "icmp_ping_retries": "2", "udp_ping": "no", "test_local_nessus_host": "yes",
+        "fast_network_discovery": "no", "name": "test-1122", "description": ""
+    }
+}
+
+
+class Api(object):
+
+    def __init__(self, service_url='https://47.104.160.37:8001', username='admin', password='admin'):
+        self.debugs = str()
+        self.errors = str()
+        self.urls = list()
+        self.service_url = service_url
+        self.headers = dict()
+        self.headers['content-type'] = 'application/json'
+        self.headers['X-API-Token'] = self.get_api_token()
+        self.create_super_user(username, password)
+        token = self.get_session(username, password)
+        self.headers['X-Cookie'] = f'token={token}'
+
+    def debug(self, **kwargs):
+        for k, v in kwargs.items():
+            self.debugs += str(k) + ':' + str(v) + ';'
+
+    def error(self, **kwargs):
+        for k, v in kwargs.items():
+            self.errors += str(k) + ':' + str(v) + ';'
+
+    def get_policy_id_by_name(self, name):
+        """根据策略名称获取策略id"""
+        for policy in self.get_policies():
+            if policy['name'] != name:
+                continue
+            return policy['id']
+        return ''
+
+    def get_template_id_by_title(self, title):
+        """根据策略类型标题获取策略类型id"""
+        if title not in TEMPLATES:
+            return ''
+        for template in self.get_templates():
+            if template['title'] != title:
+                continue
+            return template['uuid']
+        return ''
+
+    def scan_is_completed(self, scan_id):
+        """检查执行状态"""
+        return self.get_scan_status(scan_id) == 'completed'
+
+    def create_super_user(self, username, password):
+        """创建超级管理员用户"""
+        # --- 是否为register ---
+        if self.server_status() != 'register':
+            return
+        self.create_user(username, password)
+        self.server_restart()
+        # --- 等待loading结束 ---
+        while True:
+            try:
+                if self.server_status() == 'ready':
+                    break
+                print(self.server_status())
+                time.sleep(5)
+            except Exception as e:
+                print(e.__class__.__name__)
+                time.sleep(5)
+
+    def create_user(self, username, password):
+        """
+        url: https://<ip地址>:8834/users
+        """
+        if 'register' != self.server_status():
+            return 0
+
+        url = f'{self.service_url}/users'
+        data = {
+            'username': username,
+            'password': password,
+            'permissions': 128,
+        }
+
+        print('NessusApiLog:create_user:url:', url)
+        response = requests.post(url=url, json=data, headers=self.headers, verify=False)
+        print('NessusApiLog:create_user:result:', response.status_code)
+
+        if response.status_code > 300:
+            self.error(method='create_user', result=response.text)
+            return 0
+        else:
+            self.urls.append(url)
+            self.debug(method='create_user', result=response.text)
+            return response.json()['id']
+
+    def server_restart(self):
+        """
+        url: https://<ip地址>:8834/server/restart
+        """
+        url = f'{self.service_url}/server/restart'
+
+        print('NessusApiLog:server_restart:url:', url)
+        response = requests.post(url=url, headers=self.headers, verify=False)
+        print('NessusApiLog:server_restart:result:', response.status_code)
+
+        if response.status_code > 300:
+            self.error(method='server_restart', result=response.text)
+            return False
+        else:
+            self.debug(method='server_restart', result=response.text)
+            return True
+
+    def server_status(self):
+        """
+        url: https://118.190.217.96:8001/server/status
+        status:
+            loading
+            register
+            ready
+        """
+        url = f'{self.service_url}/server/status'
+
+        print('NessusApiLog:server_status:url:', url)
+        response = requests.get(url=url, headers=self.headers, verify=False)
+        print('NessusApiLog:server_status:result:', response.status_code)
+
+        if response.status_code > 300:
+            self.error(method='restart', result=response.text)
+            return ''
+        else:
+            self.debug(method='restart', result=response.text)
+            return response.json()['status']
+
+    def get_session(self, username, password):
+        """
+        url: http://<ip地址>:8834/session
+        """
+        url = f'{self.service_url}/session'
+        data = {
+            'username': username,
+            'password': password,
+        }
+        print('NessusApiLog:get_token:url:', url)
+        response = requests.post(url=url, json=data, headers=self.headers, verify=False)
+        print('NessusApiLog:get_token:result:', response.status_code)
+
+        if response.status_code > 300:
+            self.error(method='get_token', result=response.text)
+        else:
+            self.urls.append(url)
+            self.debug(method='get_token', result=response.text)
+            return response.json()['token']
+
+    def get_keys(self):
+        """
+        url: http://<ip地址>:8834/session/keys
+        doc: https://47.104.160.37:8001/api#/resources/session/keys
+        """
+        url = f'{self.service_url}/session/keys'
+
+        print('NessusApiLog:get_keys:url:', url)
+        response = requests.put(url=url, headers={'content-type': 'application/json'}, verify=False)
+        print('NessusApiLog:get_keys:result:', response.status_code)
+
+        if response.status_code > 300:
+            self.error(method='get_keys', result=response.text)
+            return {}
+        else:
+            self.debug(method='get_keys', result=response.text)
+            return response.json()
+
+    def get_policy(self, policy_id):
+        """
+        url: http://<ip地址>:8834/policies/<policy_id>
+        """
+        url = f'{self.service_url}/policies/{policy_id}'
+        print('NessusApiLog:get_policy:url:', url)
+        response = requests.get(url, headers=self.headers, verify=False)
+        print('NessusApiLog:get_policy:result:', response.status_code)
+
+        if response.status_code > 300:
+            self.error(method='get_policy', result=response.text)
+        else:
+            self.urls.append(url)
+            self.debug(method='get_policy', result=response.text)
+            return response.json()
+
+    def get_policies(self):
+        """
+        url: http://<ip地址>:8834/policies
+        """
+        url = f'{self.service_url}/policies'
+        print('NessusApiLog:get_policies:url:', url)
+        response = requests.get(url, headers=self.headers, verify=False, timeout=300)
+        print('NessusApiLog:get_policies:result:', response.status_code)
+
+        if response.status_code > 300:
+            self.error(method='get_policies', result=response.text)
+        else:
+            self.urls.append(url)
+            self.debug(method='get_policies', result=response.text)
+            return response.json()['policies']
+
+    def get_scan_status(self, scan_id):
+        """
+        url: http://<ip地址>:8834/scans/<scan_id>
+        """
+        url = f'{self.service_url}/scans/{scan_id}'
+        params = {'includeHostDetailsForHostDiscovery': 'true', 'limit': 2500}
+
+        print('NessusApiLog:get_scan:url:', url)
+        response = requests.get(url, headers=self.headers, params=params, verify=False)
+        print('NessusApiLog:get_scan:result:', response.status_code)
+
+        if response.status_code > 300:
+            self.error(method='get_scan', result=response.text)
+        else:
+            self.urls.append(url)
+            self.debug(method='get_scan', result=response.text)
+            return response.json()['info']['status']
+
+    def get_scan(self, scan_id):
+        """
+        url: http://<ip地址>:8834/scans/<scan_id>
+        """
+        url = f'{self.service_url}/scans/{scan_id}'
+        params = {'includeHostDetailsForHostDiscovery': 'true', 'limit': 2500}
+
+        print('NessusApiLog:get_scan:url:', url)
+        response = requests.get(url, headers=self.headers, params=params, verify=False)
+        print('NessusApiLog:get_scan:result:', response.status_code)
+
+        if response.status_code > 300:
+            self.error(method='get_scan', result=response.text)
+        else:
+            self.urls.append(url)
+            self.debug(method='get_scan', result=response.text)
+            return response.json()['hosts']
+
+    def get_scans(self):
+        """
+        url: http://<ip地址>:8834/scans
+        """
+        url = f'{self.service_url}/scans'
+
+        print('NessusApiLog:get_scans:url:', url)
+        response = requests.get(url, headers=self.headers, verify=False)
+        print('NessusApiLog:get_scans:result:', response.status_code)
+
+        if response.status_code > 300:
+            self.error(method='get_scans', result=response.text)
+        else:
+            self.urls.append(url)
+            self.debug(method='get_scans', result=response.text)
+            return response.json()['scans']
+
+    def create_scan(self, template_uuid, scan_name, policy_id, targets):
+        """
+        url: http://<ip地址>:8834/scans
+        doc: https://192.168.20.162:8834/api#/resources/scans/create
+        """
+        url = f'{self.service_url}/scans'
+        data = {
+            "uuid": template_uuid,
+            "settings": {
+                "emails": "",
+                "filter_type": "and",
+                "filters": [],
+                "launch_now": True,
+                "enabled": False,
+                "name": scan_name,
+                "description": "",
+                # "folder_id": 3,
+                # "scanner_id": "1",
+                "policy_id": str(policy_id),
+                "text_targets": targets,
+                "file_targets": ""
+            }
+        }
+
+        print('NessusApiLog:create_scan:url:', url)
+        response = requests.post(url, json=data, headers=self.headers, verify=False)
+        print('NessusApiLog:create_scan:result:', response.status_code)
+
+        if response.status_code > 300:
+            self.error(method='create_scan', result=response.text)
+        else:
+            self.urls.append(url)
+            self.debug(method='create_scan', result=response.text)
+            return response.json()['scan']['id']
+
+    def delete_scan(self, scan_id):
+        """
+        url: http://<ip地址>:8834/scans/<scan_id>
+        """
+        url = f'{self.service_url}/scans/{scan_id}'
+
+        print('NessusApiLog:delete_scan:url:', url)
+        response = requests.delete(url, headers=self.headers, verify=False)
+        print('NessusApiLog:delete_scan:result:', response.status_code)
+
+        if response.status_code > 300:
+            self.error(method='delete_scan', result=response.text)
+            return False
+        else:
+            self.urls.append(url)
+            self.debug(method='delete_scan', result=response.text)
+            return True
+
+    def start_scan(self, scan_id):
+        """
+        url: http://<ip地址>:8834/scans/<scan_id>/launch
+        """
+        url = f'{self.service_url}/scans/{scan_id}/launch'
+
+        print('NessusApiLog:start_scan:url:', url)
+        response = requests.post(url, json={}, headers=self.headers, verify=False)
+        print('NessusApiLog:start_scan:result:', response.status_code)
+
+        if response.status_code > 300:
+            self.error(method='start_scan', result=response.text)
+        else:
+            self.urls.append(url)
+            self.debug(method='start_scan', result=response.text)
+            return response.json()
+
+    def get_host(self, scan_id, host_id):
+        """
+        url: https://192.168.20.162:8834/scans/68/hosts/232
+        doc: https://192.168.20.162:8834/api#/resources/scans/host-details
+        """
+        url = f'{self.service_url}/scans/{scan_id}/hosts/{host_id}'
+
+        print('NessusApiLog:get_host:url:', url)
+        response = requests.get(url, params={}, headers=self.headers, verify=False)
+        print('NessusApiLog:get_host:result:', response.status_code)
+
+        if response.status_code > 300:
+            self.error(method='get_host', result=response.text)
+        else:
+            self.urls.append(url)
+            self.debug(method='get_host', result=response.text)
+            return response.json()
+
+    def get_plugin(self, scan_id, host_id, plugin_id):
+        """
+        url: https://192.168.20.162:8834/scans/68/hosts/232/plugins/100464
+        """
+        url = f'{self.service_url}/scans/{scan_id}/hosts/{host_id}/plugins/{plugin_id}'
+
+        print('NessusApiLog:get_plugin:url:', url)
+        response = requests.get(url, params={}, headers=self.headers, verify=False)
+        print('NessusApiLog:get_plugin:result:', response.status_code)
+
+        if response.status_code > 300:
+            self.error(method='get_plugin', result=response.text)
+        else:
+            self.urls.append(url)
+            self.debug(method='get_plugin', result=response.text)
+            return response.json()
+
+    def get_plugin_info(self, plugin_id):
+        """
+        url: https://192.168.20.162:8834/plugins/plugin/{id}
+        doc: https://192.168.20.162:8834/api#/resources/plugins/plugin-details
+        """
+        url = f'{self.service_url}/plugins/plugin/{plugin_id}'
+
+        print('NessusApiLog:get_plugin_info:url:', url)
+        response = requests.get(url, params={}, headers=self.headers, verify=False)
+        print('NessusApiLog:get_plugin_info:result:', response.status_code)
+
+        if response.status_code > 300:
+            self.error(method='get_plugin_info', result=response.text)
+        else:
+            self.urls.append(url)
+            self.debug(method='get_plugin_info', result=response.text)
+            return response.json()
+
+    def get_templates(self, template_type='policy'):
+        """
+        url: https://172.30.2.8:8001/editor/{type}/templates
+        doc: https://172.30.2.8:8001/api#/resources/editor/list
+        """
+        url = f'{self.service_url}/editor/{template_type}/templates'
+
+        print('NessusApiLog:get_templates:url:', url)
+        response = requests.get(url, params={}, headers=self.headers, verify=False)
+        print('NessusApiLog:get_templates:result:', response.status_code)
+
+        if response.status_code > 300:
+            self.error(method='get_templates', result=response.text)
+        else:
+            self.urls.append(url)
+            self.debug(method='get_templates', result=response.text)
+            return response.json()['templates']
+
+    def create_policy(self, template_uuid, policy_name, settings=None):
+        """
+        url: https://192.168.20.162:8834/policies
+        doc: https://192.168.20.162:8834/api#/resources/policies/create
+        """
+        url = f'{self.service_url}/policies/'
+
+        data = copy.copy(DefaultPolicyForAdvancedScan)
+        data['uuid'] = template_uuid
+        data['settings']['name'] = policy_name
+        if settings:
+            data['settings'].update(settings)
+
+        print('NessusApiLog:create_policy:url:', url)
+        response = requests.post(url, json=data, headers=self.headers, verify=False)
+        print('NessusApiLog:create_policy:result:', response.status_code)
+
+        if response.status_code > 300:
+            self.error(method='create_policy', result=response.text)
+            return ''
+        else:
+            self.urls.append(url)
+            self.debug(method='create_policy', result=response.text)
+            return response.json()['policy_id']
+
+    def get_api_token(self):
+        """
+        url: https://192.168.20.162:8844/nessus6.js?v=1583846805284
+        """
+        url = f'{self.service_url}/nessus6.js'
+        params = {'v': 1583846805284}
+
+        print('NessusApiLog:get_api_token:url:', url)
+        response = requests.get(url=url, params=params, headers=self.headers, verify=False)
+        print('NessusApiLog:get_api_token:result:', response.status_code)
+
+        if response.status_code > 300:
+            # self.error(method='get_api_token', result=response.text)
+            return ''
+        else:
+            self.urls.append(url)
+            # self.debug(method='get_api_token', result=response.text)
+            pattern = r'return"([0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12})'
+            return re.findall(pattern, response.text)[0]
+
+
+if __name__ == '__main__':
+    # api = Api(service_url='https://118.190.217.96:8001', username='admin', password='admin')
+    # api = Api(service_url='https://47.104.224.202:8001', username='admin', password='admin')
+    api = Api(service_url='https://172.30.2.8:8001', username='admin', password='admin')
+
+    # --- test api ---
+    # print(api.server_status())
+    # print(api.server_restart())
+    # print(api.server_status())
+    print(api.get_policies())
+    print(api.errors)
+    # print(api.get_templates())
+    # print(api.get_template_id_by_title('Advanced Scan'))

+ 124 - 0
3rdparty/xapi/onvif/api.py

@@ -0,0 +1,124 @@
+# note: https://github.com/FalkTannhaeuser/python-onvif-zeep
+# note: https://blog.csdn.net/zong596568821xp/article/details/89644654
+from onvif import ONVIFCamera
+import zeep
+import time
+
+mycam = ONVIFCamera('192.168.30.130', 80, 'admin', '123456',
+                    '/home/packages/test/test_onvif/python-onvif-zeep-0.2.12/wsdl/')
+
+# Create media service object
+media = mycam.create_media_service()
+# Create ptz service object
+ptz = mycam.create_ptz_service()
+
+
+# Get target profile
+def zeep_pythonvalue(self, xmlvalue):
+    return xmlvalue
+
+
+zeep.xsd.simple.AnySimpleType.pythonvalue = zeep_pythonvalue
+media_profile = media.GetProfiles()[0]
+
+# Get PTZ configuration options for getting continuous move range
+request = ptz.create_type('GetConfigurationOptions')
+request.ConfigurationToken = media_profile.PTZConfiguration.token
+ptz_configuration_options = ptz.GetConfigurationOptions(request)
+request = ptz.create_type('ContinuousMove')
+request.ProfileToken = media_profile.token
+ptz.Stop({'ProfileToken': media_profile.token})
+
+if request.Velocity is None:
+    request.Velocity = ptz.GetStatus({'ProfileToken': media_profile.token}).Position
+    request.Velocity = ptz.GetStatus({'ProfileToken': media_profile.token}).Position
+    request.Velocity.PanTilt.space = ptz_configuration_options.Spaces.ContinuousPanTiltVelocitySpace[0].URI
+    request.Velocity.Zoom.space = ptz_configuration_options.Spaces.ContinuousZoomVelocitySpace[0].URI
+
+XMAX = ptz_configuration_options.Spaces.ContinuousPanTiltVelocitySpace[0].XRange.Max
+XMIN = ptz_configuration_options.Spaces.ContinuousPanTiltVelocitySpace[0].XRange.Min
+YMAX = ptz_configuration_options.Spaces.ContinuousPanTiltVelocitySpace[0].YRange.Max
+YMIN = ptz_configuration_options.Spaces.ContinuousPanTiltVelocitySpace[0].YRange.Min
+
+
+def move_right(_ptz, _request):
+    """向右持续移动n秒"""
+    print('move right...')
+    _request.Velocity.PanTilt.x = XMAX
+    _request.Velocity.PanTilt.y = 0
+    # Start continuous move
+    _ptz.ContinuousMove(_request)
+    # Wait a certain time
+    time.sleep(1)
+    # Stop continuous move
+    _ptz.Stop({'ProfileToken': _request.ProfileToken})
+
+
+def move_left(_ptz, _request):
+    """向左持续移动n秒"""
+    print('move left...')
+    _request.Velocity.PanTilt.x = XMIN
+    _request.Velocity.PanTilt.y = 0
+    # Start continuous move
+    _ptz.ContinuousMove(_request)
+    # Wait a certain time
+    time.sleep(0.5)
+    # Stop continuous move
+    _ptz.Stop({'ProfileToken': _request.ProfileToken})
+
+
+def move_up(_ptz, _request):
+    """向上持续移动n秒"""
+    print('move up...')
+    request.Velocity.PanTilt.x = 0
+    request.Velocity.PanTilt.y = YMAX
+    # Start continuous move
+    _ptz.ContinuousMove(_request)
+    # Wait a certain time
+    time.sleep(0.5)
+    # Stop continuous move
+    _ptz.Stop({'ProfileToken': _request.ProfileToken})
+
+
+def move_down(_ptz, _request):
+    """向下持续移动n秒"""
+    print('move down...')
+    request.Velocity.PanTilt.x = 0
+    request.Velocity.PanTilt.y = YMIN
+    # Start continuous move
+    _ptz.ContinuousMove(_request)
+    # Wait a certain time
+    time.sleep(0.5)
+    # Stop continuous move
+    _ptz.Stop({'ProfileToken': _request.ProfileToken})
+
+
+# move_right(ptz, request)
+# move_left(ptz, request)
+# move_up(ptz, request)
+# move_down(ptz, request)
+
+def zoom_in(_ptz, _request):
+    print('zoom in...')
+    _request.Velocity.Zoom.x = 1
+    # Start continuous move
+    _ptz.ContinuousMove(_request)
+    # Wait a certain time
+    time.sleep(1)
+    # Stop continuous move
+    _ptz.Stop({'ProfileToken': _request.ProfileToken})
+
+
+def zoom_out(_ptz, _request):
+    print('zoom out...')
+    _request.Velocity.Zoom.x = -1
+    # Start continuous move
+    _ptz.ContinuousMove(_request)
+    # Wait a certain time
+    time.sleep(1)
+    # Stop continuous move
+    _ptz.Stop({'ProfileToken': _request.ProfileToken})
+
+
+zoom_in(ptz, request)
+# zoom_out(ptz, request)

+ 263 - 0
3rdparty/xapi/ros1/api_for_hs.py

@@ -0,0 +1,263 @@
+# update: 2024-3-20
+"""
+车辆控制器API
+"""
+from urllib import parse
+import requests
+import time
+import traceback
+
+import sys
+import importlib
+
+sys.path.append(r'E:\casper\repositories\repositories\casperz.py-project\module-py')  # for pc
+# sys.path.append(r'D:\casper\gitee\casperz.py-project\module-py')  # for pc
+methods = importlib.import_module(f"xlib")
+
+
+class API(object):
+
+    def __init__(self, address='192.168.191.91', port=8000):
+        """
+        start_plan 启动任务
+        abort_plan 终止任务
+        start_engine 远程打火
+        stall_engine 远程熄火
+        apply_use_by_ip 申请远程操作模式 1 申请远程操作模式 2 申请自动作业模式
+        """
+        # --- define ---
+        self.port = port
+        # self.url = f"http://{address}:{port}"
+
+    def cmd1001(self, address='192.168.191.91', navigation=[]):
+        """
+        启动行驶
+        data = {
+            # 指令类型
+            "cmdid": 1001,  # 执行行驶任务
+            # 指令参数
+            "param": {
+                # 导航数据
+                "navigation": [
+                    {
+                        'type': 'forward',  # 方向类型 forward 正向 backward 反向
+                        'nav_coordinates': [
+                            # 直行轨迹坐标参数
+                            {
+                                "start_point_x": 37.7749,
+                                "start_point_y": 37.7749,
+                                "end_point_x": 40,
+                                "end_point_y": -120
+                            },
+                            # 转弯轨迹坐标参数
+                            {
+                                "start_point_x": 40.7128,
+                                "start_point_y": -74.0060,
+                                "center_point_x": 10,
+                                "center_point_y": 20,
+                                "end_point_x": 50.7128,
+                                "end_point_y": -70.0060
+                            },
+                        ]
+                    },
+                    {
+                        'type': 'backward',
+                        'nav_coordinates': [
+                            # 直行轨迹坐标参数
+                            {
+                                "start_point_x": 37.7749,
+                                "start_point_y": -122.4194,
+                                "end_point_x": 40,
+                                "end_point_y": -120
+                            },
+                            # 转弯轨迹坐标参数
+                            {
+                                "start_point_x": 40.7128,
+                                "start_point_y": -74.0060,
+                                "center_point_x": 10,
+                                "center_point_y": 20,
+                                "end_point_x": 50.7128,
+                                "end_point_y": -70.0060
+                            },
+                        ]
+                    },
+                ],
+            },
+        }
+        """
+        data = {
+            'cmdid': 1001,
+            'param': {
+                'navigation': navigation,
+            }
+        }
+        url = f"http://{address}:{self.port}"
+        response = requests.post(self.url, json=data)
+        print('API.start_plan.url:', self.url)
+        print('API.start_plan.data:', data)
+        print('API.start_plan.code:', response.status_code)
+        print('API.start_plan.text:', response.text)
+
+    def cmd100101(self):
+        """
+        启动作业
+        """
+        data = {
+            # 指令类型
+            "cmdid": 100101,  # 启动作业
+            # 指令参数
+            "param": {
+                # 任务类型 102 叉包 103 放包 104 倒渣
+                "task_type": 102,
+                # 102
+                "task_coordinates": {
+                    "pot_name": "M.24",
+                    "pot_x": 40,
+                    "pot_y": 50,
+                    "mark_pot_pose": 0.3,
+                    "e_point_x": 50,
+                    "e_point_y": 60
+                },
+                # 103
+                # "task_coordinates": {
+                #     "pot_name": "M.24",
+                #     "pot_x": 40,
+                #     "pot_y": 50,
+                #     "goal_pot_pose": 0.3,
+                #     "e_point_x": 50,
+                #     "e_point_y": 60
+                # },
+                # 104
+                # "task_coordinates": {},
+            }
+        }
+
+    def cmd1002(self):
+        """
+        中止行驶任务
+        """
+        data = {
+            # 指令类型
+            "cmdid": 1002,  # 中止行驶任务
+            # 指令参数
+            "param": {}
+        }
+
+    def cmd1003(self):
+        data = {
+            # 指令类型
+            "cmdid": 1003,  # 远程打火
+            # 指令参数
+            "param": {}
+        }
+
+    def cmd1004(self):
+        data = {
+            # 指令类型
+            "cmdid": 1004,  # 远程熄火
+            # 指令参数
+            "param": {}
+        }
+
+    def cmd1005(self):
+        data = {
+            # 指令类型
+            "cmdid": 1005,  # 申请远程操作模式
+            # 指令参数
+            "param": {}
+        }
+
+    def cmd1006(self):
+        data = {
+            # 指令类型
+            "cmdid": 1006,  # 申请自动作业模式
+            # 指令参数
+            "param": {}
+        }
+
+    def test002(self, address):
+        """
+        """
+        data = {
+            # 指令类型
+            "cmdid": 1001,  # 执行行驶任务
+            # 指令参数
+            "param": {
+                # 导航数据
+                "navigation": [
+                    {
+                        'type': 'forward',
+                        'nav_coordinates': [
+                            {
+                                'start_point_x': 2.495,  # 当前位置
+                                'start_point_y': 173.1666142856,  # 当前位置
+                                'end_point_x': 182.6588877142857,
+                                'end_point_y': 169.8418064285714
+                            },
+                            {
+                                'start_point_x': 182.6588877142857,
+                                'start_point_y': 169.8418064285714,
+                                'center_point_x': 182.92185485714285,
+                                'center_point_y': 183.5769582142857,
+                                'end_point_x': 196.65700664285714,
+                                'end_point_y': 183.31399107142855
+                            },
+                            {
+                                'start_point_x': 196.65700664285714,
+                                'start_point_y': 183.31399107142855,
+                                'center_point_x': 182.92185485714285,
+                                'center_point_y': 183.5769582142857,
+                                'end_point_x': 183.184822,
+                                'end_point_y': 197.31211
+                            },
+                            {
+                                'start_point_x': 183.184822,
+                                'start_point_y': 197.31211,
+                                'end_point_x': 178.045984 - 50,
+                                'end_point_y': 197.219726
+                            }
+                        ]
+                    }
+                ]
+            },
+        }
+        url = f"http://{address}:{self.port}"
+        response = requests.post(url, json=data)
+        print('API.start_plan.url:', url)
+        print('API.start_plan.data:', data)
+        print('API.start_plan.code:', response.status_code)
+
+    def test004(self, address):
+        data = {
+            # 指令类型
+            "cmdid": 100101,  # 启动作业
+            # 指令参数
+            "param": {
+
+                "task_type": 103,  # 放包
+                "task_coordinates": {
+                    "pot_name": "N.20",
+                    "pot_x": 122.755687,
+                    "pot_y": 210.019149,
+                    "mark_pot_pose": -1.570920,
+                    "e_point_x": 0,
+                    "e_point_y": 0
+                },
+
+            }
+        }
+        url = f"http://{address}:{self.port}"
+        response = requests.post(url, json=data)
+        print('API.start_plan.url:', url)
+        print('API.start_plan.data:', data)
+        print('API.start_plan.code:', response.status_code)
+
+
+if __name__ == '__main__':
+    # --- init ---
+    api = API(port=8000)
+
+    # --- test ---
+    # out = api.test002(address='192.168.131.180')  # 行驶
+    out = api.test004(address='192.168.131.180')  # 作业
+    print(out)

+ 52 - 0
3rdparty/xapi/ros1/cmd1001.txt

@@ -0,0 +1,52 @@
+data = {
+    # 指令类型
+    "cmdid": 1001,  # 执行行驶任务
+    # 指令参数
+    "param": {
+        # 导航数据
+        "navigation": [
+            {
+                'type': 'forward',  # 方向类型 forward 正向 backward 反向
+                'nav_coordinates': [
+                    # 直行轨迹坐标参数
+                    {
+                        "start_point_x": 37.7749,
+                        "start_point_x": 37.7749,
+                        "end_point_x": 40,
+                        "end_point_y": -120
+                    },
+                    # 转弯轨迹坐标参数
+                    {
+                        "start_point_x": 40.7128,
+                        "start_point_y": -74.0060,
+                        "center_point_x": 10,
+                        "center_point_y": 20,
+                        "end_point_x": 50.7128,
+                        "end_point_y": -70.0060
+                    },
+                ]
+            },
+            {
+                'type': 'backward',
+                'nav_coordinates': [
+                    # 直行轨迹坐标参数
+                    {
+                        "start_point_x": 37.7749,
+                        "start_point_y": 37.7749,
+                        "end_point_x": 40,
+                        "end_point_y": -120
+                    },
+                    # 转弯轨迹坐标参数
+                    {
+                        "start_point_x": 40.7128,
+                        "start_point_y": -74.0060,
+                        "center_point_x": 10,
+                        "center_point_y": 20,
+                        "end_point_x": 50.7128,
+                        "end_point_y": -70.0060
+                    },
+                ]
+            },
+        ],
+    },
+}

+ 40 - 0
3rdparty/xapi/ros1/cmd100101.txt

@@ -0,0 +1,40 @@
+data = {
+    # 指令类型
+    "cmdid": 100101,  # 启动作业
+    # 指令参数
+    "param": {
+        # 任务类型 102 叉包 105 回e点 104 倒渣 103 放包 
+
+        # 102 叉包
+        # "task_type": 102,
+        # "task_coordinates": {
+        #     "pot_name": "N.12",
+        #     "pot_x": 78.381871,
+        #     "pot_y": 209.724510,
+        #     "mark_pot_pose": -1.559925,
+        #     "e_point_x": 50,
+        #     "e_point_y": 60
+        # },
+        # 105 回e点 (就是x轴的偏移量)
+        "task_type": 105,
+        "task_coordinates": {
+            "e_point_x": 78.381871 - 40,
+            "e_point_y": 199.66660199999998
+        },
+        # 104 倒渣
+        # "task_type": 104,
+        # "task_coordinates": {
+        #
+        # },
+        # 103 放包
+        # "task_type": 103,
+        # "task_coordinates": {
+        #     "pot_name": "N30",
+        #     "pot_x": 178.045984,
+        #     "pot_y": 209.219726,
+        #     "mark_pot_pose": -1.608619,
+        #     "e_point_x": 50,
+        #     "e_point_y": 60
+        # },
+    }
+}

+ 52 - 0
3rdparty/xapi/ros1/s1-行驶-去e点

@@ -0,0 +1,52 @@
+车开到n2位置,车头朝向倒渣口(事先需要联系师傅,将n20的包对上,我们需要记录一下包的位置信息)
+
+凯强 122.755687      210.019149     -1.570920
+
+n.20 122.8439634 198.54541533333332
+
+mqtt当前位置: 'position_x': 24.480705865127597, 'position_y': 202.35537350570837
+
+
+
+                "navigation": [
+                    {
+                        'type': 'forward',
+                        'nav_coordinates': [
+                            {
+                                'start_point_x': 24.4807,  # 当前n2位置
+                                'start_point_y': 202.35537350570837,  # 当前n2位置
+                                'end_point_x': 18.618844,
+                                'end_point_y': 200.67567
+                            },
+                            {
+                                'start_point_x': 18.618844,
+                                'start_point_y': 200.67567,
+                                'center_point_x': 18.306224428571426,
+                                'center_point_y': 186.9142662857143,
+                                'end_point_x': 17.993604857142852,
+                                'end_point_y': 173.15286257142859
+                            },
+                            {
+                                'start_point_x': 17.993604857142852,
+                                'start_point_y': 173.15286257142859,
+                                'end_point_x': 182.6588877142857,
+                                'end_point_y': 169.8418064285714
+                            },
+                            {
+                                'start_point_x': 182.6588877142857,
+                                'start_point_y': 169.8418064285714,
+                                'center_point_x': 182.92185485714285,
+                                'center_point_y': 183.5769582142857,
+                                'end_point_x': 183.184822,
+                                'end_point_y': 197.31211
+                            },
+                            {
+                                'start_point_x': 183.184822,
+                                'start_point_y': 197.31211,
+                                # e点位置
+                                'end_point_x': 122.8439634 - 50,  # e点需要往前开50
+                                'end_point_y': 198.54541533333332
+                            }
+                        ]
+                    }
+                ]

+ 12 - 0
3rdparty/xapi/ros1/s2-作业-叉包

@@ -0,0 +1,12 @@
+凯强 122.755687      210.019149     -1.570920
+
+
+                "task_type": 102,  # 叉包
+                "task_coordinates": {
+                    "pot_name": "N.20",
+                    "pot_x": 122.755687,
+                    "pot_y": 210.019149,
+                    "mark_pot_pose": -1.570920,
+                    "e_point_x": 0,
+                    "e_point_y": 0
+                },

+ 11 - 0
3rdparty/xapi/ros1/s3-作业-回e点

@@ -0,0 +1,11 @@
+                                'end_point_x': 122.8439634 - 50,  # e点需要往前开50
+                                'end_point_y': 198.54541533333332
+
+
+
+                "task_type": 105,  # 回e点
+                "task_coordinates": {
+                    "e_point_x": 122.8439634 - 50,
+                    "e_point_y": 198.54541533333332,
+                    "e_pose": 3.1415926,  # 固定值
+                },

+ 31 - 0
3rdparty/xapi/ros1/s4-行驶-e点-到-倒渣口2

@@ -0,0 +1,31 @@
+mqtt当前位置:'position_x': 109.30082456920857, 'position_y': 200.45750181311485
+
+
+                # 导航数据
+                "navigation": [
+                    {
+                        'type': 'forward',
+                        'nav_coordinates': [
+                            {
+                                'start_point_x': 109.30082456920857,  # mqtt中获取当前位置
+                                'start_point_y': 200.45750181311485,  # mqtt中获取当前位置
+                                'end_point_x': 18.618844,
+                                'end_point_y': 200.67567
+                            },
+                            {
+                                'start_point_x': 18.618844,
+                                'start_point_y': 200.67567,
+                                'center_point_x': 18.306224428571426,
+                                'center_point_y': 186.9142662857143,
+                                'end_point_x': 17.993604857142852,
+                                'end_point_y': 173.15286257142859
+                            },
+                            {
+                                'start_point_x': 17.993604857142852,
+                                'start_point_y': 173.15286257142859,
+                                'end_point_x': 47.9858831368238,
+                                'end_point_y': 172.47224256424514
+                            }
+                        ]
+                    }
+                ]

+ 18 - 0
3rdparty/xapi/ros1/s5-行驶-e点-到-倒渣口2

@@ -0,0 +1,18 @@
+mqtt当前位置:position_x': 50.189481964901745, 'position_y': 172.45461895435264
+
+
+                # 导航数据
+                "navigation": [
+
+                    {
+                        'type': 'backward',
+                        'nav_coordinates': [
+                            {
+                                'start_point_x': 49.46,  # 当前位置(铰链点)
+                                'start_point_y': 172.5,  # 当前位置(铰链点)
+                                'end_point_x': -2.487554142857145 - 0.8 - 0.5,  # 后车架
+                                'end_point_y': 173.02169257142856
+                            }
+                        ]
+                    }
+                ]

+ 43 - 0
3rdparty/xapi/ros1/s6-行驶-倒渣口2-到-n20的e点

@@ -0,0 +1,43 @@
+mqtt当前位置:position_x': 2.495681801706711, 'position_y': 173.16669248933502
+
+                                # e点位置
+                                'end_point_x': 122.8439634 - 50,  # e点需要往前开50
+                                'end_point_y': 198.54541533333332
+
+
+                # 导航数据
+                "navigation": [
+                    {
+                        'type': 'forward',
+                        'nav_coordinates': [
+                            {
+                                'start_point_x': 2.495,  # 当前位置
+                                'start_point_y': 173.1666142856,  # 当前位置
+                                'end_point_x': 182.6588877142857,
+                                'end_point_y': 169.8418064285714
+                            },
+                            {
+                                'start_point_x': 182.6588877142857,
+                                'start_point_y': 169.8418064285714,
+                                'center_point_x': 182.92185485714285,
+                                'center_point_y': 183.5769582142857,
+                                'end_point_x': 196.65700664285714,
+                                'end_point_y': 183.31399107142855
+                            },
+                            {
+                                'start_point_x': 196.65700664285714,
+                                'start_point_y': 183.31399107142855,
+                                'center_point_x': 182.92185485714285,
+                                'center_point_y': 183.5769582142857,
+                                'end_point_x': 183.184822,
+                                'end_point_y': 197.31211
+                            },
+                            {
+                                'start_point_x': 183.184822,
+                                'start_point_y': 197.31211,
+                                'end_point_x': 122.8439634 - 50,  # e点需要往前开50
+                                'end_point_y': 198.54541533333332
+                            }
+                        ]
+                    }
+                ]

+ 12 - 0
3rdparty/xapi/ros1/s7-作业-放包

@@ -0,0 +1,12 @@
+凯强 122.755687      210.019149     -1.570920
+
+
+                "task_type": 103,  # 放包
+                "task_coordinates": {
+                    "pot_name": "N.20",
+                    "pot_x": 122.755687,
+                    "pot_y": 210.019149,
+                    "mark_pot_pose": -1.570920,
+                    "e_point_x": 0,
+                    "e_point_y": 0
+                },

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 4 - 0
3rdparty/xapi/taiwuict/u1_for_aibox.py


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 4 - 0
3rdparty/xapi/taiwuict/u2_for_aibox.py


+ 833 - 0
3rdparty/xapi/taiwuict/u3_for_cscec.py

@@ -0,0 +1,833 @@
+# update: 2022-7-18
+"""
+中建八局一公司业务接口
+"""
+from urllib import parse
+import requests
+import time
+import traceback
+
+import sys
+import importlib
+
+sys.path.append('/home/server/projects/taiwuict/cscec-8bur-vms/supplement-python')
+# sys.path.append(r'D:\share\gitee\casper.supplement-python')  # for pc
+methods = importlib.import_module(f"libraries.base_original")
+
+
+class Api(object):
+
+    # def __init__(self, username='System001', password='Swdx@143',
+    def __init__(self, username='500A7062', password='198797#cjhxbin',
+                 project_id='d0f254cc-8196-499a-8f0d-52bf8ba91486',
+                 project_name='山东省公共卫生临床中心(济南市传染病医院二期)项目工程总承包(EPC)'):
+        """
+        第1现场:
+            济南市中心医院(东院区)项目工程总承包(EPC)
+            7eeb53a1-2bbd-4efa-8c8e-66936476226c
+
+        第2现场:
+            山东省大数据产业基地建设项目施工总承包
+            项目编号:500D10301958
+            ORGID:63729db2-ea9c-4096-b5d9-3ad0369903c8
+
+        第3现场:
+            山东省公共卫生临床中心(济南市传染病医院二期)项目工程总承包(EPC)
+            ORGID:d0f254cc-8196-499a-8f0d-52bf8ba91486
+
+        第4现场:
+            济南奥体东 13 及 17-2 号地块开发项目工程总 承包(EPC)
+            a8defc53-76b3-4f4e-931d-8dd35ba310c7
+
+        """
+
+        # --- define ---
+        self.service_url = 'http://app.cscec81.com/api'  # 正式环境
+        # self.service_url = f"http://pmdev.cscec81.com/api"  # 正式环境
+        # self.service_url = 'http://221.214.64.195:31229/api'  # 公网测试地址
+        # self.service_url = 'http://10.198.6.181:31229/api'  # vpn测试环境 https://221.214.64.195 gelubo01 Gelubo@2022
+
+        # --- release ---
+        self.project_id = project_id
+        self.project_name = project_name
+
+        # --- release ---
+        self.token = None
+        if username and password:
+            session_id, user_code, user_id = self.get_user_info(username, password)
+            self.token = f"Bearer {self.get_token(session_id, user_code, user_id)}"
+
+        # --- test ---
+        # self.token_test = 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2NjAxMTgyODIsInVzZXJfbmFtZSI6Iui1tei_nuWxsTM0NTBhMjI0NmZiLTkwMWYtNGIwNi1hMjU2LTY4YTI4Y2VkZTU2Y2UwZDk5OTk3LTkzNzEtNGMwZi04NDNjLTUyNTMzYjE4ZTYxNSIsImp0aSI6Ijg3MzcxZTY0LTgwNzEtNGJlYy04YWMzLTUxMzViMTU5MzhjMyIsImNsaWVudF9pZCI6ImJyb3dzZXIiLCJzY29wZSI6WyJjbGllbnQiXX0.NF0IXabm_7RRqcdra6A7fsBvyBWa_62rkppQAFxalc4'
+
+    @staticmethod
+    def get_user_info(username, password):
+        """
+        获取用户信息
+        url: http://pmdev.cscec81.com/Login/Login.ashx?t=' + new Date().getTime() + '&method=CheckLogin
+        """
+        # url = f"{self.service_url}/Login/Login.ashx"
+        url = f"http://app.cscec81.com/Login/Login.ashx"  # 正式环境
+        # url = f"http://pm.cscec81.com/Login/Login.ashx"  # 测试环境
+        # url = f"http://221.214.64.195:31229/Login/Login.ashx"  # 测试环境
+        url += f"?t={int(time.time() * 1000)}&method=CheckLogin"
+        data = {
+            'Username': username,
+            'password': password,
+            'usertype': '0',
+            'sys': 'sitemanage',
+            'clientType': '5',
+        }
+        payload = parse.urlencode(data, encoding='utf-8')
+        headers = {
+            'Content-Type': 'application/x-www-form-urlencoded',
+            'Cookie': 'ASP.NET_SessionId=luy3wg10b2kymc2nbiytn4xt'
+        }
+        print('Api.get_user_info.url:', url)
+        # print('Api.get_user_info.headers:', headers)
+        # print('Api.get_user_info.payload:', payload)
+        response = requests.request('POST', url, headers=headers, data=payload)
+
+        if response.status_code > 300:
+            print('Api.get_user_info.result:', response.status_code)
+            print('Api.get_user_info.detail:', response.text)
+            return '', '', ''
+        print('Api.get_user_info.result:', response.status_code)
+        json_data = response.json()
+        # print('Api.get_user_info.json_data:', json_data)
+        if not json_data or not json_data.get('data'):
+            return '', '', ''
+        session_id = json_data.get('data').get('ticketID')
+        user_code = json_data.get('data').get('userCode')
+        user_id = json_data.get('data').get('userID')
+        # print('Api.get_user_info.session_id:', session_id)
+        # print('Api.get_user_info.user_code:', user_code)
+        # print('Api.get_user_info.user_id:', user_id)
+        return session_id, user_code, user_id
+
+    @staticmethod
+    def get_token(session_id, user_code, user_id):
+        """
+        获取令牌
+        url: http://pmdev.cscec81.com/api/oauth/token?grant_type=session&sessionId="
+            + ticketID + "&userCode=" + userCode + "&userId=" + userID + "&client_type=web&system=1
+        """
+        # url = f"{self.service_url}/oauth/token"
+        url = f"http://app.cscec81.com/api/oauth/token"  # 正式环境
+        # url = f"http://pm.cscec81.com/api/oauth/token"  # 测试环境
+        url += f"?grant_type=session&sessionId={session_id}&userCode={user_code}&userId={user_id}"
+        url += f"&client_type=web&system=1"
+
+        headers = {
+            'Authorization': 'Basic YnJvd3Nlcjo='
+        }
+        print('Api.get_token.url:', url)
+        # print('Api.get_token.headers:', headers)
+        response = requests.post(url=url, headers=headers)
+
+        if response.status_code > 300:
+            print('Api.get_token.result:', response.status_code)
+            print('Api.get_token.detail:', response.text)
+            return ''
+        else:
+            print('Api.get_token.result:', response.status_code)
+            # return response.headers.get('authorization')
+            return response.json().get('access_token')
+
+    def get_cscec8_user_list(self):
+        """
+        获取八局管理人员
+        /api/economic/indoor/getProjectUserList?projectId=05037f9b-5cb6-4a43-9410-c0e6a83f280e
+        return [
+            {
+                cardId: 身份证号
+                imgUrl: 人脸图片
+                dutyId: 职务id
+                dutyName: 职务名称
+            }
+        ]
+        """
+        url = f"http://app.cscec81.com/api/economic/indoor/getProjectUserFaceList?projectId={self.project_id}"
+
+        print('Api.get_cscec8_user_list.url:', url)
+        response = requests.get(url, headers={'content-type': 'application/json'})
+
+        if response.status_code > 300:
+            print('Api.get_cscec8_user_list.result:', response.status_code)
+            print('Api.get_cscec8_user_list.detail:', response.text)
+            return []
+
+        json_data = response.json()
+        # print(json_data)
+        return json_data
+
+    def get_worker_list(self):
+        """
+        获取工人列表(云筑网工人信息)
+        url: http://app.cscec81.com/api/safeeducation/workerInfo/workers?projectName=济南市中心医院(东院区)项目工程总承包(EPC)
+        url: http://221.214.64.195:31229/api/safeeducation/workerInfo/workers?projectName=丽泽SOHO项目
+        return [
+            {
+                headImagePath: 人脸图像地址
+                subContractorName: 劳务公司
+                workTypeName: 工种
+
+            }
+        ]
+        """
+        url = f"http://app.cscec81.com/api/safeeducation/workerInfo/workers?projectName={self.project_name}"
+        url += f"&page=0&size=5000"
+
+        print('Api.get_worker_list.url:', url)
+        response = requests.get(url, headers={'content-type': 'application/json'})
+        print('Api.get_worker_list.result:', response.status_code)
+
+        if response.status_code > 300:
+            print('Api.get_worker_list.result:', response.status_code)
+            print('Api.get_worker_list.detail:', response.text)
+            return []
+
+        json_data = response.json()
+        # {'projectName': '济南市中心医院(东院区)项目工程总承包(EPC)', 'workerName': '高玉锋',
+        # 'idCardNumber': '372527198311022813', 'workTypeName': '电气设备安装工', 'headImagePath': None}
+        if not json_data or not json_data.get('success') or not json_data.get('data'):
+            return []
+        if not json_data.get('data').get('content'):
+            return []
+        # print(json_data.get('data').keys())
+        # print(json_data.get('data').get('totalElements'))
+        # print(len(json_data.get('data').get('content')))
+        # print(json_data.get('data').get('content')[0])
+        return json_data.get('data').get('content')
+
+    @staticmethod
+    def get_face_image_by_path(image_path):
+        """
+        获取工人照片
+        url: https://lwres.yzw.cn/worker-avatar/Original/2018/0612/f3230a72-57ab-4aaf-a741-61d8c078fe89.jpg
+        """
+        while True:
+            try:
+
+                url = f"https://lwres.yzw.cn/{image_path}"
+                # print('Api.get_face_image_by_path.url:', url)
+                response = requests.get(url, headers={'content-type': 'application/json'})
+                # print('Api.get_face_image_by_path.result:', response.status_code)
+
+                if response.status_code > 300:
+                    print('Api.get_face_image_by_path.result:', response.status_code)
+                    print('Api.get_face_image_by_path.detail:', response.text)
+                    return b''
+                else:
+                    return response.content
+
+            except Exception as exception:
+
+                if exception.__class__.__name__ == 'ConnectionError':
+                    print(f"Api.get_face_image_by_path: sleep 60s")
+                    time.sleep(60)
+                else:
+                    print(f"Api.get_face_image_by_path.exception:{exception.__class__.__name__}")
+                    print(f"Api.get_face_image_by_path.traceback:{traceback.format_exc()}")
+                    return b''
+
+    @staticmethod
+    def get_face_image_by_path_v2(image_path):
+        """
+        获取工人高清头像
+        url: http://app.cscec81.com/media/202110/25/20211025-161726-381-4862.jpg
+        """
+        while True:
+            try:
+
+                url = f"http://app.cscec81.com/media/{image_path}"
+                # print('Api.get_face_image_by_path_v2.url:', url)
+                response = requests.get(url, headers={'content-type': 'application/json'})
+                # print('Api.get_face_image_by_path_v2.result:', response.status_code)
+
+                if response.status_code > 300:
+                    print('Api.get_face_image_by_path_v2.result:', response.status_code)
+                    print('Api.get_face_image_by_path_v2.detail:', response.text)
+                    return b''
+                else:
+                    return response.content
+
+            except Exception as exception:
+
+                if exception.__class__.__name__ == 'ConnectionError':
+                    print(f"Api.get_face_image_by_path_v2: sleep 60s")
+                    time.sleep(60)
+                else:
+                    print(f"Api.get_face_image_by_path_v2.exception:{exception.__class__.__name__}")
+                    print(f"Api.get_face_image_by_path_v2.traceback:{traceback.format_exc()}")
+                    return b''
+
+    @staticmethod
+    def get_face_image_by_url(image_url):
+        """
+        获取八局管理人员人脸图像
+        url: https://hcm.cscec81.com/img?type=photo&size=120&index=ae2f8424-c63f-11ea-b0a9-ea6f5cf6388d&rnd=1653618903725
+        """
+        while True:
+            try:
+
+                # print('Api.get_face_image_by_url.url:', url)
+                response = requests.get(image_url, headers={'content-type': 'application/json'})
+                # print('Api.get_face_image_by_url.result:', response.status_code)
+
+                if response.status_code > 300:
+                    print('Api.get_face_image_by_url.result:', response.status_code)
+                    print('Api.get_face_image_by_url.detail:', response.text)
+                    return b''
+                else:
+                    return response.content
+
+            except Exception as exception:
+
+                if exception.__class__.__name__ == 'ConnectionError':
+                    print(f"Api.get_face_image_by_url: sleep 60s")
+                    time.sleep(60)
+                else:
+                    print(f"Api.get_face_image_by_url.exception:{exception.__class__.__name__}")
+                    print(f"Api.get_face_image_by_url.traceback:{traceback.format_exc()}")
+                    return b''
+
+    def upload_file(self, face_uuid, file_path):
+        """
+        上传文件图片
+        """
+        # service_url = 'http://221.214.64.195:31229/api'
+        # url = f"{service_url}/storages/files/anonymousUpload"
+        url = f"{self.service_url}/storages/files/anonymousUpload"
+        files = {
+            'id': (None, face_uuid),
+            'file': ('1.jpg', open(file_path, 'rb'), 'image/jpg'),
+        }
+        headers = {
+            'Authorization': self.token,
+        }
+        print('Api.upload_file.url:', url)
+        response = requests.post(url=url, files=files, headers=headers)
+
+        if response.status_code > 300:
+            print('Api.upload_file.result:', response.status_code)
+            # print('Api.upload_file.detail:', response.text)
+            return ''
+        else:
+            print('Api.upload_file.result:', response.status_code)
+            """
+            原地址
+            http://10.198.6.181:31900/cscec81-cloud/202110/12/20211012-161022-713-7035.jpg
+            http://10.198.6.173:30900/cscec81-cloud/202206/13/20220613-022118-96-3795.jpg
+            替换后地址
+            http://221.214.64.195:31229/media/202110/12/20211012-161022-713-7035.jpg
+            http://app.cscec81.com/media/202110/12/20211012-161022-713-7035.jpg
+            """
+            link = response.json().get('link')
+            # link = link.replace('http://10.198.6.181:31900/cscec81-cloud', 'http://221.214.64.195:31229/media')  # 测试
+            # link = link.replace('http://10.198.6.173:30900/cscec81-cloud', 'http://app.cscec81.com/media')  # 正式
+            # link = f"http://221.214.64.195:31229/media{link.split('cscec81-cloud')[1]}"  # 测试环境
+            link = f"http://app.cscec81.com/media{link.split('cscec81-cloud')[1]}"  # 正式环境
+            return link
+
+    def get_user_list(self):
+        """
+        获取在职人员列表
+        """
+        url = f"{self.service_url}/system/users/getUserList"
+        data = {
+            'companyId': self.project_id,  # 单位id
+            'userName': '',  # 人员名称
+            'isMainPosition': '',  # 1 主职 0 主职+兼职
+            'postId': '',  # 职务
+            'postName': '',
+        }
+        headers = {
+            'Authorization': self.token
+        }
+        # print('Api.get_user_list.url:', url)
+        response = requests.get(url, params=data, headers=headers)
+        # print('Api.get_user_list.result:', response.status_code)
+
+        if response.status_code > 300:
+            print('Api.get_user_list.result:', response.status_code)
+            print('Api.get_user_list.detail:', response.text)
+            return []
+        json_data = response.json()
+        if not json_data.get('content'):
+            return []
+        print(json_data.get('content')[0])
+        return json_data.get('content')
+
+    def push_face(self, send_at, face_file_link, face_name, cscec8_duty_name, cscec8_id, age, group, source):
+        """
+        上传新增人脸(上传八局管理人员接口)
+        """
+        # test_service_url = 'http://10.198.6.181:31229/api'
+        # url = f"{test_service_url}/worker/userInfo"
+        url = f"{self.service_url}/worker/userInfo"
+        data = [{
+            'groupId': group,  # 分组ID 001 陌生人 002 劳务工人 003 临时用工 004 项目管理人员 005 VIP 006 黑名单 007 其他
+            'equipmentId': self.project_id,  # 设备id
+            'userId': cscec8_id,  # 用户唯一标识 人脸id
+            'userName': face_name,  # 用户名 人脸名称
+            'age': age,  # 年龄
+            'postInfoName': cscec8_duty_name,  # 职务
+            'lastEnterTime': send_at,  # 最后进入时间 '2021-08-10 08:00:00'
+            'faceInfo': face_file_link,  # 文件链接地址
+            'sourceType': source,  # 是否是八局人脸库信息 0 不是 1 是
+        }]
+        # print('Api.push_face:data:', data)
+        # methods.debug_log('Api.push_face', f"m-418 | data: {data}")
+        headers = {
+            'Authorization': self.token,
+            # 'Authorization': self.token_test,
+        }
+        # print('Api.push_face.url:', url)
+        response = requests.post(url, json=data, headers=headers)
+
+        if response.status_code > 300:
+            print('Api.push_face.result:', response.status_code)
+            print('Api.push_face.detail:', response.text)
+            methods.debug_log('apis.u3_for_cscec', f"m-395: url -> {url}")
+            methods.debug_log('apis.u3_for_cscec', f"m-395: data -> {data}")
+            methods.debug_log('apis.u3_for_cscec', f"m-395: result -> {response.status_code}")
+            methods.debug_log('apis.u3_for_cscec', f"m-395: detail -> {response.text}")
+            return False
+        else:
+            # print('Api.push_face.result:', response.status_code)
+            # print('Api.push_face:json:', response.json())
+            return True
+
+    def push_work_info(self, send_at, face_file_link, face_name, prc_id, worker_contractor, worker_type_name, age,
+                       find_at):
+        """
+        添加劳务人员接口(上传农民工接口)
+        """
+        # test_service_url = 'http://425ax87563.zicp.vip'
+        # url = f"{test_service_url}/worker/userInfo/workerInfo"
+        url = f"{self.service_url}/worker/userInfo/workerInfo"
+        data = [{
+            'equipmentId': self.project_id,  # 设备id
+            'userId': prc_id,  # 用户唯一标识 农民工身份证id
+            'userName': face_name,  # 用户名 工人名称
+            'userCerd': prc_id,  # 用户身份证号
+            'age': age,  # 年龄
+            'postInfoName': '',  # 职务
+            'workType': worker_type_name,  # 工种(农民工)
+            'labourCompany': worker_contractor,  # 劳务公司(农民工)
+            'enterState': '',  # 进场状态
+            'enterTime': '',  # 进场时间
+            'synTime': find_at,  # 同步时间(同步云筑网时间)
+            'lastEnterTime': send_at,  # 最后进入时间 '2021-08-10 08:00:00'
+            'faceInfo': face_file_link,  # 文件链接地址 人脸信息(图片传八局服务器系统,入参只传服务器文件地址)
+            'labourSource': str(0),  # 是否八局底库人员 0 不是 1 是
+        }]
+        # data = [
+        #     {'equipmentId': '63729db2-ea9c-4096-b5d9-3ad0369903c8', 'userId': '511025199009011013', 'userName': '赵润',
+        #      'userCerd': '511025199009011013', 'age': '', 'postInfoName': '', 'workType': None, 'labourCompany': None,
+        #      'enterState': '', 'enterTime': '', 'synTime': '', 'lastEnterTime': '2022-05-27 10:10:56',
+        #      'faceInfo': 'http://221.214.64.195:31229/media/202205/27/20220527-150651-60-5508.jpg',
+        #      'labourSource': '0'}]
+        # print('Api.push_work_info:data:', data)
+        # methods.debug_log('Api.push_work_info', f"m-464 | data: {data}")
+        headers = {
+            'Authorization': self.token,
+            # 'Authorization': self.token_test,
+        }
+        # print('Api.push_work_info.url:', url)
+        response = requests.post(url, json=data, headers=headers)
+
+        if response.status_code > 300:
+            # print('Api.push_work_info.result:', response.status_code)
+            # print('Api.push_work_info.detail:', response.text)
+            methods.debug_log('apis.u3_for_cscec', f"m-457: url -> {url}")
+            methods.debug_log('apis.u3_for_cscec', f"m-457: data -> {data}")
+            methods.debug_log('apis.u3_for_cscec', f"m-457: result -> {response.status_code}")
+            methods.debug_log('apis.u3_for_cscec', f"m-457: detail -> {response.text}")
+            return False
+        else:
+            # print('Api.push_work_info:json:', response.json())
+            return True
+
+    def pull_update_info(self, start_at):
+        """
+        获取线上更新数据 todo 定时请求更新本地数据相关的数据
+        """
+        # test_service_url = 'http://425ax87563.zicp.vip'
+        # url = f"{test_service_url}/worker/userInfo/findUpdateUserByTime"
+        url = f"{self.service_url}/worker/userInfo/findUpdateUserByTime"
+        # url = f"http://425ax87563.zicp.vip/worker/userInfo/findUpdateUserByTime?queryStartTime=2022-05-27 11:09:00"
+        # url += '?queryStartTime=2022-05-27 11:09:00'
+        url += f"?queryStartTime={start_at}"
+        data = {
+            # 'companyId': self.project_id,  # 单位id
+            # 'queryStartTime': '2021-10-21 11:09:00',
+            # 'queryStartTime': '2022-05-27 11:09:00',
+        }
+        headers = {
+            'Authorization': self.token,
+            # 'Authorization': self.token_test,
+        }
+        print('Api.pull_update_info.url:', url)
+        response = requests.get(url, params=data, headers=headers)
+        print('Api.pull_update_info.result:', response.status_code)
+        print('Api.pull_update_info:text:', response.json())
+        return []
+        # if response.status_code > 300:
+        #     print('Api.pull_update_info:text:', response.text)
+        #     return []
+        # json_data = response.json()
+        # if not json_data.get('content'):
+        #     return []
+        # print(json_data.get('content')[0])
+        # return json_data.get('content')
+
+    def pull_alarm_list(self, create_at):
+        """
+        获取告警列表
+        """
+        # test_service_url = 'http://425ax87563.zicp.vip'
+        # url = f"{test_service_url}/worker/alarm/alarmPageList"
+        # url += f"?createTime={create_at}"
+        url = f"{self.service_url}/worker/alarm/alarmPageList"
+        url += f"?createTime={create_at}"
+        params = {
+            # 'createTime': '2021-08-10 08:00:00'
+        }
+        headers = {
+            'Authorization': self.token,
+            # 'Authorization': self.token_test,
+        }
+        print('Api.pull_alarm_list.url:', url)
+        response = requests.get(url, params=params, headers=headers)
+
+        if response.status_code > 300:
+            print('Api.pull_alarm_list.result:', response.status_code)
+            print('Api.pull_alarm_list.detail:', response.text)
+            return {}
+        else:
+            print('Api.pull_alarm_list.result:', response.status_code)
+            return response.json()
+
+    def pull_alarm_group_list(self, create_at):
+        """
+        获取报警分组列表
+        return [
+            {
+                ALARM_GROUP_STRATEGY_IDS: 1 现场屏显报警 2 现场语音报警 3 微信报警
+            }
+        ]
+        """
+        # test_service_url = 'http://425ax87563.zicp.vip'
+        # url = f"{test_service_url}/worker/alarm/alarmGroupList"
+        url = f"{self.service_url}/worker/alarm/alarmGroupList"
+        params = {
+            'projectId': self.project_id,
+            'createTime': create_at,
+        }
+        headers = {
+            'Authorization': self.token,
+            # 'Authorization': self.token_test,
+        }
+        print('Api.pull_alarm_group_list.url:', url)
+        response = requests.get(url, params=params, headers=headers)
+
+        if response.status_code > 300:
+            print('Api.pull_alarm_group_list.result:', response.status_code)
+            print('Api.pull_alarm_group_list.detail:', response.text)
+            return []
+        else:
+            print('Api.pull_alarm_group_list.result:', response.status_code)
+            return response.json()
+
+    def push_message(self):
+        """
+        推送微信消息
+        {'ALARM_TYPE': 1, 'ALARM_USER_ID': 'f6bae517-0a28-429c-b65b-b16548ab2ca4', 'ALARM_GROUP_NAME': '屏显报警',
+        'id': '17ee224382634361bc5b9ef41ce09eb1', 'ALARM_STRATEGY_GROUP_ID': '5e58ed8828c84c779b3cddb0257d6f5f',
+        'ALARM_PROJECT_ID': '63729db2-ea9c-4096-b5d9-3ad0369903c8', 'ALARM_NAME': '刘美琪'}
+        {'ALARM_TYPE': 1, 'ALARM_USER_ID': '7a574580-6af1-40af-a3c8-1c0d5aee567b', 'ALARM_GROUP_NAME': '微信报警',
+        'id': '04bb6b4628954b2282b15a3cb2e74ab8', 'ALARM_STRATEGY_GROUP_ID': '0f695744b43447b2b4cbad8dc78389f4',
+        'ALARM_PROJECT_ID': '63729db2-ea9c-4096-b5d9-3ad0369903c8', 'ALARM_NAME': '吴非'}
+
+        微信推送结果查询接口 worker/alarm/getWxPushState
+        状态 00 未发送 01 发送成功 02 发送失败 03 发送异常
+        """
+        # test_service_url = 'http://425ax87563.zicp.vip'
+        # url = f"{test_service_url}/worker/alarm/getWxAlarmUser"
+        url = f"{self.service_url}/worker/alarm/getWxAlarmUser"
+        data = {
+            'projectId': self.project_id,  # 项目id
+            # 'groupId': '5e58ed8828c84c779b3cddb0257d6f5f',  # 告警组id ALARM_STRATEGY_GROUP_ID
+            'groupId': '0f695744b43447b2b4cbad8dc78389f4',  # 告警组id ALARM_STRATEGY_GROUP_ID
+            # 'userId': 'f6bae517-0a28-429c-b65b-b16548ab2ca4',  # 告警用户id ALARM_USER_ID
+            'userId': '7a574580-6af1-40af-a3c8-1c0d5aee567b',  # 告警用户id ALARM_USER_ID
+        }
+        print(f"Api.push_message:data: {data}")
+        headers = {
+            'Authorization': self.token,
+            # 'Authorization': self.token_test,
+        }
+        print('Api.push_message.url:', url)
+        response = requests.post(url, json=data, headers=headers)
+
+        if response.status_code > 300:
+            print('Api.push_message.result:', response.status_code)
+            print('Api.push_message.detail:', response.text)
+            return {}
+        else:
+            print('Api.push_message.result:', response.status_code)
+            return response.json()
+
+    def check_message_state(self):
+        """
+        微信推送结果查询接口 worker/alarm/getWxPushState
+        状态 00 未发送 01 发送成功 02 发送失败 03 发送异常
+        """
+        # test_service_url = 'http://425ax87563.zicp.vip'
+        # url = f"{test_service_url}/worker/alarm/getWxPushState"
+        url = f"{self.service_url}/worker/alarm/getWxPushState"
+        # url += f"?wxPushId=24290bde-09d7-444b-b2ea-039213f8b628"
+        url += f"?wxPushId=77c36ad2-ad35-464b-bf52-6d16fd9c74e0"
+        data = {
+            # 'wxPushId': mid,
+            # 'wxPushId': '24290bde-09d7-444b-b2ea-039213f8b628',
+        }
+        headers = {
+            'Authorization': self.token,
+            # 'Authorization': self.token_test,
+        }
+        print('Api.check_message_state.url:', url)
+        # response = requests.get(url, json=data, headers=headers)
+        response = requests.get(url, headers=headers)
+
+        if response.status_code > 300:
+            print('Api.check_message_state.result:', response.status_code)
+            print('Api.check_message_state.detail:', response.text)
+            return {}
+        else:
+            print('Api.check_message_state.result:', response.status_code)
+            # return response.json()
+            return response.text
+
+    def push_state(self):
+        """
+        每分钟发送心跳请求接口
+        """
+        # test_service_url = 'http://425ax87563.zicp.vip'
+        # url = f"{test_service_url}/worker/equipmentMaintain/updateEquStateTime"
+        url = f"{self.service_url}/worker/equipmentMaintain/updateEquStateTime"
+        data = {
+            'projectId': self.project_id,
+        }
+        headers = {
+            'Authorization': self.token,
+            # 'Authorization': self.token_test,
+        }
+        # print('Api.push_state.url:', url)
+        response = requests.post(url, json=data, headers=headers)
+
+        if response.status_code > 300:
+            print('Api.push_state.result:', response.status_code)
+            print('Api.push_state.detail:', response.text)
+            return {}
+        else:
+            # print('Api.push_state.result:', response.status_code)
+            return response.json()
+
+    def push_face_log(self, user_id, find_at, face_link=''):
+        """
+        上传识别记录
+        methods.ts_to_string(item.get('create_at'), '%Y-%m-%d %H:%M:%S')
+        """
+        # test_service_url = 'http://10.198.6.181:31229/api'
+        # url = f"{test_service_url}/worker/ledger/addLedger"
+        url = f"{self.service_url}/worker/ledger/addLedger"
+        data = [{
+            'projectId': self.project_id,  # 项目id
+            'equipmentInfo': self.project_id,  # 设备id
+            'equipmentRecognitionTime': find_at,  # 识别时间 '2021-10-21 11:09:00'
+            'userId': user_id,  # 人脸标识 八局人员使用uuid 劳务人员使用身份证号
+            'faceInfo': face_link,  # 文件链接地址 人脸信息(图片传八局服务器系统,入参只传服务器文件地址)
+        }]
+        headers = {
+            'Authorization': self.token,
+            # 'Authorization': self.token_test,
+        }
+        # methods.debug_log('apis.u3_for_cscec', f"m-651: project_id -> {self.project_id}")
+        print('Api.push_face_log.url:', url)
+        # print('Api.push_face_log:data:', data)
+        response = requests.post(url, json=data, headers=headers)
+
+        if response.status_code > 300:
+            # print('Api.push_face_log.result:', response.status_code)
+            # print('Api.push_face_log.detail:', response.text)
+            methods.debug_log('apis.u3_for_cscec', f"m-678: url -> {url}")
+            methods.debug_log('apis.u3_for_cscec', f"m-678: data -> {data}")
+            methods.debug_log('apis.u3_for_cscec', f"m-678: result -> {response.status_code}")
+            methods.debug_log('apis.u3_for_cscec', f"m-678: detail -> {response.text}")
+            return False
+        else:
+            print('Api.push_face_log.result:', response.status_code)
+            print('Api.push_face_log.detail:', response.text)
+            # methods.debug_log('apis.u3_for_cscec', f"m-668: result -> {response.status_code}")
+            # methods.debug_log('apis.u3_for_cscec', f"m-668: detail -> {response.text}")
+            # methods.debug_log('apis.u3_for_cscec', f"m-668: detail -> {response.json()}")
+            return True
+
+
+if __name__ == '__main__':
+    # --- init ---
+    # api = Api(username='500A4475', password='cscec81#')
+    # api = Api(username='500A7062', password='198797#cjhxbin')  # 侯经理 正式环境
+    api = Api(project_id='63729db2-ea9c-4096-b5d9-3ad0369903c8',
+              project_name='山东省大数据产业基地建设项目施工总承包')  # 正式环境账号
+    # api = Api(project_id='a8defc53-76b3-4f4e-931d-8dd35ba310c7',
+    #           project_name='济南奥体东 13 及 17-2 号地块开发项目工程总 承包(EPC)')  # 正式环境账号
+    # api = Api()  # 正式环境账号
+
+    # --- test ---
+    # out = api.upload_file('aabbccdd-aabbccss-ssggaaff-sseeqqhh', r"D:\3.jpg")
+    # print(out)
+
+    # --- test ---
+    # api.push_state()
+    # api.push_face(
+    #     send_at='2022-07-18 08:09:00',
+    #     face_file_link='http://app.cscec81.com/media/202207/18/20220718-105339-394-2140.jpg',
+    #     face_name='张三001',
+    #     cscec8_duty_name='司机',
+    #     cscec8_id='aabbccdd-aabbccss-ssggaaff-sseeqqhh',
+    #     age=60,
+    #     group='004',
+    #     source=1)
+    # api.push_face_log('aabbccdd-aabbccss-ssggaaff-sseeqqhh', '2022-06-02 08:09:01',
+    #                   'http://app.cscec81.com/media/202207/18/20220718-111202-730-7523.jpg')
+
+    # --- test ---
+    # _dict = {}
+    # items = api.get_worker_list()
+    # print(items[0])
+    # print(len(items))
+    # for item in items:
+    #     _dict[item.get('idCardNumber')] = 1
+    # print(len(_dict.keys()))
+
+    # --- check 八局人员 ---
+    # items = api.get_cscec8_user_list()
+    # for item in items:
+    #     if item.get('userName') in ['孙会沅']:
+    #         print(item)
+
+    # --- check avatarAddress ---
+    # out = api.get_worker_list()
+    # for one in out:
+    #     if one.get('workerName') in ['鲁成', '韩继涛', '丁保树', '金义莲']:
+    #         print(one)
+    #     # if one.get('subContractorName'):
+    #     #     print(one.get('avatarAddress'))
+    #     #     print(one.get('flag'), type(one.get('flag')))
+    #     #     image = api.get_face_image_by_path_v2(one.get('avatarAddress'))
+    #     #     print(type(image), len(image))
+
+    # --- test ---
+    # uuid = '62a166f324bfcf82f7066b65'
+    # face_image_path = '/home/server/resources/vms-files/2022-0609-112017-618668-raw.jpg'
+    # face_image_path = '/home/server/resources/vms-files/2022-0601-172536-193936.jpg'
+    # out = api.upload_file(uuid, face_image_path)
+    # print(out)
+
+    # --- test ---
+    # o = api.pull_alarm_list('2021-06-01 08:00:00')
+    # print(o)
+    # o = api.pull_alarm_group_list('2021-06-01 08:00:00')
+    # print(o)
+    # o = api.push_message()
+    # print(o)
+    # o = api.check_message_state()
+    # print(o)
+
+    # --- test ---
+    # o = api.pull_update_info('2022-05-27 11:09:00')
+    # o = api.pull_alarm_list('2022-05-27 11:09:00')
+    # o = api.pull_alarm_group_list()
+    # print(o)
+
+    # --- test ---
+    # o = api.push_work_info(1, 2, 3, 4, 1, 1)
+    # print(o)
+
+    # --- test ---
+    # u = 'https://hcm.cscec81.com/img?type=photo&size=120&index=ae2f8424-c63f-11ea-b0a9-ea6f5cf6388d&rnd=1653618903725'
+    # u = 'https://hcm.cscec81.com/img?type=photo&size=120&index=6605f16a-095a-11ec-99ad-da7e2f6980d1&rnd=1653620550071'
+    # o = api.get_face_image_by_url(u)
+    # print(o)
+
+    # --- test ---
+    # out = api.get_cscec8_user_list()
+    # print(len(out))
+    # for i in out:
+    #     if i.get('userName') == '杜兴昌':
+    #         print(i)
+
+    # --- test ---
+    # out = api.push_face('6166f0ab95a68293064d97c4', '2021-04-14 14:43:55',
+    #                     'http://221.214.64.195:31229/media/202110/21/20211021-120733-570-3862.jpg', 1, '张001')
+    # out = api.push_work_info('6166f0ab95a68293064d97c4', '2021-10-13 14:43:55',
+    #                          'http://221.214.64.195:31229/media/202110/21/20211021-120733-570-3862.jpg')
+    # print(out)
+
+    # --- test ---
+    # out = api.pull_alarm_group_list()
+    # print(out)
+
+    # --- test ---
+    # alarm_group_id = '1dfcd494affd4ee9aeb533c2d12558e7'
+    # out = api.push_message(alarm_group_id)
+
+    # --- test ---
+    # out = api.pull_alarm_group_list()
+    # out = api.get_user_list()
+    # print(out)
+
+    # --- test ---
+    # out = api.get_user_list()
+    # print(out)
+
+    # --- test ---
+    # def write_bytes(path, data=b''):
+    #     with open(path, 'wb') as f:
+    #         f.write(data)
+    # outputs = api.get_worker_list_by_project_name('济南市中心医院(东院区)项目工程总承包(EPC)')
+    # count = 0
+    # for i in outputs:
+    #     if not i.get('headImagePath'):
+    #         continue
+    #     url = f"https://lwres.yzw.cn/{i.get('headImagePath')}"
+    #     r = requests.get(url, headers={'content-type': 'application/json'})
+    #     count += 1
+    #     name = str(count).zfill(6)
+    #     write_bytes(f"D:\\test\\111\\{name}.jpg", r.content)
+
+    # --- test ---
+    # def write_bytes(path, data=b''):
+    #     with open(path, 'wb') as f:
+    #         f.write(data)
+    # _url = f"https://lwres.yzw.cn/worker-avatar/Original/2021/0303/0f735c37-118f-4cd8-a0a5-753e0e2fc7d7.jpg"
+    # r = requests.get(_url, headers={'content-type': 'application/json'})
+    # write_bytes(f"D:\\test\\111\\{1}.jpg", r.content)
+
+    # --- test ---
+    # d1 = {}
+    # outputs = api.get_worker_list_by_project_name('济南市中心医院(东院区)项目工程总承包(EPC)')
+    # for i in outputs:
+    #     if i.get('workTypeName') not in d1:
+    #         d1[i.get('workTypeName')] = 0
+    #     d1[i.get('workTypeName')] += 1
+    # print(d1)
+
+    # --- test ---
+    # api.get_image('worker-avatar/Original/2018/0612/f3230a72-57ab-4aaf-a741-61d8c078fe89.jpg')
+    # out = api.get_worker_list_by_project_name('济南市中心医院(东院区)项目工程总承包(EPC)')
+    # print(len(out))

+ 222 - 0
3rdparty/xclient/xinflux.py

@@ -0,0 +1,222 @@
+# update: 2021-8-23-14
+# see: https://github.com/influxdata/influxdb-python - pip install influxdb
+# see: https://pypi.org/project/influxdb/#history
+# see: https://registry.hub.docker.com/_/influxdb
+# see: https://influxdb-python.readthedocs.io/en/latest/include-readme.html
+# see: https://github.com/unaizalakain/qinfluxdb - influxdb orm
+# see: https://blog.csdn.net/liuming690452074/article/details/115719884 - delete
+# see: https://blog.csdn.net/xiligey1/article/details/104530893/
+# see: https://blog.csdn.net/yue530tomtom/article/details/82688453 - func
+"""
+"""
+from influxdb import InfluxDBClient
+import datetime
+import time
+
+
+class Client(InfluxDBClient):
+
+    def __init__(self, host='fra-middleware-influx', port=8086, database='vms'):
+        """
+        内部访问:
+            host: fra-middleware-influx
+            port: 8086
+        远程访问:
+            host: 192.168.30.59
+            port: 7080
+        """
+        """
+        def filter
+        def remove
+        def append
+        def add
+
+        def write
+        def read
+        def save
+        def add
+        def set
+        def get
+        def put
+
+        def craete
+        def delete
+        def update
+        def select
+        """
+        self.database = database
+        super().__init__(host, port, 'admin', 'admin', database)
+        self.create_database(database)
+
+    def add_item(self, table, key_dict=dict(), value_dict=dict()):
+        """保存单条"""
+        _points = [
+            {
+                'measurement': table,  # 表名
+                'time': datetime.datetime.now().isoformat('T'),  # iso标准格式
+                'tags': key_dict,
+                'fields': value_dict
+            }
+        ]
+        return self.write_points(_points, database=self.database)
+
+    def add_items(self, table, key_list=list(), value_list=list()):
+        """保存多条"""
+        _points = list()
+        for key, value in zip(key_list, value_list):
+            _point = {
+                'measurement': table,  # 表名
+                'time': datetime.datetime.now().isoformat('T'),  # iso标准格式
+                'tags': key,
+                'fields': value
+            }
+            _points.append(_point)
+        return self.write_points(_points, database=self.database)
+
+    def filter_by_time_range(self, table, start_ts, end_ts):
+        """按时时间筛选"""
+        start_at = time.strftime('%Y-%m-%dT%H:%M:%SZ', time.localtime(start_ts))
+        end_at = time.strftime('%Y-%m-%dT%H:%M:%SZ', time.localtime(end_ts))
+        sql = f"select * from {table} "
+        sql += f"where time >= '{start_at}' and time <= '{end_at}'"
+        sql += f'order by time desc;'
+        result = self.query(sql, database=self.database)
+        return result.get_points()
+
+    def remove_one(self, table, k, v):  # todo 不可用
+        """按时时间筛选"""
+        sql = f"delete from {table} where \"{k}\"=\"{v}\";"
+        return self.query(sql, database=self.database)
+
+    def delete_table(self, table):
+        return self.drop_measurement(table)
+
+
+if __name__ == '__main__':
+    """
+    sudo python3 -m pip install influxdb
+    sudo python3 /home/server/projects/taiwuict/cscec-8bur-vms/supplement-python/clients/db_influx.py
+    """
+    import time
+
+    # --- init ---
+    # xdb = Client(host='192.168.30.59', port=7080, database='vms')
+    # xdb = Client(host='192.168.30.169', port=7080, database='vms')
+    # xdb = Client(host='192.168.30.13', port=7080, database='vms')
+    # xdb = Client(host='192.168.20.231', port=7080, database='vms')
+    # xdb = Client(host='192.168.0.15', port=7080, database='vms')
+    xdb = Client(host='192.168.1.242', port=7080, database='vms')  # 第4现场
+
+    # --- test ---
+    s = time.time() - (86400 * 100)
+    e = time.time()
+    out = xdb.filter_by_time_range('FaceLog', s, e)
+    for i in out:
+        print(i)
+        break
+
+    # --- test ---
+    # s = 1649606400
+    # e = 1650297600
+    # out = xdb.filter_by_time_range('FaceLog', s, e)
+    # for i in out:
+    #     print(i)
+    #     break
+
+    # --- test filter_by_time_range ---
+    # s = time.mktime(time.strptime('2020-01-09 13:45:00', '%Y-%m-%d %H:%M:%S'))
+    # e = time.mktime(time.strptime('2022-01-01 17:00:00', '%Y-%m-%d %H:%M:%S'))
+    # out = xdb.filter_by_time_range('FaceLog', s, e)
+    # for i in out:
+    #     print(i)
+    #     break
+
+    # --- test 添加数据 ---
+    # out = xdb.add_item('FaceLog', {}, {'aaa': 111, 'bbb': 222})
+    # print(out)
+
+    # --- test delete_table ---
+    # xdb.delete_table('FaceLog')
+
+    # --- test remove_one ---
+    # xdb.remove_one('FaceLog', 'face_uuid', 'aaabbbccc')
+
+    # --- test 获取数据库列表 ---
+    # out = xdb.get_list_database()
+    # print(out)
+
+    # --- test 创建数据库 ---
+    # xdb.create_database('vms')
+    # out = xdb.get_list_database()
+    # print(out)
+
+    # --- test 删除数据库 ---
+    # out1 = xdb.drop_database('vms1')
+    # out = xdb.get_list_database()
+    # print(out1, out)
+
+    # --- test 显示数据库中的表 ---
+    # out = xdb.query('show measurements;', database=xdb.database)
+    # print(out)
+
+    # --- test 添加数据 ---
+    # points = [
+    #     {
+    #         # "time": datetime.datetime.utcnow().isoformat('T'),  # iso标准时间
+    #         "time": datetime.datetime.now().isoformat('T'),  # iso标准时间
+    #         "measurement": "table23",  # 表名
+    #         "tags": {
+    #             "key1": "server01",
+    #             "key2": "us-west"
+    #         },
+    #         "fields": {
+    #             "field1": 0.64,
+    #             "field2": 0.42,
+    #         }
+    #     }
+    # ]  # 待写入数据库的点组成的列表
+    # out = xdb.write_points(points, database=xdb.database)  # 将这些点写入指定database
+    # print(out)
+
+    # --- test 删除表数据 ---
+    # table_name = 'students'
+    # xdb.query(f"drop measurement {table_name}")  # 删除表
+
+    # --- test query ---
+    # sql = f"select <字段名> from <数据库.表名> "
+    # sql += f"where time >= '<开始时间>' and time <= '<结束时间>' "
+    # sql += f"TZ('Asia/Shanghai')"
+    # out = xdb.query(sql, database='vms')
+    # print(out)
+
+    # --- test ---
+    # now = datetime.datetime.utcnow().isoformat('T')
+    # print(now, type(now))
+
+    # --- test ---
+    # _sql = f"select field1, field2 from table23 "
+    # _sql += f"where time >= '{start_at}' and time <= '{end_at}' "
+    # _sql += f"TZ('Asia/Shanghai');"
+    # out = xdb.query(_sql, database=xdb.database)
+    # print(out)
+
+    # --- test add_item ---
+    # _key_dict = {
+    #     "key1": "server01",
+    #     "key2": "server02",
+    # }
+    # _value_dict = {
+    #     "field1": 0.64,
+    #     "field2": 0.55,
+    # }
+    # out = xdb.add_item('table123', _key_dict, _value_dict)
+    # print(out)
+
+    # --- test add_item ---
+    # _key_dict = {
+    #     'face_uuid': 'aaabbbccc',
+    # }
+    # _value_dict = {
+    #     'count': 1,
+    # }
+    # xdb.add_item('FaceLog', _key_dict, _value_dict)

+ 93 - 0
3rdparty/xclient/xmaria.py

@@ -0,0 +1,93 @@
+# update: 2021-7-2-9
+"""
+pymysql==0.9.3
+peewee==3.13.1  # db orm
+"""
+from peewee import MySQLDatabase as PeeweeEngine  # todo UserWarning: Unable to determine MySQL version
+# from playhouse.mysql_ext import MySQLConnectorDatabase as PeeweeEngine  # todo MySQL connector not installed!
+from playhouse.reflection import generate_models
+
+
+class Client(PeeweeEngine):
+
+    def __init__(self, host='test-stack-mariadb', port=3306, database='vms', username='root', password='root'):
+        """
+        内部访问:
+            host: test-stack-mariadb
+            port: 3306
+        远程访问:
+            host: 118.190.217.96、192.168.20.162
+            port: 17706
+        """
+        super().__init__(database, user=username, password=password, host=host, port=port)
+        tables = generate_models(self)
+        globals().update(tables)
+        self.tables = globals()
+
+        # --- vuls ---
+        # self.vuls = dict()
+        # table = self.tables['vul_detail']
+        # for item in table.select():
+        # 	self.vuls[item.cve_id] = item.__data__
+
+        # def get_vul_by_cve_id(self, cve_id):
+        # 	return self.vuls.get(cve_id, {})
+
+    def get_all(self, table_name):
+        """
+        获取全部数据
+        """
+        table = self.tables[table_name]
+        return table.select()
+
+    def get_one(self, table_name, unique_dict):
+        """
+        单条获取
+        """
+        table = self.tables[table_name]
+        wheres = list()
+        for k, v in unique_dict.items():
+            data = getattr(table, k) == v
+            wheres.append(data)
+        for item in table.select().where(*wheres):
+            return item.__data__
+
+    def execute_sql(self, sql):
+        """
+        执行sql
+        """
+        try:
+            result = db.execute_sql(sql)
+            print(result.__class__.__name__)
+            return result
+        except Exception as exception:
+            print(exception.__class__.__name__)
+            return None
+
+
+if __name__ == '__main__':
+    # --- init ---
+    # db = Client()
+    # db = Client(host='192.168.30.49', port=7033)
+    db = Client(host='127.0.0.1', port=3306, database='ar', username='root', password='20221212!')
+
+    # --- test ---
+    sql = f'''select sum(timestampdiff(second, createtime, updatetime)) from ar.ar_phone_call where status = 1'''
+    result = db.execute_sql(sql)
+    for row in result:
+        print(' --- --- ---- ---')
+        print(row)
+        print(row.__class__.__name__)
+    print(row[0])
+    db.close()
+
+    # --- test ---
+    # items = db.get_all('vul_detail')
+    # for item in items:
+    # 	print(item.cve_id)
+    # 	# print(item.vul_name)
+
+    # --- test ---
+    # out = db.get_one('vul_detail', {'cve_id': 'CVE-2007-1858'})
+    # print(type(out.get('cvss_point')))
+    # print(out.get('cvss_point'))

+ 508 - 0
3rdparty/xclient/xmongo.py

@@ -0,0 +1,508 @@
+# update: 2022-3-30-15
+"""
+$eq 等于
+$ne 不等
+$in []
+db.collection.find({ field: { $not: { $in: [value1, value2, value3] } } })
+$regex 模糊查找
+(>) 大于 - $gt
+(<) 小于 - $lt
+(>=) 大于等于 - $gte
+(<= ) 小于等于 - $lte
+
+
+pip3 install pymongo==3.11.2 -i hhttps://mirror.baidu.com/pypi/simple
+"""
+from pymongo import MongoClient, TEXT
+from bson.objectid import ObjectId
+
+
+class Client(MongoClient):
+
+    def __init__(self, host='sri-thirdparty-mongo', port=27017, database='vms', username='admin', password='admin'):
+        """
+        内部访问:
+            host: sri-thirdparty-mongo
+            port: 27017
+        远程访问:
+            host: 118.190.217.96、192.168.20.162
+            port: 7030
+        """
+        super().__init__(f'mongodb://{username}:{password}@{host}:{port}')
+        self.db = self[database]
+
+    def run_command(self, command=None, command_type='dict', use_admin=False):
+        """
+        Command:
+            print(self.db.command('serverStatus'))
+            print(self.db.command('dbstats'))
+            print(self['admin'].command('listDatabases', 1))  # 查看数据库信息
+            print(self['admin'].command({'setParameter': 1, 'internalQueryExecMaxBlockingSortBytes': 52428800}))  # 设置排序内存限制
+            print(self['admin'].command({'getParameter': 1, 'internalQueryExecMaxBlockingSortBytes': 1}))  # 查询排序内存限制
+            print(self.db.command('collstats', 'WorkFlowPlugin'))  # 查看表信息
+            print(self.db.command({'collStats': 'WorkFlowPlugin'}))  # 查看表信息
+        Usage:
+            self.run_command(
+                command={'setParameter': 1, 'internalQueryExecMaxBlockingSortBytes': 52428800},
+                use_admin=True
+            )  # 设置排序内存限制
+        """
+        if use_admin and command_type == 'dict':
+            return self['admin'].command(command)
+
+    def get_indexes(self, table_name):
+        """
+        获取索引
+        # return collection.indexes.find()
+        # return collection.list_indexes()
+        """
+        collection = self.db[table_name]
+        return collection.index_information()
+
+    def add_index(self, table_name, index_list):
+        """
+        table_name: Xxx
+        index_list: [("field", 1)]
+        # return collection.create_index([('sec_id', TEXT)], name='search_index_zyq', default_language='english')
+        """
+        collection = self.db[table_name]
+        return collection.create_index(index_list)
+
+    def del_index(self, table_name, index_or_name):
+        """
+        删除索引 https://www.dotnetperls.com/create-index-mongodb
+        table_name: Xxx
+        index_list: [("field", 1)]
+        """
+        collection = self.db[table_name]
+        return collection.drop_index(index_or_name)
+
+    def add(self, table_name, data):
+        """
+        保存数据
+        doc: https://www.cnblogs.com/aademeng/articles/9779271.html
+        """
+        table = self.db[table_name]
+        if type(data) == dict:
+            return str(table.insert_one(data).inserted_id)
+        elif type(data) == list:
+            return [str(i) for i in table.insert_many(data).inserted_ids]
+
+    def filter(self, table_name, condition_dict, sort_field=None):
+        """
+        筛选数据
+        condition_dict: 筛选条件
+        sort_field: [('排序字段', -1)]
+        """
+        table = self.db[table_name]
+        if sort_field:
+            return table.find(condition_dict).sort(sort_field)
+        else:
+            return table.find(condition_dict)
+
+    def filter_by_aggregate(self, table_name, condition=None, sort_dict=None, page=None, size=None):
+        """
+        聚合查询
+        condition: 条件
+        sort_dict: 排序 {'字段': -1}
+        page: 页数
+        size: 条数
+        """
+        table = self.db[table_name]
+        parameters = list()
+        if condition:
+            parameters.append({'$match': condition})
+        if sort_dict:
+            parameters.append({'$sort': sort_dict})
+        if type(page) == int and type(size) == int:
+            skip = 0 if page == 1 else (page - 1) * size
+            parameters.append({'$skip': skip})  # 跳过多少条
+            parameters.append({'$limit': size})
+        return table.aggregate(parameters, allowDiskUse=True)
+
+    def get_count(self, table_name, condition_dict=None):
+        """
+        获取数据数量
+        """
+        table = self.db[table_name]
+        if not condition_dict:
+            condition_dict = {}
+        return table.count_documents(condition_dict)
+
+    def get_all(self, table_name, sort_field=None):
+        """
+        获取数据 / 排序
+        table_name: '表名'
+        sort_field: [('排序字段', -1)]
+        """
+        table = self.db[table_name]
+        if sort_field:
+            return table.find().sort(sort_field)
+        else:
+            return table.find()
+
+    def get_one(self, table_name, unique_dict):
+        """
+        单条获取
+        """
+        table = self.db[table_name]
+        data = table.find_one(unique_dict)
+        if data:
+            return data
+        else:
+            return dict()
+
+    def get_last_one(self, table_name, sort_list=None):
+        """
+        获取最后一条
+        table_name: '集合名称'
+        sort_list: [('_id', -1)]
+        """
+        table = self.db[table_name]
+        if not sort_list:
+            sort_list = [('_id', -1)]
+        return table.find_one(sort=sort_list)
+
+    def get_one_by_id(self, table_name, object_id):
+        """
+        单条获取
+        """
+        table = self.db[table_name]
+        return table.find_one({'_id': ObjectId(str(object_id))})
+
+    def update_one_by_id(self, table_name, object_id, update_dict, need_back=False):
+        """
+        单条数据
+        """
+        table = self.db[table_name]
+        modified_count = table.update_one({'_id': ObjectId(str(object_id))}, {'$set': update_dict}).modified_count
+        if need_back:
+            item = self.get_one_by_id(table_name, object_id)
+            item.pop('_id')
+            item['uuid'] = object_id
+            return item
+        else:
+            return modified_count
+
+    def update_all(self, table_name, condition_dict, update_dict):
+        """
+        批量更新
+        """
+        table = self.db[table_name]
+        return table.update_many(condition_dict, {'$set': update_dict}).matched_count
+
+    def update_one(self, table_name, unique_dict, update_dict, default_dict=None, need_back=False):
+        """
+        # if get:
+        #     update update_one_by_id
+        # else:
+        #     insert default_dict
+        # return: get
+        """
+        data = self.get_one(table_name, unique_dict)
+        if data:
+            object_id = str(data.get('_id'))
+            update_dict.update(unique_dict)
+            self.update_one_by_id(table_name, object_id, update_dict)
+        else:
+            if not default_dict:
+                default_dict = dict()
+            if '_id' in default_dict:
+                del default_dict['_id']
+            default_dict.update(update_dict)
+            default_dict.update(unique_dict)
+            object_id = self.add(table_name, default_dict)
+        if need_back:
+            return self.get_one_by_id(table_name, object_id)
+        else:
+            return object_id
+
+    def remove(self, table_name, condition_dict):
+        """
+        批量删除
+        """
+        table = self.db[table_name]
+        return table.delete_many(condition_dict).deleted_count
+
+    def remove_one_by_id(self, table_name, object_id):
+        """
+        单条删除
+        """
+        table = self.db[table_name]
+        return table.delete_many({'_id': ObjectId(str(object_id))}).deleted_count
+
+    def distinct(self, table_name, field):
+        """
+        去重
+        """
+        table = self.db[table_name]
+        return table.distinct(field)
+
+    def get_all_vague(self, table_name, unique_dict):
+        """
+        模糊查询获取
+        """
+        table = self.db[table_name]
+        return table.find(unique_dict)
+
+    def get_aggregate(self, table_name, condition):
+        """
+        分组聚合查询(by wdj)
+        """
+        table = self.db[table_name]
+        return table.aggregate(condition)
+
+    def get_col_list(self, table_name, condition, _dic):
+        """
+        只返回某一列的数据(by wdj)
+        """
+        table = self.db[table_name]
+        return table.find(condition, _dic)
+
+    # def find_by_aggregate(self, table_name,ip):
+    #     """
+    #     分组查询获取   {"$match":{"ip":ip}   {"$group":{"_id":"","counter":{"$sum":1}}}
+    #     """
+    #     table = self.db[table_name]
+    #     count= table.aggregate([{"$group":{"_id":"$find_plugin","count":{"$sum":"$risk_score"}}}])
+    #     return count
+
+    def deep_filter(self, collection, field_path, filter_type='equal', filter_value=None, return_count=False,
+                    sort_field=None):
+        """
+        field_path: 递进字段名(适用字典类型)
+        filter_type: 筛选类型 contain !contain equal !equal in !in
+        sort_field: [('排序字段', -1)]
+        """
+        if filter_type == 'equal':
+            filter_rule = {'$eq': filter_value}
+        elif filter_type == 'contain':
+            filter_rule = {'$regex': f'^.*{filter_value}.*$'}
+        else:
+            filter_rule = {}
+        condition = {
+            field_path: filter_rule
+        }
+        if return_count:
+            return self.get_count(collection, condition)
+        elif sort_field:
+            return self.filter(collection, condition, sort_field)
+        else:
+            return self.filter(collection, condition)
+
+    def del_collect(self):
+        db_collections = self.db.collection_names()
+        for collection in db_collections:
+            self.db[collection].drop()
+
+    @staticmethod
+    def uuid2oid(uuid):
+        return ObjectId(uuid)
+
+
+if __name__ == '__main__':
+    """
+    sudo python3 -m pip install pymongo
+    sudo python3 /home/server/projects/taiwuict/cscec-8bur-vms/supplement-python/clients/db_mongo.py
+    """
+    # --- init ---
+
+    # mdb = Client(database='vms', host='192.168.0.16', port=7030)
+    # mdb = Client(database='vms', host='192.168.51.242', port=7030)
+    # mdb = Client(database='vms', host='192.168.1.233', port=7030)
+    # mdb = Client(database='vms', host='192.168.0.16', port=7030)
+    # mdb = Client(database='vms', host='10.8.20.115', port=7030)  # 晨鸣大厦
+    # mdb = Client(database='vms', host='192.168.15.195', port=7030)
+    # mdb = Client(database='vms', host='192.168.0.15', port=7030)
+    # mdb = Client(database='vms', host='192.168.101.199', port=7030)  # 章丘项目
+    # mdb = Client(database='vms', host='192.168.15.195', port=7030)  # 第3现场
+    # mdb = Client(database='vms', host='192.168.1.242', port=7030)  # 第4现场
+    # mdb = Client(database='ar', host='58.34.94.176', port=7030)  # 第4现场
+    mdb = Client(host='127.0.0.1', port=27017, database='ar', username='', password='')
+
+    # --- test ---
+    data = {
+        'username': 'aabbss',
+        'password': 'aabbss',
+        'role_id': 'aabbss',
+        'create_at': 11223344,
+    }
+    uuid = mdb.add('User', data)
+    # --- test ---
+    # __condition = {
+    #     'face_name': {'$eq': None},
+    # }
+    # total = mdb.get_count('Face', __condition)
+    # print(total)
+    # total = mdb.remove('Face', __condition)
+    # print(total)
+    # total = mdb.get_count('Face', __condition)
+    # print(total)
+
+    # --- test ---
+    # __condition = {
+    #     # 'face_name': {'$ne': None},
+    #     # 'face_name': {'$eq': None},
+    #     'face_name': {'$regex': '陈忠福'},
+    #     # 'face_features': {'$eq': b'\x80\x03N.'},
+    # }
+    # items = mdb.filter('Face', __condition)
+    # for item in items:
+    #     print(item)
+    #     # print(item.keys())
+    # total = mdb.get_count('Face', __condition)
+    # print(total)
+
+    # --- test ---
+    # _id = '62cbbefba007e25f12acea9d'
+    # out = mdb.get_one_by_id('Face', _id)
+    # print(out)
+
+    # --- test ---
+    # condition = {
+    #     # 'face_name': {'$eq': None},
+    #     'face_name': {'$ne': None},
+    # }
+    # total = mdb.get_count('Face', condition)
+    # print(total)
+
+    # --- test ---
+    # items = mdb.get_all('Face')
+    # for item in items:
+    #     if 'c7304b' in str(item.get('_id')):
+    #         print(item)
+
+    # --- test ---
+    # __condition = {
+    #     # 'face_feature_info_list': {'$ne': None},
+    #     'face_feature_info_list': {'$eq': None},
+    # }
+    # # items = mdb.filter('Face', __condition)
+    # # for item in items:
+    # #     print(item)
+    # #     break
+    # total = mdb.get_count('Face', __condition)
+    # print(total)
+    # total = mdb.remove('Face', __condition)
+    # print(total)
+    # total = mdb.get_count('Face', __condition)
+    # print(total)
+
+    # --- test ---
+    # unique_dict = {
+    #     'prc_id': '371324199110201974',
+    # }
+    # item = mdb.get_one('Face', unique_dict)
+    # print(item.get('cscec8_id'))
+
+    # --- test ---
+    # __condition = {
+    #     'face_type_uuid_list': {'$in': ['62a190ca84b2c038bac3519d', 'aa', '62a1a438024e59b2e654467a']}
+    # }
+    # items = mdb.filter('Face', __condition)
+    # for item in items:
+    #     print(item.get('face_name'))
+
+    # --- test ---
+    # __condition = {
+    #     # 'prc_id': {'$ne': None},
+    #     # 'face_name': {'$ne': None},
+    # }
+    # items = mdb.filter('Face', __condition)
+    # for item in items:
+    #     print(item)
+    #     mdb.update_one_by_id('Face', str(item.get('_id')), {'upload_is': None})
+
+    # --- test ---
+    # total = mdb.get_count('Face', __condition)
+    # print(total)
+
+    # --- test ---
+    # # _id = '6295942092325efa38758bf1'
+    # # _id = '629591b792325efa38758be2'
+    # # _id = '6295925992325efa38758be5'
+    # _id = '6295915592325efa38758bdf'
+    # # mdb.update_one_by_id('Face', _id, {'prc_id': '370102198802249999'})
+    # # mdb.update_one_by_id('Face', _id, {'prc_id': '370102198802241111'})
+    # mdb.update_one_by_id('Face', _id, {'cscec8_id': 'f6bae517-0a28-429c-b65b-b16548ab2ca4'})
+
+    # --- test ---
+    # import time
+    #
+    # __condition = dict(
+    #     modify_at={'$gte': time.time() - 86400 * 100},
+    #     # modify_at={'$gte': methods.now_ts() - 3600},
+    # )
+    # items = mdb.filter('Face', __condition)
+    # for item in items:
+    #     print(item.keys())
+    # total = mdb.get_count('Face', __condition)
+    # print(total)
+
+    # --- test ---
+    # __uuid = '6244068e64481ae85ca38ef9'
+    # item = mdb.get_one_by_id('Face', __uuid)
+    # print(item)
+
+    # --- test ---
+    # _uuid = '6243fa35d169a1bf065f8f02'
+    # item = mdb.get_one_by_id('Face', _uuid)
+    # print(item.get('face_feature_info_list')[0])
+
+    # --- test ---
+    # """
+    # Face: 陌生人脸表
+    # Face.face_name: 姓名
+    # """
+    # __condition = {
+    #     # 'face_name': {'$ne': None},
+    #     # 'face_name': {'$eq': None},
+    #     'face_name': {'$regex': '王'},
+    # }
+    # items = mdb.filter('Face', __condition)
+    # for item in items:
+    #     print(item)
+    #     break
+    # total = mdb.get_count('Face', __condition)
+    # print(total)
+
+    # --- test ---
+    # __condition = {
+    #     'name': {'$eq': '未知类型'}
+    # }
+    # count = mdb.get_count('FaceType', __condition)
+    # print(count)
+
+    # --- test ---
+    # items = mdb.get_all('VisitorInfo')
+    # for item in items:
+    #     _list = item.get('aaabbbccc', [])
+    #     print('_list', type(_list), _list)
+    #     break
+
+    # --- test ---
+    # _condition = {'ipv4': '192.168.30.232'}
+    # items = mdb.filter_by_aggregate('UserCamera', condition=_condition, sort_dict={'create_at': -1}, page=1,
+    #                                 size=10)
+    # count = 0
+    # for item in items:
+    # 	count += 1
+    # print(count)
+
+    # --- test ---
+    # _uuid = '604c22d22043eb79cb425c9c'
+    # out = mdb.remove('AgentDetectionRecord', {'camera_uuid': _uuid})
+    # # out = mdb.get_one('AgentDetectionRecord', {'camera_uuid': _uuid})
+    # print(out)
+
+    # --- test ---
+    # _condition = {
+    #     '_id': {'$in': [ObjectId('605994eb7c29e9dc3887e639')]}
+    # }
+    # items = mdb.filter('AgentDetectionRecord', _condition)
+    # for item in items:
+    #     print(item)
+
+    # --- test ---
+    # out = mdb.get_count('VisitorInfo')
+    # print(out)

+ 110 - 0
3rdparty/xclient/xmqtt.py

@@ -0,0 +1,110 @@
+"""
+cd /home/server/repositories/repositories/gitee.com/casperz.py-project/module-py/xclient
+
+pip3 install paho-mqtt==1.6.1
+
+python3 xmqtt-a1.py
+python3 xmqtt-a2.py
+python3 xmqtt.py
+
+
+pip3 install paho-mqtt==1.6.1 -i hhttps://mirror.baidu.com/pypi/simple
+
+
+
+import paho.mqtt.client as mqtt
+
+# MQTT 代理设置
+broker_address = "你的代理地址"
+broker_port = 1883
+username = "admin"
+password = "SRIsri123"
+
+# 创建客户端实例
+client = mqtt.Client()
+
+# 设置用户名和密码
+client.username_pw_set(username, password)
+
+# 连接到 MQTT 代理
+client.connect(broker_address, broker_port)
+
+# 可以继续执行 MQTT 操作(发布、订阅等)
+
+
+"""
+import paho.mqtt.client as mqtt
+import time
+import json
+
+
+class Client(mqtt.Client):
+
+    def __init__(self, host='127.0.0.1', port=41883):
+        super().__init__()
+        self.connect(host=host, port=port, keepalive=60)
+        # if subscribe_topic:
+        #     def on_message(client, userdata, message):
+        #         # print(f"#userdata: {userdata}")
+        #         # print(f"#message.payload: {str(message.payload.decode())}")
+        #         print(f"#message.payload: {json.loads(message.payload)}")
+        #         print(f"#message.topic: {message.topic}")
+        #
+        #     self.on_message = on_message
+        #     self.subscribe(subscribe_topic)
+        #     self.loop_forever()
+
+    def start_subscribe_loop(self, decorate_method, subscribe_topic):
+        """启动订阅循环"""
+        self.on_message = decorate_method
+        self.subscribe(subscribe_topic)
+        self.loop_forever()
+
+    def publish_message(self, publish_topic, message):
+        """发布消息"""
+        try:
+            results = self.publish(publish_topic, message)
+            result_code, message_id = results
+            """
+            result_code: 错误码
+            result_code.0: 成功
+            result_code.1: 失败
+            result_code.4: 无法连接到 MQTT 代理
+            result_code.7: QoS错误
+            """
+            print(f"#result_code: {result_code}, #message_id: {message_id}")
+        except Exception as e:
+            print(f'#Exception: {e.__class__.__name__}')
+
+
+if __name__ == '__main__':
+    # --- init ---
+    # c1 = Client(host='127.0.0.1', port=41883)
+    c1 = Client(host='192.168.131.23', port=41883)
+
+    # --- test subscribe ---
+    # def m1(_, __, p3):
+    #     print(f"#message.payload: {json.loads(p3.payload)}")
+    # c1.start_subscribe_loop(decorate_method=m1, subscribe_topic='test/topic')
+
+    # --- test publish ---
+    # while True:
+    #     data = {
+    #         'code': 1001,
+    #         '方向': 6000,
+    #         '刹车': 6000,
+    #         '油门': 8000,
+    #     }
+    #     # c1.publish_message('bg/log', json.dumps(data))
+    #     c1.publish_message('hs/vehicle/state', json.dumps(data))
+    #     time.sleep(3)
+
+    # --- test publish ---
+    while True:
+        data = {
+            'address': "192.168.131.180",
+            'state': 2,
+            'direction': 22,
+        }
+        c1.publish_message('hs/vehicle/state', json.dumps(data))
+        time.sleep(3)

+ 155 - 0
3rdparty/xclient/xmysql.py

@@ -0,0 +1,155 @@
+# update: 2023-11-12-19
+"""
+SQLAlchemy==1.4.30
+
+问题:
+    CryptographyDeprecationWarning: Python 3.6 is no longer supported by the Python core team. Therefore, support for it is deprecated in cryptography. The next release of cryptography will remove support for Python 3.6.
+    from cryptography.hazmat.backends import default_backen
+解决:
+    pip3 install cryptography==3.4.8
+
+see: https://blog.csdn.net/weixin_46281427/article/details/122916870
+
+# --- 解决root密码中包含@的问题
+self.mysql_dwd_config = {
+    'drivername': 'mysql+pymysql',
+    'username': 'user_a',
+    'password': 'xxx@#$xxx',
+    'host': 'am-xxxxx.ads.aliyuncs.com',
+    'port': 3306,
+}
+if sqlalchemy.__version__ >= '1.4': #其实大于1.4.15之后,密码里面含有@,就必须以这种方式创建正确正则识别密码的引擎了。
+    self.mysql_engine_url = sqlalchemy.engine.URL.create(**self.mysql_dwd_config)
+    self.mysql_engine_url = self.mysql_engine_url.update_query_dict({'charset': 'utf8mb4'})
+else:
+    # password 含有@
+    self.mysql_engine_url = '{drivername}://{username}:{password}@{host}:{port}/?charset=utf8mb4'.format(**self.mysql_dwd_config)
+self.mysql_dwd_engine = sqlalchemy.create_engine(self.mysql_engine_url)
+"""
+from sqlalchemy import create_engine, inspect, MetaData, Table
+from sqlalchemy.orm import sessionmaker
+
+
+class Client():
+
+    def __init__(self, host='127.0.0.1', port=3306, database='ar', username='root', password='20221212!'):
+        """
+        """
+        # 设置字符集
+        args = 'charset=utf8mb4'
+        # 设置关闭 only_full_group_by 模式
+        args = '&sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION'
+        self.engine = create_engine(f"mysql+pymysql://{username}:{password}@{host}:{port}/{database}?{args}")
+        # self.engine = create_engine(f"mysql+pymysql://{username}:{password}@{host}:{port}/{database}")
+
+        self.database = database
+        self.inspect = inspect(self.engine)
+
+    def get_all_database(self):
+        """获取全部数据库名称"""
+        return self.inspect.get_schema_names()
+
+    def get_all_table(self, database_name):
+        """获取全部数据表名称"""
+        return self.inspect.get_table_names(schema=database_name)
+
+    def get_all_field(self, table_name):
+        """获取全部字段名称"""
+        fields = self.inspect.get_columns(table_name, schema=self.database)  # 表名,库名
+        return [i.get('name') for i in fields]
+
+    def execute_sql(self, sql):
+        """
+        执行sql
+        """
+        try:
+            result = self.engine.execute(sql).fetchone()[0]
+            # print(result.__class__.__name__)
+            return result
+        except Exception as exception:
+            print(exception.__class__.__name__)
+            return None
+
+    def get_all(self, table_name):
+        """
+        获取全部数据
+        """
+        sql = f"SELECT * FROM {table_name};"
+        try:
+            result = self.engine.execute(sql).fetchall()  # 返回的是列表
+            # print(result.__class__.__name__)
+            return result
+        except Exception as exception:
+            print(exception.__class__.__name__)
+            return None
+
+    def get_one(self, table_name='ar_user', where_key='ACCT', where_val='admin'):
+        """
+        单条获取
+        """
+        sql = f"SELECT * FROM {table_name} WHERE {where_key} = '{where_val}';"
+        try:
+            result = self.engine.execute(sql).fetchone()  # 返回的是元祖
+            # result = self.engine.execute(sql).fetchall()  # 返回的是列表
+            # print(result.__class__.__name__)
+            return result
+        except Exception as exception:
+            print(exception.__class__.__name__)
+            return None
+
+
+if __name__ == '__main__':
+    # --- init ---
+    # db = Client(host='127.0.0.1', port=3306, database='ar', username='root', password='20221212!')
+    db = Client(host='58.34.94.176', port=8806, database='ar', username='root', password='rootroot&123123')
+
+    # --- test ---
+    # result = db.get_all_field('ar_user')
+    # result = db.get_all('ar_phone_call')
+    result = db.get_one('ar_user', 'USER_ID', '10000LXQ')
+    print(result)
+    print(result[1])
+
+    # --- test ---
+#     sql = f'''select a.USER_ID, a.USER_NAME, a.EMP_NO, a.PHOTO, a.PHONE, c.DEPT_ID, c.DEPT_NAME, e.ROLE_ID, e.ROLE_NAME, a.IS_DISABLED
+#  from ar_user a left JOIN ar_user_dept_rel b ON a.USER_ID = b.USER_ID
+#  left join ar_dept c on c.DEPT_ID = b.DEPT_ID
+#  left join ar_user_role_rel d on a.USER_ID = d.USER_ID
+#  left join ar_role e on d.ROLE_ID = e.ROLE_ID
+#  where a.ACCT = 'admin'
+# '''
+#     sql = f'''select a.USER_ID, a.USER_NAME, a.EMP_NO, a.PHOTO, a.PHONE, c.DEPT_ID, c.DEPT_NAME, e.ROLE_ID, e.ROLE_NAME, a.IS_DISABLED
+#  from AR_USER a left JOIN AR_USER_DEPT_REL b ON a.USER_ID = b.USER_ID
+#  left join AR_DEPT c on c.DEPT_ID = b.DEPT_ID
+#  left join AR_USER_ROLE_REL d on a.USER_ID = d.USER_ID
+#  left join AR_ROLE e on d.ROLE_ID = e.ROLE_ID
+#  where a.ACCT = 'admin'
+# '''
+#     out = db.engine.execute(sql).fetchone()
+#     print(out)
+
+# --- test ---
+# result = db.get_all_field('ar', 'ar_user')
+# print(result)
+
+# --- test ---
+# result = db.get_one()
+# result = db.get_one(table_name='ar_user', where_key='USER_NAME', where_val='陈旭')
+# result = db.get_one(table_name='ar_user', where_key='USER_NAME', where_val='admin')
+# print(result)
+
+# --- test ---
+# sql = f'''select count(1) from ar.ar_phone_call where status in (0, 1)'''
+# result = db.execute_sql(sql)
+# print(result)
+
+# --- test ---
+# items = db.get_all('vul_detail')
+# for item in items:
+# 	print(item.cve_id)
+# 	# print(item.vul_name)
+
+# --- test ---
+# out = db.get_one('vul_detail', {'cve_id': 'CVE-2007-1858'})
+# print(type(out.get('cvss_point')))
+# print(out.get('cvss_point'))

+ 116 - 0
3rdparty/xclient/xqcloudsms.py

@@ -0,0 +1,116 @@
+from qcloudsms_py import SmsSingleSender
+from qcloudsms_py.httpclient import HTTPError
+import time
+
+
+class Client(object):
+
+    def __init__(self):
+        appid = 1400278842  # 短信应用 SDK AppID
+        appkey = '9514696ecf07081a42b4a19bfaf5bf2e'  # 短信应用 SDK AppKey
+        self.ssender = SmsSingleSender(appid, appkey)
+        self.sms_sign = '泽鹿安全'
+
+    def for_add_vul(self, phone_numbers, find_at, address, vul_id, risk):
+        """
+        新增漏洞提醒
+        """
+        template_id = 479975
+        params = [str(find_at), str(address), str(vul_id), str(risk)]
+        for phone_number in phone_numbers:
+            try:
+                result = self.ssender.send_with_param(86, str(phone_number),
+                                                      template_id, params,
+                                                      sign=self.sms_sign,
+                                                      extend='', ext='')
+                print(result)
+            except HTTPError as e:
+                print(e)
+            except Exception as e:
+                print(e)
+
+    def for_close_task(self, phone_numbers, task_id, date_time, username, state):
+        """
+        工单关闭提醒
+        """
+        template_id = 479977
+        params = [str(task_id), str(date_time), str(username), str(state)]
+        for phone_number in phone_numbers:
+            try:
+                result = self.ssender.send_with_param(86, str(phone_number),
+                                                      template_id, params,
+                                                      sign=self.sms_sign,
+                                                      extend='', ext='')
+                print(result)
+            except HTTPError as e:
+                print(e)
+            except Exception as e:
+                print(e)
+
+    def for_remind_task(self, phone_numbers, task_id, residue_time):
+        """
+        工单时限提醒
+        """
+        template_id = 479982
+        params = [str(task_id), str(residue_time)]
+        for phone_number in phone_numbers:
+            try:
+                result = self.ssender.send_with_param(86, str(phone_number),
+                                                      template_id, params,
+                                                      sign=self.sms_sign,
+                                                      extend='', ext='')
+                print(result)
+            except HTTPError as e:
+                print(e)
+            except Exception as e:
+                print(e)
+
+    def for_claim_task(self, phone_numbers, task_id, username, action):
+        """
+        工单状态变化
+        """
+        template_id = 503921
+        year = time.strftime('%Y', time.localtime(int(time.time())))
+        month = time.strftime('%m', time.localtime(int(time.time())))
+        day = time.strftime('%d', time.localtime(int(time.time())))
+        hour = time.strftime('%H', time.localtime(int(time.time())))
+        minute = time.strftime('%M', time.localtime(int(time.time())))
+        params = [str(task_id)[-8:], str(year), str(month), str(day), str(hour), str(minute), str(username)[-8:],
+                  action[-8:]]
+        for phone_number in phone_numbers:
+            try:
+                result = self.ssender.send_with_param(86, str(phone_number),
+                                                      template_id, params,
+                                                      sign=self.sms_sign,
+                                                      extend='', ext='')
+                print(result)
+            except HTTPError as e:
+                print(e)
+            except Exception as e:
+                print(e)
+
+    def for_vul_message(self, phone_numbers, find_at, address):
+        """
+        漏洞提醒
+        """
+        template_id = 630480
+        params = [str(find_at), str(address)]
+        for phone_number in phone_numbers:
+            try:
+                result = self.ssender.send_with_param(86, str(phone_number),
+                                                      template_id, params,
+                                                      sign=self.sms_sign,
+                                                      extend='', ext='')
+                print(result)
+                return result
+            except HTTPError as e:
+                print(e)
+            except Exception as e:
+                print(e)
+
+
+if __name__ == '__main__':
+    # --- init ---
+    client = Client()
+
+    # --- test ---

+ 310 - 0
3rdparty/xclient/xredis.py

@@ -0,0 +1,310 @@
+# update: 2021-7-14-11
+import redis
+import pickle
+
+
+class Client(redis.StrictRedis):
+
+    def __init__(self, host='fra-middleware-redis', port=6379, db=0, password='', channels=[]):
+        """
+        内部访问:
+            host: fra-middleware-redis
+            port: 6379
+        远程访问:
+            host: 118.190.217.96、192.168.20.162
+            port: 7070
+        """
+        self.host = host
+        self.port = port
+        self.db = db
+        super().__init__(host=self.host, port=self.port, db=self.db)
+
+        self.channels = channels
+        if self.channels:
+            """
+            dir(self.pubsub()):
+            ['HEALTH_CHECK_MESSAGE', 'PUBLISH_MESSAGE_TYPES', 'UNSUBSCRIBE_MESSAGE_TYPES', 'channels', 'check_health', 
+            'close', 'connection', 'connection_pool', 'encoder', 'execute_command', 'get_message', 'handle_message', 
+            'health_check_response', 'ignore_subscribe_messages', 'listen', 'on_connect', 'parse_response', 'patterns', 
+            'pending_unsubscribe_channels', 'pending_unsubscribe_patterns', 'ping', 'psubscribe', 'punsubscribe', 
+            'reset', 'run_in_thread', 'shard_hint', 'subscribe', 'subscribed', 'unsubscribe']
+            """
+            self.channel_pubsub = self.pubsub()
+            self.channel_pubsub.psubscribe(channels)
+            # self.channel_listen = self.channel_pubsub.listen()
+
+    def get_config(self):
+        """
+        CONFIG GET|SET: 分别用 config_get 和 config_set 实现。
+        """
+        return self.config_get()
+
+    def set_config(self, name, value):
+        """
+        CONFIG GET|SET: 分别用 config_get 和 config_set 实现。
+        """
+        return self.config_set(name=name, value=value)
+
+    def get_elements(self, key):
+        """获取列表元素"""
+        return self.lrange(key, 0, -1)
+
+    def get_elements_length(self, key):
+        """获取列表长度"""
+        return self.llen(key)
+
+    def pop_element(self, key, position='RightEnd'):
+        """
+        弹出元素
+        position: 出队位置 LeftEnd 左端 RightEnd 右端
+        """
+        _dict = {
+            'LeftEnd': 'lpop',
+            'RightEnd': 'rpop',
+        }
+        func = getattr(self, _dict.get(position))
+        pickle_data = func(key)
+        element = pickle.loads(pickle_data) if pickle_data else None
+        return element
+
+    def add_element(self, key, element, position='RightEnd'):
+        """
+        增加元素
+        position: 入队位置 LeftEnd 左端 RightEnd 右端
+        """
+        _dict = {
+            'LeftEnd': 'lpush',
+            'RightEnd': 'rpush',
+        }
+        func = getattr(self, _dict.get(position))
+        pickle_data = pickle.dumps(element)
+        elements_length = func(key, pickle_data)
+        return elements_length
+
+    def set_one(self, key, data, expire_time=None):
+        """压缩存储"""
+        pickle_data = pickle.dumps(data)
+        return self.set(key, pickle_data, ex=expire_time)
+
+    def get_one(self, key):
+        """解压获取"""
+        pickle_data = self.get(key)
+        return pickle.loads(pickle_data) if pickle_data else None
+
+    def push_one(self, channel, data):
+        """
+        推送一条
+        """
+        return self.publish(channel, pickle.dumps(data))
+
+    def pull_one(self, channel):
+        """
+        拉取一条
+        msg = self.channel_pubsub.parse_response(block=False, timeout=60)
+        msg = self.channel_pubsub.parse_response(block=False)
+            [b'pmessage', b'cctv1', b'cctv1', b'3']
+        msg = self.channel_pubsub.get_message()
+            {'type': 'pmessage', 'pattern': b'cctv1', 'channel': b'cctv1', 'data': b'asdfasdfasdf'}
+        """
+        message = self.channel_pubsub.get_message()
+        channel = channel.encode()
+        if message and message.get('pattern') and message.get('channel') == channel:
+            return pickle.loads(message.get('data'))
+
+    def pull_one_by_channel(self, channel):
+        """
+        拉取一条
+        """
+        message = self.channel_pubsub.get_message()
+        channel = channel.encode()
+        if message and message.get('pattern') and message.get('channel') == channel:
+            return pickle.loads(message.get('data'))
+
+    def pull_one_by_channels(self):
+        """
+        拉取一条
+        """
+        message = self.channel_pubsub.get_message()
+        channels = [i.encode() for i in self.channels]
+        if message and message.get('pattern') and message.get('channel') in channels:
+            return pickle.loads(message.get('data'))
+
+    def pull_one_by_channels_v2(self, channels):
+        """
+        拉取一条
+        """
+        message = self.channel_pubsub.get_message()
+        channels = [i.encode() for i in channels]
+        if message and message.get('pattern') and message.get('channel') in channels:
+            return pickle.loads(message.get('data'))
+
+    def pull_one_by_channels_v3(self, channels):
+        """
+        拉取一条(性能不佳)
+        """
+        self.channel_pubsub.psubscribe(channels)
+        message = self.channel_pubsub.get_message()
+        channels = [i.encode() for i in channels]
+        if message and message.get('pattern') and message.get('channel') in channels:
+            return pickle.loads(message.get('data'))
+
+    def print_all(self):
+        """打印"""
+        for key in self.keys():
+            key_type = self.type(key)
+
+            # if key_type != b"stream":
+            #     continue
+
+            if key_type == b'string':
+                value = self.get(key)
+            elif key_type == b'list':
+                value = self.lrange(key, 0, -1)
+            elif key_type == b'set':
+                value = self.smembers(key)
+            elif key_type == b'zset':
+                value = self.zrange(key, 0, -1)
+            elif key_type == b"hash":
+                value = self.hgetall(key)
+            elif key_type == b"stream":
+                value = self.xread({key: b"0-0"})
+            else:
+                value = None
+
+            print(f"type: {key_type} | key: {key}")
+            # print(f"type: {key_type} | key: {key} | value: {value}")
+
+    def filter_keys(self):
+        re_list = []
+        for key in self.keys():
+            if self.type(key) != b'string':
+                continue
+            if b'warn' not in key:
+                continue
+            re_list.append(key)
+        return re_list
+
+    def test(self):
+        while True:
+            msg = self.pull()
+            if msg:
+                print(msg)
+
+
+if __name__ == '__main__':
+    # --- init ---
+    # db0 = Client(host='192.168.30.49', port=7070, channels=['cctv1', 'cctv2'])
+    db0 = Client(host='192.168.30.59', port=7070)
+    # db0 = Client(host='192.168.1.190', port=7070)
+    # db0 = Client(host='fra-middleware-redis', port=6379)
+
+    # --- test ---
+    out = db0.get_elements_length('tasklist1')
+    print(out)
+
+    # --- test --
+    # db0.set_config('client-output-buffer-limit', 'normal 0 0 0 slave 268435456 67108864 60 pubsub 0 0 0')
+    # out = db0.get_config()
+    # print(out)
+
+    # --- test ---
+    # db0.push_one('cctv1', 'asdfasdfasdf')
+
+    # --- test ---
+    # db0.set_object('compare_face_task', [1, 2, 3])
+
+    # --- test ---
+    # out = db0.get_object('compare_face_task')
+    # print(out)
+
+    # --- test ---
+    # db0.hset(name='test001', key='test002', value='test003')
+    # out = db0.hgetall(name='test001')
+    # print(out)
+
+    # --- test ---
+    # db0.print_all()
+
+    # --- test ---
+    # db0.flushdb()
+
+    # --- test ---
+    # import pickle
+    # out = db0.get('real_cam')
+    # out = pickle.loads(out)
+    # print(out)
+
+    # --- test ---
+    # import pickle
+    # out = db0.get('webcam')
+    # out = pickle.loads(out)
+    # print(out)
+
+    # --- test ---
+    # import pickle
+    # config = {
+    #     'aass': 12,
+    #     '1': {
+    #        '2': {
+    #        }
+    #     }
+    # }
+    #
+    # config = pickle.dumps(config)
+    # db0.set('webcam', config, ex=1000)
+    # out = db0.get('webcam')
+    # out = pickle.loads(out)
+    # print(out)
+
+    # --- test ---
+    # out = db0.filter_keys()
+    # print(out)
+    # out = db0.get(out[0])
+    # print(out)
+
+    # --- test ---
+    # db0.delete('warn:192.168.1.68:1604928475')
+    # db0.delete('warn:192.168.1.68:1604928695')
+    # db0.delete('warn:192.168.1.68:1604928479')
+    # db0.delete('warn:192.168.1.68:1604928680')
+    # db0.delete('warn:192.168.1.68:1604928491')
+    # db0.print_all()
+
+    # --- test ---
+    # import pickle
+    # data = pickle.dumps(0)
+    # db0.set('warn:192.168.1.68:<last_at>', data, ex=1000*86400)
+    # out = db0.get(f'warn:192.168.1.68:<last_at>')
+    # print(out)
+
+    # --- test ---
+    # import pickle
+    # data = {
+    #     'last_at': 112233,
+    #     'image': pickle.dumps({}),
+    # }
+    # db0.hmset(name='192.168.1.68:admin:HuaWei123:<find_at>', mapping=data)
+    # out = db0.hmget(name='192.168.1.68:admin:HuaWei123:<find_at>', keys='last_at')
+    # print(out)
+    # out = db0.hget(name='192.168.1.68:admin:HuaWei123:<find_at>', key='last_at')
+    # print(out)
+
+    # --- test ---
+    # db0.set('food', b'mutton', ex=1000)
+    # print(type(db0.get('food')))
+    # print(repr(db0.get('food')))
+    # db0.print_all()
+
+    # --- test ---
+    # data = db0.get('192.168.1.68:admin:HuaWei123')
+    # import numpy as np
+    # data = np.frombuffer(data)
+    # print(repr(data))
+
+    # --- test ---
+    # data = db0.get('192.168.1.68:admin:HuaWei123')
+    # import pickle
+    # data = pickle.loads(data)
+    # import cv2
+    # cv2.imshow('data', data)
+    # cv2.waitKey(0)

+ 42 - 0
3rdparty/xclient/xsmtp.py

@@ -0,0 +1,42 @@
+# update: 2021-1-27-10
+import smtplib
+from email.mime.text import MIMEText
+from email.header import Header
+
+
+class Client(object):
+
+    def __init__(self, username='zhangyouqian@xxx.com', password='DEVdev123',
+                 smtp_host='smtp.exmail.qq.com',  smtp_port=465):
+        self.username = username
+        self.password = password
+        self.smtp_host = smtp_host
+        self.smtp_port = smtp_port
+
+    def send_mails(self, addrs=['zhangyouqian@secdeer.com'],
+                   title='test-0404', text='test', addressee='尊敬的用户', addresser='xxx'):
+
+        # addrs.append('daien@secdeer.com')
+        # addrs.append('lijiaming@secdeer.com')
+        message = MIMEText(text, 'plain', 'utf-8')
+        message['Subject'] = Header(title, 'utf-8')
+        message['From'] = Header(addresser, 'utf-8')
+        message['To'] = Header(addressee, 'utf-8')
+
+        try:
+            server = smtplib.SMTP_SSL(host=self.smtp_host, port=self.smtp_port)
+            server.login(self.username, self.password)
+            server.sendmail(from_addr=self.username, to_addrs=addrs, msg=message.as_string())
+            print('邮件发送成功')
+            return True
+        except Exception as e:
+            import traceback
+            print('Error: %s' % e.__class__.__name__)
+            print('Message: %s' % str(traceback.format_exc()))
+            print('邮件发送失败')
+            return False
+
+
+if __name__ == '__main__':
+    s = Client()
+    s.send_mails(addrs=['xuzhongyiqiang@xxx.com'])

+ 76 - 0
3rdparty/xclient/xsmtp_zl.py

@@ -0,0 +1,76 @@
+import smtplib
+from email.mime.text import MIMEText
+from email.header import Header
+from email.mime.multipart import MIMEMultipart
+from email.mime.application import MIMEApplication
+
+
+class Client(object):
+
+    def __init__(self):
+        self.username = 'xuzhongyiqiang@secdeer.com'
+        self.password = 'YIqiang521..'
+        self.ip = 'smtp.exmail.qq.com'
+        self.port = 45
+
+    def send_email(self, body, send_part2=None, smtp_server="smtp.exmail.qq.com"):
+        """
+        :param body:文件内容
+        :param send_part2: 附件地址
+        :param smtp_server: smtp地址
+        :return:
+        """
+        # 1.发件人、授权码,收件人信息
+        from_addr = "xuzhongyiqiang@secdeer.com"
+        pwd = "YIqiang521.."
+        to_addr = "1092364772@qq.com"
+
+        # 2.创建实例对象,设置主题等信息
+        msg = MIMEMultipart()
+        msg["Subject"] = "清零安全日报"
+        msg["From"] = from_addr
+        msg["To"] = to_addr
+
+        # 邮件内容(按每个部分)
+        part1 = MIMEText(body, "html", 'utf-8')
+        msg.attach(part1)
+        print(part1)
+
+        # send_part2 :附件地址
+        if send_part2:
+            part2 = MIMEApplication(open(send_part2, 'rb').read())
+            part2.add_header('Content-Disposition', 'attachment', filename=send_part2)
+            msg.attach(part2)
+
+        # 3.连接smtp服务器,登录服务器并发送文本
+        smtp_server = smtp_server
+        server = smtplib.SMTP(smtp_server, 25)
+        server.login(from_addr, pwd)
+        server.sendmail(from_addr, to_addr, msg.as_string())  # as_string()把MIMEText变成一个str
+        server.close()
+
+    def send_report_mail(self, addrs=['zhangyouqian@secdeer.com'],
+                         title='爬虫报告', text='爬虫报告', addressee='尊敬的用户', addresser='泽廘安全'):
+
+        addrs.append('daien@secdeer.com')
+        # addrs.append('lijiaming@secdeer.com')
+        message = MIMEText(text, 'plain', 'utf-8')
+        message['Subject'] = Header(title, 'utf-8')
+        message['From'] = Header(addresser, 'utf-8')
+        message['To'] = Header(addressee, 'utf-8')
+
+        try:
+            server = smtplib.SMTP_SSL(self.ip, self.port)
+            server.login(self.username, self.password)
+            server.sendmail(from_addr=self.username, to_addrs=addrs, msg=message.as_string())
+            print('邮件发送成功')
+        except Exception as e:
+            import traceback
+            print('Error: %s' % e.__class__.__name__)
+            print('Message: %s' % str(traceback.format_exc()))
+            print('邮件发送失败')
+
+
+if __name__ == '__main__':
+    s = Client()
+    s.send_report_mail(addrs=['zhangyouqian@secdeer.com'])

+ 198 - 0
3rdparty/xclient/xssh.py

@@ -0,0 +1,198 @@
+# update: 2021-3-26-13
+"""
+https://www.jianshu.com/p/512a5641b501
+
+# --- 上传脚本 ---
+sftp = s.open_sftp()
+sftp.put('../test.sh', '/data/test.sh')
+sftp.close()
+
+# --- 执行脚本并删除 ---
+
+docker exec zelu_8891 bash -c "python /home/server/projects/python-admin/zelu/libraries/protocol_l4/ssh/client.py"
+"""
+import paramiko
+
+
+def test():
+    host_ip = '192.168.30.13'
+    username = 'fish'
+    password = 'admin'
+
+    client = paramiko.SSHClient()
+    try:
+
+        # --- password login ---
+        client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
+        client.connect(hostname=host_ip, port=22, username=username, password=password)
+
+        # --- test ---
+        stdin, stdout, stderr = client.exec_command('ls -all /home')
+        # stdin, stdout, stderr = client.exec_command('ls /home/ShellScripts')
+        print('--- --- --- ---')
+        print(stdout.read().decode('utf-8'))
+
+    except Exception as e:
+        print(e)
+    finally:
+        client.close()
+
+
+class Client(paramiko.SSHClient):
+
+    def __init__(self, ipv4='172.18.0.1', port=22, username='fish', password='admin'):
+
+        super().__init__()
+        self.set_missing_host_key_policy(paramiko.AutoAddPolicy())
+        self.connect(hostname=ipv4, port=port, username=username, password=password)
+
+    def run_script(self, script_path, host_ip, username, password, command='sh /root/1.sh && cat /home/out.txt'):
+        """执行上传脚本"""
+        # script_path = '/home/server/projects/user-dashboard/operation/builtin_script/linux基线检查脚本.sh'
+        # script_path = r'D:\share\gitee\secdeer.user-dashboard-online\operation\builtin_script\linux基线检查脚本.sh'
+        # host_ip = '47.104.160.37'
+        # username = 'root'
+        # password = 'Secdeer_01!'
+        self.connect(hostname=host_ip, port=22, username=username, password=password)
+
+        sftp = self.open_sftp()
+        sftp.put(script_path, '/root/1.sh')
+        sftp.close()
+
+        # stdin, stdout, stderr = self.exec_command('ls -all /home')
+        # stdin, stdout, stderr = self.exec_command('sh /root/1.sh')
+        # stdin, stdout, stderr = self.exec_command('cat /home/out.txt')
+        stdin, stdout, stderr = self.exec_command(command)
+        output = stdout.read().decode('utf-8')
+        print(output)
+        print('--- --- --- ---')
+        return output
+
+    def run_command(self, command):
+        """执行命令"""
+        try:
+            stdin, stdout, stderr = self.exec_command(command)
+            output = stdout.read().decode('utf-8')
+            return output
+        except Exception as exception:
+            import traceback
+            print(f"SSHClient.run_command.exception: {exception.__class__.__name__}")
+            print(f"SSHClient.run_command.traceback: {traceback.format_exc()}")
+
+    # finally:
+    # 	self.close()
+
+    def run_sudo_command(self, command, password):
+        """执行命令"""
+        try:
+            stdin, stdout, stderr = self.exec_command(f"echo \"{password}\" | sudo -S {command}")
+            output = stdout.read().decode('utf-8')
+            return output
+        except Exception as exception:
+            import traceback
+            print(f"SSHClient.run_sudo_command.exception: {exception.__class__.__name__}")
+            print(f"SSHClient.run_sudo_command.traceback: {traceback.format_exc()}")
+
+    # finally:
+    # 	self.close()
+
+    def get_disk_utilization_rate(self, path='/'):
+        """获取根目录磁盘所用空间占比"""
+        try:
+            stdin, stdout, stderr = self.exec_command("df -h")
+            output = stdout.read().decode('utf-8')
+
+            # --- get utilization_rate by '/' ---
+            utilization_rate = str()
+            for row in output.split('\n'):
+                if not row:
+                    continue
+                if row[-1] != '/':
+                    continue
+                for val in row.split(' '):
+                    if '%' in val:
+                        utilization_rate = val
+                        break
+
+            # --- transform ---
+            if '%' in utilization_rate:
+                utilization_rate = int(utilization_rate.strip('%'))
+            else:
+                utilization_rate = 0
+            return utilization_rate
+
+        except Exception as exception:
+            import traceback
+            print(f"SSHClient.show_root_disk.exception: {exception.__class__.__name__}")
+            print(f"SSHClient.show_root_disk.traceback: {traceback.format_exc()}")
+
+    def close(self):
+        self.close()
+
+
+if __name__ == '__main__':
+    # --- init ---
+    # ssh = Client('192.168.30.13', 22, 'fish', 'admin')
+    # ssh = Client('172.18.0.1', 22, 'fish', 'admin')
+    # ssh = Client('192.168.1.45', 22, 'server', 'server')
+    ssh = Client('192.168.30.13', 22, 'server', 'server')
+
+    # --- test ---
+    out = ssh.get_disk_utilization_rate()
+    print(out)
+
+# --- test ---
+# out = ssh.run_command('date +%Y-%m-%d-%H-%M-%S')
+# date +"%Y-%m-%d %H:%M:%S"
+# print(out)
+
+# --- test ---
+# ssh.run_sudo_command('echo -e "\n#x1" >> /etc/network/interfaces', 'admin')
+# ssh.run_sudo_command('echo -e "\n#x1" >> /etc/network/interfaces', 'server')
+# ssh.run_command('echo -e "\n#x2" >> /etc/network/interfaces')
+# ssh.run_command('sudo echo -e "\n#x3" >> /etc/network/interfaces')
+# out = ssh.run_command("sudo chmod 777 /etc/network/interfaces")
+# out = ssh.run_command("cat /etc/network/interfaces")
+# print(out)
+
+# --- test ---
+# out = ssh.run_command("ifconfig")
+# for row in out.split('\n\n'):
+# 	if row[:4] != 'eth0':
+# 		continue
+# 	for one in row.split('\n'):
+# 		one = one.strip()
+# 		if one[:4] != 'inet':
+# 			continue
+# 		if one[:5] == 'inet6':
+# 			continue
+# 		one = [i for i in one.split(' ') if i]
+# 		ipv4, netmask = one[1], one[3]
+# 		print(ipv4, netmask)
+
+# --- test ---
+# out = ssh.run_command('ls /home/server/images')
+# out = ssh.run_command('rm -rf /home/server/images/*')
+# out = ssh.run_sudo_command('rm -rf /home/server/images/*', 'admin')
+# print(out)
+
+# --- test ---
+# out0 = ssh.run_sudo_command('chmod 777 /etc/network/interfaces', 'admin')
+# out1 = ssh.run_command('echo -e "\n#x2" >> /etc/network/interfaces')
+# out2 = ssh.run_command("cat /etc/network/interfaces")
+# print(out2)
+
+# --- test ---
+# out = c.run_command("ls -all /home")
+# out = c.run_command("df -h | grep 234G | awk \'{print $5}\'")
+# out = c.run_command("df -h | grep \"/dev/vda1\" | awk \'{print $5}\'")
+# out = c.run_command("df -h ")
+# print(out)
+
+# --- test ---
+# out = c.run_script(1, 2, 3, 4)
+# print(repr(out))
+
+# --- test ---
+# out = c.run_script('/home/UserFiles/hello.sh', '118.190.217.96', 'root', 'Secdeer_01!', 'sh /root/1.sh')
+# print(repr(out))

+ 31 - 0
3rdparty/xclient/xtcp.py

@@ -0,0 +1,31 @@
+"""
+python3 /home/server/repositories/repositories/sri-project.demo-py/3rdparty/xclient/xtcp.py
+"""
+import asyncio
+import struct
+
+async def send_message(reader, writer, values):
+    data = struct.pack('!hh', *values)
+    writer.write(data)
+    await writer.drain()
+    print(f"Sent values: {values}")
+
+    size = struct.calcsize('!hh')
+    response = await reader.read(size)  # 4 bytes since !hh -> 2 bytes each for h
+    if response:
+        received_values = struct.unpack('!hh', response)
+        print(f"Received response: {received_values}")
+
+async def start_client(host='127.0.0.1', port=20917, messages=[(100, 200)]):
+    reader, writer = await asyncio.open_connection(host, port)
+
+    try:
+        for values in messages:
+            await send_message(reader, writer, values)
+    finally:
+        writer.close()
+        await writer.wait_closed()
+
+if __name__ == "__main__":
+    messages = [(100, 200), (300, 400), (500, 600)]  # 示例消息列表
+    asyncio.run(start_client(messages=messages))

+ 48 - 0
3rdparty/xclient/xudp.py

@@ -0,0 +1,48 @@
+"""
+python3 /home/server/repositories/repositories/sri-project.demo-py/3rdparty/xclient/xudp.py
+"""
+import asyncio
+import struct
+
+
+class CustomProtocol:
+    def __init__(self):
+        self.data_received = asyncio.Future()
+
+    def connection_made(self, transport):
+        self.transport = transport
+
+    def datagram_received(self, data, addr):
+        self.data_received.set_result((data, addr))
+
+    def connection_lost(self, exc):
+        pass
+
+    async def send_message(self, values, addr=('127.0.0.1', 20917)):
+        data = struct.pack('!hh', *values)
+        self.transport.sendto(data, addr)
+        print(f"Sent values: {values}")
+
+        response, _ = await self.data_received
+        if response:
+            received_values = struct.unpack('!hh', response)
+            print(f"Received response: {received_values}")
+
+
+async def start_client(messages=[(100, 200)]):
+    protocol = CustomProtocol()
+    transport, _ = await asyncio.get_running_loop().create_datagram_endpoint(
+        lambda: protocol,
+        remote_addr=('127.0.0.1', 20917)
+    )
+
+    try:
+        for values in messages:
+            await protocol.send_message(values)
+    finally:
+        transport.close()
+
+
+if __name__ == "__main__":
+    messages = [(100, 200), (300, 400), (500, 600)]  # 示例消息列表
+    asyncio.run(start_client(messages=messages))

+ 39 - 0
3rdparty/xdecorator.py

@@ -0,0 +1,39 @@
+from libraries import base_original as methods
+import threading
+
+
+def single_method(_func):
+    """频率控制"""
+    cache = {}
+
+    def decorated_func(*args, **kwargs):
+        func_name = _func.__name__
+
+        if func_name not in cache:
+            cache[func_name] = 'NoRunning'
+
+        if cache.get(func_name) == 'NoRunning':
+            cache[func_name] = 'IsRunning'
+            try:
+                results = _func(*args, **kwargs)
+                cache[func_name] = 'NoRunning'
+                return results
+            except Exception as e:
+                cache[func_name] = 'NoRunning'
+                methods.debug_log(f"@single_method", f"function '{func_name}' is {e.__class__.__name__}!")
+                return dict(code=-1)
+        else:
+            methods.debug_log(f"@single_method", f"function {repr(func_name)} is not finished yet!")
+            return dict(code=1)
+
+    return decorated_func
+
+
+def new_thread(func):
+    """启用线程方式执行"""
+
+    def wrapper(*args, **kwargs):
+        t = threading.Thread(target=func, args=args, kwargs=kwargs)
+        t.start()
+
+    return wrapper

+ 306 - 0
3rdparty/xengine/cv_face_recognition/engine.py

@@ -0,0 +1,306 @@
+# note: https://github.com/SthPhoenix/InsightFace-REST
+"""
+    测试结果:
+        使用python版本的onnxruntime,推理onnx模型,推理一次时间为4751.71ms
+
+    本测试用例适用于onnxruntime-gpu 1.10.0版本
+
+    100帧fp16处理时间
+        TensorrtExecutionProvider: 1464ms
+
+    24帧fp16处理时间
+        TensorrtExecutionProvider: 358.92ms
+
+    1帧fp16处理时间
+        TensorrtExecutionProvider: 49ms
+
+    100帧处理时间
+        TensorrtExecutionProvider: 3727ms
+        CUDAExecutionProvider: 5169ms
+        CPUExecutionProvider: 68953ms
+
+    24帧处理时间
+        TensorrtExecutionProvider: 796ms
+        CUDAExecutionProvider: 1206ms
+        CPUExecutionProvider: 16591ms
+
+    1帧测试
+        TensorrtExecutionProvider: 85ms
+        CUDAExecutionProvider: 88ms
+        CPUExecutionProvider: 738ms
+"""
+from numpy.linalg import norm
+
+import onnxruntime
+import numpy as np
+import cv2
+import logging
+import binascii
+
+import sys
+import importlib
+
+sys.path.append('/home/server/projects/taiwuict/cscec-8bur-vms/supplement-python')
+methods = importlib.import_module(f"libraries.base_original")
+numpy_method = importlib.import_module(f"libraries.base_external.data_by_numpy")
+
+
+class FaceRecognitionEngine:
+    def __init__(self):
+        model_path = '/home/server/resources/DockerDependencies/2022/target/AlgorithmModels/FaceRecognition-arcface/'
+        model_path += 'arcface_r100_v1.onnx'
+        # model_path += 'MFR_glintr100.onnx'
+
+        # --- debug mode ---
+        # self.onnx_session = onnxruntime.InferenceSession(model_path, providers=['TensorrtExecutionProvider'])
+        self.onnx_session = onnxruntime.InferenceSession(model_path, providers=['CUDAExecutionProvider'])  # for test
+        # self.onnx_session = onnxruntime.InferenceSession(model_path, providers=['CPUExecutionProvider'])
+        # self.onnx_session.set_providers(['CUDAExecutionProvider'], [{'device_id': 1}])  # 指定GPU
+
+        # --- release mode ---
+        # providers = [
+        #     ('TensorrtExecutionProvider', {
+        #         # 'device_id': 1,
+        #         # 'trt_max_workspace_size': 2147483648,
+        #         'trt_fp16_enable': True,
+        #         # 'trt_int8_enable': True,
+        #         # 'trt_engine_cache_enable': True,
+        #         # 'trt_engine_cache_path': '',
+        #     }),
+        # ]
+        # self.onnx_session = onnxruntime.InferenceSession(model_path, providers=providers)
+
+        self.outputs = [e.name for e in self.onnx_session.get_outputs()]
+
+    def prepare(self, **kwargs):
+        """模型初始化"""
+        logging.info("Warming up ArcFace ONNX Runtime engine...")
+        self.onnx_session.run(output_names=self.outputs,
+                              input_feed={
+                                  self.onnx_session.get_inputs()[0].name: [np.zeros((3, 112, 112), np.float32)]})
+
+    @staticmethod
+    def normalize(embedding):
+        """特征数据格式化"""
+        embedding_norm = norm(embedding)
+        normed_embedding = embedding / embedding_norm
+        return normed_embedding
+
+    def get_face_features_normalization_by_image_array(self, image_array):
+        """获取特征"""
+
+        # --- debug ---
+        # methods.debug_log('FaceRecognitionEngine', f"m-92: size: {image_array.shape}")
+
+        # --- check todo 连乘得到像素值,旨在过滤低于112的尺寸图片 ---
+        # if np.prod(image_array.shape) < np.prod((112, 112, 3)):
+        #     return None
+
+        # --- check ---
+        if image_array is None:
+            return None
+
+        # --- check ---
+        if image_array.shape != (112, 112, 3):
+            # methods.debug_log('FaceRecognitionEngine', f"m-96: image resize before is {image_array.shape}")
+            image_array = cv2.resize(image_array, (112, 112))
+
+        if not isinstance(image_array, list):
+            image_array = [image_array]
+
+        for i, img in enumerate(image_array):
+            img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
+            img = np.transpose(img, (2, 0, 1))
+            image_array[i] = img.astype(np.float32)
+
+        image_array = np.stack(image_array)
+        net_out = self.onnx_session.run(self.outputs, {self.onnx_session.get_inputs()[0].name: image_array})
+        return self.normalize(net_out[0][0])
+
+    @staticmethod
+    def image_bytes_to_image_array(image_bytes, mode='RGB'):
+        """
+        数据格式转换
+        """
+        _image = numpy_method.bytes_to_array_v2(image_bytes)
+        _image = cv2.imdecode(_image, cv2.IMREAD_COLOR)
+        return _image
+
+    def get_face_features_normalization_by_image_bytes(self, image_bytes):
+        """获取特征"""
+        # --- bytes to array ---
+        image_array = self.image_bytes_to_image_array(image_bytes)
+
+        # --- check todo 低于112的尺寸,则过滤掉 ---
+        # if np.prod(image_array.shape) < np.prod((112, 112, 3)):
+        #     return None
+
+        # --- check size --- todo 如果是4通道,考虑通过cvtColor转3通道
+        if image_array.shape != (112, 112, 3):
+            image_array = cv2.resize(image_array, (112, 112))
+
+        if not isinstance(image_array, list):
+            image_array = [image_array]
+
+        for i, img in enumerate(image_array):
+            img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
+            img = np.transpose(img, (2, 0, 1))
+            image_array[i] = img.astype(np.float32)
+
+        image_array = np.stack(image_array)
+        net_out = self.onnx_session.run(self.outputs, {self.onnx_session.get_inputs()[0].name: image_array})
+        return self.normalize(net_out[0][0])
+
+    @staticmethod
+    def compare_faces_by_normalization(input_normalization, specimen_normalization):
+        """
+        计算相似度(使用格式化数据)
+        """
+        _sim = (1.0 + np.dot(input_normalization, specimen_normalization)) / 2.0
+        return _sim
+
+    def search_face(self, face_features_normalization, face_dict):
+        """
+        寻找近似人脸(face_dict为一对一)
+        """
+
+        # --- get face ---
+        best_face_uuid, best_face_dist = None, None
+        for face_uuid, face_features in face_dict.items():
+
+            dist = self.compare_faces_by_normalization(face_features_normalization, face_features)
+
+            # --- check --- 高相似度,直接返回 (85%以上基本就判定为同一个人了)
+            # if dist > 0.85:
+            #     methods.debug_log('FaceRecognitionEngine', f"m-162: best dist {dist} | {type(dist)}")
+            #     return face_uuid, dist
+
+            # --- check --- 低相似度,直接过滤 (一般低于71%就不是一个人了)
+            if dist > 0.71 and not best_face_dist:
+                best_face_dist = dist
+                best_face_uuid = face_uuid
+
+            if best_face_dist and dist > best_face_dist:
+                best_face_dist = dist
+                best_face_uuid = face_uuid
+
+        # methods.debug_log('FaceRecognitionEngine', f"m-178: best dist {best_face_dist}, face uuid is{best_face_uuid}")
+        return best_face_uuid, best_face_dist
+
+    # def search_face_v2(self, face_features_normalization, face_dict, filter_dist=0.745):
+    # def search_face_v2(self, face_features_normalization, face_dict, filter_dist=0.7):
+    def search_face_v2(self, face_features_normalization, face_dict, filter_dist=0.72):
+        """
+        寻找近似人脸(face_dict为一对多)
+        filter_dist: 相似度判定值
+        """
+
+        # --- get face ---
+        best_face_uuid, best_face_dist, best_face_image_path = None, 0.0, None
+        for face_uuid, info_list in face_dict.items():
+
+            for info in info_list:
+
+                face_features, image_path = info
+                dist = self.compare_faces_by_normalization(face_features_normalization, face_features)
+
+                # --- check --- 高相似度,直接返回 (85%以上基本就判定为同一个人了)
+                # if dist > 0.85:
+                #     methods.debug_log('FaceRecognitionEngine', f"m-162: best dist {dist} | {type(dist)}")
+                #     return face_uuid, dist
+
+                # --- check --- 低相似度,直接过滤 (一般低于72%就不是一个人了)
+                if dist > filter_dist and not best_face_dist:
+                    best_face_dist = dist
+                    best_face_uuid = face_uuid
+                    best_face_image_path = image_path
+
+                # --- update ---
+                if best_face_dist and dist > best_face_dist:
+                    best_face_dist = dist
+                    best_face_uuid = face_uuid
+                    best_face_image_path = image_path
+
+        # methods.debug_log('FaceRecognitionEngine', f"m-206: best dist {best_face_dist}, face uuid is{best_face_uuid}")
+        return best_face_uuid, best_face_dist, best_face_image_path
+
+    def search_face_top3(self, face_features_normalization, face_dict):
+        """
+        寻找近似人脸TOP3
+        """
+
+        # --- define ---
+        d1 = list()  # [{rate: <rate>, uuid: <uuid>}]
+
+        # --- get face ---
+        for face_uuid, face_features in face_dict.items():
+            rate = self.compare_faces_by_normalization(face_features_normalization, face_features)
+            d1.append({'rate': rate, 'uuid': face_uuid})
+            d1[rate] = face_uuid
+
+        # --- check ---
+        d2 = sorted(d1, key=lambda d: d['rate'], reverse=True)[:3]
+        for _ in range(3 - len(d2)):
+            d2.append({'rate': None, 'uuid': None})
+        return d2[0], d2[1], d2[2]
+
+    @staticmethod
+    def clip_image(image_array, left, top, width, height):
+        """剪裁图像"""
+
+        # --- debug ---
+        # methods.debug_log('FaceRecognitionEngine', f"m-185: size: {image_array.shape}")
+        # methods.debug_log('FaceRecognitionEngine',
+        #                   f"m-185: left: {left}, top: {top}, width: {width}, height: {height}")
+
+        # --- 根据deepstream的左上点坐标,进行剪裁图像 ---
+        return image_array[int(top):int(top + height), int(left):int(left + width)]
+
+        # --- 根据deepstream的左上点坐标,计算出中心点,然后剪裁112尺寸的图像 --- todo 存在误识别问题
+        # half = 112/2
+        # return image_array[int(top + height/2 - half): int(top + height/2 + half),
+        #                    int(left + width/2 - half): int(left + width/2 + half)]
+
+    @staticmethod
+    def image_hex_to_image_array(hex_str_image, mode='RGB'):
+        """
+        数据格式转换
+        """
+        try:
+            bytes_image = binascii.unhexlify(hex_str_image)
+            _image = numpy_method.bytes_to_array_v2(bytes_image)
+            _image = cv2.imdecode(_image, cv2.IMREAD_COLOR)
+            return _image
+        except Exception as exception:
+            methods.debug_log('FaceDetectionEngine', f"m-138: exception | {exception}")
+            methods.debug_log('FaceDetectionEngine', f"m-138: traceback | {methods.trace_log()}")
+            return None
+
+
+if __name__ == '__main__':
+    # --- init ---
+    agent = FaceRecognitionEngine()
+    agent.prepare()
+
+    # --- test ---
+    # p0 = cv2.imread('./face.jpg')
+    # f0 = agent.get_face_features_by_image_array(p0)
+    # p3 = cv2.imread('./worker.jpg')
+    # p3 = cv2.resize(p3, (112, 112))
+    # f3 = agent.get_face_features_by_image_array(p3)
+    # sim = agent.compare_faces(f0, f3)
+    # print(f"Similarity: {sim}")
+
+    # --- test ---
+    import requests
+
+    url = 'https://lwres.yzw.cn/worker-avatar/Original/2020/1013/96c419ca-dbf2-4bf7-a072-92fde861a2bc.jpg'
+    response = requests.get(url, headers={'content-type': 'application/json'})
+    _image_bytes = response.content
+    f0 = agent.get_face_features_normalization_by_image_bytes(_image_bytes)
+    print(f"f0: {type(f0)}")
+
+    # p1 = cv2.imread('./face.jpg')
+    # f1 = agent.get_face_features_normalization_by_image_array(p1)
+    # sim = agent.compare_faces_by_normalization(f0, f1)
+    # print(f"Similarity: {sim}")

+ 10 - 0
3rdparty/xlib/__init__.py

@@ -0,0 +1,10 @@
+from xlib.xbase64 import *
+from xlib.xfile import *
+from xlib.xipv4 import *
+from xlib.xlist import *
+from xlib.xlog import *
+from xlib.xpickle import *
+from xlib.xsubprocess import *
+from xlib.xthread import *
+from xlib.xtime import *
+from xlib.xuuid import *

+ 51 - 0
3rdparty/xlib/xbase64.py

@@ -0,0 +1,51 @@
+# update: 2021-6-30-14
+import base64
+import hashlib
+
+
+def str_to_b64(string):
+    """b64加密"""
+    try:
+        return str(base64.b64encode(str(string).encode('utf-8')), 'utf-8')
+    except Exception as exception:
+        print(f"exception: {exception.__class__.__name__}")
+        return str()
+
+
+def b64_to_str(string):
+    """b64加密"""
+    try:
+        return str(base64.b64decode(str(string).encode('utf-8')), 'utf-8')
+    except Exception as exception:
+        print(f"exception: {exception.__class__.__name__}")
+        return str()
+
+
+def text_to_byte(text, mode='utf-8'):
+    return text.encode(mode)
+
+
+def byte_to_text(byte, mode='utf-8'):
+    return byte.decode(mode)
+
+
+def text_to_b64(text):
+    """b64编码"""
+    return str(base64.b64encode(str(text).encode('utf-8')), 'utf-8')
+
+
+def b64_to_text(text):
+    """b64解码"""
+    return str(base64.b64decode(str(text).encode('utf-8')), 'utf-8')
+
+
+def byte_to_b64(byte):
+    """b64加密"""
+    return base64.b64encode(byte)
+
+
+def byte_to_md5(byte):
+    """计算md5"""
+    m = hashlib.md5()
+    m.update(byte)
+    return m.hexdigest()

+ 248 - 0
3rdparty/xlib/xfile.py

@@ -0,0 +1,248 @@
+# update: 2024-3-31-10
+"""
+mode:
+    # r   只读,默认打开方式,当文件不存在时会报错
+    # w   只写,当文件不存在时会自动创建文件,文件内容只能是字符串,只能写入字符串
+    # r+  可读可写,当文件不存在时会报错
+    # w+  可读可写。当文件不存在时会新建
+    # a   追加文件,不可读
+    # a+  追加文件,可读可写
+    # rb  以二进制读模式打开,只可读
+    # rb+ 以二进制写读写模式打开,可读可写,当文件不存在时报错
+    # wb  以位进制写模式打开,只可写
+    # wb+ 以二进制读写模式打开,可读可写。当文件不存在时新建
+    # ab  以二进制追加模式打开,追加文件,不可读
+    # ab+ 以二进制读写模式打开,追加文件。可读可写
+"""
+import hashlib
+import base64
+import pickle
+import sys
+import os
+
+
+def read_bytes(file_path):
+    with open(file_path, 'rb') as f:
+        return f.read()
+
+
+def read_text(file_path):
+    with open(file_path, 'r') as f:
+        return f.read()
+
+
+def write_bytes(path, data=b''):
+    with open(path, 'wb') as f:
+        f.write(data)
+
+
+def write_text(path, data='', mode='w'):
+    with open(path, mode) as f:
+        f.write(data)
+
+
+def write_file(path, data=None, mode='wb'):
+    with open(path, mode) as f:
+        f.write(data)
+
+
+def load_pickle_file(file_path):
+    with open(file_path, 'rb+') as f:
+        return pickle.load(f)
+
+
+def save_pickle_file(file_path, data):
+    with open(file_path, 'wb') as f:
+        f.write(pickle.dumps(data))
+
+
+def get_file_md5(file_path):
+    """获取文件md5"""
+    m = hashlib.md5()
+    with open(file_path, 'rb') as f:
+        m.update(f.read())
+    return m.hexdigest()
+
+
+def get_big_file_md5(file_path, block_size=8 * 1024):
+    """获取文件md5(默认使用8KB作为分块大小)"""
+    m = hashlib.md5()
+    with open(file_path, 'rb') as f:
+        while True:
+            block = f.read(block_size)
+            if not block:
+                break
+            m.update(block)
+    return m.hexdigest()
+
+
+def _file_iterator(file_object, block_size=8 * 1024):
+    with file_object:
+        block = file_object.read(block_size)
+        while len(block) > 0:
+            yield block
+            block = file_object.read(block_size)
+
+
+def get_big_file_md5_v2(file_path):
+    """获取文件md5(默认使用8KB作为分块大小)"""
+    file_object = open(file_path, 'rb')
+    blocks = _file_iterator(file_object)
+    m = hashlib.md5()
+    for block in blocks:
+        m.update(block)
+    return m.hexdigest()
+
+
+def get_file_b64_md5(file_path):
+    """获取文件的b64的md5"""
+    m = hashlib.md5()
+    with open(file_path, 'rb') as f:
+        block = f.read()
+        encoded = base64.b64encode(block)
+        m.update(encoded)
+    return m.hexdigest()
+
+
+def get_big_file_b64_md5(file_path, block_size=3 * 1024 * 1024):
+    """流式获取文件的b64的md5(默认使用3MB作为分块大小)"""
+    with open(file_path, 'rb') as f1, open(f'{file_path}.b64', 'wb') as f2:
+        while True:
+            block = f1.read(block_size)
+            if not block:
+                break
+            b64_data = base64.b64encode(block)
+            f2.write(b64_data)
+    return get_big_file_md5(f'{file_path}.b64')
+
+
+def get_var_size(object, unit='MB'):
+    """
+    unit: GB/MB/KB/B
+    """
+    unit_dict = {
+        'GB': 3,
+        'MB': 2,
+        'KB': 1,
+        'B': 0,
+    }
+    byte = sys.getsizeof(object)
+    size = byte / (1024 ** unit_dict.get(unit))
+    return float(round(size, 1))
+
+
+def get_file_size(file_path, unit='MB'):
+    """
+    unit: GB/MB/KB/B
+    """
+    if not is_file(file_path):
+        return None
+    unit_dict = {
+        'GB': 3,
+        'MB': 2,
+        'KB': 1,
+        'B': 0,
+    }
+    byte = os.path.getsize(file_path)
+    size = byte / (1024 ** unit_dict.get(unit))
+    return float(round(size, 1))
+
+
+def get_file_path_list(dir_path='/root', path_list=None):
+    """
+    获取指定目录下全部文件
+    Example:
+        get_file_path_list('/opt')
+        ['/opt/1.txt', '/opt/2.txt']
+
+    # import glob
+    # if os.path.isfile(input_dir):
+    #     img_list = [input_dir]
+    # else:
+    #     img_list = sorted(glob.glob(os.path.join(input_dir, '*')))
+    """
+    if not path_list:
+        path_list = []
+    for path, folders, files in os.walk(dir_path):
+
+        for file_name in files:
+            file_path = os.path.join(path, file_name)
+            if file_path in path_list:
+                continue
+            # if file_path.split('.')[-1] == 'pdb':
+            #     remove_file(file_path)
+            #     print(f"#file_path: {file_path}")
+            path_list.append(file_path)
+
+        for folder_name in folders:
+            get_file_path_list(os.path.join(path, folder_name), path_list)
+
+    return path_list
+
+
+def mkdir(dir_path):
+    """
+    创建文件目录
+    Example:
+        mkdir('/share/abc/xyz/1.txt')
+        True
+    """
+    if not dir_path:
+        return False
+
+    if dir_path[0] != '/':
+        dir_path = f"{get_pwd()}/{dir_path}"
+
+    path = '/'
+    for part in dir_path.split('/'):
+        path += f"{part}/"
+        if not os.path.isdir(path):
+            os.mkdir(path)
+    return True
+
+
+def get_pwd():
+    """
+    获取当前路径
+    """
+    path = sys.path[0]
+    if not os.path.isdir(path):
+        path = os.path.dirname(path)
+    return path
+
+
+def is_file(file_path):
+    """判断文件"""
+    return os.path.isfile(file_path)
+
+
+def is_dir(file_path):
+    """判断目录"""
+    return os.path.isdir(file_path)
+
+
+def remove_file(file_path):
+    """删除文件"""
+    return os.remove(file_path)
+
+
+def move_file(s_path, d_path):
+    """移动文件"""
+    return os.rename(s_path, d_path)
+
+
+if __name__ == '__main__':
+    """
+    """
+    # --- test ---
+    # file_dir = r'E:\casper\repositories\repositories\SRI-DYZBC.Cockpit-cpp'
+    # file_dir = r'E:\casper\repositories\repositories\SRI-DYZBC.Cockpit-cpp\EgoQt'
+    # file_dir = r'E:\casper\repositories\repositories\SRI-DYZBC.Cockpit-cpp\EgoQt\thirdparty'
+    # file_dir = r'E:\casper\repositories\repositories\SRI-DYZBC.Cockpit-cpp\EgoServer\webrtcinterop\x64\Release'
+    # file_dir = r'E:\casper\repositories\repositories\SRI-DYZBC.Cockpit-cpp\EgoQt\webrtcinterop\x64\Release'
+    # file_dir = r'E:\casper\repositories\repositories\SRI-DYZBC.Cockpit-cpp\EgoServer'
+    file_dir = r'E:\casper\repositories\repositories\SRI-DYZBC.Cockpit-cpp\EgoQt'
+    # file_dir = r'E:\casper\repositories\repositories\SRI-DYZBC.Cockpit-cpp\EgoServer'
+    path_list = get_file_path_list(file_dir)
+    print(path_list)
+    # remove_file(r'E:\casper\repositories\repositories\SRI-DYZBC.Cockpit-cpp\EgoQt\webrtcinterop\x64\Release\webrtcinterop.obj')

+ 26 - 0
3rdparty/xlib/xipv4.py

@@ -0,0 +1,26 @@
+# update: 2021-6-21-16
+
+
+def int_to_ip(integer):
+    """
+    整型转ip
+    """
+    raw = bin(int(integer)).lstrip('0b').zfill(32)
+    return '%d.%d.%d.%d' % (int(raw[0:8], 2), int(raw[8:16], 2), int(raw[16:24], 2), int(raw[24:32], 2))
+
+
+def ip_to_int(ip):
+    """
+    ip转整型
+    """
+    if not ip:
+        return 0
+    ip = str(ip)
+    raw = ip.split('.')
+    if len(raw) != 4:
+        return 0
+    binnum = bin(int(raw[0])).lstrip('0b').zfill(8)
+    binnum += bin(int(raw[1])).lstrip('0b').zfill(8)
+    binnum += bin(int(raw[2])).lstrip('0b').zfill(8)
+    binnum += bin(int(raw[3])).lstrip('0b').zfill(8)
+    return int(binnum, 2)

+ 28 - 0
3rdparty/xlib/xlist.py

@@ -0,0 +1,28 @@
+# update: 2022-6-17
+
+
+def get_last(data_list, amount):
+    """获取尾部元素"""
+    return data_list[-amount:]
+
+
+def cut_last(data_list, amount):
+    """去掉尾部元素"""
+    return data_list[:-amount]
+
+
+def get_head(data_list, amount):
+    """获取头部元素"""
+    return data_list[:amount]
+
+
+def cut_head(data_list, amount):
+    """去掉头部元素"""
+    return data_list[amount:]
+
+
+def reverse(string_or_list):
+    """倒序"""
+    if type(string_or_list) not in [str, list]:
+        return ''
+    return string_or_list[::-1]

+ 26 - 0
3rdparty/xlib/xlog.py

@@ -0,0 +1,26 @@
+# update: 2022-4-19
+import logging
+import traceback
+
+LOG = logging.getLogger(__name__)
+# logging.basicConfig(format='%(levelname)s | %(asctime)s | %(module)s.%(funcName)s:%(lineno)s >>> %(message)s',
+#                     level=logging.DEBUG)
+logging.basicConfig(format=f"INFO:     %(message)s", level=logging.INFO)
+
+
+def debug_log(tags, args, is_work=True, show_level=logging.INFO):
+    """"""
+    if not is_work:
+        return
+    elif type(args) == list:
+        lines = f"{tags}:"
+        for count, line in enumerate(args):
+            lines += f"\n- {count + 1} - {line}"
+        LOG.info(lines)
+    elif type(args) == str:
+        LOG.info(f"{tags} | {args}")
+
+
+def trace_log():
+    """"""
+    return traceback.format_exc()

+ 93 - 0
3rdparty/xlib/xpickle.py

@@ -0,0 +1,93 @@
+# update: 2021-6-30-11
+import pickle
+import json
+
+
+def pickle_dumps(obj):
+    """压缩数据"""
+    return pickle.dumps(obj)
+
+
+def pickle_loads(obj):
+    """解压数据"""
+    return pickle.loads(obj)
+
+
+def json_dumps(obj):
+    """压缩数据"""
+    return json.dumps(obj)
+
+
+def json_loads(obj):
+    """解压数据"""
+    return json.loads(obj)
+
+
+def is_json(string):
+    """是否json"""
+    try:
+        if string:
+            json.loads(string)
+        else:
+            return False
+    except TypeError:
+        return False
+    return True
+
+
+def str_to_re(string):
+    """
+    转义正则特殊符号
+    """
+    string = string.replace('$', r'\$')
+    string = string.replace('(', r'\(')
+    string = string.replace(')', r'\)')
+    string = string.replace('*', r'\*')
+    string = string.replace('.', r'\.')
+    string = string.replace('[', r'\[')
+    string = string.replace(']', r'\]')
+    string = string.replace('?', r'\?')
+    string = string.replace('\\', '\\\\')
+    string = string.replace('^', r'\^')
+    string = string.replace('{', r'\{')
+    string = string.replace('}', r'\}')
+    string = string.replace('|', r'\|')
+    return string
+
+
+def str_to_json(string):
+    """
+    eval转换
+    """
+    null = None
+    true = True
+    false = False
+    return eval(string)
+
+
+def json_to_str(input_data):
+    """
+    eval转换
+    """
+    if type(input_data) == dict:
+        for k, v in input_data.items():
+            if type(v) != str:
+                continue
+            input_data[k] = v.replace('\'', '')
+    data = str(input_data).replace('\'', '\"')
+    data = str(data).replace('None', 'null')
+    data = str(data).replace('True', 'true')
+    data = str(data).replace('False', 'false')
+    return data
+
+
+if __name__ == '__main__':
+    # --- test ---
+    # a = {111: 222}
+    # print(json_dumps(a))
+    # print(json_loads(json_dumps(a)))
+
+    # --- test ---
+    a = b'\x80\x03N.'
+    o = pickle_loads(a)
+    print(o, type(o))

+ 21 - 0
3rdparty/xlib/xsubprocess.py

@@ -0,0 +1,21 @@
+# update: 2022-4-25-18
+import subprocess
+
+
+def run_command(command, callback=False):
+    """
+    执行shell命令
+    """
+    if callback:
+        obj = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE)
+        lines = obj.stdout.readlines()
+        if len(lines) == 1:
+            lines = str(lines[0], encoding='utf-8').strip('\n')
+        return lines
+    else:
+        return subprocess.Popen(command, shell=True)
+
+
+if __name__ == '__main__':
+    out = run_command('/home/server/resources/vms-files', callback=True)
+    print(out)

+ 44 - 0
3rdparty/xlib/xthread.py

@@ -0,0 +1,44 @@
+from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor
+import time
+
+
+class Executor(object):
+
+    def __init__(self, callback=False):
+        self.pool = ThreadPoolExecutor(max_workers=300)
+        # self.pool = ProcessPoolExecutor(4)
+        self.tasks = []
+        self.callback = callback
+
+    def run(self, method, *args):
+        """增加任务"""
+        task = self.pool.submit(method, *args)
+        if self.callback:
+            self.tasks.append(task)
+        while self.callback:
+            results = []
+            for task in self.tasks:
+                results.append(task.done())
+            if len(set(results)) == 1 and results[0] == True:
+                break
+
+    def close(self):
+        """关闭线程池"""
+        self.pool.shutdown()
+
+
+def f1():
+    print(time.time() - s)
+    a = sum([i for i in range(9999999)])
+
+
+if __name__ == '__main__':
+
+    s = time.time()
+    # --- 5.139862537384033 ---
+    e = Executor()
+    for i in range(5):
+        e.run(f1)
+    e.close()
+
+    print(time.time() - s)

+ 169 - 0
3rdparty/xlib/xtime.py

@@ -0,0 +1,169 @@
+# update: 2021-10-21
+"""
+%a 星期的简写。如 星期三为Web
+%A 星期的全写。如 星期三为Wednesday
+%b 月份的简写。如4月份为Apr
+%B月份的全写。如4月份为April
+%c: 日期时间的字符串表示。(如: 04/07/10 10:43:39)
+%d: 日在这个月中的天数(是这个月的第几天)
+%f: 微秒(范围[0,999999])
+%H: 小时(24小时制,[0, 23])
+%I: 小时(12小时制,[0, 11])
+%j: 日在年中的天数 [001,366](是当年的第几天)
+%m: 月份([01,12])
+%M: 分钟([00,59])
+%p: AM或者PM
+%S: 秒(范围为[00,61],为什么不是[00, 59],参考python手册~_~)
+%U: 周在当年的周数当年的第几周),星期天作为周的第一天
+%w: 今天在这周的天数,范围为[0, 6],6表示星期天
+%W: 周在当年的周数(是当年的第几周),星期一作为周的第一天
+%x: 日期字符串(如:04/07/10)
+%X: 时间字符串(如:10:43:39)
+%y: 2个数字表示的年份
+%Y: 4个数字表示的年份
+%z: 与utc时间的间隔 (如果是本地时间,返回空字符串)
+%Z: 时区名称(如果是本地时间,返回空字符串)
+"""
+import datetime
+import time
+
+UTC_PATTERN = '%Y-%m-%dT%H:%M:%S.%fZ'
+LOCAL_PATTERN = '%Y-%m-%d %H:%M:%S'
+
+
+def string_to_dt(string, pattern='%Y-%m-%d'):
+    """
+    字符串转为日期
+    """
+    return datetime.datetime.strptime(string, pattern)
+
+
+def dt_to_string(date, pattern='%Y-%m-%d %H:%M:%S'):
+    """
+    日期转为字符串
+    """
+    return date.strftime(pattern)
+
+
+def string_to_ts(string, pattern='%Y-%m-%dT%H:%M:%S.%f'):
+    """
+    日期转为时间戳
+    Example:
+        string_to_ts(2015-01-01)
+        1420041600
+    """
+    return int(time.mktime(time.strptime(string, pattern)))
+
+
+def ts_to_string(int_time, pattern='%Y-%m-%dT%H:%M:%S.%f'):
+    """
+    时间戳->字符串
+    """
+    return time.strftime(pattern, time.localtime(int_time))
+
+
+def now_string(pattern='%Y-%m-%d %H:%M:%S'):
+    """
+    获取当前时间戳
+    """
+    return datetime.datetime.now().strftime(pattern)
+
+
+def iso_string_to_ts(string):
+    """
+    iso标准时间转时间戳
+    """
+    return time.mktime(time.strptime(string, '%Y-%m-%dT%H:%M:%S.%f'))
+
+
+def now_iso_string():
+    """
+    iso标准时间
+    """
+    return datetime.datetime.now().isoformat('T')
+
+
+def now_utc_iso_string():
+    """
+    iso标准时间
+    """
+    return datetime.datetime.utcnow().isoformat('T')
+
+
+def now_utc_dt():
+    """
+    获取当前utc时间
+    """
+    return datetime.datetime.utcnow()
+
+
+def now_dt():
+    """
+    获取当前时间
+    Example:
+        now_dt()
+        datetime.datetime(2020, 5, 16, 6, 15, 7, 39060)
+    """
+    return datetime.datetime.now()
+
+
+def now_ts(unit='s', ndigits=0):
+    """
+    获取当前时间戳
+    unit: 单位 (s: 秒 ms: 毫秒)
+    ndigits: 小数点位数
+    """
+    unit_dict = {
+        'ms': 1,
+        's': 0,
+    }
+    ts = time.time()
+    if unit_dict.get(unit):
+        ts = ts * (1000 ** unit_dict.get(unit))
+    if ndigits:
+        return round(ts, ndigits)
+    return int(ts)
+
+
+def today_ts():
+    """
+    获取当日时间戳
+    """
+    today_dt = datetime.date.today()
+    return int(time.mktime(today_dt.timetuple()))
+
+
+def utc_to_beijing(utc_string, pattern='%Y-%m-%dT%H:%M:%S.%fZ'):
+    """UTC时间转北京时间(+8:00)"""
+    utc_ts = string_to_ts(utc_string, pattern=pattern)
+    beijing_ts = utc_ts + (3600 * 8)
+    return ts_to_string(beijing_ts, pattern='%Y-%m-%d %H:%M:%S')
+
+
+def beijing_to_utc(beijing_string, pattern='%Y-%m-%d %H:%M:%S'):
+    """本地时间转UTC时间(-8:00)"""
+    beijing_ts = string_to_ts(beijing_string, pattern=pattern)
+    utc_ts = beijing_ts - (3600 * 8)
+    return ts_to_string(utc_ts, pattern='%Y-%m-%dT%H:%M:%S.%fZ')
+
+
+if __name__ == '__main__':
+    # t = '2020-08-02T01:00:00.000Z'
+    # print(utc_to_beijing(t))
+
+    # t = "2020-08-02T16:00:00.000Z"
+    # d = string_to_dt(t, "%Y-%m-%dT%H:%M:%S.%fZ")
+    # print(d)
+
+    # print(datetime.datetime.now() + datetime.timedelta(minutes=-1)).strftime("%Y-%m-%d %H:%M:%S")
+    # print(today_ts())
+    # print(string_to_ts('2021-03-25-09-53-39', '%Y-%m-%d-%H-%M-%S'))
+
+    # print(now_ts(unit='ms'))
+    # print(now_ts(unit='s'))
+    print(now_ts())
+
+    # out = string_to_ts('2021-07-16', '%Y-%m-%d')
+    # print(out)
+
+    # print(string_to_ts('2022-06-01 22:00:00', pattern='%Y-%m-%d %H:%M:%S'))  # 1654092000

+ 16 - 0
3rdparty/xlib/xuuid.py

@@ -0,0 +1,16 @@
+# update: 2021-6-28-19
+import uuid
+
+
+def is_uuid4(string):
+    """验证uuid4"""
+    try:
+        uuid.UUID(string, version=4)
+        return True
+    except ValueError:
+        return False
+
+
+def new_uuid4():
+    """生成uuid4"""
+    return str(uuid.uuid4())

+ 406 - 0
3rdparty/xpip/aes_by_crypto.py

@@ -0,0 +1,406 @@
+# update: 2021-5-12-21
+from Crypto.Cipher import AES
+import base64
+import hashlib
+import zipfile
+import pyminizip
+import pyzipper
+import os
+
+
+class _AES(object):
+    def __init__(self, key='7486E0264E999881D4EF7BEEDF05A9F7', model='ECB', iv='',
+                 code_type='utf-8'):
+        """
+        code_type: utf-8/gbk
+        """
+        self.code_type = code_type
+        self.model = {'ECB': AES.MODE_ECB, 'CBC': AES.MODE_CBC}[model]
+        self.key = self.replenish(key)
+
+        # --- create aes object ---
+        if model == 'ECB':
+            self.aes = AES.new(self.key, self.model)
+        elif model == 'CBC':
+            self.aes = AES.new(self.key, self.model, iv)
+
+    def replenish(self, block, block_size=16):
+        """block_size: AES key must be either 16, 24, or 32 bytes long"""
+        block = block.encode(self.code_type)
+        while len(block) % block_size != 0:
+            block += b'\x00'
+        return block
+
+    def encrypt(self, text):
+        text = self.replenish(text)
+        encrypt_text = self.aes.encrypt(text)
+        return base64.encodebytes(encrypt_text).decode().strip()
+
+    def decrypt(self, text):
+        text = base64.decodebytes(text.encode(self.code_type))
+        decrypt_text = self.aes.decrypt(text)
+        return decrypt_text.decode(self.code_type).strip('\0')
+
+
+def text_to_b64(string):
+    """b64编码"""
+    return str(base64.b64encode(str(string).encode('utf-8')), 'utf-8')
+
+
+def b64_to_text(string):
+    """b64解码"""
+    return str(base64.b64decode(str(string).encode('utf-8')), 'utf-8')
+
+
+def text_to_aes(text, key='YourPassword'):
+    """aes加密"""
+    aes = _AES(key=key)
+    return text_to_b64(aes.encrypt(text))
+
+
+def aes_to_text(text, key='YourPassword'):
+    """aes解密"""
+    aes = _AES(key=key)
+    return aes.decrypt(b64_to_text(text))
+
+
+def get_big_file_md5(file_path, block_size=8 * 1024):
+    """获取文件md5(默认使用8KB作为分块大小)"""
+    m = hashlib.md5()
+    with open(file_path, 'rb') as f:
+        while True:
+            block = f.read(block_size)
+            if not block:
+                break
+            m.update(block)
+    return m.hexdigest()
+
+
+def file_to_zip(file_path):
+    """生成zip压缩文件"""
+
+    # --- encrypt file name --- todo 如果aes后超过255的长度就不做aes了
+    file_name = file_path.split('/')[-1]
+    save_name = text_to_b64(file_name)
+
+    # --- define zip name ---
+    file_md5 = get_big_file_md5(file_path)
+    zip_name = f"{file_md5}.zip"
+    dir_path = '/'.join(file_path.split('/')[:-1])
+    zip_path = f"{dir_path}/{zip_name}"
+
+    # --- writing ---
+    with zipfile.ZipFile(zip_path, 'w', compression=zipfile.ZIP_DEFLATED, allowZip64=True) as f1:
+        f1.write(file_path, arcname=save_name)
+
+
+def zip_to_file():
+    pass
+
+
+def file_to_zip_v2(file_path, key='<YourPassword@2021>', compress_level=5):
+    """
+    文件转zip
+    compress_level(int) between 1 to 9, 1 (more fast) <---> 9 (more compress) or 0 (default)
+    """
+    # --- check parameter ---
+    if not os.path.isfile(file_path):
+        return dict(code=1, details='parameter error!')
+
+    # --- encrypt file name ---
+    file_name = file_path.split('/')[-1]
+    dir_path = '/'.join(file_path.split('/')[:-1])
+    save_name = text_to_aes(file_name, key=key)
+
+    # --- check again ---
+    is_encrypted = len(file_name) == 37 and file_name[32] == '.'
+    if is_encrypted:
+        return dict(code=2, details='parameter error!')
+
+    # --- check system support ---
+    if len(save_name) > 250:
+        return dict(code=3, details='parameter error!')
+
+    # --- rename file ---
+    save_path = f"{dir_path}/{save_name}"
+    os.rename(file_path, save_path)
+
+    # --- define zip name ---
+    file_md5 = get_big_file_md5(save_path)
+    zip_path = f"{dir_path}/{file_md5}.{save_name[:4]}"
+
+    try:
+        # --- writing ---
+        """
+        Args:
+            1. src file path (string)
+            2. src file prefix path (string) or None (path to prepend to file)
+            3. dst file path (string)
+            4. password (string) or None (to create no-password zip)
+            5. compress_level(int) between 1 to 9, 1 (more fast) <---> 9 (more compress) or 0 (default)
+        """
+        pyminizip.compress(save_path, None, zip_path, key, compress_level)
+
+        # --- remove file ---
+        os.remove(save_path)
+        return dict(code=0, details='ended.')
+
+    except Exception as exception:
+
+        # --- revert ---
+        os.rename(save_path, file_path)
+
+        import traceback
+        print(traceback.format_exc())
+        return dict(code=-1, details=f"{traceback.format_exc()}")
+
+
+def zip_to_file_v2(file_path, key='<YourPassword@2021>', no_path=True):
+    """zip转file"""
+
+    # --- check parameter ---
+    if not os.path.isfile(file_path):
+        return dict(code=1, details='parameter error!')
+
+    # --- check again ---
+    file_name = file_path.split('/')[-1]
+    is_encrypted = len(file_name) == 37 and file_name[32] == '.'
+    if not is_encrypted:
+        return dict(code=2, details='parameter error!')
+
+    # --- record ---
+    dir_path = '/'.join(file_path.split('/')[:-1])
+    names = os.listdir(dir_path)
+    before_files = set(f"{dir_path}/{name}" for name in names if not os.path.isdir(f"{dir_path}/{name}"))
+
+    try:
+        # --- writing ---
+        """
+        Args:
+            1. src file path (string)
+            2. password (string) or None (to unzip encrypted archives)
+            3. dir path to extract files or None (to extract in a specific dir or cwd)
+            4. withoutpath (exclude path of extracted)
+        """
+        pyminizip.uncompress(file_path, key, dir_path, no_path)
+
+        # --- record ---
+        names = os.listdir(dir_path)
+        after_files = set(f"{dir_path}/{name}" for name in names if not os.path.isdir(f"{dir_path}/{name}"))
+
+        # --- rename ---
+        for path in list(after_files - before_files):
+            name = path.split('/')[-1]
+            raw_name = aes_to_text(name, key=key)
+            os.rename(path, f"{dir_path}/{raw_name}")
+
+        # --- remove file ---
+        os.remove(file_path)
+        return dict(code=0, details='ended.')
+
+    except Exception as exception:
+
+        # --- revert ---
+        names = os.listdir(dir_path)
+        after_files = set(f"{dir_path}/{name}" for name in names if not os.path.isdir(f"{dir_path}/{name}"))
+        for path in list(after_files - before_files):
+            os.remove(path)
+
+        import traceback
+        print(traceback.format_exc())
+        return dict(code=-1, details=f"{traceback.format_exc()}")
+
+
+def file_to_zip_v2_1(file_path, key='<YourPassword@2021>', compress_level=1):
+    """file转zip(双文件保存版,其中一个文件保存加密文件名)"""
+
+    # --- check parameter ---
+    if not os.path.isfile(file_path):
+        return dict(code=1, details='parameter error!')
+
+    # --- check again ---
+    file_name = file_path.split('/')[-1]
+    is_encrypted = len(file_name) == 37 and file_name[32] == '.'
+    if is_encrypted:
+        return dict(code=2, details='parameter error!')
+
+    # --- create name file ---
+    dir_path = '/'.join(file_path.split('/')[:-1])
+    file_name_aes = text_to_aes(file_name, key=key)
+    name_file_path = f"{dir_path}/{file_name_aes[:4]}"
+    with open(name_file_path, 'w') as f1:
+        f1.write(file_name_aes)
+
+    # --- rename file ---
+    file_md5 = get_big_file_md5(file_path)
+    data_file_path = f"{dir_path}/{file_md5}"
+    os.rename(file_path, data_file_path)
+
+    # --- define zip name ---
+    zip_path = f"{dir_path}/{file_md5}.{file_name_aes[:4]}"
+
+    try:
+        # --- writing ---
+        # pyminizip.compress(save_path, None, zip_path, key, compress_level)
+        """
+        Args:
+            1. src file LIST path (list)
+            2. src file LIST prefix path (list) or []
+            3. dst file path (string)
+            4. password (string) or None (to create no-password zip)
+            5. compress_level(int) between 1 to 9, 1 (more fast) <---> 9 (more compress)
+            6. optional function to be called during processing which takes one argument, the count of how many files have been compressed
+        """
+        pyminizip.compress_multiple([data_file_path, name_file_path], ['', ''], zip_path, key, compress_level)
+
+        # --- remove file ---
+        os.remove(data_file_path)
+        os.remove(name_file_path)
+        return dict(code=0, details='ended.')
+
+    except Exception as exception:
+
+        # --- revert ---
+        os.remove(name_file_path)
+        os.rename(data_file_path, file_path)
+
+        import traceback
+        print(traceback.format_exc())
+        return dict(code=-1, details=f"{traceback.format_exc()}")
+
+
+def zip_to_file_v2_1(file_path, key='<YourPassword>', no_path=True):
+    """zip转file(双文件保存版,其中一个文件保存加密文件名)"""
+
+    # --- check parameter ---
+    if not os.path.isfile(file_path):
+        return dict(code=1, details='parameter error!')
+
+    # --- check again ---
+    file_name = file_path.split('/')[-1]
+    is_encrypted = len(file_name) == 37 and file_name[32] == '.'
+    if not is_encrypted:
+        return dict(code=2, details='parameter error!')
+
+    # --- record ---
+    dir_path = '/'.join(file_path.split('/')[:-1])
+    names = os.listdir(dir_path)
+    before_files = set(f"{dir_path}/{name}" for name in names if not os.path.isdir(f"{dir_path}/{name}"))
+
+    try:
+        # --- writing ---
+        """
+        Args:
+            1. src file path (string)
+            2. password (string) or None (to unzip encrypted archives)
+            3. dir path to extract files or None (to extract in a specific dir or cwd)
+            4. withoutpath (exclude path of extracted)
+        """
+        pyminizip.uncompress(file_path, key, dir_path, no_path)
+
+        # --- record ---
+        names = os.listdir(dir_path)
+        after_files = set(f"{dir_path}/{name}" for name in names if not os.path.isdir(f"{dir_path}/{name}"))
+
+        # --- check ---
+        temp_file = list(after_files - before_files)
+        if len(temp_file) != 2:
+            raise Exception('something is wrong!')
+
+        # --- get file name ---
+        raw_name = str()
+        for path in temp_file:
+            name = path.split('/')[-1]
+            if len(name) == 4:
+                with open(path, 'r') as f1:
+                    raw_name = aes_to_text(f1.read(), key=key)
+                os.remove(path)
+
+        # --- rename ---
+        for path in list(after_files - before_files):
+            name = path.split('/')[-1]
+            if len(name) == 32:
+                os.rename(path, f"{dir_path}/{raw_name}")
+
+        # --- remove file ---
+        os.remove(file_path)
+        return dict(code=0, details='ended.')
+
+    except Exception as exception:
+
+        # --- revert ---
+        names = os.listdir(dir_path)
+        after_files = set(f"{dir_path}/{name}" for name in names if not os.path.isdir(f"{dir_path}/{name}"))
+        for path in list(after_files - before_files):
+            os.remove(path)
+
+        import traceback
+        print(traceback.format_exc())
+        return dict(code=-1, details=f"{traceback.format_exc()}")
+
+
+def file_to_zip_v3(file_path, key='YourPassword', aes_bits=128):
+    """
+    生成aes加密zip压缩文件
+    aes_bits: 128/192/256
+    """
+    # --- check parameter ---
+    if not os.path.isfile(file_path):
+        return dict(code=1, details='parameter error!')
+
+    # --- encrypt file name ---
+    file_name = file_path.split('/')[-1]
+    save_name = text_to_aes(file_name, key=key)
+
+    # --- check system support ---
+    if len(save_name) > 250:
+        return dict(code=2, details='parameter error!')
+
+    # --- define zip name ---
+    file_md5 = get_big_file_md5(file_path)
+    zip_name = f"{file_md5}.zip"
+    dir_path = '/'.join(file_path.split('/')[:-1])
+    zip_path = f"{dir_path}/{zip_name}"
+
+    # --- writing ---
+    with pyzipper.AESZipFile(zip_path, 'w', compression=pyzipper.ZIP_LZMA) as f1:
+        f1.setpassword(key.encode())
+        f1.setencryption(pyzipper.WZ_AES, nbits=aes_bits)
+        f1.write(file_path, arcname=save_name)
+    return dict(code=0, details='ended.')
+
+
+def zip_to_file_v3(file_path, key='YourPassword'):
+    """生成aes加密zip压缩文件"""
+
+    dir_path = '/'.join(file_path.split('/')[:-1])
+
+    # --- reading ---
+    with pyzipper.AESZipFile(file_path) as f1:
+        f1.setpassword(key.encode())
+        file_list = f1.namelist()
+        for file_name in file_list:
+            # --- decrypt file name ---
+            raw_name = aes_to_text(file_name, key=key)
+
+            # --- writing ---
+            with open(f"{dir_path}/{raw_name}", 'wb') as f2:
+                f2.write(f1.read(file_name))
+    return dict(code=0, details='ended.')
+
+
+def file_to_7z(file_path, key='YourPassword'):
+    pass
+
+
+def folder_to_zip(folder_path):
+    pass
+
+
+if __name__ == '__main__':
+    # text1 = '0/588564d4-3bca-4ebf-83d8-1155963fbfa9/3066753951/1593578486/1595174400'
+    text2 = 'eFVqYzZjZ3hneVZ0T09uVVlHTm1rUT09'
+    # text2 = text_to_aes(text1, '123456')
+    test3 = aes_to_text(text2, '123456')
+    # print('密文:', text2)
+    print('明文:', test3)

+ 65 - 0
3rdparty/xpip/camera_by_cv2.py

@@ -0,0 +1,65 @@
+# update: 2022-2-23
+"""
+image.shape: 图片尺寸 (height, width, number)
+"""
+import cv2 as cv
+import time
+
+
+def get_capture_once(capture_path):
+    """获取capture"""
+
+    # --- check ---
+    cap = cv.VideoCapture(capture_path)
+    if not cap.isOpened():
+        return None
+
+    # --- check ---
+    fps = int(cap.get(cv.CAP_PROP_FPS))
+    if not 4 < fps < 100:
+        return None
+
+    return cap
+
+
+def get_capture(capture_path):
+    """获取capture"""
+
+    while True:
+
+        # --- check ---
+        cap = cv.VideoCapture(capture_path)
+        if not cap.isOpened():
+            print('m1: sleep 3s.')
+            time.sleep(3)
+            continue
+
+        # --- check ---
+        fps = int(cap.get(cv.CAP_PROP_FPS))
+        if not 4 < fps < 100:
+            print('m2: sleep 3s.')
+            time.sleep(3)
+            continue
+
+        return cap
+
+
+def rtsp_is_live(capture_path):
+    """"""
+
+    # --- check ---
+    cap = cv.VideoCapture(capture_path)
+    if not cap.isOpened():
+        return False
+
+    # --- check ---
+    fps = int(cap.get(cv.CAP_PROP_FPS))
+    if not 4 < fps < 100:
+        return False
+
+    return True
+
+
+if __name__ == '__main__':
+    print(get_capture('rtsp://admin:DEVdev123@192.168.30.235:554/h264/ch1/sub/av_stream'))
+    print(rtsp_is_live('rtsp://admin:DEVdev123@192.168.30.235:554/h264/ch1/sub/av_stream'))

+ 40 - 0
3rdparty/xpip/data_by_numpy.py

@@ -0,0 +1,40 @@
+# update: 2022-6-1-10
+import numpy as np
+
+
+def to_array(data):
+    return np.array(data)
+
+
+def to_bytes(array):
+    return array.tobytes()
+
+
+def bytes_to_array(_bytes):
+    return np.frombuffer(_bytes, dtype=np.uint8)
+
+
+def bytes_to_array_v2(_bytes):
+    return np.asarray(bytearray(_bytes), dtype='uint8')
+
+
+def string_to_array(string):
+    return np.fromstring(string, dtype=np.uint8)
+
+
+if __name__ == '__main__':
+    import cv2
+    import pickle
+
+    cap = cv2.VideoCapture('rtsp://admin:DEVdev123@192.168.30.235:554/h264/ch1/sub/av_stream')
+    ret, frame = cap.read()
+    print(frame.shape)
+    print(type(frame))
+
+    _bytes = pickle.dumps(frame)
+    print(type(_bytes))
+
+    _array = pickle.loads(_bytes)
+    print(type(_array))
+
+    print(np.array_equal(frame, _array))

+ 30 - 0
3rdparty/xpip/show_by_prettytable.py

@@ -0,0 +1,30 @@
+# update: 2021-1-15-18
+import prettytable as pt
+import logging
+
+logger = logging.getLogger('log_method')
+
+
+def show_logs(tags, args, is_work=True):
+	"""log格式化"""
+	if not is_work:
+		return
+	if type(args) == dict:
+		text = pt.PrettyTable()
+		text.field_names = ['参数', '类型', '值']
+		text.align = 'l'
+		for name, value in args.items():
+			too_long = len(str(value)) > 200
+			if too_long:
+				dots = '..'
+			else:
+				dots = ''
+			text.add_row([name, str(type(value)), str(repr(value))[:200] + dots])
+		logger.info(f"{tags}:\n{text}")
+	elif type(args) == list:
+		lines = f"{tags}:"
+		for count, line in enumerate(args):
+			lines += f"\n- {count + 1} - {line}"
+		logger.info(lines)
+	else:
+		logger.info(f"{tags}: {args}")

+ 252 - 0
3rdparty/xpip/xapscheduler.py

@@ -0,0 +1,252 @@
+# date: 2021-10-13
+"""
+# 每天0点:add_job(trigger='cron', hour='0')
+# 每1小时:add_job(trigger='interval', hour='1')
+# 每1分钟:add_job(trigger='cron', minutes='*/1')
+tips: 如果希望加强测试或重度使用,则推荐循环操作;如果轻度使用或保守推进,建议手动指定下次操作时间。
+"""
+from apscheduler.schedulers.background import BackgroundScheduler
+from apscheduler.jobstores.mongodb import MongoDBJobStore
+from apscheduler.executors.pool import ThreadPoolExecutor
+from pymongo import MongoClient
+import uuid
+
+
+class APS(object):
+
+    def __init__(self, db_type='mongo', db_host='aibox-middleware-mongo', db_port=27017,
+                 username='admin', password='admin', database='aibox', collection='LoopTask', is_clean=True):
+        """
+        内部访问:
+            host: sri-thirdparty-mongo
+            port: 27017
+        远程访问:
+            host: 118.190.217.96、192.168.20.162
+            port: 7030
+        """
+        # todo 默认使用sqlite数据库,而不是mongo
+        mongo = MongoClient(db_host, db_port, username=username, password=password)
+        if is_clean:
+            mongo[database][collection].delete_many({})
+
+        jobstores = {
+            'default': MongoDBJobStore(client=mongo, database=database, collection=collection),
+        }
+        executors = {
+            'default': ThreadPoolExecutor(max_workers=3)
+        }
+        self.scheduler = BackgroundScheduler(jobstores=jobstores, executors=executors, timezone='Asia/Shanghai')
+        self.scheduler.start()  # todo 不支持client方式查看job列表
+
+    def get_all(self):
+        """
+        获取任务列表
+        """
+        job_list = []
+        jobs = self.scheduler.get_jobs()
+        for job in jobs:
+            data = {
+                'id': job.id,
+                'name': job.name,
+                'func': job.func.__name__,
+                'args': list(job.args),
+                'trigger': str(job.trigger),
+                'next_run_time': job.next_run_time.strftime('%Y-%m-%d %H:%M:%S'),
+            }
+            job_list.append(data)
+        return job_list
+
+    def get_one(self, job_uuid):
+        """获取任务详情"""
+        job = self.scheduler.get_job(job_uuid)
+        data = {
+            'id': job.id,
+            'name': job.name,
+            'func': job.func.__name__,
+            'args': list(job.args),
+            'trigger': str(job.trigger),
+            'next_run_time': job.next_run_time.strftime('%Y-%m-%d %H:%M:%S'),
+        }
+        return data
+
+    def create_job(self, **params):
+        """
+        创建任务
+        trigger: 触发器
+            date 固定时间调度(只会执行一次)
+            interval 固定时间间隔
+            cron 定时调度
+        """
+        params['id'] = str(uuid.uuid4())
+        # return self.scheduler.add_job(**params)
+        return self.scheduler.add_job(**params, max_instances=100)  # fix maximum number of running instances reached
+
+    def remove_all(self):
+        """删除全部任务"""
+        jobs = self.scheduler.get_jobs()
+        job_ids = [i.id for i in jobs]
+        for job_id in job_ids:
+            self.remove_one(job_id)
+        return job_ids
+
+    def remove_one(self, job_uuid):
+        """删除指定任务"""
+        return self.scheduler.remove_job(job_uuid)
+
+    def pause_one(self, job_uuid):
+        """暂停指定任务"""
+        return self.scheduler.pause_job(job_uuid)
+
+    def resume_one(self, job_uuid):
+        """恢复指定任务"""
+        return self.scheduler.resume_job(job_uuid)
+
+    def pause_all(self):
+        """暂停全部任务"""
+        return self.scheduler.pause()
+
+    def resume_all(self):
+        """恢复全部任务"""
+        return self.scheduler.resume()
+
+    @classmethod
+    def create_job_by_hour(cls, run_date, ins_id):
+        """
+        定时执行
+        run_date: 执行时间(%Y-%m-%d %H:%M:%S)
+        ins_id: 数据id
+        """
+
+    # str_task_id = str(uuid.uuid4())
+    # str_item = mdb.get_one_by_id('UserEventStrategy', ins_id)
+    # str_task_id_list = str_item.get('str_task_id_list', [])
+    # methods.debug_log('ApsClient.create_job_by_hour', f"str_task_id_list: {str_task_id_list}")
+    # str_task_id_list.append(str_task_id)
+    # mdb.update_one_by_id('UserEventStrategy', ins_id, {'str_task_id_list': str_task_id_list})
+    # run_date = datetime.datetime.strptime(run_date, "%Y-%m-%d %H:%M:%S")
+    # cls.scheduler.add_job(func=action_event_strategy, trigger='date', run_date=run_date, id=str_task_id,
+    #                       args=[ins_id, ])
+
+    @classmethod
+    def create_job_by_interval(cls, ins_id, start_date, end_date):
+        """
+        每小时执行
+        :param ins_id: 数据id
+        :param start_date: 开始时间("%Y-%m-%d %H:%M:%S")
+        :param end_date: 结束时间("%Y-%m-%d %H:%M:%S")
+        :return:
+        """
+
+    # str_task_id = str(uuid.uuid4())
+    # str_item = mdb.get_one_by_id('UserEventStrategy', ins_id)
+    # str_task_id_list = str_item.get('str_task_id_list', [])
+    # methods.debug_log('ApsClient.create_job_by_interval', f"str_task_id_list: {str_task_id_list}")
+    # str_task_id_list.append(str_task_id)
+    # mdb.update_one_by_id('UserEventStrategy', ins_id, {'str_task_id_list': str_task_id_list})
+    # cls.scheduler.add_job(func=action_event_strategy, trigger='interval', id=str_task_id, hours=1,
+    #                       start_date=start_date, end_date=end_date, args=[ins_id, ])
+
+    @classmethod
+    def create_job_by_mon(cls, hour, minute, end_date, ins_id):
+        """
+        指定每周一固定时间执行
+        :param hour: 指定时
+        :param minute: 指定分
+        :param end_date: 结束时间("%Y-%m-%d %H:%M:%S")
+        :param ins_id: 数据id
+        :return:
+        """
+
+    # end_date = datetime.datetime.strptime(end_date, "%Y-%m-%d %H:%M:%S")
+    # cls.scheduler.add_job(func=action_event_strategy, trigger='cron', day_of_week='mon', id=str(uuid.uuid4()),
+    #                       hour=hour, minute=minute, end_date=end_date, args=[ins_id, ])
+
+    @classmethod
+    def create_job_by_week(cls, _args, day_of_week, hour, minute, start_date, instance_id):
+        """每周"""
+
+    # cron_id = str(uuid.uuid4())
+    # cls.scheduler.add_job(send_charts, 'cron', day_of_week=day_of_week, id=cron_id, hour=hour,
+    #                       minute=minute,
+    #                       start_date=start_date, args=_args)
+    # cls.save_job_id(instance_id, cron_id)
+    # cls.scheduler.shutdown()
+
+    @classmethod
+    def create_job_by_month(cls, _args, month, day, hour, minute, start_date, instance_id):
+        """每月"""
+
+    # cron_id = str(uuid.uuid4())
+    #
+    # cls.scheduler.add_job(send_charts, 'cron', month=month, day=day, id=cron_id, hour=hour,
+    #                       minute=minute, start_date=start_date, args=_args, )
+    # cls.save_job_id(instance_id, cron_id)
+    # cls.scheduler.shutdown()
+
+    @classmethod
+    def create_job_by_day(cls, _args, hour, minute, start_date, instance_id):
+        """每天"""
+
+    # cron_id = str(uuid.uuid4())
+    #
+    # cls.scheduler.add_job(send_charts, 'cron', id=cron_id, hour=hour, start_date=start_date,
+    #                       minute=minute, args=_args)
+    # cls.save_job_id(instance_id, cron_id)
+    # cls.scheduler.shutdown()
+
+    @classmethod
+    def create_job_by_hours(cls, _args, minute, start_date, instance_id):
+        """每小时"""
+
+    # cron_id = str(uuid.uuid4())
+    # cls.scheduler.add_job(send_charts, 'cron', id=cron_id,
+    #                       minute=minute, start_date=start_date, args=_args)
+    # cls.save_job_id(instance_id, cron_id)
+    # cls.scheduler.shutdown()
+
+    @classmethod
+    def create_job_by_n_day(cls, _args, day, hour, minute, start_date, instance_id):
+        """n天"""
+
+    # cron_id = str(uuid.uuid4())
+    # cls.scheduler.add_job(send_charts, 'interval', id=cron_id,
+    #                       days=day, hours=hour, minutes=minute, start_date=start_date,
+    #                       args=_args)
+    # cls.save_job_id(instance_id, cron_id)
+    # cls.scheduler.shutdown()
+
+    @classmethod
+    def create_job_by_n_hour(cls, _args, hour, minute, start_date, instance_id):
+        """n小时"""
+
+    # cron_id = str(uuid.uuid4())
+    # cls.scheduler.add_job(send_charts, 'interval', id=cron_id, hours=hour, minutes=minute,
+    #                       start_date=start_date, args=_args)
+    # cls.save_job_id(instance_id, cron_id)
+    # cls.scheduler.shutdown()
+
+    @classmethod
+    def create_job_by_n_minute(cls, _args, minute, start_date, instance_id):
+        """n分钟"""
+
+    # cron_id = str(uuid.uuid4())
+    # cls.scheduler.add_job(send_charts, 'interval', id=cron_id, minutes=minute, start_date=start_date,
+    #                       args=_args)
+    # cls.save_job_id(instance_id, cron_id)
+    # cls.scheduler.shutdown()
+
+    @classmethod
+    def create_job_by_n_minute_alarm(cls, minute, start_date, end_date):
+        """告警收敛"""
+    # cls.scheduler.add_job(early_count, 'interval', id=str(uuid.uuid4()), minutes=minute, start_date=start_date,
+    #                       end_date=end_date)
+    # cls.scheduler.shutdown()
+
+
+if __name__ == '__main__':
+    # --- init ---
+    aps = APS(db_type='mongo', db_host='192.168.30.13', db_port=7030,
+              username='admin', password='admin', database='vms', collection='LoopTask')
+
+    # --- 并不支持client方式测试 ---
+    pass

+ 189 - 0
3rdparty/xpip/zip_by_pyminizip.py

@@ -0,0 +1,189 @@
+# update: 2021-5-14-23
+from libraries import base_original as std
+from Crypto.Cipher import AES
+import base64
+import pyminizip
+import shutil
+import os
+
+
+class _AES(object):
+	def __init__(self, key='7486E0264E999881D4EF7BEEDF05A9F7', model='ECB', iv='',
+	             code_type='utf-8'):
+		"""
+		code_type: utf-8/gbk
+		"""
+		self.code_type = code_type
+		self.model = {'ECB': AES.MODE_ECB, 'CBC': AES.MODE_CBC}[model]
+		self.key = self.replenish(key)
+
+		# --- create aes object ---
+		if model == 'ECB':
+			self.aes = AES.new(self.key, self.model)
+		elif model == 'CBC':
+			self.aes = AES.new(self.key, self.model, iv)
+
+	def replenish(self, block, block_size=16):
+		"""block_size: AES key must be either 16, 24, or 32 bytes long"""
+		block = block.encode(self.code_type)
+		while len(block) % block_size != 0:
+			block += b'\x00'
+		return block
+
+	def encrypt(self, text):
+		text = self.replenish(text)
+		encrypt_text = self.aes.encrypt(text)
+		return base64.encodebytes(encrypt_text).decode().strip()
+
+	def decrypt(self, text):
+		text = base64.decodebytes(text.encode(self.code_type))
+		decrypt_text = self.aes.decrypt(text)
+		return decrypt_text.decode(self.code_type).strip('\0')
+
+
+def text_to_aes(text, key='YourPassword'):
+	"""aes加密"""
+	aes = _AES(key=key)
+	return std.text_to_b64(aes.encrypt(text))
+
+
+def aes_to_text(text, key='YourPassword'):
+	"""aes解密"""
+	aes = _AES(key=key)
+	return aes.decrypt(std.b64_to_text(text))
+
+
+def file_to_zip_v2_2(file_path, output_dir, key='<YourPassword@2021>', compress_level=1):
+	"""file转zip(不删除加密文件,并输出到指定目录)"""
+
+	# --- check parameter ---
+	if not os.path.isfile(file_path):
+		return dict(code=1, details='parameter error!')
+
+	# --- check parameter ---
+	if not os.path.isdir(output_dir):
+		return dict(code=2, details='parameter error!')
+
+	# --- check file name ---
+	file_name = file_path.split('/')[-1]
+	is_encrypted = len(file_name) == 37 and file_name[32] == '.'
+	if is_encrypted:
+		shutil.copy(file_path, f"{output_dir}/{file_name}")
+		return dict(code=3, details='parameter error!')
+
+	# --- create name file ---
+	# dir_path = '/'.join(file_path.split('/')[:-1])
+	file_name_aes = text_to_aes(file_name, key=key)
+	file_name_md5 = std.byte_to_md5(std.text_to_byte(file_name_aes))
+	name_file_path = f"{output_dir}/{file_name_md5[-4:]}"
+	with open(name_file_path, 'w') as f1:
+		f1.write(file_name_aes)
+
+	# --- rename file ---
+	file_md5 = std.get_big_file_md5(file_path)
+	# data_file_path = f"{dir_path}/{file_md5}"
+	# os.rename(file_path, data_file_path)
+	data_file_path = f"{output_dir}/{file_md5}"
+	shutil.copy(file_path, data_file_path)
+
+	# --- define zip name ---
+	zip_path = f"{output_dir}/{file_md5}.{file_name_md5[-4:]}"
+
+	try:
+		# --- writing ---
+		"""
+		Args:
+			1. src file LIST path (list)
+			2. src file LIST prefix path (list) or []
+			3. dst file path (string)
+			4. password (string) or None (to create no-password zip)
+			5. compress_level(int) between 1 to 9, 1 (more fast) <---> 9 (more compress)
+			6. optional function to be called during processing which takes one argument, the count of how many files have been compressed
+		"""
+		pyminizip.compress_multiple([data_file_path, name_file_path], ['', ''], zip_path, key, compress_level)
+
+		# --- remove file ---
+		os.remove(data_file_path)
+		os.remove(name_file_path)
+		return dict(code=0, details='ended.')
+
+	except Exception as exception:
+
+		# --- revert ---
+		os.remove(name_file_path)
+		os.remove(data_file_path)
+
+		import traceback
+		print(traceback.format_exc())
+		return dict(code=-1, details=f"{traceback.format_exc()}")
+
+
+def zip_to_file_v2_2(file_path, key='<YourPassword>', no_path=True):
+	"""zip转file
+	todo(不删除加密文件,并输出到指定目录)"""
+
+	# --- check parameter ---
+	if not os.path.isfile(file_path):
+		return dict(code=1, details='parameter error!')
+
+	# --- check again ---
+	file_name = file_path.split('/')[-1]
+	is_encrypted = len(file_name) == 37 and file_name[32] == '.'
+	if not is_encrypted:
+		return dict(code=2, details='parameter error!')
+
+	# --- record ---
+	dir_path = '/'.join(file_path.split('/')[:-1])
+	names = os.listdir(dir_path)
+	before_files = set(f"{dir_path}/{name}" for name in names if not os.path.isdir(f"{dir_path}/{name}"))
+
+	try:
+		# --- writing ---
+		"""
+		Args:
+			1. src file path (string)
+			2. password (string) or None (to unzip encrypted archives)
+			3. dir path to extract files or None (to extract in a specific dir or cwd)
+			4. withoutpath (exclude path of extracted)
+		"""
+		pyminizip.uncompress(file_path, key, dir_path, no_path)
+
+		# --- record ---
+		names = os.listdir(dir_path)
+		after_files = set(f"{dir_path}/{name}" for name in names if not os.path.isdir(f"{dir_path}/{name}"))
+
+		# --- check ---
+		temp_file = list(after_files - before_files)
+		if len(temp_file) != 2:
+			raise Exception('something is wrong!')
+
+		# --- get file name ---
+		raw_name = str()
+		for path in temp_file:
+			name = path.split('/')[-1]
+			if len(name) == 4:
+				with open(path, 'r') as f1:
+					raw_name = aes_to_text(f1.read(), key=key)
+				os.remove(path)
+
+		# --- rename ---
+		for path in list(after_files - before_files):
+			name = path.split('/')[-1]
+			if len(name) == 32:
+				os.rename(path, f"{dir_path}/{raw_name}")
+
+		# --- remove file ---
+		os.remove(file_path)
+		return dict(code=0, details='ended.')
+
+	except Exception as exception:
+
+		# --- revert ---
+		names = os.listdir(dir_path)
+		after_files = set(f"{dir_path}/{name}" for name in names if not os.path.isdir(f"{dir_path}/{name}"))
+		for path in list(after_files - before_files):
+			os.remove(path)
+
+		import traceback
+		print(traceback.format_exc())
+		return dict(code=-1, details=f"{traceback.format_exc()}")

+ 82 - 0
3rdparty/xplugin/hydra/plugin.py

@@ -0,0 +1,82 @@
+import subprocess
+
+
+class Plugin:
+    def __init__(self):
+        model_path = '/home/server/resources/DockerDependencies/2022/target/AlgorithmModels/FaceRecognition-arcface/'
+        model_path += 'arcface_r100_v1.onnx'
+        # model_path += 'MFR_glintr100.onnx'
+
+    @staticmethod
+    def run_hydra():
+        """执行命令"""
+        target = 'ssh://58.34.94.176:22'
+        username = 'server'
+        password = 'server@2000'
+
+        command = [
+            'hydra',
+            '-l', username,
+            '-p', password,
+            target,
+        ]
+
+        try:
+            result = subprocess.run(command, capture_output=True, text=True, check=True)
+            return result.stdout
+        except subprocess.CalledProcessError as e:
+            return e.stderr
+
+    def get_face_features_normalization_by_image_array(self, image_array):
+        """
+
+        :param image_array:
+        :return:
+        """
+        pass
+
+    @staticmethod
+    def normalize(embedding):
+        """特征数据格式化"""
+        embedding_norm = norm(embedding)
+        normed_embedding = embedding / embedding_norm
+        return normed_embedding
+
+    def get_face_features_normalization_by_image_array(self, image_array):
+        """获取特征"""
+
+        # --- debug ---
+        # methods.debug_log('FaceRecognitionEngine', f"m-92: size: {image_array.shape}")
+
+        # --- check todo 连乘得到像素值,旨在过滤低于112的尺寸图片 ---
+        # if np.prod(image_array.shape) < np.prod((112, 112, 3)):
+        #     return None
+
+        # --- check ---
+        if image_array is None:
+            return None
+
+        # --- check ---
+        if image_array.shape != (112, 112, 3):
+            # methods.debug_log('FaceRecognitionEngine', f"m-96: image resize before is {image_array.shape}")
+            image_array = cv2.resize(image_array, (112, 112))
+
+        if not isinstance(image_array, list):
+            image_array = [image_array]
+
+        for i, img in enumerate(image_array):
+            img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
+            img = np.transpose(img, (2, 0, 1))
+            image_array[i] = img.astype(np.float32)
+
+        image_array = np.stack(image_array)
+        net_out = self.onnx_session.run(self.outputs, {self.onnx_session.get_inputs()[0].name: image_array})
+        return self.normalize(net_out[0][0])
+
+
+if __name__ == '__main__':
+    # --- init ---
+    plugin = PLUGIN()
+
+    output = plugin.run_hydra()
+    print(output)

+ 260 - 0
3rdparty/xplugin/msscan/plugin.py

@@ -0,0 +1,260 @@
+"""
+# 安装
+apt-get install -y libpcap-dev masscan
+
+# --- test ssh ---
+masscan -p22 192.168.131.0/24 --rate=1000
+
+Discovered open port 22/tcp on 192.168.131.100                                 
+Discovered open port 22/tcp on 192.168.131.102                                 
+Discovered open port 22/tcp on 192.168.131.243                                 
+Discovered open port 22/tcp on 192.168.131.138                                 
+Discovered open port 22/tcp on 192.168.131.16                                  
+Discovered open port 22/tcp on 192.168.131.136                                 
+Discovered open port 22/tcp on 192.168.131.242                                 
+Discovered open port 22/tcp on 192.168.131.61                                  
+Discovered open port 22/tcp on 192.168.131.46                                  
+Discovered open port 22/tcp on 192.168.131.42                                  
+Discovered open port 22/tcp on 192.168.131.43                                  
+Discovered open port 22/tcp on 192.168.131.133                                 
+Discovered open port 22/tcp on 192.168.131.11                                  
+Discovered open port 22/tcp on 192.168.131.101                                 
+Discovered open port 22/tcp on 192.168.131.23                                  
+Discovered open port 22/tcp on 192.168.131.21                                  
+Discovered open port 22/tcp on 192.168.131.22                                  
+Discovered open port 22/tcp on 192.168.131.103                                 
+Discovered open port 22/tcp on 192.168.131.241                                 
+Discovered open port 22/tcp on 192.168.131.13                                  
+Discovered open port 22/tcp on 192.168.131.17                                  
+Discovered open port 22/tcp on 192.168.131.253                                 
+Discovered open port 22/tcp on 192.168.131.137                                 
+Discovered open port 22/tcp on 192.168.131.130                                 
+Discovered open port 22/tcp on 192.168.131.139                                 
+Discovered open port 22/tcp on 192.168.131.132
+
+# --- test 3网段 ---
+masscan 192.168.3.0/24 --rate=1000 --ports 0-65535
+
+# --- test sqlserver ---
+nmap -p 1433 192.168.131.0/24
+
+Starting Nmap 7.80 ( https://nmap.org ) at 2023-12-18 17:44 CST
+Nmap scan report for 192.168.131.1
+Host is up (0.00028s latency).
+
+PORT     STATE  SERVICE
+1433/tcp closed ms-sql-s
+
+Nmap scan report for 192.168.131.11
+Host is up (0.00021s latency).
+
+PORT     STATE  SERVICE
+1433/tcp closed ms-sql-s
+
+Nmap scan report for 192.168.131.12
+Host is up (0.00030s latency).
+
+PORT     STATE  SERVICE
+1433/tcp closed ms-sql-s
+
+Nmap scan report for 192.168.131.13
+Host is up (0.00015s latency).
+
+PORT     STATE  SERVICE
+1433/tcp closed ms-sql-s
+
+Nmap scan report for 192.168.131.16
+Host is up (0.00012s latency).
+
+PORT     STATE    SERVICE
+1433/tcp filtered ms-sql-s
+
+Nmap scan report for 192.168.131.17
+Host is up (0.00028s latency).
+
+PORT     STATE  SERVICE
+1433/tcp closed ms-sql-s
+
+Nmap scan report for 192.168.131.20
+Host is up (0.00022s latency).
+
+PORT     STATE  SERVICE
+1433/tcp closed ms-sql-s
+
+Nmap scan report for 192.168.131.21
+Host is up (0.00013s latency).
+
+PORT     STATE  SERVICE
+1433/tcp closed ms-sql-s
+
+Nmap scan report for 192.168.131.22
+Host is up (0.00024s latency).
+
+PORT     STATE  SERVICE
+1433/tcp closed ms-sql-s
+
+Nmap scan report for 192.168.131.23
+Host is up (0.000024s latency).
+
+PORT     STATE  SERVICE
+1433/tcp closed ms-sql-s
+
+Nmap scan report for 192.168.131.41
+Host is up (0.018s latency).
+
+PORT     STATE  SERVICE
+1433/tcp closed ms-sql-s
+
+Nmap scan report for 192.168.131.42
+Host is up (0.011s latency).
+
+PORT     STATE  SERVICE
+1433/tcp closed ms-sql-s
+
+Nmap scan report for 192.168.131.43
+Host is up (0.031s latency).
+
+PORT     STATE  SERVICE
+1433/tcp closed ms-sql-s
+
+Nmap scan report for 192.168.131.45
+Host is up (0.00090s latency).
+
+PORT     STATE  SERVICE
+1433/tcp closed ms-sql-s
+
+Nmap scan report for 192.168.131.46
+Host is up (0.031s latency).
+
+PORT     STATE  SERVICE
+1433/tcp closed ms-sql-s
+
+Nmap scan report for 192.168.131.61
+Host is up (0.00056s latency).
+
+PORT     STATE  SERVICE
+1433/tcp closed ms-sql-s
+
+Nmap scan report for 192.168.131.62
+Host is up (0.00059s latency).
+
+PORT     STATE  SERVICE
+1433/tcp closed ms-sql-s
+
+Nmap scan report for 192.168.131.99
+Host is up (0.00021s latency).
+
+PORT     STATE    SERVICE
+1433/tcp filtered ms-sql-s
+
+Nmap scan report for 192.168.131.100
+Host is up (0.000095s latency).
+
+PORT     STATE    SERVICE
+1433/tcp filtered ms-sql-s
+
+Nmap scan report for 192.168.131.101
+Host is up (0.00014s latency).
+
+PORT     STATE    SERVICE
+1433/tcp filtered ms-sql-s
+
+Nmap scan report for 192.168.131.102
+Host is up (0.00013s latency).
+
+PORT     STATE    SERVICE
+1433/tcp filtered ms-sql-s
+
+Nmap scan report for 192.168.131.103
+Host is up (0.00015s latency).
+
+PORT     STATE    SERVICE
+1433/tcp filtered ms-sql-s
+
+Nmap scan report for 192.168.131.130
+Host is up (0.0049s latency).
+
+PORT     STATE  SERVICE
+1433/tcp closed ms-sql-s
+
+Nmap scan report for 192.168.131.131
+Host is up (0.012s latency).
+
+PORT     STATE  SERVICE
+1433/tcp closed ms-sql-s
+
+Nmap scan report for 192.168.131.132
+Host is up (0.015s latency).
+
+PORT     STATE  SERVICE
+1433/tcp closed ms-sql-s
+
+Nmap scan report for 192.168.131.133
+Host is up (0.011s latency).
+
+PORT     STATE  SERVICE
+1433/tcp closed ms-sql-s
+
+Nmap scan report for 192.168.131.136
+Host is up (0.014s latency).
+
+PORT     STATE  SERVICE
+1433/tcp closed ms-sql-s
+
+Nmap scan report for 192.168.131.137
+Host is up (0.0039s latency).
+
+PORT     STATE  SERVICE
+1433/tcp closed ms-sql-s
+
+Nmap scan report for 192.168.131.138
+Host is up (0.010s latency).
+
+PORT     STATE  SERVICE
+1433/tcp closed ms-sql-s
+
+Nmap scan report for 192.168.131.139
+Host is up (0.0043s latency).
+
+PORT     STATE  SERVICE
+1433/tcp closed ms-sql-s
+
+Nmap scan report for 192.168.131.241
+Host is up (0.00036s latency).
+
+PORT     STATE  SERVICE
+1433/tcp closed ms-sql-s
+
+Nmap scan report for 192.168.131.242
+Host is up (0.00038s latency).
+
+PORT     STATE  SERVICE
+1433/tcp closed ms-sql-s
+
+Nmap scan report for 192.168.131.243
+Host is up (0.00048s latency).
+
+PORT     STATE  SERVICE
+1433/tcp closed ms-sql-s
+
+Nmap scan report for 192.168.131.252
+Host is up (0.0023s latency).
+
+PORT     STATE  SERVICE
+1433/tcp closed ms-sql-s
+
+Nmap scan report for 192.168.131.253
+Host is up (0.00016s latency).
+
+PORT     STATE  SERVICE
+1433/tcp closed ms-sql-s
+
+Nmap scan report for _gateway (192.168.131.254)
+Host is up (0.0010s latency).
+
+PORT     STATE  SERVICE
+1433/tcp closed ms-sql-s
+
+Nmap done: 256 IP addresses (36 hosts up) scanned in 63.19 seconds
+
+"""

+ 59 - 0
3rdparty/xserver/xtcp.py

@@ -0,0 +1,59 @@
+import asyncio
+import struct
+
+class CustomProtocol(asyncio.Protocol):
+    clients = {}
+
+    def connection_made(self, client):
+        self.client = client
+        self.client_info = client.get_extra_info('peername')
+        print(f"Connection from {self.client_info}")
+        CustomProtocol.clients[self.client_info] = client
+        self.on_connect()
+
+    def data_received(self, data):
+        asyncio.create_task(self.handle_data(data))
+
+    def connection_lost(self, exc):
+        print(f"Connection closed by {self.client_info}")
+        if self.client_info in CustomProtocol.clients:
+            del CustomProtocol.clients[self.client_info]
+        self.on_disconnect()
+
+    def on_connect(self):
+        print(f"Connected to {self.client_info}")
+
+    async def handle_data(self, data):
+        # Simulating a blocking operation with asyncio.run_in_executor
+        result = await asyncio.get_running_loop().run_in_executor(None, self.process_data, data)
+        self.client.write(result)
+
+    def process_data(self, data):
+        # Simulate a CPU-bound task
+        values = struct.unpack('!hh', data)
+        processed_values = (values[0] + 1, values[1] + 1)
+        return struct.pack('!hh', *processed_values)
+
+    def on_disconnect(self):
+        print(f"Disconnected from {self.client_info}")
+
+    @classmethod
+    async def broadcast(cls, message):
+        data = struct.pack('!hh', *message)
+        for client in cls.clients.values():
+            client.write(data)
+        await asyncio.gather(*(client.drain() for client in cls.clients.values()))
+
+async def main():
+    loop = asyncio.get_running_loop()
+    server = await loop.create_server(
+        lambda: CustomProtocol(),
+        '0.0.0.0', 20917
+    )
+
+    async with server:
+        print("Server listening on 0.0.0.0:20917")
+        await server.serve_forever()
+
+if __name__ == "__main__":
+    asyncio.run(main())

+ 61 - 0
3rdparty/xserver/xudp.py

@@ -0,0 +1,61 @@
+"""
+python3 /home/server/repositories/repositories/sri-project.demo-py/3rdparty/xserver/xudp.py
+"""
+import asyncio
+import struct
+
+
+# from concurrent.futures import ThreadPoolExecutor
+
+
+class CustomProtocol:
+    clients = {}
+
+    # executor = ThreadPoolExecutor()
+
+    def connection_made(self, transport):
+        self.transport = transport
+        self.peername = None  # UDP没有真正的连接,因此peername为空
+        print(f"UDP Server started")
+
+    def datagram_received(self, data, addr):
+        asyncio.create_task(self.handle_data(data, addr))
+
+    def error_received(self, exc):
+        print(f"Error received: {exc}")
+
+    async def handle_data(self, data, addr):
+        if len(data) < 4:
+            return  # Ensure complete data packet is received
+        loop = asyncio.get_running_loop()
+        values = await loop.run_in_executor(None, self.process_data, data)
+        # values = await loop.run_in_executor(CustomProtocol.executor, self.process_data, data)
+        print(f"Received values: {values} from {addr}")
+
+        response = struct.pack('!hh', values[0] + 1, values[1] + 1)
+        self.transport.sendto(response, addr)
+
+    @staticmethod
+    def process_data(data):
+        values = struct.unpack('!hh', data)
+        print(f"Processing data: {values}")
+        # Simulate some processing
+        return (values[0] + 1, values[1] + 1)
+
+
+async def main():
+    loop = asyncio.get_running_loop()
+    transport, protocol = await loop.create_datagram_endpoint(
+        lambda: CustomProtocol(),
+        local_addr=('127.0.0.1', 20917)
+    )
+
+    print("UDP Server listening on 127.0.0.1:20917")
+    try:
+        await asyncio.Future()  # Keep running indefinitely
+    finally:
+        transport.close()  # Close the transport
+
+
+if __name__ == "__main__":
+    asyncio.run(main())

+ 0 - 29
project-fastapi-hs/README-usage.bash

@@ -1,29 +0,0 @@
-## NOTE
-
-# 一、构建操作
-# 调试
-echo "BEGIN:" \
-&& project_path="/home/ubuntu/repositories/repositories/casperz.py-project/project-fastapi-hs" \
-&& cd ${project_path} \
-&& sudo docker-compose --file compose.yml down \
-&& sudo docker-compose --file compose.yml up --detach --build \
-&& sudo docker exec -it sri-module-server-fastapi bash
-# 启动
-echo "BEGIN:" \
-&& project_path="/home/ubuntu/repositories/repositories/casperz.py-project/project-fastapi-hs" \
-&& cd ${project_path} \
-&& sudo docker-compose --file compose.yml down \
-&& sudo docker-compose --file compose.yml up --detach --build \
-&& sudo docker-compose --file compose.yml logs --follow
-# 强制构建并运行
-echo "BEGIN:" \
-&& project_path="/home/ubuntu/repositories/repositories/casperz.py-project/project-fastapi-hs" \
-&& cd ${project_path} \
-&& sudo docker-compose --file compose.yml down \
-&& sudo docker-compose --file compose.yml build --no-cache \
-&& sudo docker-compose --file compose.yml up --detach \
-&& sudo docker logs --follow sri-module-server-flask
-
-# 二、日常调试命令
-sudo chmod -R 777 /home/ubuntu/repositories/repositories
-sudo docker restart sri-module-hs01 && sudo docker logs -f sri-module-hs01

+ 0 - 208
project-fastapi-hs/api/api.py

@@ -1,208 +0,0 @@
-from starlette.formparsers import MultiPartParser as StartletteMultiPartParser
-from fastapi import APIRouter, Request, Response, Depends
-from fastapi.responses import FileResponse
-from key import v1 as key_v1
-
-from hub import methods, Global
-import importlib
-
-router = APIRouter()
-
-config_dict = {
-
-    'v5': {
-
-        # --- 关于渣包车 ---
-        2001: 'v5.hs2000.code_2001',  # 获取全部渣包车状态接口
-        2002: 'v5.hs2000.code_2002',  # 指定渣包车点火操作接口
-        2003: 'v5.hs2000.code_2003',  # 指定渣包车熄火操作接口
-        2004: 'v5.hs2000.code_2004',  # 指定渣包车建立远程操作权限(或是切换)接口
-        # 2005: 'v5.hs2000.code_2005',  # 创建并执行自动驾驶任务【已停用】
-
-        2101: 'v5.hs2000.code_2101',  # 新增渣包车接口
-        2102: 'v5.hs2000.code_2102',  # 修改渣包车接口
-        2103: 'v5.hs2000.code_2103',  # 删除渣包车接口
-
-        # --- 关于关于任务 ---
-        3001: 'v5.hs3000.code_3001',  # 任务列表数据获取接口(分页)
-        # 3002: 'v5.hs3000.code_3002',  # 任务暂停接口【已停用】
-        3003: 'v5.hs3000.code_3003',  # 任务取消消接口
-        3004: 'v5.hs3000.code_3004',  # 任务创建并执行接口
-        3005: 'v5.hs3000.code_3005',  # 获取指定任务信息
-
-        # --- 关于场地数据 ---
-        4001: 'v5.hs4000.code_4001',  # 获取全部渣包状态数据接口
-        # 4002: 'v5.hs4000.code_4002',  # todo 获取接渣口状态数据
-        # 4003: 'v5.hs4000.code_4003',  # todo 获取倒渣口状态数据
-
-        # --- 关于告警 ---
-        5001: 'v5.hs5000.code_5001',  # 获取告警数据列表接口
-
-    }
-
-}
-
-methods_dict = {}  # {<tag>: {<method>: <path>}}
-
-
-def _get_method_by_code(code, tag):
-    """
-    通过code获取method(不调用不加载)
-    """
-    try:
-        # --- check ---
-        if tag not in methods_dict:
-            methods_dict[tag] = {}
-
-        # --- check ---
-        if code in methods_dict.get(tag):
-            return methods_dict.get(tag).get(code)
-
-        # --- get method ---
-        method_path = config_dict.get(tag).get(code)
-        tag, file_name, method_name = method_path.split('.')
-        script = importlib.import_module(f"api.{tag}.{file_name}")
-        method = getattr(script, method_name)
-
-        # --- set method ---
-        methods_dict[tag][code] = method
-        return method
-
-    except Exception as exception:
-        methods.debug_log('api._get_method_by_code.69', f"#exception: {exception.__class__.__name__}")
-        methods.debug_log('api._get_method_by_code.69', f"#traceback: {methods.trace_log()}")
-
-
-@router.post('/{tag}/api')
-async def post(tag: str, request: Request, response: Response, user: dict = Depends(key_v1.login_required)):
-    """"""
-
-    # --- check ---
-    if not user.get('skip_is'):
-        response.headers['authorization'] = key_v1.get_token_by_user(user)
-
-    # --- get sources ---
-    sources = await request.json()
-    # tag = sources.get('tag')
-    code = int(sources.get('code'))
-    page = sources.get('page', 1)
-    size = sources.get('size', 10)
-    ban_keys = ['code']
-
-    # --- set global args ---
-    sources = {key: val for key, val in sources.items() if key not in ban_keys}
-    sources['g_user_id'] = user.get('uid')
-    sources['g_user_name'] = user.get('username')
-    sources['g_user_pass'] = user.get('password')
-    sources['g_role_id'] = user.get('role_id')
-
-    # --- call action ---
-    try:
-        run_at = methods.now_ts()
-        method = _get_method_by_code(code=code, tag=tag)
-        result = await method(**sources)
-        methods.debug_log(f"api.post.101", f"#{tag}/{code}: use time {round(methods.now_ts() - run_at, 2)}s")
-
-        # --- check ---
-        if code in [
-            # 8201,  # 访客记录,列表
-        ] and result.__class__.__name__ == 'dict':
-            return dict(
-                code=result.get('code'),
-                data=result.get('data', [])[(page - 1) * size: page * size],
-                page=page,
-                size=size,
-                total=len(result.get('data', [])),
-            )
-        elif result.__class__.__name__ in ['FileResponse', 'dict']:
-            return result
-        else:
-            return dict(data=result, type=result.__class__.__name__)
-
-    except Exception as exception:
-
-        methods.debug_log('api.post.121', f"#tag: {tag}, #code: {code}")
-        methods.debug_log('api.post.121', f"#exception: {exception.__class__.__name__}")
-        methods.debug_log('api.post.121', f"#traceback: {methods.trace_log()}")
-        return dict(code=-1, data=[],
-                    reason=f"{exception.__class__.__name__}",
-                    detail=f"{methods.trace_log()}")
-
-
-@router.put('/actions')
-async def upload(request: Request, user: dict = Depends(key_v1.login_required)):
-    try:
-        # --- get sources ---
-        sources = dict()
-        parser = StartletteMultiPartParser(request.headers, request.stream())
-        params = await parser.parse()
-        # sources['params'] = params
-
-        # --- set sources --- fromdata列表处理
-        for key, value in params.multi_items():
-
-            # --- check list ---
-            if key[-4:] == 'list' and key not in sources:
-                sources[key] = list()
-            if key[-4:] == 'list':
-                sources[key].append(value)
-
-            # --- make list ---
-            else:
-                if key in sources:
-                    sources[key] = [sources[key]]
-                    sources[key].append(value)
-                else:
-                    sources[key] = value
-
-        # --- clean ---
-        tag = sources.get('tag', 'v1')
-        code = int(sources.get('code'))
-        del sources['tag']
-        del sources['code']
-
-        # --- set sources ---
-        sources['g_user_id'] = user.get('uid')
-        sources['g_user_name'] = user.get('username')
-        sources['g_user_pass'] = user.get('password')
-        sources['g_role_id'] = user.get('role_id')
-
-        # --- set files ---
-        files = dict()
-        for key, value in sources.items():
-            if value.__class__.__name__ == 'UploadFile':
-                files[key] = value
-        for key, value in files.items():
-            del sources[key]
-        sources['files'] = files
-
-        # --- call action ---
-        return await _get_method_by_code(code=code, tag=tag)(**sources)
-
-    except Exception as exception:
-
-        methods.debug_log('api.upload', f"m-299: exception | {exception.__class__.__name__}")
-        methods.debug_log('api.upload', f"m-299: traceback | {methods.trace_log()}")
-        return dict(code=-1,
-                    reason=f"{exception.__class__.__name__}",
-                    detail=f"{methods.trace_log()}")
-
-
-@router.get('/api')
-async def download(request: Request, response: Response, user: dict = Depends(key_v1.login_required)):
-    try:
-        parser = StartletteMultiPartParser(request.headers, request.stream())
-        params = await parser.parse()
-        instance_id = params.get('instance_id')
-        report = Global.mdb.get_one_by_id('', instance_id)
-        report_path = report.get('report') if report else ''
-        if not report_path:
-            return ''
-        return FileResponse(report_path)
-    except Exception as exception:
-
-        methods.debug_log('api.download.201', f"#exception: {exception.__class__.__name__}")
-        methods.debug_log('api.download.201', f"#traceback: {methods.trace_log()}")
-        return dict(code=-1,
-                    reason=f"{exception.__class__.__name__}",
-                    detail=f"{methods.trace_log()}")

+ 0 - 151
project-fastapi-hs/api/v5/hs2000.py

@@ -1,151 +0,0 @@
-from hub import methods, Global
-
-
-async def code_2001(**sources):
-    """
-    获取全部渣包车状态
-    """
-    """
-    VehicleInfo: 渣包车信息表
-    VehicleInfo.uuid: 车辆标识
-    VehicleInfo.name: 车辆名称
-    VehicleInfo.address: 车辆ip
-    VehicleInfo.state: 车辆状态 1 离线(默认值) 2 在线空闲 3 人工驾驶中 4 远程驾驶中 5 自动驾驶中
-    VehicleInfo.check_vehicle_direction: 当前车头方向是否符合自动驾驶条件 True 符合 False 不符合(默认值)
-    VehicleInfo.current_vehicle_direction: 当前车头方向类型 3 围栏方向 9 渣场方向 12 维修间方向 6 维修间正对方向 0 未知(默认值)
-    VehicleInfo.check_vehicle_coordinate: 当前车辆坐标是否符合自动驾驶条件 True 符合 False 不符合(默认值)
-    VehicleInfo.current_vehicle_coordinate_x: 当前所在位置坐标 
-    VehicleInfo.current_vehicle_coordinate_y: 当前所在位置坐标 
-    VehicleInfo.current_vehicle_weight: 当前车辆负载重量  
-    """
-    # --- fill d1 ---
-    d1 = list()
-    for item in Global.mdb.get_all('VehicleInfo'):
-        # --- check ---
-        if 'check_vehicle_direction' not in item:
-            item['check_vehicle_direction'] = False
-        if 'current_vehicle_direction' not in item:
-            item['current_vehicle_direction'] = 0
-        if 'state' not in item:
-            item['state'] = 1
-        if 'current_vehicle_weight' not in item:
-            item['current_vehicle_weight'] = 0
-
-        # --- append ---
-        item['uuid'] = str(item.get('_id'))
-        item.pop('_id')
-        d1.append(item)
-
-    return dict(code=0, data=d1)
-
-
-async def code_2002(**sources):
-    """
-    指定渣包车点火操作接口
-    """
-    return dict(code=0, data=sources.get('uuid'))
-
-
-async def code_2003(**sources):
-    """
-    指定渣包车熄火操作接口
-    """
-    return dict(code=0, data=sources.get('uuid'))
-
-
-async def code_2004(**sources):
-    """
-    指定渣包车建立远程操作权限(或是切换)接口
-    """
-    return dict(code=0, data=sources.get('uuid'))
-
-
-async def code_2101(**sources):
-    """
-    新增渣包车接口
-    """
-    # --- save ---
-    """
-    VehicleInfo: 渣包车信息表
-    VehicleInfo.uuid: 标识
-    VehicleInfo.name: 车辆名称
-    VehicleInfo.address: 车辆ip
-    VehicleInfo.state: 车辆状态 1 离线(默认值) 2 在线空闲 3 人工驾驶中 4 远程驾驶中 5 自动驾驶中
-    VehicleInfo.check_vehicle_direction: 当前车头方向是否符合自动驾驶条件 True 符合 False 不符合(默认值)
-    VehicleInfo.current_vehicle_direction: 当前车头方向类型 3 围栏方向 9 渣场方向 12 维修间方向 6 维修间正对方向 0 未知(默认值)
-    VehicleInfo.check_vehicle_coordinate: 当前车辆坐标是否符合自动驾驶条件 True 符合 False 不符合(默认值)
-    VehicleInfo.current_vehicle_coordinate_x: 当前所在位置坐标 
-    VehicleInfo.current_vehicle_coordinate_y: 当前所在位置坐标 
-    VehicleInfo.current_vehicle_weight: 当前车辆负载重量 
-    """
-    data = {
-        'name': sources.get('name'),
-        'address': sources.get('address'),
-        'state': 1,
-        'check_vehicle_direction': False,
-        'update_at': methods.now_ts(),
-    }
-    uuid = Global.mdb.add('VehicleInfo', data)
-    return dict(code=0, data=uuid)
-
-
-async def code_2102(**sources):
-    """
-    修改渣包车接口
-    """
-    # --- check ---
-    uuid = sources.get('uuid')
-    if not uuid:
-        return dict(code=1, detail=f"something is wrong.")
-
-    # --- check ---
-    item = Global.mdb.get_one_by_id('VehicleInfo', uuid)
-    if not item:
-        return dict(code=2, detail=f"something is wrong.")
-
-    # --- update VehicleInfo by id ---
-    """
-    VehicleInfo: 渣包车信息表
-    VehicleInfo.uuid: 标识
-    VehicleInfo.name: 车辆名称
-    VehicleInfo.address: 车辆ip
-    VehicleInfo.state: 车辆状态 1 离线(默认值) 2 在线空闲 3 人工驾驶中 4 远程驾驶中 5 自动驾驶中
-    VehicleInfo.check_vehicle_direction: 当前车头方向是否符合自动驾驶条件 True 符合 False 不符合(默认值)
-    VehicleInfo.current_vehicle_direction: 当前车头方向类型 3 围栏方向 9 渣场方向 12 维修间方向 6 维修间正对方向 0 未知(默认值)
-    VehicleInfo.check_vehicle_coordinate: 当前车辆坐标是否符合自动驾驶条件 True 符合 False 不符合(默认值)
-    VehicleInfo.current_vehicle_coordinate_x: 当前所在位置坐标 
-    VehicleInfo.current_vehicle_coordinate_y: 当前所在位置坐标 
-    VehicleInfo.current_vehicle_weight: 当前车辆负载重量 
-    """
-    update_dict = dict()
-    update_dict['update_at'] = methods.now_ts()
-    if sources.get('name'):
-        update_dict['name'] = sources.get('name')
-    if sources.get('address'):
-        update_dict['address'] = sources.get('address')
-    Global.mdb.update_one_by_id('VehicleInfo', uuid, update_dict)
-
-    # --- get ---
-    item = Global.mdb.get_one_by_id('VehicleInfo', uuid)
-    item['uuid'] = str(item.get('_id'))
-    item.pop('_id')
-    return dict(code=0, data=item)
-
-
-async def code_2103(**sources):
-    """
-    删除渣包车接口
-    """
-    # --- check ---
-    uuid = sources.get('uuid')
-    if not uuid:
-        return dict(code=1, detail=f"something is wrong.")
-
-    # --- check ---
-    item = Global.mdb.get_one_by_id('VehicleInfo', uuid)
-    if not item:
-        return dict(code=2, detail=f"something is wrong.")
-
-    # --- clean ---
-    Global.mdb.remove_one_by_id('VehicleInfo', uuid)
-    return dict(code=0, data=uuid)

+ 0 - 154
project-fastapi-hs/api/v5/hs3000.py

@@ -1,154 +0,0 @@
-from hub import methods, Global
-
-
-async def code_3001(**sources):
-    """
-    任务列表数据获取接口(分页)
-    """
-    # --- check ---
-    if not sources.get('page'):
-        return dict(code=1, detail=f"something is wrong.")
-    elif not sources.get('size'):
-        return dict(code=2, detail=f"something is wrong.")
-
-    # --- fill d1 ---
-    d1 = list()
-    page = sources.get('page')
-    size = sources.get('size')
-    for item in Global.mdb.get_all('VehicleTaskList'):
-        item['uuid'] = str(item.get('_id'))
-        item.pop('_id')
-        d1.append(item)
-    return dict(code=0, data=d1[(page - 1) * size: page * size], total=len(d1), page=page, size=size)
-
-
-async def code_3002(**sources):
-    """
-    任务暂停接口
-    """
-    return dict(code=0, data=sources.get('uuid'))
-
-
-async def code_3003(**sources):
-    """
-    任务取消接口
-    """
-    return dict(code=0, data=sources.get('uuid'))
-
-
-async def code_3004(**sources):
-    """
-    任务创建并执行
-    渣罐位:
-        X排.X位: 渣罐X排X位
-    接渣口:
-        dump.MN: 接渣口7
-        dump.KL: 接渣口6
-        dump.IJ: 接渣口5
-        dump.GH: 接渣口4
-        dump.EF: 接渣口3
-        dump.CD: 接渣口2
-        dump.AB: 接渣口1
-    接渣口:
-        load.1
-        load.2
-        load.3
-    """
-    # --- check ---
-    if not sources.get('uuid'):
-        return dict(code=1, detail=f"Reason: 参数缺失")
-    elif not sources.get('task_type'):
-        return dict(code=2, detail=f"Reason: 参数缺失")
-    elif not sources.get('target_point_name'):
-        return dict(code=3, detail=f"Reason: 参数缺失")
-
-    # --- check ---
-    item = Global.mdb.get_one_by_id('VehicleInfo', sources.get('uuid'))
-    if not item:
-        return dict(code=4, detail=f"Reason: 查询为空")
-
-    # --- check ---
-    # if not item.get('current_vehicle_direction'):
-    #     return dict(code=5, detail=f"Reason: 参数缺失")
-
-    # --- check ---
-    # if not item.get('current_vehicle_direction') in [3, 9, 6, 12]:
-    #     return dict(code=6, detail=f"Reason: 不具备启动条件")
-
-    # --- check ---
-    if not item.get('state') or item.get('state') != 2:
-        return dict(code=7, detail=f"Reason: 状态错误")
-
-    # --- get navigation ---
-    from unit.Scheduler_d1 import test
-    navigation = test(current_direction_type=item.get('current_vehicle_direction'),
-                      start_x=item.get('coordinate_x'),
-                      start_y=item.get('coordinate_y'),
-                      target_point_name=sources.get('target_point_name'))
-
-    # --- send --- todo 拼接数据,发送给车端
-    methods.debug_log('hs3000.code_3004.86:', f"#navigation: {navigation}")
-    # Global.http_api.cmd1001(address=item.get('address'), navigation=navigation)
-
-    # --- save ---
-    """
-    VehicleTaskList: 渣包车自动驾驶任务信息表
-    VehicleTaskList.uuid: 任务id
-    VehicleTaskList.vehicle_uuid: 车辆id
-    VehicleTaskList.task_type: 任务类型 101 自动驾驶 102 叉包 103 放包 104 倒渣
-    VehicleTaskList.target_point_name: 目标点名称
-    VehicleTaskList.task_state: 任务状态 1 已经下发 2 已完成 3 中止 4 失败
-    VehicleTaskList.create_at: 创建时间
-    """
-    data = {
-        'vehicle_uuid': sources.get('uuid'),
-        'task_type': sources.get('task_type'),
-        'target_point_name': sources.get('target_point_name'),
-        'task_state': 1,  # 任务状态 1 已经下发 2 已完成 3 中止 4 失败
-        'create_at': methods.now_ts(),
-    }
-    uuid = Global.mdb.add('VehicleTaskList', data)
-    return dict(code=0, data=uuid)
-
-
-async def code_3005(**sources):
-    """
-    获取指定任务信息
-    """
-    uuid = sources.get('uuid')
-    if not uuid:
-        return dict(code=1, detail=f"Reason: 参数缺失")
-
-    item = Global.mdb.get_one_by_id('VehicleTaskList', uuid)
-    if not item:
-        return dict(code=2, detail=f"Reason: 查无数据")
-
-    # --- check ---
-    vehicle_uuid = item.get('vehicle_uuid')
-    vehicle = Global.mdb.get_one_by_id('VehicleInfo', vehicle_uuid)
-    if not vehicle:
-        return dict(code=3, detail=f"Reason: 查无数据")
-
-    # --- check ---
-    state = vehicle.get('state')
-    if not state:
-        return dict(code=4, detail=f"Reason: 参数缺失")
-
-    # --- check --- todo 需要改成socket通信方式,接收车端消息来更新任务状态
-    """
-    VehicleTaskList: 渣包车自动驾驶任务信息表
-    VehicleTaskList.uuid: 任务id
-    VehicleTaskList.vehicle_uuid: 车辆id
-    VehicleTaskList.task_type: 任务类型 101 自动驾驶 102 叉包 103 放包 104 倒渣
-    VehicleTaskList.target_point_name: 目标点名称
-    VehicleTaskList.task_state: 任务状态 1 已经下发 2 已完成 3 中止 4 失败
-    VehicleTaskList.create_at: 创建时间
-    """
-    if state == 2:
-        Global.mdb.update_one_by_id('VehicleTaskList', uuid, {'task_state': 2})
-
-    # --- fill ---
-    item.pop('_id')
-    item['uuid'] = uuid
-    item['task_state'] = 2
-    return dict(code=0, data=item)

+ 0 - 38
project-fastapi-hs/api/v5/hs4000.py

@@ -1,38 +0,0 @@
-from hub import methods, Global
-
-
-async def code_4001(**sources):
-    """
-    获取全部渣包状态数据接口
-    """
-    # --- fill d1 ---
-    d1 = Global.enfei_api.get_pot_list()
-
-    # --- check ----
-    if type(d1) != list:
-        reason, detail = d1
-        return dict(code=1, data=[], reason=reason, detail=detail)
-
-    # --- fill d2 ---
-    d2 = list()
-    d3 = list(reversed(d1))
-    d4 = list(['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N'])  # 排
-    d5 = list(range(31))  # 罐数
-    count = 0
-    for i in d4:
-        for j in d5:
-            # --- define ---
-            data = {
-                'pot_name': f"{i}.{j + 1}",  # 渣罐别称
-                'pot_status': 0,  # 渣罐状态 1 空位 2 就绪 3 缓冷(空冷) 4 水冷 5 自冷(水冷) 6 待倒 7 故障
-                'pot_number': '',  # 渣罐编号
-            }
-            # --- update ---
-            # methods.debug_log('hs4000.code_4001.48:', f"#count: {count}")
-            data['pot_status'] = d3[count].get('packageStatus')
-            data['pot_number'] = d3[count].get('localNumber')
-            d2.append(data)
-            # methods.debug_log('hs4000.code_4001.52:', f"#data: {data}")
-            count += 1
-
-    return dict(code=0, data=d2)

+ 0 - 12
project-fastapi-hs/api/v5/hs5000.py

@@ -1,12 +0,0 @@
-from hub import methods, Global
-
-
-async def code_5001(**sources):
-    """
-    获取告警数据列表接口
-    1.2023.12.13 08:48 1号车油量低 请及时加油!
-    """
-    data = [
-        {'message': '1号车油量低,请及时加油!', 'create_at': 1704435199}
-    ]
-    return dict(code=0, data=data)

+ 0 - 457
project-fastapi-hs/data/SRI2024032814-4point.py

@@ -1,457 +0,0 @@
-"""
-大 小 英文 中文 常用指代意义
-Α α alpha 阿尔法 角度、系数、角加速度、第一个、电离度、转化率
-Β β beta 贝塔 磁通系数、角度、系数
-Γ γ gamma 伽玛 电导系数、角度、比热容比
-Δ δ delta 得尔塔 变化量、焓变、熵变、屈光度、一元二次方程中的判别式、化学位移
-Ε ε epsilon 艾普西隆 对数之基数、介电常数、电容率
-Ζ ζ zeta 泽塔 系数、方位角、阻抗、相对黏度
-Η η eta 伊塔 迟滞系数、机械效率
-Θ θ theta 西塔 温度、角度
-Ι ι iota 约(yāo)塔 微小、一点
-Κ κ kappa 卡帕 介质常数、绝热指数
-∧ λ lambda 拉姆达 波长、体积、导热系数 普朗克常数
-Μ μ mu 谬 磁导率、微、动摩擦系(因)数、流体动力黏度、货币单位,莫比乌斯函数
-Ν ν nu 纽 磁阻系数、流体运动粘度、光波频率、化学计量数
-Ξ ξ xi 克西 随机变量、(小)区间内的一个未知特定值
-Ο ο omicron 奥米克戎 高阶无穷小函数
-∏ π pi 派 圆周率、π(n)表示不大于n的质数个数、连乘
-Ρ ρ rho 柔 电阻率、柱坐标和极坐标中的极径、密度、曲率半径
-∑ σ,ς sigma 西格马 总和、表面密度、跨导、正应力、电导率
-Τ τ tau 陶 时间常数、切应力、2π(两倍圆周率)
-Υ υ upsilon 阿普西龙 位移
-Φ φ phi 斐 磁通量、电通量、角、透镜焦度、热流量、电势、直径、空集、欧拉函数
-Χ χ chi 希 统计学中有卡方(χ^2)分布
-Ψ ψ psi 普西 角速、介质电通量、ψ函数、磁链
-Ω ω omega 欧米伽 欧姆、角速度、角频率、交流电的电角度、化学中的质量分数、不饱和度
-"""
-import math
-import numpy
-import json
-
-# 道路名称列表
-path_name_list = [
-    'MN',
-    'KL',
-    'IJ',
-    'GH',
-    'EF',
-    'CD',
-    'AB',
-]
-
-
-def get_path_name_by_pot_name(pot_name):
-    """
-    根据罐名获取道路名称
-    """
-    s1, s2 = pot_name.split('.')
-    for item in path_name_list:
-        if s1 in item:
-            return item
-
-
-def get_two_end_point_by_theta_and_delta(start_point=(1, 1), theta=45, delta=1.1):
-    """
-    获取指定偏移量的两个点
-    """
-    start_point_x = start_point[0]
-    start_point_y = start_point[1]
-    theta = degrees_to_radians(theta)
-    x1 = start_point_x + (delta * numpy.cos(theta))
-    y1 = start_point_y + (delta * numpy.sin(theta))
-    x2 = start_point_x - (delta * numpy.cos(theta))
-    y2 = start_point_y - (delta * numpy.sin(theta))
-    # print(f"dubug.136: p1: {(x1, y1)}, p2: {(x2, y2)}")
-    return (x1, y1), (x2, y2)
-
-
-def get_distance_by_two_point(A=(1, 1), B=(1, 1)):
-    """
-    求两点之间的距离
-    """
-    A_x = float(A[0])
-    A_y = float(A[1])
-    B_x = float(B[0])
-    B_y = float(B[1])
-    distance = ((A_x - B_x) ** 2 + ((A_y - B_y) ** 2)) ** (1 / 2)
-    # print(f"dubug.53: 点{A}、点{B},距离为{s}")
-    return distance
-
-
-# def get_point_by_k_and_s(k=3, s=10):
-#     """
-#     已知一个点坐标,和一条线斜率,求顺着这条线指定距离后的坐标
-#     """
-#     # 计算倾斜角度 theta | θ = arctan(k)
-#     theta = numpy.arctan(k)
-#
-#     # 计算新点坐标 (x2, y2)
-#     x2 = x1 + (s * math.cos(theta))
-#     y2 = y1 + (s * math.sin(theta))
-#     # print(f"dubug.67: 增加{s}单位长度后的新点坐标 ({x2}, {y2})")
-#     return x2, y2
-
-def get_a_and_b_by_c_and_min_theta(c=13.7, min_theta=1):
-    """
-    根据直角三角形最小角和斜边,计算直角三角形直角边a、b
-    """
-    a = c * numpy.sin(degrees_to_radians(min_theta))
-    b = c * numpy.cos(degrees_to_radians(min_theta))
-    return a, b
-
-
-# def calc_theta():
-#     """
-#     计算倾斜角度
-#     """
-#     import math
-#
-#     # 已知函数 y = 3x + 2
-#     def f(x):
-#         return 3 * x + 2
-#
-#     # 已知点的坐标 (x1, y1)
-#     x1 = 1
-#     y1 = f(x1)
-#
-#     # 计算斜率 k
-#     k = 3
-#
-#     # 计算倾斜角度 theta | θ = arctan(k)
-#     theta = math.atan(k)
-#
-#     # 计算新点坐标 (x2, y2)
-#     delta_x = 10 * math.cos(theta)
-#     delta_y = 10 * math.sin(theta)
-#
-#     x2 = x1 + delta_x
-#     y2 = y1 + delta_y
-#
-#     print("已知点坐标 (x1, y1) =", (x1, y1))
-#     print("增加 10 个单位长度后的新点坐标 (x2, y2) =", (x2, y2))
-
-
-def get_k_and_b_by_points(A, B):
-    """
-    计算k与b
-    pip install sympy==1.12
-    """
-    x1 = A[0]
-    y1 = A[1]
-    x2 = B[0]
-    y2 = B[1]
-
-    from sympy import symbols, Eq, solve, Symbol
-    k = Symbol('k')
-    b = Symbol('b')
-    eqs = [Eq(k * x1 + b, y1), Eq(k * x2 + b, y2)]
-    result = solve(eqs, [k, b])
-    k = result.get(k)
-    b = result.get(b)
-    # print(f"dubug.119: y = {k}x + {b}")
-    return k, b
-
-
-def get_theta_by_k(k):
-    """
-    根据斜率计算夹角
-    """
-    theta = numpy.arctan(float(k))
-    # print(f"dubug.128: theta: {radians_to_degrees(theta)}")
-    return theta
-
-
-def degrees_to_radians(degrees):
-    """角度转弧度"""
-    return numpy.radians(degrees)
-
-
-def radians_to_degrees(radians):
-    """弧度转角度"""
-    return numpy.degrees(radians)
-
-
-def get_pi():
-    """圆周率"""
-    return numpy.pi
-
-
-def get_radians_for_90():
-    """获取90度对应的弧度"""
-    return numpy.pi / 2
-
-
-def main(MN01, MN31, A01, A31):
-    """
-    """
-    # --- fill v1 巷道间隔距离 ---
-    distance = get_distance_by_two_point(A01, MN01)
-    v1 = distance / 7
-    # print(f"debug.164: 巷道间隔距离: {v1}")
-
-    # --- fill v2 坐标系偏移角度 ---
-    k, b = get_k_and_b_by_points(A01, MN01)
-    v2 = get_theta_by_k(k)
-    v2 = radians_to_degrees(v2)
-    print(f"debug.164: 坐标系偏移角度: {90-v2}")
-
-    # --- fill d1 ---
-    _, KL01 = get_two_end_point_by_theta_and_delta(start_point=MN01, theta=v2, delta=v1)
-    _, IJ01 = get_two_end_point_by_theta_and_delta(start_point=MN01, theta=v2, delta=v1 * 2)
-    _, GH01 = get_two_end_point_by_theta_and_delta(start_point=MN01, theta=v2, delta=v1 * 3)
-    _, EF01 = get_two_end_point_by_theta_and_delta(start_point=MN01, theta=v2, delta=v1 * 4)
-    _, CD01 = get_two_end_point_by_theta_and_delta(start_point=MN01, theta=v2, delta=v1 * 5)
-    _, AB01 = get_two_end_point_by_theta_and_delta(start_point=MN01, theta=v2, delta=v1 * 6)
-    # print(f"debug.164: MN01: {MN01}")
-    # print(f"debug.164: KL01: {KL01}")
-    # print(f"debug.164: IJ01: {IJ01}")
-    # print(f"debug.164: GH01: {GH01}")
-    # print(f"debug.164: EF01: {EF01}")
-    # print(f"debug.164: CD01: {CD01}")
-    # print(f"debug.164: AB01: {AB01}")
-    # print(f"debug.164: A01: {A01}")
-    d1 = {
-        'MN.1': MN01,
-        'KL.1': KL01,
-        'IJ.1': IJ01,
-        'GH.1': GH01,
-        'EF.1': EF01,
-        'CD.1': CD01,
-        'AB.1': AB01,
-    }
-
-    # --- fill v3 巷道间隔距离 ---
-    distance = get_distance_by_two_point(A31, MN31)
-    v3 = distance / 7
-    # print(f"debug.188: 巷道间隔距离: {v3}")
-
-    # --- fill v4 坐标系偏移角度 ---
-    k, b = get_k_and_b_by_points(A31, MN31)
-    v4 = get_theta_by_k(k)
-    v4 = radians_to_degrees(v4)
-    print(f"debug.194: 坐标系偏移角度: {90-v4}")
-
-    # --- fill d2 ---
-    _, KL31 = get_two_end_point_by_theta_and_delta(start_point=MN31, theta=v4, delta=v3)
-    _, IJ31 = get_two_end_point_by_theta_and_delta(start_point=MN31, theta=v4, delta=v3 * 2)
-    _, GH31 = get_two_end_point_by_theta_and_delta(start_point=MN31, theta=v4, delta=v3 * 3)
-    _, EF31 = get_two_end_point_by_theta_and_delta(start_point=MN31, theta=v4, delta=v3 * 4)
-    _, CD31 = get_two_end_point_by_theta_and_delta(start_point=MN31, theta=v4, delta=v3 * 5)
-    _, AB31 = get_two_end_point_by_theta_and_delta(start_point=MN31, theta=v4, delta=v3 * 6)
-    # print(f"debug.233: MN31: {MN31}")
-    # print(f"debug.233: KL31: {KL31}")
-    # print(f"debug.233: IJ31: {IJ31}")
-    # print(f"debug.233: GH31: {GH31}")
-    # print(f"debug.233: EF31: {EF31}")
-    # print(f"debug.233: CD31: {CD31}")
-    # print(f"debug.233: AB31: {AB31}")
-    # print(f"debug.233: A31: {A31}")
-    d2 = {
-        'MN.31': MN31,
-        'KL.31': KL31,
-        'IJ.31': IJ31,
-        'GH.31': GH31,
-        'EF.31': EF31,
-        'CD.31': CD31,
-        'AB.31': AB31,
-    }
-
-    # --- fill pot_point_list ---
-    pot_point_list = list()
-    for i in list(['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N']):
-        for j in list(range(31)):
-            # --- set ---
-            pot_name = f"{i}.{j + 1}"  # 罐位名称
-            path_name = get_path_name_by_pot_name(pot_name)
-            XX01 = d1.get(f"{path_name}.1")
-            XX31 = d2.get(f"{path_name}.31")
-
-            # --- get v5 ---
-            distance = get_distance_by_two_point(XX01, XX31)
-            v5 = distance / 30
-            # --- get v6 ---
-            k, b = get_k_and_b_by_points(XX01, XX31)
-            v6 = radians_to_degrees(get_theta_by_k(k))
-            # --- get road_center ---
-            road_center, _ = get_two_end_point_by_theta_and_delta(start_point=XX01, theta=v6, delta=v5 * (j + 1 - 1))
-            road_center_x = road_center[0]  # 道路中心坐标
-            road_center_y = road_center[1]  # 道路中心坐标
-
-            # --- update ---
-            data_string = f"{pot_name}|{0}|{0}|{road_center_x}|{road_center_y}"
-            # print(data_string)
-            pot_point_list.append(data_string)
-
-    # --- check ---
-    print(f"debug.300: total: {len(pot_point_list)}")
-    if len(pot_point_list) != 434:
-        raise "Error: 数据不全"
-
-    # --- fill json_data_dict ---
-    json_data_dict = {
-        "title": "渣罐坐标数据",
-        "pot_name|pot_x|pot_y|road_center_x|road_center_y": pot_point_list,
-        "total": len(pot_point_list),
-    }
-
-    # --- save 渣罐坐标数据 ---
-    with open('渣罐坐标数据.json', "w", encoding='utf-8') as f:
-        json.dump(json_data_dict, f, indent=4, sort_keys=True, ensure_ascii=False)
-
-    # --- get v7 转弯半径 ---
-    distance = get_distance_by_two_point(A01, MN01)
-    v7 = distance / 14
-    # print(f"debug.309: 转弯半径: {v7}")
-
-    # --- fill d5 ---
-    _, LMhead = get_two_end_point_by_theta_and_delta(start_point=MN01, theta=v2, delta=v7)
-    _, JKhead = get_two_end_point_by_theta_and_delta(start_point=MN01, theta=v2, delta=v7 * 3)
-    _, HIhead = get_two_end_point_by_theta_and_delta(start_point=MN01, theta=v2, delta=v7 * 5)
-    _, FGhead = get_two_end_point_by_theta_and_delta(start_point=MN01, theta=v2, delta=v7 * 7)
-    _, DEhead = get_two_end_point_by_theta_and_delta(start_point=MN01, theta=v2, delta=v7 * 9)
-    _, BChead = get_two_end_point_by_theta_and_delta(start_point=MN01, theta=v2, delta=v7 * 11)
-    _, Ahead = get_two_end_point_by_theta_and_delta(start_point=MN01, theta=v2, delta=v7 * 13)
-    # print(f"debug.327: LMhead: {LMhead}")
-    # print(f"debug.327: JKhead: {JKhead}")
-    # print(f"debug.327: HIhead: {HIhead}")
-    # print(f"debug.327: FGhead: {FGhead}")
-    # print(f"debug.327: DEhead: {DEhead}")
-    # print(f"debug.327: BChead: {BChead}")
-    # print(f"debug.327: Ahead: {Ahead}")
-    d5 = {
-        'LM.head': LMhead,
-        'JK.head': JKhead,
-        'HI.head': HIhead,
-        'FG.head': FGhead,
-        'DE.head': DEhead,
-        'BC.head': BChead,
-        'A.head': Ahead,
-    }
-    # print(f"debug.355: 转弯半径: {d5}")
-
-    # --- test ---
-    # print(f"debug.339: 最小角度: {90 - v2}")
-    # print(f"debug.339: 斜边 c: {v7}")
-    # short, long = get_a_and_b_by_c_and_min_theta(v7, 90 - v2)
-    # print(f"debug.339: 直角边 a: {short}")
-    # print(f"debug.339: 直角边 b: {long}")
-
-    # --- fill centers_list ---
-    centers_list = list()
-    for k, v in d5.items():
-        # --- set ---
-        center_x, center_y = v
-        short, long = get_a_and_b_by_c_and_min_theta(v7, 90 - v2)
-        data_string = f"{k}|{center_x}|{center_y}"
-
-        # --- get center_3_x center_3_y --- 顺时针偏移一定角度
-        center_3_x = center_x + long
-        center_3_y = center_y - short
-        data_string += f"|{center_3_x}|{center_3_y}"
-
-        # --- get center_9_x center_9_y --- 顺时针偏移一定角度
-        center_9_x = center_x - long
-        center_9_y = center_y + short
-        data_string += f"|{center_9_x}|{center_9_y}"
-
-        # --- get center_12_x center_12_y --- 顺时针偏移一定角度
-        center_12_x = center_x + short
-        center_12_y = center_y + long
-        data_string += f"|{center_12_x}|{center_12_y}"
-
-        # --- get center_6_x center_6_y --- 顺时针偏移一定角度
-        center_6_x = center_x - short
-        center_6_y = center_y - long
-        data_string += f"|{center_6_x}|{center_6_y}"
-
-        # --- append ---
-        centers_list.append(data_string)
-
-    # --- get v201 转弯半径 ---
-    distance = get_distance_by_two_point(A31, MN31)
-    v201 = distance / 14
-    print(f"debug.309: 转弯半径: {v201}")
-
-    # --- fill tail_center_dict ---
-    _, LMtail = get_two_end_point_by_theta_and_delta(start_point=MN31, theta=v4, delta=v201)
-    _, JKtail = get_two_end_point_by_theta_and_delta(start_point=MN31, theta=v4, delta=v201 * 3)
-    _, HItail = get_two_end_point_by_theta_and_delta(start_point=MN31, theta=v4, delta=v201 * 5)
-    _, FGtail = get_two_end_point_by_theta_and_delta(start_point=MN31, theta=v4, delta=v201 * 7)
-    _, DEtail = get_two_end_point_by_theta_and_delta(start_point=MN31, theta=v4, delta=v201 * 9)
-    _, BCtail = get_two_end_point_by_theta_and_delta(start_point=MN31, theta=v4, delta=v201 * 11)
-    _, Atail = get_two_end_point_by_theta_and_delta(start_point=MN31, theta=v4, delta=v201 * 13)
-    # print(f"debug.397: LMtail: {LMtail}")
-    # print(f"debug.397: MN31: {MN31}")
-    tail_center_dict = {
-        'LM.tail': LMtail,
-        'JK.tail': JKtail,
-        'HI.tail': HItail,
-        'FG.tail': FGtail,
-        'DE.tail': DEtail,
-        'BC.tail': BCtail,
-        'A.tail': Atail,
-    }
-    # print(f"debug.355: 转弯半径: {d5}")
-
-    # --- fill centers_list ---
-    for k, v in tail_center_dict.items():
-        # --- set ---
-        center_x, center_y = v
-        short, long = get_a_and_b_by_c_and_min_theta(v201, 90 - v4)
-        data_string = f"{k}|{center_x}|{center_y}"
-
-        # --- get center_3_x center_3_y --- 顺时针偏移一定角度
-        center_3_x = center_x + long
-        center_3_y = center_y - short
-        data_string += f"|{center_3_x}|{center_3_y}"
-
-        # --- get center_9_x center_9_y --- 顺时针偏移一定角度
-        center_9_x = center_x - long
-        center_9_y = center_y + short
-        data_string += f"|{center_9_x}|{center_9_y}"
-
-        # --- get center_12_x center_12_y --- 顺时针偏移一定角度
-        center_12_x = center_x + short
-        center_12_y = center_y + long
-        data_string += f"|{center_12_x}|{center_12_y}"
-
-        # --- get center_6_x center_6_y --- 顺时针偏移一定角度
-        center_6_x = center_x - short
-        center_6_y = center_y - long
-        data_string += f"|{center_6_x}|{center_6_y}"
-
-        # --- append ---
-        centers_list.append(data_string)
-
-    # --- fill json_data_dict ---
-    json_data_dict = {
-        "title": "圆心坐标数据",
-        "name|center_x|center_y|center_3_x|center_3_y|center_9_x|center_9_y|center_12_x|center_12_y|center_6_x|center_6_y": centers_list,
-        "total": len(centers_list),
-    }
-
-    # --- save 渣罐坐标数据 ---
-    with open('圆心坐标数据.json', "w", encoding='utf-8') as f:
-        json.dump(json_data_dict, f, indent=4, sort_keys=True, ensure_ascii=False)
-
-
-if __name__ == '__main__':
-    # --- 自测数据 ---
-    L1 = 2, 2
-    L31 = 3, 1
-    N1 = 3, 3
-    N31 = 4, 2
-    # --- 大冶现场数据 ---
-    """
-    18.618844   200.675670   mn-1  "M.1|0|0|18.618844|200.67567",
-    14.24217    8.016018     a-1
-    179.503282   5.019985     a-31
-    183.184822   197.312110   mn-31  "M.31|0|0|183.184822|197.31211",
-    """
-    MN01 = 18.618844, 200.675670
-    A01 = 14.24217, 8.016018
-    A31 = 179.503282, 5.019985
-    MN31 = 183.184822, 197.312110
-    # --- test ---
-    main(MN01, MN31, A01, A31)

+ 0 - 5
project-fastapi-hs/data/SRI2024032814-4point.txt

@@ -1,5 +0,0 @@
-   X            Y         ID
-18.618844   200.675670   mn-1
-14.24217    8.016018     a-1
-179.503282   5.019985     a-31
-183.184822   197.312110   mn-31

+ 0 - 13
project-fastapi-hs/data/倒渣口坐标数据.json

@@ -1,13 +0,0 @@
-{
-    "name|x|y": [
-        "dump.MN|4.18|205.75",
-        "dump.KL|4.18|177.75",
-        "dump.IJ|4.18|149.75",
-        "dump.GH|4.18|121.75",
-        "dump.EF|4.18|93.75",
-        "dump.CD|4.18|65.75",
-        "dump.AB|4.18|37.75"
-    ],
-    "title": "倒渣口坐标数据",
-    "total": 7
-}

+ 0 - 20
project-fastapi-hs/data/圆心坐标数据.json

@@ -1,20 +0,0 @@
-{
-    "name|center_x|center_y|center_3_x|center_3_y|center_9_x|center_9_y|center_12_x|center_12_y|center_6_x|center_6_y": [
-        "LM.head|18.306224428571426|186.9142662857143|32.06762814285714|186.60164671428572|4.544820714285713|187.22688585714286|18.618844|200.67567|17.993604857142852|173.15286257142859",
-        "JK.head|17.680985285714282|159.39145885714285|31.442388999999995|159.07883928571428|3.9195815714285693|159.70407842857142|17.993604857142856|173.15286257142856|17.36836571428571|145.63005514285715",
-        "HI.head|17.055746142857135|131.8686514285714|30.817149857142848|131.55603185714284|3.2943424285714222|132.18127099999998|17.36836571428571|145.63005514285712|16.74312657142856|118.1072477142857",
-        "FG.head|16.43050699999999|104.345844|30.191910714285704|104.03322442857143|2.6691032857142787|104.65846357142857|16.743126571428565|118.1072477142857|16.117887428571418|90.5844402857143",
-        "DE.head|15.805267857142846|76.82303657142857|29.566671571428557|76.510417|2.0438641428571334|77.13565614285714|16.117887428571418|90.5844402857143|15.492648285714274|63.06163285714286",
-        "BC.head|15.1800287142857|49.30022914285715|28.941432428571414|48.98760957142858|1.418624999999988|49.61284871428572|15.492648285714273|63.06163285714286|14.867409142857129|35.538825428571435",
-        "A.head|14.554789571428557|21.777421714285737|28.31619328571427|21.464802142857163|0.7933858571428445|22.09004128571431|14.867409142857129|35.53882542857145|14.242169999999986|8.016018000000024",
-        "LM.tail|182.92185485714285|183.5769582142857|196.65700664285714|183.31399107142855|169.18670307142855|183.83992535714285|183.184822|197.31211|182.6588877142857|169.8418064285714",
-        "JK.tail|182.39592057142858|156.10665464285714|196.13107235714287|155.8436875|168.66076878571428|156.3696217857143|182.65888771428573|169.84180642857143|182.13295342857143|142.37150285714284",
-        "HI.tail|181.86998628571428|128.63635107142855|195.60513807142857|128.3733839285714|168.13483449999998|128.8993182142857|182.13295342857143|142.37150285714284|181.60701914285713|114.90119928571426",
-        "FG.tail|181.344052|101.16604749999998|195.0792037857143|100.90308035714284|167.6089002142857|101.42901464285711|181.60701914285715|114.90119928571426|181.08108485714286|87.4308957142857",
-        "DE.tail|180.8181177142857|73.6957439285714|194.5532695|73.43277678571427|167.0829659285714|73.95871107142854|181.08108485714286|87.4308957142857|180.55515057142856|59.96059214285712",
-        "BC.tail|180.29218342857143|46.225440357142844|194.02733521428573|45.9624732142857|166.55703164285714|46.48840749999999|180.55515057142858|59.96059214285713|180.02921628571428|32.49028857142856",
-        "A.tail|179.76624914285713|18.755136785714257|193.50140092857143|18.492169642857114|166.03109735714284|19.0181039285714|180.02921628571428|32.49028857142854|179.50328199999998|5.01998499999997"
-    ],
-    "title": "圆心坐标数据",
-    "total": 14
-}

+ 0 - 440
project-fastapi-hs/data/渣罐坐标数据.json

@@ -1,440 +0,0 @@
-{
-    "pot_name|pot_x|pot_y|road_center_x|road_center_y": [
-        "A.1|0|0|14.867409142857127|35.538825428571414",
-        "A.2|0|0|20.372802714285697|35.437207533333314",
-        "A.3|0|0|25.87819628571427|35.33558963809522",
-        "A.4|0|0|31.38358985714284|35.23397174285712",
-        "A.5|0|0|36.888983428571414|35.13235384761903",
-        "A.6|0|0|42.39437699999999|35.03073595238093",
-        "A.7|0|0|47.899770571428554|34.92911805714283",
-        "A.8|0|0|53.40516414285713|34.82750016190474",
-        "A.9|0|0|58.9105577142857|34.72588226666664",
-        "A.10|0|0|64.41595128571427|34.624264371428545",
-        "A.11|0|0|69.92134485714286|34.522646476190445",
-        "A.12|0|0|75.42673842857141|34.421028580952346",
-        "A.13|0|0|80.93213199999998|34.31941068571425",
-        "A.14|0|0|86.43752557142857|34.21779279047615",
-        "A.15|0|0|91.94291914285714|34.11617489523806",
-        "A.16|0|0|97.4483127142857|34.01455699999996",
-        "A.17|0|0|102.95370628571428|33.91293910476186",
-        "A.18|0|0|108.45909985714285|33.81132120952377",
-        "A.19|0|0|113.96449342857143|33.70970331428567",
-        "A.20|0|0|119.469887|33.608085419047576",
-        "A.21|0|0|124.97528057142857|33.50646752380948",
-        "A.22|0|0|130.48067414285714|33.404849628571384",
-        "A.23|0|0|135.9860677142857|33.303231733333284",
-        "A.24|0|0|141.4914612857143|33.201613838095184",
-        "A.25|0|0|146.99685485714284|33.09999594285709",
-        "A.26|0|0|152.50224842857142|32.99837804761899",
-        "A.27|0|0|158.007642|32.8967601523809",
-        "A.28|0|0|163.5130355714286|32.7951422571428",
-        "A.29|0|0|169.01842914285714|32.6935243619047",
-        "A.30|0|0|174.52382271428573|32.59190646666661",
-        "A.31|0|0|180.02921628571428|32.49028857142851",
-        "B.1|0|0|14.867409142857127|35.538825428571414",
-        "B.2|0|0|20.372802714285697|35.437207533333314",
-        "B.3|0|0|25.87819628571427|35.33558963809522",
-        "B.4|0|0|31.38358985714284|35.23397174285712",
-        "B.5|0|0|36.888983428571414|35.13235384761903",
-        "B.6|0|0|42.39437699999999|35.03073595238093",
-        "B.7|0|0|47.899770571428554|34.92911805714283",
-        "B.8|0|0|53.40516414285713|34.82750016190474",
-        "B.9|0|0|58.9105577142857|34.72588226666664",
-        "B.10|0|0|64.41595128571427|34.624264371428545",
-        "B.11|0|0|69.92134485714286|34.522646476190445",
-        "B.12|0|0|75.42673842857141|34.421028580952346",
-        "B.13|0|0|80.93213199999998|34.31941068571425",
-        "B.14|0|0|86.43752557142857|34.21779279047615",
-        "B.15|0|0|91.94291914285714|34.11617489523806",
-        "B.16|0|0|97.4483127142857|34.01455699999996",
-        "B.17|0|0|102.95370628571428|33.91293910476186",
-        "B.18|0|0|108.45909985714285|33.81132120952377",
-        "B.19|0|0|113.96449342857143|33.70970331428567",
-        "B.20|0|0|119.469887|33.608085419047576",
-        "B.21|0|0|124.97528057142857|33.50646752380948",
-        "B.22|0|0|130.48067414285714|33.404849628571384",
-        "B.23|0|0|135.9860677142857|33.303231733333284",
-        "B.24|0|0|141.4914612857143|33.201613838095184",
-        "B.25|0|0|146.99685485714284|33.09999594285709",
-        "B.26|0|0|152.50224842857142|32.99837804761899",
-        "B.27|0|0|158.007642|32.8967601523809",
-        "B.28|0|0|163.5130355714286|32.7951422571428",
-        "B.29|0|0|169.01842914285714|32.6935243619047",
-        "B.30|0|0|174.52382271428573|32.59190646666661",
-        "B.31|0|0|180.02921628571428|32.49028857142851",
-        "C.1|0|0|15.492648285714273|63.061632857142854",
-        "C.2|0|0|20.994731695238084|62.95826483333333",
-        "C.3|0|0|26.496815104761893|62.8548968095238",
-        "C.4|0|0|31.998898514285706|62.75152878571428",
-        "C.5|0|0|37.50098192380951|62.64816076190475",
-        "C.6|0|0|43.003065333333325|62.544792738095225",
-        "C.7|0|0|48.50514874285714|62.441424714285695",
-        "C.8|0|0|54.00723215238095|62.33805669047617",
-        "C.9|0|0|59.50931556190476|62.23468866666664",
-        "C.10|0|0|65.01139897142856|62.13132064285712",
-        "C.11|0|0|70.51348238095237|62.02795261904759",
-        "C.12|0|0|76.01556579047619|61.924584595238066",
-        "C.13|0|0|81.5176492|61.821216571428536",
-        "C.14|0|0|87.0197326095238|61.71784854761901",
-        "C.15|0|0|92.52181601904762|61.61448052380948",
-        "C.16|0|0|98.02389942857143|61.51111249999996",
-        "C.17|0|0|103.52598283809523|61.40774447619043",
-        "C.18|0|0|109.02806624761904|61.30437645238091",
-        "C.19|0|0|114.53014965714284|61.20100842857138",
-        "C.20|0|0|120.03223306666665|61.097640404761854",
-        "C.21|0|0|125.53431647619047|60.994272380952324",
-        "C.22|0|0|131.0363998857143|60.8909043571428",
-        "C.23|0|0|136.5384832952381|60.78753633333327",
-        "C.24|0|0|142.04056670476191|60.68416830952375",
-        "C.25|0|0|147.54265011428572|60.58080028571422",
-        "C.26|0|0|153.04473352380953|60.477432261904696",
-        "C.27|0|0|158.54681693333333|60.374064238095166",
-        "C.28|0|0|164.04890034285714|60.27069621428564",
-        "C.29|0|0|169.55098375238097|60.16732819047611",
-        "C.30|0|0|175.05306716190475|60.06396016666659",
-        "C.31|0|0|180.55515057142858|59.96059214285706",
-        "D.1|0|0|15.492648285714273|63.061632857142854",
-        "D.2|0|0|20.994731695238084|62.95826483333333",
-        "D.3|0|0|26.496815104761893|62.8548968095238",
-        "D.4|0|0|31.998898514285706|62.75152878571428",
-        "D.5|0|0|37.50098192380951|62.64816076190475",
-        "D.6|0|0|43.003065333333325|62.544792738095225",
-        "D.7|0|0|48.50514874285714|62.441424714285695",
-        "D.8|0|0|54.00723215238095|62.33805669047617",
-        "D.9|0|0|59.50931556190476|62.23468866666664",
-        "D.10|0|0|65.01139897142856|62.13132064285712",
-        "D.11|0|0|70.51348238095237|62.02795261904759",
-        "D.12|0|0|76.01556579047619|61.924584595238066",
-        "D.13|0|0|81.5176492|61.821216571428536",
-        "D.14|0|0|87.0197326095238|61.71784854761901",
-        "D.15|0|0|92.52181601904762|61.61448052380948",
-        "D.16|0|0|98.02389942857143|61.51111249999996",
-        "D.17|0|0|103.52598283809523|61.40774447619043",
-        "D.18|0|0|109.02806624761904|61.30437645238091",
-        "D.19|0|0|114.53014965714284|61.20100842857138",
-        "D.20|0|0|120.03223306666665|61.097640404761854",
-        "D.21|0|0|125.53431647619047|60.994272380952324",
-        "D.22|0|0|131.0363998857143|60.8909043571428",
-        "D.23|0|0|136.5384832952381|60.78753633333327",
-        "D.24|0|0|142.04056670476191|60.68416830952375",
-        "D.25|0|0|147.54265011428572|60.58080028571422",
-        "D.26|0|0|153.04473352380953|60.477432261904696",
-        "D.27|0|0|158.54681693333333|60.374064238095166",
-        "D.28|0|0|164.04890034285714|60.27069621428564",
-        "D.29|0|0|169.55098375238097|60.16732819047611",
-        "D.30|0|0|175.05306716190475|60.06396016666659",
-        "D.31|0|0|180.55515057142858|59.96059214285706",
-        "E.1|0|0|16.117887428571418|90.5844402857143",
-        "E.2|0|0|21.616660676190467|90.47932213333334",
-        "E.3|0|0|27.115433923809515|90.37420398095239",
-        "E.4|0|0|32.61420717142856|90.26908582857143",
-        "E.5|0|0|38.11298041904762|90.16396767619048",
-        "E.6|0|0|43.61175366666666|90.05884952380953",
-        "E.7|0|0|49.110526914285714|89.95373137142857",
-        "E.8|0|0|54.609300161904756|89.84861321904762",
-        "E.9|0|0|60.10807340952381|89.74349506666667",
-        "E.10|0|0|65.60684665714285|89.63837691428571",
-        "E.11|0|0|71.10561990476191|89.53325876190476",
-        "E.12|0|0|76.60439315238095|89.42814060952381",
-        "E.13|0|0|82.1031664|89.32302245714286",
-        "E.14|0|0|87.60193964761906|89.2179043047619",
-        "E.15|0|0|93.1007128952381|89.11278615238095",
-        "E.16|0|0|98.59948614285715|89.007668",
-        "E.17|0|0|104.0982593904762|88.90254984761904",
-        "E.18|0|0|109.59703263809524|88.79743169523809",
-        "E.19|0|0|115.0958058857143|88.69231354285714",
-        "E.20|0|0|120.59457913333334|88.58719539047618",
-        "E.21|0|0|126.0933523809524|88.48207723809523",
-        "E.22|0|0|131.59212562857144|88.37695908571428",
-        "E.23|0|0|137.09089887619047|88.27184093333332",
-        "E.24|0|0|142.58967212380952|88.16672278095237",
-        "E.25|0|0|148.08844537142858|88.06160462857142",
-        "E.26|0|0|153.58721861904763|87.95648647619046",
-        "E.27|0|0|159.0859918666667|87.85136832380951",
-        "E.28|0|0|164.58476511428572|87.74625017142856",
-        "E.29|0|0|170.08353836190477|87.6411320190476",
-        "E.30|0|0|175.58231160952383|87.53601386666665",
-        "E.31|0|0|181.08108485714286|87.4308957142857",
-        "F.1|0|0|16.117887428571418|90.5844402857143",
-        "F.2|0|0|21.616660676190467|90.47932213333334",
-        "F.3|0|0|27.115433923809515|90.37420398095239",
-        "F.4|0|0|32.61420717142856|90.26908582857143",
-        "F.5|0|0|38.11298041904762|90.16396767619048",
-        "F.6|0|0|43.61175366666666|90.05884952380953",
-        "F.7|0|0|49.110526914285714|89.95373137142857",
-        "F.8|0|0|54.609300161904756|89.84861321904762",
-        "F.9|0|0|60.10807340952381|89.74349506666667",
-        "F.10|0|0|65.60684665714285|89.63837691428571",
-        "F.11|0|0|71.10561990476191|89.53325876190476",
-        "F.12|0|0|76.60439315238095|89.42814060952381",
-        "F.13|0|0|82.1031664|89.32302245714286",
-        "F.14|0|0|87.60193964761906|89.2179043047619",
-        "F.15|0|0|93.1007128952381|89.11278615238095",
-        "F.16|0|0|98.59948614285715|89.007668",
-        "F.17|0|0|104.0982593904762|88.90254984761904",
-        "F.18|0|0|109.59703263809524|88.79743169523809",
-        "F.19|0|0|115.0958058857143|88.69231354285714",
-        "F.20|0|0|120.59457913333334|88.58719539047618",
-        "F.21|0|0|126.0933523809524|88.48207723809523",
-        "F.22|0|0|131.59212562857144|88.37695908571428",
-        "F.23|0|0|137.09089887619047|88.27184093333332",
-        "F.24|0|0|142.58967212380952|88.16672278095237",
-        "F.25|0|0|148.08844537142858|88.06160462857142",
-        "F.26|0|0|153.58721861904763|87.95648647619046",
-        "F.27|0|0|159.0859918666667|87.85136832380951",
-        "F.28|0|0|164.58476511428572|87.74625017142856",
-        "F.29|0|0|170.08353836190477|87.6411320190476",
-        "F.30|0|0|175.58231160952383|87.53601386666665",
-        "F.31|0|0|181.08108485714286|87.4308957142857",
-        "G.1|0|0|16.743126571428565|118.1072477142857",
-        "G.2|0|0|22.23858965714285|118.00037943333331",
-        "G.3|0|0|27.734052742857134|117.89351115238091",
-        "G.4|0|0|33.22951582857142|117.78664287142851",
-        "G.5|0|0|38.7249789142857|117.6797745904761",
-        "G.6|0|0|44.22044199999999|117.5729063095237",
-        "G.7|0|0|49.71590508571427|117.4660380285713",
-        "G.8|0|0|55.21136817142856|117.3591697476189",
-        "G.9|0|0|60.70683125714284|117.25230146666651",
-        "G.10|0|0|66.20229434285713|117.14543318571411",
-        "G.11|0|0|71.6977574285714|117.0385649047617",
-        "G.12|0|0|77.1932205142857|116.9316966238093",
-        "G.13|0|0|82.68868359999998|116.8248283428569",
-        "G.14|0|0|88.18414668571427|116.7179600619045",
-        "G.15|0|0|93.67960977142855|116.61109178095211",
-        "G.16|0|0|99.17507285714284|116.50422349999971",
-        "G.17|0|0|104.67053594285711|116.3973552190473",
-        "G.18|0|0|110.16599902857139|116.2904869380949",
-        "G.19|0|0|115.66146211428568|116.1836186571425",
-        "G.20|0|0|121.15692519999996|116.0767503761901",
-        "G.21|0|0|126.65238828571425|115.96988209523771",
-        "G.22|0|0|132.14785137142854|115.86301381428531",
-        "G.23|0|0|137.64331445714282|115.7561455333329",
-        "G.24|0|0|143.1387775428571|115.6492772523805",
-        "G.25|0|0|148.6342406285714|115.5424089714281",
-        "G.26|0|0|154.12970371428568|115.4355406904757",
-        "G.27|0|0|159.6251668|115.3286724095233",
-        "G.28|0|0|165.12062988571424|115.22180412857091",
-        "G.29|0|0|170.61609297142854|115.1149358476185",
-        "G.30|0|0|176.11155605714282|115.0080675666661",
-        "G.31|0|0|181.60701914285713|114.9011992857137",
-        "H.1|0|0|16.743126571428565|118.1072477142857",
-        "H.2|0|0|22.23858965714285|118.00037943333331",
-        "H.3|0|0|27.734052742857134|117.89351115238091",
-        "H.4|0|0|33.22951582857142|117.78664287142851",
-        "H.5|0|0|38.7249789142857|117.6797745904761",
-        "H.6|0|0|44.22044199999999|117.5729063095237",
-        "H.7|0|0|49.71590508571427|117.4660380285713",
-        "H.8|0|0|55.21136817142856|117.3591697476189",
-        "H.9|0|0|60.70683125714284|117.25230146666651",
-        "H.10|0|0|66.20229434285713|117.14543318571411",
-        "H.11|0|0|71.6977574285714|117.0385649047617",
-        "H.12|0|0|77.1932205142857|116.9316966238093",
-        "H.13|0|0|82.68868359999998|116.8248283428569",
-        "H.14|0|0|88.18414668571427|116.7179600619045",
-        "H.15|0|0|93.67960977142855|116.61109178095211",
-        "H.16|0|0|99.17507285714284|116.50422349999971",
-        "H.17|0|0|104.67053594285711|116.3973552190473",
-        "H.18|0|0|110.16599902857139|116.2904869380949",
-        "H.19|0|0|115.66146211428568|116.1836186571425",
-        "H.20|0|0|121.15692519999996|116.0767503761901",
-        "H.21|0|0|126.65238828571425|115.96988209523771",
-        "H.22|0|0|132.14785137142854|115.86301381428531",
-        "H.23|0|0|137.64331445714282|115.7561455333329",
-        "H.24|0|0|143.1387775428571|115.6492772523805",
-        "H.25|0|0|148.6342406285714|115.5424089714281",
-        "H.26|0|0|154.12970371428568|115.4355406904757",
-        "H.27|0|0|159.6251668|115.3286724095233",
-        "H.28|0|0|165.12062988571424|115.22180412857091",
-        "H.29|0|0|170.61609297142854|115.1149358476185",
-        "H.30|0|0|176.11155605714282|115.0080675666661",
-        "H.31|0|0|181.60701914285713|114.9011992857137",
-        "I.1|0|0|17.36836571428571|145.63005514285715",
-        "I.2|0|0|22.860518638095233|145.52143673333333",
-        "I.3|0|0|28.352671561904756|145.41281832380955",
-        "I.4|0|0|33.844824485714284|145.30419991428573",
-        "I.5|0|0|39.336977409523804|145.19558150476195",
-        "I.6|0|0|44.829130333333325|145.08696309523813",
-        "I.7|0|0|50.32128325714285|144.97834468571435",
-        "I.8|0|0|55.81343618095237|144.86972627619053",
-        "I.9|0|0|61.3055891047619|144.76110786666675",
-        "I.10|0|0|66.79774202857143|144.65248945714293",
-        "I.11|0|0|72.28989495238095|144.54387104761915",
-        "I.12|0|0|77.78204787619048|144.43525263809533",
-        "I.13|0|0|83.27420079999999|144.32663422857155",
-        "I.14|0|0|88.76635372380952|144.21801581904774",
-        "I.15|0|0|94.25850664761904|144.10939740952395",
-        "I.16|0|0|99.75065957142857|144.00077900000014",
-        "I.17|0|0|105.2428124952381|143.89216059047635",
-        "I.18|0|0|110.73496541904763|143.78354218095254",
-        "I.19|0|0|116.22711834285715|143.67492377142875",
-        "I.20|0|0|121.71927126666665|143.56630536190494",
-        "I.21|0|0|127.21142419047618|143.45768695238115",
-        "I.22|0|0|132.7035771142857|143.34906854285734",
-        "I.23|0|0|138.19573003809523|143.24045013333355",
-        "I.24|0|0|143.68788296190476|143.13183172380974",
-        "I.25|0|0|149.1800358857143|143.02321331428593",
-        "I.26|0|0|154.67218880952382|142.91459490476214",
-        "I.27|0|0|160.16434173333334|142.80597649523833",
-        "I.28|0|0|165.65649465714287|142.69735808571454",
-        "I.29|0|0|171.14864758095237|142.58873967619073",
-        "I.30|0|0|176.64080050476193|142.48012126666694",
-        "I.31|0|0|182.13295342857143|142.37150285714313",
-        "J.1|0|0|17.36836571428571|145.63005514285715",
-        "J.2|0|0|22.860518638095233|145.52143673333333",
-        "J.3|0|0|28.352671561904756|145.41281832380955",
-        "J.4|0|0|33.844824485714284|145.30419991428573",
-        "J.5|0|0|39.336977409523804|145.19558150476195",
-        "J.6|0|0|44.829130333333325|145.08696309523813",
-        "J.7|0|0|50.32128325714285|144.97834468571435",
-        "J.8|0|0|55.81343618095237|144.86972627619053",
-        "J.9|0|0|61.3055891047619|144.76110786666675",
-        "J.10|0|0|66.79774202857143|144.65248945714293",
-        "J.11|0|0|72.28989495238095|144.54387104761915",
-        "J.12|0|0|77.78204787619048|144.43525263809533",
-        "J.13|0|0|83.27420079999999|144.32663422857155",
-        "J.14|0|0|88.76635372380952|144.21801581904774",
-        "J.15|0|0|94.25850664761904|144.10939740952395",
-        "J.16|0|0|99.75065957142857|144.00077900000014",
-        "J.17|0|0|105.2428124952381|143.89216059047635",
-        "J.18|0|0|110.73496541904763|143.78354218095254",
-        "J.19|0|0|116.22711834285715|143.67492377142875",
-        "J.20|0|0|121.71927126666665|143.56630536190494",
-        "J.21|0|0|127.21142419047618|143.45768695238115",
-        "J.22|0|0|132.7035771142857|143.34906854285734",
-        "J.23|0|0|138.19573003809523|143.24045013333355",
-        "J.24|0|0|143.68788296190476|143.13183172380974",
-        "J.25|0|0|149.1800358857143|143.02321331428593",
-        "J.26|0|0|154.67218880952382|142.91459490476214",
-        "J.27|0|0|160.16434173333334|142.80597649523833",
-        "J.28|0|0|165.65649465714287|142.69735808571454",
-        "J.29|0|0|171.14864758095237|142.58873967619073",
-        "J.30|0|0|176.64080050476193|142.48012126666694",
-        "J.31|0|0|182.13295342857143|142.37150285714313",
-        "K.1|0|0|17.993604857142856|173.15286257142856",
-        "K.2|0|0|23.48244761904762|173.0424940333333",
-        "K.3|0|0|28.97129038095238|172.932125495238",
-        "K.4|0|0|34.46013314285714|172.82175695714275",
-        "K.5|0|0|39.9489759047619|172.7113884190475",
-        "K.6|0|0|45.43781866666666|172.60101988095224",
-        "K.7|0|0|50.92666142857142|172.49065134285695",
-        "K.8|0|0|56.415504190476184|172.3802828047617",
-        "K.9|0|0|61.90434695238095|172.26991426666643",
-        "K.10|0|0|67.39318971428571|172.15954572857115",
-        "K.11|0|0|72.88203247619046|172.0491771904759",
-        "K.12|0|0|78.37087523809522|171.93880865238063",
-        "K.13|0|0|83.85971799999999|171.82844011428537",
-        "K.14|0|0|89.34856076190475|171.71807157619008",
-        "K.15|0|0|94.83740352380951|171.60770303809483",
-        "K.16|0|0|100.32624628571428|171.49733449999957",
-        "K.17|0|0|105.81508904761904|171.38696596190428",
-        "K.18|0|0|111.30393180952379|171.27659742380902",
-        "K.19|0|0|116.79277457142855|171.16622888571376",
-        "K.20|0|0|122.28161733333332|171.0558603476185",
-        "K.21|0|0|127.77046009523808|170.94549180952322",
-        "K.22|0|0|133.25930285714284|170.83512327142796",
-        "K.23|0|0|138.7481456190476|170.7247547333327",
-        "K.24|0|0|144.23698838095237|170.61438619523742",
-        "K.25|0|0|149.72583114285712|170.50401765714216",
-        "K.26|0|0|155.21467390476187|170.3936491190469",
-        "K.27|0|0|160.70351666666664|170.28328058095164",
-        "K.28|0|0|166.1923594285714|170.17291204285635",
-        "K.29|0|0|171.68120219047617|170.0625435047611",
-        "K.30|0|0|177.17004495238092|169.95217496666584",
-        "K.31|0|0|182.6588877142857|169.84180642857055",
-        "L.1|0|0|17.993604857142856|173.15286257142856",
-        "L.2|0|0|23.48244761904762|173.0424940333333",
-        "L.3|0|0|28.97129038095238|172.932125495238",
-        "L.4|0|0|34.46013314285714|172.82175695714275",
-        "L.5|0|0|39.9489759047619|172.7113884190475",
-        "L.6|0|0|45.43781866666666|172.60101988095224",
-        "L.7|0|0|50.92666142857142|172.49065134285695",
-        "L.8|0|0|56.415504190476184|172.3802828047617",
-        "L.9|0|0|61.90434695238095|172.26991426666643",
-        "L.10|0|0|67.39318971428571|172.15954572857115",
-        "L.11|0|0|72.88203247619046|172.0491771904759",
-        "L.12|0|0|78.37087523809522|171.93880865238063",
-        "L.13|0|0|83.85971799999999|171.82844011428537",
-        "L.14|0|0|89.34856076190475|171.71807157619008",
-        "L.15|0|0|94.83740352380951|171.60770303809483",
-        "L.16|0|0|100.32624628571428|171.49733449999957",
-        "L.17|0|0|105.81508904761904|171.38696596190428",
-        "L.18|0|0|111.30393180952379|171.27659742380902",
-        "L.19|0|0|116.79277457142855|171.16622888571376",
-        "L.20|0|0|122.28161733333332|171.0558603476185",
-        "L.21|0|0|127.77046009523808|170.94549180952322",
-        "L.22|0|0|133.25930285714284|170.83512327142796",
-        "L.23|0|0|138.7481456190476|170.7247547333327",
-        "L.24|0|0|144.23698838095237|170.61438619523742",
-        "L.25|0|0|149.72583114285712|170.50401765714216",
-        "L.26|0|0|155.21467390476187|170.3936491190469",
-        "L.27|0|0|160.70351666666664|170.28328058095164",
-        "L.28|0|0|166.1923594285714|170.17291204285635",
-        "L.29|0|0|171.68120219047617|170.0625435047611",
-        "L.30|0|0|177.17004495238092|169.95217496666584",
-        "L.31|0|0|182.6588877142857|169.84180642857055",
-        "M.1|0|0|18.618844|200.67567",
-        "M.2|0|0|24.1043766|200.56355133333332",
-        "M.3|0|0|29.5899092|200.45143266666668",
-        "M.4|0|0|35.0754418|200.339314",
-        "M.5|0|0|40.5609744|200.22719533333333",
-        "M.6|0|0|46.046507000000005|200.11507666666665",
-        "M.7|0|0|51.532039600000004|200.002958",
-        "M.8|0|0|57.017572200000004|199.89083933333333",
-        "M.9|0|0|62.5031048|199.77872066666666",
-        "M.10|0|0|67.9886374|199.66660199999998",
-        "M.11|0|0|73.47417|199.55448333333334",
-        "M.12|0|0|78.9597026|199.44236466666666",
-        "M.13|0|0|84.4452352|199.330246",
-        "M.14|0|0|89.9307678|199.21812733333334",
-        "M.15|0|0|95.4163004|199.10600866666667",
-        "M.16|0|0|100.901833|198.99389",
-        "M.17|0|0|106.3873656|198.88177133333332",
-        "M.18|0|0|111.87289820000001|198.76965266666667",
-        "M.19|0|0|117.35843080000001|198.657534",
-        "M.20|0|0|122.8439634|198.54541533333332",
-        "M.21|0|0|128.329496|198.43329666666665",
-        "M.22|0|0|133.8150286|198.321178",
-        "M.23|0|0|139.3005612|198.20905933333333",
-        "M.24|0|0|144.7860938|198.09694066666665",
-        "M.25|0|0|150.2716264|197.984822",
-        "M.26|0|0|155.75715900000003|197.87270333333333",
-        "M.27|0|0|161.2426916|197.76058466666666",
-        "M.28|0|0|166.7282242|197.64846599999998",
-        "M.29|0|0|172.2137568|197.53634733333334",
-        "M.30|0|0|177.69928940000003|197.42422866666666",
-        "M.31|0|0|183.184822|197.31211",
-        "N.1|0|0|18.618844|200.67567",
-        "N.2|0|0|24.1043766|200.56355133333332",
-        "N.3|0|0|29.5899092|200.45143266666668",
-        "N.4|0|0|35.0754418|200.339314",
-        "N.5|0|0|40.5609744|200.22719533333333",
-        "N.6|0|0|46.046507000000005|200.11507666666665",
-        "N.7|0|0|51.532039600000004|200.002958",
-        "N.8|0|0|57.017572200000004|199.89083933333333",
-        "N.9|0|0|62.5031048|199.77872066666666",
-        "N.10|0|0|67.9886374|199.66660199999998",
-        "N.11|0|0|73.47417|199.55448333333334",
-        "N.12|0|0|78.9597026|199.44236466666666",
-        "N.13|0|0|84.4452352|199.330246",
-        "N.14|0|0|89.9307678|199.21812733333334",
-        "N.15|0|0|95.4163004|199.10600866666667",
-        "N.16|0|0|100.901833|198.99389",
-        "N.17|0|0|106.3873656|198.88177133333332",
-        "N.18|0|0|111.87289820000001|198.76965266666667",
-        "N.19|0|0|117.35843080000001|198.657534",
-        "N.20|0|0|122.8439634|198.54541533333332",
-        "N.21|0|0|128.329496|198.43329666666665",
-        "N.22|0|0|133.8150286|198.321178",
-        "N.23|0|0|139.3005612|198.20905933333333",
-        "N.24|0|0|144.7860938|198.09694066666665",
-        "N.25|0|0|150.2716264|197.984822",
-        "N.26|0|0|155.75715900000003|197.87270333333333",
-        "N.27|0|0|161.2426916|197.76058466666666",
-        "N.28|0|0|166.7282242|197.64846599999998",
-        "N.29|0|0|172.2137568|197.53634733333334",
-        "N.30|0|0|177.69928940000003|197.42422866666666",
-        "N.31|0|0|183.184822|197.31211"
-    ],
-    "title": "渣罐坐标数据",
-    "total": 434
-}

+ 0 - 54
project-fastapi-hs/default_data.py

@@ -1,54 +0,0 @@
-data = {
-    'enable': True,
-    'config': {
-        # --- 用户配置 ---
-        'Role&User': [
-            {
-                'role_info': {
-                    'role_type': 1,
-                    'role_name': '超级管理员',
-                    'switch_list': [
-                        'admin'
-                    ],
-                },
-                'users_info': [
-                    {
-                        'username': 'admin',
-                        'password': '123456',
-                    }
-                ],
-            },
-        ],
-        # --- 车辆配置 ---
-        'VehicleInfo': [
-            {'name': '3号车', 'address': '192.168.131.180'},
-            {'name': '5号车', 'address': '192.168.131.xxx'},
-        ],
-        # --- 倒渣口坐标数据 ---
-        # 'aaa': [
-        #     {'name': '3号车', 'address': '192.168.131.180'},
-        #     {'name': '5号车', 'address': '192.168.131.xxx'},
-        # ],
-        # --- 渣包坐标数据 ---
-        # 'bbb': [
-        #     {'name': '3号车', 'address': '192.168.131.180'},
-        #     {'name': '5号车', 'address': '192.168.131.xxx'},
-        # ],
-        # --- 转弯圆心点坐标数据 ---
-        # 'ccc': [
-        #     {'name': '3号车', 'address': '192.168.131.180'},
-        #     {'name': '5号车', 'address': '192.168.131.xxx'},
-        # ],
-        # --- 全局配置 ---
-        'GlobalVariable': {
-            'CameraConfig': {
-
-                # 海康 人脸摄像机 中建八局 第4现场 奥东项目
-                # 'camera_rtsp': 'rtsp://admin:DEVdev123@192.168.1.64:554/h264/ch1/main/av_stream',
-                # 'camera_ipv4': '192.168.1.64',
-                # 'camera_user': 'admin',
-                # 'camera_pass': 'DEVdev123',
-            }
-        }
-    }
-}

+ 0 - 2
project-fastapi-hs/test/HingeCarPath.msg

@@ -1,2 +0,0 @@
-uint32 size
-Segment[] target_path

+ 0 - 284
project-fastapi-hs/test/SRI2024032514-机房端http接口文档.txt

@@ -1,284 +0,0 @@
-# --- test 获取token ---
-service_url = 'http://10.10.61.229:9000'
-url = f'{service_url}/token/api'
-data = {
-    'username': 'admin',
-    'password': 'admin',
-}
-response = requests.post(url=url, json=data)
-print(response.headers)
-"""
-{
-  'date': 'Thu, 04 Jan 2024 07:19:58 GMT',
-  'server': 'uvicorn',
-  # 登录token
-  'authorization': 'eyJhbGciOiJIUzUxMiIsImlhdCI6MTcwNDM1Mjc5OCwiZXhwIjoxNzA0NDM5MTk4fQ.eyJpZCI6IjY1NGUzNmI0NjBmZGE0M2UzOTI2YzNmYiIsInVzZXJuYW1lIjoiYWRtaW4iLCJwYXNzd29yZCI6InBia2RmMjpzaGEyNTY6MTUwMDAwJGxEN1duR0hxJGUyNjhhNzgxOTFhYjdiNDE2ZDcxZjE1MDkxNzJjZWVkZWI3ZTNmNTM1ZGY0MGQ5NmQ4MzZlYmRjNTFmZGRmMzkifQ.IGi0lXezecP5AEjxgQ4lzQ5jyeYwDLoGmD7n29Q_1X6faSo4EKj4Q8A89BiAKBhjGAiNe7FSBFjmqhoZEXacUg',
-  'content-length': '107',
-  'content-type': 'application/json'
-}
-"""
-print(response.json())
-"""
-{
-  'code': 0  # 错误码 {0: 无异常}
-  'message': 'authorization passed.',
-  'uid': '654e36b460fda43e3926c3fb',  # 用户id
-  'role_name': '超级管理员',
-}
-"""
-
-# --- test 2001 获取全部渣包车状态 ---
-url = 'http://10.10.61.229:9000/v5/api'
-data = {
-    'code': 2001,  # 接口号
-}
-response = requests.post(url=url, json=data, headers={'authorization': token})
-print(response.json())
-"""
-{
-  'code': 0,
-  'data': [
-    {
-      'uuid': 'aabbssff',  # 渣包车唯一标识
-      'name': '6号车',  # 别称
-      'status': 1  # 状态  # 1:离线 2:在线空闲 3: 人工驾驶中 4: 远程驾驶中 5: 自动驾驶中
-    }
-  ]
-}
-"""
-
-# --- test 2002 指定渣包车点火操作接口 ---
-url = 'http://10.10.61.229:9000/v5/api'
-data = {
-    'code': 2002,  # 接口号
-    'uuid': 'aassfafe',  # 渣包车唯一标识
-}
-response = requests.post(url=url, json=data, headers={'authorization': token})
-print(response.json())
-"""
-{
-  'code': 0,
-  'data': 'aassfafe'
-}
-"""
-
-# --- test 2003 指定渣包车熄火操作接口 ---
-url = 'http://10.10.61.229:9000/v5/api'
-data = {
-    'code': 2003,  # 接口号
-    'uuid': 'aassfafe',  # 渣包车唯一标识
-}
-response = requests.post(url=url, json=data, headers={'authorization': token})
-print(response.json())
-"""
-{
-  'code': 0,
-  'data': 'aassfafe'
-}
-"""
-
-# --- test 2004 指定渣包车建立远程操作权限(或是切换)接口 ---
-url = 'http://10.10.61.229:9000/v5/api'
-data = {
-    'code': 2004,  # 接口号
-    'uuid': 'aassfafe',  # 渣包车唯一标识
-}
-response = requests.post(url=url, json=data, headers={'authorization': token})
-print(response.json())
-"""
-{
-  'code': 0,
-  'data': 'aassfafe'
-}
-"""
-
-# --- test 2005 开始作业接口(基于当前渣包车,选定作业内容) ---
-url = 'http://10.10.61.229:9000/v5/api'
-data = {
-    'code': 2005,  # 接口号
-    'uuid': 'aassfafe',  # 渣包车唯一标识
-    'task_type': 'aassfafe',  # 作业类型  # 1: 叉包 2: 翻包 3:放包
-    'task_plan': [
-        {'name': 'L20', 'x': '54', 'y': '211'},
-        {'name': 'CD01端转弯圆心', 'x': '54', 'y': '211'},
-        {'name': '#6倒渣口', 'x': '54', 'y': '211'},
-    ],  # 路径规划  # name: 包位名称/倒渣口名称/转弯圆心点坐标 x: 坐标值 y: 坐标值
-}
-response = requests.post(url=url, json=data, headers={'authorization': token})
-print(response.json())
-"""
-{
-  'code': 0,
-  'data': 'aassfafe'
-}
-"""
-
-# --- test 2101 新增渣包车接口 ---
-url = 'http://10.10.61.229:9000/v5/api'
-data = {
-    'code': 2101,  # 接口号
-    'name': '3号车',  # 别称
-}
-response = requests.post(url=url, json=data, headers={'authorization': token})
-print(response.json())
-"""
-{
-  'code': 0,
-  'data': 'aassfafe'
-}
-"""
-
-# --- test 2102 修改渣包车接口 ---
-url = 'http://10.10.61.229:9000/v5/api'
-data = {
-    'code': 2102,  # 接口号
-    'uuid': '659765411dd2f1fe6d346b3b',  # 渣包车唯一标识
-    'name': '6号车',  # 别称
-}
-response = requests.post(url=url, json=data, headers={'authorization': token})
-print(response.json())
-"""
-{
-    'code': 0,
-    'data': {
-        'uuid': '659765411dd2f1fe6d346b3b',
-        'name': '6号车',
-        'update_at': 1704435941
-    }
-}
-"""
-
-# --- test 2103 删除渣包车接口 ---
-url = 'http://10.10.61.229:9000/v5/api'
-data = {
-    'code': 2103,  # 接口号
-    'uuid': '659764dd6b8e37c3ce95d849',  # 渣包车唯一标识
-}
-response = requests.post(url=url, json=data, headers={'authorization': token})
-print(response.json())
-
-# --- test 3001 任务列表数据获取接口(分页) ---
-url = 'http://10.10.61.229:9000/v5/api'
-data = {
-    'code': 3001,  # 接口号
-    'page': 1,  # 分页
-    'size': 10,  # 每页条数
-}
-response = requests.post(url=url, json=data, headers={'authorization': token})
-print(response.json())
-"""
-{
-  'code': 0,
-  'data': [
-    {
-      'uuid': '659765411dd2f1fe6d346b3b',  # 任务id
-      'vehicle_uuid': '659765411dd2f1fe6d346b3b'  # 任务车辆id
-    }
-  ],
-  'page': 1,
-  'size': 10,
-  'total': 1  # 总条数
-}
-"""
-
-# --- test 3002 任务暂停接口 ---
-url = 'http://10.10.61.229:9000/v5/api'
-data = {
-    'code': 3002,  # 接口号
-    'uuid': 'aassfafe',  # 任务id
-}
-response = requests.post(url=url, json=data, headers={'authorization': token})
-print(response.json())
-"""
-{
-  'code': 0,
-  'data': 'aassfafe'
-}
-"""
-
-# --- test 3003 任务取消接口 ---
-url = 'http://10.10.61.229:9000/v5/api'
-data = {
-    'code': 3003,  # 接口号
-    'uuid': 'aassfafe',  # 任务id
-}
-response = requests.post(url=url, json=data, headers={'authorization': token})
-print(response.json())
-"""
-{
-  'code': 0,
-  'data': 'aassfafe'
-}
-"""
-
-# --- test 4001 获取全部渣包状态数据接口 ---
-url = 'http://10.10.61.229:9000/v5/api'
-data = {
-    'code': 4001,  # 接口号
-}
-response = requests.post(url=url, json=data, headers={'authorization': token})
-print(response.json())
-"""
-{
-  'code': 0,
-  'data': {
-    '倒渣口-1': 1,
-    '倒渣口-2': 1,
-    '倒渣口-3': 1,
-    '倒渣口-4': 1,
-    '倒渣口-5': 1,
-    '倒渣口-6': 1,
-    '倒渣口-7': 1,
-    '包位-A-1': 1,
-    '包位-A-2': 1,
-    '包位-A-3': 1,
-    '包位-A-4': 1,
-    '包位-A-5': 1,
-    '包位-A-6': 1,
-    '包位-A-7': 1,
-    '包位-A-8': 1,
-    '包位-A-9': 1,
-    '包位-A-10': 1,
-    '包位-A-11': 1,
-    '包位-A-12': 1,
-    '包位-A-13': 1,
-    '包位-A-14': 1,
-    '包位-A-15': 1,
-    '包位-A-16': 1,
-    '包位-A-17': 1,
-    '包位-A-18': 1,
-    '包位-A-19': 1,
-    '包位-A-20': 1,
-    '包位-A-21': 1,
-    '包位-A-22': 1,
-    '包位-A-23': 1,
-    '包位-A-24': 1,
-    '包位-A-25': 1,
-    '包位-A-26': 1,
-    '包位-A-27': 1,
-    '包位-A-28': 1,
-    '包位-A-29': 1,
-    '包位-A-30': 1,
-    '包位-A-31': 1,
-  }
-}
-"""
-
-# --- test 5001 获取告警数据列表接口 ---
-url = 'http://10.10.61.229:9000/v5/api'
-data = {
-    'code': 5001,  # 接口号
-}
-response = requests.post(url=url, json=data, headers={'authorization': token})
-print(response.json())
-"""
-{
-  'code': 0,
-  'data': [
-    {
-      'message': '1号车油量低,请及时加油!',  # 警告内容
-      'create_at': 1704435199  # 警告时间(时间戳)
-    }
-  ]
-}
-"""

+ 0 - 32
project-fastapi-hs/test/SRI2024032514-车端http接口文档.txt

@@ -1,32 +0,0 @@
-#车辆状态更新
-mqtt服务地址:192.168.131.23
-mqtt服务端口:41883
-mqtt话题:hs/vehicle/state
-mqtt消息及注释:
-{
-    "ip": "192.168.131.180",  # 车辆ip
-    "state": 1,  # 车辆状态 1 离线 2 在线空闲 3 人工驾驶中 4 远程驾驶中 5 自动驾驶中
-    "direction": 15,  # 车头方向(场地坐标偏转角度)
-}
-
-#渣包位置更新
-mqtt服务地址:192.168.131.23
-mqtt服务端口:41883
-mqtt话题:hs/pot/point
-mqtt消息(json字符串):{"pot": "n32", "point": null}
-mqtt消息注释:
-{
-  "pot": "n32",  # 渣包标识
-  "point": null   # 位置坐标
-}
-
-#渣包位置更新
-mqtt服务地址:192.168.131.23
-mqtt服务端口:41883
-mqtt话题:hs/pot/point
-mqtt消息(json字符串):{"pot": "n32", "point": null}
-mqtt消息注释:
-{
-  "pot": "n32",  # 渣包标识
-  "point": null   # 位置坐标
-}

+ 0 - 8
project-fastapi-hs/test/Segment.msg

@@ -1,8 +0,0 @@
-geometry_msgs/Point start_point  # 
-geometry_msgs/Point end_point
-geometry_msgs/Point center_point
-float32 max_vel
-uint8 LINE = 1            # LINE target
-uint8 CIRCLE = 2          # CIRCLE target
-####
-uint8 segment_type

+ 0 - 14
project-fastapi-hs/test/Segment.py

@@ -1,14 +0,0 @@
-# 导入所需的消息类型
-from geometry_msgs.msg import Point
-
-# 创建一个 Point 对象,并设置其 x、y、z 坐标值
-point = Point()
-point.x = 1.0
-point.y = 2.0
-point.z = 3.0
-
-# 打印 Point 对象的内容
-print("Point: ", point)
-print("X coordinate: ", point.x)
-print("Y coordinate: ", point.y)
-print("Z coordinate: ", point.z)

+ 0 - 136
project-fastapi-hs/test/test-2000.py

@@ -1,136 +0,0 @@
-import requests
-
-# --- test 获取token ---
-# url = 'http://10.10.61.229:9000/token/api'
-url = 'http://192.168.131.23:9000/token/api'
-data = {
-    'username': 'admin',  # 用户名
-    'password': 'admin',  # 密码
-}
-response = requests.post(url=url, json=data)
-code = response.json().get('code')
-token = response.headers.get('authorization')
-
-# --- test 2001 获取全部渣包车状态 ---
-url = 'http://192.168.131.23:9000/v5/api'
-data = {
-    'code': 2001,  # 接口号
-}
-response = requests.post(url=url, json=data, headers={'authorization': token})
-print(response.json())
-"""
-{
-  'code': 0,
-  'data': [
-    {
-      'name': '3号车',  # 车辆名称
-      'address': '192.168.131.180',  # 车辆ip
-      'check_vehicle_direction': True,  # 当前车头方向是否符合自动驾驶条件 True 符合 False 不符合(默认值)
-      'state': 2,  # 车辆状态 1 离线(默认值) 2 在线空闲 3 人工驾驶中 4 远程驾驶中 5 自动驾驶中
-      'current_vehicle_direction': 9,  # 当前车头方向类型 3 围栏方向 9 渣场方向 12 维修间方向 6 维修间正对方向 0 未知(默认值)
-      'current_vehicle_weight': 0,  # 当前车辆负载重量
-      'uuid': '65faa9d5921aec72550fb32d'  # 车辆标识
-    },
-    {
-      'name': '5号车',
-      'address': '192.168.131.xxx',
-      'check_vehicle_direction': False,
-      'current_vehicle_direction': 0,
-      'state': 1,
-      'current_vehicle_weight': 0,
-      'uuid': '65faa9d5921aec72550fb32e'
-    }
-  ]
-}
-"""
-
-# --- test 2002 指定渣包车点火操作接口 ---
-# url = 'http://10.10.61.229:9000/v5/api'
-# data = {
-#     'code': 2002,  # 接口号
-#     'uuid': 'aassfafe',  # 渣包车唯一标识
-# }
-# response = requests.post(url=url, json=data, headers={'authorization': token})
-# print(response.json())
-# """
-# {
-#   'code': 0,
-#   'data': 'aassfafe'
-# }
-# """
-
-# --- test 2003 指定渣包车熄火操作接口 ---
-# url = 'http://10.10.61.229:9000/v5/api'
-# data = {
-#     'code': 2003,  # 接口号
-#     'uuid': 'aassfafe',  # 渣包车唯一标识
-# }
-# response = requests.post(url=url, json=data, headers={'authorization': token})
-# print(response.json())
-# """
-# {
-#   'code': 0,
-#   'data': 'aassfafe'
-# }
-# """
-
-# --- test 2004 指定渣包车建立远程操作权限(或是切换)接口 ---
-# url = 'http://10.10.61.229:9000/v5/api'
-# data = {
-#     'code': 2004,  # 接口号
-#     'uuid': 'aassfafe',  # 渣包车唯一标识
-# }
-# response = requests.post(url=url, json=data, headers={'authorization': token})
-# print(response.json())
-# """
-# {
-#   'code': 0,
-#   'data': 'aassfafe'
-# }
-# """
-
-# --- test 2101 新增渣包车接口 ---
-# url = 'http://10.10.61.229:9000/v5/api'
-# data = {
-#     'code': 2101,  # 接口号
-#     'name': '3号车',  # 车辆名称
-#     'address': '192.168.131.41',  # 网络地址
-# }
-# response = requests.post(url=url, json=data, headers={'authorization': token})
-# print(response.json())
-# """
-# {
-#   'code': 0,
-#   'data': 'aassfafe'
-# }
-# """
-
-# --- test 2102 修改渣包车接口 ---
-# url = 'http://10.10.61.229:9000/v5/api'
-# data = {
-#     'code': 2102,  # 接口号
-#     'uuid': '659765411dd2f1fe6d346b3b',  # 渣包车唯一标识
-#     'name': '3号车',  # 车辆名称
-#     'address': '192.168.131.41',  # 网络地址
-# }
-# response = requests.post(url=url, json=data, headers={'authorization': token})
-# print(response.json())
-# """
-# {
-#     'code': 0,
-#     'data': {
-#         'uuid': '659765411dd2f1fe6d346b3b',
-#         'name': '6号车',
-#         'update_at': 1704435941
-#     }
-# }
-# """
-
-# --- test 2103 删除渣包车接口 ---
-# url = 'http://10.10.61.229:9000/v5/api'
-# data = {
-#     'code': 2103,  # 接口号
-#     'uuid': '659764dd6b8e37c3ce95d849',  # 渣包车唯一标识
-# }
-# response = requests.post(url=url, json=data, headers={'authorization': token})
-# print(response.json())

+ 0 - 95
project-fastapi-hs/test/test-3000.py

@@ -1,95 +0,0 @@
-import requests
-
-# --- test 获取token ---
-# url = 'http://10.10.61.229:9000/token/api'
-url = 'http://192.168.131.23:9000/token/api'
-data = {
-    'username': 'admin',  # 用户名
-    'password': 'admin',  # 密码
-}
-response = requests.post(url=url, json=data)
-code = response.json().get('code')
-token = response.headers.get('authorization')
-
-# --- test 3001 任务列表数据获取接口(分页) ---
-# --- test 3001 任务列表数据获取接口(分页) ---
-# url = 'http://192.168.131.23:9000/v5/api'
-# data = {
-#     'code': 3001,  # 接口号
-#     'page': 1,  # 分页
-#     'size': 10,  # 每页条数
-# }
-# response = requests.post(url=url, json=data, headers={'authorization': token})
-# print(response.json())
-# """
-# {
-#   'code': 0,
-#   'data': [
-#     {
-#       'vehicle_uuid': '65faa9d5921aec72550fb32d',  # 车辆id
-#       'task_type': 101,  # 任务类型 101 自动驾驶 102 叉包 103 放包 104 倒渣
-#       'target_point_name': 'F.20',  # 目标点名称
-#       'task_state': 1,  # 任务状态 1 已经下发 2 已完成 3 中止 4 失败
-#       'create_at': 1711526546,  # 创建时间
-#       'uuid': '6603d2922276884b00caa06c'  # 任务id
-#     }
-#   ],
-#   'total': 1,
-#   'page': 1,
-#   'size': 10
-# }
-# """
-
-# --- test 3003 任务取消接口 ---
-# url = 'http://10.10.61.229:9000/v5/api'
-# url = 'http://192.168.131.23:9000/v5/api'
-# data = {
-#     'code': 3003,  # 接口号
-#     'uuid': '659765411dd2f1fe6d346b3b',  # 任务id
-# }
-# response = requests.post(url=url, json=data, headers={'authorization': token})
-# print(response.json())
-# """
-# {
-#   'code': 0,
-#   'data': '659765411dd2f1fe6d346b3b'
-# }
-# """
-
-# --- test 3004 任务创建并执行 ---
-# url = 'http://192.168.131.23:9000/v5/api'
-# data = {
-#     'code': 3004,  # 接口号
-#     'uuid': '65faa9d5921aec72550fb32d',  # 渣包车唯一标识
-#     'task_type': 101,  # 任务类型 101 自动驾驶 102 叉包 103 放包 104 倒渣
-#     'target_point_name': 'F.20',  # 目标点名称
-# }
-# response = requests.post(url=url, json=data, headers={'authorization': token})
-# print(response.json())
-# """
-# {
-#   'code': 0,
-#   'data': '659765411dd2f1fe6d346b3b'  # 任务id
-# }
-# """
-
-# --- test 3005 获取指定任务信息 ---
-url = 'http://192.168.131.23:9000/v5/api'
-data = {
-    'code': 3005,  # 接口号
-    'uuid': '6603d2922276884b00caa06c',  # 任务id
-}
-response = requests.post(url=url, json=data, headers={'authorization': token})
-print(response.json())
-"""
-{
-  'code': 0,
-  'data': {
-    'task_type': 101,  # 任务类型 101 自动驾驶 102 叉包 103 放包 104 倒渣
-    'target_point_name': 'F.20',  # 目标点
-    'task_state': 1,  # 任务状态 1 已经下发 2 已完成 3 中止 4 失败
-    'create_at': 1711381601,  # 创建时间
-    'uuid': '66019c617b5e102e42bc363a'  # 任务id
-  }
-}
-"""

+ 0 - 33
project-fastapi-hs/test/test-4000.py

@@ -1,33 +0,0 @@
-import requests
-
-# --- test 获取token ---
-# url = 'http://10.10.61.229:9000/token/api'
-url = 'http://192.168.131.23:9000/token/api'
-data = {
-    'username': 'admin',  # 用户名
-    'password': 'admin',  # 密码
-}
-response = requests.post(url=url, json=data)
-code = response.json().get('code')
-token = response.headers.get('authorization')
-
-# --- test 4001 获取全部渣包状态数据接口 ---
-# url = 'http://10.10.61.229:9000/v5/api'
-url = 'http://192.168.131.23:9000/v5/api'
-data = {
-    'code': 4001,  # 接口号
-}
-response = requests.post(url=url, json=data, headers={'authorization': token})
-print(response.json())
-"""
-{
-  'code': 0,
-  'data': [
-    {
-      'pot_name': 'A.1',  # 渣罐别称
-      'pot_status': 4,  # 渣罐状态 1 空位 2 就绪 3 缓冷(空冷) 4 水冷 5 自冷(水冷) 6 待倒 7 故障
-      'pot_number': '1'  # 渣罐编号
-    }
-  ]
-}
-"""

+ 0 - 32
project-fastapi-hs/test/test-5000.py

@@ -1,32 +0,0 @@
-import requests
-
-# --- test 获取token ---
-url = 'http://10.10.61.229:9000/token/api'
-data = {
-    'username': 'admin',  # 用户名
-    'password': 'admin',  # 密码
-}
-response = requests.post(url=url, json=data)
-code = response.json().get('code')
-token = response.headers.get('authorization')
-# print(code, token)
-
-# --- test 5001 获取告警数据列表接口 ---
-# --- test 5001 获取告警数据列表接口 ---
-url = 'http://10.10.61.229:9000/v5/api'
-data = {
-    'code': 5001,  # 接口号
-}
-response = requests.post(url=url, json=data, headers={'authorization': token})
-print(response.json())
-"""
-{
-  'code': 0,
-  'data': [
-    {
-      'message': '1号车油量低,请及时加油!',  # 警告内容
-      'create_at': 1704435199  # 警告时间(时间戳)
-    }
-  ]
-}
-"""

+ 0 - 4
project-fastapi-hs/test/test-enfei.py

@@ -1,4 +0,0 @@
-import requests
-
-# --- test 获取渣罐信息 --- | 10.62.115.11 hyty-ifactory.platform.dyys.com > /etc/hosts
-print(requests.get(url='http://hyty-ifactory.platform.dyys.com/gongyi/ui/ResiduePackage/driver/getParamsSet').json())

+ 0 - 30
project-fastapi-hs/test/test_key_api.py

@@ -1,30 +0,0 @@
-import requests
-
-# --- test 获取token ---
-# url = 'http://10.10.61.229:9000/token/api'
-url = 'http://58.34.94.177:29000/token/api'
-data = {
-    'username': 'admin',
-    'password': 'admin',
-}
-response = requests.post(url=url, json=data)
-print(response.headers)
-"""
-{
-  'date': 'Thu, 04 Jan 2024 07:19:58 GMT',
-  'server': 'uvicorn',
-  # 登录token
-  'authorization': 'eyJhbGciOiJIUzUxMiIsImlhdCI6MTcwNDM1Mjc5OCwiZXhwIjoxNzA0NDM5MTk4fQ.eyJpZCI6IjY1NGUzNmI0NjBmZGE0M2UzOTI2YzNmYiIsInVzZXJuYW1lIjoiYWRtaW4iLCJwYXNzd29yZCI6InBia2RmMjpzaGEyNTY6MTUwMDAwJGxEN1duR0hxJGUyNjhhNzgxOTFhYjdiNDE2ZDcxZjE1MDkxNzJjZWVkZWI3ZTNmNTM1ZGY0MGQ5NmQ4MzZlYmRjNTFmZGRmMzkifQ.IGi0lXezecP5AEjxgQ4lzQ5jyeYwDLoGmD7n29Q_1X6faSo4EKj4Q8A89BiAKBhjGAiNe7FSBFjmqhoZEXacUg',
-  'content-length': '107',
-  'content-type': 'application/json'
-}
-"""
-print(response.json())
-"""
-{
-  'code': 0  # 错误码 {0: 无异常}
-  'message': 'authorization passed.',
-  'uid': '654e36b460fda43e3926c3fb',  # 登录用户id
-  'role_name': '超级管理员',
-}
-"""

+ 0 - 15
project-fastapi-hs/test/test_sanyi.py

@@ -1,15 +0,0 @@
-# json_data = [
-#     {
-#         'name': '#1',  # 倒渣口名称
-#         'state': 1,  # 倒渣口状态 (1: 可用 2: 不可用)
-#     }, {
-#         'name': '#2',  # 倒渣口名称
-#         'state': 1,  # 倒渣口状态 (1: 可用 2: 不可用)
-#     }, {
-#         'name': '#3',  # 倒渣口名称
-#         'state': 1,  # 倒渣口状态 (1: 可用 2: 不可用)
-#     }, {
-#         'name': '#4',  # 倒渣口名称
-#         'state': 1,  # 倒渣口状态 (1: 可用 2: 不可用)
-#     }..
-# ]

+ 0 - 30
project-fastapi-hs/test/test_token.py

@@ -1,30 +0,0 @@
-import requests
-
-# --- test 获取token ---
-service_url = 'http://10.10.61.229:9000'
-url = f'{service_url}/token/api'
-data = {
-    'username': 'admin',
-    'password': 'admin',
-}
-response = requests.post(url=url, json=data)
-print(response.headers)
-"""
-{
-  'date': 'Thu, 04 Jan 2024 07:19:58 GMT',
-  'server': 'uvicorn',
-  # 登录token
-  'authorization': 'eyJhbGciOiJIUzUxMiIsImlhdCI6MTcwNDM1Mjc5OCwiZXhwIjoxNzA0NDM5MTk4fQ.eyJpZCI6IjY1NGUzNmI0NjBmZGE0M2UzOTI2YzNmYiIsInVzZXJuYW1lIjoiYWRtaW4iLCJwYXNzd29yZCI6InBia2RmMjpzaGEyNTY6MTUwMDAwJGxEN1duR0hxJGUyNjhhNzgxOTFhYjdiNDE2ZDcxZjE1MDkxNzJjZWVkZWI3ZTNmNTM1ZGY0MGQ5NmQ4MzZlYmRjNTFmZGRmMzkifQ.IGi0lXezecP5AEjxgQ4lzQ5jyeYwDLoGmD7n29Q_1X6faSo4EKj4Q8A89BiAKBhjGAiNe7FSBFjmqhoZEXacUg',
-  'content-length': '107',
-  'content-type': 'application/json'
-}
-"""
-print(response.json())
-"""
-{
-  'code': 0  # 错误码 {0: 无异常}
-  'message': 'authorization passed.',
-  'uid': '654e36b460fda43e3926c3fb',  # 登录用户id
-  'role_name': '超级管理员',
-}
-"""

+ 0 - 264
project-fastapi-hs/unit/Scheduler_a1.py

@@ -1,264 +0,0 @@
-"""
-
-"""
-
-# 圆心点坐标字典 todo 关于入弯和出弯 是否是固定的
-d1 = {
-    'LM.head': {'center': (11, 22), 'center_12': (11, 21), 'center_9': (11, 21), 'center_6': (11, 21)},
-    'JK.head': {'center': (11, 22), 'center_12': (11, 21), 'center_9': (11, 21), 'center_6': (11, 21)},
-    'HI.head': {'center': (11, 22), 'center_12': (11, 21), 'center_9': (11, 21), 'center_6': (11, 21)},
-    'FG.head': {'center': (11, 22), 'center_12': (11, 21), 'center_9': (11, 21), 'center_6': (11, 21)},
-    'DE.head': {'center': (11, 22), 'center_12': (11, 21), 'center_9': (11, 21), 'center_6': (11, 21)},
-    'BC.head': {'center': (11, 22), 'center_12': (11, 21), 'center_9': (11, 21), 'center_6': (11, 21)},
-    'A.head': {'center': (11, 22), 'center_12': (11, 21), 'center_9': (11, 21), 'center_6': (11, 21)},
-
-    'LM.tail': {'center': (11, 22), 'center_12': (11, 21), 'center_3': (11, 21), 'center_6': (11, 21)},
-    'JK.tail': {'center': (11, 22), 'center_12': (11, 21), 'center_3': (11, 21), 'center_6': (11, 21)},
-    'HI.tail': {'center': (11, 22), 'center_12': (11, 21), 'center_3': (11, 21), 'center_6': (11, 21)},
-    'FG.tail': {'center': (11, 22), 'center_12': (11, 21), 'center_3': (11, 21), 'center_6': (11, 21)},
-    'DE.tail': {'center': (11, 22), 'center_12': (11, 21), 'center_3': (11, 21), 'center_6': (11, 21)},
-    'BC.tail': {'center': (11, 22), 'center_12': (11, 21), 'center_3': (11, 21), 'center_6': (11, 21)},
-    'A.tail': {'center': (11, 22), 'center_12': (11, 21), 'center_3': (11, 21), 'center_6': (11, 21)},
-
-}
-
-# 倒渣口坐标字典
-d2 = {
-    'dump.MN': {'dump': (11, 205.75)},  # 1号倒渣口
-    'dump.KL': {'dump': (11, 177.75)},  # 2号倒渣口
-    'dump.IJ': {'dump': (11, 149.75)},  # 3号倒渣口
-    'dump.GH': {'dump': (11, 121.75)},  # 4号倒渣口
-    'dump.EF': {'dump': (11, 93.75)},  # 5号倒渣口
-    'dump.CD': {'dump': (11, 65.75)},  # 6号倒渣口
-    'dump.AB': {'dump': (11, 37.75)},  # 7号倒渣口
-}
-
-# 接渣口坐标字典
-d3 = {
-    'load.1': {'load': (11, 22)},
-    'load.2': {'load': (11, 22)},
-    'load.3': {'load': (11, 22)},
-}
-
-# 停车区坐标字典
-d5 = {
-    'pack.1': {'x': 77, 'y': 44},
-    'pack.2': {'x': 77, 'y': 44},
-}
-
-# 渣罐坐标字典
-d4 = {
-    'M.31': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.30': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.29': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.28': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.27': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.26': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.25': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.24': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.23': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.22': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.21': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.20': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.19': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.18': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.17': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.16': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.15': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.14': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.13': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.12': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.11': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.10': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.9': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.8': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.7': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.6': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.5': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.4': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.3': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.2': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.1': {'pot': (22, 33), 'road_center': (44, 55)},
-
-    'F.31': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.30': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.29': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.28': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.27': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.26': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.25': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.24': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.23': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.22': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.21': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.20': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.19': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.18': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.17': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.16': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.15': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.14': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.13': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.12': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.11': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.10': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.9': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.8': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.7': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.6': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.5': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.4': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.3': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.2': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.1': {'pot': (22, 33), 'road_center': (44, 55)},
-
-}
-
-
-def get_nearest_point_from_road_center_point(x, y):
-    """
-    获取当前所在位置最接近的坐标位置
-    todo 判断是否是合理的范围,逻辑上移 offset = 11  # 允许范围(单位:米)
-    """
-    x = float(x)
-    y = float(y)
-    min_distance = float('inf')  # 初始值无穷大
-    for k, v in d4.items():
-        center_x = float(v.get('road_center')[0])
-        center_y = float(v.get('road_center')[1])
-        distance = ((center_x - x) ** 2 + (center_y - y) ** 2) ** (1 / 2)
-
-        if distance < min_distance:
-            min_distance = distance
-            nearest_point = center_x, center_y
-
-    return nearest_point
-
-
-def get_center_point_by_keyword(w1='N', w2='head'):
-    """
-    获取圆心点坐标
-    w1: 关键字
-    w2: 关键字
-    """
-    # d1 = todo 从json文件中获取
-    for k, v in d1.items():
-        k_s1, k_s2 = k.split('.')
-        if w1 not in k_s1:
-            continue
-        if w2 not in k_s2:
-            continue
-        return dict(**v, **{'name': k})
-
-
-def get_path_name_by_pot_name(pot_name='M.25'):
-    """根据渣罐名获取道路名"""
-    s1, s2 = pot_name.split('.')
-    path_name_list = [
-        'MN',
-        'KL',
-        'IJ',
-        'GH',
-        'EF',
-        'CD',
-        'AB',
-    ]
-    for s in path_name_list:
-        if s1 in s:
-            return s
-
-
-import json
-
-
-def test(s_direction='head', s_name='M.10', e_name='M.1'):
-    """
-    s_direction: 起始方向  head 渣场方向 tail 围栏方向
-    s_name: 起始位置
-    e_name: 目标位置
-    """
-    # --- update d4 ---
-    data = json.load(open('../data/渣罐坐标数据.json', 'r'))
-    for item in data.get('pot_name|pot_x|pot_y|road_center_x|road_center_y'):
-        pot_name, pot_x, pot_y, road_center_x, road_center_y = item.split('|')
-        d4[pot_name] = {
-            'pot': (pot_x, pot_y),
-            'road_center': (road_center_x, road_center_y),
-        }
-
-    # --- test
-    # x, y = get_nearest_point_from_road_center_point(x=112.5, y=27.25)
-    # return x, y
-
-    # --- check ---
-    if s_direction not in ['head', 'tail']:
-        return {'code': 1, 'data': []}
-
-    # --- check ---
-    if not s_name or not e_name:
-        return {'code': 2, 'data': []}
-
-    # --- prepare ---
-    if 'dump' in s_name:
-        s_point_item = dict(**d2.get(s_name), **{'name': s_name})
-    else:
-        s_point_item = dict(**d4.get(s_name), **{'name': s_name})
-
-    # --- prepare ---
-    if 'dump' in e_name:
-        e_point_item = dict(**d2.get(e_name), **{'name': e_name})
-    else:
-        e_point_item = dict(**d4.get(e_name), **{'name': e_name})
-
-    # --- check --- 判断是否是在正前方的情况1
-    if s_direction == 'head' and 'dump' not in s_name and 'dump' not in e_name:
-        s_s1, s_s2 = s_name.split('.')
-        e_s1, e_s2 = e_name.split('.')
-        if s_s1 == e_s1 and int(e_s2) < int(s_s2):
-            return {'code': 0, 'data': [s_point_item, e_point_item]}
-
-    # --- check --- 判断是否是在正前方的情况2
-    if s_direction == 'tail' and 'dump' not in s_name and 'dump' not in e_name:
-        s_s1, s_s2 = s_name.split('.')
-        e_s1, e_s2 = e_name.split('.')
-        if s_s1 == e_s1 and int(s_s2) < int(e_s2):
-            return {'code': 0, 'data': [s_point_item, e_point_item]}
-
-    # --- check --- head方向,向下行驶,并拐弯情况(共2个弯,1个出弯,1个入弯)
-    if s_direction == 'head' and 'dump' not in s_name and 'dump' not in e_name:
-        s_s1, s_s2 = s_name.split('.')
-        e_s1, e_s2 = e_name.split('.')
-        if s_s1 != e_s1:
-            w1 = get_path_name_by_pot_name(s_name)[:1]  # 第一位
-            center_point_item_1 = get_center_point_by_keyword(w1=w1, w2='head')
-            w1 = get_path_name_by_pot_name(e_name)[-1:]  # 最后位
-            center_point_item_2 = get_center_point_by_keyword(w1=w1, w2='head')
-            return {'code': 0, 'data': [s_point_item, center_point_item_1, center_point_item_2, e_point_item]}
-
-    # --- check --- head方向,向下行驶,从包位到倒渣口(共1个弯,1个出弯)
-    if s_direction == 'head' and 'dump' not in s_name and 'dump' in e_name:
-        pass
-
-    # --- check --- head方向,向下行驶,从倒渣口到包位(共1个弯,1个入弯)
-    if s_direction == 'head' and 'dump' in s_name and 'dump' not in e_name:
-        pass
-
-    # --- check --- tail方向,向上行驶,从倒渣口到包位(共1个弯,1个入弯)
-    if s_direction == 'tail' and 'dump' in s_name and 'dump' not in e_name:
-        pass
-
-    # --- check --- tail方向,向上行驶,从倒渣口到包位(共1个弯,1个入弯)
-    if s_direction == 'tail' and 'dump' in s_name and 'dump' not in e_name:
-        pass
-
-
-if __name__ == '__main__':
-    # --- test ---
-    # 判断是否是在正前方的情况1
-    # out = test(s_direction='head', s_name='M.10', e_name='M.1')
-    # 判断是否是在正前方的情况2
-    # out = test(s_direction='tail', s_name='M.12', e_name='M.20')
-    # head方向,向下行驶,并拐弯情况(共2个弯,1个是出弯,1个是入弯)
-    out = test(s_direction='head', s_name='M.12', e_name='F.20')
-    print(out)
-

+ 0 - 434
project-fastapi-hs/unit/Scheduler_b1.py

@@ -1,434 +0,0 @@
-"""
-
-"""
-
-# 圆心点坐标字典
-d1 = {
-    'LM.head': {'center': (11, 22)},
-    'JK.head': {'center': (11, 22)},
-    'HI.head': {'center': (11, 22)},
-    'FG.head': {'center': (11, 22)},
-    'DE.head': {'center': (11, 22)},
-    'BC.head': {'center': (11, 22)},
-    'A.head': {'center': (11, 22)},
-
-    'LM.tail': {'center': (11, 22)},
-    'JK.tail': {'center': (11, 22)},
-    'HI.tail': {'center': (11, 22)},
-    'FG.tail': {'center': (11, 22)},
-    'DE.tail': {'center': (11, 22)},
-    'BC.tail': {'center': (11, 22)},
-    'A.tail': {'center': (11, 22)},
-
-}
-
-# 倒渣口坐标字典
-d2 = {
-    'dump.MN': {'point': (11, 205.75)},  # 1号倒渣口
-    'dump.KL': {'point': (11, 177.75)},  # 2号倒渣口
-    'dump.IJ': {'point': (11, 149.75)},  # 3号倒渣口
-    'dump.GH': {'point': (11, 121.75)},  # 4号倒渣口
-    'dump.EF': {'point': (11, 93.75)},  # 5号倒渣口
-    'dump.CD': {'point': (11, 65.75)},  # 6号倒渣口
-    'dump.AB': {'point': (11, 37.75)},  # 7号倒渣口
-}
-
-# 接渣口坐标字典
-d3 = {
-    'load.1': {'point': (11, 22)},
-    'load.2': {'point': (11, 22)},
-    'load.3': {'point': (11, 22)},
-}
-
-# 停车区坐标字典
-d5 = {
-    'pack.1': {'x': 77, 'y': 44},
-    'pack.2': {'x': 77, 'y': 44},
-}
-
-# 渣罐坐标字典
-d4 = {
-    'M.31': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.30': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.29': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.28': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.27': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.26': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.25': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.24': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.23': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.22': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.21': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.20': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.19': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.18': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.17': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.16': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.15': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.14': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.13': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.12': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.11': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.10': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.9': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.8': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.7': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.6': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.5': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.4': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.3': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.2': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.1': {'pot': (22, 33), 'road_center': (44, 55)},
-
-    'F.31': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.30': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.29': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.28': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.27': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.26': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.25': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.24': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.23': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.22': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.21': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.20': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.19': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.18': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.17': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.16': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.15': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.14': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.13': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.12': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.11': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.10': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.9': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.8': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.7': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.6': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.5': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.4': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.3': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.2': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.1': {'pot': (22, 33), 'road_center': (44, 55)},
-
-}
-
-
-def get_nearest_point_name_from_pot_point(x, y):
-    """
-    获取当前位置距离最忌的罐体位置名称
-    """
-    x = float(x)
-    y = float(y)
-    min_distance = float('inf')  # 初始值无穷大
-    for k, v in d4.items():
-        center_x = float(v.get('pot')[0])
-        center_y = float(v.get('pot')[1])
-        distance = ((center_x - x) ** 2 + (center_y - y) ** 2) ** (1 / 2)
-
-        if distance < min_distance:
-            min_distance = distance
-            nearest_pot_name = k
-
-    return nearest_pot_name
-
-
-def get_nearest_point_from_road_center_point(x, y):
-    """
-    获取当前所在位置最接近的坐标位置
-    """
-    x = float(x)
-    y = float(y)
-    min_distance = float('inf')  # 初始值无穷大
-    for k, v in d4.items():
-        center_x = float(v.get('road_center')[0])
-        center_y = float(v.get('road_center')[1])
-        distance = ((center_x - x) ** 2 + (center_y - y) ** 2) ** (1 / 2)
-
-        if distance < min_distance:
-            min_distance = distance
-            nearest_point = center_x, center_y
-
-    return nearest_point
-
-
-def get_center_point_by_keyword(w1='N', w2='head'):
-    """
-    获取圆心点坐标
-    w1: 关键字
-    w2: 关键字
-    """
-    for k, v in d1.items():
-        k_s1, k_s2 = k.split('.')
-        if w1 not in k_s1:
-            continue
-        if w2 not in k_s2:
-            continue
-        return dict(**v, **{'name': k})
-
-
-def get_path_name_by_pot_name(pot_name='M.25'):
-    """根据渣罐名获取道路名"""
-    s1, s2 = pot_name.split('.')
-    path_name_list = [
-        'MN',
-        'KL',
-        'IJ',
-        'GH',
-        'EF',
-        'CD',
-        'AB',
-    ]
-    for s in path_name_list:
-        if s1 in s:
-            return s
-
-
-def get_path_name_by_dump_name(dump_name='dump.MN'):
-    """根据渣罐名获取道路名"""
-    _, s2 = dump_name.split('.')
-    return s2
-
-
-import json
-
-
-def test(current_direction_type=3, start_x=11, start_y=22, target_point_name='M.1'):
-    """
-    current_direction_type: 起始方向  3 围栏方向 9 渣场方向 12 维修间方向 6 维修间正对方向 0 未知(默认值)
-    s_name: 起始位置
-    e_name: 目标位置
-    """
-    # --- update d4 ---
-    # data = json.load(open('../data/渣罐坐标数据.json', 'r'))
-    # data = json.load(open('/home/ubuntu/repositories/repositories/casperz.py-project/project-fastapi-hs/data/渣罐坐标数据.json', 'r'))
-    data = json.load(
-        open(r'E:\casper\repositories\repositories\casperz.py-project\project-fastapi-hs\data\渣罐坐标数据.json', 'rb'))
-    for item in data.get('pot_name|pot_x|pot_y|road_center_x|road_center_y'):
-        pot_name, pot_x, pot_y, road_center_x, road_center_y = item.split('|')
-        d4[pot_name] = {
-            'pot': (pot_x, pot_y),
-            'road_center': (road_center_x, road_center_y),
-        }
-
-    # --- update d2 ---
-    # data = json.load(open('../data/渣罐坐标数据.json', 'r'))
-    # data = json.load(open('/home/ubuntu/repositories/repositories/casperz.py-project/project-fastapi-hs/data/倒渣口坐标数据.json', 'r'))
-    data = json.load(
-        open(r'E:\casper\repositories\repositories\casperz.py-project\project-fastapi-hs\data\倒渣口坐标数据.json',
-             'rb'))
-    for item in data.get('name|x|y'):
-        name, x, y = item.split('|')
-        d2[name] = {
-            'point': (x, y),
-        }
-
-    # --- check ---
-    if current_direction_type not in [3, 9]:
-        return 1  # 暂不支持
-
-    # --- check ---
-    if not start_x or not start_y:
-        return 2  # 参数缺失
-
-    # --- define ---
-    current_point_name = get_nearest_point_name_from_pot_point(start_x, start_y)
-
-    # --- define ---
-    if 'dump' in current_point_name:
-        s_point_item = dict(**d2.get(current_point_name), **{'name': current_point_name})
-    else:
-        s_point_item = dict(**d4.get(current_point_name), **{'name': current_point_name})
-
-    # --- define ---
-    if 'dump' in target_point_name:
-        e_point_item = dict(**d2.get(target_point_name), **{'name': target_point_name})
-    else:
-        e_point_item = dict(**d4.get(target_point_name), **{'name': target_point_name})
-
-    # --- define ---
-    radius = 14  # 转弯半径
-    s_s1, s_s2 = current_point_name.split('.')
-    e_s1, e_s2 = target_point_name.split('.')
-    print(f"current_point_name: {current_point_name}")
-    print(f"target_point_name: {target_point_name}")
-
-    # --- check ---
-    if 'dump' not in current_point_name and 'dump' not in target_point_name:
-        if current_direction_type == 9 and s_s1 == e_s1 and int(s_s2) > int(e_s2):
-            """
-            情况1:判断是否是在正前方的情况1
-            """
-            return [
-                {
-                    'type': 'forward',
-                    'nav_coordinates': [
-                        {
-                            # 直行轨迹坐标参数
-                            'start_point_x': start_x,
-                            'start_point_y': start_y,
-                            'end_point_x': e_point_item.get('road_center')[0],
-                            'end_point_y': e_point_item.get('road_center')[1],
-                        },
-                    ],
-                }
-            ]
-        elif current_direction_type == 3 and s_s1 == e_s1 and int(s_s2) < int(e_s2):
-            """
-            情况2:判断是否是在正前方的情况2
-            """
-            return [
-                {
-                    'type': 'forward',
-                    'nav_coordinates': [
-                        # 直线行驶
-                        {
-                            'start_point_x': start_x,
-                            'start_point_y': start_y,
-                            'end_point_x': e_point_item.get('road_center')[0],
-                            'end_point_y': e_point_item.get('road_center')[1],
-                        },
-                    ],
-                }
-            ]
-        elif current_direction_type == 9 and s_s1 > e_s1:
-            """
-            情况3:车头9方向,向6点行驶,并拐弯情况(共2个弯,1个是出弯,1个是入弯)
-            """
-            w1 = get_path_name_by_pot_name(current_point_name)[:1]  # 首位
-            center_1 = get_center_point_by_keyword(w1=w1, w2='head')
-            w1 = get_path_name_by_pot_name(target_point_name)[-1:]  # 末位
-            center_2 = get_center_point_by_keyword(w1=w1, w2='head')
-            return [
-                {
-                    'type': 'forward',
-                    'nav_coordinates': [
-                        # 直线行驶
-                        {
-                            'start_point_x': start_x,  # 起始点坐标
-                            'start_point_y': start_y,  # 起始点坐标
-                            'end_point_x': center_1.get('center')[0],  # 入弯坐标
-                            'end_point_y': center_1.get('center')[1] + radius,  # 入弯坐标
-                        },
-                        # 转弯行驶
-                        {
-                            "start_point_x": center_1.get('center')[0],  # 入弯坐标
-                            "start_point_y": center_1.get('center')[1] + radius,  # 入弯坐标
-                            "center_point_x": center_1.get('center')[0],  # 圆心坐标
-                            "center_point_y": center_1.get('center')[1],  # 圆心坐标
-                            "end_point_x": center_1.get('center')[0] - radius,  # 出弯坐标
-                            "end_point_y": center_1.get('center')[1],  # 出弯坐标
-                        },
-                        # 直线行驶
-                        {
-                            'start_point_x': center_1.get('center')[0] - radius,  # 出弯坐标
-                            'start_point_y': center_1.get('center')[1],  # 出弯坐标
-                            'end_point_x': center_2.get('center')[0] - radius,  # 入弯坐标
-                            'end_point_y': center_2.get('center')[1],  # 入弯坐标
-                        },
-                        # 转弯行驶
-                        {
-                            "start_point_x": center_2.get('center')[0] - radius,  # 入弯坐标
-                            "start_point_y": center_2.get('center')[1],  # 入弯坐标
-                            "center_point_x": center_2.get('center')[0],  # 圆心坐标
-                            "center_point_y": center_2.get('center')[1],  # 圆心坐标
-                            "end_point_x": center_2.get('center')[0],  # 出弯坐标
-                            "end_point_y": center_2.get('center')[1] - radius,  # 出弯坐标
-                        },
-                        # 直线行驶
-                        {
-                            'start_point_x': center_2.get('center')[0],  # 出弯坐标
-                            'start_point_y': center_2.get('center')[1] - radius,  # 出弯坐标
-                            'end_point_x': e_point_item.get('road_center')[0],  # 目标点坐标
-                            'end_point_y': e_point_item.get('road_center')[1],  # 目标点坐标
-                        },
-                    ],
-                }
-            ]
-
-    elif 'dump' not in current_point_name and 'dump' in target_point_name:
-        if current_direction_type == 9:
-            """
-            情况4:渣罐位,车头9点方向,6点拐弯,3点拐弯,倒车倒入指定倒渣口
-            """
-            path_name = get_path_name_by_pot_name(current_point_name)
-            # print(f"path_name: {path_name}")
-            corner_name = path_name[:1]  # 拐弯点(9点到6点方向转弯)
-            center_1 = get_center_point_by_keyword(w1=corner_name, w2='head')
-            # print(f"center_1: {center_1}")
-            path_name = get_path_name_by_dump_name(target_point_name)
-            corner_name = path_name[-1:]  # 拐弯点(6点到3点方向转弯)
-            center_2 = get_center_point_by_keyword(w1=corner_name, w2='head')
-            # print(f"center_2: {center_2}")
-            return [
-                {
-                    'type': 'forward',
-                    'nav_coordinates': [
-                        # 直线行驶
-                        {
-                            'start_point_x': start_x,  # 起始点坐标
-                            'start_point_y': start_y,  # 起始点坐标
-                            'end_point_x': center_1.get('center')[0],  # 入弯坐标
-                            'end_point_y': center_1.get('center')[1] + radius,  # 入弯坐标
-                        },
-                        # 转弯行驶
-                        {
-                            "start_point_x": center_1.get('center')[0],  # 入弯坐标
-                            "start_point_y": center_1.get('center')[1] + radius,  # 入弯坐标
-                            "center_point_x": center_1.get('center')[0],  # 圆心坐标
-                            "center_point_y": center_1.get('center')[1],  # 圆心坐标
-                            "end_point_x": center_1.get('center')[0] - radius,  # 出弯坐标
-                            "end_point_y": center_1.get('center')[1],  # 出弯坐标
-                        },
-                        # 直线行驶
-                        {
-                            'start_point_x': center_1.get('center')[0] - radius,  # 出弯坐标
-                            'start_point_y': center_1.get('center')[1],  # 出弯坐标
-                            'end_point_x': center_2.get('center')[0] - radius,  # 入弯坐标
-                            'end_point_y': center_2.get('center')[1],  # 入弯坐标
-                        },
-                        # 转弯行驶
-                        {
-                            "start_point_x": center_2.get('center')[0] - radius,  # 入弯坐标
-                            "start_point_y": center_2.get('center')[1],  # 入弯坐标
-                            "center_point_x": center_2.get('center')[0],  # 圆心坐标
-                            "center_point_y": center_2.get('center')[1],  # 圆心坐标
-                            "end_point_x": center_2.get('center')[0],  # 出弯坐标
-                            "end_point_y": center_2.get('center')[1] - radius,  # 出弯坐标
-                        },
-                        # 直线行驶
-                        {
-                            'start_point_x': center_2.get('center')[0],  # 出弯坐标
-                            'start_point_y': center_2.get('center')[1] - radius,  # 出弯坐标
-                            'end_point_x': center_2.get('center')[0] + 10,  # 3点方向移动10米,摆正车身,为倒车准备
-                            'end_point_y': center_2.get('center')[1] - radius,  # 3点方向移动10米,摆正车身,为倒车准备
-                        },
-                    ]
-                },
-                {
-                    'type': 'backward',
-                    'nav_coordinates': [
-                        # 直线行驶
-                        {
-                            'start_point_x': center_2.get('center')[0] + 10,  # 3点方向移动10米,摆正车身,为倒车准备
-                            'start_point_y': center_2.get('center')[1] - radius,  # 3点方向移动10米,摆正车身,为倒车准备
-                            'end_point_x': e_point_item.get('point')[0],  # 倒渣口坐标
-                            'end_point_y': e_point_item.get('point')[1],  # 倒渣口坐标
-                        },
-                    ]
-                }
-            ]
-
-
-if __name__ == '__main__':
-    # --- test ---
-    # 情况1:判断是否是在正前方的情况1 M.10 -> M.1
-    # out = test(current_direction_type=9, start_x=74, start_y=205.75, target_point_name='M.1')
-    # 情况2:判断是否是在正前方的情况2 M.12 -> M.20
-    # out = test(current_direction_type=3, start_x=85, start_y=205.75, target_point_name='M.20')
-    # 情况3:车头9方向,向6点行驶,并拐弯情况(共2个弯,1个是出弯,1个是入弯)
-    # out = test(current_direction_type=9, start_x=85, start_y=205.75, target_point_name='F.20')
-    # 情况4:渣罐位,车头9点方向,6点拐弯,3点拐弯,倒车倒入指定倒渣口
-    out = test(current_direction_type=9, start_x=74, start_y=205.75, target_point_name='dump.CD')
-    print(out)

+ 0 - 604
project-fastapi-hs/unit/Scheduler_c1.py

@@ -1,604 +0,0 @@
-"""
-tips:
-    推算半径:13.7
-    倒车与正开的偏移量是5米;倒车中心点=正开中心点+5
-"""
-
-# 坐标数据文件
-data_file_dir = '../data'
-data_file_path = '../data/渣罐坐标数据.json'
-# data_file_path = '/home/ubuntu/repositories/repositories/casperz.py-project/project-fastapi-hs/data/渣罐坐标数据.json'
-# data_file_path = r"E:\casper\repositories\repositories\casperz.py-project\project-fastapi-hs\data\渣罐坐标数据.json"
-
-# 道路名称列表
-path_name_list = [
-    'MN',
-    'KL',
-    'IJ',
-    'GH',
-    'EF',
-    'CD',
-    'AB',
-]
-
-# 渣罐坐标字典
-d4 = {
-
-    # 停车区坐标
-    'pack.1': {'point': (11, 22)},
-    'pack.2': {'point': (11, 22)},
-
-    # 接渣口坐标
-    'load.1': {'point': (11, 22)},
-    'load.2': {'point': (11, 22)},
-    'load.3': {'point': (11, 22)},
-
-    # 倒渣口坐标
-    'dump.MN': {'point': (11, 205.75)},  # 1号倒渣口
-    'dump.KL': {'point': (11, 177.75)},  # 2号倒渣口
-    'dump.IJ': {'point': (11, 149.75)},  # 3号倒渣口
-    'dump.GH': {'point': (11, 121.75)},  # 4号倒渣口
-    'dump.EF': {'point': (11, 93.75)},  # 5号倒渣口
-    'dump.CD': {'point': (11, 65.75)},  # 6号倒渣口
-    'dump.AB': {'point': (11, 37.75)},  # 7号倒渣口
-
-    # 渣罐位坐标
-    'M.31': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.30': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.29': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.28': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.27': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.26': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.25': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.24': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.23': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.22': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.21': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.20': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.19': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.18': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.17': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.16': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.15': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.14': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.13': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.12': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.11': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.10': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.9': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.8': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.7': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.6': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.5': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.4': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.3': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.2': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.1': {'pot': (22, 33), 'road_center': (44, 55)},
-
-    'F.31': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.30': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.29': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.28': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.27': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.26': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.25': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.24': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.23': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.22': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.21': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.20': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.19': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.18': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.17': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.16': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.15': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.14': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.13': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.12': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.11': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.10': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.9': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.8': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.7': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.6': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.5': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.4': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.3': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.2': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.1': {'pot': (22, 33), 'road_center': (44, 55)},
-
-}
-
-
-def get_nearest_point_name_from_pot_point(current_x, current_y):
-    """
-    获取当前位置距离最忌的罐体位置名称
-    """
-    current_x = float(current_x)
-    current_y = float(current_y)
-    min_distance = float('inf')  # 初始值无穷大
-    nearest_point_name = str()  # 最近点名称
-
-    # --- check road center ---
-    for k, v in d4.items():
-        if 'pack' in k or 'load' in k or 'dump' in k:
-            continue
-        point_x = float(v.get('road_center')[0])
-        point_y = float(v.get('road_center')[1])
-        distance = ((point_x - current_x) ** 2 + (point_y - current_y) ** 2) ** (1 / 2)
-        if distance < min_distance:
-            min_distance = distance
-            nearest_point_name = k
-
-    # --- check dump port ---
-    for k, v in d4.items():
-        if 'dump' not in k:
-            continue
-        point_x = float(v.get('point')[0])
-        point_y = float(v.get('point')[1])
-        distance = ((point_x - current_x) ** 2 + (point_y - current_y) ** 2) ** (1 / 2)
-        if distance < min_distance:
-            min_distance = distance
-            nearest_point_name = k
-
-    return nearest_point_name
-
-
-def get_nearest_point_from_road_center_point(x, y):
-    """
-    获取当前所在位置最接近的坐标位置
-    """
-    x = float(x)
-    y = float(y)
-    min_distance = float('inf')  # 初始值无穷大
-    for k, v in d4.items():
-        center_x = float(v.get('road_center')[0])
-        center_y = float(v.get('road_center')[1])
-        distance = ((center_x - x) ** 2 + (center_y - y) ** 2) ** (1 / 2)
-
-        if distance < min_distance:
-            min_distance = distance
-            nearest_point = center_x, center_y
-
-    return nearest_point
-
-
-def get_corner_point(w1='N', w2='head'):
-    """获取拐弯点"""
-    if w2 == 'head':
-        return d4.get(f"{w1}.{1}").get('road_center')
-    elif w2 == 'tail':
-        return d4.get(f"{w1}.{31}").get('road_center')
-
-
-def get_path_name_by_pot_name(pot_name='M.25'):
-    """根据渣罐名获取道路名"""
-    s1, s2 = pot_name.split('.')
-    for s in path_name_list:
-        if s1 in s:
-            return s
-
-
-def get_path_name_by_dump_name(dump_name='dump.MN'):
-    """根据渣罐名获取道路名"""
-    _, s2 = dump_name.split('.')
-    return s2
-
-
-import json
-
-
-def test(current_direction_type=3, start_x=11, start_y=22, target_point_name='M.1'):
-    """
-    current_direction_type: 起始方向  3 围栏方向 9 渣场方向 12 维修间方向 6 维修间正对方向 0 未知(默认值)
-    s_name: 起始位置
-    e_name: 目标位置
-    """
-
-    # --- update d4 ---
-    data = json.load(open(data_file_path, 'rb'))
-    for item in data.get('pot_name|pot_x|pot_y|road_center_x|road_center_y'):
-        pot_name, pot_x, pot_y, road_center_x, road_center_y = item.split('|')
-        d4[pot_name] = {
-            'pot': (float(pot_x), float(pot_y)),
-            'road_center': (float(road_center_x), float(road_center_y)),
-        }
-
-    # --- update d4 ---
-    data = json.load(open(f"{data_file_dir}/倒渣口坐标数据.json", 'rb'))
-    for item in data.get('name|x|y'):
-        name, x, y = item.split('|')
-        d4[name] = {
-            'point': (float(x), float(y)),
-        }
-
-    # --- check ---
-    if not start_x and not start_y:
-        return "Reason: 参数缺失"
-
-    # --- check ---
-    if current_direction_type not in [3, 9]:
-        return "Reason: 暂不支持"
-
-    # --- define ---
-    current_point_name = get_nearest_point_name_from_pot_point(start_x, start_y)
-    s_point_item = dict(**d4.get(current_point_name), **{'name': current_point_name})
-    e_point_item = dict(**d4.get(target_point_name), **{'name': target_point_name})
-
-    # --- define ---
-    radius = 14  # 转弯半径
-    s_s1, s_s2 = current_point_name.split('.')
-    e_s1, e_s2 = target_point_name.split('.')
-    print(f"current_point_name: {current_point_name}")
-    print(f"target_point_name: {target_point_name}")
-
-    # --- check ---
-    if 'dump' not in current_point_name and 'dump' not in target_point_name:
-        if current_direction_type == 9 and s_s1 == e_s1 and int(s_s2) > int(e_s2):
-            """
-            情况1:判断是否是在正前方的情况1
-            """
-            return [
-                {
-                    'type': 'forward',
-                    'nav_coordinates': [
-                        {
-                            # 直行轨迹坐标参数
-                            'start_point_x': s_point_item.get('road_center')[0],
-                            'start_point_y': s_point_item.get('road_center')[1],
-                            'end_point_x': e_point_item.get('road_center')[0],
-                            'end_point_y': e_point_item.get('road_center')[1],
-                        },
-                    ],
-                }
-            ]
-        elif current_direction_type == 3 and s_s1 == e_s1 and int(s_s2) < int(e_s2):
-            """
-            情况2:判断是否是在正前方的情况2
-            """
-            return [
-                {
-                    'type': 'forward',
-                    'nav_coordinates': [
-                        # 直线行驶
-                        {
-                            'start_point_x': s_point_item.get('road_center')[0],
-                            'start_point_y': s_point_item.get('road_center')[1],
-                            'end_point_x': e_point_item.get('road_center')[0],
-                            'end_point_y': e_point_item.get('road_center')[1],
-                        },
-                    ],
-                }
-            ]
-        elif current_direction_type == 9 and s_s1 > e_s1:
-            """
-            情况3:车头9方向,向9点6点3点行驶(共2个弯,1个是出弯,1个是入弯)
-            """
-            path_name = get_path_name_by_pot_name(current_point_name)
-            corner_name = path_name[:1]  # 拐弯点(9点到6点方向转弯)(取首位)
-            corner_point_1 = get_corner_point(w1=corner_name, w2='head')
-            corner_point_1_x = corner_point_1[0]
-            corner_point_1_y = corner_point_1[1]
-            path_name = get_path_name_by_pot_name(target_point_name)
-            corner_name = path_name[-1:]  # 拐弯点(6点到3点方向转弯)(取末位)
-            corner_point_2 = get_corner_point(w1=corner_name, w2='head')
-            corner_point_2_x = corner_point_2[0]
-            corner_point_2_y = corner_point_2[1]
-            return [
-                {
-                    'type': 'forward',
-                    'nav_coordinates': [
-                        # 直线行驶
-                        {
-                            'start_point_x': s_point_item.get('road_center')[0],  # 起始点坐标
-                            'start_point_y': s_point_item.get('road_center')[1],  # 起始点坐标
-                            'end_point_x': corner_point_1_x,  # 入弯坐标
-                            'end_point_y': corner_point_1_y,  # 入弯坐标
-                        },
-                        # 转弯行驶
-                        {
-                            "start_point_x": corner_point_1_x,  # 入弯坐标
-                            "start_point_y": corner_point_1_y,  # 入弯坐标
-                            "center_point_x": corner_point_1_x,  # 圆心坐标
-                            "center_point_y": corner_point_1_y - radius,  # 圆心坐标
-                            "end_point_x": corner_point_1_x - radius,  # 出弯坐标
-                            "end_point_y": corner_point_1_y - radius,  # 出弯坐标
-                        },
-                        # 直线行驶
-                        {
-                            'start_point_x': corner_point_1_x - radius,  # 出弯坐标
-                            'start_point_y': corner_point_1_y - radius,  # 出弯坐标
-                            'end_point_x': corner_point_2_x - radius,  # 入弯坐标
-                            'end_point_y': corner_point_2_y + radius,  # 入弯坐标
-                        },
-                        # 转弯行驶
-                        {
-                            "start_point_x": corner_point_2_x - radius,  # 入弯坐标
-                            "start_point_y": corner_point_2_y + radius,  # 入弯坐标
-                            "center_point_x": corner_point_2_x,  # 圆心坐标
-                            "center_point_y": corner_point_2_y + radius,  # 圆心坐标
-                            "end_point_x": corner_point_2_x,  # 出弯坐标
-                            "end_point_y": corner_point_2_y,  # 出弯坐标
-                        },
-                        # 直线行驶
-                        {
-                            'start_point_x': corner_point_2_x,  # 出弯坐标
-                            'start_point_y': corner_point_2_y,  # 出弯坐标
-                            'end_point_x': e_point_item.get('road_center')[0],  # 目标点坐标
-                            'end_point_y': e_point_item.get('road_center')[1],  # 目标点坐标
-                        },
-                    ],
-                }
-            ]
-        elif current_direction_type == 9 and s_s1 == e_s1 and int(s_s2) < int(e_s2):
-            """
-            情况5:判断是否是在正后方的情况1 M.3 -> M.10(共2个弯)
-            """
-            path_name = get_path_name_by_pot_name(current_point_name)
-            corner_name = path_name[:1]  # 拐弯点(9点到6点方向转弯)(取首位)
-            corner_point_1 = get_corner_point(w1=corner_name, w2='head')
-            corner_point_1_x = corner_point_1[0]
-            corner_point_1_y = corner_point_1[1]
-            corner_point_2 = get_corner_point(w1=corner_name, w2='tail')
-            corner_point_2_x = corner_point_2[0]
-            corner_point_2_y = corner_point_2[0]
-            # print(f"corner_point_1: {corner_point_1}")
-            # print(f"corner_point_2: {corner_point_2}")
-            # return "Result: 正在开发"
-            return [
-                {
-                    'type': 'forward',
-                    'nav_coordinates': [
-                        # 直线行驶
-                        {
-                            'start_point_x': s_point_item.get('road_center')[0],  # 起始点坐标
-                            'start_point_y': s_point_item.get('road_center')[1],  # 起始点坐标
-                            'end_point_x': corner_point_1_x,  # 入弯坐标
-                            'end_point_y': corner_point_1_y,  # 入弯坐标
-                        },
-                        # 转弯行驶
-                        {
-                            "start_point_x": corner_point_1_x,  # 入弯坐标
-                            "start_point_y": corner_point_1_y,  # 入弯坐标
-                            "center_point_x": corner_point_1_x,  # 圆心坐标
-                            "center_point_y": corner_point_1_y - radius,  # 圆心坐标
-                            "end_point_x": corner_point_1_x,  # 出弯坐标
-                            "end_point_y": corner_point_1_y - radius - radius,  # 出弯坐标
-                        },
-                        # 直线行驶
-                        {
-                            'start_point_x': corner_point_1_x,  # 出弯坐标
-                            'start_point_y': corner_point_1_y - radius - radius,  # 出弯坐标
-                            'end_point_x': corner_point_2_x,  # 入弯坐标
-                            'end_point_y': corner_point_2_y - radius - radius,  # 入弯坐标
-                        },
-                        # 转弯行驶
-                        {
-                            "start_point_x": corner_point_2_x,  # 入弯坐标
-                            "start_point_y": corner_point_2_y - radius - radius,  # 入弯坐标
-                            "center_point_x": corner_point_2_x,  # 圆心坐标
-                            "center_point_y": corner_point_2_y - radius,  # 圆心坐标
-                            "end_point_x": corner_point_2_x,  # 出弯坐标
-                            "end_point_y": corner_point_2_y,  # 出弯坐标
-                        },
-                        # 直线行驶
-                        {
-                            'start_point_x': corner_point_2_x,  # 出弯坐标
-                            'start_point_y': corner_point_2_y,  # 出弯坐标
-                            'end_point_x': e_point_item.get('road_center')[0],  # 目标点坐标
-                            'end_point_y': e_point_item.get('road_center')[1],  # 目标点坐标
-                        },
-                    ]
-                }
-            ]
-        else:
-            return "Result: 暂不支持"
-
-    elif 'dump' not in current_point_name and 'dump' in target_point_name:
-        if current_direction_type == 9:
-            """
-            情况4:渣罐位,车头9点方向,6点拐弯,3点拐弯,倒车倒入指定倒渣口
-            """
-            path_name = get_path_name_by_pot_name(current_point_name)
-            # print(f"path_name: {path_name}")
-            corner_name = path_name[:1]  # 拐弯点(9点到6点方向转弯)(取首位)
-            corner_point_1 = get_corner_point(w1=corner_name, w2='head')
-            corner_point_1_x = corner_point_1[0]
-            corner_point_1_y = corner_point_1[1]
-            # print(f"corner_point_1: {corner_point_1}")
-            path_name = get_path_name_by_dump_name(target_point_name)
-            corner_name = path_name[-1:]  # 拐弯点(6点到3点方向转弯)(取末位)
-            corner_point_2 = get_corner_point(w1=corner_name, w2='head')
-            corner_point_2_x = corner_point_2[0]
-            corner_point_2_y = corner_point_2[1]
-            # print(f"corner_point_2: {corner_point_2}")
-            return [
-                {
-                    'type': 'forward',
-                    'nav_coordinates': [
-                        # 直线行驶
-                        {
-                            'start_point_x': s_point_item.get('road_center')[0],  # 起始点坐标
-                            'start_point_y': s_point_item.get('road_center')[1],  # 起始点坐标
-                            'end_point_x': corner_point_1_x,  # 入弯坐标
-                            'end_point_y': corner_point_1_y,  # 入弯坐标
-                        },
-                        # 转弯行驶
-                        {
-                            "start_point_x": corner_point_1_x,  # 入弯坐标
-                            "start_point_y": corner_point_1_y,  # 入弯坐标
-                            "center_point_x": corner_point_1_x,  # 圆心坐标
-                            "center_point_y": corner_point_1_y - radius,  # 圆心坐标
-                            "end_point_x": corner_point_1_x - radius,  # 出弯坐标
-                            "end_point_y": corner_point_1_y - radius,  # 出弯坐标
-                        },
-                        # 直线行驶
-                        {
-                            'start_point_x': corner_point_1_x - radius,  # 出弯坐标
-                            'start_point_y': corner_point_1_y - radius,  # 出弯坐标
-                            'end_point_x': corner_point_2_x - radius,  # 入弯坐标
-                            'end_point_y': corner_point_2_y + radius,  # 入弯坐标
-                        },
-                        # 转弯行驶
-                        {
-                            "start_point_x": corner_point_2_x - radius,  # 入弯坐标
-                            "start_point_y": corner_point_2_y + radius,  # 入弯坐标
-                            "center_point_x": corner_point_2_x,  # 圆心坐标
-                            "center_point_y": corner_point_2_y + radius,  # 圆心坐标
-                            "end_point_x": corner_point_2_x,  # 出弯坐标
-                            "end_point_y": corner_point_2_y,  # 出弯坐标
-                        },
-                        # 直线行驶
-                        {
-                            'start_point_x': corner_point_2_x,  # 出弯坐标
-                            'start_point_y': corner_point_2_y,  # 出弯坐标
-                            'end_point_x': corner_point_2_x + 30,  # 前进30米,摆正车身,为倒车准备
-                            'end_point_y': corner_point_2_y,  # 摆正车身,为倒车准备
-                        },
-                    ]
-                },
-                {
-                    'type': 'backward',
-                    'nav_coordinates': [
-                        # 直线行驶
-                        {
-                            'start_point_x': corner_point_2_x + 30,  # 前进30米,摆正车身,为倒车准备
-                            'start_point_y': corner_point_2_y,  # 摆正车身,为倒车准备
-                            'end_point_x': e_point_item.get('point')[0],  # 倒渣口坐标
-                            'end_point_y': e_point_item.get('point')[1],  # 倒渣口坐标
-                        },
-                    ]
-                }
-            ]
-        else:
-            return "Result: 暂不支持"
-    elif 'dump' in current_point_name and 'dump' not in target_point_name and current_direction_type == 3:
-        if e_s1 in s_s2:
-            """
-            情况6:倒渣位,车头3点方向,目标点正对目标巷道情况
-            """
-            return [
-                {
-                    'type': 'forward',
-                    'nav_coordinates': [
-                        # 直线行驶
-                        {
-                            'start_point_x': s_point_item.get('point')[0],  # 起始点坐标
-                            'start_point_y': s_point_item.get('point')[1],  # 起始点坐标
-                            'end_point_x': e_point_item.get('road_center')[0],  # 目标点坐标
-                            'end_point_y': e_point_item.get('road_center')[1],  # 目标点坐标
-                        },
-                    ]
-                }
-            ]
-        elif e_s1 > s_s2[1]:
-            """
-            情况7:倒渣位,车头3点方向,目标点位于巷道上侧
-            """
-            path_name = get_path_name_by_dump_name(current_point_name)
-            corner_name = path_name[-1:]  # 拐弯点(3点->12点)(取末位)
-            corner_point_1_x, corner_point_1_y = get_corner_point(w1=corner_name, w2='tail')
-            path_name = get_path_name_by_pot_name(target_point_name)
-            corner_name = path_name[:1]  # 拐弯点(12点->9点)(取首位)
-            corner_point_2_x, corner_point_2_y = get_corner_point(w1=corner_name, w2='tail')
-            # print(f"corner_point_2_x: {corner_point_2_x}")
-            # print(f"corner_point_2_y: {corner_point_2_y}")
-            nav_coordinates_1 = [
-                # 直线行驶
-                {
-                    'start_point_x': s_point_item.get('point')[0],  # 起始点坐标
-                    'start_point_y': s_point_item.get('point')[1],  # 起始点坐标
-                    'end_point_x': corner_point_1_x,  # 入弯坐标
-                    'end_point_y': corner_point_1_y,  # 入弯坐标
-                },
-                # 转弯行驶
-                {
-                    "start_point_x": corner_point_1_x,  # 入弯坐标
-                    "start_point_y": corner_point_1_y,  # 入弯坐标
-                    "center_point_x": corner_point_1_x,  # 圆心坐标
-                    "center_point_y": corner_point_1_y + radius,  # 圆心坐标
-                    "end_point_x": corner_point_1_x + radius,  # 出弯坐标
-                    "end_point_y": corner_point_1_y + radius,  # 出弯坐标
-                },
-
-            ]
-            nav_coordinates_2 = [
-                # 直线行驶
-                {
-                    'start_point_x': corner_point_1_x + radius,  # 出弯坐标
-                    'start_point_y': corner_point_1_y + radius,  # 出弯坐标
-                    'end_point_x': corner_point_2_x + radius,  # 入弯坐标
-                    'end_point_y': corner_point_2_y - radius,  # 入弯坐标
-                }
-            ]
-            # --- check ---
-            if (corner_point_1_x + radius == corner_point_2_x + radius
-                    or corner_point_1_y + radius == corner_point_2_y - radius):
-                nav_coordinates_2 = []
-            nav_coordinates_3 = [
-                # 转弯行驶
-                {
-                    "start_point_x": corner_point_2_x + radius,  # 入弯坐标
-                    "start_point_y": corner_point_2_y - radius,  # 入弯坐标
-                    "center_point_x": corner_point_2_x,  # 圆心坐标
-                    "center_point_y": corner_point_2_y - radius,  # 圆心坐标
-                    "end_point_x": corner_point_2_x,  # 出弯坐标
-                    "end_point_y": corner_point_2_y,  # 出弯坐标
-                },
-                # 直线行驶
-                {
-                    'start_point_x': corner_point_2_x,  # 出弯坐标
-                    'start_point_y': corner_point_2_y,  # 出弯坐标
-                    'end_point_x': e_point_item.get('road_center')[0],  # 目标点坐标
-                    'end_point_y': e_point_item.get('road_center')[1],  # 目标点坐标
-                }
-            ]
-            return [
-                {
-                    'type': 'forward',
-                    'nav_coordinates': nav_coordinates_1 + nav_coordinates_2 + nav_coordinates_3
-                }
-            ]
-        elif e_s1 < s_s2[0]:
-            """
-            情况8:倒渣位,车头3点方向,目标点位于巷道下侧
-            """
-            return "Result: 暂不支持 222"
-        else:
-            return "Result: 暂不支持"
-        return "Result: 暂不支持"
-    else:
-        return "Result: 暂不支持"
-
-
-if __name__ == '__main__':
-    # --- 现场实际测试数据 ---
-    offset = 6.4
-    M01 = 14.450 + (offset * 0), 199.64
-    M31 = 184.93 - (offset * 6), 195.7
-    M03 = 35.5, 205.75
-    M12 = 85, 205.75
-    # --- cad理论测试数据 ---
-    dumpCD = 4.18, 65.75
-    # 情况1:判断是否是在正前方的情况1 M.10 -> M.2
-    # out = test(current_direction_type=9, start_x=M31[0], start_y=M31[1], target_point_name='M.1')
-    # 情况2:判断是否是在正前方的情况2 M.12 -> M.20
-    # out = test(current_direction_type=3, start_x=M12[0], start_y=M12[1], target_point_name='M.20')
-    # 情况3:车头9方向,向6点行驶,并拐弯情况(共2个弯,1个是出弯,1个是入弯)
-    # out = test(current_direction_type=9, start_x=M12[0], start_y=M12[1], target_point_name='F.20')
-    # 情况4:渣罐位,车头9点方向,6点拐弯,3点拐弯,倒车倒入指定倒渣口
-    # out = test(current_direction_type=9, start_x=M31[0], start_y=M31[1], target_point_name='dump.CD')
-    # out = test(current_direction_type=9, start_x=M03[0], start_y=M03[1], target_point_name='dump.CD')
-    # 情况5:判断是否是在正后方的情况1 M.3 -> M.10(共2个弯)
-    # out = test(current_direction_type=9, start_x=M01[0], start_y=M01[1], target_point_name='M.10')
-    # out = test(current_direction_type=9, start_x=M03[0], start_y=M03[1], target_point_name='M.10')
-    # 情况6:倒渣位,车头3点方向,目标点正对目标巷道情况
-    # out = test(current_direction_type=3, start_x=dumpCD[0], start_y=dumpCD[1], target_point_name='D.20')
-    # 情况7:倒渣位,车头3点方向,目标点位于巷道上侧
-    # out = test(current_direction_type=3, start_x=dumpCD[0], start_y=dumpCD[1], target_point_name='M.1')
-    # 情况8:倒渣位,车头3点方向,目标点位于巷道下侧  todo 存在一上来就转弯,有个圆心怎么算呢
-    # out = test(current_direction_type=3, start_x=dumpCD[0], start_y=dumpCD[1], target_point_name='A.30')
-    print(out)
-    # --- test ---
-    # out = get_nearest_point_name_from_pot_point(dumpCD[0], dumpCD[1])
-    # print(out)

+ 0 - 648
project-fastapi-hs/unit/Scheduler_d1.py

@@ -1,648 +0,0 @@
-"""
-tips:
-    推算半径:13.7
-    倒车与正开的偏移量是5米;倒车中心点=正开中心点+5
-"""
-
-# 坐标数据文件
-data_file_dir = '../data'
-data_file_path = '../data/渣罐坐标数据.json'
-# data_file_path = '/home/ubuntu/repositories/repositories/casperz.py-project/project-fastapi-hs/data/渣罐坐标数据.json'
-# data_file_path = r"E:\casper\repositories\repositories\casperz.py-project\project-fastapi-hs\data\渣罐坐标数据.json"
-
-# 道路名称列表
-path_name_list = [
-    'MN',
-    'KL',
-    'IJ',
-    'GH',
-    'EF',
-    'CD',
-    'AB',
-]
-
-# 圆心点坐标字典
-d1 = {
-    'LM.head': {'center_x': 11, 'center_y': 22},
-    'JK.head': {'center_x': 11, 'center_y': 22},
-    'HI.head': {'center_x': 11, 'center_y': 22},
-    'FG.head': {'center_x': 11, 'center_y': 22},
-    'DE.head': {'center_x': 11, 'center_y': 22},
-    'BC.head': {'center_x': 11, 'center_y': 22},
-    'A.head': {'center_x': 11, 'center_y': 22},
-
-    'LM.tail': {'center_x': 11, 'center_y': 22},
-    'JK.tail': {'center_x': 11, 'center_y': 22},
-    'HI.tail': {'center_x': 11, 'center_y': 22},
-    'FG.tail': {'center_x': 11, 'center_y': 22},
-    'DE.tail': {'center_x': 11, 'center_y': 22},
-    'BC.tail': {'center_x': 11, 'center_y': 22},
-    'A.tail': {'center_x': 11, 'center_y': 22},
-
-}
-
-# 渣罐坐标字典
-d4 = {
-
-    # 停车区坐标
-    'pack.1': {'point': (11, 22)},
-    'pack.2': {'point': (11, 22)},
-
-    # 接渣口坐标
-    'load.1': {'point': (11, 22)},
-    'load.2': {'point': (11, 22)},
-    'load.3': {'point': (11, 22)},
-
-    # 倒渣口坐标
-    'dump.MN': {'point': (11, 205.75)},  # 1号倒渣口
-    'dump.KL': {'point': (11, 177.75)},  # 2号倒渣口
-    'dump.IJ': {'point': (11, 149.75)},  # 3号倒渣口
-    'dump.GH': {'point': (11, 121.75)},  # 4号倒渣口
-    'dump.EF': {'point': (11, 93.75)},  # 5号倒渣口
-    'dump.CD': {'point': (11, 65.75)},  # 6号倒渣口
-    'dump.AB': {'point': (11, 37.75)},  # 7号倒渣口
-
-    # 渣罐位坐标
-    'M.31': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.30': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.29': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.28': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.27': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.26': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.25': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.24': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.23': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.22': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.21': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.20': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.19': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.18': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.17': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.16': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.15': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.14': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.13': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.12': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.11': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.10': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.9': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.8': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.7': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.6': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.5': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.4': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.3': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.2': {'pot': (22, 33), 'road_center': (44, 55)},
-    'M.1': {'pot': (22, 33), 'road_center': (44, 55)},
-
-    'F.31': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.30': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.29': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.28': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.27': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.26': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.25': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.24': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.23': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.22': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.21': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.20': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.19': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.18': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.17': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.16': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.15': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.14': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.13': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.12': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.11': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.10': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.9': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.8': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.7': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.6': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.5': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.4': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.3': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.2': {'pot': (22, 33), 'road_center': (44, 55)},
-    'F.1': {'pot': (22, 33), 'road_center': (44, 55)},
-
-}
-
-
-def get_nearest_point_name_from_pot_point(current_x, current_y):
-    """
-    获取当前位置距离最忌的罐体位置名称
-    """
-    current_x = float(current_x)
-    current_y = float(current_y)
-    min_distance = float('inf')  # 初始值无穷大
-    nearest_point_name = str()  # 最近点名称
-
-    # --- check road center ---
-    for k, v in d4.items():
-        if 'pack' in k or 'load' in k or 'dump' in k:
-            continue
-        point_x = float(v.get('road_center')[0])
-        point_y = float(v.get('road_center')[1])
-        distance = ((point_x - current_x) ** 2 + (point_y - current_y) ** 2) ** (1 / 2)
-        if distance < min_distance:
-            min_distance = distance
-            nearest_point_name = k
-
-    # --- check dump port ---
-    for k, v in d4.items():
-        if 'dump' not in k:
-            continue
-        point_x = float(v.get('point')[0])
-        point_y = float(v.get('point')[1])
-        distance = ((point_x - current_x) ** 2 + (point_y - current_y) ** 2) ** (1 / 2)
-        if distance < min_distance:
-            min_distance = distance
-            nearest_point_name = k
-
-    return nearest_point_name
-
-
-def get_nearest_point_from_road_center_point(x, y):
-    """
-    获取当前所在位置最接近的坐标位置
-    """
-    x = float(x)
-    y = float(y)
-    min_distance = float('inf')  # 初始值无穷大
-    for k, v in d4.items():
-        center_x = float(v.get('road_center')[0])
-        center_y = float(v.get('road_center')[1])
-        distance = ((center_x - x) ** 2 + (center_y - y) ** 2) ** (1 / 2)
-
-        if distance < min_distance:
-            min_distance = distance
-            nearest_point = center_x, center_y
-
-    return nearest_point
-
-
-def get_path_name_by_pot_name(pot_name='M.25'):
-    """根据渣罐名获取道路名"""
-    s1, s2 = pot_name.split('.')
-    for s in path_name_list:
-        if s1 in s:
-            return s
-
-
-def get_path_name_by_dump_name(dump_name='dump.MN'):
-    """根据渣罐名获取道路名"""
-    _, s2 = dump_name.split('.')
-    return s2
-
-
-def get_center_point(w1='N', w2='head'):
-    """
-    获取圆心点坐标
-    w1: 关键字
-    w2: 关键字
-    """
-    for k, v in d1.items():
-        k_s1, k_s2 = k.split('.')
-        if w1 not in k_s1:
-            continue
-        if w2 not in k_s2:
-            continue
-        return dict(**v, **{'name': k})
-
-
-import json
-import numpy
-
-
-def test(current_direction_type=3, start_x=11, start_y=22, target_point_name='M.1'):
-    """
-    current_direction_type: 起始方向  3 围栏方向 9 渣场方向 12 维修间方向 6 维修间正对方向 0 未知(默认值)
-    start_x: 起始位置
-    start_y: 起始位置
-    target_point_name: 目标名称
-    """
-
-    # --- update d1 ---
-    data = json.load(open(f"{data_file_dir}/圆心坐标数据.json", 'rb'))
-    for item in data.get(
-            'name|center_x|center_y|center_3_x|center_3_y|center_9_x|center_9_y|center_12_x|center_12_y|center_6_x|center_6_y'):
-        name, center_x, center_y, center_3_x, center_3_y, center_9_x, center_9_y, center_12_x, center_12_y, center_6_x, center_6_y = item.split(
-            '|')
-        d1[name] = {
-            'center_x': float(center_x),
-            'center_y': float(center_y),
-            'center_3_x': float(center_3_x),
-            'center_3_y': float(center_3_y),
-            'center_9_x': float(center_9_x),
-            'center_9_y': float(center_9_y),
-            'center_12_x': float(center_12_x),
-            'center_12_y': float(center_12_y),
-            'center_6_x': float(center_6_x),
-            'center_6_y': float(center_6_y),
-        }
-
-    # --- update d4 ---
-    data = json.load(open(data_file_path, 'rb'))
-    for item in data.get('pot_name|pot_x|pot_y|road_center_x|road_center_y'):
-        pot_name, pot_x, pot_y, road_center_x, road_center_y = item.split('|')
-        d4[pot_name] = {
-            'pot': (float(pot_x), float(pot_y)),
-            'road_center': (float(road_center_x), float(road_center_y)),
-        }
-
-    # --- update d4 ---
-    data = json.load(open(f"{data_file_dir}/倒渣口坐标数据.json", 'rb'))
-    for item in data.get('name|x|y'):
-        name, x, y = item.split('|')
-        d4[name] = {
-            'point': (float(x), float(y)),
-        }
-
-    # --- check ---
-    if not start_x and not start_y:
-        return "Reason: 参数缺失"
-
-    # --- check ---
-    if current_direction_type not in [3, 9]:
-        return "Reason: 暂不支持"
-
-    # --- define ---
-    current_point_name = get_nearest_point_name_from_pot_point(start_x, start_y)
-    s_point_item = dict(**d4.get(current_point_name), **{'name': current_point_name})
-    e_point_item = dict(**d4.get(target_point_name), **{'name': target_point_name})
-
-    # --- define ---
-    radius = 14  # 转弯半径
-    s_s1, s_s2 = current_point_name.split('.')
-    e_s1, e_s2 = target_point_name.split('.')
-    print(f"current_point_name: {current_point_name}")
-    print(f"target_point_name: {target_point_name}")
-
-    # --- check ---
-    if 'dump' not in current_point_name and 'dump' not in target_point_name:
-        if current_direction_type == 9 and s_s1 == e_s1 and int(s_s2) > int(e_s2):
-            """
-            情况1:判断是否是在正前方的情况1
-            """
-            return [
-                {
-                    'type': 'forward',
-                    'nav_coordinates': [
-                        {
-                            # 直行轨迹坐标参数
-                            'start_point_x': s_point_item.get('road_center')[0],
-                            'start_point_y': s_point_item.get('road_center')[1],
-                            'end_point_x': e_point_item.get('road_center')[0],
-                            'end_point_y': e_point_item.get('road_center')[1],
-                        },
-                    ],
-                }
-            ]
-        elif current_direction_type == 3 and s_s1 == e_s1 and int(s_s2) < int(e_s2):
-            """
-            情况2:判断是否是在正前方的情况2
-            """
-            return [
-                {
-                    'type': 'forward',
-                    'nav_coordinates': [
-                        # 直线行驶
-                        {
-                            'start_point_x': s_point_item.get('road_center')[0],
-                            'start_point_y': s_point_item.get('road_center')[1],
-                            'end_point_x': e_point_item.get('road_center')[0],
-                            'end_point_y': e_point_item.get('road_center')[1],
-                        },
-                    ],
-                }
-            ]
-        elif current_direction_type == 9 and s_s1 > e_s1:
-            """
-            情况3:从起始渣罐位向9点6点3点方向行驶到目标渣罐位
-            """
-            path_name = get_path_name_by_pot_name(current_point_name)
-            corner_name = path_name[:1]  # 拐弯点 9点向6点 取首位
-            center_point_1 = get_center_point(w1=corner_name, w2='head')
-            path_name = get_path_name_by_pot_name(target_point_name)
-            corner_name = path_name[-1:]  # 拐弯点 6点向3点 取末位
-            center_point_2 = get_center_point(w1=corner_name, w2='head')
-            # print(f"debug.294: center_point_1: {center_point_1}")
-            # print(f"debug.294: center_point_2: {center_point_2}")
-            return [
-                {
-                    'type': 'forward',
-                    'nav_coordinates': [
-                        # 直线行驶
-                        {
-                            'start_point_x': s_point_item.get('road_center')[0],  # 起始点坐标
-                            'start_point_y': s_point_item.get('road_center')[1],  # 起始点坐标
-                            'end_point_x': center_point_1.get('center_12_x'),  # 入弯坐标
-                            'end_point_y': center_point_1.get('center_12_y'),  # 入弯坐标
-                        },
-                        # 转弯行驶
-                        {
-                            "start_point_x": center_point_1.get('center_12_x'),  # 入弯坐标
-                            "start_point_y": center_point_1.get('center_12_y'),  # 入弯坐标
-                            "center_point_x": center_point_1.get('center_x'),  # 圆心坐标
-                            "center_point_y": center_point_1.get('center_y'),  # 圆心坐标
-                            "end_point_x": center_point_1.get('center_9_x'),  # 出弯坐标
-                            "end_point_y": center_point_1.get('center_9_y'),  # 出弯坐标
-                        },
-                        # 直线行驶
-                        {
-                            'start_point_x': center_point_1.get('center_9_x'),  # 出弯坐标
-                            'start_point_y': center_point_1.get('center_9_y'),  # 出弯坐标
-                            'end_point_x': center_point_2.get('center_9_x'),  # 入弯坐标
-                            'end_point_y': center_point_2.get('center_9_y'),  # 入弯坐标
-                        },
-                        # 转弯行驶
-                        {
-                            "start_point_x": center_point_2.get('center_9_x'),  # 入弯坐标
-                            "start_point_y": center_point_2.get('center_9_y'),  # 入弯坐标
-                            "center_point_x": center_point_2.get('center_x'),  # 圆心坐标
-                            "center_point_y": center_point_2.get('center_y'),  # 圆心坐标
-                            "end_point_x": center_point_2.get('center_6_x'),  # 出弯坐标
-                            "end_point_y": center_point_2.get('center_6_y'),  # 出弯坐标
-                        },
-                        # 直线行驶
-                        {
-                            'start_point_x': center_point_2.get('center_6_x'),  # 出弯坐标
-                            'start_point_y': center_point_2.get('center_6_y'),  # 出弯坐标
-                            'end_point_x': e_point_item.get('road_center')[0],  # 目标点坐标
-                            'end_point_y': e_point_item.get('road_center')[1],  # 目标点坐标
-                        },
-                    ],
-                }
-            ]
-        elif current_direction_type == 9 and s_s1 == e_s1 and int(s_s2) < int(e_s2):
-            """
-            情况5:判断是否是在正后方的情况
-            """
-            path_name = get_path_name_by_pot_name(current_point_name)
-            corner_name = path_name[:1]  # 拐弯点 9点6点3点 取首位
-            center_point_1 = get_center_point(w1=corner_name, w2='head')
-            center_point_2 = get_center_point(w1=corner_name, w2='tail')
-            print(f"debug.403: center_point_1: {center_point_1}")
-            print(f"debug.403: center_point_2: {center_point_2}")
-            return [
-                {
-                    'type': 'forward',
-                    'nav_coordinates': [
-                        # 直线行驶
-                        {
-                            'start_point_x': s_point_item.get('road_center')[0],  # 起始点坐标
-                            'start_point_y': s_point_item.get('road_center')[1],  # 起始点坐标
-                            'end_point_x': center_point_1.get('center_12_x'),  # 入弯坐标
-                            'end_point_y': center_point_1.get('center_12_y'),  # 入弯坐标
-                        },
-                        # 转弯行驶
-                        {
-                            "start_point_x": center_point_1.get('center_12_x'),  # 入弯坐标
-                            "start_point_y": center_point_1.get('center_12_y'),  # 入弯坐标
-                            "center_point_x": center_point_1.get('center_x'),  # 圆心坐标
-                            "center_point_y": center_point_1.get('center_y'),  # 圆心坐标
-                            "end_point_x": center_point_1.get('center_6_x'),  # 出弯坐标
-                            "end_point_y": center_point_1.get('center_6_y'),  # 出弯坐标
-                        },
-                        # 直线行驶
-                        {
-                            'start_point_x': center_point_1.get('center_6_x'),  # 出弯坐标
-                            'start_point_y': center_point_1.get('center_6_x'),  # 出弯坐标
-                            'end_point_x': center_point_2.get('center_6_x'),  # 入弯坐标
-                            'end_point_y': center_point_2.get('center_6_y'),  # 入弯坐标
-                        },
-                        # 转弯行驶
-                        {
-                            "start_point_x": center_point_2.get('center_6_x'),  # 入弯坐标
-                            "start_point_y": center_point_2.get('center_6_y'),  # 入弯坐标
-                            "center_point_x": center_point_2.get('center_x'),  # 圆心坐标
-                            "center_point_y": center_point_2.get('center_y'),  # 圆心坐标
-                            "end_point_x": center_point_2.get('center_12_x'),  # 出弯坐标
-                            "end_point_y": center_point_2.get('center_12_y'),  # 出弯坐标
-                        },
-                        # 直线行驶
-                        {
-                            'start_point_x': center_point_2.get('center_12_x'),  # 出弯坐标
-                            'start_point_y': center_point_2.get('center_12_y'),  # 出弯坐标
-                            'end_point_x': e_point_item.get('road_center')[0],  # 目标点坐标
-                            'end_point_y': e_point_item.get('road_center')[1],  # 目标点坐标
-                        },
-                    ]
-                }
-            ]
-        else:
-            return "Result: 暂不支持"
-
-    elif 'dump' not in current_point_name and 'dump' in target_point_name:
-        if current_direction_type == 9:
-            """
-            情况4:渣罐位,车头9点方向,6点拐弯,3点拐弯,倒车倒入指定倒渣口
-            """
-            # --- get ---
-            path_name = get_path_name_by_pot_name(current_point_name)
-            corner_name = path_name[:1]  # 拐弯点 9点向6点 取首位
-            center_point_1 = get_center_point(w1=corner_name, w2='head')
-            path_name = get_path_name_by_dump_name(target_point_name)
-            corner_name = path_name[-1:]  # 拐弯点 6点向3点 取末位
-            center_point_2 = get_center_point(w1=corner_name, w2='head')
-            print(f"debug.465: center_point_1: {center_point_1}")
-            print(f"debug.465: center_point_2: {center_point_2}")
-            # --- set ---
-            degrees = 1.3
-            short = 30 * numpy.sin(numpy.radians(degrees))
-            long = 30 * numpy.cos(numpy.radians(degrees))
-            return [
-                {
-                    'type': 'forward',
-                    'nav_coordinates': [
-                        # 直线行驶
-                        {
-                            'start_point_x': s_point_item.get('road_center')[0],  # 起始点坐标
-                            'start_point_y': s_point_item.get('road_center')[1],  # 起始点坐标
-                            'end_point_x': center_point_1.get('center_12_x'),  # 入弯坐标
-                            'end_point_y': center_point_1.get('center_12_y'),  # 入弯坐标
-                        },
-                        # 转弯行驶
-                        {
-                            "start_point_x": center_point_1.get('center_12_x'),  # 入弯坐标
-                            "start_point_y": center_point_1.get('center_12_y'),  # 入弯坐标
-                            "center_point_x": center_point_1.get('center_x'),  # 圆心坐标
-                            "center_point_y": center_point_1.get('center_y'),  # 圆心坐标
-                            "end_point_x": center_point_1.get('center_9_x'),  # 出弯坐标
-                            "end_point_y": center_point_1.get('center_9_x'),  # 出弯坐标
-                        },
-                        # 直线行驶
-                        {
-                            'start_point_x': center_point_1.get('center_9_x'),  # 出弯坐标
-                            'start_point_y': center_point_1.get('center_9_x'),  # 出弯坐标
-                            'end_point_x': center_point_2.get('center_9_x'),  # 入弯坐标
-                            'end_point_y': center_point_2.get('center_9_y'),  # 入弯坐标
-                        },
-                        # 转弯行驶
-                        {
-                            "start_point_x": center_point_2.get('center_9_x'),  # 入弯坐标
-                            "start_point_y": center_point_2.get('center_9_y'),  # 入弯坐标
-                            "center_point_x": center_point_2.get('center_x'),  # 圆心坐标
-                            "center_point_y": center_point_2.get('center_x'),  # 圆心坐标
-                            "end_point_x": center_point_2.get('center_6_x'),  # 出弯坐标
-                            "end_point_y": center_point_2.get('center_6_y'),  # 出弯坐标
-                        },
-                        # 直线行驶
-                        {
-                            'start_point_x': center_point_2.get('center_6_x'),  # 出弯坐标
-                            'start_point_y': center_point_2.get('center_6_y'),  # 出弯坐标
-                            'end_point_x': center_point_2.get('center_6_x') + long,  # 前进30米,摆正车身,为倒车准备
-                            'end_point_y': center_point_2.get('center_6_y') - short,  # 前进30米,摆正车身,为倒车准备
-                        },
-                    ]
-                },
-                {
-                    'type': 'backward',
-                    'nav_coordinates': [
-                        # 直线行驶
-                        {
-                            'start_point_x': center_point_2.get('center_6_x') + long,  # 前进30米,摆正车身,为倒车准备
-                            'start_point_y': center_point_2.get('center_6_y') - short,  # 前进30米,摆正车身,为倒车准备
-                            'end_point_x': e_point_item.get('point')[0],  # 倒渣口坐标
-                            'end_point_y': e_point_item.get('point')[1],  # 倒渣口坐标
-                        },
-                    ]
-                }
-            ]
-        else:
-            return "Result: 暂不支持"
-    elif 'dump' in current_point_name and 'dump' not in target_point_name and current_direction_type == 3:
-        if e_s1 in s_s2:
-            """
-            情况6:倒渣位,车头3点方向,目标点正对目标巷道情况
-            """
-            return [
-                {
-                    'type': 'forward',
-                    'nav_coordinates': [
-                        # 直线行驶
-                        {
-                            'start_point_x': s_point_item.get('point')[0],  # 起始点坐标
-                            'start_point_y': s_point_item.get('point')[1],  # 起始点坐标
-                            'end_point_x': e_point_item.get('road_center')[0],  # 目标点坐标
-                            'end_point_y': e_point_item.get('road_center')[1],  # 目标点坐标
-                        },
-                    ]
-                }
-            ]
-        elif e_s1 > s_s2[1]:
-            """
-            情况7:倒渣位,车头3点方向,目标点位于巷道上侧
-            """
-
-            path_name = get_path_name_by_dump_name(current_point_name)
-            corner_name = path_name[-1:]  # 拐弯点 3点12点 取末位
-            center_point_1 = get_center_point(w1=corner_name, w2='tail')
-
-            path_name = get_path_name_by_pot_name(target_point_name)
-            corner_name = path_name[:1]  # 拐弯点 12点9点 取首位
-            center_point_2 = get_center_point(w1=corner_name, w2='tail')
-
-            nav_coordinates_1 = [
-                # 直线行驶
-                {
-                    'start_point_x': s_point_item.get('point')[0],  # 起始点坐标
-                    'start_point_y': s_point_item.get('point')[1],  # 起始点坐标
-                    'end_point_x': center_point_1.get('center_6_x'),  # 入弯坐标
-                    'end_point_y': center_point_1.get('center_6_y'),  # 入弯坐标
-                },
-                # 转弯行驶
-                {
-                    "start_point_x": center_point_1.get('center_6_x'),  # 入弯坐标
-                    "start_point_y": center_point_1.get('center_6_y'),  # 入弯坐标
-                    "center_point_x": center_point_1.get('center_x'),  # 圆心坐标
-                    "center_point_y": center_point_1.get('center_y'),  # 圆心坐标
-                    "end_point_x": center_point_1.get('center_3_x'),  # 出弯坐标
-                    "end_point_y": center_point_1.get('center_3_y'),  # 出弯坐标
-                },
-
-            ]
-            nav_coordinates_2 = [
-                # 直线行驶
-                {
-                    'start_point_x': center_point_1.get('center_3_x'),  # 出弯坐标
-                    'start_point_y': center_point_1.get('center_3_y'),  # 出弯坐标
-                    'end_point_x': center_point_2.get('center_3_x'),  # 入弯坐标
-                    'end_point_y': center_point_2.get('center_3_x'),  # 入弯坐标
-                }
-            ]
-
-            # --- check ---
-            if nav_coordinates_2[0].get('start_point_x') == nav_coordinates_2[0].get('end_point_x'):
-                nav_coordinates_2 = []
-            if nav_coordinates_2[0].get('start_point_y') == nav_coordinates_2[0].get('end_point_y'):
-                nav_coordinates_2 = []
-
-            nav_coordinates_3 = [
-                # 转弯行驶
-                {
-                    "start_point_x": center_point_2.get('center_3_x'),  # 入弯坐标
-                    "start_point_y": center_point_2.get('center_3_x'),  # 入弯坐标
-                    "center_point_x": center_point_2.get('center_x'),  # 圆心坐标
-                    "center_point_y": center_point_2.get('center_y'),  # 圆心坐标
-                    "end_point_x": center_point_2.get('center_12_x'),  # 出弯坐标
-                    "end_point_y": center_point_2.get('center_12_y'),  # 出弯坐标
-                },
-                # 直线行驶
-                {
-                    'start_point_x': center_point_2.get('center_12_x'),  # 出弯坐标
-                    'start_point_y': center_point_2.get('center_12_y'),  # 出弯坐标
-                    'end_point_x': e_point_item.get('road_center')[0],  # 目标点坐标
-                    'end_point_y': e_point_item.get('road_center')[1],  # 目标点坐标
-                }
-            ]
-            return [
-                {
-                    'type': 'forward',
-                    'nav_coordinates': nav_coordinates_1 + nav_coordinates_2 + nav_coordinates_3
-                }
-            ]
-        elif e_s1 < s_s2[0]:
-            """
-            情况8:倒渣位,车头3点方向,目标点位于巷道下侧
-            """
-            return "Result: 暂不支持 222"
-        else:
-            return "Result: 暂不支持"
-        return "Result: 暂不支持"
-    else:
-        return "Result: 暂不支持"
-
-
-if __name__ == '__main__':
-    # --- 现场实际测试数据 ---
-    offset = 6.4
-    M01 = 14.450 + (offset * 0), 199.64
-    M31 = 184.93 - (offset * 6), 195.7
-    M03 = 35.5, 205.75
-    M12 = 85, 205.75
-    dumpCD = 15.49 - 10, 63.06
-    # 情况1:判断是否是在正前方的情况1 M.10 -> M.2
-    # out = test(current_direction_type=9, start_x=M31[0], start_y=M31[1], target_point_name='M.1')
-    # 情况2:判断是否是在正前方的情况2 M.12 -> M.20
-    # out = test(current_direction_type=3, start_x=M12[0], start_y=M12[1], target_point_name='M.20')
-    # 情况3:从起始渣罐位向9点6点3点方向行驶到目标渣罐位 | M.12 -> F.20
-    # out = test(current_direction_type=9, start_x=M12[0], start_y=M12[1], target_point_name='F.20')
-    # 情况4:渣罐位,车头9点方向,6点拐弯,3点拐弯,倒车倒入指定倒渣口
-    # out = test(current_direction_type=9, start_x=M31[0], start_y=M31[1], target_point_name='dump.CD')
-    # out = test(current_direction_type=9, start_x=M03[0], start_y=M03[1], target_point_name='dump.CD')
-    # 情况5:判断是否是在正后方的情况 M.3 -> M.10(共2个弯)
-    # out = test(current_direction_type=9, start_x=M01[0], start_y=M01[1], target_point_name='M.10')
-    # out = test(current_direction_type=9, start_x=M03[0], start_y=M03[1], target_point_name='M.10')
-    # 情况6:倒渣位,车头3点方向,目标点正对目标巷道情况
-    # out = test(current_direction_type=3, start_x=dumpCD[0], start_y=dumpCD[1], target_point_name='D.20')
-    # 情况7:倒渣位,车头3点方向,目标点位于巷道上侧
-    out = test(current_direction_type=3, start_x=dumpCD[0], start_y=dumpCD[1], target_point_name='M.1')
-    # 情况8:倒渣位,车头3点方向,目标点位于巷道下侧  todo 存在一上来就转弯,有个圆心怎么算呢
-    # out = test(current_direction_type=3, start_x=dumpCD[0], start_y=dumpCD[1], target_point_name='A.30')
-    print(out)
-    # --- test ---
-    # out = get_nearest_point_name_from_pot_point(dumpCD[0], dumpCD[1])
-    # print(out)

+ 0 - 12
project-responder-hs/README-usage.bash

@@ -1,12 +0,0 @@
-## NOTE
-
-# 一、构建操作
-# 构建并启动
-echo "BEGIN:" \
-&& project_path="/home/ubuntu/repositories/repositories/casperz.py-project/project-responder-hs" \
-&& cd ${project_path} \
-&& sudo docker-compose --file compose.yml down \
-&& sudo docker-compose --file compose.yml up --detach --build \
-&& sudo docker-compose --file compose.yml logs --follow
-# 日常调试命令
-sudo docker restart sri-module-hs02 && sudo docker logs -f sri-module-hs02

+ 0 - 36
project-responder-hs/api/url.py

@@ -1,36 +0,0 @@
-from api.Command import Command
-from api.Key import Key
-# from api.Task import Task
-# from api.TEST import TEST
-
-action_methods = {
-
-    # --- for command ---
-    'Command.cmd001': (Command, 'cmd001', 'NoBack'),  # update code by git commit
-    'Command.cmd002': (Command, 'cmd002', 'NoBack'),  # update pth by apache server
-    'Command.cmd003': (Command, 'cmd003', 'IsBack'),  # docker ps
-    'Command.cmd004': (Command, 'cmd004', 'IsBack'),  # docker images
-
-    # --- 初始化操作接口 ---
-    'Key.create_key': (Key, 'create_key', 'IsBack'),  # 生成key
-    'Key.verify_key': (Key, 'verify_key', 'IsBack'),  # 验证key
-
-    # --- for task ---
-    # 'Task.task002': (Task, 'task002', 'IsBack'),  # 接收 fastapi 发送来的 uuid 并计算人脸存储特征 同样提供判断该照片是否能用
-    # 'Task.task003': (Task, 'task003', 'IsBack'),  # 为8301接口提供业务支持
-
-    # --- for test ---
-    # 'TEST.test002': (TEST, 'test002', 'NoBack'),  # 刷超分人脸图片接口 将超分图片加入到底库中
-    # 'TEST.test001': (TEST, 'test001', 'NoBack'),  # 批量导入人脸特征数据 from mariadb to mongodb
-    # 'TEST.test004': (TEST, 'test004', 'NoBack'),  # 更新 mongo.VisitorTags 表数据
-    # 'TEST.test006': (TEST, 'test006', 'IsBack'),  # 对比人脸特征
-    # 'TEST.test007': (TEST, 'test007', 'IsBack'),  # 测试websocket在线信息
-    # 'TEST.test008': (TEST, 'test008', 'IsBack'),  # test
-    # 'TEST.test009': (TEST, 'test009', 'IsBack'),  # test
-    # 'TEST.test011': (TEST, 'test011', 'IsBack'),  # 下载语音文件
-    # 'TEST.test012': (TEST, 'test012', 'IsBack'),  # 录入人脸图片
-    # 'TEST.test013': (TEST, 'test013', 'IsBack'),  # 对比人脸图像的相似度
-    # 'TEST.test014': (TEST, 'test014', 'IsBack'),  # 对比人脸图像的相似度
-    # 'TEST.test015': (TEST, 'test015', 'IsBack'),  # 检索相似人脸
-
-}

+ 0 - 162
project-responder-hs/app.py

@@ -1,162 +0,0 @@
-# note: https://responder.kennethreitz.org/en/latest/search.html?q=resp.content
-from hub import methods
-
-
-def generate_app():
-    """"""
-    from api.url import action_methods
-    # from factories.line_manage import LineManage
-
-    # see: https://lzomedia.com/blog/host-fastapi-backend-api-and-react-app-frontend-locally/
-    # --- define middleware --- see: https://www.starlette.io/middleware/
-    # from starlette.applications import Starlette
-    # from starlette.middleware import Middleware
-    # # from starlette.middleware.httpsredirect import HTTPSRedirectMiddleware
-    # # from starlette.middleware.trustedhost import TrustedHostMiddlewar
-    # middleware = [
-    #     Middleware(
-    #         TrustedHostMiddleware,
-    #         allow_credentials=True,
-    #         allowed_hosts=['*'],
-    #         allow_methods=["*"],
-    #         allow_headers=["*"],
-    #     ),
-    #     # Middleware(HTTPSRedirectMiddleware)
-    # ]
-
-    # --- define app --- see: https://responder.kennethreitz.org/en/latest/tour.html#cors
-    import responder
-    app = responder.API(
-        # cors=True,
-        # allow_methods=['*'],
-        # allow_credentials=True,
-    )
-
-    async def coroutine_method(module, method, _params):
-        """协程方法"""
-        # run_at = time.time()
-        result = await getattr(module, method)(**_params)
-        # methods.debug_log(f"app.coroutine_method", f"use time {round(time.time() - run_at, 2)}s")
-        return result
-
-    def foreground_method(module, method, _params):
-        """等待返回"""
-        # run_at = time.time()
-        result = getattr(module, method)(**_params)
-        # methods.debug_log(f"app.foreground_method", f"use time {round(time.time() - run_at, 2)}s")
-        return result
-
-    @app.background.task
-    def background_method(module, method, _params):
-        """不等返回"""
-        # run_at = time.time()
-        result = getattr(module, method)(**_params)
-        # methods.debug_log(f"app.background_method", f"use time {round(time.time() - run_at, 2)}s")
-        return result
-
-    async def run_method(_method_key, _params):
-
-        if _method_key not in action_methods:
-            return dict(code=3, details=f"{_method_key} not found!")
-        else:
-            module, method, method_type = action_methods[_method_key]
-            del _params['module']
-            del _params['method']
-            if method_type == 'IsAsync':
-                return await coroutine_method(module, method, _params)
-            elif method_type == 'IsBack':
-                return foreground_method(module, method, _params)
-            elif method_type == 'NoBack':
-                return background_method(module, method, _params)
-
-    @app.route('/api')
-    async def web_api(request, response):
-        try:
-            if request.params:
-                params = dict(request.params.items())
-            else:
-                params = await request.media()
-
-            # --- todo 存在get请求只能接受一个参数的问题 ---
-            if 'mp3_name' in params:
-                params['module'] = 'TEST'
-                params['method'] = 'test011'
-
-            methods.debug_log('app.web_api', f"m-60: params is {params}")
-            if not params.get('module'):
-                response.media = dict(code=1, details=f"module is null!")
-            elif not params.get('method'):
-                response.media = dict(code=2, details=f"method is null!")
-            else:
-                method_key = f"{params.get('module')}.{params.get('method')}"
-                result = await run_method(method_key, params)
-                if result.__class__.__name__ == 'bytes':
-                    response.content = result
-                elif result.__class__.__name__ == 'str':
-                    response.text = result
-                elif result.__class__.__name__ == 'dict':
-                    response.media = result
-                elif result.__class__.__name__ == 'Future':
-                    response.media = dict(code=0, details=f"{result} is running.")
-                elif not result:
-                    response.media = dict(code=0, details=f"return is null.")
-                else:
-                    response.media = dict(code=0, details=f"return type is {result.__class__.__name__}.")
-
-        except Exception as exception:
-
-            methods.debug_log('app.web_api', f"m-86: exception | {exception}")
-            methods.debug_log('app.web_api', f"m-86: traceback | {methods.trace_log()}")
-            response.media = dict(code=-1, details=f"{methods.trace_log()}")
-
-    @app.route('/line', websocket=True)
-    async def line(ws):
-        """
-        let wsuri = `${location.protocol === 'https' ? 'wss' : 'ws'}://${location.host}:8801/line`;
-        connect_json_text = {
-            line_id: 连接id,暂为token
-        }
-        )
-        send_json_text_1 = {
-            face_uuid: 匹配到的人脸id
-            face_name: 人脸名称
-            input_face_b64: 抓拍图片(b64格式字符串)
-        }
-        """
-        try:
-            await ws.accept()
-            while True:
-
-                data = await ws.receive_text()  # 消息接受方法 receive_{text/json/bytes}
-                if not data:
-                    methods.debug_log('app.line', f"error code is 1!")
-                    break
-                if not methods.is_json(data):
-                    methods.debug_log('app.line', f"error code is 2!")
-                    break
-
-                data = methods.json_loads(data)
-                # methods.debug_log('app.line', f"data: {data}")
-                if not data.get('line_id'):
-                    methods.debug_log('api.line', f"error code is 3!")
-                    break
-
-                # --- check ---
-                if not data.get('line_id'):
-                    methods.debug_log('api.line', f"error code is 4!")
-                    break
-
-                # --- save ---
-                line_id = data.get('line_id')
-                # LineManage.line_dict[line_id] = ws
-
-        except Exception as exception:
-
-            if exception.__class__.__name__ == 'WebSocketDisconnect':
-                await ws.close()
-            else:
-                methods.debug_log('app.line', f"m-136: exception | {exception}")
-                methods.debug_log('app.line', f"m-136: traceback | {methods.trace_log()}")
-
-    # --- return ---
-    return app

+ 0 - 26
project-responder-hs/main.py

@@ -1,26 +0,0 @@
-from app import generate_app
-app = generate_app()
-
-def main():
-    # 定时任务
-    # from lib.JobManage import JobManage
-    # JobManage.run()
-
-    # 监听mqtt消息服务
-    from unit.VehicleStateMessageListener import VehicleStateMessageListener
-    VehicleStateMessageListener.run_background(background_is=True)
-
-    # 监听mqtt消息服务
-    from unit.PotDataMessageListener import PotDataMessageListener
-    PotDataMessageListener.run_background(background_is=True)
-
-    # 给websocket发数据的
-    # from factories.line_manage import LineManage
-    # LineManage.run_background()
-
-    # websocket服务/api服务
-    app.run(address='0.0.0.0', port=5042, debug=True)
-
-
-if __name__ == '__main__':
-    main()

+ 0 - 25
project-responder-hs/test/SRI2024032716-服务端mqtt话题接口文档.txt

@@ -1,25 +0,0 @@
-#车辆状态更新
-mqtt服务地址:192.168.131.23
-mqtt服务端口:41883
-mqtt话题:hs/vehicle/state
-mqtt消息说明:
-{
-    "address": "192.168.131.180",  # 车辆ip
-    "state": 1,  # 车辆状态 1 离线 2 在线空闲 3 人工驾驶中 4 远程驾驶中 5 自动驾驶中
-    "direction": 15,  # 车头方向(场地坐标偏转角度)
-    "coordinate_x": 15,  # 当前车辆坐标
-    "coordinate_y": 15,  # 当前车辆坐标
-    "weight": 15,  # 负载重量
-}
-
-#渣包位置更新
-mqtt服务地址:192.168.131.23
-mqtt服务端口:41883
-mqtt话题:hs/pot/data
-mqtt消息说明:
-{
-  "pot_name": "M.24",  # 渣罐编号
-  "pot_x": 40,  # 坐标值
-  "pot_y": 50,  # 坐标值
-  "mark_pot_pose": 0.3  # 渣罐姿态
-}

+ 0 - 11
project-responder-hs/test/test_key_api.txt

@@ -1,11 +0,0 @@
-import requests
-
-# --- urls ---
-# service_url = 'http://192.168.30.115:18800'
-# service_url = 'http://192.168.30.115:8800'
-service_url = 'http://192.168.30.13:8800'
-# service_url = 'http://192.168.3.59:8802'
-
-# --- test Key ---
-# print(requests.post(url=f'{service_url}/api', json={'module': 'Key', 'method': 'create_key'}).text)
-# print(requests.post(url=f'{service_url}/api', json={'module': 'Key', 'method': 'verify_key'}).text)

+ 0 - 31
project-responder-hs/test/test_mqtt.py

@@ -1,31 +0,0 @@
-import paho.mqtt.client as mqtt
-import time
-import json
-
-client = mqtt.Client()
-client.connect(host='192.168.131.23', port=41883)
-
-
-def test(topic="hs/vehicle/state"):
-    data = {
-        "address": "192.168.131.180",  # 车辆ip
-        "state": 2,  # 车辆状态 1 离线 2 在线空闲 3 人工驾驶中 4 远程驾驶中 5 自动驾驶中
-        "direction": 12,  # 车头方向(场地坐标偏转角度)
-    }
-    return topic, client.publish(topic, json.dumps(data))
-
-# def test(topic="hs/pot/data"):
-#     data = {
-#         "address": "192.168.131.180",  # 车辆ip
-#         "state": 2,  # 车辆状态 1 离线 2 在线空闲 3 人工驾驶中 4 远程驾驶中 5 自动驾驶中
-#         "direction": 12,  # 车头方向(场地坐标偏转角度)
-#     }
-#     return topic, client.publish(topic, json.dumps(data))
-
-if __name__ == '__main__':
-    # --- test ---
-    while True:
-        topic, results = test()
-        result_code, message_id = results
-        print(f"#topic: {topic}, #result_code: {result_code}, #message_id: {message_id}")
-        time.sleep(3)

+ 0 - 41
project-responder-hs/test/test_test_api.txt

@@ -1,41 +0,0 @@
-import requests
-
-service_url = 'http://192.168.0.15:8802'
-# service_url = 'http://192.168.0.16:8802'
-# service_url = 'http://192.168.1.233:8802'
-
-# --- test test api ---
-print(requests.post(url=f'{service_url}/api', json={'module': 'TEST', 'method': 'test002'}).text)
-# print(requests.post(url=f'{service_url}/api', json={'module': 'TEST', 'method': 'test015'}).text)
-
-# --- test test001 导入人脸数据 ---
-# response = requests.post(url=f'{service_url}/api', json={'module': 'TEST', 'method': 'test001'})
-# print(response.text)
-
-# --- test test002 启动循环检查指定rtsp地址 ---
-# data = {
-#     'module': 'TEST',
-#     'method': 'test002',
-#     # 'rtsp_addr': 'rtsp://admin:DEVdev123@192.168.30.233:554/cam/realmonitor?channel=1&subtype=0',  # 大华
-#     'rtsp_addr': 'rtsp://admin:DEVdev123@192.168.30.235:554/h264/ch1/sub/av_stream',  # 海康
-# }
-# response = requests.post(url=f'{service_url}/api', json=data)
-# print(response.text)
-
-# --- test test006 ---
-# data = {
-#     'module': 'TEST',
-#     'method': 'test006',
-# }
-# response = requests.post(url=f'{service_url}/api', json=data)
-# print(response.text)
-
-# --- test test003 ---
-# data = {
-#     'module': 'TEST',
-#     'method': 'test003',
-#     'line_id': '112233',
-# }
-# response = requests.post(url=f'{service_url}/api', json=data)
-# print(response.text)
-

+ 0 - 60
project-responder-hs/unit/PotDataMessageListener.py

@@ -1,60 +0,0 @@
-from hub import methods, Global
-
-import threading
-import time
-import json
-
-
-class PotDataMessageListener(object):
-
-    @staticmethod
-    def decorate_method(client, userdata, message):
-        """消息处理方法"""
-        try:
-            # --- update ---
-            """
-            PotData: 渣罐数据
-            PotData.pot_name: 渣罐别称(例: M.24)
-            PotData.pot_x: 坐标值
-            PotData.pot_y: 坐标值
-            PotData.mark_pot_pose: 渣罐姿态
-            """
-            message = json.loads(message.payload)
-            unique_dict = {'pot_name': message.get('pot_name')}
-            update_dict = {
-                'pot_x': message.get('pot_x'),
-                'pot_y': message.get('pot_y'),
-                'mark_pot_pose': message.get('mark_pot_pose'),
-            }
-            Global.mdb.update_one('PotData', unique_dict, update_dict)
-            methods.debug_log(f"PotDataMessageListener.30", f"#message: {message}")
-
-        except Exception as exception:
-            methods.debug_log('PotDataMessageListener.33', f"#exception: {exception}")
-            methods.debug_log('PotDataMessageListener.33', f"#traceback: {methods.trace_log()}")
-
-    @classmethod
-    def start_check_loop(cls):
-        """启动循环"""
-        """
-        topic: hs/pot/data
-        message.name: 渣罐名称
-        message.pot_x: 坐标值
-        message.pot_y: 坐标值
-        message.mark_pot_pose: 渣罐姿态
-        """
-        Global.mq02.start_subscribe_loop(
-            decorate_method=PotDataMessageListener.decorate_method,
-            subscribe_topic='hs/pot/data'
-        )
-
-    @classmethod
-    def run_background(cls, background_is=True):
-        """启动现成"""
-        p1 = threading.Thread(target=cls.start_check_loop)
-        p1.start()
-
-
-if __name__ == '__main__':
-    # --- test ---
-    MessageListener.run_background()

+ 0 - 94
project-responder-hs/unit/VehicleStateMessageListener.py

@@ -1,94 +0,0 @@
-from hub import methods, Global
-
-import threading
-import time
-import json
-
-
-class VehicleStateMessageListener(object):
-
-    @staticmethod
-    def decorate_method(client, userdata, message):
-        """消息处理方法"""
-        try:
-            # --- check ---
-            message = json.loads(message.payload)
-            if 'direction' not in message:
-                methods.debug_log(f"VehicleStateMessageListener.18", f"#message: {message}")
-                return
-
-            # --- define ---
-            check_vehicle_direction = False
-            current_vehicle_direction = 0
-            direction = message.get('direction')
-            offset = 15  # 允许偏移角度(单位:度)
-            if 0 - offset < direction < 0 + offset:
-                check_vehicle_direction = True
-                current_vehicle_direction = 3
-            elif 90 - offset < direction < 90 + offset:
-                check_vehicle_direction = True
-                current_vehicle_direction = 12
-            elif 180 - offset < direction < 180 + offset:
-                check_vehicle_direction = True
-                current_vehicle_direction = 9
-            elif 270 - offset < direction < 270 + offset:
-                check_vehicle_direction = True
-                current_vehicle_direction = 6
-
-            # --- update ---
-            """
-            VehicleInfo: 渣包车信息表
-            VehicleInfo.uuid: 标识
-            VehicleInfo.name: 车辆名称
-            VehicleInfo.address: 车辆ip
-            VehicleInfo.state: 车辆状态 1 离线(默认值) 2 在线空闲 3 人工驾驶中 4 远程驾驶中 5 自动驾驶中
-            VehicleInfo.check_vehicle_direction: 当前车头方向是否符合自动驾驶条件 True 符合 False 不符合(默认值)
-            VehicleInfo.current_vehicle_direction: 当前车头方向类型 3 围栏方向 9 渣场方向 12 维修间方向 6 维修间正对方向 0 未知(默认值)
-            VehicleInfo.check_vehicle_coordinate: 当前车辆坐标是否符合自动驾驶条件 True 符合 False 不符合(默认值)
-            VehicleInfo.current_vehicle_coordinate_x: 当前所在位置坐标 
-            VehicleInfo.current_vehicle_coordinate_y: 当前所在位置坐标 
-            VehicleInfo.current_vehicle_weight: 当前车辆负载重量 
-            """
-            unique_dict = {'address': message.get('address')}
-            update_dict = {
-                'state': message.get('state'),
-                'check_vehicle_direction': check_vehicle_direction,
-                'current_vehicle_direction': current_vehicle_direction,
-                'coordinate_x': message.get('coordinate_x'),
-                'coordinate_y': message.get('coordinate_y'),
-                'current_vehicle_weight': message.get('weight'),
-            }
-            Global.mdb.update_one('VehicleInfo', unique_dict, update_dict)
-            methods.debug_log(f"VehicleStateMessageListener.38", f"#message: {message}")
-
-        except Exception as exception:
-            methods.debug_log('VehicleStateMessageListener.40', f"#exception: {exception}")
-            methods.debug_log('VehicleStateMessageListener.40', f"#traceback: {methods.trace_log()}")
-
-    @classmethod
-    def start_check_loop(cls):
-        """启动循环"""
-        """
-        topic: hs/vehicle/state
-        message.address: 车辆ip
-        message.state: 车辆状态 1 离线 2 在线空闲 3 人工驾驶中 4 远程驾驶中 5 自动驾驶中
-        message.direction: 车头方向(场地坐标偏转角度) 
-        message.coordinate_x: 当前车辆坐标
-        message.coordinate_y: 当前车辆坐标
-        message.weight: 负载重量
-        """
-        Global.mq01.start_subscribe_loop(
-            decorate_method=VehicleStateMessageListener.decorate_method,
-            subscribe_topic='hs/vehicle/state'
-        )
-
-    @classmethod
-    def run_background(cls, background_is=True):
-        """启动现成"""
-        p1 = threading.Thread(target=cls.start_check_loop)
-        p1.start()
-
-
-if __name__ == '__main__':
-    # --- test ---
-    MessageListener.run_background()

+ 1 - 1
project-fastapi-hs/Dockerfile → sri-server-bg01/Dockerfile

@@ -51,7 +51,7 @@ RUN echo "Install Python Requirements:" \
         influxdb==5.3.1 \
         pymysql==0.9.3 \
         peewee==3.17.0 \
-        SQLAlchemy==1.4.30\
+        SQLAlchemy==1.4.30 \
         # --- for server --- \
         aiofiles==23.2.1 \
         python-multipart==0.0.6 \

+ 37 - 0
sri-server-bg01/README-usage.bash

@@ -0,0 +1,37 @@
+## NOTE
+
+# 一、构建操作
+# 构建启动
+echo "BEGIN:" \
+&& project_path="/home/server/repositories/repositories/casperz.py-project/project-fastapi-bg" \
+&& cd ${project_path} \
+&& sudo docker-compose --file compose.yml down \
+&& sudo docker-compose --file compose.yml up --detach --build \
+&& sudo docker-compose --file compose.yml logs --follow
+# 调试
+echo "BEGIN:" \
+&& project_path="/home/server/repositories/repositories/casperz.py-project/project-fastapi-bg" \
+&& cd ${project_path} \
+&& sudo docker-compose --file compose.yml down \
+&& sudo docker-compose --file compose.yml up --detach --build \
+&& sudo docker exec -it sri_module_agent_001 bash
+# 强制构建并运行
+echo "BEGIN:" \
+&& project_path="/home/server/repositories/repositories/casperz.py-project/project-fastapi-bg" \
+&& cd ${project_path} \
+&& sudo docker-compose --file compose.yml down \
+&& sudo docker-compose --file compose.yml build --no-cache \
+&& sudo docker-compose --file compose.yml up --detach \
+&& sudo docker-compose --file compose.yml logs --follow
+# 重启
+echo "BEGIN:" \
+&& project_path="/home/server/repositories/repositories/casperz.py-project/project-fastapi-bg" \
+&& cd ${project_path} \
+&& sudo docker-compose --file compose.yml down \
+&& sudo docker-compose --file compose.yml up --detach \
+&& sudo docker-compose --file compose.yml logs --follow
+
+# 二、日常调试命令
+sudo chmod -R 777 /home/ubuntu/repositories/repositories
+sudo chmod -R 777 /home/server/repositories/repositories
+sudo docker restart sri-module-bg01 && sudo docker logs -f sri-module-bg01

+ 0 - 0
project-fastapi-hs/README-usage.md → sri-server-bg01/README-usage.md


+ 0 - 0
project-fastapi-hs/README-usage.txt → sri-server-bg01/README-usage.txt


Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio