Python一键完成奥智利AZL-212C系列分机刷机示例

# -*- coding: utf-8 -*-

################################################################################
## Form generated from reading UI file 'app.ui'
##
## Created by: Qt User Interface Compiler version 6.6.2
##
## WARNING! All changes made in this file will be lost when recompiling UI file!
################################################################################

from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale,
    QMetaObject, QObject, QPoint, QRect,
    QSize, QTime, QUrl, Qt)
from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,
    QFont, QFontDatabase, QGradient, QIcon,
    QImage, QKeySequence, QLinearGradient, QPainter,
    QPalette, QPixmap, QRadialGradient, QTransform)
from PySide6.QtWidgets import (QApplication, QComboBox, QLabel, QMainWindow,
    QPushButton, QSizePolicy, QStatusBar, QTextEdit,
    QWidget)

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        if not MainWindow.objectName():
            MainWindow.setObjectName(u"MainWindow")
        MainWindow.resize(611, 630)
        MainWindow.setStyleSheet(u"font: 9pt \"Microsoft YaHei UI\";")
        self.centralwidget = QWidget(MainWindow)
        self.centralwidget.setObjectName(u"centralwidget")
        self.comboBox_networkcard = QComboBox(self.centralwidget)
        self.comboBox_networkcard.setObjectName(u"comboBox_networkcard")
        self.comboBox_networkcard.setGeometry(QRect(90, 10, 260, 22))
        self.label_networkcard = QLabel(self.centralwidget)
        self.label_networkcard.setObjectName(u"label_networkcard")
        self.label_networkcard.setGeometry(QRect(20, 10, 53, 20))
        self.label_class = QLabel(self.centralwidget)
        self.label_class.setObjectName(u"label_class")
        self.label_class.setGeometry(QRect(20, 50, 53, 20))
        self.comboBox_class = QComboBox(self.centralwidget)
        self.comboBox_class.setObjectName(u"comboBox_class")
        self.comboBox_class.setGeometry(QRect(90, 50, 261, 22))
        self.textEdit_networkadapter = QTextEdit(self.centralwidget)
        self.textEdit_networkadapter.setObjectName(u"textEdit_networkadapter")
        self.textEdit_networkadapter.setGeometry(QRect(20, 130, 161, 180))
        self.label_networkadapter = QLabel(self.centralwidget)
        self.label_networkadapter.setObjectName(u"label_networkadapter")
        self.label_networkadapter.setGeometry(QRect(20, 100, 131, 20))
        self.label_device = QLabel(self.centralwidget)
        self.label_device.setObjectName(u"label_device")
        self.label_device.setGeometry(QRect(190, 100, 121, 20))
        self.textEdit_device = QTextEdit(self.centralwidget)
        self.textEdit_device.setObjectName(u"textEdit_device")
        self.textEdit_device.setGeometry(QRect(190, 130, 161, 180))
        self.textEdit_log = QTextEdit(self.centralwidget)
        self.textEdit_log.setObjectName(u"textEdit_log")
        self.textEdit_log.setGeometry(QRect(20, 330, 571, 241))
        self.textEdit_configlabel = QTextEdit(self.centralwidget)
        self.textEdit_configlabel.setObjectName(u"textEdit_configlabel")
        self.textEdit_configlabel.setGeometry(QRect(360, 10, 231, 301))
        self.label_log = QLabel(self.centralwidget)
        self.label_log.setObjectName(u"label_log")
        self.label_log.setGeometry(QRect(20, 310, 121, 20))
        self.pushButton_update = QPushButton(self.centralwidget)
        self.pushButton_update.setObjectName(u"pushButton_update")
        self.pushButton_update.setGeometry(QRect(20, 580, 571, 31))
        MainWindow.setCentralWidget(self.centralwidget)
        self.statusbar = QStatusBar(MainWindow)
        self.statusbar.setObjectName(u"statusbar")
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)

        QMetaObject.connectSlotsByName(MainWindow)
    # setupUi

    def retranslateUi(self, MainWindow):
        MainWindow.setWindowTitle(QCoreApplication.translate("MainWindow", u"\u9ad8\u6e05\u53ef\u89c6\u5206\u673a(C\u673a)\u81ea\u52a8\u5237\u673a\u5de5\u5177", None))
        self.label_networkcard.setText(QCoreApplication.translate("MainWindow", u"\u9009\u62e9\u7f51\u5361", None))
        self.label_class.setText(QCoreApplication.translate("MainWindow", u"\u9009\u62e9\u90e8\u95e8", None))
        self.label_networkadapter.setText(QCoreApplication.translate("MainWindow", u"\u672c\u673a\u7f51\u7edc\u9002\u914d\u5668\u914d\u7f6e\u4fe1\u606f", None))
        self.label_device.setText(QCoreApplication.translate("MainWindow", u"\u540c\u6bb5\u53ef\u89c6\u5bf9\u8bb2\u8bbe\u5907\u4fe1\u606f", None))
        self.label_log.setText(QCoreApplication.translate("MainWindow", u"\u8fd0\u884c\u65e5\u5fd7", None))
        self.pushButton_update.setText(QCoreApplication.translate("MainWindow", u"\u4e00\u952e\u5237\u673a", None))
    # retranslateUi
