Raspberry Pi Pico W mit BME280 und OLED in Thonny und MicroPython

Während die verschiedenen Raspberry Pi Mikrocomputer aufgrund der Lieferengpässe immer noch schwer zu bekommen sind, scheint die Krise bei den Mikrocontrollern Pico überwunden. Grund genug, die Blog-Reihe aus dem Frühjahr mit Schwerpunkt auf dem Pico W, also der Variante mit WLAN, fortzusetzen. Dabei werde ich erneut MicroPython und die Entwicklungsumgebung (IDE) Thonny benutzen.

Im ersten Teil hatten wir die Installation von Thonny, die Einrichtung des Raspberry Pi Pico sowie erste Anwendungsprogramme zur Nutzung der Ein- und Ausgänge kennengelernt. Im zweiten Teil ging es um die Programmierung der bekannten Schnittstellen OneWire, UART und I2C, allesamt Zweitbelegungen der Pins. Und im dritten Teil hatten wir eine Anwendung für die neueste und schnellste Schnittstelle SPI oder Serial Peripheral Interface aka 4-wire bus vorgestellt. Bereits im Herbst letzten Jahres hatte Jörn Weise eine Wetterstation mit dem Sensor BME280 und dem 0,96 Zoll OLED SSD1306 Display gezeigt.

In diesem Beitrag möchte ich die Vorteile der WLAN-Schnittstelle nutzen und Temperatur und relative Luftfeuchtigkeit mit dem Web Server im heimischen Netz bereitstellen. Dabei werde ich jedoch den preiswürdigen Sensor DHT20 und das 1,3“-OLED mit SH1106-Treiber-IC benutzen, um Wiederholungen zu minimieren.

Doch zunächst das Pinout-Diagramm des Raspberry Pi Pico W und die Unterschiede zwischen dem Raspberry Pi Pico und dem Pico W:

Obwohl Formfaktor und Pinbelegung (weitestgehend) gleichgeblieben sind, sind die Unterschiede im Layout gut zu erkennen. Am deutlichsten wird das beim WLAN-Chip und bei den drei meist freibleibenden Pins für DEBUG, die wegen der WLAN-Antenne nun mitten auf dem Chip zu finden sind. Geändert hat sich der Anschluss für die eingebaute LED; mehr dazu später. Das WLAN-Interface mit 2,4 GHz nutzt den Chip Infineon CYW43439. Bluetooth ist dabei noch nicht implementiert; dies erfordert ein Firmware Update, das jedoch nicht zeitnah geplant ist. Die jeweils neueste Version der MicroPython-Firmware findet man unter https://micropython.org/download/rp2-pico-w/.

Nach dem Herunterladen der neuesten Datei mit der Endung .uf2 wird der Pico mit gedrückter BOOTSEL-Taste in den USB-Port eines Rechners gesteckt; dann wird er dort als USB-Laufwerk RPI-RP2 angezeigt; siehe nachfolgendes Bild. Einfach die heruntergeladene Datei in das Verzeichnis kopieren. Nach Beendigung des Kopiervorgangs verschwindet das Laufwerk und der Pico W wird unter Thonny als virtueller COM-Port erkannt.

Wer Thonny noch nicht installiert oder aktualisiert hat, hier noch einmal der Link:

Download von https://thonny.org/ oder  https://github.com/thonny/thonny/releases

Aktuell im Oktober 2022: thonny-4.0.1.exe

Einstellungen werden unter der Registerkarte Run/Ausführen vorgenommen.

Wie üblich testen wir zuerst „hello world“ in der Kommandozeile (auch Shell oder REPL genannt).

Das „hello world“ beim Physical Computing ist die blinkende LED, unser zweiter Versuch:

Im Programm ist der oben angesprochene Unterschied für die eingebaute LED zu sehen. Beim einfachen Pico wird diese über Pin 25 angesprochen, einem Pin, der nicht nach außen geführt ist. Beim Pico W ist die LED mit dem Wireless Chip verbunden und wird über den Namen „LED“ angesprochen. 

 import machine
 import utime
 led_onboard = machine.Pin("LED", machine.Pin.OUT)
 while True:
     led_onboard.toggle()
     utime.sleep(1)

Nachdem alles geklappt hat, möchte ich zunächst die Versuchsanordnung von Jörn Weise nachbauen, um dann sowohl einen anderen Sensor, als auch ein anderes Display zu verwenden.

