0

In the biginning i got my readings and i would get this error in between my readings once in a while. After that, I started getting this message more than i would get my readings. I changed up my code a lot now and i still get it. I will get 2 readings and i will get 3 "returned no data messages" this happens over and over again, its a pattern so i believe its something wrong with my code. Theres parts that arent aligned and misidented but thats due because of this text box, ignore it.

This is my code:

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()

Its a pattern like i mentioned. I get 2 readings of my sensor and then 3 returned no data messages in the else statement. I already changed the sensor twice. and the cables, the serial connection is good. I think its the way im reading and returning my data but i do not know how to go about it.

0 Answers0