import binascii
import os
import socket
import subprocess
import ipaddress
import sys
import time
from pathlib import Path
from lxml import etree
import pandas as pd
import psutil
from PySide6.QtCore import QThread, Signal
from PySide6.QtWidgets import QApplication, QMainWindow
from app import Ui_MainWindow

# 初始化全局变量
config_table_list = []
network_card_list = []
device_config_list = []
device_information_list = []


def Parse_Device_Xml(data: str) -> list:
    root = etree.fromstring(data.encode('utf-8'))
    code = root.findtext('CODE')
    devname = root.findtext('DEVNAME')
    ip = root.findtext('IP')
    mask = root.findtext('MASK')
    gateway = root.findtext('GATEWAY')
    mac = root.findtext('MAC')
    version = root.findtext('VERSION')
    device_information_list.clear()
    device_information_list.extend([code, devname, ip, mask, gateway, mac, version])
    return device_information_list


def Get_Networkcard_Ip_And_Netmask(interface_name: str) -> list:
    """
    获取指定网卡的IP地址和子网掩码
    :param interface_name: str,连接名称
    :return: list,ip和子网掩码
    """
    interface_info = psutil.net_if_addrs()[interface_name]
    # 查找IPv4地址,子网掩码
    for snic in interface_info:
        if snic.family == socket.AddressFamily.AF_INET:
            ip_address = snic.address
            netmask = snic.netmask
            return [ip_address, netmask]


def Check_If_Key_Files_Exist() -> bool:
    """
    检测软件运行目录是否存在xml文件和xls文件
    :return: str,检测结果
    """
    xls_path = [str(p) for p in Path(os.getcwd()).rglob("*.xls")]
    xml_path = [str(p) for p in Path(os.getcwd()).rglob("*.xml")]
    if len(xls_path) > 0 and len(xml_path) > 0:
        return True
    else:
        return False


def Extension_Number_Packaging(number: str) -> str:
    """
    分机号数据包组包
    :param number: str,分机号
    :return: str,十六进制格式数据包
    """
    data = ''.join([h.replace('0x', '00') for h in [hex(ord(c)) for c in number]])
    package = "BBBB666601100A00000000000000000020000000A4F619" + data + "0000002D02C8F6190040884300"
    return str(package)


def Disable_Network_Adapter(adapter_name: str) -> bool:
    """
    禁用网络适配器
    :param adapter_name: str,连接名称
    :return: 如果命令执行成功,则为True,否则为False
    """
    try:
        # 使用 subprocess 调用命令
        result = os.system(f'wmic path win32_networkadapter where NetConnectionID="{adapter_name}" call disable')
        return result == 0  # 0 表示命令执行成功
    except Exception as e:
        print(f"禁用网络适配器时出错: {e}")
        return False


def Ping(ip: str) -> bool:
    """
    测试与指定IP能否正常通信
    :param ip: str,ip
    :return: 如果命令执行成功,则为True,否则为False
    """
    try:
        # 使用ping命令,发送1个包
        response = os.system("ping -c 1 " + ip)
        # 检查响应值,如果为0,表示可以ping通
        return response == 0  # 0 表示命令执行成功
    except Exception as e:
        print(f"执行Ping命令时出错: {e}")
        return False


