现场快递柜状态采集与控制系统

这篇具有很好参考价值的文章主要介绍了现场快递柜状态采集与控制系统。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

题目:现场快递柜状态采集与控制系统
目标:设计实现一个对现场快递柜状态数据采集、显示、参数设置、抽屉打开、保鲜控 制等功能软件系统。

编译环境:Vscode

程序语言:python


UI界面截图:

现场快递柜状态采集与控制系统,python,ui,物联网,vscode

运行状态截图:

现场快递柜状态采集与控制系统,python,ui,物联网,vscode

现场快递柜状态采集与控制系统,python,ui,物联网,vscode

温度曲线截图:

现场快递柜状态采集与控制系统,python,ui,物联网,vscode

 Server.py(主程序代码):

from PySide2.QtCore import QFile    # 导入文件类
from PySide2.QtWidgets import QApplication  # 导入QtWidgets模块
from PySide2.QtUiTools import QUiLoader  # 加载UI文件
import threading  # 线程模块
import serial  # 导入串口模块
from ControlTable import *  # 导入控制表类(用户)
from send import *  # 导入发送模块(用户)
from receive import *  # 导入接收模块(用户)

# 配置串口
portx = "COM2"
bps = 38400
# 超时设置,None:永远等待操作,0为立即返回请求结果,其他值为等待超时时间(单位为秒)
timex = None
ser = serial.Serial(portx, bps, timeout=timex)  # 开启串口通信


