#!/usr/bin/env python
-- coding: utf-8 --
@Time : 2023/08/31 14:02
@Author : Piu
@Version : python3.8
@File : pageview230831.py
@Software : PyCharm
import datetime
import re
import time
import serial
from PyQt5.QtCore import QThread
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, QPushButton, QVBoxLayout, QHBoxLayout, QStackedWidget,
QLabel, QComboBox, QLineEdit, QLCDNumber
from PyQt5.QtSerialPort import QSerialPortInfo
from dateutil.relativedelta import relativedelta
import iconfile
import crc16Check
get now time to hex string
%w表示时,1-6表示周一到周六,0表示周日
print(date.strftime(“%w”))
def now_time_tohex_string(nowtimestring):
now_time_pattern = nowtimestring.strftime(‘%Y-%m-%d-%H-%M-%S’)
now_time_pattern_list = now_time_pattern.split(‘-’)
# year to hex
# 年高字节中无空格-XXXX年转为16进制表示,eg:2022转十六进制07e6
# now_time_pattern_list[0] = (“%02X%02X” % (int(now_time_pattern_list[0][2:]) // 256,
# int(now_time_pattern_list[0]) % 256))
# year to hex
# 年高字节中无空格-XXXX年取后两字节转为16进制表示,eg:2022,取22转十六进制16
now_time_pattern_list[0] = (“%02X” % (int(now_time_pattern_list[0][2:]) % 256))
# month,day,hour,minute,second to hex
for index in range(1, len(now_time_pattern_list)):
now_time_pattern_list[index] = (“%02X” % (int(now_time_pattern_list[index]) % 256))
timestringhex = ‘’
# year,month,day,
for timestr in now_time_pattern_list:
# 每个字符中不添加空格
timestringhex += timestr
timestringhex = timestringhex.rstrip()
return timestringhex
累加校验
def calculate_checksum(hex_string):
# 去除空格
hex_string = hex_string.replace(" ", “”)
# 将十六进制字符串转换为字节数组
bytes_array = bytes.fromhex(hex_string)
# 计算累加和
Sum = sum(bytes_array)
# 返回校验和-两字节
# return (~Sum + 1) & 0xFFFF
# 返回校验和-使用了 & 0xFF 操作符对累加和进行了截断,限制结果为一个字节,最终的校验和结果将保留最低的8位
return (~Sum + 1) & 0xFF
Adds a space every two characters to a given string
def string_add_space(strcmd):
pattern = re.compile(‘.{2}’)
return ’ '.join(pattern.findall(strcmd)).upper()
对串口的参数进行配置 - loadprofile
def port_open_recv_lp(self):
ser.port = self.combo_box.currentText()
ser.baudrate = int(self.combo_box_baudrate.currentText())
ser.bytesize = 8
ser.stopbits = 1
# 奇偶校验位
ser.parity = “N”
ser.open()
# isOpen()函数来查看串口的开闭状态
if (ser.isOpen()):
# print(“串口打开成功!”)
pass
else:
# print(“串口打开失败!”)
pass
对串口的参数进行配置 - daily
def port_open_recv_daily(self):
ser.port = self.combo_box2.currentText()
ser.baudrate = int(self.combo_box_baudrate2.currentText())
ser.bytesize = 8
ser.stopbits = 1
# 奇偶校验位
ser.parity = “N”
ser.open()
# isOpen()函数来查看串口的开闭状态
if (ser.isOpen()):
# print(“串口打开成功!”)
pass
else:
# print(“串口打开失败!”)
pass
对串口的参数进行配置 - billing
def port_open_recv_billing(self):
ser.port = self.combo_box3.currentText()
ser.baudrate = int(self.combo_box_baudrate3.currentText())
ser.bytesize = 8
ser.stopbits = 1
# 奇偶校验位
ser.parity = “N”
ser.open()
# isOpen()函数来查看串口的开闭状态
if (ser.isOpen()):
# print(“串口打开成功!”)
pass
else:
# print(“串口打开失败!”)
pass
关闭串口
def port_close():
ser.close()
if (ser.isOpen()):
# print(“串口关闭失败!”)
pass
else:
# print(“串口关闭成功!”)
pass
串口数据发送
def send(send_data):
if (ser.isOpen()):
ser.write(send_data)
# print(“发送成功”, send_data)
# str_send = string_add_space(str(binascii.b2a_hex(send_data))[2:-1])
# print(datetime.datetime.now().strftime(‘%Y-%m-%d %H:%M:%S.%f’)[:-3] + " TX》“, str_send)
# 停止、等待数据,这一步非常关键。timeout压根没用
time.sleep(0.1)
count = ser.inWaiting()
# 数据的接收
if count > 0:
data = ser.read(count)
if data != b’‘:
pass
# str_recv = string_add_space(str(binascii.b2a_hex(data))[2:-1])
# print(datetime.datetime.now().strftime(’%Y-%m-%d %H:%M:%S.%f’)[:-3] + " RX》”, str_recv)
else:
# print(“发送失败!”)
pass
loadprofile线程
class buttonThread_lp(QThread):
def init(self):
super().init()
self.running = False
def run(self):
self.running = True
# 获取输入框的值并进行处理
# 负荷曲线条数条数
input1_value = window.input1_edit.text()
# 负荷曲线间隔
input2_value = window.input2_edit.text()
# 设置起始时间
input3_value = window.input3_edit.text()
# 设置延时间隔
input31_value = window.input4_edit.text()
# 显示当前修改时钟次数
window.lcd.display(window.num)
strtime = input3_value
port_open_recv_lp(window)
# 开启 identification 服务
send(bstr_ack)
send(bstr_identification)
# 开启 negotiate 服务
send(bstr_ack)
send(bstr_negotiate)
# 开启 logon 服务
send(bstr_ack)
send(bstr_logon)
# 开启 security 服务
send(bstr_ack)
send(bstr_security)
# 循环写时钟次数
for i in range(0, int(input1_value)):
# 负荷曲线捕获周期 = input2_value
delta = datetime.timedelta(minutes=int(input2_value))
date = datetime.datetime.strptime(strtime, "%Y-%m-%d %H:%M:%S") + delta
# 更新下一次进入循环时的strtime
strtime = date.strftime("%Y-%m-%d %H:%M:%S")
datehex1 = "000A0003" + now_time_tohex_string(date) + "10"
# 计算 data sum
checksum = calculate_checksum(datehex1)
# checksum_byte = hex(checksum).upper()[2:]
checksum_byte = ('{:02X}'.format(checksum))
# data_frame = datehex1 + checksum_byte
frame_no_crccheck = frame_head + datehex1 + checksum_byte
# 拼接帧 和 计算帧校验
frame_crccheck = crc16Check.CalcFCS16frame(frame_no_crccheck)
frame_write = frame_no_crccheck + frame_crccheck
frame_write = string_add_space(frame_write)
# 写时钟的发送帧转换为字节型数据
bstr_write = bytes.fromhex(frame_write)
if self.isInterruptionRequested():
window.lcd.display(0)
break
# 执行写时钟操作
send(bstr_ack)
send(bstr_write)
time.sleep(int(input31_value))
window.num += 1
window.lcd.display(window.num)
# 开启 terminate 服务 - 立即结束本次会话
send(bstr_ack)
send(bstr_terminate)
# 关闭串口
port_close()
window.num = 0
def stop(self):
self.requestInterruption()
daily线程
class buttonThread_daily(QThread):
def init(self):
super().init()
self.running = False
def run(self):
self.running = True
# 获取输入框的值并进行处理
# 日冻结条数
input1_value = window.input21_edit.text()
# 设置起始时间
input3_value = window.input23_edit.text()
# 显示当前修改时钟次数
window.lcd2.display(window.num2)
strtime = input3_value
port_open_recv_daily(window)
# 开启 identification 服务
send(bstr_ack)
send(bstr_identification)
# 开启 negotiate 服务
send(bstr_ack)
send(bstr_negotiate)
# 开启 logon 服务
send(bstr_ack)
send(bstr_logon)
# 开启 security 服务
send(bstr_ack)
send(bstr_security)
# 循环写时钟次数
for i in range(0, int(input1_value)):
# 日冻结 - 天数+1
delta = datetime.timedelta(days=1)
date = datetime.datetime.strptime(strtime, "%Y-%m-%d %H:%M:%S") + delta
# 更新下一次进入循环时的strtime
strtime = date.strftime("%Y-%m-%d %H:%M:%S")
next_day = date.replace(hour=23, minute=59, second=57)
datehex1 = "000A0003" + now_time_tohex_string(next_day) + "10"
# 计算 data sum
checksum = calculate_checksum(datehex1)
# checksum_byte = hex(checksum).upper()[2:]
checksum_byte = ('{:02X}'.format(checksum))
# data_frame = datehex1 + checksum_byte
frame_no_crccheck = frame_head + datehex1 + checksum_byte
# 拼接帧 和 计算帧校验
frame_crccheck = crc16Check.CalcFCS16frame(frame_no_crccheck)
frame_write = frame_no_crccheck + frame_crccheck
frame_write = string_add_space(frame_write)
# 写时钟的发送帧转换为字节型数据
bstr_write = bytes.fromhex(frame_write)
if self.isInterruptionRequested():
window.lcd2.display(0)
break
# 执行写时钟操作
send(bstr_ack)
send(bstr_write)
time.sleep(5)
window.num2 += 1
window.lcd2.display(window.num2)
# 开启 terminate 服务 - 立即结束本次会话
send(bstr_ack)
send(bstr_terminate)
# 关闭串口
port_close()
window.num2 = 0
def stop(self):
# self.running = False
self.requestInterruption()
billing线程
class buttonThread_billing(QThread):
def init(self):
super().init()
self.running = False
def run(self):
self.running = True
# 获取输入框的值并进行处理
# 月结算条数
input1_value = window.input31_edit.text()
# 设置起始时间
input3_value = window.input33_edit.text()
# 显示当前修改时钟次数
window.lcd3.display(window.num3)
strtime = input3_value
port_open_recv_billing(window)
# 开启 identification 服务
send(bstr_ack)
send(bstr_identification)
# 开启 negotiate 服务
send(bstr_ack)
send(bstr_negotiate)
# 开启 logon 服务
send(bstr_ack)
send(bstr_logon)
# 开启 security 服务
send(bstr_ack)
send(bstr_security)
# 循环写时钟次数
for i in range(0, int(input1_value)):
# 月结算---month+1
delta = relativedelta(months=1)
date = datetime.datetime.strptime(strtime, "%Y-%m-%d %H:%M:%S") + delta
# 更新下一次进入循环时的strtime
strtime = date.strftime("%Y-%m-%d %H:%M:%S")
year = date.year
month = date.month
last_day = datetime.date(year + int(month / 12), (month % 12) + 1, 1) - datetime.timedelta(days=1)
next_month_last_day = date.replace(day=last_day.day, hour=23, minute=59, second=57)
datehex1 = "000A0003" + now_time_tohex_string(next_month_last_day) + "10"
# 计算 data sum
checksum = calculate_checksum(datehex1)
# checksum_byte = hex(checksum).upper()[2:]
checksum_byte = ('{:02X}'.format(checksum))
# data_frame = datehex1 + checksum_byte
frame_no_crccheck = frame_head + datehex1 + checksum_byte
# 拼接帧 和 计算帧校验
frame_crccheck = crc16Check.CalcFCS16frame(frame_no_crccheck)
frame_write = frame_no_crccheck + frame_crccheck
frame_write = string_add_space(frame_write)
# 写时钟的发送帧转换为字节型数据
bstr_write = bytes.fromhex(frame_write)
if self.isInterruptionRequested():
window.lcd3.display(0)
break
# 执行写时钟操作
send(bstr_ack)
send(bstr_write)
time.sleep(5)
window.num3 += 1
window.lcd3.display(window.num3)
# 开启 terminate 服务 - 立即结束本次会话
send(bstr_ack)
send(bstr_terminate)
# 关闭串口
port_close()
window.num3 = 0
def stop(self):
# self.running = False
self.requestInterruption()
class MainWindow(QMainWindow):
def init(self):
super().init()
# self.init_ui()
# def init_ui(self):
self.lpThread = buttonThread_lp()
self.dailyThread = buttonThread_daily()
self.billingThread = buttonThread_billing()
# 设置标题
self.setWindowTitle("TimeLoop")
# 设置窗口的ICO
self.setWindowIcon(QIcon(':/mexico.ico'))
# 设置窗口的固定大小
self.setFixedSize(270, 440)
# 创建主窗口的布局
main_layout = QVBoxLayout()
# 创建按钮布局
button_layout = QHBoxLayout()
# 创建导航栏按钮
button1 = QPushButton("负荷曲线")
button2 = QPushButton("日冻结")
button3 = QPushButton("月结算")
# 将按钮添加到按钮布局中
button_layout.addWidget(button1)
button_layout.addWidget(button2)
button_layout.addWidget(button3)
# 创建一个 stacked widget 来容纳页面
stacked_widget = QStackedWidget()
# 创建三个页面
page1 = QWidget()
page2 = QWidget()
page3 = QWidget()
# 第一个页面内容 - 负荷曲线 ----------------------------------------------------------
# 添加串口检测功能到第一个页面
scan_button = QPushButton("扫描串口")
scan_button.clicked.connect(self.check_serial_ports)
self.combo_box = QComboBox()
self.scan_serial_ports()
# 创建一个波特率下拉框
baudrate_label = QLabel("波特率:")
self.combo_box_baudrate = QComboBox()
items = ['9600', '19200', '115200']
self.combo_box_baudrate.addItems(items)
# 创建第一个输入框和标签
self.input1_label = QLabel("负荷曲线条数:")
self.input1_edit = QLineEdit()
# 添加描述文本到输入框
self.input1_edit.setPlaceholderText('设置正整数')
# 创建第二个输入框和标签
self.input2_label = QLabel("负荷曲线间隔(min):")
self.input2_edit = QLineEdit()
# 添加描述文本到输入框
self.input2_edit.setPlaceholderText('设置正整数')
# 创建第三个输入框和标签
self.input3_label = QLabel("设置起始时间:")
self.input3_edit = QLineEdit()
default_value = "2022-06-01 07:59:57"
self.input3_edit.setText(default_value)
# 创建第四个输入框和标签
self.input4_label = QLabel("设置延时间隔(s):")
self.input4_edit = QLineEdit()
# 添加描述文本到输入框
self.input4_edit.setPlaceholderText('设置正整数')
# 创建确认按钮
self.confirm_button = QPushButton("开始循环修改时钟", clicked=self.lpThread_start)
# 当前进度
self.input5_label = QLabel("当前修改时钟次数:")
self.lcd = QLCDNumber(self)
self.num = 0
self.lcd.display(self.num)
self.lcd.setSegmentStyle(QLCDNumber.Flat)
# self.lcd.setStyleSheet("border: 2px solid black; color: red; background: silver;")
self.lcd.setStyleSheet("color: green;")
# 创建确认按钮
self.stop_button = QPushButton("停止循环修改时钟", clicked=self.lpThread_stop)
page1_layout = QVBoxLayout()
page1_layout.addWidget(scan_button)
page1_layout.addWidget(self.combo_box)
page1_layout.addWidget(baudrate_label)
page1_layout.addWidget(self.combo_box_baudrate)
# 将输入框和标签添加到布局中
page1_layout.addWidget(self.input1_label)
page1_layout.addWidget(self.input1_edit)
# 将输入框和标签添加到布局中
page1_layout.addWidget(self.input2_label)
page1_layout.addWidget(self.input2_edit)
# 将输入框和标签添加到布局中
page1_layout.addWidget(self.input3_label)
page1_layout.addWidget(self.input3_edit)
# 将输入框和标签添加到布局中
page1_layout.addWidget(self.input4_label)
page1_layout.addWidget(self.input4_edit)
# # 将确认按钮添加到布局中
page1_layout.addWidget(self.confirm_button)
page1_layout.addWidget(self.input5_label)
page1_layout.addWidget(self.lcd)
page1_layout.addWidget(self.stop_button)
page1.setLayout(page1_layout)
# 第二个页面内容 - 日冻结 ----------------------------------------------------------
# 添加串口检测功能到第二个页面
scan_button2 = QPushButton("扫描串口")
scan_button2.clicked.connect(self.check_serial_ports_daily)
self.combo_box2 = QComboBox()
self.scan_serial_ports_daily()
# 创建一个波特率下拉框
baudrate_label2 = QLabel("波特率:")
self.combo_box_baudrate2 = QComboBox()
items = ['9600', '19200', '115200']
self.combo_box_baudrate2.addItems(items)
# 创建第一个输入框和标签
self.input21_label = QLabel("日冻结条数:")
self.input21_edit = QLineEdit()
# 添加描述文本到输入框
self.input21_edit.setPlaceholderText('设置正整数')
# 创建第三个输入框和标签
self.input23_label = QLabel("设置起始时间:")
self.input23_edit = QLineEdit()
default_value = "2022-06-01 07:59:57"
self.input23_edit.setText(default_value)
# 创建确认按钮
self.confirm_button2 = QPushButton("开始循环修改时钟", clicked=self.dailyThread_start)
# 当前进度
self.input25_label = QLabel("当前修改时钟次数:")
self.lcd2 = QLCDNumber(self)
self.num2 = 0
self.lcd2.display(self.num2)
self.lcd2.setSegmentStyle(QLCDNumber.Flat)
# self.lcd.setStyleSheet("border: 2px solid black; color: red; background: silver;")
self.lcd2.setStyleSheet("color: green;")
# 创建确认按钮
self.stop_button2 = QPushButton("停止循环修改时钟", clicked=self.dailyThread_stop)
page2_layout = QVBoxLayout()
page2_layout.addWidget(scan_button2)
page2_layout.addWidget(self.combo_box2)
page2_layout.addWidget(baudrate_label2)
page2_layout.addWidget(self.combo_box_baudrate2)
# 将输入框和标签添加到布局中
page2_layout.addWidget(self.input21_label)
page2_layout.addWidget(self.input21_edit)
# 将输入框和标签添加到布局中
page2_layout.addWidget(self.input23_label)
page2_layout.addWidget(self.input23_edit)
# # 将确认按钮添加到布局中
page2_layout.addWidget(self.confirm_button2)
page2_layout.addWidget(self.input25_label)
page2_layout.addWidget(self.lcd2)
page2_layout.addWidget(self.stop_button2)
page2.setLayout(page2_layout)
# 第三个页面内容 - 月结算 ----------------------------------------------------------
# 添加串口检测功能到第三个页面
scan_button3 = QPushButton("扫描串口")
scan_button3.clicked.connect(self.check_serial_ports_billing)
self.combo_box3 = QComboBox()
self.scan_serial_ports_billing()
# 创建一个波特率下拉框
baudrate_label3 = QLabel("波特率:")
self.combo_box_baudrate3 = QComboBox()
items = ['9600', '19200', '115200']
self.combo_box_baudrate3.addItems(items)
# 创建第一个输入框和标签
self.input31_label = QLabel("月结算条数:")
self.input31_edit = QLineEdit()
# 添加描述文本到输入框
self.input31_edit.setPlaceholderText('设置正整数')
# 创建第三个输入框和标签
self.input33_label = QLabel("设置起始时间:")
self.input33_edit = QLineEdit()
default_value = "2022-06-01 07:59:57"
self.input33_edit.setText(default_value)
# 创建确认按钮
self.confirm_button3 = QPushButton("开始循环修改时钟", clicked=self.billingThread_start)
# 当前进度
self.input35_label = QLabel("当前修改时钟次数:")
self.lcd3 = QLCDNumber(self)
self.num3 = 0
self.lcd3.display(self.num3)
self.lcd3.setSegmentStyle(QLCDNumber.Flat)
# self.lcd.setStyleSheet("border: 2px solid black; color: red; background: silver;")
self.lcd3.setStyleSheet("color: green;")
# 创建确认按钮
self.stop_button3 = QPushButton("停止循环修改时钟", clicked=self.billingThread_stop)
page3_layout = QVBoxLayout()
page3_layout.addWidget(scan_button3)
page3_layout.addWidget(self.combo_box3)
page3_layout.addWidget(baudrate_label3)
page3_layout.addWidget(self.combo_box_baudrate3)
# 将输入框和标签添加到布局中
page3_layout.addWidget(self.input31_label)
page3_layout.addWidget(self.input31_edit)
# 将输入框和标签添加到布局中
page3_layout.addWidget(self.input33_label)
page3_layout.addWidget(self.input33_edit)
# # 将确认按钮添加到布局中
page3_layout.addWidget(self.confirm_button3)
page3_layout.addWidget(self.input35_label)
page3_layout.addWidget(self.lcd3)
page3_layout.addWidget(self.stop_button3)
page3.setLayout(page3_layout)
# 将页面添加到 stacked widget 中
stacked_widget.addWidget(page1)
stacked_widget.addWidget(page2)
stacked_widget.addWidget(page3)
# 默认显示第一个页面
stacked_widget.setCurrentIndex(0)
# 绑定按钮的点击事件,实现页面切换
button1.clicked.connect(lambda: stacked_widget.setCurrentIndex(0))
button2.clicked.connect(lambda: stacked_widget.setCurrentIndex(1))
button3.clicked.connect(lambda: stacked_widget.setCurrentIndex(2))
# 设置 stacked widget 为主窗口的中心部件
main_layout.addLayout(button_layout)
main_layout.addWidget(stacked_widget)
# 创建一个 widget 来容纳整个布局
widget = QWidget()
widget.setLayout(main_layout)
# 设置 widget 为主窗口的中心部件
self.setCentralWidget(widget)
def lpThread_stop(self):
self.confirm_button.setStyleSheet('')
self.lpThread.stop()
self.lcd.display(0)
self.input1_edit.clear()
self.input2_edit.clear()
self.input3_edit.clear()
self.input4_edit.clear()
default_value = "2021-01-01 01:59:57"
self.input3_edit.setText(default_value)
def lpThread_start(self):
self.confirm_button.setStyleSheet('background-color: springgreen;')
self.lpThread.start()
def dailyThread_stop(self):
self.confirm_button2.setStyleSheet('')
self.dailyThread.stop()
self.lcd2.display(0)
self.input21_edit.clear()
self.input23_edit.clear()
default_value = "2022-01-01 01:59:57"
self.input23_edit.setText(default_value)
def dailyThread_start(self):
self.confirm_button2.setStyleSheet('background-color: springgreen;')
self.dailyThread.start()
def billingThread_stop(self):
self.confirm_button3.setStyleSheet('')
self.billingThread.stop()
self.lcd3.display(0)
self.input31_edit.clear()
self.input33_edit.clear()
default_value = "2023-01-01 01:59:57"
self.input33_edit.setText(default_value)
def billingThread_start(self):
self.confirm_button3.setStyleSheet('background-color: springgreen;')
self.billingThread.start()
# 串口检测相关
def scan_serial_ports(self):
ports = QSerialPortInfo().availablePorts()
for port in ports:
self.combo_box.addItem(port.portName())
if len(ports) > 0:
self.combo_box.setCurrentIndex(0)
def check_serial_ports(self):
self.combo_box.clear()
self.scan_serial_ports()
# daily
def scan_serial_ports_daily(self):
ports = QSerialPortInfo().availablePorts()
for port in ports:
self.combo_box2.addItem(port.portName())
if len(ports) > 0:
self.combo_box2.setCurrentIndex(0)
def check_serial_ports_daily(self):
self.combo_box2.clear()
self.scan_serial_ports_daily()
# billing
def scan_serial_ports_billing(self):
ports = QSerialPortInfo().availablePorts()
for port in ports:
self.combo_box3.addItem(port.portName())
if len(ports) > 0:
self.combo_box3.setCurrentIndex(0)
def check_serial_ports_billing(self):
self.combo_box3.clear()
self.scan_serial_ports_billing()
ser = serial.Serial()
写时钟待发送帧
frame_ack = “06”
frame_identification = “EE 00 00 00 00 01 20 13 10”
frame_negotiate = “EE 00 20 00 00 05 61 04 00 80 06 C2 29”
frame_logon = “EE 00 00 00 00 0D 50 00 02 41 64 6D 69 6E 69 73 74 72 61 F9 04”
frame_security = “EE 00 20 00 00 15 51 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 B6 A5”
frame_terminate = “EE 00 20 00 00 01 21 0B 61”
读取时钟
frame_read_time = “EE 00 00 00 00 03 30 00 34 7B 6B”
发送帧转化为字节型
bstr_ack = bytes.fromhex(frame_ack)
bstr_identification = bytes.fromhex(frame_identification)
bstr_negotiate = bytes.fromhex(frame_negotiate)
bstr_logon = bytes.fromhex(frame_logon)
bstr_security = bytes.fromhex(frame_security)
bstr_terminate = bytes.fromhex(frame_terminate)
bstr_read_time = bytes.fromhex(frame_read_time)
frame_head = “EE0000000011400007000B”
frame_check = “”
if name == ‘main’:
app = QApplication([])
window = MainWindow()
window.show()
app.exec_()