def Calculate_Gateway_Address(ip: str, netmask: str) -> str:
    """
    计算网关地址
    :param ip: ip
    :param netmask: 子网掩码
    :return:
    """
    # 给定的IP地址和子网掩码
    _ip = ipaddress.IPv4Address(ip)
    _netmask = ipaddress.IPv4Address(netmask)
    # 计算网络地址
    network = ipaddress.IPv4Network(_ip.exploded + '/' + _netmask.exploded, strict=False)
    # 打印子网的第二个IP地址
    return str(network.network_address + 1)


def Read_Config_Xls_To_List() -> list:
    """
    读取xls配置表到列表
    :return: list,分机号开头为1的C机配置表
    """
    xls_path = [str(p) for p in Path(os.getcwd()).rglob("*.xls")]
    df = pd.read_excel(xls_path[0])
    for i in range(df.shape[0]):
        data = str(df.iloc[i, 0])
        if data[0] != "1":
            continue
        else:
            key = str(df.iloc[i, 1])
            value = str(df.iloc[i, 0]) + "|" + str(df.iloc[i, 2]) + "|" + str(df.iloc[i, 3]) + "|" + str(df.iloc[i, 4])
            config_table_list.append({key: value})
    return config_table_list


def Read_Config_Xml():
    """
    读取xml配置表
    :return: hex,配置表数据字节集
    """
    xml_path = [str(p) for p in Path(os.getcwd()).rglob("*.xml")]
    with open(xml_path[0], 'rb') as f:
        data = f.read()
        hex_data = binascii.hexlify(data).decode().upper()
        return hex_data


def Get_Pc_Network_Card():
    """
    获取本计算机所有网卡连接名称
    :return: list,本机网卡连接名称列表
    """
    interfaces = psutil.net_if_addrs()
    for interface_name in interfaces:
        # 检查每个网络接口是否有IPv4地址
        for snic in interfaces[interface_name]:
            if snic.family == socket.AF_INET:
                network_card_list.append(interface_name)
    return network_card_list


def Send_Data_To_Device(ip: str, packets: list) -> bool:
    """
    发送数据到可视对讲分机
    :param ip: 设备IP
    :param packets: list,数据包(可多个,使用列表格式传入)
    :return: bool,成功返回True,失败返回False
    """
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    try:
        connection_status = Ping(ip)
        while True:
            if connection_status:
                # 如果可以ping通分机则建立TCP连接
                s.connect((ip, 34918))
                for packet in packets:
                    # 发送数据包
                    data = binascii.unhexlify(packet)
                    sent = s.send(data)
                    while True:
                        if sent == len(data):
                            # 校验数据包是否发送成功,失败则重发
                            break
                        else:
                            # 重新发送数据包
                            sent = s.send(data)
                return True
            else:
                # 如果无法ping通分机,则等1s后再次尝试
                time.sleep(1)
                connection_status = Ping(ip)
    except socket.error as e:
        print("将数据包传输到分机设备失败,错误信息:", e)
        return False
    finally:
        # 关闭套接字
        s.close()


def Search_Device_Info():
    """
    向局域网发送搜索设备组播消息
    :return:
    """
    # 创建一个udp套接字
    udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    # 设置socket属性,允许发送广播数据
    udp_socket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
    # 准备接收方的地址
    dest_addr = ('255.255.255.255', 3001)  # 注意这是一个元组
    # 自定义广播数据
    send_data = ('<?xml version="1.0" encoding="GB2312" '
                 '?><XML_MSG_BODY><XML_MSG_TYPE>SEARCH_DEV_INFO</XML_MSG_TYPE><XML_LOCAL_IP>45.91.3.146'
                 '</XML_LOCAL_IP></XML_MSG_BODY>')
    try:
        # 可以使用套接字收发数据
        udp_socket.sendto(send_data.encode('GB2312'), dest_addr)
    except socket.timeout:
        print("发送搜索分机广播消息超时,正在重试...")
        time.sleep(1)
    except OSError as e:
        if e.winerror == 10065:  # [WinError 10065] No route to host
            print("发送搜索分机广播消息时没有到主机的路由,正在重试...")
            time.sleep(1)
        else:
            print(f"发送搜索分机广播消息时出现意外错误: {e}")
    finally:
        # 关闭套接字
        udp_socket.close()