class Software:

    def __init__(self):
        # 从文件中加载UI定义
        qfile_Server = QFile("UI/software.ui")
        qfile_Server.open(QFile.ReadOnly)
        qfile_Server.close()
        # 从 UI 定义中动态 创建一个相应的窗口对象
        self.ui = QUiLoader().load(qfile_Server)
        self.ui.Shezhiwendu.setPlaceholderText('请输入温度')
        self.ui.openButton.clicked.connect(self.open)
        self.ui.closeButton.clicked.connect(self.close)
        self.ui.yaStateSet.clicked.connect(self.CompressorSet)
        self.ui.drawer1.clicked.connect(lambda: self.drawer(1))
        self.ui.drawer2.clicked.connect(lambda: self.drawer(2))
        self.ui.drawer3.clicked.connect(lambda: self.drawer(3))
        self.ui.drawer4.clicked.connect(lambda: self.drawer(4))
        self.ui.drawer5.clicked.connect(lambda: self.drawer(5))
        self.ui.drawer6.clicked.connect(lambda: self.drawer(6))
        self.ui.drawer7.clicked.connect(lambda: self.drawer(7))
        self.ui.drawer8.clicked.connect(lambda: self.drawer(8))
        self.ui.drawer9.clicked.connect(lambda: self.drawer(9))
        self.ui.drawer10.clicked.connect(lambda: self.drawer(10))
        self.ui.Shezhiwendu.returnPressed.connect(self.TemptureSet)
        self.ui.setAttritutes.clicked.connect(self.SendAttributes)
        #  定义初始状态参数
        self.yastate = False
        self.drawerStates = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

    def open(self):  # 开机
        self.ui.systemstate.setText('     ' + "运行")
        self.ui.openButton.setEnabled(False)
        self.ui.closeButton.setEnabled(True)
        self.ui.Shezhiwendu.setEnabled(True)
        self.ui.yastate.setEnabled(True)
        self.ui.drawer1.setEnabled(True)
        self.ui.drawer2.setEnabled(True)
        self.ui.drawer3.setEnabled(True)
        self.ui.drawer4.setEnabled(True)
        self.ui.drawer5.setEnabled(True)
        self.ui.drawer6.setEnabled(True)
        self.ui.drawer7.setEnabled(True)
        self.ui.drawer8.setEnabled(True)
        self.ui.drawer9.setEnabled(True)
        self.ui.drawer10.setEnabled(True)

        self.ui.DeviceID.setEnabled(True)
        self.ui.DeviceAddress.setEnabled(True)
        self.ui.readInterpret.setEnabled(True)
        self.ui.ComDelay.setEnabled(True)
        self.ui.temptureSet.setEnabled(True)
        self.ui.temptureError.setEnabled(True)
        self.ui.setAttritutes.setEnabled(True)
        self.ui.yaStateSet.setEnabled(True)

    def close(self):  # 关机
        self.ui.Shezhiwendu.clear()
        self.ui.Shezhiwendu.setEnabled(False)
        self.ui.yastate.setEnabled(False)
        self.ui.Currentwendu.setText("")  # 将文本框置空
        self.ui.yastate.setText("")  # 将文本框置空
        self.ui.systemstate.setText("")  # 将文本框置空
        self.ui.DeviceID.setText("")  # 将文本框置空
        self.ui.temptureSet.setText("")  # 将文本框置空
        self.ui.openButton.setEnabled(True)
        self.ui.closeButton.setEnabled(False)
        # 将文本框置空
        self.ui.drawer1.setText("")
        self.ui.drawer2.setText("")
        self.ui.drawer3.setText("")
        self.ui.drawer4.setText("")
        self.ui.drawer5.setText("")
        self.ui.drawer6.setText("")
        self.ui.drawer7.setText("")
        self.ui.drawer8.setText("")
        self.ui.drawer9.setText("")
        self.ui.drawer10.setText("")
        self.ui.drawer1.setEnabled(False)
        self.ui.drawer2.setEnabled(False)
        self.ui.drawer3.setEnabled(False)
        self.ui.drawer4.setEnabled(False)
        self.ui.drawer5.setEnabled(False)
        self.ui.drawer6.setEnabled(False)
        self.ui.drawer7.setEnabled(False)
        self.ui.drawer8.setEnabled(False)
        self.ui.drawer9.setEnabled(False)
        self.ui.drawer10.setEnabled(False)
        self.ui.DeviceID.setEnabled(False)
        self.ui.DeviceAddress.setEnabled(False)
        self.ui.readInterpret.setEnabled(False)
        self.ui.ComDelay.setEnabled(False)
        self.ui.temptureSet.setEnabled(False)
        self.ui.temptureError.setEnabled(False)
        self.ui.setAttritutes.setEnabled(False)
        self.ui.yaStateSet.setEnabled(False)

    def drawer(self, i):   # 开关抽屉控制
        drawerStates_Send = self.drawerStates
        if i == 1:
            if self.drawerStates[0] == 0:
                drawerStates_Send[0] = 1
            else:
                drawerStates_Send[0] = 0
        elif i == 2:
            if self.drawerStates[1] == 0:
                drawerStates_Send[1] = 1
            else:
                drawerStates_Send[1] = 0
        elif i == 3:
            if self.drawerStates[2] == 0:
                drawerStates_Send[2] = 1
            else:
                drawerStates_Send[2] = 0
        elif i == 4:
            if self.drawerStates[3] == 0:
                drawerStates_Send[3] = 1
            else:
                drawerStates_Send[3] = 0
        elif i == 5:
            if self.drawerStates[4] == 0:
                drawerStates_Send[4] = 1
            else:
                drawerStates_Send[4] = 0
        elif i == 6:
            if self.drawerStates[5] == 0:
                drawerStates_Send[5] = 1
            else:
                drawerStates_Send[5] = 0
        elif i == 7:
            if self.drawerStates[6] == 0:
                drawerStates_Send[6] = 1
            else:
                drawerStates_Send[6] = 0
        elif i == 8:
            if self.drawerStates[7] == 0:
                drawerStates_Send[7] = 1
            else:
                drawerStates_Send[7] = 0
        elif i == 9:
            if self.drawerStates[8] == 0:
                drawerStates_Send[8] = 1
            else:
                drawerStates_Send[8] = 0
        elif i == 10:
            if self.drawerStates[9] == 0:
                drawerStates_Send[9] = 1
            else:
                drawerStates_Send[9] = 0
        drawControlFrame_Send(ser, 0x3f, drawerStates_Send)

    def TemptureSet(self):  # 设置温度
        tempture = self.ui.Shezhiwendu.text()
        if tempture != "":
            address = ControlTableAttributes['Address']
            setTempFrame_Send(ser, address, int(tempture))

    def CompressorSet(self):  # 压缩机控制按钮
        if self.yastate == False:
            self.yastate = True
            self.ui.signal.setText(
                "The start compressor command has been send")
        else:
            self.yastate = False
            self.ui.signal.setText(
                "The stop compressor command has been send")

    def SendAttributes(self):  # 发送设置的属性
        if self.ui.DeviceID.text() != "" and self.ui.temptureSet.text() != "":
            Attributes = {
                'DeviceID': int(self.ui.DeviceID.text(), 16).to_bytes(5, 'big'),
                'Address': int(self.ui.DeviceAddress.currentText()),
                'StateUpload': int(self.ui.readInterpret.currentText()),
                'CompressorStartDelay': int(self.ui.ComDelay.currentText()),
                'tempture_set': tempture_send(int(self.ui.temptureSet.text())),
                'temptureError': int(self.ui.temptureError.currentText()),
            }
            print(Attributes)
            setParaFrame_Send(ser, Attributes)
            self.ui.signal.setText("")
        else:   # 如果未填写好
            self.ui.signal.setText("Please enter DeviceID and tempture of set")


