
Luftfiltergeräte hört man aktuell an allen Ecken, die Corona Pandemie hat dies deutlich befördert. Da ich im Mai immer mal für 4 Wochen an einer Pollenallergie leide und ich schon einen Tipp für ein Luftfiltergerät bekommen habe, habe ich mich mit den Geräten etwas mehr auseinander gesetzt. Die Geräte messen in der Regel die Feinstaubmenge in der Luft und sind dann in verschiedenen Stufen unterwegs. Also dachte ich mir, messen wir doch erst mal den Feinstaub in der Wohnung, bevor wir Geräte aufstellen. 😉
Auf die Suche gegangen, bin ich dann auf den PM-Sensor SDS011 gestoßen, dieser kann per USB angeschlossen werden und misst in PM 2,5 und PM 10. Infos zu diesen Werten findet ihr in Wikipedia beim Suchbegriff Feinstaub. Auch die europäischen Grenzwerte findet Ihr dort. Hier nun der Sensor.


Das kleine eckige oben drauf ist ein kleiner Lüfter, dieser ist auch leicht zu hören. Also Obacht wenn ihr das Teil im Wohnzimmer aufstellen wollt. Bei mir steht er im Esszimmer und stört mich von der Geräuschkulisse nicht. Man kann das Teil jedoch auch gut in einen Schrank verlegen, denn es hat diesen silbernen Anschluss. Dort kann ein Schlauch angeschlossen werden, dieser muss am Ende eben nur die zu testende Luft frei ansaugen können. Dies gibt einem vielfältige Möglichkeiten das Teil auch verdeckt zu verbauen.
Nach dem Einstecken im Raspberry PI meldet sich dieses mit (Befehloutput -> dmesg)
[ 8.003492] usbcore: registered new interface driver ch341
[ 8.003588] usbserial: USB Serial support registered for ch341-uart
[ 8.003704] ch341 1-1.3:1.0: ch341-uart converter detected
[ 8.026555] usb 1-1.3: ch341-uart converter now attached to ttyUSB0
Zum Auslesen des Sensors nutze ich das Python Programm von marw -> https://gist.github.com/marw/ read_nova_pm_sensor.py
Ich habe das Python Programm leicht angepasst, sodass statt ttyUSB0 ein fester Name verwendet wird, den ich per UDEV Rule definiert habe. Soll einfach dafür sorgen, wenn sich ein 2. Gerät im System befindet, dass es immer das Richtige für den Sensor verwendet.
pi@blackberrypi:~ $ cat /usr/local/bin/feinstaub.py#!/usr/bin/env python3
"""
Get reading from Nova PM Sensor SDS011
(dust sensor, air quality sensor, PM10, PM2,5)
Designed to run from cron and append CSV file.
Script tested using Python3.4 on Ubuntu 14.04.
TODO: choose by dev name using udev, add dev id info, python package pyudev
udevadm info -q property --export /dev/ttyUSB_ch341
"""
import os
import csv
import io
import logging
import datetime
import argparse
try:
import serial
except ImportError:
print('Python serial library required, on Ubuntu/Debian:')
print(' apt-get install python-serial python3-serial')
raise
LOG_FORMAT = '%(asctime)-15s %(levelname)-8s %(message)s'
def append_csv(filename, field_names, row_dict):
"""
Create or append one row of data to csv file.
"""
file_exists = os.path.isfile(filename)
with io.open(filename, 'a', encoding='utf-8') as csvfile:
writer = csv.DictWriter(csvfile,
delimiter=',',
lineterminator='\n',
fieldnames=field_names)
if not file_exists:
writer.writeheader()
writer.writerow(row_dict)
def read_nova_dust_sensor(device='/dev/ttyUSB_ch341'):
dev = serial.Serial(device, 9600)
if not dev.isOpen():
dev.open()
msg = dev.read(10)
assert msg[0] == ord(b'\xaa')
assert msg[1] == ord(b'\xc0')
assert msg[9] == ord(b'\xab')
pm25 = (msg[3] * 256 + msg[2]) / 10.0
pm10 = (msg[5] * 256 + msg[4]) / 10.0
checksum = sum(v for v in msg[2:8]) % 256
assert checksum == msg[8]
return {'PM10': pm10, 'PM2_5': pm25}
def main():
logging.basicConfig(format=LOG_FORMAT, level=logging.INFO)
parser = argparse.ArgumentParser(description='Read data from Nova PM sensor.')
parser.add_argument('--device', default='/dev/ttyUSB_ch341',
help='Device file of connected by USB RS232 Nova PM sensor')
parser.add_argument('--csv', default=None,
help='Append results to csv, you can use year, month, day in format')
args = parser.parse_args()
data = read_nova_dust_sensor(args.device)
logging.info('PM10=% 3.1f ug/m^3 PM2.5=% 3.1f ug/m^3', data['PM10'], data['PM2_5'])
if args.csv:
field_list = ['date', 'PM10', 'PM2_5']
today = datetime.datetime.today()
data['date'] = today.strftime('%Y-%m-%d %H:%M:%S')
csv_file = args.csv % {'year': today.year,
'month': '%02d' % today.month,
'day': '%02d' % today.day,
}
append_csv(csv_file, field_list, data)
if __name__ == '__main__':
main()
Damit das Programm funktioniert, müssen die Pakete python-serial und python3-serial installiert sein.
pi@blackberrypi:~ $ sudo apt install python-serial python3-serial
Beim Aufruf des Python Programm ergibt sich folgender Output.
pi@blackberrypi:~ $ feinstaub.py
2022-01-15 02:09:03,905 INFO PM10= 10.7 ug/m^3 PM2.5= 3.0 ug/m^3
Die UDEV Rule sieht wie folgt aus.
pi@blackberrypi:~ $ cat /etc/udev/rules.d/88-ch341.rules
ACTION=="add", ATTRS{serial}=="3f980000.usb", SYMLINK+="ttyUSB_ch341"
Der folgende Befehl aktiviert die Rule
pi@blackberrypi:~ $ sudo udevadm control --reload
Danach ist der Sensor immer unter /dev/ttyUSB_ch341 zu finden.
Um die Werte aus dem Python Programm für mein Zabbix einfacher lesbar zu machen, habe ich dafür ein kleines Shell Script geschrieben. Diese liegt zwei Dateien /tmp/pm10 und /tmp/pm25 ab und liest den Wert jede Minute aus. Das Programm läuft dann dauerhaft im Hintergrund.
pi@blackberrypi:~ $ cat /usr/local/bin/feinstaub.sh
#!/bin/bash
# Script das feinstaub.py aufruft und die beiden Werte in pm10 und pm25 teilt um diese dann aus zabbix auszulesen
# pm10 steht für partikel 10 und pm25 für partikel 2,5
while true
do
feinstaub.py 2>&1 | cut -f 9,12 -d ' '| { read pm10 pm25;
echo $pm10 > /tmp/pm10;
echo $pm25 > /tmp/pm25; }
sleep 60
done
Die Zabbix Config hierfür sieht wie folgt aus.


