Browse Source

feat(mcu): 添加动态参数配置管理功能

- 在BaseClass中扩展sendSocketMessage方法,增加msg_type参数支持
- 实现ConfigManager类,支持动态参数的获取和设置功能
- 添加设备控制相关的动态配置接口和数据处理逻辑
- 在socket消息处理器中集成动态配置的获取和设置命令
- 更新文档说明新增的动态配置相关API接口
rambo 1 ngày trước cách đây
mục cha
commit
f39f08416f

+ 185 - 22
python/conifg_info.py

@@ -1,41 +1,160 @@
+import functools
+
+
+def return_false_on_error(func):
+    """装饰器:当函数执行出现异常时返回 False"""
+
+    @functools.wraps(func)
+    def wrapper(*args, **kwargs):
+        try:
+            return func(*args, **kwargs)
+        except Exception as e:
+            print(f"Error in {func.__name__}: {e}")
+            return False
+
+    return wrapper
+
+
 class ConfigManager:
-    def __init__(self):
+    def __init__(self, device_control):
         self.CONFIG_METADATA = {}
         self.CONFIG_METADATA_BY_ADDR = {}
+        self.device_control = device_control
 
         # 初始化配置项
         self._init_config_keys()
 
-    def _set_key_float(self, _key, _addr, _tips="", _readonly=False):
+    def _set_key_float(self, _key, _addr, _tips="", _readonly=False, _precision=1):
         self.CONFIG_METADATA[_key] = {
             "addr": _addr,
             "tips": _tips,
             "readonly": _readonly,
             "type": "float",
+            "precision": _precision,
         }
         if _addr in self.CONFIG_METADATA_BY_ADDR:
             print("{} 有重复".format(_addr))
             raise Exception("地址重复")
         self.CONFIG_METADATA_BY_ADDR[_addr] = _key
 
-    def _set_key_int(self, _key, _addr, _tips="", _readonly=False):
+    def _set_key_int(self, _key, _addr, _tips="", _readonly=False, _precision=0):
         self.CONFIG_METADATA[_key] = {
             "addr": _addr,
             "tips": _tips,
             "readonly": _readonly,
             "type": "int",
+            "precision": _precision,
         }
         if _addr in self.CONFIG_METADATA_BY_ADDR:
             print("{} 有重复".format(_addr))
             raise Exception("地址重复")
         self.CONFIG_METADATA_BY_ADDR[_addr] = _key
 
+    def get_dynamic_value(self, data):
+        cmd = [124]
+        addr = data["addr"]
+        cmd.extend([0xff & addr >> 8, 0xff & addr])
+        data = self.device_control.get_basic_info_mcu_without_async(data=cmd)
+        if not data:
+            return False
+        return_data = self.analysis_data(data[1:])
+        if return_data:
+            return str(return_data["value"])
+        return False
+
+        # 地址、正负、类型(整数、浮点)、精度(0.01)、数据(6个字节)、是否只读
+
+    def set_dynamic_value(self, data):
+        try:
+            value = float(data["value"])
+        except:
+            return False
+        addr = data['addr']
+        print("config_data", value, addr)
+        cmd = [125]
+        cmd.extend(self.read_addr_value(value, addr))
+        print("config_data cmd", cmd)
+        data = self.device_control.get_basic_info_mcu_without_async(data=cmd)
+        if not data:
+            return False
+        return_data = self.analysis_data(data[1:])
+        if return_data:
+            print("参数设置成功", return_data)
+            return True
+        return False
+
+    def read_addr_value(self, value, addr):
+        if addr not in self.CONFIG_METADATA_BY_ADDR:
+            return []
+        try:
+            buf = []
+            # 地址、正负、类型(整数、浮点)、精度(0.01)、数据(6个字节)、是否只读
+            __key_name = self.CONFIG_METADATA_BY_ADDR[addr]
+            __meta = self.CONFIG_METADATA[__key_name]
+            buf.extend([0xff & addr >> 8, 0xff & addr])  # 地址
+            _read_only = 1 if __meta["readonly"] else 0  # 是否只读
+            _dir = 1 if value >= 0 else 0  # 是否正负
+            _type = 1 if __meta["type"] == "int" else 0  # 是否整数
+            _precision = __meta["precision"]  # 精度
+            abs_int_value = int(abs(value * 10 ** __meta["precision"]))
+            buf.extend([0xff & abs_int_value >> 40, 0xff & abs_int_value >> 32, 0xff & abs_int_value >> 24,
+                        0xff & abs_int_value >> 16, 0xff & abs_int_value >> 8, 0xff & abs_int_value])
+            buf.extend([_read_only, _dir, _type, _precision])
+            print("127----buf-{}:{}".format(addr, buf))
+            return buf
+        except:
+            return []
+
+    @return_false_on_error
+    def analysis_data(self, _data):
+        _addr = _data[0] << 8 | _data[1]
+        if _addr not in self.CONFIG_METADATA_BY_ADDR:
+            return False
+
+        start = 2
+        _value = _data[start] << 40 | _data[start + 1] << 32 | _data[start + 2] << 24 | _data[start + 3] << 16 | \
+                 _data[start + 4] << 8 | _data[start + 5]
+
+        start = start + 5
+        _read_only = True if _data[start + 1] == 1 else False  # 是否只读
+        _dir = 1 if _data[start + 2] == 1 else -1
+        _type = "int" if _data[start + 3] == 1 else "float"
+        _precision = _data[start + 4]
+
+        if _dir < 0:
+            _value = _value * _dir
+
+        if _type == "float":
+            if _precision > 0:
+                _round_x = _precision
+                _precision = _precision * -1
+                _value = _value * 10 ** _precision
+                _value = round(_value, _round_x)
+        else:
+            _value = int(_value)
+
+        return_data = {"addr": _addr,
+                       "key_name": self.CONFIG_METADATA_BY_ADDR[_addr],
+                       "readonly": _read_only,
+                       "value": _value}
+        return return_data
+
+    def is_camera_has_focal(self):
+        """
+        是否有定焦器
+        """
+        data = {"addr": 208}
+        is_camera_has_focal = self.get_dynamic_value(data)
+        if is_camera_has_focal:
+            return True
+        return False
+
     def _init_config_keys(self):
         # test keys
