Difference between revisions of "Raspberry Pi Environmental Monitoring"
Michael.mast (talk | contribs) |
Michael.mast (talk | contribs) |
||
| Line 183: | Line 183: | ||
===Install Node-Red=== | ===Install Node-Red=== | ||
<ref>https://nodered.org/docs/getting-started/raspberrypi</ref> | <ref>https://nodered.org/docs/getting-started/raspberrypi</ref> | ||
| + | When running the install script, make sure the pi settings are applied. | ||
<pre> | <pre> | ||
bash <(curl -sL https://raw.githubusercontent.com/node-red/linux-installers/master/deb/update-nodejs-and-nodered) | bash <(curl -sL https://raw.githubusercontent.com/node-red/linux-installers/master/deb/update-nodejs-and-nodered) | ||
| + | sudo systemctl enable --now nodered | ||
</pre> | </pre> | ||
| + | Install the dashboard components<ref>https://flows.nodered.org/node/node-red-dashboard</ref> | ||
Revision as of 10:14, 24 December 2019
Contents
Purpose
To monitor air temperature, humidity, and air quality.
Air Quality
Base Config for Sensor
A friend sent me a Nova PM Sensor. I do not know python yet, but looking over the script that is readily available[1][2] I should be able to modify this to work for my needs.
mkdir -p /home/pi/build/air && cd /home/pi/build/air sudo apt install git-core python-serial python-enum mariadb-server python-mysql.connector wget -O aqi.py https://raw.githubusercontent.com/zefanja/aqi/master/python/aqi.py echo [] > aqi.json sed -i 's|/var/www/html/aqi.json|/home/pi/build/air/aqi.json|' aqi.py
At this point we can run the script, see output on the screen, and see the history written to the json file.
./aqi.py Y: 18, M: 1, D: 18, ID: 0xbc2d, CRC=OK PM2.5: 0.0 , PM10: 0.0 PM2.5: 0.7 , PM10: 0.7 PM2.5: 0.6 , PM10: 0.6 PM2.5: 0.7 , PM10: 0.7
Configure for writing to database
However, I want the history written to a database. Configure mariadb anyway you want, if you have credentials keep them on hand.
create database air; create user air; grant all on air.* to 'air'; use air; create table aqi (pm25 FLOAT, pm10 FLOAT, date DATETIME); select * from aqi; Empty set (0.00 sec) insert into aqi values (2.1, 2.3, now()); Query OK, 1 row affected (0.02 sec) select * from aqi; +------+------+---------------------+ | pm25 | pm10 | date | +------+------+---------------------+ | 2.1 | 2.3 | 2019-12-20 13:32:18 | +------+------+---------------------+ 1 row in set (0.00 sec)
Now we edit the script to work with mysql[3]
Please note that of this writing I the script searches the entire database for 0 values and deletes them. I need to go back and update to simply not write 0 values in the first place.
Full Modified 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, mysql.connector
mydb = mysql.connector.connect(
host="localhost",
user="air",
database="air"
)
mycursor = mydb.cursor()
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
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()
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])
pm25=values[0]
pm10=values[1]
mycursor.execute('INSERT INTO aqi (pm25, pm10, date) VALUES (%s, %s, %s)' % (pm25,pm10,'now()'))
mydb.commit()
mycursor.execute("delete from aqi where pm10 = 0 and pm25 = 0")
time.sleep(2)
print("Going to sleep for 1 min...")
cmd_set_sleep(1)
time.sleep(60)
mycursor.execute("delete from aqi where date < (now() - interval 1 year)")
Graph Display
The same pointed me to node-red for the display. What I really wanted was a nerdy ncurses display, but node-red should suffice until I learn ncurses.
Install Node-Red
[4] When running the install script, make sure the pi settings are applied.
bash <(curl -sL https://raw.githubusercontent.com/node-red/linux-installers/master/deb/update-nodejs-and-nodered) sudo systemctl enable --now nodered
Install the dashboard components[5]
- ↑ https://hackernoon.com/how-to-measure-particulate-matter-with-a-raspberry-pi-75faa470ec35
- ↑ https://openschoolsolutions.org/measure-particulate-matter-with-a-raspberry-pi/
- ↑ https://www.w3schools.com/python/python_mysql_insert.asp
- ↑ https://nodered.org/docs/getting-started/raspberrypi
- ↑ https://flows.nodered.org/node/node-red-dashboard