SDS011 Sensor issues

Hello Cayenne Community,

Currently working on a PM sensor (SDS011 via Serial) to work with Cayenne from a Raspi B plus. I am having issues with getting the data to my Cayenne account. I’m too versed with Python but learning as I go, I understand this a is problem. The code I am using is designed for thinkspeak, not sure how to correctly use to MQTT via Cayenne client.

Thanks for Any help or suggestions.

Code:
import time
from datetime import datetime
import paho.mqtt.publish as publish
import psutil
from sds011 import *
import aqi

sensor = SDS011(“/dev/ttyUSB0”, use_query_mode=True)

def get_data(n=3):
sensor.sleep(sleep=False)
pmt_2_5 = 0
pmt_10 = 0
time.sleep(10)
for i in range (n):
x = sensor.query()
pmt_2_5 = pmt_2_5 + x[0]
pmt_10 = pmt_10 + x[1]
time.sleep(2)
pmt_2_5 = round(pmt_2_5/n, 1)
pmt_10 = round(pmt_10/n, 1)
sensor.sleep(sleep=True)
time.sleep(2)
return pmt_2_5, pmt_10

def conv_aqi(pmt_2_5, pmt_10):
aqi_2_5 = aqi.to_iaqi(aqi.POLLUTANT_PM25, str(pmt_2_5))
aqi_10 = aqi.to_iaqi(aqi.POLLUTANT_PM10, str(pmt_10))
return aqi_2_5, aqi_10

def save_log():
with open(“/YOUR PATH/air_quality.csv”, “a”) as log:
dt = datetime.now()
log.write(“{},{},{},{},{}\n”.format(dt, pmt_2_5, aqi_2_5, pmt_10, aqi_10))
log.close()

channelID = “YOUR CHANNEL ID”
apiKey = “YOUR WRITE KEY”
topic = “channels/” + channelID + “/publish/” + apiKey
mqttHost = “mqtt.thingspeak.com

tTransport = “tcp”
tPort = 1883
tTLS = None

while True:
pmt_2_5, pmt_10 = get_data()
aqi_2_5, aqi_10 = conv_aqi(pmt_2_5, pmt_10)
tPayload = “field1=” + str(pmt_2_5)+ “&field2=” + str(aqi_2_5)+ “&field3=” + str(pmt_10)+ “&field4=” + str(aqi_10)
try:
publish.single(topic, payload=tPayload, hostname=mqttHost, port=tPort, tls=tTLS, transport=tTransport)
save_log()
time.sleep(60)
except:
print (“[INFO] Failure in sending data”)
time.sleep(12)

you can use GitHub - myDevicesIoT/Cayenne-MQTT-Python: Python Library for Cayenne MQTT API to send data to cayenne.

Okay,

I tried with this version of the code, but due to my inept-ness about python, it’s not working.

import time
from datetime import datetime
import cayenne.client
import psutil
from sds011 import *
import aqi

sensor = SDS011("/dev/ttyUSB0", use_query_mode=True)


def get_data(n=3):
    sensor.sleep(sleep=False)
    pmt_2_5 = 0
    pmt_10 = 0
    time.sleep(10)
    for i in range(n):
        x = sensor.query()
        pmt_2_5 = pmt_2_5 + x[0]
        pmt_10 = pmt_10 + x[1]
        time.sleep(2)
    pmt_2_5 = round(pmt_2_5 / n, 1)
    pmt_10 = round(pmt_10 / n, 1)
    sensor.sleep(sleep=True)
    time.sleep(2)
    return pmt_2_5, pmt_10


def conv_aqi(pmt_2_5, pmt_10):
    aqi_2_5 = aqi.to_iaqi(aqi.POLLUTANT_PM25, str(pmt_2_5))
    aqi_10 = aqi.to_iaqi(aqi.POLLUTANT_PM10, str(pmt_10))
    return aqi_2_5, aqi_10


def cmd_query_data():
    ser.write(construct_command(CMD_QUERY_DATA))
    d = read_response()
    values = []
    if d[1] == "\xc0":
        values = process_data(d)
    return values

MQTT_USERNAME = "username info"
MQTT_PASSWORD = "password_info"
MQTT_CLIENT_ID = "id_info"

client = cayenne.client.CayenneMQTTClient()
client.begin = (MQTT_USERNAME, MQTT_PASSWORD, MQTT_CLIENT_ID)

mqttHost = "mqtt.cayenne.com"

tTransport = "tcp"
tPort = 1883
tTLS = None