Außer den MicroPython-Modulen machine und utime werden noch die Module bme280 und ssd1306 für das 0,96“-OLED benötigt. Beide findet man bei PyPI, indem man unter der Registerkarte „Extras“ auf „Verwalte Pakete …“ klickt und die Begriffe im Suchfenster eingibt. Bei der Auswahl bitte auf das Wort „micropython“ im Namen achten.

Schaltbild:

Aufbau hat geklappt, siehe Foto:

Nun möchte ich zunächst das 0,96“-Display durch ein 1,3“-OLED ersetzen. Das hat aber nicht den Treiber-IC SSD1306, sondern den SH1106; und dafür gibt es auf PyPI kein MicroPython-Modul. Die Suche auf GitHub geht schnell: https://github.com/robert-hh/SH1106

Das Modul ist eigentlich für den ESP8266 geschrieben, funktioniert aber gut. Also ZIP-Datei herunterladen, entpacken, sh1106.py unter Thonny starten und auf dem Pico W im Verzeichnis lib abspeichern. Einzige Abweichung für den Pico W im i2c-Beispielprogramm ist ein zusätzlicher Parameter bei der Instanziierung, die Nummer für die i2c-Schnittstelle:
i2c=I2C(0, sda=sda, scl=scl, freq=400000)

Bei der Instanziierung des Displays musste ich rotate=180 einfügen:
oled = sh1106.SH1106_I2C(128, 64, i2c, None, 0x3c,rotate=180)

Damit hat‘s auf Anhieb geklappt. Also ran an den DHT20, anstelle des teuren BME280.

Den DHT20 hatte ich bereits in einem Blog-Beitrag im Juli 2022 vorgestellt. Interessant ist die i2c-Schnittstelle, worin dieser kombinierte Temperatur- und Luftfeuchtigkeitssensor sich vom DHT11 und DHT22 unterscheidet. Auch dafür gibt es noch kein MicroPython-Modul auf PyPI. Also wieder Suche auf GitHub. Fündig werde ich bei https://github.com/flrrth/pico-dht20

Wieder Download ZIP, entpacken, dht20.py mit Thonny starten und auf dem Pico W im Unterverzeichnis lib abspeichern.

Hier die wesentlichen neuen Zeilen im Code:

 from dht20 import DHT20
 dht20 = DHT20(0x38, i2c)           # 0x38 ist die i2c-Adresse

Und in der while-Schleife:

     measurements = dht20.measurements
     tempC = measurements['t']
     humRH = measurements['rh']

Hier das ganze Programm zum Download.

Nun fehlt nur noch die Ergänzung, die aus dem Pico W einen Web Server für die atmosphärischen Daten macht. Recherche im Internet. Bislang Fehlanzeige. Aber es gibt zwei Beispielprogramme der Raspberry Pi Foundation, die auch von anderen Bloggern kopiert wurden: Ein einfacher Web Server mit Textanzeige und Schalten der LED über das Intranet, zu finden in der Broschüre „Connecting-to-the-internet-with-pico-w“.

Den Teil zum Anmelden im heimischen WLAN wird man stets benötigen:

 import time
 import network
 ssid = 'Wireless Network'
 password = 'The Password'
 wlan = network.WLAN(network.STA_IF)
 wlan.active(True)
 wlan.connect(ssid, password)
 # Wait for connect or fail
 max_wait = 10
 while max_wait > 0:
     if wlan.status() < 0 or wlan.status() >= 3:
         break
     max_wait -= 1
     print('waiting for connection...')
     time.sleep(1)
 # Handle connection error
 if wlan.status() != 3:
     raise RuntimeError('network connection failed')
 else:
     print('connected')
     status = wlan.ifconfig()
     print( 'ip = ' + status[0] )

In den Zeilen

 ssid = 'Wireless Network'
 password = 'The Password'

bitte die SSID und das Passwort für das eigene Heimnetzwerk eintragen.

Als Grundlage für mein Projekt benutze ich das Beispielprogramm für die Textausgabe. Hier muss ich im Wesentlichen die Schriftgröße der zweiten Zeile vergrößern, um den Text auf dem Smartphone lesen zu können, sowie die Messwerte als String einfügen. Die Aktualisierung der Messwerte erfolgt alle 10 Sekunden aufgrund der HTML-Zeile

 <meta http-equiv="refresh" content="10">

Download.

 # Example Code for Web Server and DHT20 sensor
 # based on example of Raspberry Pi Pico documentation
 # import modules
 import network
 import socket
 import utime
 from machine import Pin, I2C
 from dht20 import DHT20
 import sh1106
 
 ssid = 'Xxxxxx' #Your network name
 password = 'Yyyyyyyy' #Your WiFi password
 
 #initialize I2C
 sda = Pin(12)
 scl = Pin(13)
 i2c0=I2C(0,sda=sda, scl=scl, freq=400000)
 dht20 = DHT20(0x38, i2c0)
 WIDTH = 128
 HIGHT = 64
 oled = sh1106.SH1106_I2C(128, 64, i2c0, None, 0x3c,rotate=180)
 
 #Connect to WLAN
 wlan = network.WLAN(network.STA_IF)
 wlan.active(True)
 wlan.connect(ssid, password)
 
 
 # Wait for connect or fail
 max_wait = 10
 while max_wait > 0:
     if wlan.status() < 0 or wlan.status() >= 3:
         break
     max_wait -= 1
     print('waiting for connection...')
     utime.sleep(1)
 
 # Handle connection error
 if wlan.status() != 3:
     raise RuntimeError('network connection failed')
 else:
     print('connected')
     status = wlan.ifconfig()
     print( 'ip = ' + status[0] )    
 
 # Open socket
 addr = socket.getaddrinfo('0.0.0.0', 80)[0][-1]
 connection = socket.socket()
 connection.bind(addr)
 connection.listen(1)
 
 def webpage(output):
     #Template HTML
     html = f"""
            <!DOCTYPE html>
            <html>
            <head>
            <title>Pico W</title>
            <meta http-equiv="refresh" content="10">
            </head>
            <body>
            <p><h1>{output}</h1></p>
            </body>
            </html>
            """
     return str(html)
     
 try:
     while True:
         measurements = dht20.measurements
         t = round(measurements['t'],1)
         rh = int(measurements['rh'])
         temp = "Temperature: " + str(t) + "*C"
         humid = "Rel.Humidity: " + str(rh) +"%"
         print(temp)
         print(humid)
         output = temp + humid
         #Write data to display
         oled.fill(0)
         oled.text("Pico W, DHT20 ",6,10)
         oled.text("Temp:" + str(t) + "*C",6,26)
         oled.text("Rel.Humid:" + str(rh) + "%",6,42)
         oled.show()
         client = connection.accept()[0]
         request = client.recv(1024)
         request = str(request)      
         html = webpage(output)
         client.send(html)
         client.close()
 
 except KeyboardInterrupt:
     machine.reset()
Schließlich habe ich das Programm unter dem Namen main.py auf dem Pico W abgespeichert. Damit startet das Programm selbstständig, wenn der Pico W mit Strom versorgt wird. So ist die Überwachung des Gartenhäuschens, oder von Abstellräumen leicht möglich.

Fazit: Für weniger als zwei Euro Aufpreis gegenüber dem Pico ohne WLAN erhält man mit dem Pico W einen vielseitig einsetzbaren Mikrocontroller, der problemlos im heimischen WLAN angemeldet werden kann und damit für viele eigene Smart  Home-Projekte geeignet ist. Ich selbst werde ihn demnächst bei meinem Lieblingsprojekt Robot Car einsetzen. Schwierigkeiten erwarte ich dabei nicht; ich werde berichten.

DisplaysProjekte für anfängerRaspberry piSensoren

2 Kommentare

Andreas Wolter

Andreas Wolter

@Philipp: das Display ist immer an. Wenn Sie das ändern möchten, müssten Sie die Schaltung verändern. Das wäre dann ein separater Teil im Code, der mit dem Taster die Stromversorgung zum Display steuert. Wenn das Display an bleiben und nur die Ausgabe gelöscht werden soll, müssten Sie in der Hauptschleife while nach der Zeile #Write data to display eine if-Anweisung einfügen, mit der Sie den Taster abfragen. Wurde er gedrückt, wird der Code für die Displayanzeige ausgeführt. Zusätzlich müsste dann als zweite Bedingung eine Stopuhr mitlaufen, so dass nach Ablauf der Zeit die Bedingung zur Anzeige nicht mehr erfüllt ist. Sowas wie
if (taster == TRUE and timer NOT > 10000)

nach Ablauf der Zeit müsste die Tastervariable wieder auf FALSE gesetzt werden und der Timer auf 0.

Grüße,
Andreas Wolter
AZ-Delivery Blog

Philipp

Philipp

Hallo,
Wie kann ich in dieses Projektbeine Funktion einfügen die das display nur auf Tastendruck für 10 sec einschaltet…
Mfg Philipp

Einen Kommentar hinterlassen

Alle Kommentare werden vor der Veröffentlichung moderiert