传感器数据模拟软件【StreamFaker】【带界面】【发送到Rabbitmq】【python3+pyqt5实现】

Background

  • 大家都知道哈,我做的基本都是传感器监测类项目,很多项目开发时传感器都没安装呢,所以没有数据。但是,项目在开发中,没有数据的话,数据处理逻辑和接口很难开发,即使写出来了没数据测试也是不放心的哈。
  • 所以,就有了这个软件,模拟假数据(另一篇博客中也提到过【传感器监测数据实时存储、计算和展示(RabbitMQ-Flink-InfluxDB)】哈,那个版本还是没有UI的,还有很多bug的)。
  • 那,【StreamFaker】【提取码:king】这是最终版的带UI操作界面,界面比较丑哈,我这里只注重功能性哈,以后有机会再美化吧。
  • 说实话,数据模拟还是挺麻烦的。下面我简单介绍下软件的基本信息和使用方法。

1、先上软件最终效果哈

有些功能没有实现哈,这里说下能用的话,其他的也不怎么用的到,所以后来没在整了。
第一行菜单栏

  • StreamFaker:软件名,自己起的,这个名字我用了,你们不许用咯;
  • dev:测试环境(支持不同的开发环境);
  • cr11g_landslip:项目名简写(不同的项目使用时修改下配置就行了);

第二行

  • 项目管理和设置这两个按钮没用哈,在配置里(configures.xls)直接修改;

第三行

  • 项目管理和设置这两个按钮没用哈,在配置里(configures.xls)直接修改;
  • 启动/停止和退出可以使用的;

第四行传感器选择

  • 就是个摆设,复选框也没用哈,在配置里(configures.xls)直接修改;

第五行运行状态

  • 这个可以用哈,运行时就是黄灯,停止时就是灰色的灯;

最后一行

  • 是否推送MQ:摆设哈;
  • 是否打开日志:可以用哈,发送的数据会存储在日志文件中(StreamFaker.log);

在这里插入图片描述

2、传感器信息

我们项目中的传感器,不同的类型有不同的指标,如下图所示,有的指标是传感器的监测数据,有的是后面计算出来的

在这里插入图片描述

3、配置文件 configures.xls

我们需要配置rabbitmq(第一个sheet)、项目(第二个sheet)和传感器信息(第三个sheet)。

  • isEnable:使用哪个环境,对应界面上第一行的dev;
  • appNameSuffix:项目名简写,对应界面上第一行的cr11g_landslip;

其他都是rabbitmq的基本配置信息了。

在这里插入图片描述

第二个sheet,key代表的依次为,是否启用,项目id,传感器类型,指标个数,最大值,最小值,数据间隔(即发送的数据频率,单位秒);

在这里插入图片描述

第三个sheet,是每个类型下的传感器id。

在这里插入图片描述

4、源码

需要 imgs目录和configures.xls配置文件

在这里插入图片描述

import datetime
import logging
import os
import random
import sys
import threading
import time
from logging import handlers

import pika
import xlrd
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QApplication
from PyQt5.QtWidgets import QComboBox, QPushButton, QSpinBox

# 软件名称
from pika import BasicProperties

self_name = 'StreamFaker'
# 停止标志
stop_flag = False
# 是否生成日志标志
log_flag = True


# 日志级别关系映射
class Logger(object):
    level_relations = {
        'debug': logging.DEBUG,
        'info': logging.INFO,
        'warning': logging.WARNING,
        'error': logging.ERROR,
        'critical': logging.CRITICAL
    }

    def __init__(self, filename, level='info', when='D', backCount=3, fmt='%(asctime)s - %(levelname)s: %(message)s'):
        self.logger = logging.getLogger(filename)
        format_str = logging.Formatter(fmt)  # 设置日志格式
        self.logger.setLevel(self.level_relations.get(level))  # 设置日志级别
        sh = logging.StreamHandler()  # 往屏幕上输出
        sh.setFormatter(format_str)  # 设置屏幕上显示的格式
        th = handlers.TimedRotatingFileHandler(filename=filename, when=when, backupCount=backCount,
                                               encoding='utf-8')  # 往文件里写入#指定间隔时间自动生成文件的处理器
        # 实例化TimedRotatingFileHandler
        # interval是时间间隔,backupCount是备份文件的个数,如果超过这个个数,就会自动删除,when是间隔的时间单位,单位有以下几种:
        # S 秒
        # M 分
        # H 小时、
        # D 天、
        # W 每星期(interval==0时代表星期一)
        # midnight 每天凌晨
        th.setFormatter(format_str)  # 设置文件里写入的格式
        self.logger.addHandler(sh)  # 把对象加到logger里
        self.logger.addHandler(th)


# 日志文件名
log = Logger(self_name + '.log')


class Configure:
    # 读取配置文件
    rd = xlrd.open_workbook('configures.xls')

    # 获取 rabbitmq 的配置信息 sheet
    rabbitmq_sheet = rd.sheet_by_name('rabbitmq')
    # 获取传感器的基本信息
    baseInfo_sheet = rd.sheet_by_name('baseInfo')
    # 获取传感器类型和通讯标号信息
    serialNumber_sheet = rd.sheet_by_name('serialNumber')

    # 获取传感器的基本配置信息
    def get_sensor_conf(self):
        """
        列表元素为字典结构:
        conf_sensor = {
            'projectId': '27',
            'targetType': '21',
            'serialNumbers': [1, 3, 5],
            'quotaAmount': 5,
            'minValue': 1,
            'maxValue': 10,
            'interval': 100
            }
        """
        # 最终返回列表,列表元素为字典结构
        list_conf = []
        # 获取总列数
        cols = self.baseInfo_sheet.ncols
        # 以第一列为字典的 key
        dict_keys = self.baseInfo_sheet.col_values(0)
        # 遍历所有列,其中列的 isEnable 为 1 的列作为字典的 value
        for col_index in range(1, cols):
            # 判断每列的第二行的数据是否 为 1
            col = self.baseInfo_sheet.col_values(col_index)
            if int(col[1]) == 1:
                dict_values = col
                # 放入字典结构中
                conf_sensor = {}
                organize_dict(conf_sensor, dict_keys, dict_values)
                list_conf.append(conf_sensor)
        # 获取唯一id, targetType 和 serialNumbers 的对应关系
        sc_dict = self.get_serial_number()
        # 根据 pid、targetType 和 serialNumbers 的对应关系放入字段结构中
        for conf in list_conf:
            key = conf['key']
            tt = conf['targetType']
            conf_key = key + '_' + tt
            conf['serialNumbers'] = sc_dict[conf_key]
        for cfg in list_conf:
            cfg.pop('key')
            cfg.pop('isEnable')
        return list_conf

    # 获取各项目的传感器类型和通讯编号信息
    def get_serial_number(self):
        # 最终返回字典结构 key: pid_tt    value: [sc]
        sc_dict = {}
        # 获取总列数
        cols = self.serialNumber_sheet.ncols
        # 遍历所有列
        for col_index in range(0, cols):
            # 每列的第一个值为唯一id,第二个值为类型,其它值为 sc
            pid = self.serialNumber_sheet.col_values(col_index)[0]
            tt = self.serialNumber_sheet.col_values(col_index)[1]
            sc = self.serialNumber_sheet.col_values(col_index)[2:]
            # 把空值去掉
            sc = list(filter(None, sc))
            # 把数值转成 int
            sc = [int(v) for v in sc]
            # 字典结构的 key
            dict_key = str(pid) + '_' + str(int(tt))
            # 放入字典结构
            sc_dict[dict_key] = sc
        # 返回数据
        return sc_dict

    # 获取 rabbitmq 的配置信息
    def get_rabbitmq_conf(self):
        """
        最终返回字典结构:
        conf_rabbitmq = {
            'env': 'dev',
            'host': 'elephant',
            'port': 5672,
            'vHost': 'panda',
            'username': 'panda',
            'password': 'Rabbit1234!',
            'exchange': 'dky_cft',
            'routingKey': 'payload'
            }
        """
        # 最终返回字典结构
        conf_rabbitmq = {}
        # 获取总列数
        cols = self.rabbitmq_sheet.ncols
        # 以第一列为字典的 key
        dict_keys = self.rabbitmq_sheet.col_values(0)[2:]
        # 遍历所有列,其它列的 isEnable 为 1 的列作为字典的 value
        for col_index in range(1, cols):
            # 判断每列的第二行的数据是否 为 1
            col = self.rabbitmq_sheet.col_values(col_index)
            if int(col[1]) == 1:
                env = col[0]
                conf_rabbitmq['env'] = env
                dict_values = col[2:]
                organize_dict(conf_rabbitmq, dict_keys, dict_values)
        return conf_rabbitmq


# 组织字典结构数据
def organize_dict(conf_dict, dict_keys, dict_values):
    # 数值为 int 的 key
    int_keys = ['port', 'projectId', 'targetType', 'quotaAmount', 'interval']
    str_keys = ['projectId', 'targetType']
    for index in range(0, len(dict_keys)):
        dict_key = dict_keys[index]
        dict_value = dict_values[index]
        if dict_key in int_keys:
            dict_value = int(dict_value)
        if dict_key in str_keys:
            dict_value = str(dict_value)
        conf_dict[dict_key] = dict_value


class RabbitMQUtil(object):
    """
    构造方法:
    config = {
        'host': '192.168.18.155',
        'port': 5672,
        'vHost': 'panda',
        'username': 'panda',
        'password': 'Rabbit1234!',
        'exchange': 'sensorPayload_test',
        'routingKey': 'payload'
        }
    """

    # 初始化配置
    def __init__(self, conf):
        super().__init__()
        self.host = conf['host']
        self.port = conf['port']
        self.vHost = conf['vHost']
        self.username = conf['username']
        self.password = conf['password']
        self.exchange = conf['exchange']
        self.routingKey = conf['routingKey']
        self.credential = None
        self.connection = None
        self.channel = None

        try:
            self.credential = pika.PlainCredentials(self.username, self.password)
            self.connection = pika.BlockingConnection(
                pika.ConnectionParameters(self.host, self.port, self.vHost, self.credential))
            self.channel = self.connection.channel()
        except():
            print("connect error, please check the config")

    # 发布消息
    def public_msg(self, json):
        # body = json.dumps({"test": "test"})
        self.channel.basic_publish(
            exchange=self.exchange,
            routing_key=self.routingKey,
            body=json
            # properties=BasicProperties.FLAG_DELIVERY_MODE
        )

    # 接收处理消息的回调函数
    def callback(self, body):
        super()
        print(str(body).replace('b', '').replace('\'', ''))

    # 订阅消息
    def consume_msg(self, queue):
        self.channel.queue_declare(queue=queue, durable=True, arguments={"x-message-ttl": 259200000})
        self.channel.basic_consume(queue, self.callback, True)
        self.channel.start_consuming()

    # 关闭连接
    def close(self):
        if not self.connection:
            self.connection.close()
        else:
            print("connection already disconnected")


class MsgUtil(object):
    """
    构造方法:
    config = {
        'projectId': '23',
        'targetType': '1',
        'serialNumbers': [1,5,6,7],
        'targetAmount': 4,
        'quotaAmount': 6,
        'minValue': 1,
        'maxValue': 10
        }
    """

    def __init__(self, conf):
        self.projectId = conf['projectId']
        self.targetType = conf['targetType']
        self.serialNumbers = conf['serialNumbers']
        self.quotaAmount = conf['quotaAmount']
        self.minValue = conf['minValue']
        self.maxValue = conf['maxValue']
        self.funCode = '1'
        self.reserve = '1'
        self.targetAmount = None
        self.timestamp = None

    # 获取逗号分隔的字符串(项目id,时间(17位字符串),功能码,测点类型,预留字节,测定个数,指标个数,测点1id,指标1数值,指标2数值,...,测点2id,指标1数值,指标2数值,...,)
    # 例子:100,20201015170020100,1,14,1,2,3,1,-7.182,-6.868,2.397,23,-9.077,5.666,-6.547
    def get_msg(self):
        self.targetAmount = len(self.serialNumbers)
        self.timestamp = get_format_time()
        base_info_seq = (self.projectId, str(self.timestamp), self.funCode, self.targetType, self.reserve,
                         str(self.targetAmount), str(self.quotaAmount))
        val_seq = ()
        for serialCode in self.serialNumbers:
            val_seq = val_seq + (str(serialCode),)
            for i in range(1, self.quotaAmount + 1):
                random_value = get_random_value(self.minValue, self.maxValue)
                val_seq = val_seq + (random_value,)

        return get_comma_str(base_info_seq, val_seq)


# 自定义线程类,指定频率向 RabbitMQ 发送消息
class MyThread(threading.Thread):
    conn = None

    def __init__(self, thread_id, interval, msg_util):
        threading.Thread.__init__(self)
        self.thread_id = thread_id
        self.interval = interval * 1000 * 1000
        self.msg_util = msg_util
        self.__running = threading.Event()  # 用于停止线程的标识
        self.__running.set()  # 将running设置为True
        self.conn = get_rabbit_connection()
        self._stop_event = threading.Event()

    def run(self):
        lastTime = 0
        while self.__running.isSet():
            message = self.msg_util.get_msg()
            thisTime = get_nano_now()
            diffTime = thisTime - lastTime
            if diffTime < self.interval:
                # 休眠
                delay = (self.interval - diffTime) / (1000 * 1000 * 1000)
                # print("===============< 休眠 >=================", delay)
                time.sleep(delay)
            # 判断是否已停止
            if stop_flag:
                return
            # 发布消息
            if log_flag:
                log.logger.info(message)
            # print(message)
            self.conn.public_msg(message)
            lastTime = get_nano_now()

    def stop(self):
        self.__running.clear()  # 设置为False
        self._stop_event.set()


