main.py 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901
  1. # -*- coding: gb2312 -*-
  2. import time
  3. from os import path, makedirs
  4. import sys
  5. from datetime import datetime
  6. from PyQt5.QtWidgets import QApplication, QMainWindow
  7. from PyQt5.QtCore import pyqtSignal
  8. from PyQt5.QtCore import QUrl
  9. from PyQt5.QtCore import QTimer
  10. from PyQt5.QtWebEngineWidgets import QWebEngineView
  11. from PyQt5.QtGui import QTextCursor
  12. from mainwindow import *
  13. import logging
  14. from platform import node
  15. from paho.mqtt import client as mqtt_client
  16. from json import loads as json_loads, dumps as json_dumps, JSONDecodeError
  17. from threading import Thread
  18. from requests import get as requests_get
  19. # pyinstaller.exe -D -n LogTT_tools_V0.0.0.2 main.py
  20. # pyinstaller.exe -w -F -n LogTT_tools_V0.0.0.3 main.py
  21. client_id = "LogTT_tool_" + node()
  22. g_client = mqtt_client.Client(client_id)
  23. mqtt_broker = 'test-mqtt.cpyypt.cn'
  24. mqtt_port = 9000
  25. mqtt_user = 'admin'
  26. mqtt_pwd = 'houjianwei'
  27. mqtt_keepalive = 5
  28. mqtt_timer_time_out = 3*1000
  29. # mqtt_subtopic = [("cpyypt/up/9002/#", 0), ("cpyypt/down/9002/broadcast", 0)]
  30. mqtt_subtopic = [("cpyypt/up/9002/#", 0)]
  31. mqtt_pubtopic = "cpyypt/down/9002/0000000001"
  32. version = "0.0.0.3"
  33. version_w_ascii = 1
  34. version_w_hex = 1
  35. error_msg = ""
  36. info_msg = ""
  37. start_ttl = "TTL_U="
  38. start_rs232 = "RS232_U="
  39. start_rs485 = "RS485_U="
  40. start_fixed = "FIXED_INFO="
  41. start_heart = "HEART_MSG="
  42. start_pt = "PT_CMD="
  43. data_buf = {}
  44. LOG_FORMAT = "%(asctime)s - %(levelname)s - %(message)s"
  45. logging.basicConfig(filename='formater.log', level=logging.DEBUG, format=LOG_FORMAT)
  46. logging.debug("\n\n................")
  47. def get_log_file_name_ascii(sn):
  48. # global
  49. log_file_name = f"./log/LogTT_{sn}_ascii_" + datetime.now().strftime('%Y-%m-%d') + ".log"
  50. return log_file_name
  51. def get_log_file_name_hex(sn):
  52. # global
  53. log_file_name = f"./log/LogTT_{sn}_hex_" + datetime.now().strftime('%Y-%m-%d') + ".log"
  54. return log_file_name
  55. def is_valid_json(json_str):
  56. try:
  57. json_loads(json_str)
  58. return True
  59. except JSONDecodeError:
  60. return False
  61. class MyWindow(QMainWindow, Ui_MainWindow):
  62. map_refresh_signal = pyqtSignal(int, float, float)
  63. rx_data_signal = pyqtSignal(str, str, str)
  64. mqtt_connect_state_signal = pyqtSignal(str)
  65. log_display_update_signal = pyqtSignal(str)
  66. def __init__(self, parent=None):
  67. print("__init__")
  68. logging.info("__init__")
  69. super(MyWindow, self).__init__(parent)
  70. self.setupUi(self)
  71. self.initUI()
  72. self.set_svr_env = "test"
  73. self.sn_current = 0
  74. self.mqtt_connect_state = "未连接"
  75. browser = QWebEngineView()
  76. self.browser = browser
  77. self.horizontalLayout.layout().addWidget(self.browser)
  78. self.horizontalLayoutWidget.setGeometry(QtCore.QRect(0, 0, 1024, 600))
  79. # self.pushButton_set_subscribe.clicked.connect(lambda: {self.mqtt_subscribe(g_client), Thread(target=g_client.loop_forever, daemon=True).start()})
  80. self.pushButton_set_subscribe.clicked.connect(lambda: {self.mqtt_subscribe(g_client)})
  81. self.mqtt_connect(g_client)
  82. self.mqtt_subscribe(g_client)
  83. self.mqtt_disconnect(g_client)
  84. self.mqtt_thread = Thread(target=g_client.loop_forever, daemon=True)
  85. self.mqtt_thread.start()
  86. if not path.exists("log"):
  87. makedirs("log")
  88. self.textEdit_log_0rx_display.setText("")
  89. self.textEdit_log_0rx_display.moveCursor(QTextCursor.End)
  90. self.textEdit_log_0rx_display.document().setMaximumBlockCount(10000)
  91. self.display_clear()
  92. def initUI(self):
  93. print("initUI")
  94. logging.info("initUI")
  95. self.setWindowTitle("LogTT_tools:test-" + version + ",未连接")
  96. # self.tabWidget.setCurrentIndex(self.tabWidget.indexOf(self.tab_lsb))
  97. # self.comboBox_log_sn.currentIndexChanged.connect(self.comboBox_log_sn_change)
  98. self.comboBox_log_sn.activated.connect(self.display_update)
  99. self.comboBox_log_sn.activated.connect(self.sn_update_something)
  100. self.pushButton_log_rx_clr.clicked.connect(self.log_rx_clr)
  101. self.map_refresh_signal.connect(self.map_refresh)
  102. self.rx_data_signal.connect(self.parse_data)
  103. self.mqtt_connect_state_signal.connect(self.mainWindow_title_update)
  104. self.log_display_update_signal.connect(self.log_display_update)
  105. self.pushButton_set_create.clicked.connect(self.set_create)
  106. self.pushButton_set_send.clicked.connect(self.set_send)
  107. self.pushButton_set_create_send.clicked.connect(self.set_create_send)
  108. # self.pushButton_set_send.clicked.connect(lambda: {self.publish(g_client)})
  109. self.pushButton_set_connect.clicked.connect(lambda: {self.connect(g_client)})
  110. self.comboBox_set_svr.activated.connect(self.set_svr)
  111. self.checkBox_set_io_up_enable.clicked.connect(self.set_io_up_able)
  112. self.checkBox_set_io_up_disable.clicked.connect(self.set_io_up_disable)
  113. self.checkBox_set_io_down_enable.clicked.connect(self.set_io_down_able)
  114. self.checkBox_set_io_down_disable.clicked.connect(self.set_io_down_disable)
  115. self.checkBox_set_io_parameter.clicked.connect(self.set_io_parameter)
  116. self.checkBox_set_io_cfg.clicked.connect(self.set_io_cfg)
  117. self.checkBox_set_default_tx_sn.clicked.connect(self.set_default_tx_sn)
  118. self.lineEdit_tx_sn.textChanged.connect(self.set_tx_sn_change)
  119. self.pushButton_lsb_refresh.clicked.connect(self.lsb_get_fixed_info)
  120. self.pushButton_log_send.clicked.connect(self.log_send)
  121. self.pushButton_log_refresh.clicked.connect(self.log_refresh)
  122. # self.lineEdit_log_rx_buf_max.textChanged.connect(self.log_rx_buf_max)
  123. self.pushButton_log_2rs485_0on.clicked.connect(self.log_rs485_up_enable)
  124. self.pushButton_log_2rs485_1off.clicked.connect(self.log_rs485_up_disable)
  125. def timer_test_f(self, str):
  126. print("mqtt timer_test_f," + datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3])
  127. self.timer_test_t.start(3*1000) # 10秒后重连
  128. def mqtt_timer_f(self):
  129. print("mqtt mqtt_timer_f," + datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3])
  130. # self.mqtt_timer.start(3*1000) # 10秒后重连
  131. def log_rx_clr(self):
  132. self.textEdit_log_0rx_display.setText("")
  133. def mainWindow_title_update(self, state):
  134. self.setWindowTitle("LogTT_tools:" + "test-" + version + "," + state)
  135. if state == "已连接":
  136. self.mqtt_subscribe(g_client)
  137. def mqtt_connect(self, client):
  138. print("mqtt mqtt_connect," + datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3])
  139. try:
  140. def on_connect(client, userdata, flags, rc):
  141. if rc == 0:
  142. print("Connected to MQTT Broker!" + datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3])
  143. self.mqtt_connect_state_signal.emit("已连接")
  144. else:
  145. print("Failed to connect, return code %d\n", rc)
  146. self.mqtt_connect_state_signal.emit("连接失败")
  147. # self.mqtt_timer.start(mqtt_timer_time_out) # 10秒后重连
  148. client.username_pw_set(mqtt_user, mqtt_pwd)
  149. client.on_connect = on_connect
  150. client.connect(mqtt_broker, mqtt_port, mqtt_keepalive)
  151. print("[√]连接成功," + datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3])
  152. except Exception as e:
  153. print("[!]Connect error")
  154. print("[×]连接失败," + datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3])
  155. pass
  156. def mqtt_disconnect(self, client):
  157. print("mqtt mqtt_disconnect," + datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3])
  158. def on_disconnect(client, userdata, rc):
  159. print("self.sender()", self.sender())
  160. if rc != 0:
  161. print("Unexpected disconnection." + datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3])
  162. else:
  163. print("Disconnected from MQTT." + datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3])
  164. # 更新 UI 线程
  165. self.mqtt_connect_state_signal.emit("已断开")
  166. client.on_disconnect = on_disconnect
  167. def mqtt_subscribe(self, client):
  168. print("mqtt mqtt_subscribe," + datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3])
  169. global info_msg
  170. global error_msg
  171. def on_message(client, userdata, msg):
  172. LogTT_SN = str.split(msg.topic, "/")[-1]
  173. head = b""
  174. body = b""
  175. cmd_type = ""
  176. flag_ascii = False
  177. flag_hex = True
  178. if msg.payload[:len(start_ttl)] == start_ttl.encode("utf-8"):
  179. cmd_type = start_ttl
  180. flag_ascii = True
  181. flag_hex = True
  182. head = msg.payload[:len(start_ttl)]
  183. body = msg.payload[len(start_ttl):]
  184. elif msg.payload[:len(start_rs232)] == start_rs232.encode("utf-8"):
  185. cmd_type = start_rs232
  186. flag_ascii = False
  187. flag_hex = True
  188. head = msg.payload[:len(start_rs232)]
  189. body = msg.payload[len(start_rs232):]
  190. elif msg.payload[:len(start_rs485)] == start_rs485.encode("utf-8"):
  191. cmd_type = start_rs485
  192. flag_ascii = False
  193. flag_hex = True
  194. head = msg.payload[:len(start_rs485)]
  195. body = msg.payload[len(start_rs485):]
  196. elif msg.payload[:len(start_fixed)] == start_fixed.encode("utf-8"):
  197. cmd_type = start_fixed
  198. flag_ascii = True
  199. flag_hex = False
  200. head = msg.payload[:len(start_fixed)]
  201. body = msg.payload[len(start_fixed):]
  202. elif msg.payload[:len(start_heart)] == start_heart.encode("utf-8"):
  203. cmd_type = start_heart
  204. flag_ascii = True
  205. flag_hex = False
  206. head = msg.payload[:len(start_heart)]
  207. body = msg.payload[len(start_heart):]
  208. elif msg.payload[:len(start_pt)] == start_pt.encode("utf-8"):
  209. cmd_type = start_pt
  210. flag_ascii = True
  211. flag_hex = False
  212. head = msg.payload[:len(start_pt)]
  213. body = msg.payload[len(start_pt):]
  214. else:
  215. cmd_type = ""
  216. flag_ascii = False
  217. flag_hex = True
  218. body = msg.payload
  219. if flag_ascii:
  220. try:
  221. body_str = body.decode('gb2312')
  222. except UnicodeDecodeError:
  223. try:
  224. body_str = body.decode('utf-8')
  225. except UnicodeDecodeError:
  226. body_str = body.hex().upper()
  227. head_str = head.decode('utf-8')
  228. msg_ascii = datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3] + "-->:"
  229. msg_ascii = msg_ascii + f"topic:{msg.topic} msg:{head_str}\r\n{body_str}"
  230. msg_ascii = msg_ascii.rstrip() + "\r\n"
  231. # 输出信息
  232. try:
  233. with open(get_log_file_name_ascii(LogTT_SN), 'a') as f:
  234. global version_w_ascii
  235. if version_w_ascii > 0:
  236. f.write("version:" + version + "\n")
  237. version_w_ascii = 0
  238. f.write(msg_ascii)
  239. f.close()
  240. except Exception as e:
  241. print(str(e))
  242. print(msg_ascii, end="")
  243. if self.comboBox_log_sn.currentIndex() == -1:
  244. # self.textEdit_log_0rx_display.append(msg_ascii)
  245. self.log_display_update_signal.emit(msg_ascii)
  246. elif self.comboBox_log_sn.currentText() == LogTT_SN:
  247. # self.textEdit_log_0rx_display.append(msg_ascii)
  248. self.log_display_update_signal.emit(msg_ascii)
  249. self.rx_data_signal.emit(LogTT_SN, head_str, body_str)
  250. # self.parse_data(LogTT_SN, head_str, body_str)
  251. if flag_hex:
  252. msg_hex = datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3] + "-->:"
  253. msg_hex = msg_hex + f"topic:{msg.topic} msg:{head.decode('utf-8')}{body.hex().upper()}"
  254. # 输出信息
  255. try:
  256. with open(get_log_file_name_hex(LogTT_SN), 'a') as f:
  257. global version_w_hex
  258. if version_w_hex > 0:
  259. f.write("version:" + version + "\n")
  260. version_w_hex = 0
  261. f.write(msg_hex + "\r\n")
  262. f.close()
  263. except Exception as e:
  264. print(str(e))
  265. if not flag_ascii:
  266. print(msg_hex)
  267. # self.textEdit_log_0rx_display.append(msg_ascii)
  268. self.log_display_update_signal.emit(msg_hex)
  269. client.subscribe(mqtt_subtopic)
  270. client.on_message = on_message
  271. print("[√]订阅成功," + datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3])
  272. def mqtt_publish_test(self, client):
  273. print("mqtt mqtt_publish_test," + datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3])
  274. try:
  275. msg = "qqqqqqqqqqqqqqq"
  276. result = client.publish(mqtt_pubtopic, msg)
  277. # result: [0, 1]
  278. status = result[0]
  279. if status == 0:
  280. print(f"[√]发送成功, Send `{msg}` to topic `{mqtt_pubtopic}`")
  281. else:
  282. print(f"[×]发送失败, Failed to send message to topic {mqtt_pubtopic}")
  283. except:
  284. print("[!]请先连接服务器!")
  285. def parse_data(self, sn, head, body):
  286. if data_buf.get(sn) is None:
  287. data_buf[sn] = {}
  288. if data_buf[sn].get("base_info") is None:
  289. data_buf[sn]["base_info"] = {}
  290. if data_buf[sn].get("pos_info") is None:
  291. data_buf[sn]["pos_info"] = {}
  292. data_buf[sn]["heart_time_stamp"] = datetime.now().strftime('%H:%M:%S.%f')[:-3]
  293. # start_fixed = "FIXED_INFO="
  294. # start_heart = "HEART_MSG="
  295. # FIXED_INFO={"base_info":{"name":"张三","uplinkB":1010,"rsrp":-99,"tel":"13888888888","reset_times":49,"project":"LogTT","csq":23,"downlinkB":573,"rsrq":-13,"dev_type":"9002","simid":0,"muid":"20230818221817A863212A0300364949","snr":-1,"version":"9002.4.002","iccid":"89860622330053052122","imei":"869861069998891","rssi":-66,"dev_pd":"20240329","dev_sn":1},"pos_info":{"lng":0,"lat":0}}
  296. # if head == start_fixed or head == start_heart:
  297. if is_valid_json(body):
  298. body_dict = json_loads(body)
  299. if body_dict["base_info"]:
  300. base_info = body_dict["base_info"]
  301. if base_info.get("project"): data_buf[sn]["base_info"]["project"] = base_info.get("project")
  302. if base_info.get("version"): data_buf[sn]["base_info"]["version"] = base_info.get("version")
  303. if base_info.get("name"): data_buf[sn]["base_info"]["name"] = base_info.get("name")
  304. if base_info.get("tel"): data_buf[sn]["base_info"]["tel"] = base_info.get("tel")
  305. if base_info.get("dev_type"): data_buf[sn]["base_info"]["dev_type"] = base_info.get("dev_type")
  306. if base_info.get("dev_sn"): data_buf[sn]["base_info"]["dev_sn"] = str(sn)
  307. if base_info.get("dev_pd"): data_buf[sn]["base_info"]["dev_pd"] = base_info.get("dev_pd")
  308. if base_info.get("reset_times"): data_buf[sn]["base_info"]["reset_times"] = base_info.get("reset_times")
  309. if base_info.get("imei"): data_buf[sn]["base_info"]["imei"] = base_info.get("imei")
  310. if base_info.get("muid"): data_buf[sn]["base_info"]["muid"] = base_info.get("muid")
  311. if base_info.get("iccid"): data_buf[sn]["base_info"]["iccid"] = base_info.get("iccid")
  312. if base_info.get("simid"): data_buf[sn]["base_info"]["simid"] = base_info.get("simid")
  313. if base_info.get("csq"): data_buf[sn]["base_info"]["csq"] = base_info.get("csq")
  314. if base_info.get("rssi"): data_buf[sn]["base_info"]["rssi"] = base_info.get("rssi")
  315. if base_info.get("snr"): data_buf[sn]["base_info"]["snr"] = base_info.get("snr")
  316. if base_info.get("rsrq"): data_buf[sn]["base_info"]["rsrq"] = base_info.get("rsrq")
  317. if base_info.get("rsrp"): data_buf[sn]["base_info"]["rsrp"] = base_info.get("rsrp")
  318. if base_info.get("uplinkB"): data_buf[sn]["base_info"]["uplinkB"] = base_info.get("uplinkB")
  319. if base_info.get("downlinkB"): data_buf[sn]["base_info"]["downlinkB"] = base_info.get("downlinkB")
  320. if body_dict["pos_info"]:
  321. pos_info = body_dict["pos_info"]
  322. if pos_info.get("lng"): data_buf[sn]["pos_info"]["lng"] = pos_info.get("lng")
  323. if pos_info.get("lat"): data_buf[sn]["pos_info"]["lat"] = pos_info.get("lat")
  324. # 更新数据
  325. self.data_update(sn)
  326. def data_update(self, sn):
  327. self.comboBox_log_sn_add(sn)
  328. self.display_update(sn)
  329. self.dev_list_refresh(sn)
  330. if self.comboBox_log_sn.currentIndex() != -1:
  331. sn_cur = self.comboBox_log_sn.currentText()
  332. if sn == sn_cur:
  333. if data_buf.get(sn_cur):
  334. if data_buf[sn_cur].get("pos_info"):
  335. lng = data_buf[sn_cur]["pos_info"].get("lng", 116.1666213)
  336. lat = data_buf[sn_cur]["pos_info"].get("lat", 39.9007607)
  337. # self.map_refresh_signal.emit(sn_cur, float(lng), float(lat))
  338. def comboBox_log_sn_change(self):
  339. # self.sn_current = sn
  340. self.display_update()
  341. def comboBox_log_sn_add(self, sn):
  342. if sn == "0000000116":
  343. return
  344. if self.comboBox_log_sn.findText(sn) == -1:
  345. self.comboBox_log_sn.addItem(sn)
  346. num_items = self.comboBox_log_sn.count()
  347. current_text = self.comboBox_log_sn.currentText()
  348. # 插入,且排序
  349. text_list = []
  350. for index in range(num_items):
  351. text_list.append(self.comboBox_log_sn.itemText(index))
  352. text_list = sorted(text_list)
  353. for index in range(num_items):
  354. self.comboBox_log_sn.setItemText(index, text_list[index])
  355. self.comboBox_log_sn.setCurrentText(current_text)
  356. def display_base_info_clear(self):
  357. self.label_log_01dev_type.setText("设备类型:")
  358. self.label_log_02sn.setText("设备SN:")
  359. self.label_log_03reset_times.setText("复位次数:")
  360. self.label_log_04app_ver.setText("固件版本:")
  361. self.label_log_05name.setText("姓名:")
  362. self.label_log_06telephone.setText("电话:")
  363. self.label_log_09imei.setText("IMEI:")
  364. self.label_log_10iccid.setText("ICCID:")
  365. self.label_log_11rssi.setText("信号强度:")
  366. self.label_log_12snr.setText("信噪比:")
  367. def display_pos_info_clear(self):
  368. self.label_log_07longitude.setText("经度:")
  369. self.label_log_08latitude.setText("维度:")
  370. def display_clear(self):
  371. self.display_base_info_clear()
  372. self.display_pos_info_clear()
  373. self.groupBox_log_1base.setTitle("日志设备基础信息")
  374. def display_update(self, sn=0):
  375. sn_cur = self.comboBox_log_sn.currentText()
  376. if sn_cur in data_buf:
  377. if data_buf[sn_cur]["base_info"]:
  378. base_info = data_buf[sn_cur]["base_info"]
  379. self.label_log_01dev_type.setText("设备类型:" + base_info.get("dev_type", ""))
  380. self.label_log_02sn.setText("设备SN:" + str(sn_cur))
  381. self.label_log_03reset_times.setText("复位次数:" + str(base_info.get("reset_times", 0)))
  382. self.label_log_04app_ver.setText("固件版本:" + base_info.get("version", ""))
  383. self.label_log_05name.setText("姓名:" + base_info.get("name", ""))
  384. self.label_log_06telephone.setText("电话:" + base_info.get("tel", ""))
  385. self.label_log_09imei.setText("IMEI:" + base_info.get("imei", ""))
  386. self.label_log_10iccid.setText("ICCID:" + base_info.get("iccid", ""))
  387. self.label_log_11rssi.setText("信号强度:" + str(base_info.get("rssi", 0)))
  388. self.label_log_12snr.setText("信噪比:" + str(base_info.get("snr", 0)))
  389. else:
  390. self.display_base_info_clear()
  391. if data_buf[sn_cur]["pos_info"]:
  392. pos_info = data_buf[sn_cur]["pos_info"]
  393. lng = pos_info.get("lng", 0) if pos_info.get("lng", 0) != 0 else 116.1666213
  394. self.label_log_07longitude.setText("经度:" + str(lng))
  395. lat = pos_info.get("lat", 0) if pos_info.get("lat", 0) != 0 else 39.9007607
  396. self.label_log_08latitude.setText("维度:" + str(lat))
  397. else:
  398. self.display_pos_info_clear()
  399. self.groupBox_log_1base.setTitle("日志设备基础信息:" + str(data_buf[sn_cur]["heart_time_stamp"]))
  400. else:
  401. self.display_clear()
  402. self.label_lsb_01dev_type.setText(self.label_log_01dev_type.text())
  403. self.label_lsb_02sn.setText(self.label_log_02sn.text())
  404. self.label_lsb_03reset_times.setText(self.label_log_03reset_times.text())
  405. self.label_lsb_04app_ver.setText(self.label_log_04app_ver.text())
  406. self.label_lsb_05name.setText(self.label_log_05name.text())
  407. self.label_lsb_06telephone.setText(self.label_log_06telephone.text())
  408. self.label_lsb_09imei.setText(self.label_log_09imei.text())
  409. self.label_lsb_10iccid.setText(self.label_log_10iccid.text())
  410. self.label_lsb_11rssi.setText(self.label_log_11rssi.text())
  411. self.label_lsb_12snr.setText(self.label_log_12snr.text())
  412. self.label_lsb_07longitude.setText(self.label_log_07longitude.text())
  413. self.label_lsb_08latitude.setText(self.label_log_08latitude.text())
  414. self.groupBox_lsb_1base.setTitle(self.groupBox_log_1base.title())
  415. def sn_update_something(self):
  416. if self.checkBox_set_default_tx_sn.isChecked():
  417. sn_text = self.comboBox_log_sn.currentText()
  418. sn_num = int(sn_text)
  419. sn_text = f"%u" % sn_num
  420. self.lineEdit_tx_sn.setText(sn_text)
  421. # self.lineEdit_5pub_topic.setText("cpyypt/down/9002/" + self.lineEdit_tx_sn.text().zfill(10))
  422. def dev_list_refresh(self, sn):
  423. dev_str = self.plainTextEdit_log_dev_list.toPlainText()
  424. dev_list = str.split(dev_str)
  425. # dev_list = [dev for dev in data_buf.keys()]
  426. if sn not in dev_list:
  427. # print(dev_list)
  428. dev_list.append(sn)
  429. dev_list = sorted(dev_list)
  430. dev_text = ""
  431. for dev in dev_list:
  432. dev_text = dev_text + str(dev) + "\n"
  433. self.plainTextEdit_log_dev_list.setPlainText(dev_text)
  434. def mqtt_send_data(self, client, pub_topic, userdata):
  435. try:
  436. result = client.publish(pub_topic, userdata)
  437. # result: [0, 1]
  438. status = result[0]
  439. if status == 0:
  440. msg = f"[√]发送成功, Send `{userdata}` to topic `{pub_topic}`"
  441. else:
  442. msg = f"[×]发送失败, Failed to send message to topic {pub_topic}"
  443. except:
  444. msg = "[!]请先连接服务器!"
  445. # self.textEdit_log_0rx_display.append(msg + "\n")
  446. self.log_display_update_signal.emit(msg + "\n")
  447. def log_display_update(self, text):
  448. # 当前光标是否在最后
  449. cursor_end = False
  450. position = self.textEdit_log_0rx_display.textCursor().position()
  451. length = len(self.textEdit_log_0rx_display.toPlainText())
  452. if position == length:
  453. cursor_end = True
  454. self.textEdit_log_0rx_display.append(text)
  455. # 是否将光标移动到最后
  456. if cursor_end:
  457. self.textEdit_log_0rx_display.moveCursor(QTextCursor.End)
  458. def log_rx_buf_max(self):
  459. max_text = self.lineEdit_log_rx_buf_max.text()
  460. max_num = 10000
  461. try:
  462. max_num = int(max_text)
  463. except ValueError:
  464. max_num = 10000
  465. if max_num <= 100:
  466. max_num = 100
  467. self.lineEdit_log_rx_buf_max.setText(max_num)
  468. if max_num >= 100000:
  469. max_num = 100000
  470. self.lineEdit_log_rx_buf_max.setText(f'{max_num}')
  471. self.textEdit_log_0rx_display.document().setMaximumBlockCount(max_num)
  472. def log_refresh(self):
  473. if self.comboBox_log_sn.currentIndex() != -1:
  474. sn_cur = self.comboBox_log_sn.currentText()
  475. send_topic = "cpyypt/down/9002/" + sn_cur
  476. send_data = 'PT_CMD={"get_fixed_info": "true"}'
  477. self.mqtt_send_data(g_client, send_topic, send_data)
  478. def log_send(self):
  479. if self.comboBox_log_sn.currentIndex() != -1:
  480. sn_cur = self.comboBox_log_sn.currentText()
  481. cmd_header = "TTD_TTL"
  482. cmd_tail = ""
  483. io_select = self.comboBox_tx_io_select.currentIndex()
  484. if io_select == 0:
  485. cmd_header = 'TTD_TTL'
  486. elif io_select == 1:
  487. cmd_header = 'TTD_RS232'
  488. elif io_select == 2:
  489. cmd_header = 'TTD_RS485'
  490. if self.radioButton_log_1tx_ascii.isChecked():
  491. cmd_header = cmd_header + "_A="
  492. if self.checkBox_r_n.isChecked():
  493. cmd_tail = "\r\n"
  494. else:
  495. cmd_header = cmd_header + "_H="
  496. cmd_body = self.textEdit_log_1tx.toPlainText()
  497. send_data = cmd_header + cmd_body + cmd_tail
  498. send_topic = "cpyypt/down/9002/" + sn_cur
  499. self.mqtt_send_data(g_client, send_topic, send_data)
  500. def log_rs485_up_enable(self):
  501. if self.comboBox_log_sn.currentIndex() != -1:
  502. sn_cur = self.comboBox_log_sn.currentText()
  503. send_data = 'PT_CMD={"rs485_cfg": {"up_enable": 1}}'
  504. send_topic = "cpyypt/down/9002/" + sn_cur
  505. self.mqtt_send_data(g_client, send_topic, send_data)
  506. def log_rs485_up_disable(self):
  507. if self.comboBox_log_sn.currentIndex() != -1:
  508. sn_cur = self.comboBox_log_sn.currentText()
  509. send_data = 'PT_CMD={"rs485_cfg": {"up_enable": 0}}'
  510. send_topic = "cpyypt/down/9002/" + sn_cur
  511. self.mqtt_send_data(g_client, send_topic, send_data)
  512. def map_refresh(self, sn=0, longitude=116.1798005, latitude=39.9030239):
  513. print("map_refresh")
  514. self.map_get_regeocode(sn, longitude, latitude)
  515. self.map_load_static_map(sn, longitude, latitude)
  516. def map_get_regeocode(self, sn=0, longitude=116.1798005, latitude=39.9030239, key='ebe21d6ee4409542d070b8be762ab0a5'):
  517. # print(longitude, latitude, key)
  518. # 构建请求URL
  519. url = f"https://restapi.amap.com/v3/geocode/regeo?key={key}&location={longitude},{latitude}"
  520. # 发送请求
  521. response = requests_get(url)
  522. # 解析JSON响应
  523. data = response.json()
  524. text = "信号基站位置信息:"
  525. if data['status'] == '1':
  526. # 打印地理编码结果
  527. geo_result = data['regeocode']
  528. # print(f"地址: {geo_result['formatted_address']}")
  529. # print(f"省: {geo_result['addressComponent']['province']}")
  530. # print(f"市: {geo_result['addressComponent']['city']}")
  531. # print(f"区: {geo_result['addressComponent']['district']}")
  532. text = text + f"\n省: {geo_result['addressComponent']['province']}"
  533. text = text + f"\n市: {geo_result['addressComponent']['city']}"
  534. text = text + f"\n区: {geo_result['addressComponent']['district']}"
  535. text = text + f"\n地址: {geo_result['formatted_address']}"
  536. else:
  537. text = "逆向地理编码失败"
  538. print(text)
  539. self.textEdit_lsb_address.setText(text)
  540. def map_load_static_map(self, sn=0, longitude=116.1798005, latitude=39.9030239, key='ebe21d6ee4409542d070b8be762ab0a5'):
  541. # 高德地图URL,location为初始定位,可以是城市名或经纬度
  542. location_str = f'{longitude},{latitude}'
  543. #print(self, sn, longitude, latitude, key)
  544. #location_str = "116.1798005,39.9030239"
  545. url = f"https://restapi.amap.com/v3/geocode/regeo?key=ebe21d6ee4409542d070b8be762ab0a5&location=116.1798005,39.9030239"
  546. # url = f"https://restapi.amap.com/v3/geocode/regeo?output=xml&location=116.1798005,39.9030239&key=ebe21d6ee4409542d070b8be762ab0a5&radius=1000&extensions=all"
  547. url = f"https://restapi.amap.com/v3/staticmap?location={location_str}&zoom=13&size=1024*600&markers=mid,,A:{location_str}&key={key}"
  548. print(url)
  549. self.browser.load(QUrl(url))
  550. # self.setCentralWidget(self.browser)
  551. # self.browser.show()
  552. def lsb_get_fixed_info(self):
  553. sn_cur = ""
  554. send_cmd_flag = False
  555. if self.comboBox_log_sn.currentIndex() != -1:
  556. sn_cur = self.comboBox_log_sn.currentText()
  557. else:
  558. return
  559. if data_buf.get(sn_cur):
  560. if data_buf[sn_cur].get("pos_info"):
  561. lng = data_buf[sn_cur]["pos_info"].get("lng", 116.1666213)
  562. lat = data_buf[sn_cur]["pos_info"].get("lat", 39.9007607)
  563. self.map_refresh(sn_cur, lng, lat)
  564. else:
  565. send_cmd_flag = True
  566. else:
  567. send_cmd_flag = True
  568. if send_cmd_flag:
  569. send_topic = "cpyypt/down/9002/" + sn_cur
  570. send_data = 'PT_CMD={"get_fixed_info": "true"}'
  571. self.mqtt_send_data(g_client, send_topic, send_data)
  572. def set_svr(self):
  573. index_cur = self.comboBox_set_svr.currentIndex()
  574. if index_cur == 0:
  575. self.lineEdit_set_0ip.setText("test-******")
  576. self.lineEdit_set_1port.setText("******")
  577. self.lineEdit_set_2usr.setText("******")
  578. self.lineEdit_set_3password.setText("******")
  579. self.set_svr_env = "test"
  580. elif index_cur == 1:
  581. self.lineEdit_set_0ip.setText("prod-******")
  582. self.lineEdit_set_1port.setText("******")
  583. self.lineEdit_set_2usr.setText("******")
  584. self.lineEdit_set_3password.setText("******")
  585. self.set_svr_env = "prod"
  586. else:
  587. self.set_svr_env = "usr_def"
  588. def set_create(self):
  589. # PT_CMD={"imei_check":"869861069999337","reboot":"true","dev_cfg":{"dev_type":"9002","dev_sn":5,"dev_pd":"20240329"}}
  590. # PT_CMD={"reboot":"true","dev_cfg":{"dev_type":"9002","dev_sn":"0000000001","dev_pd":"20240322"},"reg_cfg":{"name":"李四","tel":"13999999999"}}
  591. set_dict = {}
  592. # 下发指令,是否绑定IMEI
  593. if self.checkBox_set_bind_imei.isChecked():
  594. set_dict["imei_check"] = self.lineEdit_0imei.text()
  595. else:
  596. set_dict.pop("imei_check", None)
  597. # 获取基础信息
  598. if self.checkBox_set_get_fixed_info.isChecked():
  599. set_dict["get_fixed_info"] = "true"
  600. else:
  601. set_dict.pop("get_fixed_info", None)
  602. # 恢复默认参数
  603. if self.checkBox_set_default_cfg.isChecked():
  604. set_dict["default_cfg"] = "true"
  605. else:
  606. set_dict.pop("default_cfg", None)
  607. # 重启
  608. if self.checkBox_set_reboot.isChecked():
  609. set_dict["reboot"] = "true"
  610. else:
  611. set_dict.pop("reboot", None)
  612. # 设备信息
  613. if self.checkBox_set_dev_cfg.isChecked():
  614. set_dict["dev_cfg"] = {}
  615. set_dict["dev_cfg"]["dev_sn"] = self.lineEdit_set_dev_sn.text()
  616. set_dict["dev_cfg"]["dev_pd"] = self.lineEdit_set_dev_pd.text()
  617. else:
  618. set_dict.pop("dev_cfg", None)
  619. # 注册信息
  620. if self.checkBox_set_reg_cfg.isChecked():
  621. set_dict["reg_cfg"] = {}
  622. set_dict["reg_cfg"]["name"] = self.lineEdit_set_reg_name.text()
  623. set_dict["reg_cfg"]["tel"] = self.lineEdit_set_reg_tel.text()
  624. else:
  625. set_dict.pop("reg_cfg", None)
  626. # 服务器信息
  627. if self.checkBox_set_svr_cfg.isChecked():
  628. set_dict["svr_cfg"] = {}
  629. set_dict["svr_cfg"]["svr_ip"] = self.lineEdit_set_svr_cfg.text()
  630. set_dict["svr_cfg"]["svr_port"] = self.lineEdit_set_svr_port.text()
  631. set_dict["svr_cfg"]["svr_usr_name"] = self.lineEdit_set_svr_usr_name.text()
  632. set_dict["svr_cfg"]["svr_usr_pwd"] = self.lineEdit_set_svr_usr_pwd.text()
  633. else:
  634. set_dict.pop("svr_cfg", None)
  635. # 接口参数
  636. io_name = self.comboBox_set_io_select.currentText() + "_cfg"
  637. if self.checkBox_set_io_cfg.isChecked():
  638. io_name = io_name.lower()
  639. set_dict[io_name] = {}
  640. if self.checkBox_set_io_up_enable.isChecked():
  641. set_dict[io_name]["up_enable"] = 1
  642. if self.checkBox_set_io_up_disable.isChecked():
  643. set_dict[io_name]["up_enable"] = 0
  644. if (not self.checkBox_set_io_up_enable.isChecked()) and (not self.checkBox_set_io_up_disable.isChecked()):
  645. set_dict[io_name].pop("up_enable", None)
  646. if self.checkBox_set_io_down_enable.isChecked():
  647. set_dict[io_name]["down_enable"] = 1
  648. if self.checkBox_set_io_down_disable.isChecked():
  649. set_dict[io_name]["down_enable"] = 0
  650. if (not self.checkBox_set_io_down_enable.isChecked()) and (not self.checkBox_set_io_down_disable.isChecked()):
  651. set_dict[io_name].pop("down_enable", None)
  652. if self.checkBox_set_io_parameter.isChecked():
  653. if self.lineEdit_set_baud_rate.text() != "":
  654. set_dict[io_name]["baud_rate"] = int(self.lineEdit_set_baud_rate.text())
  655. if self.lineEdit_set_data_bits.text() != "":
  656. set_dict[io_name]["data_bits"] = int(self.lineEdit_set_data_bits.text())
  657. if self.lineEdit_set_stop_bits.text() != "":
  658. set_dict[io_name]["stop_bits"] = int(self.lineEdit_set_stop_bits.text())
  659. if self.lineEdit_set_partiy.text() != "":
  660. set_dict[io_name]["partiy"] = int(self.lineEdit_set_partiy.text())
  661. '''
  662. if self.lineEdit_set_bit_order.text() != "":
  663. set_dict[io_name]["bit_order"] = int(self.lineEdit_set_bit_order.text())
  664. if self.lineEdit_set_buff_size.text() != "":
  665. set_dict[io_name]["buff_size"] = int(self.lineEdit_set_buff_size.text())
  666. if self.lineEdit_set_rs485_gpio.text() != "":
  667. set_dict[io_name]["rs485_gpio"] = int(self.lineEdit_set_rs485_gpio.text())
  668. if self.lineEdit_set_rs485_level.text() != "":
  669. set_dict[io_name]["rs485_level"] = int(self.lineEdit_set_rs485_level.text())
  670. if self.lineEdit_set_rs485_delay.text() != "":
  671. set_dict[io_name]["rs485_delay"] = int(self.lineEdit_set_rs485_delay.text())
  672. '''
  673. else:
  674. set_dict.pop(io_name, None)
  675. set_str = json_dumps(set_dict, ensure_ascii=False)
  676. print(set_str)
  677. if len(set_str) > 4:
  678. self.textEdit_set_tx.setText("PT_CMD=" + set_str)
  679. def set_send(self):
  680. print("mqtt set_send," + datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3])
  681. send_topic = self.lineEdit_5pub_topic.text()
  682. send_data = self.textEdit_set_tx.toPlainText()
  683. self.mqtt_send_data(g_client, send_topic, send_data)
  684. def set_create_send(self):
  685. self.set_create()
  686. self.set_send()
  687. def set_io_up_able(self):
  688. if self.checkBox_set_io_up_enable.isChecked():
  689. self.checkBox_set_io_up_disable.setChecked(False)
  690. self.checkBox_set_io_cfg.setChecked(True)
  691. if (not self.checkBox_set_io_parameter.isChecked()) and \
  692. (not self.checkBox_set_io_up_enable.isChecked()) and \
  693. (not self.checkBox_set_io_up_disable.isChecked()) and \
  694. (not self.checkBox_set_io_down_enable.isChecked()) and \
  695. (not self.checkBox_set_io_down_disable.isChecked()):
  696. self.checkBox_set_io_cfg.setChecked(False)
  697. def set_io_up_disable(self):
  698. if self.checkBox_set_io_up_disable.isChecked():
  699. self.checkBox_set_io_up_enable.setChecked(False)
  700. self.checkBox_set_io_cfg.setChecked(True)
  701. if (not self.checkBox_set_io_parameter.isChecked()) and \
  702. (not self.checkBox_set_io_up_enable.isChecked()) and \
  703. (not self.checkBox_set_io_up_disable.isChecked()) and \
  704. (not self.checkBox_set_io_down_enable.isChecked()) and \
  705. (not self.checkBox_set_io_down_disable.isChecked()):
  706. self.checkBox_set_io_cfg.setChecked(False)
  707. def set_io_down_able(self):
  708. if self.checkBox_set_io_down_enable.isChecked():
  709. self.checkBox_set_io_down_disable.setChecked(False)
  710. self.checkBox_set_io_cfg.setChecked(True)
  711. if (not self.checkBox_set_io_parameter.isChecked()) and \
  712. (not self.checkBox_set_io_up_enable.isChecked()) and \
  713. (not self.checkBox_set_io_up_disable.isChecked()) and \
  714. (not self.checkBox_set_io_down_enable.isChecked()) and \
  715. (not self.checkBox_set_io_down_disable.isChecked()):
  716. self.checkBox_set_io_cfg.setChecked(False)
  717. def set_io_down_disable(self):
  718. if self.checkBox_set_io_down_disable.isChecked():
  719. self.checkBox_set_io_down_enable.setChecked(False)
  720. self.checkBox_set_io_cfg.setChecked(True)
  721. if (not self.checkBox_set_io_parameter.isChecked()) and \
  722. (not self.checkBox_set_io_up_enable.isChecked()) and \
  723. (not self.checkBox_set_io_up_disable.isChecked()) and \
  724. (not self.checkBox_set_io_down_enable.isChecked()) and \
  725. (not self.checkBox_set_io_down_disable.isChecked()):
  726. self.checkBox_set_io_cfg.setChecked(False)
  727. def set_io_parameter(self):
  728. if self.checkBox_set_io_parameter.isChecked():
  729. self.checkBox_set_io_cfg.setChecked(True)
  730. if (not self.checkBox_set_io_parameter.isChecked()) and \
  731. (not self.checkBox_set_io_up_enable.isChecked()) and \
  732. (not self.checkBox_set_io_up_disable.isChecked()) and \
  733. (not self.checkBox_set_io_down_enable.isChecked()) and \
  734. (not self.checkBox_set_io_down_disable.isChecked()):
  735. self.checkBox_set_io_cfg.setChecked(False)
  736. def set_io_cfg(self):
  737. if not self.checkBox_set_io_parameter.isChecked():
  738. self.checkBox_set_io_parameter.setChecked(False)
  739. self.checkBox_set_io_up_enable.setChecked(False)
  740. self.checkBox_set_io_up_disable.setChecked(False)
  741. self.checkBox_set_io_down_enable.setChecked(False)
  742. self.checkBox_set_io_down_disable.setChecked(False)
  743. def set_default_tx_sn(self):
  744. if self.checkBox_set_default_tx_sn.isChecked():
  745. self.lineEdit_tx_sn.setEnabled(False)
  746. self.lineEdit_5pub_topic.setEnabled(False)
  747. else:
  748. self.lineEdit_tx_sn.setEnabled(True)
  749. self.lineEdit_5pub_topic.setEnabled(True)
  750. def set_tx_sn_change(self):
  751. sn = self.lineEdit_tx_sn.text()
  752. sn_str = sn.zfill(10)
  753. self.lineEdit_5pub_topic.setText("cpyypt/down/9002/" + sn_str)
  754. def main():
  755. app = QApplication(sys.argv) # 创建一个QApplication,也就是你要开发的软件app
  756. myWin = MyWindow() # 创建一个QMainWindow,用来装载你需要的各种组件、控件,myWin()类的实例化对象
  757. myWin.show() # 执行QMainWindow的show()方法,显示这个QMainWindow
  758. # 捕获并处理异常
  759. try:
  760. sys.exit(app.exec_())
  761. # sys.exit(app.exec_()) # 使用exit()或者点击关闭按钮退出QApplication
  762. except SystemExit as e:
  763. # 异常处理代码
  764. print(f"程序异常退出: {e}")
  765. # 这里可以添加额外的处理代码,例如保存状态、清理资源等
  766. if __name__ == '__main__':
  767. main()