def Listen_Device_Info() -> str:
    """
    监听局域网中分机返回的消息
    :return: str,分机返回的消息数据
    """
    # 1.创建一个udp套接字
    udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    # 2.绑定本地的相关信息,如果一个网络程序不绑定,则系统会随机分配
    local_addr = ("", 3002)
    udp_socket.bind(local_addr)
    udp_socket.settimeout(1)  # 设置套接字超时时间为1秒
    try:
        while True:
            try:
                # 3. 等待接收对方发送的数据
                recv_data = udp_socket.recvfrom(1024)  # 1024表示本次接收的最大字节数
                # 接收到的数据recv_data是一个元组,第1个元素是对方发送的数据,第2个元素是对方的ip和端口
                print(f"接收到分机消息,{recv_data}")
                return str(recv_data[0].decode('GB2312'))
            except socket.timeout:
                print("未接收到分机消息,正在重试。。。")
                Search_Device_Info()
    finally:
        # 3.关闭套接字
        udp_socket.close()


def Set_Computer_Network_Card_Dhcp(name: str) -> bool:
    """
    设置本计算机指定网卡为DHCP模式
    :param name: 连接名称
    :return: 如果命令都成功执行,则为True,否则为False
    """
    print(name)
    try:
        # 设置IP地址为DHCP
        ip_result = subprocess.run(f'netsh interface ip set address name="{name}" source=dhcp', shell=True,
                                   stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
        # 设置DNS为DHCP
        dns_result = subprocess.run(f'netsh interface ip set dns name="{name}" source=dhcp', shell=True,
                                    stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
        print(f"设置指定网卡DHCP返回值: {ip_result.returncode},{dns_result.returncode}")
        return True
    except Exception as e:
        print(f"Error setting network adapter to DHCP: {e}")
        return False


def Set_Computer_Network_Card_Ip(name: str, addr: str, mask: str, gateway: str) -> bool:
    """
    设置本计算机指定网卡的ip地址,子网掩码,网关地址
    :param name: str,连接名称
    :param addr: str,ip
    :param mask: str,子网掩码
    :param gateway: str,网关地址
    :return: 如果命令都成功执行,则为True,否则为False
    """
    try:
        # 设置IP地址为静态
        ip_result = subprocess.run(
            f'netsh interface ip set address name="{name}" source=static addr={addr} mask={mask} gateway={gateway} gwmetric=1',
            shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
        print(f"设置指定网卡IP返回值: {ip_result.returncode}")
        return True
    except Exception as e:
        print(f"Error setting network adapter IP: {e}")
        return False


class Worker(QThread):
    """
    自定义多线程类
    """
    finished_int = Signal(int)  # 定义一个带有一个int参数的信号
    finished_str = Signal(str)  # 定义一个带有一个str参数的信号
    finished_list = Signal(list)  # 定义一个带有一个list参数的信号
    finished_bool = Signal(bool)  # 定义一个带有一个bool参数的信号

    def __init__(self, func, return_type, args=()):
        super(Worker, self).__init__()
        self.func = func  # 保存业务函数的引用
        self.args = args  # 保存业务函数的参数
        self.return_type = return_type  # 保存返回类型的引用

    def run(self):
        # 调用业务函数
        result = self.func(*self.args)
        # 根据返回类型发出相应的信号
        if self.return_type == int:
            self.finished_int.emit(result)
        elif self.return_type == str:
            self.finished_str.emit(result)
        elif self.return_type == list:
            self.finished_list.emit(result)
        elif self.return_type == bool:
            self.finished_bool.emit(result)


class MyMainWindow(QMainWindow, Ui_MainWindow):
    def __init__(self, parent=None):
        super(MyMainWindow, self).__init__(parent)
        self.worker_set_all_networkcard_dhcp = None
        self.worker_update_device_config_table = None
        self.worker_set_networkcard_config = None
        self.worker_parsing_device_message = None
        self.worker_waiting_device_connection = None
        self.worker_pushButton_update_clicked = None
        self.worker_comboBox_class_currentIndex_Changed = None
        self.worker_comboBox_networkcard_currentIndex_Changed = None
        self.worker_update_comboBox_networkcard = None
        self.worker_update_comboBox_class = None
        self.worker_initialization = None
        self.setupUi(self)
        # 初始化
        self.initialization()
        # self.set_all_networkcard_dhcp()
        # 组合框网卡信息列表项被选择
        self.comboBox_networkcard.currentIndexChanged.connect(self.comboBox_networkcard_currentIndex_Changed)
        # 组合框部门信息列表项被选择
        self.comboBox_class.currentIndexChanged.connect(self.comboBox_class_currentIndex_Changed)
        # 按钮一键刷机被点击
        self.pushButton_update.clicked.connect(self.pushButton_update_clicked)
        # 禁用编辑框用户输入,仅用于显示信息。
        self.textEdit_device.setEnabled(False)
        self.textEdit_configlabel.setEnabled(False)
        self.textEdit_networkadapter.setEnabled(False)
        self.textEdit_log.setEnabled(False)

    def initialization(self):
        """
        子线程:初始化。UI界面创建完成后,检测关键文件是否缺失.
        :return: 无返回
        """
        self.worker_initialization = Worker(Check_If_Key_Files_Exist, bool)
        self.worker_initialization.finished_bool.connect(self.initialization_callback)
        self.worker_initialization.start()

    def set_all_networkcard_dhcp(self):
        """
        子线程:设置计算机所有可用网卡为DHCP模式
        :return: 无返回
        """
        self.textEdit_log.append(
            f'<font color="#12a182">{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())}->为避免您的网络配置'
            f'影响分机连接,已经自动将已启用的网卡设置为DHCP模式。</font>')
        for i in range(self.comboBox_class.count()):
            networkcardname = self.comboBox_class.itemText(i)
            self.worker_set_all_networkcard_dhcp = Worker(Set_Computer_Network_Card_Dhcp, bool, (networkcardname,))
            self.worker_set_all_networkcard_dhcp.finished_bool.connect(self.set_all_networkcard_dhcp_callback)
            self.worker_set_all_networkcard_dhcp.start()
            self.textEdit_log.append(
                f'<font color="#12a182">{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())}->设置网卡{networkcardname}'
                f'为DHCP模式。🆗</font>')

    def update_device_config_table(self, ip: str, data: list, mode: int):
        """
        子线程:向可视对讲分机下发配置表,在set_networkcard_config_callback_1函数执行后调用
        :return: 无返回
        """
        if mode == 1:
            self.worker_update_device_config_table = Worker(Send_Data_To_Device, bool, (ip, data))
            self.worker_update_device_config_table.finished_bool.connect(self.update_device_config_table_callback_1)
            self.worker_update_device_config_table.start()
        elif mode == 2:
            self.worker_update_device_config_table = Worker(Send_Data_To_Device, bool, (ip, data))
            self.worker_update_device_config_table.finished_bool.connect(self.update_device_config_table_callback_2)
            self.worker_update_device_config_table.start()

    def set_networkcard_ip(self, networkcard_name: str, ip: str, mask: str, gateway: str, mode: int):
        """
        子线程:设置网卡配置,当mode为1时在parsing_device_message_callback函数执行后调用,当mode为2时
        :return: 无返回
        """
        if mode == 1:
            self.worker_set_networkcard_config = Worker(Set_Computer_Network_Card_Ip, bool,
                                                        (networkcard_name, ip, mask, gateway))
            self.worker_set_networkcard_config.finished_bool.connect(self.set_networkcard_config_callback_1)
            self.worker_set_networkcard_config.start()
        elif mode == 2:
            self.worker_set_networkcard_config = Worker(Set_Computer_Network_Card_Ip, bool,
                                                        (networkcard_name, ip, mask, gateway))
            self.worker_set_networkcard_config.finished_bool.connect(self.set_networkcard_config_callback_2)
            self.worker_set_networkcard_config.start()

    def parsing_device_message(self, data, mode: int):
        """
        子线程:解析分机返回消息,在waiting_device_connection_callback函数执行后调用。
        :param mode:
        :param data: str,分机返回的数据包
        :return: 无返回
        """
        if mode == 1:
            self.worker_parsing_device_message = Worker(Parse_Device_Xml, list, (data,))
            self.worker_parsing_device_message.finished_list.connect(self.parsing_device_message_callback_1)
            self.worker_parsing_device_message.start()
        elif mode == 2:
            self.worker_parsing_device_message = Worker(Parse_Device_Xml, list, (data,))
            self.worker_parsing_device_message.finished_list.connect(self.parsing_device_message_callback_2)
            self.worker_parsing_device_message.start()
        elif mode == 3:
            self.worker_parsing_device_message = Worker(Parse_Device_Xml, list, (data,))
            self.worker_parsing_device_message.finished_list.connect(self.parsing_device_message_callback_3)
            self.worker_parsing_device_message.start()

    def waiting_device_connection(self, mode: int):
        """
        子线程:监听可视对讲分机回执消息,等待连接,在pushButton_update_clicked_callback函数执行后调用。
        :return:
        """
        if mode == 1:
            self.worker_waiting_device_connection = Worker(Listen_Device_Info, str)
            self.worker_waiting_device_connection.finished_str.connect(self.waiting_device_connection_callback_1)
            self.worker_waiting_device_connection.start()
        elif mode == 2:
            self.worker_waiting_device_connection = Worker(Listen_Device_Info, str)
            self.worker_waiting_device_connection.finished_str.connect(self.waiting_device_connection_callback_2)
            self.worker_waiting_device_connection.start()
        elif mode == 3:
            self.worker_waiting_device_connection = Worker(Listen_Device_Info, str)
            self.worker_waiting_device_connection.finished_str.connect(self.waiting_device_connection_callback_3)
            self.worker_waiting_device_connection.start()

    def update_comboBox_class(self):
        """
        子线程:更新部门组合框列表项,在initialization_callback函数执行后调用。
        :return: 无返回
        """
        self.worker_update_comboBox_class = Worker(Read_Config_Xls_To_List, list)
        self.worker_update_comboBox_class.finished_list.connect(self.update_comboBox_class_callback)
        self.worker_update_comboBox_class.start()

    def update_comboBox_networkcard(self):
        """
        子线程:更新网卡组合框列表项,在initialization_callback函数执行后调用。
        :return: 无返回
        """
        self.worker_update_comboBox_networkcard = Worker(Get_Pc_Network_Card, list)
        self.worker_update_comboBox_networkcard.finished_list.connect(self.update_comboBox_networkcard_callback)
        self.worker_update_comboBox_networkcard.start()

    def comboBox_networkcard_currentIndex_Changed(self):
        """
        子线程:组合框网卡信息列表项被选择,在MyMainWindow中调用
        :return: 无返回
        """
        self.worker_comboBox_networkcard_currentIndex_Changed = Worker(Get_Networkcard_Ip_And_Netmask, list,
                                                                       (self.comboBox_networkcard.currentText(),))
        self.worker_comboBox_networkcard_currentIndex_Changed.finished_list.connect(
            self.comboBox_networkcard_currentIndex_Changed_callback)
        self.worker_comboBox_networkcard_currentIndex_Changed.start()

    def set_networkcard_dhcp(self, mode: int):
        """
        子线程:设置指定连接名称的网卡为DHCP模式,当mode为1时在pushButton_update_clicked函数执行后调用,当mode为2时
        :param mode:
        :return:
        """
        if mode == 1:
            self.worker_pushButton_update_clicked = Worker(Set_Computer_Network_Card_Dhcp, bool,
                                                           (self.comboBox_networkcard.currentText(),))
            self.worker_pushButton_update_clicked.finished_bool.connect(self.set_networkcard_dhcp_callback_1)
            self.worker_pushButton_update_clicked.start()
        elif mode == 2:
            self.worker_pushButton_update_clicked = Worker(Set_Computer_Network_Card_Dhcp, bool,
                                                           (self.comboBox_networkcard.currentText(),))
            self.worker_pushButton_update_clicked.finished_bool.connect(self.set_networkcard_dhcp_callback_2)
            self.worker_pushButton_update_clicked.start()
        elif mode == 3:
            self.worker_pushButton_update_clicked = Worker(Set_Computer_Network_Card_Dhcp, bool,
                                                           (self.comboBox_networkcard.currentText(),))
            self.worker_pushButton_update_clicked.finished_bool.connect(self.set_networkcard_dhcp_callback_3)
            self.worker_pushButton_update_clicked.start()

    def pushButton_update_clicked(self):
        """
        子线程:按钮一键刷机被点击
        :return: 无返回
        """
        # 禁用网卡和部门组合框选项
        self.comboBox_class.setEnabled(False)
        self.comboBox_networkcard.setEnabled(False)
        # 禁用一键刷机按钮点击
        self.pushButton_update.setEnabled(False)
        # 情况编辑框内容
        self.textEdit_log.clear()
        self.textEdit_device.clear()
        # 启动线程
        self.set_networkcard_dhcp(1)

    def set_all_networkcard_dhcp_callback(self):
        pass

    def comboBox_class_currentIndex_Changed(self):
        """
        组合框部门列表项被选择,在MyMainWindow中调用
        :return: 无返回
        """
        self.comboBox_class_currentIndex_Changed_callback()

    def initialization_callback(self, result):
        """
        执行initialization函数回调
        :param result: 接收initialization程返回值
        :return: 无返回值
        """
        if result:
            self.update_comboBox_class()
            self.update_comboBox_networkcard()
            self.textEdit_log.append(
                f'<font color="#12a182">{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())}->环境初始化完成,'
                f'请选择网卡和部门后执行刷机工作。🆗</font>')

        else:
            # 如果配置表缺失,则禁止点击相关组件
            self.pushButton_update.setEnabled(False)
            self.comboBox_class.setEnabled(False)
            self.textEdit_log.append(
                f'<font color="red">{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())}->未找到配置表,'
                f'请将本软件复制到配置表同级目录后重新运行。🤡</font>')

    def update_comboBox_class_callback(self, result):
        """
        执行update_comboBox_class函数回调
        :param result: 接收update_comboBox_class返回值
        :return: 无返回值
        """
        for key in result:
            self.comboBox_class.addItems(key.keys())  # 在槽函数中向comboBox中添加项
        self.textEdit_log.append(
            f'<font color="#74759b">{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())}->请选择需要刷入的部门名称,'
            f'该选择与写入分机号关联。😊</font>')

    def update_comboBox_networkcard_callback(self, result):
        """
        执行update_comboBox_networkcard函数回调
        :param result: 接收update_comboBox_networkcard返回值
        :return: 无返回
        """
        self.comboBox_networkcard.addItems(result)
        self.textEdit_log.append(
            f'<font color="#bec936">{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())}->请选择与可视对讲分机连接的网络适配器,'
            f'错选可能搜索不到分机!⚠</font>')

    def comboBox_networkcard_currentIndex_Changed_callback(self, result):
        """
        执行comboBox_networkcard_currentIndex_Changed函数回调
        :param result: 接收comboBox_networkcard_currentIndex_Changed返回值
        :return: 无返回
        """
        # 先清空内容,在写入数据。
        self.textEdit_networkadapter.clear()
        if len(result) > 0:
            self.textEdit_networkadapter.append(f'<font color="black">IP:{result[0]}<br/>子网掩码:{result[1]}</font>')

    def comboBox_class_currentIndex_Changed_callback(self):
        """
        执行comboBox_class_currentIndex_Changed函数回调
        :return: 无返回
        """
        # 先清空内容,在写入数据。
        self.textEdit_configlabel.clear()
        class_name = self.comboBox_class.currentText()
        for con_dict in config_table_list:
            if class_name in con_dict:
                value = con_dict[class_name]
                split_text = value.split('|')
                self.textEdit_configlabel.append(
                    f'<font color="black">分机号:{split_text[0]}<br/>IP地址:{split_text[1]}<br/>子网掩码:{split_text[2]}<br'
                    f'/>网关地址:{split_text[3]}</font>')
                device_config_list.clear()
                device_config_list.extend([split_text[0], split_text[1], split_text[2], split_text[3]])

    def set_networkcard_dhcp_callback_1(self, result):
        if result:
            self.textEdit_log.append(
                f'<font color="green">{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())}->设置网卡:{self.comboBox_networkcard.currentText()}DHCP模式成功。</font>')
            self.textEdit_log.append(
                f'<font color="blue">{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())}->等待可视对讲分机连接中。</font>')
            self.waiting_device_connection(1)
        else:
            self.textEdit_log.append(
                f'<font color="red">{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())}->设置网卡:{self.comboBox_networkcard.currentText()}DHCP模式失败,请检查该网卡运行状态!</font>')

    def set_networkcard_dhcp_callback_2(self, result):
        if result:
            self.textEdit_log.append(
                f'<font color="green">{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())}->设置网卡:{self.comboBox_networkcard.currentText()}DHCP模式成功。</font>')
            self.textEdit_log.append(
                f'<font color="blue">{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())}->等待可视对讲分机连接中。</font>')
            self.waiting_device_connection(2)
        else:
            self.textEdit_log.append(
                f'<font color="red">{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())}->设置网卡:{self.comboBox_networkcard.currentText()}DHCP模式失败,请检查该网卡运行状态!</font>')

    def set_networkcard_dhcp_callback_3(self, result):
        if result:
            self.textEdit_log.append(
                f'<font color="green">{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())}->设置网卡:{self.comboBox_networkcard.currentText()}DHCP模式成功。</font>')
            self.textEdit_log.append(
                f'<font color="blue">{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())}->等待可视对讲分机连接中。</font>')
            self.waiting_device_connection(3)
        else:
            self.textEdit_log.append(
                f'<font color="red">{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())}->设置网卡:{self.comboBox_networkcard.currentText()}DHCP模式失败,请检查该网卡运行状态!</font>')

    def waiting_device_connection_callback_1(self, result):
        self.parsing_device_message(result, 1)

    def waiting_device_connection_callback_2(self, result):
        self.parsing_device_message(result, 2)

    def waiting_device_connection_callback_3(self, result):
        self.parsing_device_message(result, 3)

    def parsing_device_message_callback_1(self, result):
        self.textEdit_log.append(
            f'<font color="green">{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())}->来自{result[2]}的分机:{result[1]}-已连接。</font>\n')
        self.textEdit_device.append(
            f'<font color="black">设备ID:{result[0]}<br>设备名称:{result[1]}<br>IP地址:{result[2]}<br>子网掩码:{result[3]}<br>网关地址:{result[4]}</font>')
        self.set_networkcard_ip(self.comboBox_networkcard.currentText(), str(ipaddress.ip_address(result[2]) + 1),
                                result[3], result[4], 1)

    def parsing_device_message_callback_2(self, result):
        self.textEdit_log.append(
            f'<font color="green">{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())}->来自{result[2]}的分机:{result[1]}-已连接。</font>\n')
        self.textEdit_device.append(
            f'<font color="black">设备ID:{result[0]}<br>设备名称:{result[1]}<br>IP地址:{result[2]}<br>子网掩码:{result[3]}<br>网关地址:{result[4]}</font>')
        self.set_networkcard_ip(self.comboBox_networkcard.currentText(), str(ipaddress.ip_address(result[2]) + 1),
                                result[3], result[4], 2)

    def parsing_device_message_callback_3(self, result):
        self.textEdit_log.append(
            f'<font color="green">{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())}->刷机完成,新设备分区号:{result[0]}'
            f'-设备名称:{result[1]}-IP地址:{result[2]}-子网掩码:{result[3]}</font>\n')
        self.comboBox_class.setEnabled(True)
        self.comboBox_networkcard.setEnabled(True)
        self.pushButton_update.setEnabled(True)

    def set_networkcard_config_callback_1(self, result):
        self.textEdit_log.append(
            f'<font color="blue">{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())}->配置网卡:{self.comboBox_networkcard.currentText()}为静态IP地址。</font>\n')
        if result:
            self.update_device_config_table(device_information_list[2],
                                            ['BBBB666604100A0000000000000000000000000000000000', '367A0100',
                                             Read_Config_Xml()], 1)

    def set_networkcard_config_callback_2(self, result):
        self.textEdit_log.append(
            f'<font color="blue">{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())}->配置网卡:{self.comboBox_networkcard.currentText()}为静态IP地址。</font>\n')
        if result:
            self.update_device_config_table(device_information_list[2],
                                            [Extension_Number_Packaging(device_config_list[0])], 2)

    def update_device_config_table_callback_1(self, result):
        if result:
            self.textEdit_log.append(
                f'<font color="green">{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())}->向可视对讲分机下发配置表成功,'
                f'等待设备重启中。</font>\n')
            self.set_networkcard_dhcp(2)
        else:
            self.textEdit_log.append(
                f'<font color="red">{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())}->向可视对讲分机下发配置表失败,'
                f'要不试试看官方的刷机工具叭😂。</font>\n')
            self.comboBox_class.setEnabled(True)
            self.comboBox_networkcard.setEnabled(True)
            self.pushButton_update.setEnabled(True)

    def update_device_config_table_callback_2(self, result):
        if result:
            self.textEdit_log.append(
                f'<font color="green">{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())}->写入可视对讲分机号成功,'
                f'等待设备重启中。</font>\n')
            self.set_networkcard_dhcp(3)
        else:
            self.textEdit_log.append(
                f'<font color="red">{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())}->写入可视对讲分机号失败,'
                f'要不试试看官方的刷机工具叭😂。</font>\n')


if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = MyMainWindow()
    window.show()
    sys.exit(app.exec())