# 获取获逗号分隔的字符串,参数是元素为字符串的 tuple
def get_comma_str(*params):
    comma = ','
    res = ()
    for p in params:
        res = res + p
    return comma.join(res)


# 获取获取指定范围的一个随机数(字符串类型),保留三位小数
def get_random_value(minValue, maxValue):
    return str(round(random.uniform(minValue, maxValue), 5))


# 获取当前时间,格式:20200929173338500
def get_format_time():
    now = datetime.datetime.now()
    return now.strftime("%Y%m%d%H%M%S%f")[:-3]


# 获取13位当前毫秒时间戳,格式:1602747077320
def get_nano_now():
    return time.time_ns()


# 获取 RabbitMQ 连接
def get_rabbit_connection():
    config = Configure()
    return RabbitMQUtil(config.get_rabbitmq_conf())


# 获取启动后 app 的名字
def get_app_name():
    config = Configure()
    env = config.get_rabbitmq_conf()["env"]
    app_name_suffix = config.get_rabbitmq_conf()["appNameSuffix"]
    if app_name_suffix is None or app_name_suffix == "":
        app_name_suffix = get_current_os_dir()
    return self_name + "【" + env + "】" + "【" + app_name_suffix + "】"


# 获取当前系统目录名
def get_current_os_dir():
    dirs = os.path.split(os.path.realpath(__file__))[0].split("\\")
    return dirs[len(dirs) - 1]


