Connect SDS011 sensor to Cayenne [SOLVED]

Hi, I’m struggling with adding Nova SDS011 sensor to Cayenne. I have make it work with Raspberry Pi Zero with that tutorial and now I cannot add it to Cayenne. I have base code that works in /home/pi/aqi.py

#!/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

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)


if __name__ == "__main__":
    cmd_set_sleep(0)
    cmd_firmware_ver()
    cmd_set_working_period(PERIOD_CONTINUOUS)
    cmd_set_mode(MODE_QUERY);
    while True:
        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)

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

        # append new values
        jsonrow = {'pm25': values[0], 'pm10': values[1], 'time': time.strftime("%d.%m.%Y %H:%M:%S")}
        data.append(jsonrow)

        # save it
        with open(JSON_FILE, 'w') as outfile:
            json.dump(data, outfile)

        if MQTT_HOST != '':
            pub_mqtt(jsonrow)
            
        print("Going to sleep for 1 min...")
        cmd_set_sleep(1)
        time.sleep(60)

I make another file with that code czujnik.py and add cayenne credentials from dashboard [BringYour Own Thing]

#!/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  = "06487d60-1537-11ea-84bb-8f71124cfdfb"
MQTT_PASSWORD  = "23309cdee31964b2ae4caed9417b689c9bebece2"
MQTT_CLIENT_ID = "389199a0-2f40-11ea-84bb-8f71124cfdfb"

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)

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)


if __name__ == "__main__":
    cmd_set_sleep(0)
    cmd_firmware_ver()
    cmd_set_working_period(PERIOD_CONTINUOUS)
    cmd_set_mode(MODE_QUERY);
    while True:
        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)

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

        # append new values
        jsonrow = {'pm25': values[0], 'pm10': values[1], 'time': time.strftime("%d.%m.%Y %H:%M:%S")}
        data.append(jsonrow)

        # save it
        with open(JSON_FILE, 'w') as outfile:
            json.dump(data, outfile)

        if MQTT_HOST != '':
            pub_mqtt(jsonrow)
            
        print("Going to sleep for 1 min...")
        cmd_set_sleep(1)
        time.sleep(60)

and in ssh console I see it read data but there’s nothing on Cayenne Dashboard. I see device is on and after a while it shows offline.

python czujnik.py 
Connecting to mqtt.mydevices.com:8883
Y: 18, M: 11, D: 16, ID: 0xd30d, CRC=OK
PM2.5:  1.6 , PM10:  8.1
PM2.5:  1.7 , PM10:  7.8
PM2.5:  1.7 , PM10:  7.8
PM2.5:  1.6 , PM10:  6.7
PM2.5:  1.6 , PM10:  6.7
PM2.5:  1.7 , PM10:  6.7
PM2.5:  1.6 , PM10:  6.1
PM2.5:  1.6 , PM10:  5.4
PM2.5:  1.6 , PM10:  5.3
PM2.5:  1.8 , PM10:  5.4
PM2.5:  1.8 , PM10:  5.7
PM2.5:  1.8 , PM10:  5.9
PM2.5:  1.8 , PM10:  5.0
PM2.5:  1.7 , PM10:  4.2
PM2.5:  1.6 , PM10:  5.4
Going to sleep for 1 min...

I’m not programmer and I don’t know how to code in python so I will be greatful if somebody will help.
Regards.

to send data to cayenne you need to use client.virtualWrite(1, x) where x is the value of the sensor.

I add that lines to my code:

i=0
timestamp = 0

while True:
    client.loop()
    
    if (time.time() > timestamp + 10):
        client.virtualWrite(0, "PM2.5: ")
        client.virtualWrite(1, "PM10: ")
        timestamp = time.time()
        i = i+1

and now it looks like that:

#!/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  = "06487d60-1537-11ea-84bb-8f71124cfdfb"
MQTT_PASSWORD  = "23309cdee31964b2ae4caed9417b689c9bebece2"
MQTT_CLIENT_ID = "389199a0-2f40-11ea-84bb-8f71124cfdfb"

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