# 实例化窗口程序
app = QApplication([])
software = Software()
software.ui.show()
# 设置接受数据守护线程
receivethread = threading.Thread(
    target=lambda: Receive(software, ser))
receivethread.setDaemon(True)
receivethread.start()
# 循环执行
app.exec_()

Receive.py(接收模块) :

from ControlTable import *  # 导入控制表数据结构(用户)
import datetime  # 计算时间
import chart    # 导入图像模块(用户)
from send import compressorControlFrame_Send  # 字节流处理(用户)


TemptureList = []  # 存储温度列表
DateTimeList = []  # 时间轴更新


def Receive(software, ser):  # 接收线程
    while(True):
        if software.ui.closeButton.isEnabled():
            Frame = ser.read(80)    # 接收80B数据
            resultFrame = ReceiveFrame(Frame)  # 将接收到的数据转换为常量字节流
            for result in resultFrame:
                if result[2] == 0x2C:   # 接收到的帧为控制表状态帧
                    # 保存接收到的数据
                    ControlTableAttributes_set(
                        result[6:11], result[11], result[13], result[14], result[17], result[18])
                    ControlTableStatus_set(
                        result[24:29], result[29], result[31], result[32], result[33], result[36:38])

                    tempture = temptureReceive()  # 计算接收到的温度并绘制图像

                    if software.yastate == True:    # 如果启动了压缩机
                        # 设置温度计算
                        temptureSet = '{:0>8}'.format(
                            str(bin(ControlTableStatus['tempture_set']))[2:])
                        if(temptureSet[0] == '0'):
                            temptureSet = str(
                                int(temptureSet[1:7], 2)+1/2*int(temptureSet[7], 2))
                        else:
                            temptureSet = '-' + str(
                                int(temptureSet[1:7], 2)+1/2*int(temptureSet[7], 2))
                        # 判断当前温度,调控压缩机开关
                        if float(tempture) <= float(temptureSet) - ControlTableAttributes['tempture_controlerror'] + 1:
                            compressorControlFrame_Send(ser, 0x3f, False)
                        if float(tempture) >= float(temptureSet) + ControlTableAttributes['tempture_controlerror'] - 1:
                            compressorControlFrame_Send(ser, 0x3f, True)
                    else:   # 如果没有启动压缩机
                        compressorControlFrame_Send(ser, 0x3f, False)

                    Lock = LockReceive()  # 计算Lock状态
                    UISoftwareUpdate(software, Lock, tempture)  # UI更新


def temptureReceive():  # 计算接收到的温度并绘制图像
    tempture = '{:0>8}'.format(
        str(bin(ControlTableStatus['tempture_current']))[2:])
    if(tempture[0] == '0'):
        tempture = str(
            int(tempture[1:7], 2)+1/2*int(tempture[7], 2))
    else:
        tempture = '-' + str(
            int(tempture[1:7], 2)+1/2*int(tempture[7], 2))

    DateTimeList.append(
        datetime.datetime.now().strftime("%H:%M:%S"))
    TemptureList.append(float(tempture))
    chart.Scatter(DateTimeList, TemptureList, '#abddff')

    return tempture


