Roboter Staubsauger AEG RX9 auseinander nehmen - und wieder zusammenbauen ;)

Bild
Saugroboter AEG RX9 auseinander nehmen - und wieder zusammenbauen ;) Als unser jahrelang treuer Saugroboter RX9 von AEG wegen eines Fehler mit der Sensorik (?) den Geist aufgegeben hatte, wollte ich einfach probieren ihn zu reparieren. Wir waren mit dem RX9 auch eigentlich sehr zufrieden und wollten es nicht riskieren, am Ende viel Geld für ein schlechteres Modell auszugeben. Eine Reparatur beim Hersteller war für erstmal mich keine Option - der Preis lag pauschal bei rund 300 Euro. Für den Preis wollte ich es lieber selbst versuchen. Anleitungen und Videos zur erweiterten Selbsthilfe sind im Netz aber nicht zu finden.  Also blieb nur der Weg, das Gerät selbst zu öffnen, um an die Teile zu kommen. Zum einen gibt es im Netz z.B. bei eBay Ersatzteile (anscheinend Originale) oder man versucht, ein gebrauchtes Exemplar zu kaufen. Im Februar 2023 gab es deutschlandweit mehrere hundert Treffer mit Preisen ab 50 Euro - je nach Fehlerklasse.. So bin ich günstig an ein Gerät mit dem Fehler &quo

Feinstaubsensor SDS011 auf dem Raspberry Pi

Hier beschreibe ich, wie der Feinstaubsensor Nova PM SDS011 bei mir auf dem Raspberry Pi läuft und die Daten an das Projekt luftdaten.info übermittelt.

Ich habe meine Messstation ähnlich gebaut wie bei www.luftdaten.info beschrieben; nur dass ich einen Raspberry Pi Zero W verwendet habe und zusätzlich noch den Sensor DHT22 für Temperatur und Luftdruck. Meine Messergebnisse vom Feinstaubsensor werden an das Projekt www.luftdaten.info übermittelt.

Vom Prinzip her laufen bei mir im Hintergrund immer wieder kleine Skripte als Cron-Jobs, welche die Werte der Sensoren in der rrd-Datenbank ablegen. Damit kann ich die Daten dann für eine Vierlzahl von Zwecken weiterverwenden, ohne immer wieder die Sensoren abfragen zu müssen. Gerade beim SDS011 war mir wichtig, dass er nur alle 10 Minuten läuft, damit sich die Lebensdauer des Geräts erhöht.

Leider werden bei luftdaten.info die Werte für Temperatur und Luftfeuchtigkeit noch nicht angezeigt. Daher nutze ich die bisher nur für andere Zwecke, z.B. zur Anzeige über meinen FHEM-Server mit der TabletUI.

1. Liste der Bauteile

- 2x Abwasserrohrbogen in der größten Ausführung. Gibts beim Baumarkt für wenig Geld.
- Raspberry Pi 3 mit Case
- Sensor für Temperatur und Luftfeuchtigkeit DHT22
- Feinstaubsensor SDS011 mit USB-Modul; habe meinen bei eBay über eckstein besorgt. Immer aufpassen, dass auch das USB-Modul mit dabei ist. Es ist wichtig für den einfachen Betrieb am Pi.
- Kleiner Schlauch zum Ansaugen der Außenluft; im Prinzip genügt hier ein Strohhalm
- Heißkleber, Schrauben und doppelseitiges Klebeband zur Befestigung der Bauteile

2. Zusammenbau 

Der grundlegende Zusammenbau wird bei www.luftdaten.info beschrieben - ein so geniales wie einfaches Konzept!

Mit dem Heißkleber habe ich den Pi samt Gehäuse im Innenraum fixiert. Den SDS011 habe ich mit zwei kleinen Holzschrauben am Rohrbogen befestigt, so dass der Schlauch unten aus einem der Rohrbögen herausragen kann. Der DHT22 sitzt mit einem doppelseitigen Klebeband am unteren Ende. Besser wäre es aber eigentlich, ihn außen zu montieren, weil die Temperatur innen im Rohr besonders bei Sonneneinstrahlung von der Außentemperatur abweichen kann.

Die Stromversorgung läuft bei mir auf dem Balkon direkt per (wetterfestem) USB-Adapter.

3. Konfiguration DHT22

Der DHT22 wird einfach an die GPIO-Pins des Raspberry Pi angeschlossen. Dafür und für die Basisinbetriebnahme über das Binary "loldht" gibt es tonnenweise Beschreibung im Netz, z.B. hier

Dann habe ich mir ein kleines Skipt geschrieben, welches die Werte für Temperatur und Luftfeuchtigkeit alle paar Minuten in Dateien schreibt:


#!/bin/bash

#Einstellungen
MINTEMP=-20
MAXTEMP=50
MINHUM=0
MAXHUM=100

###########################################

DIR=/opt/templog
cd $DIR

GPIO=$1
INPUT=$(sudo ./loldht $GPIO |grep Temperature)
#echo $INPUT
HUM=$(echo $INPUT|cut -d " " -f3)
TEMP=$(echo $INPUT|cut -d " " -f7)

if [ $(echo "if (${HUM} > ${MAXHUM}) 1 else 0" | bc) -eq 1 -o $(echo "if (${HUM} < ${MINHUM}) 1 else 0" | bc) -eq 1 ]; then
    if [ -f $DIR/dht_hum.txt ]; then
        cat $DIR/dht_hum.txt
    fi
else
    echo $HUM
    echo $HUM > $DIR/dht_hum.txt
fi

if [ $(echo "if (${TEMP} > ${MAXTEMP}) 1 else 0" | bc) -eq 1 -o $(echo "if (${TEMP} < ${MINTEMP}) 1 else 0" | bc) -eq 1 ]; then
    if [ -f $DIR/dht_temp.txt ]; then
        cat $DIR/dht_temp.txt
    fi
else
    echo $TEMP
    echo $TEMP > $DIR/dht_temp.txt
fi


4. Konfiguration SDS011

Dank des USB-Moduls ist der SDS011 kinderleicht zu betreiben. Bei mir sieht das dann so aus:

pi@sensorium:/opt/feinstaub/dusty/luftdaten-python $ lsusb
Bus 001 Device 004: ID 1a86:7523 QinHeng Electronics HL-340 USB-Serial adapter

Die Ansteuerung nehme ich dann über ein Python-Skript aus dem Netz vor, ein gutes gibt es z.B. hier

Damit werden dann die Werte für PPM10 und PPM2.5 in zwei Dateien geschrieben.

5. Lokales sammeln und persistieren der Daten 

Die Skripte zum Sammeln der Daten von den Sensoren laufen bei mir als Cronjob alle 10 Minuten:

*/10 * * * * cd /opt/feinstaub;./feinstaub.py
*/10 * * * * /opt/templog/dht22.sh
*/10 * * * * /opt/templog/rrdlogger_novadht.py

Für die Persistierung der Werte mit rrdtool habe ich die Datenbasis so angelegt:

#!/bin/sh

rrdtool create /opt/templog/data/templog_novadht.rrd --step 600  \
DS:humidity:GAUGE:1200:0:100  \
DS:temperature:GAUGE:1200:-50:100  \
DS:pm10:GAUGE:1200:-1:9999  \
DS:pm25:GAUGE:1200:-1:9999  \
RRA:AVERAGE:0.5:1:144 \
RRA:AVERAGE:0.5:3:336 \
RRA:AVERAGE:0.5:6:720 \
RRA:AVERAGE:0.5:36:1460

Für das Einlesen der Daten aus den Dateien in die Datenbank nutze ich dann wiederum ein Skript:

#!/usr/bin/python

import logging
import logging.handlers
import rrdtool
import time
import sys
import commands

def do_update():
  timestamp = time.time()
  humidity = commands.getstatusoutput("cat /opt/templog/dht_hum.txt")
  temperature = commands.getstatusoutput("cat /opt/templog/dht_temp.txt")
  pm10 = commands.getstatusoutput("cat /opt/feinstaub/ppm10.txt")
  pm25 = commands.getstatusoutput("cat /opt/feinstaub/ppm25.txt")
  rrdtool.update("/opt/templog/data/templog_novadht.rrd","%d:%s:%s:%s:%s" % (timestamp, humidity[1], temperature[1], pm10[1], pm25[1]))
  print timestamp
  print humidity[1]
  print temperature[1]
  print pm10[1]
  print pm25[1]

# set up logging to syslog to avoid output being captured by cron
syslog = logging.handlers.SysLogHandler(address="/dev/log")
syslog.setFormatter(logging.Formatter("templogger: %(levelname)s %(message)s"))
logging.getLogger().addHandler(syslog)

do_update()
Das Skript läuft ebenfalls als Cronjob alle 10 Minuten (siehe unter 5).
6. Senden der Daten an luftdaten.info

Übernahme und Anpassung der Skripten von https://github.com/corny/luftdaten-python

Ich habe das Skript allerdings etwas anpassen müssen, da ich keinen Luftdruck übermittle und die Messwerte außerdem nicht direkt vom Sensor, sondern aus dem rrdtool auslese.

Eine angepasste Version gibt es am Ende des Blogs.

Eine Herausforderung bei der Übermittlung der Daten war zudem, dass luftdaten.info mindestens alle fünf Minuten ein Update erwartet, sonst fliegt die Meldestelle von der Webseite. Das ist so nicht beschrieben und man muss beim Timing der Skripte entsprechend aufpassen.

Außerdem muss man sich vorher bei luftdaten.info per Email registrieren und damit eine ID für seine Messstation generieren lassen. Diese Infos trägt man dann in der config.yml ein, die Teil des luftdaten-pythonm Projekts ist.

7. Backup des Servers

Bash-Skript als Cron-job mit tar auf lokales NAS.


8. Angepasste Version der Datei main.py

Wie unter (6) beschrieben, zum auslesen der Werte aus dem rrdtool

#!/usr/bin/env python3

import sys
import os
import yaml

# Import-Pfade setzen
sys.path.append(os.path.join(sys.path[0],"sds011"))
sys.path.append(os.path.join(sys.path[0],"bme280"))

import time
import json
import subprocess
import requests
import numpy as np
#from sds011 import SDS011
#from Adafruit_BME280 import *

# Config
with open("config.yml", 'r') as ymlfile:
    config = yaml.load(ymlfile)

# Logging
import logging
logging.basicConfig(level=logging.DEBUG)

#bme280 = BME280(
#    address=0x76,
#    t_mode=BME280_OSAMPLE_8,
#    p_mode=BME280_OSAMPLE_8,
#    h_mode=BME280_OSAMPLE_8,
#)

# Create an instance of your bme280
#dusty = SDS011('/dev/ttyUSB0')

# Now we have some details about it
#print("SDS011 initialized: device_id={} firmware={}".format(dusty.device_id,dusty.firmware))

# Set dutycyle to nocycle (permanent)
#dusty.dutycycle = 0

class Measurement:
    def __init__(self):
#        pm25_values = []
#        pm10_values = []
#        dusty.workstate = SDS011.WorkStates.Measuring
#        try:
#            for a in range(8):
#                values = dusty.get_values()
#                if values is not None:
#                    pm10_values.append(values[0])
#                    pm25_values.append(values[1])
#        finally:
#            dusty.workstate = SDS011.WorkStates.Sleeping

        items1 = subprocess.getstatusoutput('rrdtool lastupdate /opt/templog/data/templog_novadht.rrd | tail -1 | cut -d" "  -f2,3,4,5')
        items = items1[1].split() 
       
        self.pm25_value  = float(items[3])
        self.pm10_value  = float(items[2])
        self.temperature = float(items[1])
        self.humidity    = float(items[0])
        self.pressure    = 0

    def sendInflux(self):
        cfg = config['influxdb']

        if not cfg['enabled']:
            return

        data = "feinstaub,node={} SDS_P1={:0.2f},SDS_P2={:0.2f},BME280_temperature={:0.2f},BME280_pressure={:0.2f},BME280_humidity={:0.2f}".format(
            cfg['node'],
            self.pm10_value,
            self.pm25_value,
            self.temperature,
            self.pressure,
            self.humidity,
        )

        requests.post(cfg['url'],
            auth=(cfg['username'], cfg['password']),
            data=data,
        )

    def sendLuftdaten(self):
        if not config['luftdaten']['enabled']:
            return

        self.__pushLuftdaten('https://api-rrd.madavi.de/data.php', 0, {
            "SDS_P1":             self.pm10_value,
            "SDS_P2":             self.pm25_value,
            "BME280_temperature": self.temperature,
            "BME280_pressure":    self.pressure,
            "BME280_humidity":    self.humidity,
        })
        self.__pushLuftdaten('https://api.luftdaten.info/v1/push-sensor-data/', 1, {
            "P1": self.pm10_value,
            "P2": self.pm25_value,
        })
        self.__pushLuftdaten('https://api.luftdaten.info/v1/push-sensor-data/', 11, {
            "temperature": self.temperature,
            "pressure":    self.pressure,
            "humidity":    self.humidity,
        })


    def __pushLuftdaten(self, url, pin, values):
        requests.post(url,
            json={
                "software_version": "python-dusty 0.0.1",
                "sensordatavalues": [{"value_type": key, "value": val} for key, val in values.items()],
            },
            headers={
                "X-PIN":    str(pin),
                "X-Sensor": sensorID,
            }
        )

# extracts serial from cpuinfo
def getSerial():
   with open('/proc/cpuinfo','r') as f:
       for line in f:
           if line[0:5]=='Serial':
               print(line[10:26])
   raise Exception('CPU serial not found')

def run():
    m = Measurement()

    print('pm2.5     = {:f} '.format(m.pm25_value))
    print('pm10      = {:f} '.format(m.pm10_value))
    print('Temp      = {:0.2f} deg C'.format(m.temperature))
    print('Humidity  = {:0.2f} %'.format(m.humidity))
    print('Pressure  = {:0.2f} hPa'.format(m.pressure/100))

    m.sendLuftdaten()
    m.sendInflux()


sensorID  = "raspi-00000000a42a67d9"
starttime = time.time()

run()

print("Stopped")

Kommentare

Beliebte Posts aus diesem Blog

Froggit Sainlogic Ecowitt Wetterstation mit Sensoren in iobroker und KNX integrieren

Roboter Staubsauger AEG RX9 auseinander nehmen - und wieder zusammenbauen ;)