while True:
    client.loop()
    
    if (time.time() > timestamp + 10):
        client.virtualWrite(1, PM2.5)
        client.virtualWrite(2, PM10)
        timestamp = time.time()
        i = i+1

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)


if __name__ == "__main__":
    cmd_set_sleep(0)
    cmd_firmware_ver()
    cmd_set_working_period(PERIOD_CONTINUOUS)
    cmd_set_mode(MODE_QUERY);
    while True:
        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)

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

        # append new values
        jsonrow = {'pm25': values[0], 'pm10': values[1], 'time': time.strftime("%d.%m.%Y %H:%M:%S")}
        data.append(jsonrow)

        # save it
        with open(JSON_FILE, 'w') as outfile:
            json.dump(data, outfile)

        if MQTT_HOST != '':
            pub_mqtt(jsonrow)
            
        print("Going to sleep for 1 min...")
        cmd_set_sleep(1)
        time.sleep(60)

and now I see that on terminal:

pi@raspberrypi:~ $ python czujnik.py 
Connecting to mqtt.mydevices.com:8883
Connected with result code 0
SUB v1/06487d60-1537-11ea-84bb-8f71124cfdfb/things/389199a0-2f40-11ea-84bb-8f71124cfdfb/cmd/+
PUB v1/06487d60-1537-11ea-84bb-8f71124cfdfb/things/389199a0-2f40-11ea-84bb-8f71124cfdfb/sys/model Python
PUB v1/06487d60-1537-11ea-84bb-8f71124cfdfb/things/389199a0-2f40-11ea-84bb-8f71124cfdfb/sys/version 1.1.0
PUB v1/06487d60-1537-11ea-84bb-8f71124cfdfb/things/389199a0-2f40-11ea-84bb-8f71124cfdfb/data/0 PM2.5: 
PUB v1/06487d60-1537-11ea-84bb-8f71124cfdfb/things/389199a0-2f40-11ea-84bb-8f71124cfdfb/data/1 PM10: 
PUB v1/06487d60-1537-11ea-84bb-8f71124cfdfb/things/389199a0-2f40-11ea-84bb-8f71124cfdfb/data/0 PM2.5: 
PUB v1/06487d60-1537-11ea-84bb-8f71124cfdfb/things/389199a0-2f40-11ea-84bb-8f71124cfdfb/data/1 PM10: 
PUB v1/06487d60-1537-11ea-84bb-8f71124cfdfb/things/389199a0-2f40-11ea-84bb-8f71124cfdfb/data/0 PM2.5: 
PUB v1/06487d60-1537-11ea-84bb-8f71124cfdfb/things/389199a0-2f40-11ea-84bb-8f71124cfdfb/data/1 PM10: 
PUB v1/06487d60-1537-11ea-84bb-8f71124cfdfb/things/389199a0-2f40-11ea-84bb-8f71124cfdfb/data/0 PM2.5: 
PUB v1/06487d60-1537-11ea-84bb-8f71124cfdfb/things/389199a0-2f40-11ea-84bb-8f71124cfdfb/data/1 PM10: 
PUB v1/06487d60-1537-11ea-84bb-8f71124cfdfb/things/389199a0-2f40-11ea-84bb-8f71124cfdfb/data/0 PM2.5: 
PUB v1/06487d60-1537-11ea-84bb-8f71124cfdfb/things/389199a0-2f40-11ea-84bb-8f71124cfdfb/data/1 PM10: 
PUB v1/06487d60-1537-11ea-84bb-8f71124cfdfb/things/389199a0-2f40-11ea-84bb-8f71124cfdfb/data/0 PM2.5: 
PUB v1/06487d60-1537-11ea-84bb-8f71124cfdfb/things/389199a0-2f40-11ea-84bb-8f71124cfdfb/data/1 PM10: 
PUB v1/06487d60-1537-11ea-84bb-8f71124cfdfb/things/389199a0-2f40-11ea-84bb-8f71124cfdfb/data/0 PM2.5: 
PUB v1/06487d60-1537-11ea-84bb-8f71124cfdfb/things/389199a0-2f40-11ea-84bb-8f71124cfdfb/data/1 PM10: 
PUB v1/06487d60-1537-11ea-84bb-8f71124cfdfb/things/389199a0-2f40-11ea-84bb-8f71124cfdfb/data/0 PM2.5: 
PUB v1/06487d60-1537-11ea-84bb-8f71124cfdfb/things/389199a0-2f40-11ea-84bb-8f71124cfdfb/data/1 PM10: 
PUB v1/06487d60-1537-11ea-84bb-8f71124cfdfb/things/389199a0-2f40-11ea-84bb-8f71124cfdfb/data/0 PM2.5: 
PUB v1/06487d60-1537-11ea-84bb-8f71124cfdfb/things/389199a0-2f40-11ea-84bb-8f71124cfdfb/data/1 PM10: 
PUB v1/06487d60-1537-11ea-84bb-8f71124cfdfb/things/389199a0-2f40-11ea-84bb-8f71124cfdfb/data/0 PM2.5: 
PUB v1/06487d60-1537-11ea-84bb-8f71124cfdfb/things/389199a0-2f40-11ea-84bb-8f71124cfdfb/data/1 PM10: 
....

and I see that in my dashboard:

sorry but your programming knowledge is really weak. Try this:

i=0
timestamp = 0

while True:
    client.loop()
    
    if (time.time() > timestamp + 10):
        client.virtualWrite(0, values[0])
        client.virtualWrite(1, values[1])
        timestamp = time.time()
        i = i+1

There’s only that error:

pi@raspberrypi:~ $ python czujnik.py 
Connecting to mqtt.mydevices.com:8883
Traceback (most recent call last):
  File "czujnik.py", line 28, in <module>
    client.virtualWrite(0, values[0])
NameError: name 'values' is not defined

can you share your entire code?

czujnik.py

#!/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  = "06487d60-1537-11ea-84bb-8f71124cfdfb"
MQTT_PASSWORD  = "23309cdee31964b2ae4caed9417b689c9bebece2"
MQTT_CLIENT_ID = "389199a0-2f40-11ea-84bb-8f71124cfdfb"

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

while True:
    client.loop()
    
    if (time.time() > timestamp + 10):
        client.virtualWrite(0, values[0])
        client.virtualWrite(1, values[1])
        timestamp = time.time()
        i = i+1

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)


if __name__ == "__main__":
    cmd_set_sleep(0)
    cmd_firmware_ver()
    cmd_set_working_period(PERIOD_CONTINUOUS)
    cmd_set_mode(MODE_QUERY);
    while True:
        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)

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

        # append new values
        jsonrow = {'pm25': values[0], 'pm10': values[1], 'time': time.strftime("%d.%m.%Y %H:%M:%S")}
        data.append(jsonrow)

        # save it
        with open(JSON_FILE, 'w') as outfile:
            json.dump(data, outfile)

        if MQTT_HOST != '':
            pub_mqtt(jsonrow)
            
        print("Going to sleep for 1 min...")
        cmd_set_sleep(1)
        time.sleep(60)
#!/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  = "06487d60-1537-11ea-84bb-8f71124cfdfb"
MQTT_PASSWORD  = "23309cdee31964b2ae4caed9417b689c9bebece2"
MQTT_CLIENT_ID = "389199a0-2f40-11ea-84bb-8f71124cfdfb"

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)


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)
    
        if (time.time() > timestamp + 10):
            client.virtualWrite(0, values[0])
            client.virtualWrite(1, values[1])
            timestamp = time.time()
            i = i+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)

        # append new values
        jsonrow = {'pm25': values[0], 'pm10': values[1], 'time': time.strftime("%d.%m.%Y %H:%M:%S")}
        data.append(jsonrow)

        # save it
        with open(JSON_FILE, 'w') as outfile:
            json.dump(data, outfile)

        if MQTT_HOST != '':
            pub_mqtt(jsonrow)
            
        print("Going to sleep for 1 min...")
        cmd_set_sleep(1)
        time.sleep(60)