def LockReceive():  # 计算Lock状态
    return '{:0>8}'.format(
        str(bin(ControlTableStatus['LockState'][0]))[2:])[::-1] + '{:0>8}'.format(
            str(bin(ControlTableStatus['LockState'][1]))[2:4])[::-1] + '{:0>8}'.format(
        str(bin(ControlTableStatus['LockState'][1]))[4:])


def UISoftwareUpdate(software, Lock, tempture):  # 更新UI界面
    if software.ui.closeButton.isEnabled():
        drawerStateReceived(software, Lock)
        software.ui.yastate.setText('     ' + CompressorState_show(
            ControlTableStatus['CompressorState']))
        software.ui.Currentwendu.setText(tempture + "℃")


def drawerStateReceived(software, Lock):  # 根据Lock字段显示各个抽屉的状态
    if Lock[0] == '1':
        software.drawerStates[0] = 1
        software.ui.drawer1.setText("开")
    else:
        software.drawerStates[0] = 0
        software.ui.drawer1.setText("关")
    if Lock[1] == '1':
        software.drawerStates[1] = 1
        software.ui.drawer2.setText("开")
    else:
        software.drawerStates[1] = 0
        software.ui.drawer2.setText("关")
    if Lock[2] == '1':
        software.drawerStates[2] = 1
        software.ui.drawer3.setText("开")
    else:
        software.drawerStates[2] = 0
        software.ui.drawer3.setText("关")
    if Lock[3] == '1':
        software.drawerStates[3] = 1
        software.ui.drawer4.setText("开")
    else:
        software.drawerStates[3] = 0
        software.ui.drawer4.setText("关")
    if Lock[4] == '1':
        software.drawerStates[4] = 1
        software.ui.drawer5.setText("开")
    else:
        software.drawerStates[4] = 0
        software.ui.drawer5.setText("关")
    if Lock[5] == '1':
        software.drawerStates[5] = 1
        software.ui.drawer6.setText("开")
    else:
        software.drawerStates[5] = 0
        software.ui.drawer6.setText("关")
    if Lock[6] == '1':
        software.drawerStates[6] = 1
        software.ui.drawer7.setText("开")
    else:
        software.drawerStates[6] = 0
        software.ui.drawer7.setText("关")
    if Lock[7] == '1':
        software.drawerStates[7] = 1
        software.ui.drawer8.setText("开")
    else:
        software.drawerStates[7] = 0
        software.ui.drawer8.setText("关")
    if Lock[8] == '1':
        software.drawerStates[8] = 1
        software.ui.drawer9.setText("开")
    else:
        software.drawerStates[8] = 0
        software.ui.drawer9.setText("关")
    if Lock[9] == '1':
        software.drawerStates[9] = 1
        software.ui.drawer10.setText("开")
    else:
        software.drawerStates[9] = 0
        software.ui.drawer10.setText("关")


def ReceiveFrame(hex_datas):  # 匹配帧头和帧尾,获取匹配成功的帧
    resultFrame = []
    for i in range(0, len(hex_datas)-1):
        if hex_datas[i] == 0xFF and hex_datas[i+1] == 0xFF:
            for j in range(i, len(hex_datas)-1):
                if hex_datas[j] == 0xFF and hex_datas[j+1] == 0xF7:
                    result = hex_datas[i:j+2]
                    if len(result) == 14 or len(result) == 44:
                        resultFrame.append(result)
    return resultFrame  # 返回匹配成功的帧(列表)

chart.py(绘图模块):

import pyecharts.options as opts  # 绘图
from pyecharts.charts import Line   # 导入Line模块


def Scatter(time, tempture, colour):  # 绘制折线图html文件
    time = time[-10:]   # 取time末尾10位
    tempture = tempture[-10:]  # 取温度末尾10位
    c = (
        Line(init_opts=opts.InitOpts(
            width="900px",
            height="600px",
        )).add_xaxis(time).add_yaxis('温度/°C', tempture).set_colors(colour).set_global_opts(
            title_opts=opts.TitleOpts(title="温度变化"),
            yaxis_opts=opts.AxisOpts(name="温度°C"),
            xaxis_opts=opts.AxisOpts(name="time"))
    ).render("html\chart.html")  # 生成折线图html文件

send.py(发送模块):

import packet  # 封装成帧格式

# 启停压缩机控制帧发送


def compressorControlFrame_Send(ser, address, comOn):
    result = ser.write(packet.compressorControlFrame(address, comOn))

# 开锁帧发送


def drawControlFrame_Send(ser, address, draw):
    result = ser.write(packet.drawControlFrame(address, draw))

# 查询帧发送


def searchFrame_Send(ser, address):
    result = ser.write(packet.searchFrame(address))

# 设置温度帧发送


def setTempFrame_Send(ser, address, temp):
    temp = tempture_send(temp)
    result = ser.write(packet.setTempFrame(address, temp))

# 设置参数帧发送


def setParaFrame_Send(ser, Attributes):
    result = ser.write(packet.setParaFrame(Attributes))

# 设置温度转换成发送格式


def tempture_send(tempture):
    tempture = float(tempture)  # 将温度转化为浮点型
    s = str(tempture).split('.')  # 再转化为字符串型,以.分割列表
    tempture = str(int(int(s[0]) < 0)) + \
        '{:0>6}'.format(
            str(bin(int(s[0]))[2:])) + str(int(int(s[1]) != 0))  # 填充左边数字补零,宽度为6 将温度转换为十六进制数
    tempture = int(tempture, 2)
    return tempture

packet.py (封装成帧 ):

import struct  # 导入封装成帧模块
frameNum = 0  # 帧号

# 封装成帧


def DataFrame(address, funNum, data):
    length = len(data) + 10
    crc_frame = calc_crc(struct.pack(
        '4B', length, frameNum, address, funNum) + data)
    return struct.pack('6B', eval('0xFF'), eval('0xFF'), length, frameNum,
                       address, funNum) + data + struct.pack('H', crc_frame) + struct.pack('2B', eval('0xFF'), eval('0xF7'))

# 解封装


def DataFrame_unpack(frame):
    return struct.unpack('6B', frame[0:6]) + struct.unpack(str(len(frame[6:-2])) + 'B', frame[6:-2]) + struct.unpack('2B', frame[-2:])

# (1)查询帧(10Byte)


def searchFrame(address):  # 设备地址(16进制)
    global frameNum
    frameNum = (frameNum + 1) % 255
    Data = DataFrame(address, 1, b'')
    return Data

# (2)启停压缩机控制帧(11Byte)


def compressorControlFrame(address, comOn):  # 设备地址(16进制),是否启动压缩机(bool)
    global frameNum
    frameNum = (frameNum + 1) % 255
    if comOn:
        Data = DataFrame(address, 2, b'\x01')  # 数据1,启动
    else:
        Data = DataFrame(address, 2, b'\x00')  # 数据0,停止
    return Data

# (3)开锁帧(12Byte)


def drawControlFrame(address, draw):  # 设备地址(16进制),抽屉状态(元组)
    global frameNum
    b1 = 0
    b2 = 0
    frameNum = (frameNum + 1) % 255
    # 处理第一个字节
    for i in range(8):
        b1 += draw[i]*2**i
    # 处理第二个字节
    for i in [8, 9]:
        b2 += draw[i]*2**(i-8)

    Data = DataFrame(address, 3, b1.to_bytes(
        1, 'big')+b2.to_bytes(1, 'big'))  # 7
    return Data

# (4)设置温度帧(11Byte)


def setTempFrame(address, temp):  # 设备地址(16进制),设置温度(10进制)
    global frameNum
    frameNum = (frameNum + 1) % 255
    Data = DataFrame(address, 4, temp.to_bytes(1, 'big'))
    return Data

# (5)设置参数帧(28Byte)


