Raspberry Pi Pico W DHT22 Temperatur Sensor

Aus Laub-Home Wiki

Mit dem Raspberry Pi Pico oder Raspberry Pi Pico w ist es möglich den DHT22 Temperatur- & Luftfeuchtigkeitssensor auszulesen. Dieses Setup kann man zum Beispiel nutzen, um dauerhaft Temperatur und Luftfeuchtigkeit in einem Raum zu messen. Es ist möglich den Pico mit einem Battery Pack zu nutzen, was ihn dann somit sehr flexibel der Örtlichkeiten macht. Verbindet man den Pico W mit einem Wlan ist es auch möglich die Werte zum Beispiel via MQTT an das Smart Home senden.

Seid ihr auf der Suche nach einer Anleitung den DHT22 Sensor an einem Raspberry Pi zum laufen zu bekommen, schaut hier weiter:

Voraussetzungen

Wenn ihr noch keine Erfahrung mit dem Raspberry Pi Pico gesammelt habt, dann schaut am besten erst einmal hier rein:

Anschluss des Sensors am GPIO

Raspberry Pi Pico Pinbelegung
Raspberry Pi Pico W Pinbelegung

Wir schließen den Sensor wie folgt an:

Raspberry Pi Pico DHT22
Pin 36 3V3 +3,3V 1 (VCC) / +
Pin 29 GPIO 22 2 (Data)
Pin 28 GND 4 (GND) / -

Auslesen der Daten

Mit dem folgenden MicroPython Script kann man die Werte des DHT22 Sensors auslesen:

dht22.py

from machine import Pin
from time import sleep
from dht import DHT22

# GPIO Pin Number
gpio=22

# initializing GPIO and DHT22
sleep(1)
dht22_sensor = DHT22(Pin(gpio, Pin.IN, Pin.PULL_UP))

#degree symbol decleration
degreecels = '\u00B0' + "C"
# do the things
while True:
    dht22_sensor.measure()
    if dht22_sensor.temperature() == -50:
        dht22_sensor.measure()
    temperature = dht22_sensor.temperature()
    humidity = dht22_sensor.humidity()
    print('Temperature:', temperature, degreecels)
    print('   Humidity:', humidity, '%', '\n')
    sleep(3)

Die Konsolen Ausgabe sieht dann wie folgt aus.

>>> Running dht22.py

      Temperatur: 24.5 °C
Luftfeuchtigkeit: 54.7 % 

      Temperatur: 24.6 °C
Luftfeuchtigkeit: 54.6 % 

      Temperatur: 24.6 °C
Luftfeuchtigkeit: 55.0 % 

      Temperatur: 24.7 °C
Luftfeuchtigkeit: 54.1 % 

Senden der Sensorwerte via MQTT

Möchte man die Sensor Werte dann an einen MQTT Broker schicken, muss man zunächst den Pico W mit dem WLAN Verbinden und dann die ausgelesenen Daten mit umqtt an den MQTT Broker schicken. All dies macht das folgende Script. Die MQTT Werte werden nach der Homie MQTT Convention gesendet. Als Voraussetzung zur Nutzung des Skriptes (dht22homiemqtt.py) braucht ihr eine config.py mit allen Variablen zur Konfiguration und die wificonnection.py die für die WLAN Verbindung zuständig ist. Diese beiden Dateien, müssen auch immer auf den Pico mit übertragen werden. Auch wenn ihr das dht22homiemqtt.py testen möchtet in eurer IDE greift dieses auf die auf dem Pico liegenden config.py und wificonnection.py zu.

Ihr findet alle Scripte auch unter GitHub:

config.py -- Konfigurationsdatei

In dieser Datei könnt ihr die Variablen definieren, die von der wificonnection.py und dht22homiemqtt.py verwendet werden.

config.py

# -*- coding: utf-8 -*-
"""Configuration File
This file is where you keep secret settings, passwords, and tokens!
If you put them in the code you risk committing that info or sharing it
you need to upload that file also on the Pico,
even if you are just testing your scripts.
"""

### Board Configuration ###
## Status LED ##
# LED can show you the status of the running scripts
# e.g. Wifi Connection Status Code
ledstatus = True

## LightSleep Mode ##
# Using LightSleep mode of Pico W to save power (True) just a Loop when "False"
usinglightsleep = True

## Wifi ##
# Wifi Connection Settings
wifissid = "<YourSSID>"
wifipassword = "<YOourWifiPassword>"
# Set a hostname
wifihostname = "<Hostname>"
# Which Wifi Country Code?
wificountrycode = "<CountryCode>" # "DE" for example


### MQTT Broker ###
mqttbroker = "<FQDN / IP of MQTTBroker>"
mqttport = 1883 # 8883 for TLS
mqttusername = "<MQTT-Username>"
mqttpassword = "<MQTT-Password"
mqttclientid = "<UniqueMQTTClientID>" # "pico-w-001" for example
# if you like to generate a unique ID:
#import ubinascii
#mqttclientid = ubinascii.hexlify(machine.unique_id())
mqttssl = False # True for TLS connection
mqttqos = 0 # only 0 and 1 is supported
mqttretainmessage = True # True or False
# Homie Configuration / Naming
homieclientid = "<UniqueHomieClientID>" # "pico-w-001-dht22" for example
homieclientname = "<Name your Homie Device>" # "Pico W 001 DHT22 Sensor" for example
homienodes="dht22"
# how often should be a publish to MQTT (in Seconds)
publishtime = 300


### Sensor Configurations ###
# At which value humidity alarm will be fired (x in %)
humidityalarm = 70

## DHT22 Sensor ##
# DHT22 GPIO Pin Number
dhtgpiopin = 22

wificonnection.py -- Wlan Management Datei

Mit Hilfe dieser Datei, verbindet sich die dht22homiemqtt.py mit dem Wifi. Und killt die Verbindung wieder bevor der Pico schlafen geht. Die Konfiguration zieht sie sich aus der config.py. Es gibt die folgenden Funktionen:

  • wificonnection.connect() --> Verbindet mit dem WLAN
  • wificonnection.disconnect() --> Trennt die Verbindung mit dem WLAN
  • wificonnection.status() --> Gibt den aktuellen Status der Verbindung aus (True / False)

wificonnection.py

# -*- coding: utf-8 -*-
"""Wifi Connection Module
Connecting Wifi, disconnecting Wifi and Wifi status
you'll need config.py to configure SSID, Password and CountryCode
* wificonnection.connect()
* wificonnection.disconnect()
* wificonnection.status()
"""

import config
from machine import reset, Pin
from time import sleep
import network

# wlan declearation
wlan = network.WLAN(network.STA_IF)
# led declaration
if config.ledstatus:
    led = Pin('LED', Pin.OUT)


def connect():
    # Setting Country Code
    network.country(config.wificountrycode)
    
    # Setting Hostname
    network.hostname(config.wifihostname)

    # activate wifi
    wlan.active(True)
    wlan.connect(config.wifissid, config.wifipassword)

    # Wait for connect or fail
    print('waiting for wifi connection ...')
    max_wait = 30
    while max_wait > 0:
        if wlan.status() < 0 or wlan.status() >= 3:
            break
        max_wait -= 1
        sleep(.2)

    # Handle connection error
    if wlan.status() != 3:
        raise RuntimeError('wifi connection failed')
        reset()
    else:
        # LED blinking
        if config.ledstatus:
            for i in range(wlan.status()):
                led.on()
                sleep(.1)
                led.off()
                sleep(.1)
        print('wifi connected: ' + str(wlan.status()))
        status = wlan.ifconfig()
        print('ip = ' + status[0])


def disconnect():
    wlan.disconnect()
    wlan.active(False)
    wlan.deinit()
    # Quick Fix for deinit and lightsleep mode problem https://github.com/micropython/micropython/discussions/10889
    wlanled = Pin('LED', Pin.OUT)
    Pin(23,Pin.IN,Pin.PULL_DOWN)
    print('wifi disconnected: ' + str(wlan.status()))
    

def status():
    print("wifi status: " + str(wlan.isconnected()))

dht22homiemqtt.py -- Hauptscript

Dieses Script holt sich die Konfigurationswerte aus der config.py. Dann passieren die folgenden Dinge:

  • Verbindung mit dem Wlan wificonnection.connect()
  • Verbindung zum MQTT Broker und Erstellung der Homie Convention Struktur
  • Auslesen der DHT22 Sensor Werte
  • Senden von Temperatur und Luftfeuchtigkeit an den MQTT Broker
  • UsingLightSleep - False / True
  • False: Entweder ein Loop des Lesens des Sensors und verschicken der Daten an den MQTT Broker
  • True: Oder trennen von MQTT und WLAN und schlafen legen bis zum nächsten publizieren.

dht22homiemqtt.py

# -*- coding: utf-8 -*-
"""DHT22 Homie MQTT
reads data (Temperature & Humidity) of DHT22 sensor and
sends values to a MQTT Broker in Homie MQTT Convention format
You are able to set a value, when humidity alarm is fired.

You need to copy wificonnection.py and a configured config.py to your pico!
umqtt.simple will install, if not available on the pico
"""

import config
from wificonnection import connect, disconnect
from time import sleep
from dht import DHT22
from machine import reset, lightsleep, Pin

#led declaration
if config.ledstatus:
    led = Pin('LED', Pin.OUT)
    led.value(True)
#degree symbol decleration
degreecels = '\u00B0' + "C"

# Functions
def loadumqtt():
    global MQTTClient
    try:
        from umqtt.simple import MQTTClient
    except ImportError:
        print("Module umqtt.simple not found, try to install it now...")
        import mip
        mip.install("umqtt.simple")
        try:
            from umqtt.simple import MQTTClient
        except ImportError:
            print("Module umqtt.simple still not available... EXIT")
            reset()


def publish(topic, payload):
    client.publish("homie/" + config.homieclientid + "/" + topic,
                   payload, retain=config.mqttretainmessage, qos=config.mqttqos)


def mqttconnect():
    global client
    client = MQTTClient(config.mqttclientid, config.mqttbroker, port=config.mqttport, user=config.mqttusername,
                            password=config.mqttpassword, keepalive=10, ssl=config.mqttssl,
                            ssl_params={})
    client.set_last_will("homie/" + config.homieclientid + "/$state",
                            "lost", retain=config.mqttretainmessage, qos=config.mqttqos)
    client.connect()
    # homie client config
    publish("$state", "init")
    publish("$homie", "4.0")
    publish("$name", config.homieclientname)
    publish("$nodes", config.homienodes)
    # homie node config
    publish(config.homienodes + "/$name", "DHT22 Sensor")
    publish(config.homienodes + "/$properties", "temperature,humidity,humidityalarm")
    publish(config.homienodes + "/temperature/$name", "Temperature")
    publish(config.homienodes + "/temperature/$unit", degreecels.encode('utf8'))
    publish(config.homienodes + "/temperature/$datatype", "float")
    publish(config.homienodes + "/temperature/$settable", "false")
    publish(config.homienodes + "/humidity/$name", "Humidity")
    publish(config.homienodes + "/humidity/$unit", "%")
    publish(config.homienodes + "/humidity/$datatype", "float")
    publish(config.homienodes + "/humidity/$settable", "false")
    publish(config.homienodes + "/humidityalarm/$name", "Humidity Alarm")
    publish(config.homienodes + "/humidityalarm/$datatype", "boolean")
    publish(config.homienodes + "/humidityalarm/$settable", "false")
    # homie state ready
    publish("$state", "ready")


def sensorpublish():
    publish(config.homienodes + "/temperature", "{:.1f}".format(temperature))
    publish(config.homienodes + "/humidity", "{:.1f}".format(humidity))
    if humidity >= config.humidityalarm:
        publish(config.homienodes + "/humidityalarm", "true")
    else:
        publish(config.homienodes + "/humidityalarm", "false")
    

def dht22sensor():
    global temperature
    global humidity
    # initializing GPIO and DHT22
    dht22_sensor = DHT22(Pin(config.dhtgpiopin, Pin.IN, Pin.PULL_UP))
    dht22_sensor.measure()
    if dht22_sensor.temperature() == -50:
        dht22_sensor.measure()
    temperature = dht22_sensor.temperature()
    humidity = dht22_sensor.humidity()
    print('\nTemperature = ', temperature, degreecels)
    print('Humidity = ', humidity, '%', '\n')
 

# do the things
try:
    # read sensor
    dht22sensor()
    # connect to wifi
    connect()
    # install / load umqtt
    loadumqtt()
    if config.ledstatus:
        led.value(True)
    # connect to mqtt broker and initialize homie convention
    mqttconnect()    
    sensorpublish()
    sleep(.3)
    if config.usinglightsleep:
        publish("$state", "sleeping")
        sleep(.3)
        client.disconnect()
        sleep(.3)
        disconnect()
        print("going to lightsleep for %s seconds" % config.publishtime)
        if config.ledstatus:
            led.value(False)
        sleep(.1)
        lightsleep((config.publishtime)*1000)
        #deepsleep((config.publishtime)*1000)
    else:
        while True:    
            print("just a break for %s seconds" % config.publishtime)
            if config.ledstatus:
                led.value(False)
            sleep(config.publishtime)
            if config.ledstatus:
                led.value(True)
            dht22sensor()
            sensorpublish()
except RuntimeError as error:
    print('Runtime Error: ', error.args[0])
    pass
except OSError as e:
    print('OS Error: ', e.args[0])
    pass
sleep(0.1)
print("machine reset ...")
reset()

main.py -- Autostart

Möchte man, das das dht22homiemqtt.py Script autark auf dem Pico läuft, dann muss man entweder dieses als main.py umbenennen und auf den Pico übertragen, oder aber der bessere Weg, wir erstellen eine main.py und starten über diese unser dht22homiemqtt.py Script. Der Vorteil dieses Scripts hier, ist, das man mittels überbrücken von einem GPIO Pin (hier GPIO19) zu GND wieder in den programmierbaren Modus des Pico kommt:

main.py

# -*- coding: utf-8 -*-
"""Main Script
to prevent always blank flashing the pico
GPIO(19) is used to detect, if the system will break
instead of running the MQTT script.
Just use a jumper cable to connect GND and GPIO(19)
or use a switch on these two pins.
* on exit you'll see led 5 times flashing
* on entering the python script led will flash 1 time
"""

import config
from time import sleep
from machine import Pin
from sys import exit

# declare EXIT Pin GPIO(19)
sw = Pin(19,Pin.IN,Pin.PULL_UP)
# declare LED variable
if config.ledstatus:
    led = Pin('LED', Pin.OUT)

# Check if GPIO19 is activated
if  sw.value():
    if config.ledstatus:
        # LED blink on Startup
        led.value(True)
        sleep(.3)
        led.value(False)
    # Loading DHT22 Sensor Script
    import dht22homiemqtt.py
else:
    if config.ledstatus:
        blink = 5
        for i in range(blink):
            led.value(True)
            sleep(.1)
            led.value(False)
            sleep(.1)
    exit()

Stromverbrauch

Wenn man den LightSleep Mode verwendet, verbraucht der Pico während des Schlafes kaum einen für mich messbaren Strom. Hier kommt es alle paar Sekunden zu einem Peak von 0,020 W (0,004 A)

Beim Ausführen des Skriptes selbst liegen folgenden Maximal Werte an:

Raspberry Pi Pico W
Volt 5,179 V
Ampere 0,060 A
Watt 0,309 W
Einmalige Laufzeit des Skriptes in Sekunden Mit Status LED 9 s
Ohne Status LED 8 s

Ich habe bereits ein paar Langzeittests mit Batterie Packs gemacht. Hier komme ich bei einer halbstündigen Messung und 4x AA 2300mAh Akku Batterien auf eine knapp 2 monatiger Laufzeit. Also nicht sehr empfehlenswert. Mit USB Netzteil jedoch ein kaum vorhandener Stromverbrauch bei Dauerbetrieb!

Quellen