Now this:

  File "czujnik.py", line 139
    client.loop()
    ^
IndentationError: unexpected indent

i have made changes to above code.

Now it works but there’s some error because it stops. First I see widgets on my dashboard and when it stops they dissapear. Second time I start that code it stops earlier.

pi@raspberrypi:~ $ python czujnik.py 
Connecting to mqtt.mydevices.com:8883
Y: 18, M: 11, D: 16, ID: 0xd30d, CRC=OK
Connected with result code 0
SUB v1/06487d60-1537-11ea-84bb-8f71124cfdfb/things/389199a0-2f40-11ea-84bb-8f71124cfdfb/cmd/+
PUB v1/06487d60-1537-11ea-84bb-8f71124cfdfb/things/389199a0-2f40-11ea-84bb-8f71124cfdfb/sys/model Python
PUB v1/06487d60-1537-11ea-84bb-8f71124cfdfb/things/389199a0-2f40-11ea-84bb-8f71124cfdfb/sys/version 1.1.0
PM2.5:  0.0 , PM10:  0.0
PM2.5:  3.8 , PM10:  12.8
PM2.5:  4.2 , PM10:  13.2
PM2.5:  4.8 , PM10:  11.6
PM2.5:  4.8 , PM10:  10.5
PM2.5:  5.0 , PM10:  9.9
PM2.5:  4.9 , PM10:  9.3
PM2.5:  5.0 , PM10:  9.1
PM2.5:  5.2 , PM10:  10.9
PM2.5:  5.3 , PM10:  10.6
PM2.5:  5.4 , PM10:  10.6
PM2.5:  5.5 , PM10:  10.5
PM2.5:  5.7 , PM10:  10.6
PM2.5:  5.7 , PM10:  10.7
PM2.5:  5.7 , PM10:  10.7
PUB v1/06487d60-1537-11ea-84bb-8f71124cfdfb/things/389199a0-2f40-11ea-84bb-8f71124cfdfb/data/0 5.7
PUB v1/06487d60-1537-11ea-84bb-8f71124cfdfb/things/389199a0-2f40-11ea-84bb-8f71124cfdfb/data/1 10.7
Going to sleep for 1 min...
PM2.5:  0.0 , PM10:  0.0
PM2.5:  0.0 , PM10:  0.0
PM2.5:  3.8 , PM10:  6.4
PM2.5:  4.8 , PM10:  7.4
PM2.5:  5.0 , PM10:  6.7
PM2.5:  5.3 , PM10:  7.5
PM2.5:  5.3 , PM10:  8.1
PM2.5:  5.3 , PM10:  8.4
PM2.5:  5.4 , PM10:  8.3
PM2.5:  5.3 , PM10:  8.1
PM2.5:  5.4 , PM10:  8.0
PM2.5:  5.5 , PM10:  9.2
PM2.5:  5.4 , PM10:  9.1
PM2.5:  5.5 , PM10:  9.0
PM2.5:  5.5 , PM10:  9.4
PUB v1/06487d60-1537-11ea-84bb-8f71124cfdfb/things/389199a0-2f40-11ea-84bb-8f71124cfdfb/data/0 5.5
PUB v1/06487d60-1537-11ea-84bb-8f71124cfdfb/things/389199a0-2f40-11ea-84bb-8f71124cfdfb/data/1 9.4
Going to sleep for 1 min...
^CTraceback (most recent call last):
  File "czujnik.py", line 170, in <module>
    cmd_set_sleep(1)
  File "czujnik.py", line 103, in cmd_set_sleep
    read_response()
  File "czujnik.py", line 80, in read_response
    byte = ser.read(size=1)
  File "/usr/lib/python2.7/dist-packages/serial/serialposix.py", line 483, in read
    ready, _, _ = select.select([self.fd, self.pipe_abort_read_r], [], [], timeout.time_left())