-        self.test_key1 = 0.5
-        self._set_key_float(_key="test_key1", _addr=1)
-        self.test_key2 = 1
-        self._set_key_int(_key="test_key2", _addr=2, _tips="测试-2")
+        # self.test_key1 = 0.5
+        # self._set_key_float(_key="test_key1", _addr=1, _precision=2)
+        # self.test_key2 = 1
+        # self._set_key_int(_key="test_key2", _addr=2, _tips="测试-2")
 
         # 升降机上次命令位置
         self.camera_high_motor_target_value = 0
@@ -234,6 +353,54 @@ class ConfigManager:
             _key="turntable_move_is_exist", _addr=122, _tips="前后移动电机是否存在"
         )
 
+        # 升降电机的到位偏差
+        self.camera_high_motor_arrived_deviation = 100
+        self._set_key_int(
+            _key="camera_high_motor_arrived_deviation", _addr=123, _tips="升降电机的到位偏差"
+        )
+
+        # 相机角度电机的到位偏差
+        self.camera_steering_arrived_deviation = 100
+        self._set_key_int(
+            _key="camera_steering_arrived_deviation", _addr=124, _tips="相机角度电机的到位偏差"
+        )
+
+        # 焦段电机的到位偏差
+        self.camera_zoom_arrived_deviation = 100
+        self._set_key_int(
+            _key="camera_zoom_arrived_deviation", _addr=125, _tips="焦段电机的到位偏差"
+        )
+
+        # 前后移动电机的到位偏差
+        self.move_turntable_arrived_deviation = 100
+        self._set_key_int(
+            _key="move_turntable_arrived_deviation", _addr=126, _tips="前后移动电机的到位偏差"
+        )
+
+        # 转盘角度电机的到位偏差
+        self.turntable_steering_arrived_deviation = 100
+        self._set_key_int(
+            _key="turntable_steering_arrived_deviation", _addr=127, _tips="转盘角度电机的到位偏差"
+        )
+
+        # 转盘转速比例
+        self.turntable_speed_raito = 1.0
+        self._set_key_float(
+            _key="turntable_speed_raito", _addr=128, _tips="转盘转速比例"
+        )
+
+        # 变焦初始化力矩
+        self.c_torque_max_electric = 800
+        self._set_key_int(
+            _key="c_torque_max_electric", _addr=129, _tips="变焦初始化力矩"
+        )
+
+        # 变焦运动方向
+        self.zoom_dir = 0
+        self._set_key_int(
+            _key="zoom_dir", _addr=130, _tips="变焦运动方向"
+        )
+
         # -------------------------------------
         # 转盘偏移角度 单位1度
         self.turntable_steering_deviation = 0
@@ -287,35 +454,31 @@ class ConfigManager:
         self.camera_has_focal = 0
         self._set_key_int(_key="camera_has_focal", _addr=208, _tips="相机调焦功能支持")
 
-        # 相机最大焦段
-        self.camera_max_focal = 55
-        self._set_key_int(_key="camera_max_focal", _addr=209, _tips="相机最大焦段")
-
-        # 相机最小焦段
-        self.camera_min_focal = 15
-        self._set_key_int(_key="camera_min_focal", _addr=210, _tips="相机最小焦段")
+        # 相机焦段最大运动距离
+        self.camera_max_distance = 8000
+        self._set_key_int(_key="camera_max_distance", _addr=209, _tips="相机焦段最大运动距离")
 
         # 相机焦段步进ratio
         self.camera_focal_ratio = 0.0
         self._set_key_float(
-            _key="camera_focal_ratio", _addr=211, _tips="相机焦段步进ratio"
-        )
-
-        # 相机焦段步进自动归零
-        self.camera_zoom_auto_to_zero = 1
-        self._set_key_float(
-            _key="camera_zoom_auto_to_zero", _addr=212, _tips="相机焦段步进自动归零"
+            _key="camera_focal_ratio", _addr=210, _tips="相机焦段步进ratio"
         )
 
         # 相机焦段当前实时位置
         self.camera_zoom_motor_current_value = 0
         self._set_key_float(
             _key="camera_zoom_motor_current_value",
-            _addr=213,
+            _addr=211,
             _tips="相机焦段当前实时位置",
             _readonly=True,
         )
 
+        # 伺服电机每次运动后的偏移数值
+        self.servo_add_v = 0
+        self._set_key_int(
+            _key="servo_add_v", _addr=212, _tips="伺服电机每次运动后的偏移数值"
+        )
+
         # =====================================================
         # 获取剩余内存
         self.get_memory = 0

+ 330 - 103
python/docs/socket命令.md

@@ -1,13 +1,18 @@
 ## 智慧拍 socket 命令说明
+
 ### Socket 连接信息
+
     * 本地: ws://10.56.42.176:7074/ws
     * 打包后: ws://127.0.0.1:7074/ws
+
 #### 统一响应示例说明
+
 * code:为0时代表成功操作
 * msg:为接口执行命令时的提示信息
-* status:-1连接失败  0未连接 1连接中  2链接成功  3端口占用
+* status:-1连接失败 0未连接 1连接中 2链接成功 3端口占用
 * msg_type:mcu为设备控制,blue_tooth为蓝牙控制,blue_tooth_scan 为蓝牙扫码时发送的消息数据
 * data:为返回的数据信息,无实际交互需求时,前端可忽略
+
 ```python
 {
     "code": 0,
@@ -23,39 +28,53 @@
     "msg_type": "mcu"
 }
 ```
+
 ### 设备连接
-*  type 
+
+* type
     * 值为connect_mcu时,为连接mcu设备操作
     * 值为connect_bluetooth时,为连接蓝牙遥控器
 * data:可以忽略为null
+
 #### 请求示例
+
 ```python
-{"data":null,"type":"connect_mcu"}
+{"data": null, "type": "connect_mcu"}
 ```
+
 _<mark>以下操作前必须保证设备已连接!!!<mark>_
+
 ### 初始化mcu设备
+
 _<mark>目前连接设备后,后端会自动进行设备初始化操作,如无特殊需求可忽略<mark>_
-*  type 固定为 init_mcu
+
+* type 固定为 init_mcu
 * data:可以忽略为null
+
 #### 请求示例
+
 ```python
-{"data":null,"type":"init_mcu"}
+{"data": null, "type": "init_mcu"}
 ```
+
 ### 单独控制设备得某一个功能运行命令
+
 _(该命令用于单独自定义配置中某一项的单独调整测试,不进行任何存储操作)_
 
-* type 为control_mcu时,为设备得单独控制 
+* type 为control_mcu时,为设备得单独控制
 * data中的 device_name释义:
-  *  camera_high_motor:相机高度;步长1;最小0;最大400
-  *  camera_steering:相机倾角;步长0.1,最小-40;最大40
-  *  camera_steering:相机倾角
-  * turntable_steering:转盘角度;步长1;最小-720;最大720
-  * turntable_position_motor:转盘位置;步长1,最小0;最大800
-  * overturn_steering:翻转,当device_name为当前类型时,value可以忽略或传递任意值,后端不做任何处理
-  * take_picture:拍照测试;当device_name为当前类型时,value为0或者大于0的数值;提交对焦次数参数
-  * laser_position:激光开关;当device_name为当前类型时,value为0或者1;0为关   1为开
+    * camera_high_motor:相机高度;步长1;最小0;最大400
+    * camera_steering:相机倾角;步长0.1,最小-40;最大40
+    * camera_steering:相机倾角
+    * turntable_steering:转盘角度;步长1;最小-720;最大720
+    * turntable_position_motor:转盘位置;步长1,最小0;最大800
+    * overturn_steering:翻转,当device_name为当前类型时,value可以忽略或传递任意值,后端不做任何处理
+    * take_picture:拍照测试;当device_name为当前类型时,value为0或者大于0的数值;提交对焦次数参数
+    * laser_position:激光开关;当device_name为当前类型时,value为0或者1;0为关 1为开
 * value为设备得控制值,参考上述的最大最小值进行处理
+
 #### 请求示例
+
 ```python
 {
     "data": {
@@ -66,15 +85,17 @@ _(该命令用于单独自定义配置中某一项的单独调整测试,不进
 }
 ```
 
-
 ### 执行拍摄任务
+
 * type 为run_mcu时,为设备拍照动作连贯执行
 * data中的 action参数释义:
     * 执行左脚程序 : 为用户配置【执行左脚程序】,其状态必须至少有一条为true,否则不会运行并且报错无可用参数
     * 执行右脚程序 : 为用户配置【执行右脚程序】,其状态必须至少有一条为true,否则不会运行并且报错无可用参数
 * data中的 goods_art_no参数释义:
     * 商品货号,必须存在且为字符串形式传递
+
 #### 请求示例
+
 ```python
 {
     "data": {
@@ -84,7 +105,9 @@ _(该命令用于单独自定义配置中某一项的单独调整测试,不进
     "type": "run_mcu"
 }
 ```
+
 ### 执行拍摄任务命令发送完成后-服务端响应消息
+
 * msg_type 为image_process时,代表上述命令已发送给设备执行任务
 * data参数释义:
     * image_counts : 执行拍照任务的数量,可理解为照片张数
