Bläddra i källkod

Merge branch 'smart-shooter-merge' into smart-shooter-master

rambo 4 månader sedan
förälder
incheckning
1a4a9d4ed8

+ 12 - 17
python/api.py

@@ -626,12 +626,6 @@ def get_photo_records(page: int = 1, size: int = 5):
         }
     ]
     for item in result:
-        print(item)
-        # list_item = photos.read_all(
-        #     session,
-        #     conditions={"goods_art_no": item.goods_art_no},
-        #     join_conditions=join_conditions,
-        # )
         query = (
             select(PhotoRecord, DeviceConfig.action_name)
             .where(PhotoRecord.goods_art_no == item.goods_art_no)
@@ -731,10 +725,21 @@ def update_left_right_config(params: LeftRightParams):
     save_device_config = sysConfig.updateConditions(
         session, conditions={"key": "action_configs"}, **kwargs
     )
-    # return {"code": 0, "msg": "操作成功", "data": save_device_config}
     return {"code": 0, "msg": "操作成功", "data": None}
 
 
+@app.post("/update_record", description="更新拍照记录")
+def update_record(params: RecordUpdate):
+    session = SqlQuery()
+    photoRecord = CRUD(PhotoRecord)
+    model = photoRecord.read(session, conditions={"id": params.id})
+    if model == None:
+        return {"code": 1, "msg": "记录不存在", "data": None}
+    kwargs = params.__dict__
+    save_device_config = photoRecord.update(session, obj_id=params.id, **kwargs)
+    return {"code": 0, "msg": "操作成功", "data": save_device_config}
+
+
 @app.post("/update_sys_configs", description="创建或修改系统配置")
 def save_sys_configs(params: SysConfigParams):
     session = SqlQuery()
@@ -754,16 +759,6 @@ def save_sys_configs(params: SysConfigParams):
 def create_main_image(params: MaineImageTest):
     file_path = params.file_path
     onePic = OnePicTest(pic_path=file_path)
-    # session = SqlQuery()
-    # sysConfig = CRUD(SysConfigs)
-    # model = sysConfig.read(session, conditions={"key": params.key})
-    # if model == None:
-    #     return {"code": 1, "msg": "配置不存在", "data": None}
-    # # 走编辑逻辑
-    # kwargs = params.__dict__
-    # save_device_config = sysConfig.updateConditions(
-    #     session, conditions={"key": params.key}, **kwargs
-    # )
     main_out_path = onePic.HandlerMainImage()
     return {"code": 0, "msg": "操作成功", "data": {"main_out_path": main_out_path}}
 

+ 4 - 3
python/databases.py

@@ -79,8 +79,9 @@ def insert_photo_records(
     device_config = PhotoRecord(**data)
     session.add(device_config)
     session.commit()
+    record_id = device_config.id
     session.close()
-    return True
+    return True, record_id
 
 
 # 创建一个通用的 CRUD 类
@@ -93,8 +94,8 @@ class CRUD:
         db_obj = self.model(**obj_in_data)
         session.add(db_obj)
         session.commit()
-        session.refresh(db_obj)
-        session.close()
+        # session.refresh(db_obj)
+        # session.close()
         return db_obj
 
     def read(

+ 106 - 0
python/docs/socket命令.md

@@ -553,4 +553,110 @@ _(该命令用于单独自定义配置中某一项的单独调整测试,不进
     "msg_type": "stop_action"
 }
 ```
+
+
+
+#### 使用smart shooter进行相机控制
+<mark>以下操作需要连接连接相机并拉起smartshooter5软件<mark>
+##### 获取相机是否连接
+* data:{}
+* type:
+    * 当该字段为smart_shooter_getinfo时,代表获取相机连接信息,是否连接成功
+##### 请求示例
+```python
+{
+    "data":{},
+    "type": "smart_shooter_getinfo"
+}
+```
+##### 响应示例-连接成功
+###### 发送后指令转换
+```python
+{
+    "code": 0,
+    "msg": "相机已连接",
+    "status": 2,
+    "data": null,
+    "msg_type": "smart_shooter_getinfo"
+}
+```
+##### 响应示例-连接失败
+###### 发送后指令转换
+```python
+{
+    "code": 0,
+    "msg": "相机未连接",
+    "status": -1,
+    "data": null,
+    "msg_type": "smart_shooter_getinfo"
+}
+```
+
+##### 启动/关闭预览
+* data:
+    * value:为true时代表打开预览,为false时代表关闭预览
+* type:
+    * 当该字段为smart_shooter_enable_preview时,代表操作预览启动关闭操作
+##### 请求示例
+```python
+{
+    "data":{"value":false},
+    "type": "smart_shooter_enable_preview"
+}
+```
+##### 响应示例-启动预览
+```python
+{
+    "code": 0,
+    "msg": "预览启用成功",
+    "status": 2,
+    "data": null,
+    "msg_type": ""
+}
+```
+##### 响应示例-关闭预览
+```python
+{
+    "code": 0,
+    "msg": "预览关闭成功",
+    "status": 2,
+    "data": null,
+    "msg_type": ""
+}
+```
+
+
+##### 拍照
+* data:{}
+* type:
+    * 当该字段为smart_shooter_photo_take时,代表操作拍照动作
+##### 请求示例
+```python
+{
+    "data":{},
+    "type": "smart_shooter_photo_take"
+}
+```
+##### 响应示例-拍照成功
+```python
+{
+    "code": 0,
+    "msg": "拍照成功",
+    "status": 2,
+    "data": null,
+    "msg_type": ""
+}
+```
+##### 响应示例-照片获取成功
+```python
+{
+    "code": 1,
+    "msg": "照片获取成功",
+    "data": {
+        "photo_file_name": "C:\\Users\\15001\\Pictures\\Smart Shooter 5\\SSP_45.JPG"
+    },
+    "msg_type": "smart_shooter_photo_take"
+}
+```
+
 ##### 未完待续.....

+ 6 - 2
python/mcu/BaseClass.py

@@ -1,11 +1,15 @@
 import asyncio
 from sockets import ConnectionManager
 from utils.common import message_queue
+from mcu.capture.smart_shooter_class import SmartShooter
 
 class BaseClass:
 
-    def __init__(self, websocket_manager: ConnectionManager):
+    def __init__(
+        self, websocket_manager: ConnectionManager, smart_shooter: SmartShooter = None
+    ):
         self.websocket_manager = websocket_manager
+        self.smart_shooter = smart_shooter
         self.msg_type = ""
         # -1连接失败  0未连接 1连接中  2连接成功  3端口占用
         # self.device_status = 2
@@ -94,4 +98,4 @@ class BaseClass:
             except:
                 serial_handle = None
                 _recv_data = b""
-                return False
+                return False

+ 26 - 29
python/mcu/BlueToothMode.py

@@ -9,13 +9,17 @@ from utils.SingletonType import SingletonType
 from .RemoteControlV2 import RemoteControlV2
 from .BaseClass import BaseClass
 from sockets.connect_manager import ConnectionManager
+from mcu.capture.smart_shooter_class import SmartShooter
 
-class BlueToothMode(BaseClass,metaclass=SingletonType):
+
+class BlueToothMode(BaseClass, metaclass=SingletonType):
     instance = None
     init_flag = None
 
-    def __init__(self, websocket_manager: ConnectionManager):
-        super().__init__(websocket_manager)
+    def __init__(
+        self, websocket_manager: ConnectionManager, smart_shooter: SmartShooter = None
+    ):
+        super().__init__(websocket_manager, smart_shooter)
         """此处设计为,如果已经存在实例时,不再执行初始化"""
         if self.init_flag:
             return
@@ -149,8 +153,8 @@ class BlueToothMode(BaseClass,metaclass=SingletonType):
                     self.print_error("Failed to connect to the device.")
                     self.devices[address]["connect_state"] = False
                     self.disconnect_device(
-                            address=address, name=self.devices[address]["name"]
-                        )
+                        address=address, name=self.devices[address]["name"]
+                    )
                     continue
                 if len(self.devices) == 0:
                     break
@@ -162,32 +166,28 @@ class BlueToothMode(BaseClass,metaclass=SingletonType):
                     for char in service.characteristics:
                         if "notify" in char.properties:
                             self.print_error(
-                                    f"Subscribing to characteristic: {char.uuid}"
-                                )
+                                f"Subscribing to characteristic: {char.uuid}"
+                            )
                             await client.start_notify(
-                                    char,
-                                    lambda char, data: asyncio.create_task(
-                                        self.notification_handler(address, char, data)
-                                    ),
-                                )
+                                char,
+                                lambda char, data: asyncio.create_task(
+                                    self.notification_handler(address, char, data)
+                                ),
+                            )
 
                 # 进入一个简单的循环,保持连接
                 self.print_error(
-                        "进入一个简单的循环  保持连接", self.devices[address]["name"]
-                    )
-                self.connect_device(
-                        address=address, name=self.devices[address]["name"]
-                    )
+                    "进入一个简单的循环  保持连接", self.devices[address]["name"]
+                )
+                self.connect_device(address=address, name=self.devices[address]["name"])
                 self.retry_num += 1
                 while True:
                     if not client.is_connected:
-                        self.print_error(
-                                f"Device {address} disconnected unexpectedly."
-                            )
+                        self.print_error(f"Device {address} disconnected unexpectedly.")
                         with self._lock:
                             self.disconnect_device(
-                                    address=address, name=self.devices[address]["name"]
-                                )
+                                address=address, name=self.devices[address]["name"]
+                            )
                             if len(self.devices) == 0:
                                 break
                             self.devices[address]["connect_state"] = False
@@ -196,13 +196,9 @@ class BlueToothMode(BaseClass,metaclass=SingletonType):
                         break
                     if self.devices[address]["send_queue"]:
                         with self._lock:
-                            send_data = self.devices[address][
-                                    "send_queue"
-                                ].popleft()
+                            send_data = self.devices[address]["send_queue"].popleft()
                             # print("-----------> send_data:", self.change_hex_to_10_int(send_data))
-                        await self.write_characteristic(
-                                client, char.uuid, send_data
-                            )
+                        await self.write_characteristic(client, char.uuid, send_data)
                         await asyncio.sleep(0.01)
 
                     await asyncio.sleep(0.02)
@@ -229,7 +225,7 @@ class BlueToothMode(BaseClass,metaclass=SingletonType):
         # self.devices_name[_name] = address
         # asyncio.create_task(self.connect_and_listen(address))
         if self.connect_state == True:
-            print('蓝牙已连接,不可重新连接')
+            print("蓝牙已连接,不可重新连接")
             message = {
                 "_type": "show_info",
                 "plugins_mode": "remote_control",
@@ -251,6 +247,7 @@ class BlueToothMode(BaseClass,metaclass=SingletonType):
                 await asyncio.sleep(3)
             await self.scan_for_esp32()
         print("蓝牙断开连接,已释放")
+
     def run(self):
         self.print_error("开启蓝牙扫描")
         asyncio.run(self.main_func())

+ 72 - 69
python/mcu/DeviceControl.py

@@ -16,13 +16,15 @@ from .McuDeviationSet import McuDeviationSet
 from .OtherSet import OtherSet
 from .DebugUart import DebugUart
 import copy
-
+from mcu.capture.smart_shooter_class import SmartShooter
 # mcu命令
 class DeviceControl(BaseClass, metaclass=SingletonType):
     lock = threading.Lock()
 
-    def __init__(self, websocket_manager: ConnectionManager):
-        super().__init__(websocket_manager)
+    def __init__(
+        self, websocket_manager: ConnectionManager, smart_shooter: SmartShooter = None
+    ):
+        super().__init__(websocket_manager=websocket_manager,smart_shooter=smart_shooter)
         self.msg_type = "mcu"
         self.mcu_deviation_set = McuDeviationSet(self)
         self.mcu_other_set = OtherSet(self)
@@ -114,6 +116,7 @@ class DeviceControl(BaseClass, metaclass=SingletonType):
             92: self.get_from_mcu_move_respond_data,  # 获取MCU响应
             100: self.print_mcu_error_data,  # 打印下位机的错误内容
         }
+
     async def sendCommand(self,command):
         await asyncio.sleep(0.01)
         loop = asyncio.get_event_loop()
@@ -261,12 +264,16 @@ class DeviceControl(BaseClass, metaclass=SingletonType):
 
     async def getDeviationInfo(self):
         await asyncio.sleep(0.01)
-        # 发送获取偏移量
-        data = [self.command["get_deviation"], 1]
-        self.add_send_data_queue(data)
-        # if self.serial_ins:
-        #     self.serial_ins.write_cmd(data)
-        print("发送获取偏移量")
+        try:
+            # 发送获取偏移量
+            data = [self.command["get_deviation"], 1]
+            self.add_send_data_queue(data)
+            # if self.serial_ins:
+            #     self.serial_ins.write_cmd(data)
+            print("发送获取偏移量")
+        except Exception as e:
+            print(e)
+            print("getDeviationInfo", "暂未获取到self.command")
 
     def set_deviation(self, device_name, _type=0, deviation=0):
         # turntable----0 angle_ratio   1 turntable_steering_deviation
@@ -333,7 +340,8 @@ class DeviceControl(BaseClass, metaclass=SingletonType):
             print("send_data_queue  append  :{}".format(data))
             self.send_data_queue.append(data)
         self.lock.release()
-    def send_all_cmd(self):
+    async def send_all_cmd(self):
+        await asyncio.sleep(0.001)
         while True:
             if self.send_data_queue:
                 self.sendSocketMessage(msg="正在发送命令", device_status=1)
@@ -446,8 +454,9 @@ class DeviceControl(BaseClass, metaclass=SingletonType):
         buf.extend(self.encapsulation_data(data=has_been_set_motor_config, len_data=1))
         self.add_send_data_queue(buf)
 
-    def cleanAllReceiveData(self):
+    async def cleanAllReceiveData(self):
         while True:
+            await asyncio.sleep(0.001)
             receive_data = self.serial_ins.read_cmd(out_time=1)
             if not receive_data:
                 break
@@ -1265,8 +1274,9 @@ class DeviceControl(BaseClass, metaclass=SingletonType):
             self.sendSocketMessage(code=1, msg="mcu 非停止状态", device_status=1)
         return True
 
-    def controlDevice(self, device_name, value):
+    async def controlDevice(self, device_name, value):
         '''控制设备移动等'''
+        await asyncio.sleep(0.01)
         if not self.is_running:
             self.sendSocketMessage(
                 code=1, msg="mcu设备未连接,请先连接设备", device_status=0
@@ -1331,18 +1341,15 @@ class DeviceControl(BaseClass, metaclass=SingletonType):
                     device_name="laser_position", value=0 if int(value) <= 0 else 1
                 )
             case "take_picture":
-                capture_one = DigiCam()
-                try:
-                    # camera_is_connect = capture_one.checkCameraConnect()
-                    # if camera_is_connect is not True:
-                    #     self.sendSocketMessage(1,"相机未连接,请检查",device_status=-1)
-                    #     return
-                    capture_one.getCaptureFolderPath()
-                    if value > 0:
-                        capture_one.auto_focus()
-                    capture_one.run_capture_action("Capture")
-                except:
-                    self.sendSocketMessage(1,"digicam未初始化,请检查",device_status=-1)
+                # loop = asyncio.get_event_loop()
+                # if value>0:
+                #     # 指定自动对焦
+                #     loop.create_task(
+                #         self.smart_shooter.CameraAutofocus(),
+                #         name="CameraAutofocus",
+                #     )
+                # 拍照
+                await self.smart_shooter.CameraShooter(msg_type="run_mcu")
             case "to_deal_device":
                 self.to_deal_device(device_name, value=value, _type=0, times=1)
             case _:
@@ -1350,6 +1357,7 @@ class DeviceControl(BaseClass, metaclass=SingletonType):
             # case "photograph":
             #     self.photograph(goods_art_no=None)
     def checkDevice(self):
+        print("检查设备是否运行中")
         if not self.is_running:
             self.sendSocketMessage(
                 code=1, msg="mcu设备未连接,请先连接设备", device_status=0
@@ -1366,12 +1374,15 @@ class DeviceControl(BaseClass, metaclass=SingletonType):
             )
             return False
 
-    async def run_mcu_config(self, config_list, goods_art_no, action_info):
+    async def run_mcu_config(
+        self, config_list, goods_art_no, action_info, smart_shooter
+    ):
         if self.checkDevice() == False:
             return
         image_counts = 0
         if config_list:
             action_names = []
+            record_ids = []
             if len(config_list) > 1:
                 if config_list[-1]["take_picture"] is True:
                     new_init_config = copy.copy(config_list[0])
@@ -1389,17 +1400,18 @@ class DeviceControl(BaseClass, metaclass=SingletonType):
             for idx, item in enumerate(config_list):
                 is_take_picture = item["take_picture"]
                 action_id = item["id"]
+                record_id = -1
                 if is_take_picture:
-                    action_names.append(item["action_name"])
                     image_counts += 1
                     # 批量插入
                     image_deal_mode = 0 if action_info == "执行左脚程序" else 1
-                    insert_photo_records(
+                    state,record_id = insert_photo_records(
                         image_deal_mode=image_deal_mode,
                         goods_art_no=goods_art_no,
                         image_index=idx,
                         action_id=action_id,
                     )
+                config_list[idx]["record_id"] = record_id
             total_len = len(config_list)
             self.action_state = 1
             self.msg_type = "image_process"
@@ -1416,17 +1428,20 @@ class DeviceControl(BaseClass, metaclass=SingletonType):
                     ),
                 },
             )
-            self.controlDevice("laser_position", 0)
+            await self.controlDevice("laser_position", 0)
             self.msg_type = "mcu"
             self.is_runn_action = True
             for index, action in enumerate(config_list):
-                await asyncio.sleep(0.1)
+                # await asyncio.sleep(0.01)
                 if self.is_stop_action == True:
                     self.is_stop_action = False
                     break
-                action_is_take_picture = action["take_picture"]
+                # action_is_take_picture = action["take_picture"]
+                record_id = action["record_id"]
                 image_index = -1
-                if action_is_take_picture:
+                if record_id == -1:
+                    image_index = -1
+                else:
                     image_index = index
                 program_item = ProgramItem(
                     websocket_manager=self.websocket_manager,
@@ -1434,44 +1449,35 @@ class DeviceControl(BaseClass, metaclass=SingletonType):
                     mcu=self,
                     goods_art_no=goods_art_no,
                     image_index=image_index,
+                    smart_shooter=smart_shooter,
+                    record_id=record_id,
                 )
-                print("self.action_state===>", self.action_state)
                 if self.action_state != 1:
                     # 异常终止
                     print("action异常终止")
                     break
                 self.msg_type = "photo_take"
-                if not program_item.run(total_len):
+                if not await program_item.run(total_len):
                     self.sendSocketMessage(
                         code=1,
                         msg="{} 执行失败~".format(program_item.action_name),
+                        data={"goods_art_no": goods_art_no, "id": action_id},
                         device_status=0,
                     )
                     self.to_deal_device(device_name="buzzer", times=3)
                     break
                 else:
-                    # self.show_info("{}执行完成~".format(action.action_name))
+                    if program_item.action_name == "移动到初始位":
+                        self.msg_type = "mcu"
+                        break
                     self.sendSocketMessage(
                         code=0,
                         msg="{} 执行完成~".format(program_item.action_name),
-                        data={"goods_art_no": goods_art_no},
+                        data={"goods_art_no": goods_art_no, "id": record_id},
                         device_status=2,
                     )
                 self.msg_type = "mcu"
                 # 在第三张图时检查是否有对应图片生成
-                # if index == 3:
-                #     # if not self.image_process_data.check_photo_is_get():
-                #     self.sendSocketMessage(
-                #             code=1,
-                #             msg="未获取到图片数据",
-                #             device_status=0,
-                #         )
-                #     self.action_state = 2
-                #     return
-                if index == total_len - 1:
-                    #  最后一个初始化处理
-                    pass
-                # self.action_state = 2
             self.action_state = 2
             self.is_runn_action = False
             self.msg_type = "photo_take_finish"
@@ -1481,46 +1487,39 @@ class DeviceControl(BaseClass, metaclass=SingletonType):
                 device_status=2,
             )
             self.msg_type = "mcu"
-            self.controlDevice("laser_position", 1)
+            await self.controlDevice("laser_position", 1)
 
-    async def run_mcu_config_single(self, config_info, goods_art_no,msg_type="run_mcu_single_finish",image_index=-1):
+    async def run_mcu_config_single(self, config_info, goods_art_no,msg_type="run_mcu_single_finish",image_index=-1,smart_shooter=None,action_id=-1):
         '''独立拍照  仅作测试用'''
+        await asyncio.sleep(0.01)
         if self.checkDevice() == False:
             return
+        print("检查完成", config_info)
         if config_info:
             self.action_state = 1
             self.msg_type = "mcu"
-            await asyncio.sleep(0.1)
             program_item = ProgramItem(
                     websocket_manager=self.websocket_manager,
                     action_data=config_info,
                     mcu=self,
                     goods_art_no=goods_art_no,
                     image_index=image_index,
+                    smart_shooter=smart_shooter,
+                    record_id=action_id,
                 )
-            print("self.action_state===>", self.action_state)
             if self.action_state != 1:
                 # 异常终止
                 print("action异常终止")
                 return
             self.msg_type = "photo_take"
-            # if not program_item.run_only_mcu(1):
-            #     self.sendSocketMessage(
-            #             code=1,
-            #             msg="{} 执行失败~".format(program_item.action_name),
-            #             device_status=0,
-            #         )
-            #     self.to_deal_device(device_name="buzzer", times=3)
-            #     return
-            # else:
-            program_item.run(3)
-            # self.show_info("{}执行完成~".format(action.action_name))
+            program_item.smart_shooter = smart_shooter
+            await program_item.run(3)
             self.sendSocketMessage(
-                        code=0,
-                        msg="{} 执行完成~".format(program_item.action_name),
-                        data={"goods_art_no": goods_art_no},
-                        device_status=2,
-                    )
+                code=0,
+                msg="{} 执行完成~".format(program_item.action_name),
+                data={"goods_art_no": goods_art_no, "id": action_id},
+                device_status=2,
+            )
             self.msg_type = "mcu"
             self.action_state = 2
             self.msg_type = msg_type
@@ -1530,6 +1529,10 @@ class DeviceControl(BaseClass, metaclass=SingletonType):
                     device_status=2,
                 )
             self.msg_type = "mcu"
+        else:
+            self.sendSocketMessage(
+                code=1, msg="未查询到重拍记录得配置信息,请确认", device_status=0
+            )
 
 
 async def checkMcuConnection(device_ctrl: DeviceControl):
@@ -1544,7 +1547,7 @@ async def checkMcuConnection(device_ctrl: DeviceControl):
         return
     """实时检测串口是否连接"""
     while True:
-        await asyncio.sleep(0.5)
+        await asyncio.sleep(0.01)
         if device_ctrl.mcu_exit:
             break
         ports_dict = device_ctrl.scan_serial_port()

+ 8 - 4
python/mcu/McuDeviationSet.py

@@ -21,8 +21,8 @@ class McuDeviationSet:
         self.last_value = defaultdict(float)
         is_debug = True if settings.IS_DEBUG == "true" else False
         self.mcu_debug = McuDebug(mcu, is_debug=is_debug, is_deviation=False)
-        loop = asyncio.get_event_loop()
-        loop.create_task(self.get_mcu_deviation(), name="get_mcu_deviation")
+        # loop = asyncio.get_event_loop()
+        self.get_mcu_deviation()
         # # 运动到设定位
         # QTimer.singleShot(2500, self.init_pos)
 
@@ -235,8 +235,12 @@ class McuDeviationSet:
     def _to_init_all(self, *args):
         self.mcu.to_init_device_origin_point(device_name="mcu", is_force=True)
 
-    async def get_mcu_deviation(self):
-        await self.mcu.getDeviationInfo()
+    def get_mcu_deviation(self):
+        # await asyncio.sleep(0.01)
+        # await self.mcu.getDeviationInfo()
+        # loop = asyncio.get_event_loop()
+        # loop.create_task(self.mcu.getDeviationInfo(), name="get_mcu_deviation")
+        asyncio.run(self.mcu.getDeviationInfo())
 
     def get_mcu_deviation_info(self, data):
         if "_type" not in data:

+ 76 - 32
python/mcu/ProgramItem.py

@@ -1,3 +1,4 @@
+import asyncio
 import json
 import os
 
@@ -7,24 +8,39 @@ import time
 from .capture.module_digicam import DigiCam
 from .capture.module_watch_dog import FileEventHandler
 
+
 class ProgramItem(BaseClass):
     # program_sign = Signal(dict)
     # program_refresh_photo_list_sign = Signal()
 
-    def __init__(self,websocket_manager, action_data:any, mcu, goods_art_no:str=None,image_index:int=-1):
+    def __init__(
+        self,
+        websocket_manager,
+        action_data: any,
+        mcu,
+        goods_art_no: str = None,
+        image_index: int = -1,
+        record_id: int = -1,
+        smart_shooter=None,
+    ):
         super().__init__(BaseClass)
         # 1 表示等待中,2表示没有等待
         self.wait_state = 2
         self.msg_type = "mcu"
         print("action_data====>", action_data)
         self.data = action_data
-        self.capture_one = DigiCam()
-        captrure_folder_path = self.capture_one.getCaptureFolderPath()
-        self.watch_dog = FileEventHandler()
-        self.watch_dog.goods_art_no = goods_art_no
-        self.watch_dog.image_index = image_index
-        self.watch_dog.mcu = mcu
-        self.watch_dog.start_observer(captrure_folder_path)
+        print("ProgramItem smart_shooter", smart_shooter)
+        self.smart_shooter = smart_shooter
+        if smart_shooter == None:
+            self.capture_one = DigiCam()
+            captrure_folder_path = self.capture_one.getCaptureFolderPath()
+            self.watch_dog = FileEventHandler()
+            self.watch_dog.goods_art_no = goods_art_no
+            self.watch_dog.image_index = image_index
+            self.watch_dog.mcu = mcu
+            self.watch_dog.start_observer(captrure_folder_path)
+        else:
+            print("使用smart_shooter")
         print("21 =========ProgramItem=======action_data=====")
         print(action_data)
         self.action_id = self.get_value(action_data, "id")
@@ -51,6 +67,7 @@ class ProgramItem(BaseClass):
 
         self.last_photograph_time = None  # 最近一次拍照时间
         self.goods_art_no = goods_art_no  # 货号
+        self.record_id = record_id  # 货号
 
         self.set_other()
         self.error_info_text = ""  # 错误提示信息
@@ -93,7 +110,7 @@ class ProgramItem(BaseClass):
         }
         if self.is_wait:
             msg = "{}--等待".format(self.action_name)
-            self.sendSocketMessage(msg=msg,device_status=0)
+            self.sendSocketMessage(msg=msg, device_status=0)
         else:
             msg = "{}".format(self.action_name)
             self.sendSocketMessage(msg=msg, device_status=2)
@@ -125,24 +142,24 @@ class ProgramItem(BaseClass):
         #     self.ui_retry.setEnabled(True)
         #     self.ui_action_name.setToolTip(self.error_info_text)
 
-    def check_mcu_move_is_stop(self, re_check=False):
+    async def check_mcu_move_is_stop(self, re_check=False):
         self.error_info_text = ""
         # 发送基础数据信息
         # self.mcu.to_get_mcu_base_info()
         _s = time.time()
         last_num_1 = self.mcu.last_mcu_info_data["num"]
-        self.mcu.cleanAllReceiveData()
+        await self.mcu.cleanAllReceiveData()
         while 1:
             if self.mcu.action_state != 1:
                 # 外部终止,停止运行
                 return False
             cr_time = time.time()
-            print(cr_time - _s, cr_time,_s)
+            print(cr_time - _s, cr_time, _s)
             if cr_time - _s > 8:
                 self.error_info_text = "MCU检测运动未停止,自动退出"
                 self.set_state(state_value=99)  # 标记异常
                 print("MCU检测运动未停止,自动退出")
-                self.sendSocketMessage(msg=self.error_info_text,device_status=-1)
+                self.sendSocketMessage(msg=self.error_info_text, device_status=-1)
                 return False
                 # return True
             # 存在时间间隙,导致误认为所有设备已完成运动
@@ -150,15 +167,15 @@ class ProgramItem(BaseClass):
                 return True
             else:
                 self.mcu.to_get_mcu_base_info()
-                self.mcu.send_all_cmd()
-                time.sleep(0.5)
+                await self.mcu.send_all_cmd()
+                await asyncio.sleep(0.5)
                 self.mcu.get_basic_info_mcu()
                 # return True
 
-            time.sleep(0.1)
+            await asyncio.sleep(0.1)
             # self.mcu.to_get_mcu_base_info()
 
-    def run(self, total_len=5, *args):
+    async def run(self, total_len=5, *args):
         if total_len == 1:
             self.mode_type = "其他配置"
             self.set_other()
@@ -166,12 +183,11 @@ class ProgramItem(BaseClass):
         print("1{}  - is run".format(self.action_name))
         self.set_state(state_value=1)
         if settings.IS_TEST:
-            self.do_run()
+            await self.do_run()
         else:
             try:
-                self.do_run()
+                await self.do_run()
             except BaseException as e:
-                # print("p_item 错误:{}".format(e))
                 self.sendSocketMessage(
                     msg="p_item 错误:{}".format(e), device_status=-1
                 )
@@ -209,16 +225,21 @@ class ProgramItem(BaseClass):
                 time.sleep(0.1)
             self.mcu.send_all_cmd()
 
-    def do_run(self, *args):
+    async def do_run(self, *args):
+        await asyncio.sleep(0.001)
         # if not self.goods_art_no:  # and self.action_name != "初始化位置"
         #     return False
         start_time = time.time()
         # ============连接MCU 处理步进电机与舵机等
         if settings.IS_MCU:
-            if self.mode_type != "其他配置" and self.check_mcu_move_is_stop() is False:
+            if self.mode_type != "其他配置" and await self.check_mcu_move_is_stop() is False:
                 # MCU运动是否有停止检查,设定超时时间
                 return
-            print("{} 检查停止时间1:{}".format(self.action_name, time.time() - start_time))
+            print(
+                "{} 检查停止时间1:{}".format(
+                    self.action_name, time.time() - start_time
+                )
+            )
             if self.is_led:
                 self.mcu.to_deal_device(device_name="laser_position", value=1)
             else:
@@ -252,34 +273,57 @@ class ProgramItem(BaseClass):
                 # time.sleep(0.1)
 
             # MCU运动是否有停止检查,设定超时时间
-            self.mcu.send_all_cmd()
+            await self.mcu.send_all_cmd()
             if self.mode_type != "其他配置":
-                time.sleep(1.2)
+                await asyncio.sleep(1.2)
                 print("二次检查")
-                if self.check_mcu_move_is_stop(re_check=True) is False:
+                if await self.check_mcu_move_is_stop(re_check=True) is False:
                     print("MCU检测运动未停止,自动退出,   提前退出")
                     return
 
         if self.delay_time:
-            # print("拍照前延时:{}".format(self.delay_time))
-            time.sleep(self.delay_time)
-
+            await asyncio.sleep(self.delay_time)
         if self.is_photograph:
-            print("拍照==>", time.time())
             # print("photograph==================")
             self.mcu.to_deal_device(device_name="buzzer", times=1)
             # 用于临时拍照计数
             is_af = True if self.af_times > 0 else False
-            self.capture_one.photograph(is_af=is_af)
+            if self.smart_shooter != None:
+                # 拍照
+                print("smart shooter 拍照")
+                record_id = self.record_id
+                goods_art_no = self.goods_art_no
+                if record_id == -1:
+                    goods_art_no = ""
+                print("smart shooter CameraShooter")
+                await self.smart_shooter.CameraShooter(
+                    msg_type="run_mcu",
+                    goods_art_no=goods_art_no,
+                    id=record_id,
+                    is_af=is_af,
+                )
+                print("smart shooter CameraShooter end")
+            else:
+                # 指定自动对焦
+                self.capture_one.photograph(is_af=is_af)
             self.last_photograph_time = time.time()  # 记录最近一次拍照时间
         # print("{} 拍照时间:{}".format(self.action_name, time.time() - start_time))
         print("{}-{}已完成".format(self.mode_type, self.action_name))
 
         if self.after_delay_time:
             print("拍照后延时:{}".format(self.after_delay_time))
-            time.sleep(self.after_delay_time)
+            await asyncio.sleep(self.after_delay_time)
         return True
 
+    async def RunSmartShooter(self, goods_art_no,record_id):
+        await asyncio.gather(
+            self.smart_shooter.CameraShooter(
+                msg_type="run_mcu",
+                goods_art_no=goods_art_no,
+                id=record_id,
+            ),
+        )
+
     def rephotograph_one_pic(self, *args):
         """
         1、获取最近一张照片

+ 53 - 23
python/mcu/RemoteControlV2.py

@@ -3,11 +3,12 @@
 
 import json
 import time, asyncio
+from model import DeviceConfig
 import settings
 from .SerialIns import SerialIns
 from .BaseClass import BaseClass
 from sockets.connect_manager import ConnectionManager
-from databases import SqlQuery, PhotoRecord, CRUD, insert_photo_records
+from databases import SqlQuery, PhotoRecord,DeviceConfig, CRUD, insert_photo_records
 from .capture.module_digicam import DigiCam
 from .capture.module_watch_dog import FileEventHandler
 
@@ -234,7 +235,7 @@ class RemoteControlV2(BaseClass):
         self.msg_type = "blue_tooth"
         self.photo_take_state = 2
 
-    async def handlerTakePhoto(self):
+    async def handlerTakePhoto(self, smart_shooter=None):
         """处理单独拍照"""
         await asyncio.sleep(0.1)
         print("开始单拍0")
@@ -262,30 +263,61 @@ class RemoteControlV2(BaseClass):
                 )
                 self.msg_type = "blue_tooth"
                 return
+            deviceConfig = CRUD(DeviceConfig)
+            deviceConfigData = deviceConfig.read(session=session, conditions={"id": record.action_id})
+            select_tab_id = deviceConfigData.tab_id
+            AllTabConfig = deviceConfig.read_all(session=session, conditions={"tab_id": select_tab_id})
+            action_id = 0
+            if AllTabConfig[len(AllTabConfig) - 1].take_picture == True:
+                action_id = AllTabConfig[0].id
+            else:
+                action_id = AllTabConfig[len(AllTabConfig) - 1].id
+            image_index = record.image_index + 1
+            self.photo_take_state = 1
+            deviceConfig = CRUD(DeviceConfig)
+            deviceConfigData = deviceConfig.read(
+                session=session, conditions={"id": record.action_id}
+            )
+            select_tab_id = deviceConfigData.tab_id
+            AllTabConfig = deviceConfig.read_all(
+                session=session, conditions={"tab_id": select_tab_id}
+            )
+            action_id = 0
+            if AllTabConfig[len(AllTabConfig) - 1].take_picture == True:
+                action_id = AllTabConfig[0].id
+            else:
+                action_id = AllTabConfig[len(AllTabConfig) - 1].id
             image_index = record.image_index + 1
             self.photo_take_state = 1
-            insert_photo_records(
+            state, record_id = insert_photo_records(
                 record.image_deal_mode,
                 record.goods_art_no,
                 image_index,
-                record.action_id,
+                action_id,
             )
             print("开始单拍1-插入数据")
-            capture_one = DigiCam()
             try:
-                watch_dog = FileEventHandler()
-                if watch_dog.observer is None:
-                    captrure_folder_path = capture_one.getCaptureFolderPath()
-                    watch_dog.start_observer(captrure_folder_path)
-                watch_dog.goods_art_no = record.goods_art_no
-                watch_dog.image_index = image_index
-                print("开始单拍1-检查相机")
-                # camera_is_connect = capture_one.checkCameraConnect()
-                # if camera_is_connect is not True:
-                #     self.sendSocketMessage(1, "相机未连接,请检查", device_status=-1)
-                #     return
-                capture_one.run_capture_action("Capture")
-                print("开始单拍1-完成拍照")
+                if smart_shooter == None:
+                    capture_one = DigiCam()
+                    watch_dog = FileEventHandler()
+                    if watch_dog.observer is None:
+                        captrure_folder_path = capture_one.getCaptureFolderPath()
+                        watch_dog.start_observer(captrure_folder_path)
+                    watch_dog.goods_art_no = record.goods_art_no
+                    watch_dog.image_index = image_index
+                    print("开始单拍1-检查相机")
+                    capture_one.run_capture_action("Capture")
+                    print("开始单拍1-完成拍照")
+                else:
+                    loop = asyncio.get_event_loop()
+                    loop.create_task(
+                        smart_shooter.CameraShooter(
+                            msg_type="handler_take_picture",
+                            goods_art_no=record.goods_art_no,
+                            id=record_id,
+                        ),
+                        name="CameraShooter",
+                    )
                 time.sleep(1)
                 self.msg_type = "photo_take"
                 self.sendSocketMessage(
@@ -295,12 +327,13 @@ class RemoteControlV2(BaseClass):
                         if record.image_deal_mode == 1
                         else "执行左脚程序"
                     ),
-                    data={"goods_art_no": record.goods_art_no},
+                    data={"goods_art_no": record.goods_art_no, "id": record_id},
                     device_status=2,
                 )
                 self.msg_type = "blue_tooth"
             except Exception as e:
-                self.sendSocketMessage(1, "digicam未初始化,请检查", device_status=-1)
+                print(f"错误:{e}")
+                self.sendSocketMessage(1, "处理失败,请重试", device_status=-1)
         self.photo_take_state = 0
 
     async def analysis_received_data(self):
@@ -311,11 +344,8 @@ class RemoteControlV2(BaseClass):
             receive_data = self.bluetooth_ins.read_cmd_one(
                 address=self.bluetooth_address
             )
-            # print("received data", 1)
         else:
             receive_data = self.serial_ins.read_cmd(out_time=1, check=None)
-        # print("received data", 2)
-        # print("self.bluetooth_ins", receive_data)
         if receive_data is False:
             self.connect_state = False
             return False

+ 16 - 4
python/mcu/capture/module_watch_dog.py

@@ -10,7 +10,7 @@ from databases import CRUD, SqlQuery, PhotoRecord
 import asyncio
 
 
-def updateImageRaw(time_str, image_path, goods_art_no, image_index):
+def updateImageRaw(time_str, image_path, goods_art_no, record_id):
     session = SqlQuery()
     crud = CRUD(PhotoRecord)
     res = crud.read(
@@ -18,7 +18,15 @@ def updateImageRaw(time_str, image_path, goods_art_no, image_index):
         conditions={
             "image_path": None,
             "goods_art_no": goods_art_no,
-            "image_index": image_index,
+            "id": record_id,
+        },
+    )
+    print(
+        "更新图片数据库======>",
+        {
+            "image_path": image_path,
+            "goods_art_no": goods_art_no,
+            "id": record_id,
         },
     )
     if res:
@@ -29,7 +37,7 @@ def updateImageRaw(time_str, image_path, goods_art_no, image_index):
         }
         crud.update(
             session,
-            res.id,
+            record_id,
             **update,
         )
 
@@ -45,6 +53,7 @@ class FileEventHandler(FileSystemEventHandler, metaclass=SingletonType):
         #     self.init_flag = True
         self.goods_art_no = None
         self.image_index = -1
+        self.record_id = -1
         self.mcu = None
         super().__init__()
         # self.window = window
@@ -176,7 +185,10 @@ class FileEventHandler(FileSystemEventHandler, metaclass=SingletonType):
                 )
                 loop.close()
                 updateImageRaw(
-                    create_time, file_path, self.goods_art_no, self.image_index
+                    create_time,
+                    file_path,
+                    self.goods_art_no,
+                    self.record_id,
                 )
             except BaseException as e:
                 print("获取文件create_time失败", e)

+ 385 - 0
python/mcu/capture/smart_shooter_class.py

@@ -0,0 +1,385 @@
+import json
+import datetime
+import random
+import zmq
+import asyncio
+from PIL import Image
+from io import BytesIO
+import base64
+import zmq, sys
+from utils.SingletonType import SingletonType
+
+
+# 定义为单例模式,避免被重复实例化
+class SmartShooter(metaclass=SingletonType):
+    SET_REQ = "tcp://127.0.0.1:54544"
+    LISTEN_REQ = "tcp://127.0.0.1:54543"
+
+    def __init__(self, websocket_manager):
+        self.msg_type = "smart_shooter"
+        self.websocket_manager = websocket_manager
+        # 是否停止监听
+        self.stop_listen = False
+        # 相机连接状态
+        self.connect_status = False
+        # 实时预览状态
+        self.perview_state = False
+        self.callback_listen = None
+        self.listen_init = False
+        self.websocket = None
+        # loop = asyncio.get_event_loop()
+        # loop.create_task(
+        #         self.connect_listen(),
+        #         name="connect_listen",
+        #     )
+
+    def __send_tcp_message(self, socket, msg):
+        # await asyncio.sleep(0.01)
+        socket.send_string(json.dumps(msg))
+        rep = socket.recv()
+        str_msg = rep.decode("utf-8")
+        json_msg = json.loads(str_msg)
+        return json_msg
+
+    def __create_req(self, time_out=5) -> tuple[zmq.Socket, zmq.Context]:
+        context = zmq.Context()
+        req_socket = context.socket(zmq.REQ)
+        # 设置发送超时为 5000 毫秒(5 秒)
+        req_socket.setsockopt(zmq.RCVTIMEO, time_out * 1000)
+        # 设置接收超时为 5000 毫秒(5 秒)
+        req_socket.setsockopt(zmq.SNDTIMEO, time_out * 1000)
+        req_socket.setsockopt(zmq.LINGER, 0)  # 设置为 0 表示不等待未完成的操作
+        req_socket.connect(self.SET_REQ)
+        return req_socket, context
+
+    def __create_listen(self) -> tuple[zmq.Socket, zmq.Context]:
+        context = zmq.Context()
+        listen_socket = context.socket(zmq.SUB)
+        listen_socket.setsockopt(zmq.SUBSCRIBE, b"")
+        # 设置发送超时为 5000 毫秒(5 秒)
+        listen_socket.setsockopt(zmq.RCVTIMEO, 4000)
+        # 设置接收超时为 5000 毫秒(5 秒)
+        listen_socket.setsockopt(zmq.SNDTIMEO, 4000)
+        listen_socket.setsockopt(zmq.LINGER, 0)  # 设置为 0 表示不等待未完成的操作
+        listen_socket.connect(self.LISTEN_REQ)
+        return listen_socket, context
+
+    async def GetCameraInfo(self, is_send=True, msg_type=""):
+        await asyncio.sleep(0.01)
+        self.msg_type = msg_type
+        """
+            实时获取相机信息,是否连接、软件是否被打开
+            """
+        socket, context = self.__create_req(time_out=2)
+        try:
+            req = {}
+            req["msg_type"] = "Request"
+            req["msg_id"] = "GetCamera"
+            req["msg_seq_num"] = 0
+            req["CameraSelection"] = "All"
+            json_msg = self.__send_tcp_message(socket, req)
+            msg_result = json_msg.get("msg_result")
+            if not msg_result:
+                self.connect_status = False
+                msg_send = "相机未连接或软件未打开"
+                if is_send:
+                    message = {
+                        "code": 1,
+                        "msg": msg_send,
+                        "data": msg_result,
+                        "msg_type": self.msg_type,
+                        "device_status": -1,
+                    }
+                    await self.websocket_manager.send_personal_message(
+                        message, self.websocket
+                    )
+                return False, msg_send
+            cameraInfo = json_msg.get("CameraInfo")
+            if cameraInfo == None or len(cameraInfo) == 0:
+                self.connect_status = False
+                msg_send = "相机未连接"
+                if is_send:
+                    message = {
+                        "code": 1,
+                        "msg": msg_send,
+                        "data": msg_result,
+                        "msg_type": self.msg_type,
+                        "device_status": -1,
+                    }
+                    await self.websocket_manager.send_personal_message(
+                        message, self.websocket
+                    )
+                return False, "相机未连接"
+            # 链接的相机
+            # connect_camera = cameraInfo
+            CameraStatus = any(
+                item.get("CameraStatus") in ["Ready", "Busy"] for item in cameraInfo
+            )
+            # CameraStatus = connect_camera.get("CameraStatus")
+            if not CameraStatus:
+                self.connect_status = False
+                msg_send = "相机未连接"
+                if is_send:
+                    message = {
+                        "code": 1,
+                        "msg": msg_send,
+                        "data": msg_result,
+                        "msg_type": self.msg_type,
+                        "device_status": -1,
+                    }
+                    await self.websocket_manager.send_personal_message(
+                        message, self.websocket
+                    )
+                return False, msg_send
+            self.connect_status = True
+            msg_send = "相机已连接"
+            if is_send:
+                message = {
+                    "code": 0,
+                    "msg": msg_send,
+                    "data": msg_result,
+                    "msg_type": self.msg_type,
+                    "device_status": 2,
+                }
+                await self.websocket_manager.send_personal_message(
+                    message, self.websocket
+                )
+            return True, "相机已连接"
+        except zmq.Again:
+            print("获取相机信息超时,继续监听...")
+            msg_send = "相机未连接或软件未打开"
+            if is_send:
+                message = {
+                    "code": 1,
+                    "msg": msg_send,
+                    "data": None,
+                    "msg_type": self.msg_type,
+                    "device_status": -1,
+                }
+                await self.websocket_manager.send_personal_message(
+                    message, self.websocket
+                )
+            return False, msg_send
+        except Exception as e:
+            print("拍照异常", e)
+            self.connect_status = False
+            socket.close()
+            context.term()
+            msg_send = "相机未连接或软件未打开"
+            if is_send:
+                message = {
+                    "code": 1,
+                    "msg": msg_send,
+                    "data": None,
+                    "msg_type": self.msg_type,
+                    "device_status": -1,
+                }
+                await self.websocket_manager.send_personal_message(
+                    message, self.websocket
+                )
+            return False, msg_send
+
+    async def EnableCameraPreview(self, enable_status=True, msg_type=""):
+        self.msg_type = msg_type
+        """
+        激活相机预览
+        """
+        camera_states, _ = await self.GetCameraInfo(is_send=False)
+        if not camera_states:
+            return False, "请先连接相机"
+        try:
+            socket, context = self.__create_req()
+            req = {}
+            req["msg_type"] = "Request"
+            req["msg_id"] = "EnableLiveview"
+            req["msg_seq_num"] = 0
+            req["CameraSelection"] = "All"
+            req["Enable"] = enable_status
+            json_msg = self.__send_tcp_message(socket, req)
+            msg_result = json_msg.get("msg_result")
+            if not msg_result:
+                self.perview_state = False
+                msg_send = "预览启用失败"
+                self.sendSocketMessage(
+                    code=0,
+                    msg=msg_send,
+                    device_status=2,
+                )
+                return False, "预览启用失败"
+            msg_send = "预览启用成功" if enable_status else "预览关闭成功"
+            message = {
+                "code": 0,
+                "msg": msg_send,
+                "data": None,
+                "msg_type": self.msg_type,
+                "device_status": 2,
+            }
+            await self.websocket_manager.send_personal_message(message, self.websocket)
+            return True, "预览启用成功" if enable_status else "预览关闭成功"
+        except zmq.Again:
+            print("启动预览超时,继续监听...")
+        except:
+            self.perview_state = False
+            socket.close()
+            context.term()
+            msg_send = "相机未连接或软件未打开"
+            message = {
+                "code": 1,
+                "msg": msg_send,
+                "data": None,
+                "msg_type": self.msg_type,
+                "device_status": -1,
+            }
+            await self.websocket_manager.send_personal_message(message, self.websocket)
+            return False, "相机未连接或软件未打开"
+
+    async def CameraAutofocus(self):
+        """
+        相机自动对焦
+        """
+        camera_states, _ = await self.GetCameraInfo(is_send=False)
+        print("CameraAutofocus 执行对焦")
+        if not camera_states:
+            return False, "请先连接相机"
+        try:
+            socket, context = self.__create_req()
+            req = {}
+            req["msg_type"] = "Request"
+            req["msg_id"] = "Autofocus"
+            req["msg_seq_num"] = 0
+            req["CameraSelection"] = "All"
+            json_msg = self.__send_tcp_message(socket, req)
+            print("json_msg", json_msg)
+            msg_result = json_msg.get("msg_result")
+            if not msg_result:
+                return False, "对焦失败"
+            return True, "对焦成功"
+        except zmq.Again:
+            print("对焦超时,继续监听...")
+        except:
+            socket.close()
+            context.term()
+            return False, "相机未连接或软件未打开"
+
+    async def CameraShooter(self, msg_type="", goods_art_no="", id=0, is_af=False):
+        # 对焦混用
+        if is_af:
+            await self.CameraAutofocus()
+        self.msg_type = msg_type
+        print("camera_states", msg_type)
+        """
+        执行拍照
+        """
+        camera_states, _ = await self.GetCameraInfo(is_send=True)
+        print("camera_states CameraShooter", camera_states)
+        if not camera_states:
+            return False, "请先连接相机"
+        try:
+            socket, context = self.__create_req()
+            req = {}
+            req["msg_type"] = "Request"
+            req["msg_id"] = "Shoot"
+            req["msg_seq_num"] = 1
+            req["CameraSelection"] = "All"
+            if goods_art_no != "" and id != 0:
+                # 此处用逗号分割,货号和id,需要在监听部分进行切割保存处理,如果使用下划线或者减号,可能货号中存在对应符号
+                req["PhotoOrigin"] = f"{goods_art_no},{id}"
+            else:
+                req["PhotoOrigin"] = ""
+            json_msg = self.__send_tcp_message(socket, req)
+            print("CameraShooter", json_msg)
+            msg_result = json_msg.get("msg_result")
+            if not msg_result:
+                msg_send = "拍照失败"
+                message = {
+                    "code": 1,
+                    "msg": msg_send,
+                    "data": None,
+                    "msg_type": self.msg_type,
+                    "device_status": -1,
+                }
+                await self.websocket_manager.send_personal_message(
+                    message, self.websocket
+                )
+                return False, msg_send
+            msg_send = "拍照成功"
+            message = {
+                "code": 0,
+                "msg": msg_send,
+                "data": None,
+                "msg_type": self.msg_type,
+                "device_status": 2,
+            }
+            msg_send = "相机未连接或软件未打开"
+            message = {
+                "code": 1,
+                "msg": msg_send,
+                "data": None,
+                "msg_type": self.msg_type,
+                "device_status": -1,
+            }
+            await self.websocket_manager.send_personal_message(message, self.websocket)
+            return True, "拍照成功"
+        except zmq.Again:
+            msg_send = "相机未连接或软件未打开"
+            message = {
+                "code": 1,
+                "msg": msg_send,
+                "data": {goods_art_no: goods_art_no, "id": id},
+                "msg_type": self.msg_type,
+                "device_status": -1,
+            }
+            await self.websocket_manager.send_personal_message(message, self.websocket)
+            return True, "拍照失败"
+        except:
+            socket.close()
+            context.term()
+            msg_send = "相机未连接或软件未打开"
+            message = {
+                "code": 1,
+                "msg": msg_send,
+                "data": None,
+                "msg_type": self.msg_type,
+                "device_status": -1,
+            }
+            await self.websocket_manager.send_personal_message(message, self.websocket)
+            return False, msg_send
+
+    async def connect_listen(self):
+        print("smart shooter connect_listen", self.connect_status, self.listen_init)
+        if self.connect_status == True or self.listen_init == True:
+            return True
+        # 发起监听
+        sub_socket, context = self.__create_listen()
+        print("构建监听", self.connect_status)
+        while True:
+            self.listen_init = True
+            await asyncio.sleep(0.01)
+            if self.callback_listen == None:
+                continue
+            camera_states, camera_msg = await self.GetCameraInfo(is_send=False)
+            if not camera_states:
+                print("相机未连接")
+                await asyncio.sleep(0.01)  # 等待相机连接
+                continue
+            if self.stop_listen:
+                break
+            try:
+                self.connect_status = True
+                raw = sub_socket.recv()
+                str_msg = raw.decode("utf-8")
+                json_msg = json.loads(str_msg)
+                if json_msg["msg_id"] == "NetworkPing":
+                    continue
+                await self.callback_listen(json_msg)
+            except zmq.Again:
+                print("接收超时,继续监听...")
+                continue
+            except Exception as e:
+                self.connect_status = False
+                print(f"发生错误: {e}")
+                break
+        self.listen_init = False
+        sub_socket.close()
+        context.term()
+        print("smart shooter连接断开")

+ 7 - 0
python/models.py

@@ -110,3 +110,10 @@ class LogoParamsupdate(BaseModel):
 class DeviceConfigTabsReq(BaseModel):
     id: int = Field(default=None, primary_key=True)
     mode_name: str = Field(default="", description="Tab名称")
+
+
+class RecordUpdate(BaseModel):
+    """系统配置"""
+
+    id: int = Field(default=0, description="记录id")
+    image_path: str = Field(default=None, description="图片地址")

+ 13 - 10
python/service/OnePicTest.py

@@ -46,10 +46,13 @@ class OnePicTest():
         check_path("temp")
         check_path("temp\pic_test")
         root = r"{}\temp\pic_test".format(os.getcwd())
-        for file_name in os.listdir(root):
-            path = "{}\{}".format(root, file_name)
-            if os.path.isfile(path):
-                os.remove(path)
+        try:
+            for file_name in os.listdir(root):
+                path = "{}\{}".format(root, file_name)
+                if os.path.isfile(path):
+                    os.remove(path)
+        except Exception as e:
+            print("deal_image", e)
 
         # ==============抠图处理=====================
         remove_pic_ins = RemoveBgALi()
@@ -66,8 +69,8 @@ class OnePicTest():
         print("image_path", image_path)
         print("cut_image_path", cut_image_path)
         print("main_out_path", main_out_path)
-        try:
-            GeneratePic().run(
+        # try:
+        GeneratePic().run(
                     image_path=image_path,
                     cut_image_path=cut_image_path,
                     out_path=main_out_path,
@@ -76,9 +79,9 @@ class OnePicTest():
                     out_pic_size=1024,
                     is_logo=False,
             )
-        except Exception as e:
-            print(e)
-            raise UnicornException("处理失败,请重试")
+        # except Exception as e:
+        #     print(e)
+        #     raise UnicornException("处理失败,请重试")
 
         # return_data["code"] = 0
         # return_data["data"]["image_path"] = image_path
@@ -91,7 +94,7 @@ class OnePicTest():
         if not os.path.exists(self.pic_path):
             raise UnicornException("图片不存在")
         image_pth = Image.open(self.pic_path)
-        if image_pth.mode != "RGB":
+        if image_pth.mode == "RGBA":
             raise UnicornException("抠图图片不能是PNG")
         return_data = self.deal_image(self.pic_path)
         # if return_data["message"]:

+ 7 - 4
python/service/generate_main_image/grenerate_main_image_test.py

@@ -402,11 +402,14 @@ class GeneratePic(object):
         print("242  need_time_1:{}".format(time.time() - _s))
 
         orign_x, orign_y = orign_im.size
-        time.sleep(1)
+        time.sleep(3)
         cut_image = Image.open(cut_image_path)  # 原始图的已扣图
-        cut_image, new_box = get_mini_crop_img(img=cut_image)
-        im_shadow = orign_im.crop(new_box)  # 切图
-        new_x, new_y = im_shadow.size
+        try:
+            cut_image, new_box = get_mini_crop_img(img=cut_image)
+            im_shadow = orign_im.crop(new_box)  # 切图
+            new_x, new_y = im_shadow.size
+        except:
+            im_shadow = cut_image
 
         # ================自动色阶处理
         _s = time.time()

+ 1 - 3
python/sockets/connect_manager.py

@@ -26,14 +26,12 @@ class ConnectionManager:
 
     async def send_personal_message(self, message: str, websocket: WebSocket):
         '''向用户发送消息'''
-        print("ready message successfully")
         await websocket.send_json(message)
-        print("sent message successfully")
 
     async def broadcast(self, message: str):
         """广播消息"""
         for connection in self.active_connections:
             if connection.client_state == WebSocketState.DISCONNECTED:
                 continue
-            print("connection", connection.client_state)
+            print("正在发送广播消息", "message", connection.client_state)
             await connection.send_json(message)

+ 162 - 51
python/sockets/message_handler.py

@@ -5,10 +5,33 @@ from mcu.DeviceControl import DeviceControl, checkMcuConnection
 from mcu.BlueToothMode import BlueToothMode
 from databases import DeviceConfig, SqlQuery, CRUD, PhotoRecord, SysConfigs
 from mcu.capture.module_digicam import DigiCam
+from mcu.capture.smart_shooter_class import SmartShooter
+from models import RecordUpdate
+from sqlalchemy.exc import NoResultFound
+import os, datetime
+
+async def updateDataRecord(PhotoFilename, id):
+    await asyncio.sleep(0.01)
+    create_time = datetime.datetime.fromtimestamp(os.path.getctime(PhotoFilename))
+    data = {"id": id, "image_path": PhotoFilename, "photo_create_time": create_time}
+    # record_model = PhotoRecord(**data)
+    session = SqlQuery()
+    record_model = CRUD(PhotoRecord)
+    model = record_model.read(session, conditions={"id": id})
+    if model == None:
+        print(f"smart shooter 拍照记录更新失败,记录id:{id},不存在")
+    else:
+        # 走编辑逻辑
+        record_model.updateConditions(session, conditions={"id": id}, **data)
+        print(f"smart shooter 拍照记录更新成功,记录id:{id}")
+
 
 # socket消息发送逻辑处理方法
 async def handlerSend(
-    manager: ConnectionManager, receiveData: str, websocket: WebSocket
+    manager: ConnectionManager,
+    receiveData: str,
+    websocket: WebSocket,
+    smart_shooter: SmartShooter,
 ):
     loop = asyncio.get_event_loop()
     receiveData = json.loads(receiveData)
@@ -18,8 +41,50 @@ async def handlerSend(
     code = receiveData.get("code")
     msg = receiveData.get("msg")
     data = receiveData.get("data")
-    print("receiveData", receiveData)
-    print("jsonType", jsonType)
+
+    async def MsgCallback(msg):
+        msg_id = msg.get("msg_id")
+        match msg_id:
+            case "PhotoUpdated":
+                PhotoFilename = msg.get("PhotoFilename")
+                PhotoLocation = msg.get("PhotoLocation")
+                PhotoOrigin = msg.get("PhotoOrigin")
+                if (PhotoFilename != "" and PhotoFilename != None) and (
+                    PhotoLocation == "Local Disk"
+                ):
+                    # temp_photo_name = PhotoFilename
+                    # 更新拍照记录
+                    print("PhotoFilename", PhotoFilename, PhotoOrigin)
+                    if PhotoOrigin != "" and PhotoOrigin != "external":
+                        goods_art_no, id = PhotoOrigin.split(",")
+                        loop.create_task(
+                            updateDataRecord(PhotoFilename, id), name="PhotoFilename"
+                        )
+                    data = manager.jsonMessage(
+                        code=0,
+                        msg=f"照片获取成功",
+                        data={"photo_file_name": PhotoFilename},
+                        msg_type="smart_shooter_photo_take",
+                    )
+                    await manager.send_personal_message(data, websocket)
+            case "LiveviewUpdated":
+                CameraLiveviewImage = msg.get("CameraLiveviewImage", None)
+                # base64_to_image(CameraLiveviewImage, "liveview.jpg")
+                # print("收到直播画面:CameraLiveviewImage")
+                data = manager.jsonMessage(
+                    code=1,
+                    msg=f"预览数据发送",
+                    data={"smart_shooter_preview": CameraLiveviewImage},
+                    msg_type="smart_shooter_enable_preview",
+                )
+                await manager.send_personal_message(data, websocket)
+
+    # 构建监听条件
+    smart_shooter.callback_listen = MsgCallback
+    loop.create_task(
+        smart_shooter.connect_listen(),
+        name="smart_shooter_connect_listen",
+    )
     match jsonType:
         case "ping":
             """发送心跳"""
@@ -30,10 +95,12 @@ async def handlerSend(
             pass
         case "forward_message":
             data = receiveData.get("data")
-            dictMsg = {"code":code,"msg":msg,"data":data}
+            dictMsg = {"code": code, "msg": msg, "data": data}
             await manager.broadcast(dictMsg)
         case "connect_mcu":
-            device_ctrl = DeviceControl(websocket_manager=manager)
+            device_ctrl = DeviceControl(
+                websocket_manager=manager, smart_shooter=smart_shooter
+            )
             device_ctrl.mcu_exit = False
             # if device_ctrl.serial_ins.check_connect():
             #     print("未连接")
@@ -46,9 +113,11 @@ async def handlerSend(
             loop.create_task(blue_tooth.main_func(), name="blue_tooth")
             # loop.close()
         case "init_mcu":
-            device_ctrl = DeviceControl(websocket_manager=manager)
+            device_ctrl = DeviceControl(
+                websocket_manager=manager, smart_shooter=smart_shooter
+            )
             # 是否强制初始化
-            is_force_init = data.get("value",False)
+            is_force_init = data.get("value", False)
             loop.create_task(device_ctrl.initDevice(is_force_init), name="init_mcu")
         case "control_mcu":
             device_name = data.get("device_name")
@@ -56,15 +125,17 @@ async def handlerSend(
             if (device_name == "" or device_name == None) or (
                 value == "" or value == None
             ):
-                data = manager.jsonMessage(
-                    code=1, msg="参数错误", msg_type="mcu"
-                )
+                data = manager.jsonMessage(code=1, msg="参数错误", msg_type="mcu")
                 await manager.send_personal_message(data, websocket)
                 return
-            device_ctrl = DeviceControl(websocket_manager=manager)
-            device_ctrl.controlDevice(device_name, value)
+            device_ctrl = DeviceControl(
+                websocket_manager=manager, smart_shooter=smart_shooter
+            )
+            await device_ctrl.controlDevice(device_name, value)
         case "stop_action":
-            device_ctrl = DeviceControl(websocket_manager=manager)
+            device_ctrl = DeviceControl(
+                websocket_manager=manager, smart_shooter=smart_shooter
+            )
             if device_ctrl.is_runn_action == True:
                 print("动作执行中,停止")
                 device_ctrl.is_stop_action = True
@@ -74,7 +145,7 @@ async def handlerSend(
             msg_type = "run_mcu"
             action_info = data.get("action", "执行左脚程序")
             goods_art_no = data.get("goods_art_no", None)
-            if goods_art_no == None or goods_art_no =="":
+            if goods_art_no == None or goods_art_no == "":
                 # 判断货号是否存在
                 data = manager.jsonMessage(
                     code=1, msg="goods_art_no不能为空", msg_type=msg_type
@@ -92,7 +163,9 @@ async def handlerSend(
                 action_flag = "right"
             tab_id = action_configs_json.get(action_flag)
             photoRecord = CRUD(PhotoRecord)
-            goods_art_record = photoRecord.read(session,conditions={"goods_art_no": goods_art_no})
+            goods_art_record = photoRecord.read(
+                session, conditions={"goods_art_no": goods_art_no}
+            )
             if goods_art_record != None:
                 data = manager.jsonMessage(
                     code=1,
@@ -112,42 +185,35 @@ async def handlerSend(
                 await manager.send_personal_message(data, websocket, msg_type=msg_type)
                 return
             action_list = [device.model_dump() for device in all_devices]
-            print("action_list", action_list)
-            device_ctrl = DeviceControl(websocket_manager=manager)
+            print("handl send smart_shooter", smart_shooter)
+            device_ctrl = DeviceControl(
+                websocket_manager=manager, smart_shooter=smart_shooter
+            )
             loop.create_task(
-                device_ctrl.run_mcu_config(action_list, goods_art_no, action_info),
+                device_ctrl.run_mcu_config(
+                    action_list, goods_art_no, action_info, smart_shooter
+                ),
                 name="run_mcu_config",
             )
         case "run_mcu_single":
-            device_ctrl = DeviceControl(websocket_manager=manager)
+            device_ctrl = DeviceControl(
+                websocket_manager=manager, smart_shooter=smart_shooter
+            )
             loop.create_task(
-                device_ctrl.run_mcu_config_single(data, None, "run_mcu_single"),
+                device_ctrl.run_mcu_config_single(
+                    data, None, "run_mcu_single", -1, smart_shooter
+                ),
                 name="run_mcu_single",
             )
         case "handler_take_picture":
-            blue_tooth = BlueToothMode(websocket_manager=manager)
+            blue_tooth = BlueToothMode(
+                websocket_manager=manager, smart_shooter=smart_shooter
+            )
             loop.create_task(
-                blue_tooth.remote_control_v2.handlerTakePhoto(),
+                blue_tooth.remote_control_v2.handlerTakePhoto(smart_shooter),
                 name="run_mcu_config",
             )
-        case "re_take_picture":#重拍
-            # try:
-            #     # 判断拍照软件是否初始化
-            #     digicam = DigiCam()
-            #     camera_is_connect = digicam.checkCameraConnect()
-            #     if camera_is_connect is not True:
-            #         data = manager.jsonMessage(
-            #             code=1, msg="相机未连接,请检查", msg_type=msg_type
-            #         )
-            #         await manager.send_personal_message(data, websocket)
-            #         return
-            #     digicam.getCaptureFolderPath()
-            # except:
-            #     data = manager.jsonMessage(
-            #         code=1, msg="digicam未初始化,请检查", msg_type=msg_type
-            #     )
-            #     await manager.send_personal_message(data, websocket)
-            #     return
+        case "re_take_picture":  # 重拍
             msg_type = "re_take_picture"
             record_id = data.get("record_id")
             session = SqlQuery()
@@ -166,32 +232,42 @@ async def handlerSend(
             image_index = goods_art_record.image_index
             crud = CRUD(DeviceConfig)
             condtions = {"id": action_id}
-            device_action = crud.read(
-                session, conditions=condtions
-            )
+            device_action = crud.read(session, conditions=condtions)
             if device_action == None:
                 # 判断是否有可用配置
                 data = manager.jsonMessage(code=1, msg="当前没有可用配置")
                 await manager.send_personal_message(data, websocket, msg_type=msg_type)
                 return
+            print("device_action", device_action)
             # 清除图片记录,执行重拍
             reset_data = {"image_path": None}
             photoRecord.update(session, record_id, **reset_data)
-            device_ctrl = DeviceControl(websocket_manager=manager)
+            device_ctrl = DeviceControl(
+                websocket_manager=manager, smart_shooter=smart_shooter
+            )
             loop.create_task(
                 device_ctrl.run_mcu_config_single(
-                    device_action.model_dump(), goods_art_no, msg_type=msg_type,image_index=image_index
+                    device_action.model_dump(),
+                    goods_art_no,
+                    msg_type=msg_type,
+                    image_index=image_index,
+                    smart_shooter=smart_shooter,
+                    action_id=record_id,
                 ),
                 name="run_mcu_config_single",
             )
         case "get_deviation":
-            device_ctrl = DeviceControl(websocket_manager=manager)
+            device_ctrl = DeviceControl(
+                websocket_manager=manager, smart_shooter=smart_shooter
+            )
             loop.create_task(
                 device_ctrl.getDeviationInfo(),
                 name="get_deviation",
             )
         case "set_deviation":
-            device_ctrl = DeviceControl(websocket_manager=manager)
+            device_ctrl = DeviceControl(
+                websocket_manager=manager, smart_shooter=smart_shooter
+            )
             value = data.get("value", None)
             action_name = data.get("action_name", None)
             loop.create_task(
@@ -199,7 +275,9 @@ async def handlerSend(
                 name="set_deviation",
             )
         case "move_deviation":
-            device_ctrl = DeviceControl(websocket_manager=manager)
+            device_ctrl = DeviceControl(
+                websocket_manager=manager, smart_shooter=smart_shooter
+            )
             value = data.get("value", None)
             action_name = data.get("action_name", None)
             loop.create_task(
@@ -207,23 +285,56 @@ async def handlerSend(
                 name="move_deviation",
             )
         case "get_mcu_other_info":
-            device_ctrl = DeviceControl(websocket_manager=manager)
+            device_ctrl = DeviceControl(
+                websocket_manager=manager, smart_shooter=smart_shooter
+            )
             loop.create_task(
                 device_ctrl.getMcuOtherInfo(),
                 name="mcu_other_set_get",
             )
         case "set_mcu_other_info":
-            device_ctrl = DeviceControl(websocket_manager=manager)
+            device_ctrl = DeviceControl(
+                websocket_manager=manager, smart_shooter=smart_shooter
+            )
             loop.create_task(
                 device_ctrl.setMcuOtherInfo(data),
                 name="setMcuOtherInfo",
             )
         case "send_command":
-            device_ctrl = DeviceControl(websocket_manager=manager)
+            device_ctrl = DeviceControl(
+                websocket_manager=manager, smart_shooter=smart_shooter
+            )
             loop.create_task(
                 device_ctrl.sendCommand(data.get("command", None)),
                 name="sendCommand",
             )
+        case "smart_shooter_getinfo":
+            """
+            获取相机信息,是否连接
+            """
+            loop.create_task(
+                smart_shooter.GetCameraInfo(msg_type="smart_shooter_getinfo"),
+                name="smart_shooter_getinfo",
+            )
+        case "smart_shooter_enable_preview":
+            """
+            启动相机或关闭实时预览
+            """
+            value = data.get("value", True)
+            loop.create_task(
+                smart_shooter.EnableCameraPreview(
+                    enable_status=value, msg_type="smart_shooter_enable_preview"
+                ),
+                name="smart_shooter_enable_preview",
+            )
+        case "smart_shooter_photo_take":
+            """
+            获取相机信息,是否连接
+            """
+            loop.create_task(
+                smart_shooter.CameraShooter(msg_type="smart_shooter_photo_take"),
+                name="smart_shooter_photo_take",
+            )
         case _:
             data = manager.jsonMessage(code=1, msg="未知消息")
             await manager.send_personal_message(data, websocket)

+ 7 - 2
python/sockets/socket_server.py

@@ -5,18 +5,20 @@ from .connect_manager import ConnectionManager
 from .message_handler import *
 from mcu.DeviceControl import DeviceControl,checkMcuConnection
 from mcu.BlueToothMode import BlueToothMode
+from mcu.capture.smart_shooter_class import SmartShooter
 import time
 from .socket_client import socket_manager
 conn_manager = ConnectionManager()
 active_connections = set()
 device_ctrl = DeviceControl(websocket_manager=conn_manager)
 blue_tooth = BlueToothMode(websocket_manager=conn_manager)
+smart_shooter = SmartShooter(websocket_manager=conn_manager)
 from utils.common import message_queue
 @app.websocket("/ws")
 async def websocket_endpoint(websocket: WebSocket):
     await conn_manager.connect(websocket)
     active_connections.add(websocket)
-
+    smart_shooter.websocket = websocket
     try:
         # await socket_manager.connect()
         async def handler_messages():
@@ -25,6 +27,7 @@ async def websocket_endpoint(websocket: WebSocket):
                     byteDats = await websocket.receive()
                     socket_type = byteDats.get("type")
                     if socket_type == "websocket.disconnect":
+                        smart_shooter.stop_listen = True
                         device_ctrl.close_connect()
                         device_ctrl.mcu_exit = True
                         device_ctrl.clearMyInstance()
@@ -42,7 +45,9 @@ async def websocket_endpoint(websocket: WebSocket):
                         blue_tooth.clearMyInstance()
                         break
                     print("byteDats", byteDats)
-                    await handlerSend(conn_manager, json.dumps(byteDats), websocket)
+                    await handlerSend(
+                        conn_manager, json.dumps(byteDats), websocket, smart_shooter
+                    )
                 except Exception as e:
                     print(e)
                     break