def setParaFrame(para):
    global frameNum
    frameNum = (frameNum + 1) % 255
    data = para['DeviceID']+para['Address'].to_bytes(1, 'big')+b'\x00'+para['StateUpload'].to_bytes(1, 'big')+para['CompressorStartDelay'].to_bytes(
        1, 'big')+b'\x00\x00'+para['tempture_set'].to_bytes(1, 'big')+para['temptureError'].to_bytes(1, 'big')+b'\xff\xff\xff\xff\x00'
    Data = DataFrame(0x7f, 5, data)
    return Data

# (6)设置温度控制偏差帧(11Byte)


def setCtrlDeviationFrame(address, deviation):  # address是16进制,deviation是10进制
    global frameNum
    frameNum = (frameNum + 1) % 255
    Data = DataFrame(address, 6, deviation.to_bytes(1, 'big'))
    return Data

# (7)设置设备地址帧(16Byte)


def setDeviceAdressFrame(eqCodeing, newAddress):  # 形参均为16进制整型
    global frameNum
    frameNum = (frameNum + 1) % 255
    Data = DataFrame(0x7f, 9, eqCodeing.to_bytes(
        5, 'big')+newAddress.to_bytes(1, 'big'))
    return Data

# 循环冗余校验


def calc_crc(string):
    crc = 0xFFFF
    for pos in string:
        crc ^= pos
        for i in range(len(string)):
            if ((crc & 1) != 0):
                crc >>= 1
                crc ^= 0xA001
            else:
                crc >>= 1
    return eval(hex(((crc & 0xff) << 8) + (crc >> 8)))  # 返回CRC校验码(16进制字节流)

ControlTable.py(存放接收到的数据结构): 

# 控制表状态,用字典储存各个信息,每读取一次更新一次
ControlTableStatus = {
    'DeviceID': b'\xFF\xFF\xFF\xFF\xFF',  # 设备ID比特流
    'SystemState': 0x00,  # 二位十六进制数表示一个比特
    'CompressorState': 0x00,
    'tempture_set': 0x00,
    'tempture_current': 0x00,
    'LockState': b'\x00\x00',
}

# 控制表状态设置


def ControlTableStatus_set(DeviceID, SystemState, CompressorState, tempture_set, tempture_current, LockState):
    ControlTableStatus['DeviceID'] = DeviceID
    ControlTableStatus['SystemState'] = SystemState
    ControlTableStatus['CompressorState'] = CompressorState
    ControlTableStatus['tempture_set'] = tempture_set
    ControlTableStatus['tempture_current'] = tempture_current
    ControlTableStatus['LockState'] = LockState
    return ControlTableStatus

# 展示系统状态,用数字0,1,2分别表示三种状态


def SystemState_show(SystemState):
    if SystemState == 0:
        return "停止"
    elif SystemState == 1:
        return "预启动"
    elif SystemState == 2:
        return "运行"

# 展示压缩机状态,表示四种状态


def CompressorState_show(CompressorState):
    if CompressorState == 0:
        return "停止"
    elif CompressorState == 1:
        return "预启动"
    elif CompressorState == 2:
        return "运行"
    elif CompressorState == 3:
        return "故障"


# 控制表属性,同样用字典储存
ControlTableAttributes = {
    'DeviceID': b'\xFF\xFF\xFF\xFF\xFF',
    'Address': 0x01,
    'StateUpload': 0x01,
    'CompressorStartDelay': 0x1E,
    'tempture_set': 0x00,
    'tempture_controlerror': 0x02,
}

# 控制表属性设置


def ControlTableAttributes_set(DeviceID, Address, StateUpload, CompressorStartDelay, tempture_set, tempture_controlerror):
    ControlTableAttributes['DeviceID'] = DeviceID
    ControlTableAttributes['Address'] = Address
    ControlTableAttributes['StateUpload'] = StateUpload
    ControlTableAttributes['CompressorStartDelay'] = CompressorStartDelay
    ControlTableAttributes['tempture_set'] = tempture_set
    ControlTableAttributes['tempture_controlerror'] = tempture_controlerror
    return ControlTableAttributes

  文章来源地址https://www.toymoban.com/news/detail-537956.html

到了这里,关于现场快递柜状态采集与控制系统的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包