Rasperry Pi, Python, SDS011, Thingspeak channel update, Help appreciated.

5 views (last 30 days)
Hello Community,
first of all let me admit, that I am - according to python - a "script-kiddie". I recently learned html5, css3 and javascript, but that is not helpful here. That is why I need your help.
I found a script that is reading the data from my sds011 sensor. It passes its data to a webpage. So far so good. Now I would like to pass the data to thingspeak. After a couple of hours trying without really understanding I would appreciate help. I think the code line below ist the one I need for updating my channel in thingspeak. But the channel remains empty. No data shown. What have I done wrong? Help appreciated. Learning python is on my "To-Do-List" ;-)
Kind regards,
Roger
Short code:
import urllib
....
urllib.request.urlopen("https://api.thingspeak.com/update?api_key=RJASGFLWRVM5JKHM&field1=pm25&field2=pm10")
The entire 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 urllib
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)
#!!!!!!!!!!!!!!!!!!! HERE
urllib.request.urlopen("https://api.thingspeak.com/update?api_key=RJASGFLWRVM5JKHM&field1=pm25&field2=pm10")
print("Going to sleep for 2 min...")
# Alter time.sleep = 1200
cmd_set_sleep(1)
time.sleep(120)
  1 Comment
Roger Notknomuch
Roger Notknomuch on 26 May 2020
In the meantime I found a solution.
For anybody who is interested. I added a writing method using websockets...
Here is the entire script:
#!/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
####### ADDED
import paho.mqtt.publish as publish
import psutil
import string
# The ThingSpeak Channel ID.
# Replace <YOUR-CHANNEL-ID> with your channel ID.
channelID = "1061352"
# The write API key for the channel.
# Replace <YOUR-CHANNEL-WRITEAPIKEY> with your write API key.
writeAPIKey = "RJASGFLWRVM5JKHM"
# The hostname of the ThingSpeak MQTT broker.
mqttHost = "mqtt.thingspeak.com"
# You can use any username.
mqttUsername = "Roger NotKnoMuch"
# Your MQTT API key from Account > My Profile.
mqttAPIKey = "GIE04M6OE1XPQWX0"
# Define websocket on Port 80
tTransport = "websockets"
tPort = 80
# Create the topic string.
topic = "channels/" + channelID + "/publish/" + writeAPIKey
######## ADDED END
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)
###### ADDED
# get the system performance data over 20 seconds.
pm25 = values[0]
pm10 = values[1]
# build the payload string.
payload = "field1=" + str(pm25) + "&field2=" + str(pm10)
# attempt to publish this data to the topic.
try:
publish.single(topic, payload, hostname=mqttHost, transport=tTransport, port=tPort,auth={'username':mqttUsername,'password':mqttAPIKey})
print (" Published Data = ",pm25," and ", pm10," to host: " , mqttHost , " clientID= " , clientID)
except (KeyboardInterrupt):
break
except:
print ("There was an error while publishing the data.")
###### ADDED END
print("Going to sleep for 1 min...")
# Alter time.sleep = 1200
cmd_set_sleep(1)
time.sleep(1200)

Sign in to comment.

Accepted Answer

Roger Notknomuch
Roger Notknomuch on 26 May 2020
Problem solved

More Answers (0)

Communities

More Answers in the  ThingSpeak Community

Categories

Find more on Write Data to Channel in Help Center and File Exchange

Products

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!