@@ -92,10 +115,12 @@ _(该命令用于单独自定义配置中某一项的单独调整测试,不进
     * action_names : 执行的动作名称
     * current_time : 当前时间
 * msg 消息提示
+
 #### 响应示例
+
 ```python
 {
-    "msg":"MCU 命令已发送完成",
+    "msg": "MCU 命令已发送完成",
     "data": {
         "image_counts": 4,
         "goods_art_no": "1234556",
@@ -108,10 +133,12 @@ _(该命令用于单独自定义配置中某一项的单独调整测试,不进
         ],
         "current_time": "年月日时分秒"
     },
-    "msg_type":"image_process"
+    "msg_type": "image_process"
 }
 ```
+
 ### 单张照片拍照完成后-服务端响应消息
+
 * msg_type:
     * 为photo_take时,代表拍照已完成
     * 为photo_take_finish时,代表所有拍照任务已完成
@@ -120,65 +147,80 @@ _(该命令用于单独自定义配置中某一项的单独调整测试,不进
     * goods_art_no : 货号
     * current_time : 当前时间
 * msg 消息提示
+
 #### 响应示例-单个任务拍照成功(前端需要刷新列表)
+
 ```python
 {
     "code": 0,
     "msg": "拍鞋底 执行完成~",
     "status": 2,
     "data": null,
-    "msg_type":"photo_take"
+    "msg_type": "photo_take"
 }
 ```
+
 #### 响应示例-单个任务拍照失败
+
 ```python
 {
     "code": 1,
     "msg": "拍鞋底 执行失败~",
     "status": 2,
     "data": null,
-    "msg_type":"photo_take"
+    "msg_type": "photo_take"
 }
 ```
+
 ### 响应示例-整体任务拍照完成
+
 ```python
 {
     "code": 1,
     "msg": "执行左脚程序 执行成功~",
     "status": 2,
     "data": null,
-    "msg_type":"photo_take_finish"
+    "msg_type": "photo_take_finish"
 }
 ```
+
 ### 接收遥控器扫码货号动作处理
+
 #### 消息示例
+
 * data中的子data参数释义:
     * action:【执行左脚程序】或【执行右脚程序】
     * goods_art_no :扫描到的货号,当货号为空时代表用户未扫码,直接按遥控器的左右操作,需要前端判断用户是否在前端页面填写了货号,或者提醒用户填写货号
 * msg_type:当该字段为blue_tooth_scan时,前端可直接解析得到data数据包,将数据直接发送给socket服务端即可【执行拍摄任务】
+
 ```python
 {
     "code": 0,
     "msg": "准备执行[左脚程序]",
     "status": 2,
     "data": {
-            "data": {
-                    "action": "执行左脚程序",
-                    "goods_art_no": "货号信息",
-                    },
-                    "type": "run_mcu",
+        "data": {
+            "action": "执行左脚程序",
+            "goods_art_no": "货号信息",
+        },
+        "type": "run_mcu",
     },
     "msg_type": "blue_tooth_scan"
 }
 ```
+
 ### 接收遥控器点击拍照事件处理
+
 <mark>遥控器得拍照命令需要由后端转发到前端,再由前端将消息转发给后端对应得拍照命令<mark>
 当蓝牙遥控器点击拍照后,后端消息响应如下:
+
 * data中参数释义:
     * type:handler_take_picture 为后端单拍任务得类型
     * data :忽略
 * msg_type:当该字段为handler_take_picture时,前端可直接解析得到data数据包,将数据直接发送给socket服务端即可【执行单任务】
+
 #### 消息示例
+
 ```python
 {
     "code": 0,
@@ -191,23 +233,31 @@ _(该命令用于单独自定义配置中某一项的单独调整测试,不进
     "msg_type": "handler_take_picture"
 }
 ```
+
 <mark>注:在多次按下拍照按钮时,前端需要在命令发送给后端时且拍照未完成之前处理拦截操作,否则会出现拍照任务在不断执行<mark>
 
 ### 单拍任务命令
+
 #### 发送-消息示例
+
 ```python
 {
-        "type": "handler_take_picture",
-        "data": null
+    "type": "handler_take_picture",
+    "data": null
 }
 ```
+
 #### 响应-消息示例
-<mark>注意:当前响应可能会出现失败得情况,如:用户清空了所有货号数据;用户未打开拍照软件等其他错误消息响应;前端需要判断code是否为0;去释放拦截<mark>
+
+<mark>
+注意:当前响应可能会出现失败得情况,如:用户清空了所有货号数据;用户未打开拍照软件等其他错误消息响应;前端需要判断code是否为0;去释放拦截<mark>
+
 * data中参数释义:
     * msg: 消息文本内容
     * data :
         * goods_art_no:货号,便于前端查询详情数据
 * msg_type:当该字段为photo_take时,代表照片已拍摄完成
+
 ```python
 {
     "code": 0,
@@ -219,6 +269,7 @@ _(该命令用于单独自定义配置中某一项的单独调整测试,不进
 ```
 
 #### 修改配置-独立操作MCU
+
 * data中参数释义:
     * msg: 消息文本内容
     * data :
@@ -237,7 +288,9 @@ _(该命令用于单独自定义配置中某一项的单独调整测试,不进
         * action_index:固定1
         * pre_delay:1;拍照后延迟;这里因为后端不控制拍照,所以无效
 * type:当该字段为run_mcu_single时,代表独立执行MCU设备
+
 ##### 请求示例
+
 ```python
 {
     "data": {
@@ -259,8 +312,11 @@ _(该命令用于单独自定义配置中某一项的单独调整测试,不进
     "type": "run_mcu_single"
 }
 ```
+
 ##### 响应示例
+
 ###### 当 msg_type 为run_mcu_single时,代表独立执行MCU设备完成,前端将此命令作为完成依据
+
 ```python
 {
     "code": 0,
@@ -270,11 +326,16 @@ _(该命令用于单独自定义配置中某一项的单独调整测试,不进
     "msg_type": "run_mcu_single_finish"
 }
 ```
+
 #### 设备调平-获取
+
 <mark>以下操作需要连接设备且初始化<mark>
+
 * data:空对象或忽略,任何值无意义
 * type:当该字段为get_deviation时,代表获取调平设备信息
+
 ##### 请求示例
+
 ```python
 {
     "data": {
@@ -282,7 +343,9 @@ _(该命令用于单独自定义配置中某一项的单独调整测试,不进
     "type": "get_deviation"
 }
 ```
+
 ##### 响应示例
+
 * data:
     * camera_high_motor_deviation:相机高度偏移 mm
     * camera_steering_deviation: 相机角度偏移 度
@@ -293,6 +356,7 @@ _(该命令用于单独自定义配置中某一项的单独调整测试,不进
     * overturn_steering_down_speed: 翻转舵机-下降速度
     * turntable_front_end_deviation: 转盘前后电机偏移度
 * type:当该字段为get_deviation_data时,代表成功获取到调平设备信息
+
 ```python
 {
     "code": 0,
@@ -306,49 +370,56 @@ _(该命令用于单独自定义配置中某一项的单独调整测试,不进
         "overturn_steering_high": 150.0,
         "overturn_steering_up_speed": 2,
         "overturn_steering_down_speed": 4,
-        "turntable_front_end_deviation":300
+        "turntable_front_end_deviation": 300
     },
     "msg_type": "get_deviation_data"
 }
 ```
 
-
 #### 设备调平-设置
+
 <mark>以下操作需要连接设备且初始化<mark>
+
 * data:
     * value: 偏移量值,最好传递浮点型
     * action_name:
-        * "相机电机",  # min 0 max 400,步长1
-        * "相机舵机",  # min -40 max 40,步长0.1
-        * "转盘舵机",  # min -720 max 720,步长1
-        * "转盘前后电机",  # min 0 max 950,步长1
-        * "翻板舵机中位",  # min 0 max 180,步长0.5
-        * "翻板舵机高位",  # min 0 max 180,步长0.5
-        * "翻板舵机上升速度",  # min 1 max 10,步长1
-        * "翻板舵机下降速度",  # min 1 max 10,步长1
-    * type: 
+        * "相机电机", # min 0 max 400,步长1
+        * "相机舵机", # min -40 max 40,步长0.1
+        * "转盘舵机", # min -720 max 720,步长1
+        * "转盘前后电机", # min 0 max 950,步长1
+        * "翻板舵机中位", # min 0 max 180,步长0.5
+        * "翻板舵机高位", # min 0 max 180,步长0.5
+        * "翻板舵机上升速度", # min 1 max 10,步长1
+        * "翻板舵机下降速度", # min 1 max 10,步长1
+    * type:
         * "move" 为移动
         * "set" 为设置
 * type:
     * 当该字段为set_deviation时,代表设置调平设备信息
     * 当该字段为move_deviation时,代表移动调平设备偏移
+
 ##### 请求示例
+
 ```python
 {
     "data": {
         "value": 10,
-        "action_name":"相机电机",
-        "type":"move"
+        "action_name": "相机电机",
+        "type": "move"
     },
     "type": "set_deviation"
 }
 ```
+
 ##### 响应示例
+
 * data:忽略
 * type:
     * 当该字段为set_deviation时,代表响应调平设备设置
     * 当该字段为move_deviation时,代表响应调平设备移动
+
 ###### 成功状态
+
 ```python
 {
     "code": 0,
@@ -358,7 +429,9 @@ _(该命令用于单独自定义配置中某一项的单独调整测试,不进
     "msg_type": "set_deviation"
 }
 ```
+
 ###### 失败状态
+
 ```python
 {
     "code": 1,
@@ -369,26 +442,32 @@ _(该命令用于单独自定义配置中某一项的单独调整测试,不进
 }
 ```
 
-
-
 #### 获取MCU其他设置信息
+
 <mark>以下操作需要连接设备且初始化<mark>
-* data:为null或其他值  后端忽略
+
+* data:为null或其他值 后端忽略
 * type:
     * 当该字段为get_mcu_other_info时,代表获取MCU其他设置信息
+
 ##### 请求示例
+
 ```python
 {
-    "data":null,
+    "data": null,
     "type": "get_mcu_other_info"
 }
 ```
+
 ##### 响应示例
+
 * data:忽略
 * type:
     * 当该字段为get_other_mcu_info,代表成功获取MCU其他设置信息
-<mark>以下数据包作为写入设备时对应得字段名称<mark>
+      <mark>以下数据包作为写入设备时对应得字段名称<mark>
+
 ###### 成功状态
+
 ```python
 {
     "code": 0,
@@ -416,17 +495,19 @@ _(该命令用于单独自定义配置中某一项的单独调整测试,不进
 }
 ```
 
-
-
 #### 设置MCU其他设置信息
+
 <mark>以下操作需要连接设备且初始化<mark>
+
 * data:设置得数据包
 * type:
     * 当该字段为set_mcu_other_info时,代表设置MCU其他设置信息
+
 ##### 请求示例
+
 ```python
 {
-    "data":{
+    "data": {
         "is_auto_send_base_info": 0,
         "is_move_retry": 0,
         "is_data_response": 0,
@@ -447,12 +528,16 @@ _(该命令用于单独自定义配置中某一项的单独调整测试,不进
     "type": "set_mcu_other_info"
 }
 ```
+
 ##### 响应示例
+
 * data:忽略
 * type:
     * 当该字段为get_other_mcu_info,代表成功获取MCU其他设置信息
-<mark>以下数据包作为写入设备时对应得字段名称<mark>
+      <mark>以下数据包作为写入设备时对应得字段名称<mark>
+
 ###### 成功状态
+
 ```python
 {
     "code": 0,
@@ -463,14 +548,17 @@ _(该命令用于单独自定义配置中某一项的单独调整测试,不进
 }
 ```
 
-
 #### 通过命令行发送设备指令
+
 <mark>以下操作需要连接设备且初始化<mark>
+
 * data:
     * command:命令行指令,字符串“0x01 0x42 0x6C 0x6b”为前端默认展示得字符串值,写死即可
 * type:
     * 当该字段为send_command时,代表设置通过命令行发送指令
+
 ##### 请求示例
+
 ```python
 {
     "data": {
@@ -479,7 +567,9 @@ _(该命令用于单独自定义配置中某一项的单独调整测试,不进
     "type": "send_command"
 }
 ```
+
 ##### 响应示例
+
 * data:
     * command:收到的指令
     * type:
@@ -487,8 +577,10 @@ _(该命令用于单独自定义配置中某一项的单独调整测试,不进
         * 为output时代表收到指令回复,前端需要填充到回复得文本展示框中;
 * type:
     * 当该字段为send_command,代表成功获取到指令回复
-<mark>以下数据包作为写入设备时对应得字段名称<mark>
+      <mark>以下数据包作为写入设备时对应得字段名称<mark>
+
 ###### 发送后指令转换
+
 ```python
 {
     "code": 0,
@@ -501,7 +593,9 @@ _(该命令用于单独自定义配置中某一项的单独调整测试,不进
     "msg_type": "send_command"
 }
 ```
+
 ###### 接收到指令回复
+
 ```python
 {
     "code": 0,
@@ -514,33 +608,45 @@ _(该命令用于单独自定义配置中某一项的单独调整测试,不进
     "msg_type": "send_command"
 }
 ```
+
 #### 执行重拍操作
+
 <mark>以下操作需要连接设备且初始化<mark>
+
 * data:
     * record_id:原记录id
 * type:
     * 当该字段为re_take_picture时,代表进行重拍操作
-<mark>注:后续得拍照动作参考消息回复为的type均为:re_take_picture,照片拍摄完成的消息依旧为photo_take<mark>
+      <mark>注:后续得拍照动作参考消息回复为的type均为:re_take_picture,照片拍摄完成的消息依旧为photo_take<mark>
+
 ##### 请求示例
+
 ```python
 {
-    "data":{"record_id":1},
+    "data": {"record_id": 1},
     "type": "re_take_picture"
 }
 ```
+
 #### 停止拍摄
+
 <mark>以下操作需要连接设备且初始化<mark>
+
 * data:null
 * type:
     * 当该字段为stop_action时,代表停止拍摄
+
 ##### 请求示例
+
 ```python
 {
-    "data":null,
+    "data": null,
     "type": "stop_action"
 }
 ```
+
 <mark>当通过物理遥控器按键停止拍摄时,会收到以下消息,前端需要把上方的【停止拍摄】消息转发给后端即可<mark>
+
 ```
 {
     "code": 0,
@@ -554,23 +660,29 @@ _(该命令用于单独自定义配置中某一项的单独调整测试,不进
 }
 ```
 
-
-
 #### 使用smart shooter进行相机控制
+
 <mark>以下操作需要连接连接相机并拉起smartshooter5软件<mark>
+
 ##### 获取相机是否连接
+
 * data:{}
 * type:
     * 当该字段为smart_shooter_getinfo时,代表获取相机连接信息,是否连接成功
+
 ##### 请求示例
+
 ```python
 {
-    "data":{},
+    "data": {},
     "type": "smart_shooter_getinfo"
 }
 ```
+
 ##### 响应示例-连接成功
+
 ###### 发送后指令转换
+
 ```python
 {
     "code": 0,
@@ -580,8 +692,11 @@ _(该命令用于单独自定义配置中某一项的单独调整测试,不进
     "msg_type": "smart_shooter_getinfo"
 }
 ```
+
 ##### 响应示例-连接失败
+
 ###### 发送后指令转换
+
 ```python
 {
     "code": 0,
@@ -593,18 +708,23 @@ _(该命令用于单独自定义配置中某一项的单独调整测试,不进
 ```
 
 ##### 启动/关闭预览
+
 * data:
     * value:为true时代表打开预览,为false时代表关闭预览
 * type:
     * 当该字段为smart_shooter_enable_preview时,代表操作预览启动关闭操作
+
 ##### 请求示例
+
 ```python
 {
-    "data":{"value":false},
+    "data": {"value": false},
     "type": "smart_shooter_enable_preview"
 }
 ```
+
 ##### 响应示例-启动预览
+
 ```python
 {
     "code": 0,
@@ -614,7 +734,9 @@ _(该命令用于单独自定义配置中某一项的单独调整测试,不进
     "msg_type": ""
 }
 ```
+
 ##### 响应示例-关闭预览
+
 ```python
 {
     "code": 0,
@@ -625,19 +747,23 @@ _(该命令用于单独自定义配置中某一项的单独调整测试,不进
 }
 ```
 
-
 ##### 拍照
+
 * data:{}
 * type:
     * 当该字段为smart_shooter_photo_take时,代表操作拍照动作
+
 ##### 请求示例
+
 ```python
 {
-    "data":{},
+    "data": {},
     "type": "smart_shooter_photo_take"
 }
 ```
+
 ##### 响应示例-拍照成功
+
 ```python
 {
     "code": 0,
@@ -647,7 +773,9 @@ _(该命令用于单独自定义配置中某一项的单独调整测试,不进
     "msg_type": ""
 }
 ```
+
 ##### 响应示例-照片获取成功
+
 ```python
 {
     "code": 1,
@@ -659,24 +787,30 @@ _(该命令用于单独自定义配置中某一项的单独调整测试,不进
 }
 ```
 
-
-
-
 ##### 获取相机属性-ISO等相关信息
+
 * data:{}
 * type:
     * 当该字段为smart_shooter_get_camera_property时,代表获取相机属性-ISO等相关信息
+
 ##### 请求示例
+
 ```python
 {
-    "data":{},
+    "data": {},
     "type": "smart_shooter_get_camera_property"
 }
 ```
+
 ##### 响应示例-获取成功
+
 <mark>如果相机未连接可能data参数为空,需要注意判断</mark>
+
 * data释意:
-    * 该值是通过smartshooter直接获取的,是当前相机的所有属性值,前端在使用对应值得时候,需要遍历数组,判断对应:CameraPropertyType,如CameraPropertyType=="ISO" 后获取当前对象,其中“CameraPropertyValue”为相机当前属性得当前值,“CameraPropertyRange”为当前属性值得范围
+    *
+  该值是通过smartshooter直接获取的,是当前相机的所有属性值,前端在使用对应值得时候,需要遍历数组,判断对应:CameraPropertyType,如CameraPropertyType=="
+  ISO" 后获取当前对象,其中“CameraPropertyValue”为相机当前属性得当前值,“CameraPropertyRange”为当前属性值得范围
+
 ```python
 {
     "code": 0,
@@ -909,13 +1043,14 @@ _(该命令用于单独自定义配置中某一项的单独调整测试,不进
 ```
 
 ##### 获取详情图处理接口中的<mark>[详情页模板]</mark>执行进度信息
+
 * data:{}
     * goods_no:款号
     * temp_name:模板名称
     * status:状态
     * goods_art_nos:货号-数组
 * msg_type:详情图处理固定为[detail_progress]
-<mark>以下为消息发送得示例</mark>
+  <mark>以下为消息发送得示例</mark>
 
 ```
 {
@@ -933,6 +1068,7 @@ _(该命令用于单独自定义配置中某一项的单独调整测试,不进
     "msg_type": "detail_progress"
 }
 ```
+
 ```
 {
     "code": 0,
@@ -946,6 +1082,7 @@ _(该命令用于单独自定义配置中某一项的单独调整测试,不进
     "msg_type": "detail_progress"
 }
 ```
+
 ```
 {
     "code": 0,
@@ -959,6 +1096,7 @@ _(该命令用于单独自定义配置中某一项的单独调整测试,不进
     "msg_type": "detail_progress"
 }
 ```
+
 ```
 {
     "code": 0,
@@ -973,13 +1111,13 @@ _(该命令用于单独自定义配置中某一项的单独调整测试,不进
 }
 ```
 
-
 ##### 获取详情图处理接口中的<mark>[抠图]</mark>执行进度信息
+
 * data:{}
     * status:状态
     * goods_art_nos:货号-数组
 * msg_type:详情图处理固定为[segment_progress]
-<mark>以下为消息发送得示例</mark>
+  <mark>以下为消息发送得示例</mark>
 
 ```
 {
@@ -996,6 +1134,7 @@ _(该命令用于单独自定义配置中某一项的单独调整测试,不进
     "msg_type": "segment_progress"
 }
 ```
+
 ```
 {
     "code": 0,
@@ -1011,12 +1150,14 @@ _(该命令用于单独自定义配置中某一项的单独调整测试,不进
     "msg_type": "detail_progress"
 }
 ```
+
 ##### 获取详情图处理接口中的<mark>[上传商品到第三方]</mark>执行进度信息
+
 * data:{}
     * status:状态
     * online_stores:上传商品到第三方得渠道名称,数组形式
 * msg_type:详情图处理固定为[upload_goods_progress]
-<mark>以下为消息发送得示例</mark>
+  <mark>以下为消息发送得示例</mark>
 
 ```
 {
@@ -1032,6 +1173,7 @@ _(该命令用于单独自定义配置中某一项的单独调整测试,不进
     "msg_type": "upload_goods_progress"
 }
 ```
+
 ```
 {
     "code": 0,
@@ -1046,83 +1188,99 @@ _(该命令用于单独自定义配置中某一项的单独调整测试,不进
     "msg_type": "upload_goods_progress"
 }
 ```
+
 ##### 发送独立抠图命令任务
+
 * data:{}
     * token:用户token信息
     * goods_art_no:货号-数组
     * uuid:前端传递uuid
 * msg_type:固定为[segment_progress]
+
 ###### 请求示例
+
 ```json
 {
-    "type": "segment_progress",
-    "data": {
-        "token": "",
-        "uuid": "",
-        "goods_art_no": []
-    }
+  "type": "segment_progress",
+  "data": {
+    "token": "",
+    "uuid": "",
+    "goods_art_no": []
+  }
 }
 ```
+
 ###### 响应示例-成功
+
 ```json
 {
-    "code": 0,
-    "msg": "开始处理抠图",
-    "status": 2,
-    "data": {
-        "status": "进行中",
-        "goods_art_nos": [
-            "AQN1411322",
-            "B411351"
-        ]
-    },
-    "msg_type": "segment_progress"
+  "code": 0,
+  "msg": "开始处理抠图",
+  "status": 2,
+  "data": {
+    "status": "进行中",
+    "goods_art_nos": [
+      "AQN1411322",
+      "B411351"
+    ]
+  },
+  "msg_type": "segment_progress"
 }
 ```
+
 ```json
 {
-    "code": 0,
-    "msg": "抠图结束",
-    "status": 2,
-    "data": {
-        "status": "已完成",
-        "goods_art_nos": [
-            "AQN1411322",
-            "B411351"
-        ]
-    },
-    "msg_type": "segment_progress"
+  "code": 0,
+  "msg": "抠图结束",
+  "status": 2,
+  "data": {
+    "status": "已完成",
+    "goods_art_nos": [
+      "AQN1411322",
+      "B411351"
+    ]
+  },
+  "msg_type": "segment_progress"
 }
 ```
+
 ###### 响应示例-失败-异常
+
 * code:1
     * 异常情况下code会固定为1
 * msg:异常输出得错误内容;前端需要判断code是否等于1,如果等于1则代表异常,输出msg得内容即可,因为是异步执行,也可以忽略异常,不做处理
 * msg_type:固定为[segment_progress]
+
 ```json
 {
-    "code": 1,
-    "msg": "异常输出得错误内容",
-    "status": 2,
-    "data": null,
-    "msg_type": "segment_progress"
+  "code": 1,
+  "msg": "异常输出得错误内容",
+  "status": 2,
+  "data": null,
+  "msg_type": "segment_progress"
 }
 ```
+
 ##### 发送获取设备状态命令
+
 * data:null
 * msg_type:固定为[get_mcu_info]
+
 ```
 {
     "type": "get_mcu_info",
     "data": null
 }
 ```
+
 ###### 响应示例-成功
+
 * state_camera_motor:相机高度状态
 * state_camera_steering:相机角度状态
 * state_turntable_steering:转盘状态
 * state_move_turntable_steering:转盘前后移动状态
 * state_overturn_steering:翻板状态
+
 ```
 {
     "code": 0,
@@ -1143,4 +1301,73 @@ _(该命令用于单独自定义配置中某一项的单独调整测试,不进
     "msg_type": "get_mcu_info"
 }
 ```
+
+###### 增加参数设置页面(给设备设置其他动态参数)-批量获取动态参数
+
+* data:{}
+* msg_type:固定为[get_dynamic_config]
+  <mark>以下为消息发送得示例</mark>
+
+```
+{
+    "data": {
+    },
+    "msg_type": "get_dynamic_config"
+}
+```
+
+* 响应示例-成功
+  注意,前端需要遍历data中的数据进行渲染设置栏,并且需要注意readonly属性,如果为true则代表该参数不可修改
+
+```
+{
+    "code": 0,
+    "msg": "成功",
+    "data": {
+        "camera_high_motor_target_value": {
+            "addr": 3,
+            "tips": "升降机当前位置",
+            "readonly": true,
+            "type": "float",
+            "precision": 1,
+            "value": "0.0"
+        }
+        }}
+```
+
+###### 增加参数设置页面(给设备设置其他动态参数)-设置对应项动态参数
+
+* data:{}
+    * "addr": 113,
+    * "readonly": false,
+    * "value": "38.6"
+* msg_type:固定为[set_dynamic_config]
+  <mark>以下为消息发送得示例</mark>
+
+```
+{
+    "data": {
+    "addr": 113,
+            "tips": "转盘转速比",
+            "readonly": false,
+            "type": "float",
+            "precision": 1,
+            "value": "38.6"
+    },
+    "msg_type": "set_dynamic_config"
+}
+```
+
+* 响应示例-成功
+
+```
+{
+    "code": 0,
+    "msg": "成功",
+    "data": {
+        "status": true
+        }
+ }
+```
+
 ##### 未完待续.....

+ 20 - 15
python/mcu/BaseClass.py

@@ -1,4 +1,4 @@
-import asyncio,time
+import asyncio, time
 from sockets import ConnectionManager
 from utils.common import message_queue
 from mcu.capture.smart_shooter_class import SmartShooter
@@ -7,7 +7,7 @@ from mcu.capture.smart_shooter_class import SmartShooter
 class BaseClass:
 
     def __init__(
-        self, websocket_manager: ConnectionManager, smart_shooter: SmartShooter = None
+            self, websocket_manager: ConnectionManager, smart_shooter: SmartShooter = None
     ):
         self.websocket_manager = websocket_manager
         self.smart_shooter = smart_shooter
@@ -16,34 +16,39 @@ class BaseClass:
         # -1连接失败  0未连接 1连接中  2连接成功  3端口占用
         # self.device_status = 2
 
-    def sendSocketMessage(self, code=0, msg="", data=None, device_status=2):
+    def sendSocketMessage(self, code=0, msg="", data=None, device_status=2, msg_type=None):
         t_start = time.time()
+        if msg_type:
+            message_type = msg_type
+        else:
+            message_type = self.msg_type
         payload = {
             "code": code,
             "msg": msg,
             "status": device_status,
             "data": data,
-            "msg_type": self.msg_type,
+            "msg_type": message_type,
         }
-        
+
         print(f"[T1: {t_start:.4f}] sendSocketMessage 调用, msg={msg}")
 
         loop = asyncio.get_event_loop()
         if self.websocket == None:
-            print(f"[T1: {time.time()-t_start:.4f}s] 走队列路径")
+            print(f"[T1: {time.time() - t_start:.4f}s] 走队列路径")
             loop.create_task(message_queue.put(payload))
         else:
-            print(f"[T1: {time.time()-t_start:.4f}s] 走直接发送路径")
-            
+            print(f"[T1: {time.time() - t_start:.4f}s] 走直接发送路径")
+
             async def _do_send():
                 t2 = time.time()
-                print(f"[T2: {t2-t_start:.4f}s] 任务开始执行, 准备调用 send_personal_message")
+                print(f"[T2: {t2 - t_start:.4f}s] 任务开始执行, 准备调用 send_personal_message")
                 await self.websocket_manager.send_personal_message(payload, self.websocket)
                 t3 = time.time()
-                print(f"[T3: {t3-t_start:.4f}s] send_personal_message 完成, 总耗时: {t3-t2:.4f}s")
-                
+                print(f"[T3: {t3 - t_start:.4f}s] send_personal_message 完成, 总耗时: {t3 - t2:.4f}s")
+
             loop.create_task(_do_send())
         print("\033[1;32;40m 发送消息===>sendSocketMessage \033[0m", data)
+
     async def asyncSendSocketMessage(self, code=0, msg="", data=None, device_status=2):
         data = {
             "code": code,
@@ -88,9 +93,9 @@ class BaseClass:
                     #     return None
                     # time.sleep(0.01)
                     continue
-                _data = self.receive_data[3 : data_len + 4]
+                _data = self.receive_data[3: data_len + 4]
                 # 更新缓存区
-                self.receive_data = self.receive_data[data_len + 4 :]
+                self.receive_data = self.receive_data[data_len + 4:]
                 # 校验数据
                 if 0xFF & ~sum(_data[:-1]) == _data[-1]:
                     # print("receive_data:", self.change_hex_to_int(self.receive_data[:-1]))
@@ -108,8 +113,8 @@ class BaseClass:
                             self.receive_data = b""
                     else:
                         if (
-                            self.receive_data[0] == 0x55
-                            and self.receive_data[1] == 0x55
+                                self.receive_data[0] == 0x55
+                                and self.receive_data[1] == 0x55
                         ):
                             break
                         else:

+ 45 - 11
python/mcu/DeviceControl.py

@@ -155,6 +155,38 @@ class DeviceControl(BaseClass, metaclass=SingletonType):
             150: self.dynamic_parameter_issuance,  # 动态参数下发
         }
 
+    def set_dynamic_config(self, config):
+        """
+        设置动态参数配置
+        """
+        print("set_dynamic_config", config)
+        if not self.init_state:
+            self.sendSocketMessage(code=1, msg="mcu设备未初始化", device_status=4)
+            return False
+        return self.config_manager.set_dynamic_value(config)
+
+    def get_dynamic_config(self):
+        """
+        获取动态参数配置
+        """
+        if not self.init_state:
+            self.sendSocketMessage(code=1, msg="mcu设备未初始化", device_status=4)
+            return False
+        # 先收集需要删除的键
+        keys_to_delete = []
+        for item in list(self.config_manager.CONFIG_METADATA.keys()):
+            item_value = self.config_manager.get_dynamic_value(self.config_manager.CONFIG_METADATA[item])
+            if not item_value:
+                keys_to_delete.append(item)
+                continue
+            self.config_manager.CONFIG_METADATA[item]['value'] = item_value
+
+        # 遍历结束后再删除
+        for key in keys_to_delete:
+            del self.config_manager.CONFIG_METADATA[key]
+
+        return self.config_manager.CONFIG_METADATA
+
     def get_device_info(self):
         if not self.init_state:
             self.sendSocketMessage(code=1, msg="mcu设备未初始化", device_status=4)
@@ -167,8 +199,9 @@ class DeviceControl(BaseClass, metaclass=SingletonType):
         if not data:
             return False
         return_data = self.analysis_data(data[1:])
-        print("return_data", return_data)
-        print("camera_high_motor_deviation_offset", self.camera_high_motor_deviation_offset)
+        is_camera_has_focal = self.config_manager.is_camera_has_focal()
+        # print("return_data", return_data)
+        # print("camera_high_motor_deviation_offset", self.camera_high_motor_deviation_offset)
         if return_data:
             camera_height = return_data.get('value', 35)
             self.camera_height = camera_height - self.camera_high_motor_deviation_offset
@@ -177,9 +210,9 @@ class DeviceControl(BaseClass, metaclass=SingletonType):
         self.msg_type = 'get_device_info'
         self.sendSocketMessage(
             code=0,
-            msg="设置mcu其他配置信息完成",
+            msg="获取其他设备信息",
             device_status=2,
-            data={"camera_height": self.camera_height}
+            data={"camera_height": self.camera_height, "is_camera_has_focal": is_camera_has_focal}
         )
         self.msg_type = 'mcu'
         return self.camera_height
@@ -330,7 +363,7 @@ class DeviceControl(BaseClass, metaclass=SingletonType):
             logger.info("已经初始化过,请勿重复初始化")
             self.sendSocketMessage(msg="设备初始化完成", device_status=2)
             return False
-        self.config_manager = ConfigManager()
+        self.config_manager = ConfigManager(self)
         self.serial_ins.clearn_flush()
         self.to_init_device_origin_point(device_name="mcu", is_force=is_force)
         print("MCU 开始循环~")
@@ -556,8 +589,13 @@ class DeviceControl(BaseClass, metaclass=SingletonType):
                 logger.info(f"设备初始化完成:%{data}")
                 self.sendSocketMessage(msg=data, device_status=2)
             else:
-                print("设备异常数据打印:", data)
+                # print("设备异常数据打印:", data)
                 logger.info(f"115  设备异常数据打印:%{data}")
+                msg_data = {
+                    "message": data
+                }
+                self.sendSocketMessage(msg="设备信息打印", data=msg_data, device_status=2,
+                                       msg_type="print_mcu_error_data")
         except BaseException as e:
             print("117 error {}".format(e))
             logger.info(f"117 error %{e}")
@@ -690,11 +728,7 @@ class DeviceControl(BaseClass, metaclass=SingletonType):
     def get_basic_info_mcu(self):
         receive_data = self.serial_ins.read_cmd(out_time=1)
         if receive_data is False:
-            print("------------------------------------------------4657564654")
-            print(
-                "------------------------------------------------get_basic_info_mcu------------------"
-            )
-            logger.info("------------------------------------------------4657564654")
+            logger.info("get_basic_info_mcu,------------------------------------------------4657564654")
             self.connect_state = False
             return False
         if not receive_data:

+ 30 - 0
python/sockets/message_handler.py

@@ -790,6 +790,36 @@ async def handlerSend(
                 ),
                 name="handlerCutOut",
             )
+        case "get_dynamic_config":
+            device_ctrl = DeviceControl(
+                websocket_manager=manager, smart_shooter=smart_shooter
+            )
+            dynamic_configs = device_ctrl.get_dynamic_config()
+            # print("dynamic_configs", dynamic_configs)
+            data = manager.jsonMessage(
+                code=0,
+                msg="成功",
+                msg_type="get_dynamic_config",
+                data=dynamic_configs,
+            )
+            await manager.send_personal_message(data, websocket)
+        case "set_dynamic_config":
+            # 设置动态参数
+            device_ctrl = DeviceControl(
+                websocket_manager=manager, smart_shooter=smart_shooter
+            )
+            readonly = data.get("readonly", False)
+            if not readonly:
+                dynamic_configs = device_ctrl.set_dynamic_config(data)
+            else:
+                dynamic_configs = False
+            data = manager.jsonMessage(
+                code=0,
+                msg="成功",
+                msg_type="set_dynamic_config",
+                data={"status": dynamic_configs},
+            )
+            await manager.send_personal_message(data, websocket)
         case _:
             data = manager.jsonMessage(code=1, msg="未知消息")
             await manager.send_personal_message(data, websocket)