message_handler.py 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984
  1. from .connect_manager import ConnectionManager
  2. from models import WebSocket
  3. import json, asyncio
  4. from mcu.DeviceControl import DeviceControl, checkMcuConnection
  5. from mcu.BlueToothMode import BlueToothMode
  6. from databases import DeviceConfig, SqlQuery, CRUD, PhotoRecord, SysConfigs
  7. from mcu.capture.module_digicam import DigiCam
  8. from mcu.capture.smart_shooter_class import SmartShooter
  9. from models import RecordUpdate
  10. from service.run_main import RunMain
  11. from utils.utils_func import check_path
  12. import time, shutil, os
  13. from service.base import check_move_goods_art_no_folder
  14. from service.deal_image import DealImage
  15. import settings
  16. from middleware import UnicornException
  17. from service.online_request.module_online_data import CategoryLink
  18. from concurrent.futures import ThreadPoolExecutor
  19. from functools import partial
  20. from logger import logger
  21. import stat
  22. from mcu.one_data_set_control import OneDataSet
  23. # 创建全局线程池
  24. executor = ThreadPoolExecutor(max_workers=4)
  25. def get_tab_id_by_category(session, goods_art_no, default_tab_id):
  26. """
  27. 通过货号请求线上分类,匹配sys_configs中key=category_links的配置来替换tab_id
  28. :param session: 数据库会话
  29. :param goods_art_no: 货号
  30. :param default_tab_id: 默认tab_id(action_configs中的原值)
  31. :return: 匹配到的tab_id;分类为空或未匹配到时返回default_tab_id
  32. """
  33. try:
  34. # 请求线上接口,通过货号匹配分类名称
  35. category_link = CategoryLink("Bearer " + (settings.USER_TOKEN or ""))
  36. category_name = category_link.get_category_name(goods_art_no)
  37. # 分类名称为空,继续使用上一行的tab_id
  38. if not category_name:
  39. return default_tab_id
  40. # 读取sys_configs中category_links配置,格式:[{"category_name":"","tab_name":"","tab_id":123}]
  41. sys_configs = CRUD(SysConfigs)
  42. item = sys_configs.read(session, conditions={"key": "category_links"})
  43. if item == None:
  44. return default_tab_id
  45. links = json.loads(item.value)
  46. for link in links:
  47. # 分类名称匹配成功,用配置中的tab_id覆盖上一行变量
  48. if link.get("category_name") == category_name:
  49. print("分类关联匹配成功:", category_name, "->", link.get("tab_id"))
  50. return link.get("tab_id")
  51. # 未匹配到分类,继续使用上一行的tab_id
  52. return default_tab_id
  53. except Exception as e:
  54. # 异常不影响拍摄流程,回退到默认tab_id
  55. logger.error(f"匹配分类关联异常: goods_art_no={goods_art_no}, error={str(e)}")
  56. return default_tab_id
  57. async def handlerCutOut(
  58. manager=None, run_main=None, config_data={}, websocket=None, msg_type=""
  59. ):
  60. max_retry_count = 1 # 最多重试1次
  61. retry_count = 0
  62. while retry_count <= max_retry_count:
  63. try:
  64. if retry_count > 0:
  65. logger.info(f"抠图操作重试第{retry_count}次")
  66. # return_data = run_main.check_before_cutout(config_data)
  67. # await run_main.check_for_cutout_image_first_call_back(return_data)
  68. # 将阻塞操作放到线程池中执行
  69. loop = asyncio.get_event_loop()
  70. return_data = await loop.run_in_executor(
  71. executor, partial(run_main.check_before_cutout, config_data)
  72. )
  73. # await run_main.check_for_cutout_image_first_call_back(return_data)
  74. await loop.run_in_executor(
  75. executor,
  76. partial(run_main.check_for_cutout_image_first_call_back, return_data),
  77. )
  78. # 成功则退出循环
  79. break
  80. except UnicornException as e:
  81. logger.error(f"抠图操作发生UnicornException: {e.msg}")
  82. logger.error(f"异常类型: UnicornException")
  83. logger.error(f"当前重试次数: {retry_count}/{max_retry_count}")
  84. # data = manager.jsonMessage(
  85. # code=1,
  86. # msg=e.msg,
  87. # msg_type=msg_type,
  88. # )
  89. # await manager.send_personal_message(data, websocket)
  90. return
  91. except FileNotFoundError as e:
  92. error_msg = str(e)
  93. logger.error(f"抠图操作发生FileNotFoundError: {error_msg}")
  94. logger.error(f"异常类型: FileNotFoundError")
  95. logger.error(f"当前重试次数: {retry_count}/{max_retry_count}")
  96. # 检查是否是原始图缺失错误
  97. if "原始图" in error_msg and retry_count < max_retry_count:
  98. logger.info("检测到原始图缺失,尝试重新拷贝原图并重试...")
  99. try:
  100. # 重新拷贝原图
  101. goods_art_nos = config_data.get("goods_art_nos", [])
  102. image_dir = config_data.get("image_dir", "")
  103. for goods_art_no in goods_art_nos:
  104. dealImage = DealImage(image_dir)
  105. resFlag, path = dealImage.dealMoveImageV2(
  106. goods_art_no=goods_art_no,
  107. )
  108. if not resFlag:
  109. logger.error(f"重新拷贝原图失败: {goods_art_no}")
  110. raise UnicornException(f"重新拷贝原图失败: {goods_art_no}")
  111. logger.info("原图重新拷贝成功,准备重试抠图操作")
  112. retry_count += 1
  113. continue # 重试
  114. except Exception as copy_error:
  115. logger.error(f"重新拷贝原图时发生错误: {str(copy_error)}")
  116. return
  117. else:
  118. logger.error(f"重新拷贝原图时发生错误: 非原始图错误或已达到最大重试次数")
  119. return
  120. except Exception as e:
  121. import traceback
  122. error_msg = str(e)
  123. stack_trace = traceback.format_exc()
  124. logger.error(f"抠图操作发生未知异常: {error_msg}")
  125. logger.error(f"异常类型: {type(e).__name__}")
  126. logger.error(f"当前重试次数: {retry_count}/{max_retry_count}")
  127. logger.error(f"完整堆栈跟踪:\n{stack_trace}")
  128. # 如果是第一次执行且未达到最大重试次数,则重试
  129. if retry_count < max_retry_count:
  130. logger.info("准备重试抠图操作...")
  131. retry_count += 1
  132. continue
  133. return
  134. def handlerFolderDelete(limit_path, goods_art_no_arrays, is_write_txt_log):
  135. check_path(limit_path)
  136. move_folder_array = check_move_goods_art_no_folder(
  137. "output", goods_art_no_arrays, limit_path
  138. )
  139. for goods_art_revice in goods_art_no_arrays:
  140. cutout_goods = f"{limit_path}/{goods_art_revice}"
  141. if os.path.exists(cutout_goods):
  142. for root, dirs, files in os.walk(cutout_goods):
  143. for file in files:
  144. filepath = os.path.join(root, file)
  145. os.chmod(filepath, stat.S_IWRITE)
  146. logger.info(f"解除占用并开始删除目录:{cutout_goods}")
  147. # 尝试多次删除,增加成功率
  148. retry_count = 3
  149. while retry_count > 0:
  150. try:
  151. shutil.rmtree(cutout_goods, onerror=settings.handle_remove_readonly)
  152. del move_folder_array[goods_art_revice]
  153. break
  154. except OSError as e:
  155. logger.info(f"目录已经被删除-OSError:{str(e)}")
  156. break
  157. except (PermissionError) as e:
  158. retry_count -= 1
  159. if retry_count == 0:
  160. logger.info(
  161. f"抠图前目录删除出现问题-PermissionError:{str(e)};{goods_art_revice};{cutout_goods}")
  162. if is_write_txt_log:
  163. error_file_path = f"{cutout_goods}/异常说明-出现目录丢失或缺少图片请点开查看原因.txt"
  164. with open(error_file_path, 'w', encoding='utf-8') as f:
  165. f.write("目录删除失败\n")
  166. f.write(f"原因: 文件被占用或没有删除权限\n")
  167. f.write(f"错误信息: {str(e)}\n")
  168. f.write(f"时间: {time.strftime('%Y-%m-%d %H:%M:%S')}\n")
  169. f.write(f"请关闭可能正在使用此目录的程序后,为当前货号点击重拍后重试\n")
  170. else:
  171. raise UnicornException(f"目录检查出现问题:{str(e)},请关闭错误提示中的被占用文件")
  172. else:
  173. logger.info(f"抠图前目录删除出现问题--PermissionError:{str(e)};{retry_count}")
  174. time.sleep(0.5) # 等待0.5秒后重试
  175. except Exception as e:
  176. retry_count -= 1
  177. if retry_count == 0:
  178. logger.info(f"抠图前目录删除出现问题--Exception:{str(e)};{goods_art_revice};{cutout_goods}")
  179. if is_write_txt_log:
  180. error_file_path = f"{cutout_goods}/异常说明-出现目录丢失或缺少图片请点开查看原因.txt"
  181. with open(error_file_path, 'w', encoding='utf-8') as f:
  182. f.write("目录删除失败\n")
  183. f.write(f"原因: {str(e)}\n")
  184. f.write(f"时间: {time.strftime('%Y-%m-%d %H:%M:%S')}\n")
  185. f.write(f"请检查目录状态后,为当前货号点击重拍后重试\n")
  186. else:
  187. raise UnicornException(f"目录检查出现问题:{str(e)},请关闭错误提示中的被占用文件")
  188. else:
  189. logger.info(f"抠图前目录删除出现问题--Exception:{str(e)};{retry_count}")
  190. time.sleep(0.5) # 等待0.5秒后重试
  191. return move_folder_array
  192. def validate_goods_art_no(goods_art_no):
  193. """
  194. 验证货号输入是否包含特殊字符
  195. """
  196. import re
  197. # 定义不允许的特殊字符,主要是文件系统中可能导致路径问题的字符
  198. invalid_chars = r'[<>:"/\\|?*]'
  199. if re.search(invalid_chars, goods_art_no):
  200. # 找出所有非法字符
  201. invalid_found = re.findall(invalid_chars, goods_art_no)
  202. invalid_str = ', '.join(set(invalid_found))
  203. return False, f"货号包含非法字符: {invalid_str},请修改后再提交"
  204. return True, ""
  205. # socket消息发送逻辑处理方法
  206. async def handlerSend(
  207. manager: ConnectionManager,
  208. receiveData: str,
  209. websocket: WebSocket,
  210. smart_shooter: SmartShooter,
  211. ):
  212. loop = asyncio.get_event_loop()
  213. receiveData = json.loads(receiveData)
  214. # 处理消息发送逻辑
  215. try:
  216. receiveData = json.loads(receiveData.get("text"))
  217. print("receiveData", receiveData)
  218. jsonType = receiveData.get("type")
  219. code = receiveData.get("code")
  220. msg = receiveData.get("msg")
  221. data = receiveData.get("data")
  222. except:
  223. jsonType = "ping"
  224. match jsonType:
  225. case "ping":
  226. """发送心跳"""
  227. data = manager.jsonMessage("pong")
  228. await manager.send_personal_message(data, websocket)
  229. case "pong":
  230. """发送心跳"""
  231. pass
  232. case "forward_message":
  233. data = receiveData.get("data")
  234. dictMsg = {"code": code, "msg": msg, "data": data}
  235. await manager.broadcast(dictMsg)
  236. case "connect_mcu":
  237. device_ctrl = DeviceControl(
  238. websocket_manager=manager, smart_shooter=smart_shooter
  239. )
  240. device_ctrl.mcu_exit = False
  241. # if device_ctrl.serial_ins.check_connect():
  242. # print("未连接")
  243. loop.create_task(checkMcuConnection(device_ctrl), name="mcu")
  244. case "connect_bluetooth":
  245. blue_tooth = BlueToothMode(websocket_manager=manager)
  246. blue_tooth.bluetooth_exit = False
  247. # await blue_tooth.main_func()
  248. print("连接蓝牙信息")
  249. loop.create_task(blue_tooth.main_func(), name="blue_tooth")
  250. # loop.close()
  251. case "init_mcu":
  252. device_ctrl = DeviceControl(
  253. websocket_manager=manager, smart_shooter=smart_shooter
  254. )
  255. # 是否强制初始化
  256. is_force_init = False
  257. loop.create_task(device_ctrl.initDevice(is_force_init), name="init_mcu")
  258. case "get_mcu_info":
  259. device_ctrl = DeviceControl(
  260. websocket_manager=manager, smart_shooter=smart_shooter
  261. )
  262. if not device_ctrl.is_running:
  263. device_ctrl.sendSocketMessage(
  264. code=1, msg="mcu设备未连接,请先连接设备", device_status=0
  265. )
  266. device_ctrl.send_get_all_info_to_mcu()
  267. case "control_mcu":
  268. device_name = data.get("device_name")
  269. value = data.get("value")
  270. if (device_name == "" or device_name == None) or (
  271. value == "" or value == None
  272. ):
  273. data = manager.jsonMessage(code=1, msg="参数错误", msg_type="mcu")
  274. await manager.send_personal_message(data, websocket)
  275. return
  276. device_ctrl = DeviceControl(
  277. websocket_manager=manager, smart_shooter=smart_shooter
  278. )
  279. await device_ctrl.controlDevice(device_name, value)
  280. case "stop_action":
  281. device_ctrl = DeviceControl(
  282. websocket_manager=manager, smart_shooter=smart_shooter
  283. )
  284. if device_ctrl.is_runn_action == True:
  285. print("动作执行中,停止")
  286. device_ctrl.is_stop_action = True
  287. else:
  288. print("动作没有执行,略过")
  289. data = manager.jsonMessage(code=0, msg="执行终止", msg_type="run_mcu_stop")
  290. await manager.send_personal_message(data, websocket)
  291. return
  292. case "run_mcu":
  293. msg_type = "run_mcu"
  294. action_info = data.get("action", "执行左脚程序")
  295. goods_art_no = data.get("goods_art_no", None)
  296. company_id = data.get("company_id", None)
  297. weight = data.get("weight", None)
  298. goods_art_no = goods_art_no.strip()
  299. if goods_art_no == None or goods_art_no == "":
  300. # 判断货号是否存在
  301. data = manager.jsonMessage(
  302. code=1, msg="goods_art_no不能为空", msg_type=msg_type
  303. )
  304. await manager.send_personal_message(data, websocket)
  305. return
  306. is_ok, msg = validate_goods_art_no(goods_art_no)
  307. if not is_ok:
  308. data = manager.jsonMessage(
  309. code=1, msg=msg, msg_type=msg_type
  310. )
  311. await manager.send_personal_message(data, websocket)
  312. return
  313. session = SqlQuery()
  314. sys_configs = CRUD(SysConfigs)
  315. action_configs = sys_configs.read(
  316. session, conditions={"key": "action_configs"}
  317. )
  318. action_configs_json = json.loads(action_configs.value)
  319. action_flag = "left"
  320. if "右" in action_info:
  321. action_flag = "right"
  322. tab_id = action_configs_json.get(action_flag)
  323. # 指定企业开启分类关联匹配:dev环境-安恒(34398);prod环境-45064
  324. # 通过货号匹配线上分类关联(category_links),匹配成功则覆盖tab_id,否则沿用默认tab_id
  325. category_company_map = {"dev": 34398, "prod": 45064}
  326. if company_id == category_company_map.get(settings.APPENV):
  327. tab_id = get_tab_id_by_category(session, goods_art_no, tab_id)
  328. photoRecord = CRUD(PhotoRecord)
  329. goods_art_record = photoRecord.read(
  330. session, conditions={"goods_art_no": goods_art_no, "delete_time": None}
  331. )
  332. if goods_art_record != None:
  333. data = manager.jsonMessage(
  334. code=1,
  335. msg=f"货号[{goods_art_no}]已存在,请勿重复拍摄~",
  336. msg_type=msg_type,
  337. )
  338. await manager.send_personal_message(data, websocket)
  339. return
  340. crud = CRUD(DeviceConfig)
  341. condtions = {"tab_id": tab_id}
  342. all_devices = crud.read_all(
  343. session, conditions=condtions, order_by="action_index", ascending=True
  344. )
  345. if len(all_devices) == 0:
  346. # 判断是否有可用配置
  347. data = manager.jsonMessage(code=1, msg="当前没有可用配置")
  348. await manager.send_personal_message(data, websocket, msg_type=msg_type)
  349. return
  350. action_list = [dict(device.__dict__) for device in all_devices]
  351. print("执行拍摄 打印动作列表", condtions)
  352. # logger.info("执行拍摄 打印动作列表", json.dumps(action_list))
  353. device_ctrl = DeviceControl(
  354. websocket_manager=manager, smart_shooter=smart_shooter
  355. )
  356. loop.create_task(
  357. device_ctrl.run_mcu_config(
  358. action_list, goods_art_no, action_info, smart_shooter, weight
  359. ),
  360. name="run_mcu_config",
  361. )
  362. session.close()
  363. case "run_mcu_single":
  364. device_ctrl = DeviceControl(
  365. websocket_manager=manager, smart_shooter=smart_shooter
  366. )
  367. loop.create_task(
  368. device_ctrl.run_mcu_config_single(
  369. data, None, "run_mcu_single", -1, smart_shooter
  370. ),
  371. name="run_mcu_single",
  372. )
  373. case "handler_take_picture":
  374. print("收到单拍指令", 'handler_take_picture')
  375. if data is None:
  376. PointName = "A"
  377. else:
  378. PointName = data.get("point_name", "A")
  379. print("收到单拍指令", PointName)
  380. device_ctrl = DeviceControl(
  381. websocket_manager=manager, smart_shooter=smart_shooter
  382. )
  383. await device_ctrl.controlDevice("laser_position", 0)
  384. blue_tooth = BlueToothMode(
  385. websocket_manager=manager, smart_shooter=smart_shooter
  386. )
  387. session = SqlQuery()
  388. crud = CRUD(PhotoRecord)
  389. record = crud.read(session=session, order_by="id", ascending=False, conditions={"delete_time": None})
  390. if record == None:
  391. # 发送失败消息
  392. data = manager.jsonMessage(
  393. code=1,
  394. msg="单拍失败,请先输入货号或扫码进行组合拍摄",
  395. msg_type="handler_take_picture",
  396. )
  397. await manager.send_personal_message(data, websocket)
  398. return
  399. try:
  400. limit_path = "{}/{}".format(settings.OUTPUT_DIR,
  401. time.strftime("%Y-%m-%d", time.localtime(time.time()))
  402. )
  403. move_folder_array = handlerFolderDelete(limit_path, [record.goods_art_no], False)
  404. except UnicornException as e:
  405. data = manager.jsonMessage(
  406. code=1,
  407. msg=e.msg,
  408. msg_type="handler_take_picture",
  409. )
  410. await manager.send_personal_message(data, websocket)
  411. return
  412. record_action_id = record.action_id
  413. deviceConfig = CRUD(DeviceConfig)
  414. deviceConfigSignle = deviceConfig.read(session, conditions={"id": record_action_id})
  415. deviceConfigAll = deviceConfig.read_all(session, conditions={"tab_id": deviceConfigSignle.tab_id},
  416. order_by="action_index",
  417. ascending=True, )
  418. lastConfig = deviceConfigAll[-1]
  419. if not lastConfig.take_picture:
  420. used_config_id = lastConfig.id
  421. else:
  422. used_config_id = deviceConfigAll[0].id
  423. loop.create_task(
  424. blue_tooth.remote_control_v2.handlerTakePhoto(smart_shooter, session, record, PointName,
  425. used_config_id),
  426. name="run_mcu_config",
  427. )
  428. session.close()
  429. await asyncio.sleep(2.5)
  430. await device_ctrl.controlDevice("laser_position", 1)
  431. case "re_take_picture": # 重拍
  432. msg_type = "re_take_picture"
  433. record_id = data.get("record_id")
  434. session = SqlQuery()
  435. photoRecord = CRUD(PhotoRecord)
  436. goods_art_record = photoRecord.read(session, conditions={"id": record_id, "delete_time": None})
  437. if goods_art_record == None:
  438. data = manager.jsonMessage(
  439. code=1,
  440. msg=f"记录不存在,请核实后重新操作~",
  441. msg_type=msg_type,
  442. )
  443. await manager.send_personal_message(data, websocket)
  444. return
  445. action_id = goods_art_record.action_id
  446. goods_art_no = goods_art_record.goods_art_no
  447. image_index = goods_art_record.image_index
  448. crud = CRUD(DeviceConfig)
  449. condtions = {"id": action_id}
  450. device_action = crud.read(session, conditions=condtions)
  451. result_dict = dict(device_action.__dict__)
  452. print("device_action打印输出====>>>", result_dict)
  453. if device_action == None:
  454. # 判断是否有可用配置
  455. data = manager.jsonMessage(code=1, msg="当前没有可用配置")
  456. await manager.send_personal_message(data, websocket, msg_type=msg_type)
  457. return
  458. # 清除图片记录,执行重拍
  459. reset_data = {"image_path": None}
  460. photoRecord.update(session, record_id, **reset_data)
  461. device_ctrl = DeviceControl(
  462. websocket_manager=manager, smart_shooter=smart_shooter
  463. )
  464. loop.create_task(
  465. device_ctrl.run_mcu_config_single(
  466. result_dict,
  467. goods_art_no,
  468. msg_type=msg_type,
  469. image_index=image_index,
  470. smart_shooter=smart_shooter,
  471. action_id=record_id,
  472. ),
  473. name="run_mcu_config_single",
  474. )
  475. session.close()
  476. case "get_deviation":
  477. device_ctrl = DeviceControl(
  478. websocket_manager=manager, smart_shooter=smart_shooter
  479. )
  480. device_ctrl.getDeviationInfo()
  481. case "set_deviation":
  482. device_ctrl = DeviceControl(
  483. websocket_manager=manager, smart_shooter=smart_shooter
  484. )
  485. value = data.get("value", None)
  486. action_name = data.get("action_name", None)
  487. loop.create_task(
  488. device_ctrl.set_deviation_cmd(value, action_name, "set"),
  489. name="set_deviation",
  490. )
  491. case "move_deviation":
  492. device_ctrl = DeviceControl(
  493. websocket_manager=manager, smart_shooter=smart_shooter
  494. )
  495. value = data.get("value", None)
  496. action_name = data.get("action_name", None)
  497. loop.create_task(
  498. device_ctrl.set_deviation_cmd(value, action_name, "move"),
  499. name="move_deviation",
  500. )
  501. case "get_mcu_other_info":
  502. device_ctrl = DeviceControl(
  503. websocket_manager=manager, smart_shooter=smart_shooter
  504. )
  505. loop.create_task(
  506. device_ctrl.getMcuOtherInfo(),
  507. name="mcu_other_set_get",
  508. )
  509. case "set_mcu_other_info":
  510. device_ctrl = DeviceControl(
  511. websocket_manager=manager, smart_shooter=smart_shooter
  512. )
  513. loop.create_task(
  514. device_ctrl.setMcuOtherInfo(data),
  515. name="setMcuOtherInfo",
  516. )
  517. case "send_command":
  518. device_ctrl = DeviceControl(
  519. websocket_manager=manager, smart_shooter=smart_shooter
  520. )
  521. loop.create_task(
  522. device_ctrl.sendCommand(data.get("command", None)),
  523. name="sendCommand",
  524. )
  525. case "smart_shooter_getinfo":
  526. """
  527. 获取相机信息,是否连接
  528. """
  529. # token
  530. # env
  531. # print("smart_shooter_getinfo",data)
  532. # isMultCameraMode = data.get("isMultiCameraMode",False)
  533. loop.create_task(
  534. smart_shooter.GetCameraInfo(
  535. msg_type="smart_shooter_getinfo",
  536. is_send=True,
  537. # isMultCameraMode=isMultCameraMode,
  538. ),
  539. name="smart_shooter_getinfo",
  540. )
  541. case "smart_shooter_enable_preview":
  542. """
  543. 启动相机或关闭实时预览
  544. """
  545. value = data.get("value", True)
  546. if data is None:
  547. PointName = "A"
  548. else:
  549. PointName = data.get("point_name", "A")
  550. logger.info(f"启动相机或关闭实时预览,PointName:{PointName},value:{value}")
  551. camera_configs = settings.getSysConfigs(
  552. "camera_configs",
  553. "iso_config",
  554. None,
  555. )
  556. msg_type = "smart_shooter_enable_preview_status"
  557. print("传入得msg_type====>>>", msg_type)
  558. temp_A_point = camera_configs.get(PointName, None)
  559. CameraKey = temp_A_point.get("CameraKey", None) if temp_A_point else None
  560. loop.create_task(
  561. smart_shooter.EnableCameraPreview(
  562. enable_status=value,
  563. msg_type=msg_type,
  564. CameraKey=CameraKey,
  565. ),
  566. name=msg_type,
  567. )
  568. case "smart_shooter_auto_focus":
  569. """
  570. 启动相机或关闭实时预览
  571. """
  572. if data is None:
  573. PointName = "A"
  574. else:
  575. PointName = data.get("point_name", "A")
  576. camera_configs = settings.getSysConfigs(
  577. "camera_configs",
  578. "iso_config",
  579. None,
  580. )
  581. msg_type = "smart_shooter_auto_focus"
  582. temp_A_point = camera_configs.get(PointName, None)
  583. CameraKey = temp_A_point.get("CameraKey", None) if temp_A_point else None
  584. status, msg = await smart_shooter.CameraAutofocus(
  585. CameraKey=CameraKey,
  586. )
  587. if not status:
  588. data = manager.jsonMessage(
  589. code=1,
  590. msg=msg,
  591. msg_type=msg_type,
  592. )
  593. await manager.send_personal_message(data, websocket)
  594. case "smart_shooter_get_camera_property":
  595. """
  596. 启动相机或关闭实时预览
  597. """
  598. if data is None:
  599. PointName = "A"
  600. else:
  601. PointName = data.get("point_name", "A")
  602. camera_configs = settings.getSysConfigs(
  603. "camera_configs",
  604. "iso_config",
  605. None,
  606. )
  607. temp_A_point = camera_configs.get(PointName, None)
  608. CameraKey = temp_A_point.get("CameraKey", None) if temp_A_point else None
  609. msg_type = "smart_shooter_get_camera_property"
  610. print("CameraKey", CameraKey)
  611. code = 0
  612. status, info = await smart_shooter.GetCameraProperty(CameraKey=CameraKey)
  613. code = 1 if status == False else 0
  614. msg = info if status == False else "操作成功"
  615. data = info if status == True else {}
  616. data = manager.jsonMessage(
  617. code=code,
  618. msg=msg,
  619. msg_type=msg_type,
  620. data=data,
  621. )
  622. await manager.send_personal_message(data, websocket)
  623. case "smart_shooter_photo_take":
  624. """
  625. 获取相机信息,是否连接
  626. """
  627. if data is None:
  628. PointName = "A"
  629. else:
  630. PointName = data.get("point_name", "A")
  631. camera_configs = settings.getSysConfigs(
  632. "camera_configs",
  633. "iso_config",
  634. None,
  635. )
  636. temp_A_point = camera_configs.get(PointName, None)
  637. CameraKey = temp_A_point.get("CameraKey", None) if temp_A_point else None
  638. device_ctrl = DeviceControl(
  639. websocket_manager=manager, smart_shooter=smart_shooter
  640. )
  641. await device_ctrl.controlDevice("laser_position", 0)
  642. # 兼容主图测试
  643. id = data.get("id", 0)
  644. goods_art_no = data.get("goods_art_no", "")
  645. goods_art_no = goods_art_no.strip()
  646. if goods_art_no:
  647. try:
  648. limit_path = "{}/{}".format(settings.OUTPUT_DIR,
  649. time.strftime("%Y-%m-%d", time.localtime(time.time()))
  650. )
  651. move_folder_array = handlerFolderDelete(limit_path, [goods_art_no], False)
  652. except UnicornException as e:
  653. data = manager.jsonMessage(
  654. code=1,
  655. msg=e.msg,
  656. msg_type="smart_shooter_photo_take",
  657. )
  658. await manager.send_personal_message(data, websocket)
  659. return
  660. if not await device_ctrl.camera_check_mcu_move_is_stop(re_check=True):
  661. logger.warning("拍照前运动检测失败===>,等待0.5秒后再检测一次")
  662. await asyncio.sleep(0.5)
  663. if not await device_ctrl.camera_check_mcu_move_is_stop(re_check=True):
  664. logger.warning("拍照前运动检测二次失败===>,强制拍摄")
  665. await asyncio.sleep(0.5)
  666. is_af = True
  667. loop.create_task(
  668. smart_shooter.CameraShooter(
  669. msg_type="run_mcu",
  670. id=id,
  671. goods_art_no=goods_art_no,
  672. is_af=is_af,
  673. CameraKey=CameraKey,
  674. ),
  675. name="smart_shooter_photo_take",
  676. )
  677. await asyncio.sleep(2.5)
  678. await device_ctrl.controlDevice("laser_position", 1)
  679. case "digicam_take_picture":
  680. msg_type = "re_take_picture"
  681. id = data.get("id", 0)
  682. goods_art_no = data.get("goods_art_no", "")
  683. session = SqlQuery()
  684. photoRecord = CRUD(PhotoRecord)
  685. goods_art_record = photoRecord.read(session, conditions={"id": id, "delete_time": None})
  686. if goods_art_record == None:
  687. data = manager.jsonMessage(
  688. code=1,
  689. msg=f"记录不存在,请核实后重新操作~",
  690. msg_type=msg_type,
  691. )
  692. await manager.send_personal_message(data, websocket)
  693. return
  694. reset_data = {"image_path": None}
  695. photoRecord.update(session, id, **reset_data)
  696. device_ctrl = DeviceControl(websocket_manager=manager) #
  697. loop.create_task(
  698. device_ctrl.only_take_photo(
  699. goods_art_no=goods_art_no,
  700. image_index=goods_art_record.image_index,
  701. record_id=id,
  702. ),
  703. name="sendCommand",
  704. )
  705. session.close()
  706. case "segment_progress":
  707. msg_type = "segment_progress"
  708. obj = None
  709. token = data.get("token", "")
  710. settings.USER_TOKEN = token
  711. token = "Bearer " + token
  712. uuid = data.get("uuid", "")
  713. run_main = RunMain(obj, token, uuid)
  714. goods_art_no_arrays = data.get("goods_art_no", [])
  715. limit_path = "{}/{}".format(settings.OUTPUT_DIR,
  716. time.strftime("%Y-%m-%d", time.localtime(time.time()))
  717. )
  718. try:
  719. move_folder_array = handlerFolderDelete(limit_path, goods_art_no_arrays, True)
  720. except UnicornException as e:
  721. data = manager.jsonMessage(
  722. code=1,
  723. msg=e.msg,
  724. msg_type=msg_type,
  725. )
  726. await manager.send_personal_message(data, websocket)
  727. return
  728. # 该数组表示是否需要后面的移动文件夹操作,减少重复抠图,提升抠图时间和速度
  729. session = SqlQuery()
  730. for goods_art_no in goods_art_no_arrays:
  731. pr = CRUD(PhotoRecord)
  732. images = pr.read_all(session, conditions={"goods_art_no": goods_art_no, "delete_time": None})
  733. if not images:
  734. data = manager.jsonMessage(
  735. code=1,
  736. msg=f"商品货号【{goods_art_no}】在商品档案资料中不存在,请检查货号是否正确",
  737. msg_type=msg_type,
  738. )
  739. await manager.send_personal_message(data, websocket)
  740. return
  741. if move_folder_array.get(goods_art_no) == None:
  742. image_dir = "{}/data/".format(os.getcwd()).replace("\\", "/")
  743. check_path(image_dir)
  744. for idx, itemImg in enumerate(images):
  745. if itemImg.image_path == "" or itemImg.image_path == None:
  746. data = manager.jsonMessage(
  747. code=1,
  748. msg=f"货号【{goods_art_no}】存在没有拍摄完成的图片,请重拍或删除后重试",
  749. msg_type=msg_type,
  750. )
  751. await manager.send_personal_message(data, websocket)
  752. return
  753. # new_file_name = (
  754. # str(idx)+"_"+str(itemImg.goods_art_no) + "_" + str(idx) + ".jpg"
  755. # )
  756. # if not os.path.exists(
  757. # image_dir + "/" + os.path.basename(new_file_name)
  758. # ):
  759. # shutil.copy(itemImg.image_path, image_dir + new_file_name)
  760. dealImage = DealImage(image_dir)
  761. resFlag, path = dealImage.dealMoveImageV2(
  762. goods_art_no=goods_art_no,
  763. )
  764. if not resFlag:
  765. # path
  766. data = manager.jsonMessage(
  767. code=1,
  768. msg=f"抠图操作异常,请检查目录是否存在,或者权限不足",
  769. msg_type=msg_type,
  770. )
  771. await manager.send_personal_message(data, websocket)
  772. return
  773. session.close()
  774. # try:
  775. cutout_mode = settings.getSysConfigs("other_configs", "cutout_mode", "普通抠图")
  776. match cutout_mode:
  777. case "普通抠图":
  778. cutOutMode = "1"
  779. case "精细化抠图":
  780. cutOutMode = "2"
  781. case "旗舰AI抠图":
  782. cutOutMode = "3"
  783. case "旗舰AI抠图-精细":
  784. cutOutMode = "4"
  785. case "旗舰AI抠图-透明物品":
  786. cutOutMode = "5"
  787. case _:
  788. cutOutMode = "1"
  789. config_data = {
  790. "image_dir": limit_path,
  791. "image_order": (
  792. "俯视,侧视,后跟,鞋底,内里,组合,组合2,组合3,组合4,组合5"
  793. ),
  794. "goods_art_no": "",
  795. "goods_art_nos": goods_art_no_arrays,
  796. "is_check_number": False,
  797. "resize_image_view": "后跟",
  798. "cutout_mode": cutOutMode,
  799. "logo_path": "",
  800. "special_goods_art_no_folder_line": "",
  801. "is_use_excel": False, # 是否使用excel
  802. "excel_path": "", # excel路径
  803. "is_check_color_is_all": False,
  804. "cutout_is_pass": True,
  805. "assigned_page_dict": {},
  806. "detail_is_pass": True,
  807. "upload_is_pass": False,
  808. "upload_is_enable": settings.IS_UPLOAD_HLM, # 是否上传到惠利玛商品库,通过config.ini得is_upload开启
  809. "is_filter": False,
  810. "temp_class": {},
  811. "temp_name": "",
  812. "temp_name_list": [],
  813. "target_error_folder": f"{limit_path}/软件-生成详情错误",
  814. "success_handler": [],
  815. }
  816. loop.create_task(
  817. handlerCutOut(
  818. manager=manager,
  819. run_main=run_main,
  820. config_data=config_data,
  821. websocket=websocket,
  822. msg_type=msg_type,
  823. ),
  824. name="handlerCutOut",
  825. )
  826. case "get_dynamic_config":
  827. device_ctrl = DeviceControl(
  828. websocket_manager=manager, smart_shooter=smart_shooter
  829. )
  830. dynamic_configs = device_ctrl.get_dynamic_config()
  831. # print("dynamic_configs", dynamic_configs)
  832. data = manager.jsonMessage(
  833. code=0,
  834. msg="成功",
  835. msg_type="get_dynamic_config",
  836. data=dynamic_configs,
  837. )
  838. await manager.send_personal_message(data, websocket)
  839. case "one_key_down":
  840. device_ctrl = DeviceControl(
  841. websocket_manager=manager, smart_shooter=smart_shooter
  842. )
  843. device_ctrl.one_key_down()
  844. case "get_dynamic_config_signle":
  845. device_ctrl = DeviceControl(
  846. websocket_manager=manager, smart_shooter=smart_shooter
  847. )
  848. name = data.get("name")
  849. value = device_ctrl.get_dynamic_config_signle(name)
  850. # print("dynamic_configs", dynamic_configs)
  851. data = manager.jsonMessage(
  852. code=0,
  853. msg="成功",
  854. msg_type="get_dynamic_config_signle",
  855. data={"value": value},
  856. )
  857. await manager.send_personal_message(data, websocket)
  858. case "set_dynamic_config":
  859. # 设置动态参数
  860. device_ctrl = DeviceControl(
  861. websocket_manager=manager, smart_shooter=smart_shooter
  862. )
  863. readonly = data.get("readonly", False)
  864. if not readonly:
  865. dynamic_configs = device_ctrl.set_dynamic_config(data)
  866. else:
  867. dynamic_configs = False
  868. data = manager.jsonMessage(
  869. code=0,
  870. msg="成功",
  871. msg_type="set_dynamic_config",
  872. data={"status": dynamic_configs},
  873. )
  874. await manager.send_personal_message(data, websocket)
  875. case "get_device_info":
  876. device_ctrl = DeviceControl(
  877. websocket_manager=manager, smart_shooter=smart_shooter
  878. )
  879. device_ctrl.getDeviationInfo()
  880. await asyncio.sleep(0.1)
  881. device_ctrl.get_device_info()
  882. case "to_recheck_focal":
  883. device_ctrl = DeviceControl(
  884. websocket_manager=manager, smart_shooter=smart_shooter
  885. )
  886. device_ctrl.to_recheck_focal("camera_zoom_motor")
  887. case "oneclick_release":
  888. device_ctrl = DeviceControl(
  889. websocket_manager=manager, smart_shooter=smart_shooter
  890. )
  891. device_ctrl.set_stepper_disable("mcu", False)
  892. case "mcu_power_off":
  893. device_ctrl = DeviceControl(
  894. websocket_manager=manager, smart_shooter=smart_shooter
  895. )
  896. device_ctrl.one_key_turnoff("mcu", False)
  897. case "get_scale_data":
  898. '''获取安衡电子秤数据'''
  899. device_ctrl = DeviceControl(
  900. websocket_manager=manager, smart_shooter=smart_shooter
  901. )
  902. if device_ctrl.anheng_scale._running == False:
  903. data = manager.jsonMessage(
  904. code=1,
  905. msg=f"电子秤不存在,请核实后重新操作~",
  906. msg_type="anheng_scale_status",
  907. )
  908. await manager.send_personal_message(data, websocket)
  909. device_ctrl.anheng_scale.is_send_message = True
  910. case "delete_photo_record": # 重拍
  911. msg_type = "delete_photo_record"
  912. record_id = data.get("record_id")
  913. session = SqlQuery()
  914. photoRecord = CRUD(PhotoRecord)
  915. goods_art_record = photoRecord.read(session, conditions={"id": record_id, "delete_time": None})
  916. if goods_art_record == None:
  917. data = manager.jsonMessage(
  918. code=1,
  919. msg=f"记录不存在,请核实后重新操作~",
  920. msg_type=msg_type,
  921. )
  922. await manager.send_personal_message(data, websocket)
  923. return
  924. photoRecord.deleteConditions(session, conditions={"id": record_id, "delete_time": None})
  925. session.close()
  926. data = manager.jsonMessage(
  927. code=0,
  928. msg=f"记录删除成功",
  929. msg_type=msg_type,
  930. )
  931. await manager.send_personal_message(data, websocket)
  932. return
  933. case "get_one_data_set":
  934. onseData = OneDataSet()
  935. result = onseData.create_command_list()
  936. data = manager.jsonMessage(
  937. code=0,
  938. msg=f"获取测试命令",
  939. msg_type='get_one_data_set',
  940. data={"commands": json.loads(result)}
  941. )
  942. await manager.send_personal_message(data, websocket)
  943. case "send_get_one_data_set":
  944. command = data.get("command")
  945. onseData = OneDataSet()
  946. device_ctrl = DeviceControl(
  947. websocket_manager=manager, smart_shooter=smart_shooter
  948. )
  949. if not device_ctrl.is_running:
  950. data = manager.jsonMessage(
  951. code=-1,
  952. msg=f"设备未连接",
  953. msg_type="send_get_one_data_set",
  954. )
  955. await manager.send_personal_message(data, websocket)
  956. return
  957. onseData.mcu = device_ctrl
  958. onseData.deal_send_json_to_mcu(command)
  959. case _:
  960. data = manager.jsonMessage(code=1, msg="未知消息")
  961. await manager.send_personal_message(data, websocket)
  962. return