在 biginning 中,我得到了读数,并且偶尔会在读数之间出现此错误。从那以后,我收到的这条消息的数量开始多于我收到的读数。我现在对代码进行了很多更改,但我仍然明白。我将得到 2 个读数,并且将得到 3 个“未返回数据消息”,这种情况会一遍又一遍地发生,这是一种模式,所以我相信我的代码有问题。有些部分未对齐和错误识别,但这是由于此文本框造成的,请忽略它。
这是我的代码:
import json
import paho.mqtt.client as mqtt
import serial
import time
class PMSensor:
# Constructor for the PMSensor class, initializes the class variables
def __init__(self, serial_port, baud_rate, bytesize, parity, stopbits, mqtt_broker, mqtt_port, mqtt_username, mqtt_password, mqtt_topic):
""" Serial port variables """
# Initialize the PM sensor object with the specified serial port, baud rate, bytesize, parity, and stopbits
self.serial_port = serial_port
self.baud_rate = baud_rate
self.bytesize = bytesize
self.stopbits = stopbits
self.parity = parity
""" MQTT variables """
# Initialize the MQTT client with the specified broker, port, username, and password
self.mqtt_broker = mqtt_broker
self.mqtt_port = mqtt_port
self.mqtt_username = mqtt_username
self.mqtt_password = mqtt_password
self.mqtt_topic = mqtt_topic
self.ser = None
# Callback function for MQTT client connection event
def on_connect(self, client, userdata, flags, rc):
# If connection is successful the rc code should be 0, if not successfult rc code will return a 5
# if code returns 5, check broker address, port and userdata.
if rc == 0:
print('Connected to MQTT broker.')
print("--------------------------------------")
client.subscribe(self.mqtt_topic)
else:
print('Failed to connect to MQTT broker with error code:', rc)
def on_disconnect(self, client, userdata, rc):
print("Ddisconnected from MQTT broker with result code: " + str(rc))
def connect_mqtt(self):
# Function to connect to the MQTT broker with the specified username and password
self.client.username_pw_set(self.mqtt_username, self.mqtt_password)
self.client.connect(self.mqtt_broker, self.mqtt_port)
# Using the PM constructor variables we stablish the serial connection
def establish_serial_connection(self):
try:
self.ser = serial.Serial(self.serial_port, self.baud_rate, self.bytesize, self.parity, self.stopbits)
if self.ser.is_open:
print('Serial connection established:', self.ser.portstr)
else:
print('Failed to establish serial connection.')
return False
return True
except Exception as e:
print('Error while establishing serial connection:', e)
return False
# This function checks that the serial connection is open, once we stablish connection
# we flush the buffer and proceed to read 32 bytes. The first two bytes are fixed as
# /x42 and /x4d, in order to read the data we need to check for this to match with the sensor.
# Once the first two bytes are a match, we proceed to read the rest of the data and assign them
# to their proper variables.
def read_pm25(self):
try:
""" check for serial connection """
if self.ser.is_open:
""" Clear buffer """
self.ser.flushInput()
""" Proceed to read 32 bytes """
data = self.ser.read(32)
""" Check that the first two fixed bytes of data match that of the sensor """
if data[:2] == b'\x42\x4d':
# This part of the code is taking each piece of the serial stream
# (16 byte stream) and converting it from the hexadecimal values to the output values.
# The first high 8 bit reading can be multiplied by 256 to shift the bit
# value over by 8 places to the left in order to add it to the lower 8
# bit value reading. This is also the same as << 8.
# The apm10, 25, and 100 are the factory calibration settings.
apm1 = (data[4] << 8) + data[5]
apm25 = (data[6] << 8) + data[7]
apm10 = (data[8] << 8) + data[9]
# PM10, 25, and 100 are the generic atmospheric conditions for calibration.
pm1 = (data[10] << 8) + data[11]
pm25 = (data[12] << 8) + data[13]
pm10 = (data[14] << 8) + data[15]
# The gt03, 05, 10, 25, 50, 100 are the number of particles with
# certain diameter readings. (all units are unit ug/m3
gt03um = (data[16] << 8) + data[17]
gt05um = (data[18] << 8) + data[19]
gt10um = (data[20] << 8) + data[21]
gt25um = (data[22] << 8) + data[23]
gt50um = (data[24] << 8) + data[25]
gt100um = (data[26] << 8) + data[27]
return apm1, apm25, apm10, pm1, pm25, pm10, gt03um, gt05um, gt10um, gt25um, gt50um, gt100um
return None
except Exception as e:
print('Error while reading PM sensor:', e)
return None
# Format the data to display in shell.
def display_in_shell(self, apm1, apm25, apm10, pm1, pm25, pm10, gt03um, gt05um, gt10um, gt25um, gt50um, gt100um):
print("--------------------------------------")
print("Concentration Units (Standard)")
print(f'\n PM1.0 (ug/m3): {apm1} \t\t PM2.5 (ug/m3): {apm25} \t\t PM10 (ug/m3): {apm10}')
print("--------------------------------------")
print("Concentration Units (Enviromental)")
print(f'\nPM1.0 (ug/m3): {pm1} \t\t PM2.5 (ug/m3): {pm25} \t\t PM10 (ug/m3): {pm10}')
print("--------------------------------------")
print("Particle Count\n")
print(f' >0.3um in 0.1L air: {gt03um}')
print(f' >0.5um in 0.1L air: {gt05um}')
print(f' >1.0um in 0.1L air: {gt10um}')
print(f' >2.5um in 0.1L air: {gt25um}')
print(f' >5.0um in 0.1L air: {gt50um}')
print(f' >10um in 0.1L air: {gt100um}')
print("--------------------------------------")
def start(self):
# if serial connection is established proceed to connect to mqtt
if self.establish_serial_connection():
try:
# Function to start the PM sensor data reading and sending process
# Connect to MQTT broker
self.connect_mqtt()
# Set the MQTT callback functions
self.client.on_connect = self.on_connect
self.client.on_disconnect = self.on_disconnect
# Start the MQTT loop in the background
self.client.loop_start()
except Exception as e:
print("Could not establish connection with broker -->", e)
while True:
# Function to start the PM sensor data reading and sending process
pm_data = self.read_pm25()
# if no data is returned by the sensor, display else statement.
if pm_data is not None:
apm1, apm25, apm10, pm1, pm25, pm10, gt03um, gt05um, gt10um, gt25um, gt50um, gt100um = pm_data
self.display_in_shell(apm1, apm25, apm10, pm1, pm25, pm10, gt03um, gt05um, gt10um, gt25um, gt50um, gt100um)
payload = json.dumps({'apm1': apm1, 'apm25': apm25, 'apm10': apm10, 'pm1': pm1, 'pm25': pm25, 'pm10': pm10,
'gt03um': gt03um, 'gt05um': gt05um, 'gt10um': gt10um, 'gt25um': gt25um, 'gt50um': gt50um, 'gt100um': gt100um})
mqtt_client.publish(self.mqtt_topic, payload)
else:
print('Failed to read PM sensor data.')
time.sleep(1)
def stop(self):
# Function to stop the PM sensor data reading and sending process
# Stop the MQTT loop
self.client.loop_stop()
# Disconnect from the MQTT broker
self.client.disconnect()
# Create an instance of the PMSensor class
pms5003_sensor = PMSensor(serial_port = '/dev/ttyUSB0',
baud_rate = 9600,
bytesize = serial.EIGHTBITS,
parity = serial.PARITY_NONE,
stopbits = serial.STOPBITS_ONE,
timeout = 2.0
mqtt_broker="192.168.21.201",
mqtt_port=1883,
mqtt_username='WLED',
mqtt_password='Toyota',
mqtt_topic='TMNA/PEMC/FirstFloor/LivingWall/reTerminal/ParticulateSensor/Enviromental')
# Start the PM sensor data reading and sending process
pms5003_sensor.start()
# To stop the PM sensor data reading and sending process, call the stop() method
# pms5003_sensor.stop()
就像我提到的那样。我获得了传感器的 2 个读数,然后 3 个读数在 else 语句中没有返回任何数据消息。我已经换过两次传感器了。和电缆,串行连接良好。我认为这是我读取和返回数据的方式,但我不知道如何去做。
我刚刚看到这个问题。我用 C 语言编写了 ESP32 代码,但遇到了非常相似的问题。就我而言,我在被动模式下使用 PMS5003。在这种模式下,您发送 requestRead(),等待(我有 1 秒),然后处理读取的数据。我注意到有时接收缓冲区中存在错误数据,导致校验和和读取长度错误。我不记得在哪里 - 对不起原作者,但我找到了一个在发出 readRequest() 之前清除读取缓冲区的示例。这意味着 PMS5003 数据被读入干净的缓冲区并解决了我的“无数据”问题。我知道你正在用 Python 编写你的项目,而我的项目是用 C 编写的,但这可能是一个类似的问题。我正在使用 pms.h 和 SoftwareSerial.h,并且在从 PMS5003 请求数据之前,我通过以下方式清除读取缓冲区:
while (pmsSerial.available())
{
pmsSerial.read(); // read any residual buffer data
}
希望这有帮助。