# UI 界面
class Ui_mainWindow(object):

    def setupUi(self, mainWindow):
        mainWindow.setObjectName("mainWindow")
        mainWindow.resize(799, 571)
        mainWindow.setMouseTracking(True)
        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap("imgs/wlf.ico"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
        mainWindow.setWindowIcon(icon)
        mainWindow.setAutoFillBackground(False)
        mainWindow.setStyleSheet("background-color: rgb(218, 238, 237);")

        # mainWindow【主窗口】
        self.centralwidget = QtWidgets.QWidget(mainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.frame = QtWidgets.QFrame(self.centralwidget)
        self.frame.setGeometry(QtCore.QRect(0, 50, 801, 81))
        self.frame.setStyleSheet("background-color: rgb(158, 178, 209);")
        self.frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
        self.frame.setFrameShadow(QtWidgets.QFrame.Raised)
        self.frame.setObjectName("frame")

        # QPushButton【项目管理】
        self.pushButton = QtWidgets.QPushButton(self.frame)
        self.pushButton.setGeometry(QtCore.QRect(120, 20, 91, 41))
        font = QtGui.QFont()
        font.setFamily("Arial")
        font.setBold(True)
        font.setWeight(75)
        self.pushButton.setFont(font)
        self.pushButton.setStyleSheet("background-color: rgb(90, 181, 134);")
        icon1 = QtGui.QIcon()
        icon1.addPixmap(QtGui.QPixmap("imgs/home-filling.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.pushButton.setIcon(icon1)
        self.pushButton.setIconSize(QtCore.QSize(25, 25))
        self.pushButton.setObjectName("pushButton")

        # QPushButton【设置】
        self.pushButton_2 = QtWidgets.QPushButton(self.frame)
        self.pushButton_2.setGeometry(QtCore.QRect(280, 20, 91, 41))
        font = QtGui.QFont()
        font.setBold(True)
        font.setWeight(75)
        self.pushButton_2.setFont(font)
        self.pushButton_2.setStyleSheet("background-color: rgb(90, 181, 134);")
        icon2 = QtGui.QIcon()
        icon2.addPixmap(QtGui.QPixmap("imgs/setting-filling.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.pushButton_2.setIcon(icon2)
        self.pushButton_2.setIconSize(QtCore.QSize(25, 25))
        self.pushButton_2.setObjectName("pushButton_2")

        # QPushButton【开始】
        self.pushButton_3 = QtWidgets.QPushButton(self.frame)
        self.pushButton_3.setGeometry(QtCore.QRect(430, 20, 91, 41))
        font = QtGui.QFont()
        font.setBold(True)
        font.setWeight(75)
        self.pushButton_3.setFont(font)
        self.pushButton_3.setStyleSheet("background-color: rgb(90, 181, 134);")
        icon3 = QtGui.QIcon()
        icon3.addPixmap(QtGui.QPixmap("imgs/play-fill.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.pushButton_3.setIcon(icon3)
        self.pushButton_3.setIconSize(QtCore.QSize(30, 30))
        self.pushButton_3.setCheckable(False)
        self.pushButton_3.setChecked(False)
        self.pushButton_3.setDefault(False)
        self.pushButton_3.setObjectName("pushButton_3")

        # QPushButton【停止】
        self.pushButton_4 = QtWidgets.QPushButton(self.frame)
        self.pushButton_4.setGeometry(QtCore.QRect(430, 20, 91, 41))
        font = QtGui.QFont()
        font.setBold(True)
        font.setWeight(75)
        self.pushButton_4.setFont(font)
        self.pushButton_4.setStyleSheet("background-color: rgb(90, 181, 134);")
        icon4 = QtGui.QIcon()
        icon4.addPixmap(QtGui.QPixmap("imgs/suspended-fill.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.pushButton_4.setIcon(icon4)
        self.pushButton_4.setIconSize(QtCore.QSize(30, 30))
        self.pushButton_4.setCheckable(False)
        self.pushButton_4.setChecked(False)
        self.pushButton_4.setObjectName("pushButton_4")

        # QPushButton【退出】
        self.pushButton_5 = QtWidgets.QPushButton(self.frame)
        self.pushButton_5.setGeometry(QtCore.QRect(580, 20, 91, 41))
        font = QtGui.QFont()
        font.setBold(True)
        font.setWeight(75)
        self.pushButton_5.setFont(font)
        self.pushButton_5.setStyleSheet("background-color: rgb(90, 181, 134);")
        icon5 = QtGui.QIcon()
        icon5.addPixmap(QtGui.QPixmap("imgs/exit1.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.pushButton_5.setIcon(icon5)
        self.pushButton_5.setIconSize(QtCore.QSize(21, 21))
        self.pushButton_5.setObjectName("pushButton_5")

        # QPushButton【设置】
        self.pushButton_7 = QtWidgets.QPushButton(self.frame)
        self.pushButton_7.setGeometry(QtCore.QRect(280, 20, 91, 41))
        font = QtGui.QFont()
        font.setBold(True)
        font.setWeight(75)
        self.pushButton_7.setFont(font)
        self.pushButton_7.setStyleSheet("background-color: rgb(227, 0, 0);")
        self.pushButton_7.setIcon(icon2)
        self.pushButton_7.setIconSize(QtCore.QSize(25, 25))
        self.pushButton_7.setObjectName("pushButton_7")
        self.pushButton_4.raise_()
        self.pushButton_3.raise_()
        self.pushButton_7.raise_()
        self.pushButton.raise_()
        self.pushButton_2.raise_()
        self.pushButton_5.raise_()

        # QPushButton【启用传感器展示】
        self.groupBox = QtWidgets.QGroupBox(self.centralwidget)
        self.groupBox.setGeometry(QtCore.QRect(100, 170, 591, 101))
        font = QtGui.QFont()
        font.setBold(False)
        font.setWeight(50)
        self.groupBox.setFont(font)
        self.groupBox.setStyleSheet("background-color: rgb(114, 230, 171);")
        self.groupBox.setObjectName("groupBox")
        self.checkBox = QtWidgets.QCheckBox(self.groupBox)
        self.checkBox.setGeometry(QtCore.QRect(20, 40, 71, 16))
        self.checkBox.setObjectName("checkBox")
        self.checkBox_2 = QtWidgets.QCheckBox(self.groupBox)
        self.checkBox_2.setGeometry(QtCore.QRect(80, 40, 71, 16))
        self.checkBox_2.setObjectName("checkBox_2")
        self.groupBox_2 = QtWidgets.QGroupBox(self.centralwidget)
        self.groupBox_2.setGeometry(QtCore.QRect(100, 310, 221, 111))
        self.groupBox_2.setLayoutDirection(QtCore.Qt.LeftToRight)
        self.groupBox_2.setStyleSheet("background-color: rgb(114, 230, 171);")
        self.groupBox_2.setObjectName("groupBox_2")

        # QPushButton【运行状态】
        self.pushButton_6 = QtWidgets.QPushButton(self.groupBox_2)
        self.pushButton_6.setGeometry(QtCore.QRect(50, 20, 121, 81))
        self.pushButton_6.setLayoutDirection(QtCore.Qt.LeftToRight)
        self.pushButton_6.setText("")
        icon6 = QtGui.QIcon()
        icon6.addPixmap(QtGui.QPixmap("imgs/lamp-off.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.pushButton_6.setIcon(icon6)
        self.pushButton_6.setIconSize(QtCore.QSize(70, 70))
        self.pushButton_6.setCheckable(False)
        self.pushButton_6.setChecked(False)
        self.pushButton_6.setObjectName("pushButton_6")

        # QPushButton【运行状态】
        self.pushButton_8 = QtWidgets.QPushButton(self.groupBox_2)
        self.pushButton_8.setGeometry(QtCore.QRect(50, 20, 121, 81))
        self.pushButton_8.setLayoutDirection(QtCore.Qt.LeftToRight)
        self.pushButton_8.setText("")
        icon7 = QtGui.QIcon()
        icon7.addPixmap(QtGui.QPixmap("imgs/lamp-on.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.pushButton_8.setIcon(icon7)
        self.pushButton_8.setIconSize(QtCore.QSize(70, 70))
        self.pushButton_8.setCheckable(False)
        self.pushButton_8.setChecked(False)
        self.pushButton_8.setObjectName("pushButton_8")
        self.pushButton_8.raise_()
        self.pushButton_6.raise_()

        # QCheckBox【mqtt】
        self.checkBox_3 = QtWidgets.QCheckBox(self.centralwidget)
        self.checkBox_3.setGeometry(QtCore.QRect(100, 460, 111, 31))
        self.checkBox_3.setStyleSheet("background-color: rgb(114, 230, 171);")
        icon8 = QtGui.QIcon()
        icon8.addPixmap(QtGui.QPixmap("imgs/notification-filling-off.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
        icon8.addPixmap(QtGui.QPixmap("imgs/notification-filling-on.png"), QtGui.QIcon.Normal, QtGui.QIcon.On)
        self.checkBox_3.setIcon(icon8)
        self.checkBox_3.setIconSize(QtCore.QSize(20, 20))
        self.checkBox_3.setCheckable(True)
        self.checkBox_3.setChecked(False)
        self.checkBox_3.setObjectName("checkBox_3")

        # QCheckBox【日志】
        self.checkBox_4 = QtWidgets.QCheckBox(self.centralwidget)
        self.checkBox_4.setGeometry(QtCore.QRect(220, 460, 121, 31))
        self.checkBox_4.setStyleSheet("background-color: rgb(114, 230, 171);")
        icon9 = QtGui.QIcon()
        icon9.addPixmap(QtGui.QPixmap("imgs/file-common-filling.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.checkBox_4.setIcon(icon9)
        self.checkBox_4.setIconSize(QtCore.QSize(20, 20))
        self.checkBox_4.setObjectName("checkBox_4")

        # QTableWidget【传感器类型】
        self.tableWidget = QtWidgets.QTableWidget(self.centralwidget)
        self.tableWidget.setEnabled(True)
        self.tableWidget.setGeometry(QtCore.QRect(80, 130, 641, 371))
        self.tableWidget.setBaseSize(QtCore.QSize(0, 0))
        font = QtGui.QFont()
        font.setBold(False)
        font.setWeight(50)
        self.tableWidget.setFont(font)
        self.tableWidget.setStyleSheet("background-color: rgb(153, 153, 0);")
        self.tableWidget.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
        self.tableWidget.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        self.tableWidget.setDragEnabled(False)
        self.tableWidget.setAlternatingRowColors(False)
        self.tableWidget.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection)
        self.tableWidget.setGridStyle(QtCore.Qt.SolidLine)
        self.tableWidget.setWordWrap(True)
        self.tableWidget.setRowCount(15)
        self.tableWidget.setObjectName("tableWidget")
        self.tableWidget.hide()
        self.tableWidget.setColumnCount(6)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setHorizontalHeaderItem(0, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setHorizontalHeaderItem(1, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setHorizontalHeaderItem(2, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setHorizontalHeaderItem(3, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setHorizontalHeaderItem(4, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setHorizontalHeaderItem(5, item)
        mainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(mainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 799, 23))
        self.menubar.setObjectName("menubar")
        self.menu = QtWidgets.QMenu(self.menubar)
        self.menu.setObjectName("menu")
        self.menu_2 = QtWidgets.QMenu(self.menubar)
        self.menu_2.setObjectName("menu_2")
        mainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(mainWindow)
        self.statusbar.setObjectName("statusbar")
        mainWindow.setStatusBar(self.statusbar)
        self.menubar.addAction(self.menu.menuAction())
        self.menubar.addAction(self.menu_2.menuAction())

        # 设置按钮点击动作
        self.reTranslateUi(mainWindow)
        self.pushButton_3.clicked.connect(self.pushButton_4.show)
        self.pushButton_3.clicked.connect(mainWindow.start)
        self.pushButton_4.clicked.connect(self.pushButton_4.hide)
        self.pushButton_4.clicked.connect(mainWindow.stop)
        self.pushButton_4.clicked.connect(self.pushButton_3.show)
        self.pushButton_4.clicked.connect(self.pushButton_6.show)
        self.pushButton_5.clicked.connect(mainWindow.close)
        self.pushButton_5.clicked.connect(mainWindow.stop)
        self.pushButton_2.clicked.connect(self.tableWidget.show)
        self.pushButton_2.clicked.connect(self.pushButton_7.show)
        self.pushButton_7.clicked.connect(self.pushButton_2.show)
        self.pushButton_7.clicked.connect(self.tableWidget.hide)
        self.pushButton_2.clicked.connect(self.pushButton_2.hide)
        self.pushButton_7.clicked.connect(self.pushButton_7.hide)
        self.pushButton_3.clicked.connect(self.pushButton_3.hide)
        self.pushButton_3.clicked.connect(self.pushButton_8.show)
        self.pushButton_4.clicked.connect(self.pushButton_8.hide)
        self.pushButton_3.clicked.connect(self.pushButton_6.hide)
        self.checkBox_4.clicked.connect(mainWindow.set_log_flag)
        QtCore.QMetaObject.connectSlotsByName(mainWindow)

    def reTranslateUi(self, mainWindow):
        _translate = QtCore.QCoreApplication.translate
        mainWindow.setWindowTitle(_translate("mainWindow", get_app_name()))
        self.pushButton.setText(_translate("mainWindow", "项目管理"))
        self.pushButton_2.setText(_translate("mainWindow", "设置"))
        self.pushButton_3.setText(_translate("mainWindow", "启动"))
        self.pushButton_4.setText(_translate("mainWindow", "停止"))
        self.pushButton_5.setText(_translate("mainWindow", "退出"))
        self.pushButton_7.setText(_translate("mainWindow", "保存"))
        self.groupBox.setTitle(_translate("mainWindow", "传感器选择"))
        self.checkBox.setText(_translate("mainWindow", "位移"))
        self.checkBox_2.setText(_translate("mainWindow", "应变"))
        self.groupBox_2.setTitle(_translate("mainWindow", "运行状态"))
        self.checkBox_3.setText(_translate("mainWindow", "是否推送MQ"))
        self.checkBox_4.setText(_translate("mainWindow", "是否打开日志"))
        self.checkBox_4.setChecked(True)
        item = self.tableWidget.horizontalHeaderItem(0)
        item.setText(_translate("mainWindow", "传感器类型"))
        item = self.tableWidget.horizontalHeaderItem(1)
        item.setText(_translate("mainWindow", "最大值"))
        item = self.tableWidget.horizontalHeaderItem(2)
        item.setText(_translate("mainWindow", "最小值"))
        item = self.tableWidget.horizontalHeaderItem(3)
        item.setText(_translate("mainWindow", "频率(Hz)"))
        item = self.tableWidget.horizontalHeaderItem(4)
        item.setText(_translate("mainWindow", "数量"))
        item = self.tableWidget.horizontalHeaderItem(5)
        item.setText(_translate("mainWindow", "是否启用"))
        # 在单元格内放置控件
        comBox = QComboBox()
        comBox.addItems([' 应变', ' 位移'])
        comBox.setStyleSheet('QComboBox{margin:3px}')
        self.tableWidget.setCellWidget(0, 0, comBox)
        comBox = QComboBox()
        comBox.addItems([' 1', ' 10', ' 20'])
        comBox.setStyleSheet('QComboBox{margin:3px}')
        self.tableWidget.setCellWidget(0, 3, comBox)

        # 数量
        spinBox = QSpinBox()
        spinBox.setMinimum(1)
        spinBox.setMaximum(500)
        spinBox.setSingleStep(1)
        spinBox.setStyleSheet('QComboBox{margin:3px}')
        self.tableWidget.setCellWidget(0, 4, spinBox)

        # 是否启用
        selectBtn = QPushButton()
        selectBtn.setDown(False)
        selectBtn.setCheckable(True)
        icon4 = QtGui.QIcon()
        icon4.addPixmap(QtGui.QPixmap("imgs/unchecked.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
        icon4.addPixmap(QtGui.QPixmap("imgs/checked.png"), QtGui.QIcon.Normal, QtGui.QIcon.On)
        selectBtn.setIcon(icon4)
        selectBtn.setStyleSheet('QPushButton{margin:3px}')
        self.tableWidget.setCellWidget(0, 5, selectBtn)

        self.menu.setTitle(_translate("mainWindow", "项目管理"))
        self.menu_2.setTitle(_translate("mainWindow", "设置"))


class MyWindow(QtWidgets.QMainWindow, Ui_mainWindow):
    msg_utils = []
    intervals = []
    thread_list = []
    conn = None

    def __init__(self):
        super(MyWindow, self).__init__()
        self.setupUi(self)
        configure = Configure()
        msg_conf = configure.get_sensor_conf()
        param_list = []
        # 初始化所有配置信息
        for conf in msg_conf:
            msg_util = MsgUtil(conf)
            # 发送时间间隔(ms)
            interval = conf['interval']
            param_list.append(interval)
            param_list.append(msg_util)
        self.intervals = param_list[::2]
        self.msg_utils = param_list[1::2]
        self.conn = get_rabbit_connection()

    # 启动
    def start(self):
        global stop_flag
        stop_flag = False
        # 初始化所有线程
        for i in range(len(self.intervals)):
            interval = self.intervals[i]
            msg_util = self.msg_utils[i]
            thread = MyThread(i, interval, msg_util)
            self.thread_list.append(thread)
        for thread in self.thread_list:
            thread.start()

    # 停止
    def stop(self):
        global stop_flag
        stop_flag = True
        for thread in self.thread_list:
            thread.stop()
        self.thread_list.clear()

    # 设置日志标志
    @staticmethod
    def set_log_flag():
        global log_flag
        if log_flag:
            log_flag = False
        else:
            log_flag = True

    # 对 QMainWindow 类重写,关闭窗口的时候先把进程关闭
    def closeEvent(self, event):
        """
        重写closeEvent方法,实现 QMainWindow 窗体关闭时执行一些代码
        :param event: close()触发的事件
        :return: None
        """
        reply = QtWidgets.QMessageBox.question(self,
                                               self_name,
                                               "是否要退出程序?",
                                               QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No,
                                               QtWidgets.QMessageBox.No)
        if reply == QtWidgets.QMessageBox.Yes:
            self.stop()
            event.accept()
        else:
            event.ignore()

    # 加载配置信息
    @staticmethod
    def load_conf(sp):
        splash.show()
        for i in range(1, 11):  # 模拟主程序加载过程
            time.sleep(0.3)  # 加载数据
            sp.showMessage("Loading... {0}%".format(i * 10), QtCore.Qt.AlignHCenter | QtCore.Qt.AlignBottom, QtCore.Qt.black)
            QtWidgets.qApp.processEvents()  # 允许主进程处理事件
        splash.close()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    splash = QtWidgets.QSplashScreen(QtGui.QPixmap("imgs/load-2.png"))
    splash.showMessage("Loading... 0%", QtCore.Qt.AlignHCenter | QtCore.Qt.AlignBottom, QtCore.Qt.black)
    window = MyWindow()
    window.show()
    window.load_conf(splash)
    sys.exit(app.exec_())

5、最终模拟出来的数据格式

  • 消息格式:项目id,17位时间(yyyyMMddHHmmssSSS),功能码,类型id,预留字节,测定个数,指标个数, 通讯编号,指标1数值,指标2数值,…
  • 逗号分隔的字符串
  • 下图是这个软件的另一个Web版本哈,配合项目基础信息,基本零配置就可以直接模拟数据。

在这里插入图片描述

  • 6
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 13
    评论
您可以使用RabbitMQ、Spring Boot和WebSocket来实现前端可发送和接收消息的功能。下面是一个基本的实现步骤: 1. 首先,确保您的Spring Boot项目中已经添加了RabbitMQ和WebSocket的依赖。 2. 在Spring Boot应用程序中配置RabbitMQ,包括连接配置和队列配置。您可以使用`@Configuration`注解创建一个配置类,并使用`@Bean`注解创建一个`ConnectionFactory`和一个`RabbitTemplate`实例。 3. 创建一个消息接收器(Consumer)来监听RabbitMQ队列中的消息。您可以使用`@RabbitListener`注解将一个方法标记为消息接收器,并指定要监听的队列名称。 4. 在Spring Boot应用程序中配置WebSocket,包括处理器和拦截器等。您可以使用`@Configuration`注解创建一个配置类,并使用`@Bean`注解创建一个`WebSocketHandler`和一个`HandshakeInterceptor`实例。 5. 创建一个WebSocket处理器(Handler)来处理前端发送的消息。您可以实现`WebSocketHandler`接口,并重写相应的方法来处理连接、消息发送和关闭等事件。 6. 在WebSocket处理器中,您可以使用RabbitTemplate将接收到的消息发送RabbitMQ队列中。您可以在处理器的`handleTextMessage()`方法中调用RabbitTemplate的相关方法来发送消息。 7. 在前端页面中,使用JavaScript或其他框架来建立WebSocket连接,并发送和接收消息。您可以使用WebSocket的API来发送和接收消息,并在接收到消息时更新页面内容。 通过以上步骤,您可以实现前端可发送和接收消息的功能。当前端发送消息时,WebSocket处理器会接收到消息并将其发送RabbitMQ队列中。然后,消息接收器会监听该队列,并将消息发送给其他需要接收该消息的客户端。这样,前端页面就可以实现实时的消息发送和接收功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

WaiSaa

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值