smart_shooter_class.py 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567
  1. import json
  2. import datetime
  3. import random
  4. import zmq
  5. import asyncio
  6. from PIL import Image
  7. from io import BytesIO
  8. import base64,threading
  9. import zmq, sys, time
  10. from utils.SingletonType import SingletonType
  11. import settings
  12. import logging
  13. from utils.common import message_queue
  14. logger = logging.getLogger(__name__)
  15. # 定义为单例模式,避免被重复实例化
  16. class SmartShooter(metaclass=SingletonType):
  17. SET_REQ = "tcp://127.0.0.1:54544"
  18. LISTEN_REQ = "tcp://127.0.0.1:54543"
  19. def __init__(self, websocket_manager):
  20. self.msg_type = "smart_shooter"
  21. self.websocket_manager = websocket_manager
  22. # 是否停止监听
  23. self.stop_listen = False
  24. # 相机连接状态
  25. self.connect_status = False
  26. # 实时预览状态
  27. self.perview_state = False
  28. self.callback_listen = None
  29. self.listen_init = None
  30. self.websocket = None
  31. # self.main_loop = None
  32. def __send_tcp_message(self, socket, msg):
  33. # await asyncio.sleep(0.01)
  34. socket.send_string(json.dumps(msg))
  35. rep = socket.recv()
  36. str_msg = rep.decode("utf-8")
  37. json_msg = json.loads(str_msg)
  38. return json_msg
  39. def __create_req(self, time_out=5) -> tuple[zmq.Socket, zmq.Context]:
  40. context = zmq.Context()
  41. req_socket = context.socket(zmq.REQ)
  42. # 设置发送超时为 5000 毫秒(5 秒)
  43. req_socket.setsockopt(zmq.RCVTIMEO, time_out * 1000)
  44. # 设置接收超时为 5000 毫秒(5 秒)
  45. req_socket.setsockopt(zmq.SNDTIMEO, time_out * 1000)
  46. req_socket.setsockopt(zmq.LINGER, 0) # 设置为 0 表示不等待未完成的操作
  47. req_socket.connect(self.SET_REQ)
  48. return req_socket, context
  49. def __create_listen(self) -> tuple[zmq.Socket, zmq.Context]:
  50. context = zmq.Context()
  51. listen_socket = context.socket(zmq.SUB)
  52. listen_socket.setsockopt(zmq.SUBSCRIBE, b"")
  53. # 设置发送超时为 5000 毫秒(5 秒)
  54. listen_socket.setsockopt(zmq.RCVTIMEO, 4000)
  55. # 设置接收超时为 5000 毫秒(5 秒)
  56. listen_socket.setsockopt(zmq.SNDTIMEO, 4000)
  57. listen_socket.setsockopt(zmq.LINGER, 0) # 设置为 0 表示不等待未完成的操作
  58. listen_socket.connect(self.LISTEN_REQ)
  59. return listen_socket, context
  60. async def GetCameraProperty(self, CameraKey=None):
  61. '''获取相机属性'''
  62. await asyncio.sleep(0.01)
  63. """
  64. 实时获取相机信息,是否连接、软件是否被打开
  65. """
  66. socket, context = self.__create_req(time_out=2)
  67. try:
  68. req = {}
  69. req["msg_type"] = "Request"
  70. req["msg_id"] = "GetCamera"
  71. req["msg_seq_num"] = 0
  72. req["CameraSelection"] = "All"
  73. if CameraKey is not None:
  74. req["CameraSelection"] = "Single"
  75. req["CameraKey"] = CameraKey
  76. json_msg = self.__send_tcp_message(socket, req)
  77. msg_result = json_msg.get("msg_result")
  78. if not msg_result:
  79. self.connect_status = False
  80. msg_send = "相机未连接或软件未打开"
  81. return False, msg_send
  82. cameraInfo = json_msg.get("CameraInfo")
  83. if cameraInfo == None or len(cameraInfo) == 0:
  84. self.connect_status = False
  85. msg_send = "相机未连接"
  86. return False, "相机未连接"
  87. # 链接的相机
  88. CameraStatus = False
  89. CameraIndex =-1
  90. for cam_idx,item in enumerate(cameraInfo):
  91. CameraStatus = item.get("CameraStatus") in ["Ready", "Busy"]
  92. if CameraStatus == True:
  93. CameraIndex = cam_idx
  94. break
  95. # CameraStatus = connect_camera.get("CameraStatus")
  96. if not CameraStatus:
  97. self.connect_status = False
  98. msg_send = "相机未连接"
  99. return False, msg_send
  100. self.connect_status = True
  101. msg_send = "相机已连接"
  102. return True, cameraInfo[CameraIndex].get("CameraPropertyInfo")
  103. except zmq.Again:
  104. msg_send = "相机未连接或软件未打开"
  105. return False, msg_send
  106. except Exception as e:
  107. self.connect_status = False
  108. socket.close()
  109. context.term()
  110. msg_send = "相机未连接或软件未打开"
  111. return False, msg_send
  112. async def GetCameraInfo(self, is_send=True, msg_type="",CameraKey=None):
  113. await asyncio.sleep(0.001)
  114. self.msg_type = msg_type
  115. """
  116. 实时获取相机信息,是否连接、软件是否被打开
  117. """
  118. socket, context = self.__create_req(time_out=2)
  119. try:
  120. req = {}
  121. req["msg_type"] = "Request"
  122. req["msg_id"] = "GetCamera"
  123. req["msg_seq_num"] = 0
  124. req["CameraSelection"] = "All"
  125. if CameraKey is not None:
  126. req["CameraSelection"] = "Single"
  127. req["CameraKey"] = CameraKey
  128. json_msg = self.__send_tcp_message(socket, req)
  129. msg_result = json_msg.get("msg_result")
  130. if not msg_result:
  131. self.connect_status = False
  132. msg_send = "相机未连接或软件未打开"
  133. if is_send:
  134. message = {
  135. "code": 1,
  136. "msg": msg_send,
  137. "data": msg_result,
  138. "msg_type": self.msg_type,
  139. "device_status": -1,
  140. }
  141. await self.websocket_manager.send_personal_message(
  142. message, self.websocket
  143. )
  144. return False, msg_send
  145. cameraInfo = json_msg.get("CameraInfo")
  146. if cameraInfo == None or len(cameraInfo) == 0:
  147. self.connect_status = False
  148. msg_send = "相机未连接"
  149. if is_send:
  150. message = {
  151. "code": 1,
  152. "msg": msg_send,
  153. "data": msg_result,
  154. "msg_type": self.msg_type,
  155. "device_status": -1,
  156. }
  157. await self.websocket_manager.send_personal_message(
  158. message, self.websocket
  159. )
  160. return False, "相机未连接"
  161. # 链接的相机
  162. CameraStatus = any(
  163. item.get("CameraStatus") in ["Ready", "Busy"] for item in cameraInfo
  164. )
  165. if not CameraStatus:
  166. self.connect_status = False
  167. msg_send = "相机未连接"
  168. if is_send:
  169. message = {
  170. "code": 1,
  171. "msg": msg_send,
  172. "data": msg_result,
  173. "msg_type": self.msg_type,
  174. "device_status": -1,
  175. }
  176. await self.websocket_manager.send_personal_message(
  177. message, self.websocket
  178. )
  179. return False, msg_send
  180. self.connect_status = True
  181. msg_send = "相机已连接"
  182. if is_send:
  183. message = {
  184. "code": 0,
  185. "msg": msg_send,
  186. "data": msg_result,
  187. "msg_type": self.msg_type,
  188. "device_status": 2,
  189. }
  190. await self.websocket_manager.send_personal_message(
  191. message, self.websocket
  192. )
  193. # print("相机已连接状态信息---->", cameraInfo)
  194. return True, "相机已连接"
  195. except zmq.Again:
  196. print("获取相机信息超时,继续监听...")
  197. msg_send = "相机未连接或软件未打开"
  198. if is_send:
  199. message = {
  200. "code": 1,
  201. "msg": msg_send,
  202. "data": None,
  203. "msg_type": self.msg_type,
  204. "device_status": 2,
  205. }
  206. await self.websocket_manager.send_personal_message(
  207. message, self.websocket
  208. )
  209. return False, msg_send
  210. except Exception as e:
  211. print("拍照异常", e)
  212. self.connect_status = False
  213. socket.close()
  214. context.term()
  215. msg_send = "相机未连接或软件未打开"
  216. if is_send:
  217. message = {
  218. "code": 1,
  219. "msg": msg_send,
  220. "data": None,
  221. "msg_type": self.msg_type,
  222. "device_status": -1,
  223. }
  224. await self.websocket_manager.send_personal_message(
  225. message, self.websocket
  226. )
  227. return False, msg_send
  228. async def SetCameraFPS(self, fps=5,CameraKey=None):
  229. """
  230. 激活相机预览
  231. """
  232. camera_states, _ = await self.GetCameraInfo(is_send=False,CameraKey=CameraKey)
  233. if not camera_states:
  234. return False, "请先连接相机"
  235. socket, context = self.__create_req()
  236. try:
  237. req = {}
  238. req["msg_type"] = "Request"
  239. req["msg_id"] = "LiveviewFPS"
  240. req["msg_seq_num"] = 0
  241. req["CameraSelection"] = "All"
  242. if CameraKey is not None:
  243. req["CameraSelection"] = "Single"
  244. req["CameraKey"] = CameraKey
  245. req["CameraLiveviewFPS"] = fps
  246. json_msg = self.__send_tcp_message(socket, req)
  247. msg_result = json_msg.get("msg_result")
  248. if not msg_result:
  249. self.perview_state = False
  250. return False, "设置失败"
  251. return True, "设置失败"
  252. except:
  253. self.perview_state = False
  254. socket.close()
  255. context.term()
  256. return False, "相机未连接或软件未打开"
  257. async def setCameraProperty(self, property="ISO", value=0, CameraKey=None):
  258. # SetProperty
  259. camera_states, _ = await self.GetCameraInfo(is_send=False, CameraKey=CameraKey)
  260. if not camera_states:
  261. return False, "请先连接相机"
  262. socket, context = self.__create_req()
  263. try:
  264. req = {}
  265. req["msg_type"] = "Request"
  266. req["msg_id"] = "SetProperty"
  267. req["msg_seq_num"] = 0
  268. req["CameraSelection"] = "All"
  269. if CameraKey is not None:
  270. req["CameraSelection"] = "Single"
  271. req["CameraKey"] = CameraKey
  272. req["CameraPropertyType"] = str(property)
  273. req["CameraPropertyValue"] = str(value)
  274. json_msg = self.__send_tcp_message(socket, req)
  275. msg_result = json_msg.get("msg_result")
  276. if not msg_result:
  277. return False, f"{property}设置失败"
  278. return True, f"{property}设置成功"
  279. except zmq.Again:
  280. print(f"设置{property}超时,继续监听...")
  281. except:
  282. self.perview_state = False
  283. socket.close()
  284. context.term()
  285. msg_send = "相机未连接或软件未打开"
  286. return False, msg_send
  287. async def getConfigIso(self):
  288. """获取ISO配置信息"""
  289. camera_configs = settings.getSysConfigs(
  290. "camera_configs",
  291. "iso_config",
  292. {"low": 100, "high": 6400, "mode": "un_auto"},
  293. )
  294. low_iso = camera_configs.get("low", 100)
  295. high_iso = camera_configs.get("high", 6400)
  296. return low_iso, high_iso
  297. async def EnableCameraPreview(self, enable_status=True, msg_type="",CameraKey=None):
  298. self.msg_type = msg_type
  299. await self.SetCameraFPS(5,CameraKey=CameraKey)
  300. """
  301. 激活相机预览
  302. """
  303. camera_states, _ = await self.GetCameraInfo(is_send=False,CameraKey=CameraKey)
  304. if not camera_states:
  305. return False, "请先连接相机"
  306. try:
  307. low_iso,high_iso = await self.getConfigIso()
  308. print("LOW_ISO", low_iso)
  309. print("HIGH_ISO", high_iso)
  310. # 等于auto就不设置
  311. if enable_status == True:
  312. if str(high_iso).lower() != "auto":
  313. await self.setCameraProperty(property="ISO", value=str(high_iso), CameraKey=CameraKey)
  314. else:
  315. print("high_iso 等于auto就不设置")
  316. if enable_status == False:
  317. if str(low_iso).lower() != "auto":
  318. await self.setCameraProperty(property="ISO", value=str(low_iso), CameraKey=CameraKey)
  319. else:
  320. print("low_iso 等于auto就不设置")
  321. socket, context = self.__create_req()
  322. req = {}
  323. req["msg_type"] = "Request"
  324. req["msg_id"] = "EnableLiveview"
  325. req["msg_seq_num"] = 0
  326. req["CameraSelection"] = "All"
  327. if CameraKey is not None:
  328. req["CameraSelection"] = "Single"
  329. req["CameraKey"] = CameraKey
  330. req["Enable"] = enable_status
  331. json_msg = self.__send_tcp_message(socket, req)
  332. msg_result = json_msg.get("msg_result")
  333. if not msg_result:
  334. self.perview_state = False
  335. msg_send = "预览启用失败"
  336. # self.sendSocketMessage(
  337. # code=0,
  338. # msg=msg_send,
  339. # device_status=2,
  340. # )
  341. return False, "预览启用失败"
  342. msg_send = "预览启用成功" if enable_status else "预览关闭成功"
  343. message = {
  344. "code": 0,
  345. "msg": msg_send,
  346. "data": None,
  347. "msg_type": self.msg_type,
  348. "device_status": 2,
  349. }
  350. await self.websocket_manager.send_personal_message(message, self.websocket)
  351. return True, "预览启用成功" if enable_status else "预览关闭成功"
  352. except zmq.Again:
  353. print("启动预览超时,继续监听...")
  354. except:
  355. self.perview_state = False
  356. socket.close()
  357. context.term()
  358. msg_send = "相机未连接或软件未打开"
  359. message = {
  360. "code": 1,
  361. "msg": msg_send,
  362. "data": None,
  363. "msg_type": self.msg_type,
  364. "device_status": -1,
  365. }
  366. await self.websocket_manager.send_personal_message(message, self.websocket)
  367. return False, "相机未连接或软件未打开"
  368. async def CameraAutofocus(self, CameraKey=None):
  369. """
  370. 相机自动对焦
  371. """
  372. camera_states, _ = await self.GetCameraInfo(is_send=False, CameraKey=CameraKey)
  373. print("CameraAutofocus 执行对焦")
  374. if not camera_states:
  375. return False, "请先连接相机"
  376. socket, context = self.__create_req()
  377. try:
  378. req = {}
  379. req["msg_type"] = "Request"
  380. req["msg_id"] = "Autofocus"
  381. req["msg_seq_num"] = 0
  382. req["CameraSelection"] = "All"
  383. if CameraKey is not None:
  384. req["CameraSelection"] = "Single"
  385. req["CameraKey"] = CameraKey
  386. start_time = time.time() # 添加对焦开始时间记录
  387. json_msg = self.__send_tcp_message(socket, req)
  388. end_time = time.time() # 添加对焦结束时间记录
  389. logger.info(f"对焦通信耗时: {end_time - start_time:.4f} 秒")
  390. print("json_msg", json_msg)
  391. msg_result = json_msg.get("msg_result")
  392. if not msg_result:
  393. return False, "对焦失败"
  394. return True, "对焦成功"
  395. except zmq.Again:
  396. print("对焦超时,继续监听...")
  397. except:
  398. socket.close()
  399. context.term()
  400. return False, "相机未连接或软件未打开"
  401. async def CameraShooter(self, msg_type="", goods_art_no="", id=0, is_af=False,delay=0.5, CameraKey=None):
  402. # 这里延迟一秒钟 等待前置命令完成
  403. await asyncio.sleep(delay)
  404. # 对焦混用
  405. if is_af:
  406. await self.EnableCameraPreview(enable_status=True, msg_type=msg_type, CameraKey=CameraKey)
  407. start_time = time.time()
  408. await self.CameraAutofocus(CameraKey=CameraKey)
  409. end_time = time.time()
  410. elapsed_time = end_time - start_time
  411. logger.info(f"自动对焦耗时 {elapsed_time:.4f} 秒")
  412. await self.EnableCameraPreview(enable_status=False, msg_type=msg_type, CameraKey=CameraKey)
  413. self.msg_type = msg_type
  414. print("camera_states", msg_type)
  415. """
  416. 执行拍照
  417. """
  418. camera_states, _ = await self.GetCameraInfo(is_send=True, CameraKey=CameraKey)
  419. print("camera_states CameraShooter", camera_states)
  420. if not camera_states:
  421. return False, "请先连接相机"
  422. socket, context = self.__create_req()
  423. try:
  424. low_iso,high_iso = await self.getConfigIso()
  425. print("LOW_ISO", low_iso)
  426. print("HIGH_ISO", high_iso)
  427. if str(low_iso).lower() != "auto":
  428. await self.setCameraProperty(property="ISO", value=str(low_iso), CameraKey=CameraKey)
  429. else:
  430. print("low_iso 等于auto就不设置")
  431. req = {}
  432. req["msg_type"] = "Request"
  433. req["msg_id"] = "Shoot"
  434. req["msg_seq_num"] = 1
  435. req["CameraSelection"] = "All"
  436. if CameraKey is not None:
  437. req["CameraSelection"] = "Single"
  438. req["CameraKey"] = CameraKey
  439. if goods_art_no != "" and id != 0:
  440. # 此处用逗号分割,货号和id,需要在监听部分进行切割保存处理,如果使用下划线或者减号,可能货号中存在对应符号
  441. req["PhotoOrigin"] = f"{goods_art_no},{id}"
  442. else:
  443. req["PhotoOrigin"] = ""
  444. json_msg = self.__send_tcp_message(socket, req)
  445. print("CameraShooter", json_msg)
  446. msg_result = json_msg.get("msg_result")
  447. if not msg_result:
  448. msg_send = "拍照失败"
  449. message = {
  450. "code": 1,
  451. "msg": msg_send,
  452. "data": None,
  453. "msg_type": self.msg_type,
  454. "device_status": -1,
  455. }
  456. await self.websocket_manager.send_personal_message(
  457. message, self.websocket
  458. )
  459. return False, msg_send
  460. msg_send = "拍照成功"
  461. message = {
  462. "code": 0,
  463. "msg": msg_send,
  464. "data": None,
  465. "msg_type": self.msg_type,
  466. "device_status": 2,
  467. }
  468. await self.websocket_manager.send_personal_message(message, self.websocket)
  469. return True, "拍照成功"
  470. except zmq.Again:
  471. msg_send = "相机未连接或软件未打开"
  472. message = {
  473. "code": 1,
  474. "msg": msg_send,
  475. "data": {goods_art_no: goods_art_no, "id": id},
  476. "msg_type": self.msg_type,
  477. "device_status": -1,
  478. }
  479. await self.websocket_manager.send_personal_message(message, self.websocket)
  480. return True, "拍照失败"
  481. except:
  482. socket.close()
  483. context.term()
  484. msg_send = "相机未连接或软件未打开"
  485. message = {
  486. "code": 1,
  487. "msg": msg_send,
  488. "data": None,
  489. "msg_type": self.msg_type,
  490. "device_status": -1,
  491. }
  492. await self.websocket_manager.send_personal_message(message, self.websocket)
  493. return False, msg_send
  494. async def asyncMessageListen(self):
  495. if self.websocket.client_state.name != "CONNECTED":
  496. print("WebSocket连接已断开,停止发送消息")
  497. return
  498. try:
  499. # 使用非阻塞方式检查队列中是否有项目
  500. if not message_queue.empty():
  501. message = message_queue.get_nowait()
  502. print("发送消息中。。。。。", message)
  503. await self.websocket_manager.send_personal_message(
  504. message, self.websocket
  505. )
  506. message_queue.task_done()
  507. except Exception as e:
  508. # 处理可能的异常,如队列为空等
  509. pass
  510. def connect_listen(self):
  511. print("smart shooter connect_listen START")
  512. if self.connect_status == True or self.listen_init == True:
  513. return True
  514. sub_socket, context = self.__create_listen()
  515. print("构建监听", self.connect_status)
  516. # 不再需要 self.listen_loop,我们只使用主循环
  517. try:
  518. while True:
  519. self.listen_init = True
  520. if self.stop_listen:
  521. break
  522. # 1. 阻塞接收 ZMQ 消息 (这是唯一的阻塞点,但在子线程,所以没问题)
  523. try:
  524. raw = sub_socket.recv() # 这里会阻塞直到有消息或超时
  525. str_msg = raw.decode("utf-8")
  526. json_msg = json.loads(str_msg)
  527. if json_msg.get("msg_id") == "NetworkPing":
  528. continue
  529. # 2. 将回调提交到【主事件循环】
  530. if hasattr(self, 'main_loop') and self.main_loop:
  531. # 非阻塞提交,立即返回
  532. asyncio.run_coroutine_threadsafe(self.callback_listen(json_msg), self.main_loop)
  533. else:
  534. print("Error: main_loop not set in SmartShooter")
  535. except zmq.Again:
  536. # 超时,继续循环
  537. continue
  538. except Exception as e:
  539. print(f"ZMQ Error: {e}")
  540. break
  541. finally:
  542. self.listen_init = False
  543. self.connect_status = False
  544. sub_socket.close()
  545. context.term()
  546. print("smart shooter连接断开")