while True:
    client.loop()
    if (time.time() > timestamp + 62):
        cmd_set_sleep(0)
        for t in range(15):
            values = cmd_query_data();
            if values is not None and len(values) == 2:
                print("PM2.5: ", values[0], ", PM10: ", values[1])
                time.sleep(2)

        client.virtualWrite(0, values[0])
        client.virtualWrite(1, values[1])

    print("Going to sleep for 1 min...")
        cmd_set_sleep(1)
        timestamp = time.time()

what is not working? can you add the below line to see the logs.

import logging
client.begin(MQTT_USERNAME, MQTT_PASSWORD, MQTT_CLIENT_ID, loglevel=logging.INFO)

Hello shramik,
I am having issues trying to write the data from the sensor to cayenne.

this is traceback from running the code below:

Connecting to mqtt.mydevices.com:1883
Traceback (most recent call last):
File “/home/pi/Cay/who.py”, line 57, in
if (time.time() > timestamp + 62):
NameError: name ‘timestamp’ is not defined

import time
from datetime import datetime
import cayenne.client
import psutil
from sds011 import *
import aqi
import logging

sensor = SDS011("/dev/ttyUSB0", use_query_mode=True)


def get_data(n=3):
    sensor.sleep(sleep=False)
    pmt_2_5 = 0
    pmt_10 = 0
    time.sleep(10)
    for i in range(n):
        x = sensor.query()
        pmt_2_5 = pmt_2_5 + x[0]
        pmt_10 = pmt_10 + x[1]
        time.sleep(2)
    pmt_2_5 = round(pmt_2_5 / n, 1)
    pmt_10 = round(pmt_10 / n, 1)
    sensor.sleep(sleep=True)
    time.sleep(2)
    return pmt_2_5, pmt_10


def conv_aqi(pmt_2_5, pmt_10):
    aqi_2_5 = aqi.to_iaqi(aqi.POLLUTANT_PM25, str(pmt_2_5))
    aqi_10 = aqi.to_iaqi(aqi.POLLUTANT_PM10, str(pmt_10))
    return aqi_2_5, aqi_10


def save_log():
    with open("/YOUR PATH/air_quality.csv", "a") as log:
        dt = datetime.now()
        log.write("{},{},{},{},{}\n".format(dt, pmt_2_5, aqi_2_5, pmt_10, aqi_10))
    log.close()

MQTT_USERNAME  = "this is filled in"
MQTT_PASSWORD  = "this is filled in"
MQTT_CLIENT_ID = "this is filed in"

client = cayenne.client.CayenneMQTTClient()
client.begin(MQTT_USERNAME, MQTT_PASSWORD, MQTT_CLIENT_ID, loglevel=logging.INFO)

mqttHost = "mqtt.cayenne.com"

tTransport = "tcp"
tPort = 1883
tTLS = None

while True:
    client.loop()
    if (time.time() > timestamp + 62):
        cmd_set_sleep(0)
        for t in range(15):
            values = cmd_query_data();
            if values is not None and len(values) == 2:
                print("pmt_2_5: ", values[0], ",pmt_10: ", values[1])
                time.sleep(2)

        client.virtualWrite(0, values[0])
        client.virtualWrite(1, values[1])

    print("Going to sleep for 1 min...")
        cmd_set_sleep(1)
        timestamp = time.time()

add this
timestamp = 0

I got this:

Traceback (most recent call last):
File “/home/pi/Cay/who.py”, line 60, in
cmd_set_sleep(0)
NameError: name ‘cmd_set_sleep’ is not defined

I also looked at the code you helped skweresp with and I figured this would be better since it has worked for another user.

traceback on this code:

Connecting to mqtt.mydevices.com:8883
Traceback (most recent call last):
File “caytest1.py”, line 140, in
cmd_set_sleep(0)
File “caytest1.py”, line 111, in cmd_set_sleep
ser.write(construct_command(CMD_SLEEP, [0x1, mode]))
File “/usr/lib/python3/dist-packages/serial/serialposix.py”, line 532, in write
d = to_bytes(data)
File “/usr/lib/python3/dist-packages/serial/serialutil.py”, line 63, in to_bytes
raise TypeError(‘unicode strings are not supported, please encode to bytes: {!r}’.format(seq))
TypeError: unicode strings are not supported, please encode to bytes: ‘ª´\x06\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00ÿÿ\x06«’

code:

#!/usr/bin/python -u
# coding=utf-8
# "DATASHEET": http://cl.ly/ekot
# https://gist.github.com/kadamski/92653913a53baf9dd1a8
from __future__ import print_function
import serial, struct, sys, time, json, subprocess
import cayenne.client
import time
import logging

# Cayenne authentication info. This should be obtained from the Cayenne Dashboard.
MQTT_USERNAME  = "efda9010-e0cc-11ea-a67f-15e30d90bbf4"
MQTT_PASSWORD  = "ce0d7134567d31ef0df8b593d4f15905e8da7820"
MQTT_CLIENT_ID = "36818710-e1b5-11ea-b767-3f1a8f1211ba"

client = cayenne.client.CayenneMQTTClient()
client.begin(MQTT_USERNAME, MQTT_PASSWORD, MQTT_CLIENT_ID, loglevel=logging.INFO, port=8883)
# For a secure connection use port 8883 when calling client.begin:
# client.begin(MQTT_USERNAME, MQTT_PASSWORD, MQTT_CLIENT_ID, port=8883, loglevel=logging.INFO)

i = 0
timestamp = 0

DEBUG = 0
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
PERIOD_CONTINUOUS = 0

JSON_FILE = '/var/www/html/aqi.json'

MQTT_HOST = ''
MQTT_TOPIC = '/weather/particulatematter'

ser = serial.Serial()
ser.port = "/dev/ttyUSB0"
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
    return [pm25, pm10]
    # 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()
    values = []
    if d[1] == "\xc0":
        values = process_data(d)
    return values


def cmd_set_sleep(sleep):
    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()


def pub_mqtt(jsonrow):
    cmd = ['mosquitto_pub', '-h', MQTT_HOST, '-t', MQTT_TOPIC, '-s']
    print('Publishing using:', cmd)
    with subprocess.Popen(cmd, shell=False, bufsize=0, stdin=subprocess.PIPE).stdin as f:
        json.dump(jsonrow, f)


cmd_set_sleep(0)
cmd_firmware_ver()
cmd_set_working_period(PERIOD_CONTINUOUS)
cmd_set_mode(MODE_QUERY);
while True:
    client.loop()
    if (time.time() > timestamp + 62):
        cmd_set_sleep(0)
        for t in range(15):
            values = cmd_query_data();
            if values is not None and len(values) == 2:
                print("PM2.5: ", values[0], ", PM10: ", values[1])
                time.sleep(2)

        client.virtualWrite(0, values[0])
        client.virtualWrite(1, values[1])

        print("Going to sleep for 1 min...")
        cmd_set_sleep(1)
        timestamp = time.time()

please make sure you atleast copy the right code.

have you atleast got the sensor connected and getting reading from it. Try this code and see if it works SDS011 dust sensor reading · GitHub

I just used the code from the GitHub link at got this:

Traceback (most recent call last):
File “/home/pi/Cay/testing.py”, line 18, in
ser.port = sys.argv[1]
IndexError: list index out of range

i guess you serial port is blocking and busy. can you restart your computer.

I just did and got the same error.

see if you have connected the device properly lsusb and ls -l /dev/tty*

I believe I do here is the information:

pi@raspberrypi:~ $ lsusb
Bus 001 Device 004: ID 1a86:7523 QinHeng Electronics HL-340 USB-Serial adapter
Bus 001 Device 005: ID 0424:7800 Standard Microsystems Corp. 
Bus 001 Device 003: ID 0424:2514 Standard Microsystems Corp. USB 2.0 Hub
Bus 001 Device 002: ID 0424:2514 Standard Microsystems Corp. USB 2.0 Hub
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
pi@raspberrypi:~ $ ls -l /dev/tty*
crw-rw-rw- 1 root tty       5,  0 Aug 20 11:10 /dev/tty
crw--w---- 1 root tty       4,  0 Aug 20 11:10 /dev/tty0
crw------- 1 pi   tty       4,  1 Aug 20 11:10 /dev/tty1
crw--w---- 1 root tty       4, 10 Aug 20 11:10 /dev/tty10
crw--w---- 1 root tty       4, 11 Aug 20 11:10 /dev/tty11
crw--w---- 1 root tty       4, 12 Aug 20 11:10 /dev/tty12
crw--w---- 1 root tty       4, 13 Aug 20 11:10 /dev/tty13
crw--w---- 1 root tty       4, 14 Aug 20 11:10 /dev/tty14
crw--w---- 1 root tty       4, 15 Aug 20 11:10 /dev/tty15
crw--w---- 1 root tty       4, 16 Aug 20 11:10 /dev/tty16
crw--w---- 1 root tty       4, 17 Aug 20 11:10 /dev/tty17
crw--w---- 1 root tty       4, 18 Aug 20 11:10 /dev/tty18
crw--w---- 1 root tty       4, 19 Aug 20 11:10 /dev/tty19
crw--w---- 1 root tty       4,  2 Aug 20 11:10 /dev/tty2
crw--w---- 1 root tty       4, 20 Aug 20 11:10 /dev/tty20
crw--w---- 1 root tty       4, 21 Aug 20 11:10 /dev/tty21
crw--w---- 1 root tty       4, 22 Aug 20 11:10 /dev/tty22
crw--w---- 1 root tty       4, 23 Aug 20 11:10 /dev/tty23
crw--w---- 1 root tty       4, 24 Aug 20 11:10 /dev/tty24
crw--w---- 1 root tty       4, 25 Aug 20 11:10 /dev/tty25
crw--w---- 1 root tty       4, 26 Aug 20 11:10 /dev/tty26
crw--w---- 1 root tty       4, 27 Aug 20 11:10 /dev/tty27
crw--w---- 1 root tty       4, 28 Aug 20 11:10 /dev/tty28
crw--w---- 1 root tty       4, 29 Aug 20 11:10 /dev/tty29
crw--w---- 1 root tty       4,  3 Aug 20 11:10 /dev/tty3
crw--w---- 1 root tty       4, 30 Aug 20 11:10 /dev/tty30
crw--w---- 1 root tty       4, 31 Aug 20 11:10 /dev/tty31
crw--w---- 1 root tty       4, 32 Aug 20 11:10 /dev/tty32
crw--w---- 1 root tty       4, 33 Aug 20 11:10 /dev/tty33
crw--w---- 1 root tty       4, 34 Aug 20 11:10 /dev/tty34
crw--w---- 1 root tty       4, 35 Aug 20 11:10 /dev/tty35
crw--w---- 1 root tty       4, 36 Aug 20 11:10 /dev/tty36
crw--w---- 1 root tty       4, 37 Aug 20 11:10 /dev/tty37
crw--w---- 1 root tty       4, 38 Aug 20 11:10 /dev/tty38
crw--w---- 1 root tty       4, 39 Aug 20 11:10 /dev/tty39
crw--w---- 1 root tty       4,  4 Aug 20 11:10 /dev/tty4
crw--w---- 1 root tty       4, 40 Aug 20 11:10 /dev/tty40
crw--w---- 1 root tty       4, 41 Aug 20 11:10 /dev/tty41
crw--w---- 1 root tty       4, 42 Aug 20 11:10 /dev/tty42
crw--w---- 1 root tty       4, 43 Aug 20 11:10 /dev/tty43
crw--w---- 1 root tty       4, 44 Aug 20 11:10 /dev/tty44
crw--w---- 1 root tty       4, 45 Aug 20 11:10 /dev/tty45
crw--w---- 1 root tty       4, 46 Aug 20 11:10 /dev/tty46
crw--w---- 1 root tty       4, 47 Aug 20 11:10 /dev/tty47
crw--w---- 1 root tty       4, 48 Aug 20 11:10 /dev/tty48
crw--w---- 1 root tty       4, 49 Aug 20 11:10 /dev/tty49
crw--w---- 1 root tty       4,  5 Aug 20 11:10 /dev/tty5
crw--w---- 1 root tty       4, 50 Aug 20 11:10 /dev/tty50
crw--w---- 1 root tty       4, 51 Aug 20 11:10 /dev/tty51
crw--w---- 1 root tty       4, 52 Aug 20 11:10 /dev/tty52
crw--w---- 1 root tty       4, 53 Aug 20 11:10 /dev/tty53
crw--w---- 1 root tty       4, 54 Aug 20 11:10 /dev/tty54
crw--w---- 1 root tty       4, 55 Aug 20 11:10 /dev/tty55
crw--w---- 1 root tty       4, 56 Aug 20 11:10 /dev/tty56
crw--w---- 1 root tty       4, 57 Aug 20 11:10 /dev/tty57
crw--w---- 1 root tty       4, 58 Aug 20 11:10 /dev/tty58
crw--w---- 1 root tty       4, 59 Aug 20 11:10 /dev/tty59
crw--w---- 1 root tty       4,  6 Aug 20 11:10 /dev/tty6
crw--w---- 1 root tty       4, 60 Aug 20 11:10 /dev/tty60
crw--w---- 1 root tty       4, 61 Aug 20 11:10 /dev/tty61
crw--w---- 1 root tty       4, 62 Aug 20 11:10 /dev/tty62
crw--w---- 1 root tty       4, 63 Aug 20 11:10 /dev/tty63
crw--w---- 1 root tty       4,  7 Aug 20 11:10 /dev/tty7
crw--w---- 1 root tty       4,  8 Aug 20 11:10 /dev/tty8
crw--w---- 1 root tty       4,  9 Aug 20 11:10 /dev/tty9
crw-rw---- 1 root dialout 204, 64 Aug 20 11:10 /dev/ttyAMA0
crw------- 1 root root      5,  3 Aug 20 11:10 /dev/ttyprintk
crw--w---- 1 root tty       4, 64 Aug 20 11:10 /dev/ttyS0
crw-rw---- 1 root dialout 188,  0 Aug 20 11:10 /dev/ttyUSB0

in your code, replace:

with

ser.port = "/dev/ttyUSB0"

I updated it and got this back:

Traceback (most recent call last):
  File "testing.py", line 95, in <module>
    cmd_set_sleep(0)
  File "testing.py", line 76, in cmd_set_sleep
    ser.write(construct_command(CMD_SLEEP, [0x1, mode]))
  File "testing.py", line 38, in construct_command
    dump(ret, '> ')
  File "testing.py", line 27, in dump
    print(prefix + ' '.join(x.encode('hex') for x in d))
  File "testing.py", line 27, in <genexpr>
    print(prefix + ' '.join(x.encode('hex') for x in d))
LookupError: 'hex' is not a text encoding; use codecs.encode() to handle arbitrary codecs
pi@raspberry

try this How To Measure Particulate Matter With a Raspberry Pi | HackerNoon

That code works I am getting readings from the sensor

Try this code.

#!/usr/bin/python -u
# coding=utf-8
# "DATASHEET": http://cl.ly/ekot
# https://gist.github.com/kadamski/92653913a53baf9dd1a8

import cayenne.client
import time
import logging

from __future__ import print_function
import serial
import struct
import sys
import time
import json
import subprocess

DEBUG = 0
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
PERIOD_CONTINUOUS = 0

JSON_FILE = '/var/www/html/aqi.json'

MQTT_HOST = ''
MQTT_TOPIC = '/weather/particulatematter'

ser = serial.Serial()
ser.port = "/dev/ttyUSB0"
ser.baudrate = 9600

ser.open()
ser.flushInput()

byte, data = 0, ""

# Cayenne authentication info. This should be obtained from the Cayenne Dashboard.
MQTT_USERNAME = "MQTT_USERNAME"
MQTT_PASSWORD = "MQTT_PASSWORD"
MQTT_CLIENT_ID = "MQTT_CLIENT_ID"

# The callback for when a message is received from Cayenne.


def on_message(message):
    print("message received: " + str(message))
    # If there is an error processing the message return an error string, otherwise return nothing.


client = cayenne.client.CayenneMQTTClient()
client.on_message = on_message
client.begin(MQTT_USERNAME, MQTT_PASSWORD,
             MQTT_CLIENT_ID, loglevel=logging.INFO)
# For a secure connection use port 8883 when calling client.begin:
# client.begin(MQTT_USERNAME, MQTT_PASSWORD, MQTT_CLIENT_ID, port=8883, loglevel=logging.INFO)

i = 0
timestamp = 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
    return [pm25, pm10]
    #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()
    values = []
    if d[1] == "\xc0":
        values = process_data(d)
    return values


def cmd_set_sleep(sleep):
    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()


def pub_mqtt(jsonrow):
    cmd = ['mosquitto_pub', '-h', MQTT_HOST, '-t', MQTT_TOPIC, '-s']
    print('Publishing using:', cmd)
    with subprocess.Popen(cmd, shell=False, bufsize=0, stdin=subprocess.PIPE).stdin as f:
        json.dump(jsonrow, f)


if __name__ == "__main__":
    cmd_set_sleep(0)
    cmd_firmware_ver()
    cmd_set_working_period(PERIOD_CONTINUOUS)
    cmd_set_mode(MODE_QUERY)
    while True:
        client.loop()
        cmd_set_sleep(0)
        for t in range(15):
            values = cmd_query_data()
            if values is not None and len(values) == 2:
                print("PM2.5: ", values[0], ", PM10: ", values[1])
                time.sleep(2)
        client.virtualWrite(1, values[0])
        client.virtualWrite(2, values[1])

        # open stored data
        try:
            with open(JSON_FILE) as json_data:
                data = json.load(json_data)
        except IOError as e:
            data = []

        # check if length is more than 100 and delete first element
        if len(data) > 100:
            data.pop(0)

        print("Going to sleep for 1 min...")
        cmd_set_sleep(1)
        time.sleep(60)