KeyboardInterrupt
pi@raspberrypi:~ $ python czujnik.py 
Connecting to mqtt.mydevices.com:8883
Y: 18, M: 11, D: 16, ID: 0xd30d, CRC=OK
Connected with result code 0
SUB v1/06487d60-1537-11ea-84bb-8f71124cfdfb/things/389199a0-2f40-11ea-84bb-8f71124cfdfb/cmd/+
PUB v1/06487d60-1537-11ea-84bb-8f71124cfdfb/things/389199a0-2f40-11ea-84bb-8f71124cfdfb/sys/model Python
PUB v1/06487d60-1537-11ea-84bb-8f71124cfdfb/things/389199a0-2f40-11ea-84bb-8f71124cfdfb/sys/version 1.1.0
PM2.5:  0.0 , PM10:  0.0
PM2.5:  3.6 , PM10:  6.9
PM2.5:  3.7 , PM10:  6.0
PM2.5:  4.5 , PM10:  9.2
PM2.5:  4.6 , PM10:  8.6
#!/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  = "06487d60-1537-11ea-84bb-8f71124cfdfb"
MQTT_PASSWORD  = "23309cdee31964b2ae4caed9417b689c9bebece2"
MQTT_CLIENT_ID = "389199a0-2f40-11ea-84bb-8f71124cfdfb"

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)


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

Maybe this problem is because aqi.py code still works? I # that in crontab but it’s still working :confused:

did you try the above code?

Yest I test it now but on dashboard it show me only last values from first series and it don’t show rest of results:

Connecting to mqtt.mydevices.com:8883
Y: 18, M: 11, D: 16, ID: 0xd30d, CRC=OK
Connected with result code 0
SUB v1/06487d60-1537-11ea-84bb-8f71124cfdfb/things/389199a0-2f40-11ea-84bb-8f71124cfdfb/cmd/+
PUB v1/06487d60-1537-11ea-84bb-8f71124cfdfb/things/389199a0-2f40-11ea-84bb-8f71124cfdfb/sys/model Python
PUB v1/06487d60-1537-11ea-84bb-8f71124cfdfb/things/389199a0-2f40-11ea-84bb-8f71124cfdfb/sys/version 1.1.0
PM2.5:  5.6 , PM10:  8.3
PM2.5:  5.7 , PM10:  8.5
PM2.5:  5.6 , PM10:  9.2
PM2.5:  5.6 , PM10:  9.1
PM2.5:  5.5 , PM10:  9.2
PM2.5:  5.5 , PM10:  9.7
PM2.5:  5.7 , PM10:  9.9
PM2.5:  5.5 , PM10:  9.8
PM2.5:  5.7 , PM10:  9.5
PM2.5:  5.6 , PM10:  9.7
PM2.5:  5.8 , PM10:  9.9
PM2.5:  5.8 , PM10:  10.2
PM2.5:  5.5 , PM10:  9.8
PM2.5:  5.5 , PM10:  9.6
PM2.5:  5.5 , PM10:  9.7

show me only PM2.5: 5.5 and PM10: 9.7 in dashboard.
Then it stops after second series:

Connecting to mqtt.mydevices.com:8883
Y: 18, M: 11, D: 16, ID: 0xd30d, CRC=OK
Connected with result code 0
SUB v1/06487d60-1537-11ea-84bb-8f71124cfdfb/things/389199a0-2f40-11ea-84bb-8f71124cfdfb/cmd/+
PUB v1/06487d60-1537-11ea-84bb-8f71124cfdfb/things/389199a0-2f40-11ea-84bb-8f71124cfdfb/sys/model Python
PUB v1/06487d60-1537-11ea-84bb-8f71124cfdfb/things/389199a0-2f40-11ea-84bb-8f71124cfdfb/sys/version 1.1.0
PM2.5:  5.6 , PM10:  8.3
PM2.5:  5.7 , PM10:  8.5
PM2.5:  5.6 , PM10:  9.2
PM2.5:  5.6 , PM10:  9.1
PM2.5:  5.5 , PM10:  9.2
PM2.5:  5.5 , PM10:  9.7
PM2.5:  5.7 , PM10:  9.9
PM2.5:  5.5 , PM10:  9.8
PM2.5:  5.7 , PM10:  9.5
PM2.5:  5.6 , PM10:  9.7
PM2.5:  5.8 , PM10:  9.9
PM2.5:  5.8 , PM10:  10.2
PM2.5:  5.5 , PM10:  9.8
PM2.5:  5.5 , PM10:  9.6
PM2.5:  5.5 , PM10:  9.7
PUB v1/06487d60-1537-11ea-84bb-8f71124cfdfb/things/389199a0-2f40-11ea-84bb-8f71124cfdfb/data/0 5.5
PUB v1/06487d60-1537-11ea-84bb-8f71124cfdfb/things/389199a0-2f40-11ea-84bb-8f71124cfdfb/data/1 9.7
Going to sleep for 1 min...
PM2.5:  0.0 , PM10:  0.0
PM2.5:  0.0 , PM10:  0.0
PM2.5:  3.5 , PM10:  18.3
PM2.5:  4.2 , PM10:  11.9
PM2.5:  5.1 , PM10:  12.5
PM2.5:  6.0 , PM10:  12.5
PM2.5:  6.5 , PM10:  12.3
PM2.5:  6.3 , PM10:  13.8
PM2.5:  6.1 , PM10:  12.5
PM2.5:  5.9 , PM10:  11.9
PM2.5:  5.8 , PM10:  11.3
PM2.5:  6.0 , PM10:  11.4
PM2.5:  6.2 , PM10:  11.4
PM2.5:  6.1 , PM10:  11.0
PM2.5:  6.1 , PM10:  10.5
PUB v1/06487d60-1537-11ea-84bb-8f71124cfdfb/things/389199a0-2f40-11ea-84bb-8f71124cfdfb/data/0 6.1
PUB v1/06487d60-1537-11ea-84bb-8f71124cfdfb/things/389199a0-2f40-11ea-84bb-8f71124cfdfb/data/1 10.5
Going to sleep for 1 min...
Disconnected with result code 1

are the widgets green color on your dashboard? you need to add them by clicking + present on top right corner.

Yes I add them:


They change when I start again python czujnik.py and now they’re offline and in ssh shows: Disconnected with result code 1 after second series.
When I ctrl+c:

^CTraceback (most recent call last):
  File "czujnik.py", line 136, in <module>
    values = cmd_query_data();
  File "czujnik.py", line 94, in cmd_query_data
    d = read_response()
  File "czujnik.py", line 80, in read_response
    byte = ser.read(size=1)
  File "/usr/lib/python2.7/dist-packages/serial/serialposix.py", line 483, in read
    ready, _, _ = select.select([self.fd, self.pipe_abort_read_r], [], [], timeout.time_left())
KeyboardInterrupt

i am not sure but i guess it is because the serial port is still open and you are trying to close it forcefully. Ignore it, if it only happens when you stop the script with ctrl+c

I make ctrl+c because nothing happen longer than 5 minutes and terminal stops with: Disconnected with result code 1 and cayenne dashboard is offline.

#!/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  = "06487d60-1537-11ea-84bb-8f71124cfdfb"
MQTT_PASSWORD  = "23309cdee31964b2ae4caed9417b689c9bebece2"
MQTT_CLIENT_ID = "389199a0-2f40-11ea-84bb-8f71124cfdfb"

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