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 https://github.com/myDevicesIoT/Cayenne-MQTT-Python 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 https://gist.github.com/kadamski/92653913a53baf9dd1a8

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 https://hackernoon.com/how-to-measure-particulate-matter-with-a-raspberry-pi-75faa470ec35

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)