Particulate Matter Sensor - Nova SDS021. Wildly varying values. Anyone else?

I have this sensor connected to my install and all worked well for two days, values in the 6 - 20 range as expected. Using the built-in component:

Without any change, except a reboot, the values jumped up to the 30 to 60 range for the same room.

I then migrated the sensor to a Pi Zero, a Pi 3, and a Pi 3+ with Hassbian - and the situation re-occured.

I can forgive the Pi Zero as its voltages are a little different, but I can’t understand the variance with the other setups.

My configuration is standard, and doesn’t show any errors:

  - platform: serial_pm
    serial_device: /dev/ttyUSB0
    name: Nova
    brand: novafitness,sds021

The value jumps in Grafana:

I’m guessing it’s the sensor itself, which makes it working properly for a time extra annoying.

Has anyone else a similar experience?

Work-around api that will run on a Pi Zero etc.

I’ve noticed that if the api runs immediately after start-up / reboot then the same issue occurs, so if you want to run this automatically add a 30 second delay, e.g. in /etc/rc.local

sleep 30 && python ...

This might be what is causing the issue with the component, I’ve an issue logged as:

For SDS021:


# Forked from:
# Credits: Matjaz Rihtar, Matej Kovacic

from flask import Flask, jsonify
import serial, struct, time

# Set default USB port
USBPORT = "/dev/ttyUSB0"

class SDS021Reader:

    def __init__(self, inport):
        self.serial = serial.Serial(port=inport, baudrate=9600)

    def readValue( self ):
        step = 0
        while True:
            while self.serial.inWaiting() != 0:
                v = ord(

                if step == 0:
                    if v == 170:
                        step = 1

                elif step == 1:
                    if v == 192:
                        values = [0,0,0,0,0,0,0]
                        step = 2
                        step = 0

                elif step > 8:
                    step = 0
                    # Compute PM2.5 and PM10 values
                    pm25 = (values[1]*256 + values[0])/10.0
                    pm10 = (values[3]*256 + values[2])/10.0
                    return [pm25,pm10]

                elif step >= 2:
                    values[step - 2] = v
                    step = step + 1

app = Flask(__name__)

reader = SDS021Reader(USBPORT)

@app.route('/api/airquality', methods=['GET'])
def get_air_quality():
    pm_25_value , pm_10_value = reader.readValue()
    return jsonify({'PM25': str(pm_25_value), 'PM10': str(pm_10_value)})

if __name__ == '__main__':'', debug=False)

Sensors.yaml example entries:

## Nova SDS021

  - platform: rest
    name: nova_sds021_group_values
      - PM10
      - PM25
    value_template: '{{ value_json.state }}'

  - platform: template
        friendly_name: "PM10 sds021"
        value_template: '{{ states.sensor.nova_sds021_group_values.attributes["PM10"] }}'
        unit_of_measurement: 'µg/m³'
        friendly_name: "PM2.5 sds021"
        value_template: '{{ states.sensor.nova_sds021_group_values.attributes["PM25"] }}'
        unit_of_measurement: 'µg/m³'

  - platform: filter
    name: "PM10 (moving average) sds021"
    entity_id: sensor.pm10_sds021
      - filter: time_simple_moving_average
        window_size: 00:05
        precision: 2

  - platform: filter
    name: "PM2.5 (moving average) sds021"
    entity_id: sensor.pm25_sds021
      - filter: time_simple_moving_average
        window_size: 00:05
        precision: 2

How do we know that the value which is shown at startup is wrong and value after long time is correct. What I think is that if sds011 is running for long time may be it starts giving the lowest value? Whenever the sensor runs full night its values are dropped to around 5-6 and if i restart in morning they become 23- 30 and stay there until evening.

How do we know which values are actually correct.?

Hi, I do not know if someone can help me,
Please look at this post on github, with the same problem but PM5003 sensor: