Skip to content

Instantly share code, notes, and snippets.

@kadamski
Last active March 31, 2024 02:03
Show Gist options
  • Save kadamski/92653913a53baf9dd1a8 to your computer and use it in GitHub Desktop.
Save kadamski/92653913a53baf9dd1a8 to your computer and use it in GitHub Desktop.
SDS011 dust sensor reading
#!/usr/bin/python
# coding=utf-8
# "DATASHEET": http://cl.ly/ekot
from __future__ import print_function
import serial, struct, sys, time
DEBUG = 1
CMD_MODE = 2
CMD_QUERY_DATA = 4
CMD_DEVICE_ID = 5
CMD_SLEEP = 6
CMD_FIRMWARE = 7
CMD_WORKING_PERIOD = 8
MODE_ACTIVE = 0
MODE_QUERY = 1
ser = serial.Serial()
ser.port = sys.argv[1]
ser.baudrate = 9600
ser.open()
ser.flushInput()
byte, data = 0, ""
def dump(d, prefix=''):
print(prefix + ' '.join(x.encode('hex') for x in d))
def construct_command(cmd, data=[]):
assert len(data) <= 12
data += [0,]*(12-len(data))
checksum = (sum(data)+cmd-2)%256
ret = "\xaa\xb4" + chr(cmd)
ret += ''.join(chr(x) for x in data)
ret += "\xff\xff" + chr(checksum) + "\xab"
if DEBUG:
dump(ret, '> ')
return ret
def process_data(d):
r = struct.unpack('<HHxxBB', d[2:])
pm25 = r[0]/10.0
pm10 = r[1]/10.0
checksum = sum(ord(v) for v in d[2:8])%256
print("PM 2.5: {} μg/m^3 PM 10: {} μg/m^3 CRC={}".format(pm25, pm10, "OK" if (checksum==r[2] and r[3]==0xab) else "NOK"))
def process_version(d):
r = struct.unpack('<BBBHBB', d[3:])
checksum = sum(ord(v) for v in d[2:8])%256
print("Y: {}, M: {}, D: {}, ID: {}, CRC={}".format(r[0], r[1], r[2], hex(r[3]), "OK" if (checksum==r[4] and r[5]==0xab) else "NOK"))
def read_response():
byte = 0
while byte != "\xaa":
byte = ser.read(size=1)
d = ser.read(size=9)
if DEBUG:
dump(d, '< ')
return byte + d
def cmd_set_mode(mode=MODE_QUERY):
ser.write(construct_command(CMD_MODE, [0x1, mode]))
read_response()
def cmd_query_data():
ser.write(construct_command(CMD_QUERY_DATA))
d = read_response()
if d[1] == "\xc0":
process_data(d)
def cmd_set_sleep(sleep=1):
mode = 0 if sleep else 1
ser.write(construct_command(CMD_SLEEP, [0x1, mode]))
read_response()
def cmd_set_working_period(period):
ser.write(construct_command(CMD_WORKING_PERIOD, [0x1, period]))
read_response()
def cmd_firmware_ver():
ser.write(construct_command(CMD_FIRMWARE))
d = read_response()
process_version(d)
def cmd_set_id(id):
id_h = (id>>8) % 256
id_l = id % 256
ser.write(construct_command(CMD_DEVICE_ID, [0]*10+[id_l, id_h]))
read_response()
if __name__ == "__main__":
cmd_set_sleep(0)
cmd_set_mode(1);
cmd_firmware_ver()
time.sleep(3)
cmd_query_data();
cmd_set_mode(0);
cmd_set_sleep()
@alokvermaiitr
Copy link

What needs to change in the code if I would not use Sensor Hat?

@kadamski
Copy link
Author

@alokvermaiitr what you mean by Sensor Hat?

@FaisalAhmed123
Copy link

For those still having the issue where it maxes out, I wrote some new code which seems to work past the 20,000 mark https://github.com/FaisalAhmed123/Nova-PM2.5-Sensor-Reading-Interpreter/blob/main/main.py

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment