BlueToothMode.py 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456
  1. import asyncio
  2. import time
  3. from bleak import BleakScanner, BleakClient
  4. import threading
  5. from collections import deque
  6. from networkx import is_connected
  7. from utils.SingletonType import SingletonType
  8. from .RemoteControlV2 import RemoteControlV2
  9. from .BaseClass import BaseClass
  10. from sockets.connect_manager import ConnectionManager
  11. from mcu.capture.smart_shooter_class import SmartShooter
  12. class BlueToothMode(BaseClass, metaclass=SingletonType):
  13. instance = None
  14. init_flag = None
  15. def __init__(
  16. self, websocket_manager: ConnectionManager, smart_shooter: SmartShooter = None
  17. ):
  18. super().__init__(websocket_manager, smart_shooter)
  19. """此处设计为,如果已经存在实例时,不再执行初始化"""
  20. if self.init_flag:
  21. return
  22. else:
  23. self.init_flag = True
  24. self.msg_type = "blue_tooth"
  25. self.bluetooth_exit = False
  26. self.remote_control_v2 = RemoteControlV2(self, websocket_manager)
  27. # 用于存储找到的目标设备的地址
  28. self.target_device_address = None
  29. self._lock = threading.Lock()
  30. self.connect_state = False
  31. self.receive_data = b""
  32. self.devices = {}
  33. self.devices_name = {}
  34. self.last_value = None
  35. self.retry_num = 0
  36. self.last_error = ""
  37. def __new__(cls, *args, **kwargs):
  38. """如果当前没有实例时,调用父类__new__方法,生成示例,有则返回保存的内存地址。"""
  39. if not cls.instance:
  40. cls.instance = super().__new__(cls)
  41. return cls.instance
  42. def print_error(self, text, *args):
  43. if text != self.last_error:
  44. self.last_error = text
  45. print(text)
  46. async def scan_for_esp32(self):
  47. """扫描附近的BLE设备,并寻找ESP32"""
  48. # print("打印连接状态", self.connect_state)
  49. if self.connect_state == True:
  50. return
  51. # self.sendSocketMessage(
  52. # code=0, msg="遥控设备V2 未连接", data=None, device_status=-1
  53. # )
  54. # print("Scanning for ESP32 devices...*****************")
  55. # print("打印连接状态2", self.connect_state)
  56. try:
  57. devices = await BleakScanner.discover()
  58. except BaseException as e:
  59. self.print_error("蓝牙疑似未打开,{}".format(e))
  60. # self.sendSocketMessage(
  61. # code=0, msg="蓝牙疑似未打开,{}".format(e), data=None, device_status=-1
  62. # )
  63. return
  64. for d in devices:
  65. # print(f"Device: {d.name} - Address: {d.address}")
  66. # 假设ESP32的广播名称包含"ESP32-S3"字符串
  67. if d.name:
  68. if "ESP32-S3" in d.name:
  69. if d.address not in self.devices:
  70. self.devices_name[d.name] = d.address
  71. self.devices[d.address] = {
  72. "name": d.name,
  73. "client": None,
  74. "send_queue": deque(maxlen=20),
  75. "recv_queue": deque(maxlen=20),
  76. "receive_data": b"",
  77. "connect_state": True,
  78. }
  79. self.print_error(
  80. f"Found device: {d.name} - Address: {d.address}"
  81. )
  82. asyncio.create_task(self.connect_and_listen(d.address))
  83. self.connect_state = True
  84. # 注册到遥控器等上位机
  85. def connect_device(self, address, name):
  86. print("注册到遥控器等上位机", address, name)
  87. if "remote" in name:
  88. self.remote_control_v2.to_connect_bluetooth(address, is_test=False)
  89. # 关闭连接
  90. def disconnect_device(self, address, name):
  91. print("关闭蓝牙连接", address, name)
  92. if "remote" in name:
  93. self.print_error("71 关闭蓝牙连接{}-{}".format(address, name))
  94. self.remote_control_v2.close_bluetooth_connect()
  95. self.connect_state = False
  96. self.receive_data = b""
  97. self.devices = {}
  98. self.devices_name = {}
  99. self.last_value = None
  100. self.retry_num = 0
  101. self.last_error = ""
  102. async def handle_disconnect(self, client):
  103. """处理断开连接事件"""
  104. self.print_error("Device was disconnected.")
  105. # 尝试重新连接
  106. while not client.is_connected:
  107. try:
  108. self.print_error("Attempting to reconnect...")
  109. await client.connect()
  110. except Exception as e:
  111. self.print_error(f"Failed to reconnect: {e}")
  112. await asyncio.sleep(5) # 等待一段时间再重试
  113. async def notification_handler(self, address, characteristic, data: bytearray):
  114. """处理接收到的通知数据"""
  115. with self._lock:
  116. #
  117. # if data == bytearray(b'UU\x01c\x9c'):
  118. # self.devices[address]['send_queue'].append(bytearray(b'UU\x01c\x9c'))
  119. # pass
  120. # else:
  121. # # print("60 data:", address, data)
  122. self.devices[address]["recv_queue"].append(data)
  123. self.devices[address]["connect_state"] = True
  124. async def write_characteristic(self, client, characteristic_uuid, data):
  125. """向指定特征写入数据"""
  126. try:
  127. await client.write_gatt_char(characteristic_uuid, data)
  128. except BaseException as e:
  129. self.print_error("write_characteristic error ", e)
  130. async def connect_and_listen(self, address):
  131. """连接到指定地址的ESP32设备并监听通知"""
  132. self.print_error("""连接到指定地址的ESP32设备并监听通知""")
  133. while True:
  134. # try:
  135. if len(self.devices) == 0:
  136. break
  137. async with BleakClient(address) as client:
  138. if not client.is_connected:
  139. self.print_error("Failed to connect to the device.")
  140. self.devices[address]["connect_state"] = False
  141. self.disconnect_device(
  142. address=address, name=self.devices[address]["name"]
  143. )
  144. continue
  145. if len(self.devices) == 0:
  146. break
  147. self.devices[address]["connect_state"] = True
  148. self.print_error(f"Connected to {address}")
  149. # 获取服务和特征(假设你已经知道要监听的特征UUID)
  150. services = await client.get_services()
  151. for service in services:
  152. for char in service.characteristics:
  153. if "notify" in char.properties:
  154. self.print_error(
  155. f"Subscribing to characteristic: {char.uuid}"
  156. )
  157. await client.start_notify(
  158. char,
  159. lambda char, data: asyncio.create_task(
  160. self.notification_handler(address, char, data)
  161. ),
  162. )
  163. # 进入一个简单的循环,保持连接
  164. self.print_error(
  165. "进入一个简单的循环 保持连接", self.devices[address]["name"]
  166. )
  167. self.connect_device(address=address, name=self.devices[address]["name"])
  168. self.retry_num += 1
  169. while True:
  170. if not client.is_connected:
  171. self.print_error(f"Device {address} disconnected unexpectedly.")
  172. with self._lock:
  173. self.disconnect_device(
  174. address=address, name=self.devices[address]["name"]
  175. )
  176. if len(self.devices) == 0:
  177. break
  178. self.devices[address]["connect_state"] = False
  179. break
  180. if len(self.devices) == 0:
  181. break
  182. if self.devices[address]["send_queue"]:
  183. with self._lock:
  184. send_data = self.devices[address]["send_queue"].popleft()
  185. # print("-----------> send_data:", self.change_hex_to_10_int(send_data))
  186. await self.write_characteristic(client, char.uuid, send_data)
  187. await asyncio.sleep(0.01)
  188. await asyncio.sleep(0.02)
  189. # except Exception as e:
  190. # with self._lock:
  191. # self.disconnect_device(
  192. # address=address, name=self.devices[address]["name"]
  193. # )
  194. # self.devices[address]["connect_state"] = False
  195. # print(f"Error during connection or listening: {e}")
  196. # await asyncio.sleep(2) # 发生错误时等待一段时间再重试
  197. async def main_func(self):
  198. """主函数"""
  199. # address = "24:EC:4A:26:4B:BE"
  200. # _name = "ESP32-S3-remote"
  201. # self.devices[address] = {'name': _name,
  202. # 'client': None,
  203. # 'send_queue': [],
  204. # 'recv_queue': [],
  205. # "receive_data": b"",
  206. # "connect_state": True,
  207. # }
  208. # self.devices_name[_name] = address
  209. # asyncio.create_task(self.connect_and_listen(address))
  210. if self.connect_state == True:
  211. print("蓝牙已连接,不可重新连接")
  212. message = {
  213. "_type": "show_info",
  214. "plugins_mode": "remote_control",
  215. "data": "遥控设备V2 打开蓝牙成功",
  216. }
  217. self.sendSocketMessage(
  218. code=0, msg="遥控设备V2 打开蓝牙成功", data=message, device_status=2
  219. )
  220. return
  221. await self.scan_for_esp32()
  222. # 定期重新扫描以发现新设备
  223. while True:
  224. print("正在扫描设备...")
  225. if self.bluetooth_exit:
  226. break
  227. if self.devices:
  228. await asyncio.sleep(20)
  229. else:
  230. await asyncio.sleep(3)
  231. await self.scan_for_esp32()
  232. print("蓝牙断开连接,已释放")
  233. def run(self):
  234. self.print_error("开启蓝牙扫描")
  235. asyncio.run(self.main_func())
  236. def clearMyInstance(self):
  237. print("清除蓝牙实例...")
  238. SingletonType.clear_instance()
  239. def write_cmd(self, address, data: list):
  240. buf = []
  241. buf.extend([0x55, 0x55, (0xFF & len(data))])
  242. buf.extend(data)
  243. buf.extend([0xFF & ~sum(data)])
  244. self.send_data(address, bytes(buf))
  245. def send_data(self, address, byte_list: bytes):
  246. chunk_size = 20
  247. chunks = [
  248. byte_list[i : i + chunk_size] for i in range(0, len(byte_list), chunk_size)
  249. ]
  250. try:
  251. with self._lock:
  252. for chunk in chunks:
  253. self.devices[address]["send_queue"].append(chunk)
  254. except Exception as e:
  255. self.devices[address]["connect_state"] = False
  256. self.print_error(f"Error sending notification: {address},{e}")
  257. def change_hex_to_int(self, _bytearray):
  258. return " ".join([hex(x)[2:].zfill(2) for x in _bytearray])
  259. def change_hex_to_10_int(self, _bytearray):
  260. return " ".join([str(int(x)) for x in _bytearray])
  261. def read_cmd(self, time_out=10):
  262. data_list = []
  263. for device_name in self.devices_name:
  264. address = self.devices_name[device_name]
  265. # print(self.devices[address]['connect_state'])
  266. while self.devices[address]["recv_queue"]:
  267. receive_data = self.read_cmd_one(address)
  268. if receive_data:
  269. data_list.append(
  270. {
  271. "device_name": device_name,
  272. "address": address,
  273. "receive_data": receive_data,
  274. }
  275. )
  276. return data_list
  277. def read_cmd_one(self, address):
  278. # 获取所有缓冲区的字节
  279. if not self.devices[address]["connect_state"]:
  280. return
  281. # print("读取数据....")
  282. while 1:
  283. receive_data = self.devices[address]["receive_data"]
  284. # print("166 receive_data", receive_data)
  285. if self.devices[address]["recv_queue"]:
  286. with self._lock:
  287. read_d = self.devices[address]["recv_queue"].popleft()
  288. # print("170 read_d", read_d)
  289. receive_data += read_d
  290. self.devices[address]["receive_data"] = receive_data
  291. if not receive_data:
  292. return None
  293. if len(receive_data) < 4:
  294. break
  295. # print("--------receive_data",self.change_hex_to_10_int(receive_data))
  296. if receive_data[0] == 0x55 and receive_data[1] == 0x55:
  297. data_len = receive_data[2]
  298. if len(receive_data) < data_len + 4:
  299. # n += 1
  300. # if n > time_out:
  301. # time.sleep(0.001)
  302. # return False
  303. # continue
  304. return
  305. _data = receive_data[3 : data_len + 4]
  306. # 更新缓存区
  307. with self._lock:
  308. self.devices[address]["receive_data"] = receive_data[data_len + 4 :]
  309. receive_data = receive_data[data_len + 4 :]
  310. # 校验数据
  311. if 0xFF & ~sum(_data[:-1]) == _data[-1]:
  312. return _data[:-1]
  313. else:
  314. print("数据异常,丢弃")
  315. return False
  316. else:
  317. # 起始位不是 55 55 进行移除
  318. while receive_data:
  319. if len(receive_data) == 1:
  320. if receive_data[0] == 0x55:
  321. break
  322. else:
  323. with self._lock:
  324. self.devices[address]["receive_data"] = b""
  325. receive_data = b""
  326. else:
  327. if receive_data[0] == 0x55 and receive_data[1] == 0x55:
  328. break
  329. else:
  330. with self._lock:
  331. self.devices[address]["receive_data"] = receive_data[1:]
  332. receive_data = receive_data[1:]
  333. def analysis_received_data(self):
  334. receive_data = self.read_cmd(time_out=5)
  335. if not receive_data:
  336. return
  337. else:
  338. # print("receive_data:", receive_data)
  339. # print("read2 receive_data {}".format(self.change_hex_to_int(receive_data)))
  340. pass
  341. for data in receive_data:
  342. address = data["address"]
  343. rec_data = data["receive_data"]
  344. # print("read address {}".format(address))
  345. # print("read receive_data {}".format(self.change_hex_to_int(rec_data)))
  346. # 数据 结构 command,按命令解析
  347. if rec_data[0] == 1:
  348. # 扫码数据
  349. bar_code = rec_data[1:].decode()
  350. bar_code = bar_code.replace("\r", "")
  351. bar_code = bar_code.replace("\n", "")
  352. print("bar_code:", bar_code)
  353. return
  354. if rec_data[0] == 2:
  355. print("read receive_data {}".format(self.change_hex_to_int(rec_data)))
  356. return
  357. if rec_data[0] == 90:
  358. print(
  359. "read receive_data-90 {}".format(self.change_hex_to_int(rec_data))
  360. )
  361. return
  362. if rec_data[0] == 99:
  363. blue_mode.write_cmd(address, [99])
  364. # print("发送心跳包")
  365. return
  366. if rec_data[0] == 111:
  367. print(
  368. "{} receive_data-111 {}".format(
  369. self.retry_num, self.change_hex_to_10_int(rec_data)
  370. )
  371. )
  372. value = (
  373. rec_data[1] << 24
  374. | rec_data[2] << 16
  375. | rec_data[3] << 8
  376. | rec_data[4]
  377. )
  378. if self.last_value is None:
  379. self.last_value = value
  380. else:
  381. self.last_value += 1
  382. if self.last_value == value:
  383. flag = True
  384. else:
  385. flag = False
  386. print(
  387. "{} value:{},last_value;{},flag:{}\n".format(
  388. self.retry_num, value, self.last_value, flag
  389. )
  390. )
  391. if __name__ == "__main__":
  392. blue_mode = BlueToothMode(None)
  393. threading.Thread(target=blue_mode.run, args=()).start()
  394. print("=" * 50)
  395. n = 0
  396. time.sleep(1)
  397. k = 0
  398. last_t = time.time()
  399. while 1:
  400. time.sleep(0.001)
  401. s = time.time()
  402. address = "24:EC:4A:26:4B:BE"
  403. blue_mode.analysis_received_data()
  404. n += 1
  405. if n == 500:
  406. print(s - last_t)
  407. for i in range(3):
  408. k += 1
  409. data = [
  410. 111,
  411. 0xFF & k >> 24,
  412. 0xFF & k >> 16,
  413. 0xFF & k >> 8,
  414. 0xFF & k,
  415. ]
  416. data.extend([x for x in range(100, 130)])
  417. blue_mode.write_cmd(address=address, data=data)
  418. print("send_value:{}".format(k))
  419. data = [90]
  420. blue_mode.write_cmd(address=address, data=data)
  421. n = 0
  422. last_t = s