Sidetip: Wem vielleicht in meinen Zabbix Configs die History storage period und der 0 Wert bei Trend storage period aufgefallen ist. Diese habe ich bewusst so gewählt. Ich möchte eine lange Zeit Echtwerte (vollständig Detailtiefe). Daher habe ich Trend völlig abgeschaltet und die History auf 8 Jahre (8×365 = 2920) hoch gesetzt.
So sieht nun ein ganz „normaler“ Tag im Haus im Zabbix Graph aus. 🙂

BTW bei diesen Feinstaubwerten wäre kein einziger Luftfilter angelaufen, da sich die Feinstaubwerte völlig im Normalbereich befinden.
Automatisierung? Dann los mit Ansible.
# cat /etc/ansible/feinstaub.yml
---
- name: Transfer feinstaub.sh Script and feinstaub.py Python PGM and execute the script with user pi
hosts: blackberrypi.home,raspberrypi.home
become: yes
tasks:
- name: Install python3-serial python-serial
apt:
pkg:
- python3-serial
- python-serial
- name: Transfer the feinstaub.sh script and feinstaub.py python PGM Code and check_feinstaub.sh for cron.d
copy: src={{ item }} dest=/usr/local/bin/
with_fileglob:
- feinstaub/*
- name: Changing Permissions shell script
file: dest=/usr/local/bin/feinstaub.sh owner=root group=root mode=0755
- name: Changing Permissions feinstaub.py python pgm
file: dest=/usr/local/bin/feinstaub.py owner=root group=root mode=0755
- name: Transfer cron.d Entry for automatic start at reboot and check script
copy: src=/etc/ansible/cron.d/feinstaub dest=/etc/cron.d/
- name: Transfer feinstaub tty Symlink UDEV Rule in rules.d (/dev/ttyUSB_ch341)
copy: src=/etc/ansible/udev/rules.d/88-ch341.rules dest=/etc/udev/rules.d/
- name: reload udev
command: "udevadm control --reload-rules"
- name: kill all running feinstaub process
shell: "killall feinstaub.sh --wait"
ignore_errors: true # In case there is no process
- name: Start feinstaub.sh in Backgroud
become_user: pi
shell: "(/usr/local/bin/feinstaub.sh >/dev/null 2>&1 &)"
async: 10
poll: 0
Das Ansible Playbook (YML) kann dann einfach mit folgendem Befehl verteilt werden.
ansible-playbook -u pi feinstaub.yml
Wer das Ansible Playbook genau betrachtet, dem ist sicherlicht nicht entgangen, dass 2 Zielhosts hier hinterlegt sind. Das ist richtig. Nachdem der 1. Feinstaubsensor so erfolgreich in meinem Heim lief, fragte ich mich, welche Feinstaubwerte denn draußen existieren und welchen Einfluß diese wiederum auf meine Werte im Haus haben. Lohnt es sich bei schlechten Werten im Haus zu lüften oder sind draußen gar noch schlechterer Werte?
Durch Ansible ist dies schnell auf einen 2. Raspberry bei mir in der Garage neben dem Haus verteilt. Den 2. gekauften Sensor einfach angesteckt und mit einem kleinen Schlauch an die Außenluft verbunden. Zu beachten ist bei den Sensoren, dass diese auch bei Nebel reagieren und bei ganz feinem Nieselregen. Daher nicht gleich in Panik verfallen, wenn die Werte mal explodieren und es einfach nur regnet draußen. 😉


So sieht das dann zusammen im Zabbix Graph aus.

Bei der Spitze morgens um 7 Uhr sieht man, was passiert wenn einer der Nachbarn seinen Kamin anwirft. 😀
Sideinfo: Wußtet Ihr, dass beim Kochen massiv Feinstaub entsteht (weit über die Grenzwerte)? Hier mal ein Graph wo in der Pfanne 10 Minuten etwas Gemüse angebraten wurde. Seitdem ist bei mir die Dunstabzugshaube immer an. 🙂 Die gute Nachricht: Mit Lüften konnte das Problem relativ schnell entschärft werden. Und nein die Küche war nicht blau. 😀

Hier noch ein Link zu einem wissenschaftlichen Bericht dazu.
Wenn Ihr Fragen oder Anmerkungen habt, schreibt mir gerne eine Mail -> info AT svenczaja.de