Raspberry Pi Pico W jetzt mit Bluetooth - Teil 1 - AZ-Delivery

Im Blog-Beitrag vom 03. Januar 2023 hatten wir vorgestellt, wie der Raspberry Pi Pico W mit den Temperatursensoren BME280 und DHT20 lokal die Temperatur und Luftfeuchtigkeit auf einem 0,96“ bzw. 1,3“ OLED-Display anzeigt und zugleich die Daten im heimischen WLAN bereitstellt. Diese Fähigkeit des Pico W wird mit dem Infineon Chip CYW43439 für WLAN 2,4 GHz realisiert und ist seit der Vorstellung am 30. Juni 2022 verfügbar.

Grundsätzlich kann dieser Chip auch Bluetooth 5.2 ermöglichen; das wurde aber bislang nicht von der Firmware unterstützt. Es hat fast ein Jahr gedauert und offensichtlich erhebliche Manpower erfordert, um MicroPython und die Firmware dafür anzupassen. Mehr dazu in der Pressemitteilung von Eben Upton vom 14. Juni 2023.

Der schnellste Weg, um die neueste Firmware zu installieren, ist der Download der *.uf2-Datei für Raspberry Pi Pico W with Wi-Fi and Bluetooth LE support. Beim Schreiben des Blog-Beitrags war es diese Datei: micropython-firmware-pico-w-130623.uf2. Dann hält man den BOOTSEL Button gedrückt und verbindet die Pico W über USB mit dem PC. Im Explorer erscheint der Pico wie ein USB-Stick, so dass man die Datei *.uf2 mit „drag and drop“ auf den Pico verschieben kann. Wenige Sekunden später verschwindet das USB-Laufwerk und der Pico W kann mit Thonny bedient werden (siehe auch vorangegangene Blog-Beiträge zum Thema Pico, Erster TeilZweiter Teil, Dritter Teil,  Wetterstation mit dem Sensor BME280 und dem 0,96 Zoll OLED SSD1306 Display).  Ich hatte zuvor meine anderen Programme vom Pico W auf dem PC gesichert. Das hätte nicht nötig getan, denn die MicroPython-Programme wurden beim Update der Firmware nicht gelöscht.

Einen großen Anteil an der Anpassung der Firmware hatten die Überarbeitung der Dokumentation und die Erstellung von Programm-Beispielen. Auch wenn Sie die folgenden Internetseiten bereits kennen - es lohnt sich das Herunterladen der neuen Versionen der Broschüre „Connecting to the Internet with Raspberry Pi Pico W“ und der MicroPython Beispiele (examples)

https://www.raspberrypi.com/documentation/microcontrollers/raspberry-pi-pico.html

https://datasheets.raspberrypi.com/picow/connecting-to-the-internet-with-pico-w.pdf

https://github.com/micropython/micropython/tree/master/examples/bluetooth

https://docs.micropython.org/en/latest/library/bluetooth.html

Es ist müßig, die Komplexität von Bluetooth verstehen zu wollen und die mehrere tausend Seiten Dokumentation bzw. Spezifikation zu lesen. Der pragmatische Ansatz lautet wie so oft: Beispiele studieren und für den eigenen Zweck anpassen. Los geht’s.

Meines Erachtens schwer zu verstehen und dennoch empfehlenswert sind die Kapitel 4 „About Bluetooth“ und Kapitel 6 „Working with Bluetooth in MicroPython“ der Broschüre „Connecting to the Internet with Raspberry Pi Pico W“. Hier finde ich auf Seite 37ff ein Beispiel, wie man die Temperatur mit dem Pico W misst und über Bluetooth bereitstellt. Die Verwendung des internen Temperatursensors eignet sich sicherlich für den Überhitzungsschutz des Mikrocontrollers, aber zeigt definitiv nicht die Umgebungstemperatur an. Deshalb „verheirate“ ich dieses Programm-Beispiel mit meinem Programm für den Temperatursensor DHT20 und das 1,3“ OLED aus dem Januar-Blog, allerdings ohne den WLAN-Anteil.

Hier die Schaltung wie im Blog vom Januar, die Zählschleife (Counter) habe ich weggelassen, dafür blinkt die LED im Sekundentakt.

Verwendete Hardware:

1

Raspberry Pi Pico W mit aktueller Firmware

1

Temperatur-/rel. Luftfeuchtesensor DHT20

1

1,3“ OLED

1

Breadboard, Jumperkabel

PC mit Thonny, Android Smartphone/Tablet


Programm-Code (download):

 # Example temperature sensor and Bluetooth, based on
 # Connecting to the Internet with Raspberry Pi Pico W
 # Copyright © 2022-2023 Raspberry Pi Ltd
 # licensed under a Creative Commons Attribution-NoDerivatives 4.0 International (CC BY-ND).
 # Example on page 37ff
 # modified for temperature sensor DHT10 for AZ-Delivery
 import bluetooth
 import random
 import struct
 import time
 import machine
 import ubinascii
 from ble_advertising import advertising_payload
 from micropython import const
 from machine import Pin
 ## modified for AZ-Delivery
 import sh1106
 from dht20 import DHT20
 from machine import Pin, I2C
 sda=Pin(12)
 scl=Pin(13)
 i2c=I2C(0, sda=sda, scl=scl, freq=400000)
 WIDTH = 128
 HIGHT = 64
 oled = sh1106.SH1106_I2C(128, 64, i2c, None, 0x3c,rotate=180)
 dht20 = DHT20(0x38, i2c)           # 0x38 ist die i2c-Adresse
 ##
 
 
 _IRQ_CENTRAL_CONNECT = const(1)
 _IRQ_CENTRAL_DISCONNECT = const(2)
 _IRQ_GATTS_INDICATE_DONE = const(20)
 
 
 _FLAG_READ = const(0x0002)
 _FLAG_NOTIFY = const(0x0010)
 _FLAG_INDICATE = const(0x0020)
 
 
 # org.bluetooth.service.environmental_sensing
 _ENV_SENSE_UUID = bluetooth.UUID(0x181A)
 
 
 # org.bluetooth.characteristic.temperature
 _TEMP_CHAR = (
     bluetooth.UUID(0x2A6E),
     _FLAG_READ | _FLAG_NOTIFY | _FLAG_INDICATE,
 )
 _ENV_SENSE_SERVICE = (
     _ENV_SENSE_UUID,
    (_TEMP_CHAR,),
 )
 
 
 # org.bluetooth.characteristic.gap.appearance.xml
 _ADV_APPEARANCE_GENERIC_THERMOMETER = const(768)
 
 
 class BLETemperature:
     def __init__(self, ble, name=""):
         self._sensor_temp = machine.ADC(4)
         self._ble = ble
         self._ble.active(True)
         self._ble.irq(self._irq)
        ((self._handle,),) = self._ble.gatts_register_services((_ENV_SENSE_SERVICE,))
         self._connections = set()
         if len(name) == 0:
             name = 'Pico %s' % ubinascii.hexlify(self._ble.config('mac')[1],':').decode().upper()
         print('Sensor name %s' % name)
         self._payload = advertising_payload(
         name=name, services=[_ENV_SENSE_UUID]
        )
         self._advertise()
 
 
     def _irq(self, event, data):
         # Track connections so we can send notifications.
         if event == _IRQ_CENTRAL_CONNECT:
             conn_handle, _, _ = data
             self._connections.add(conn_handle)
         elif event == _IRQ_CENTRAL_DISCONNECT:
             conn_handle, _, _ = data
             self._connections.remove(conn_handle)
             # Start advertising again to allow a new connection.
             self._advertise()
         elif event == _IRQ_GATTS_INDICATE_DONE:
             conn_handle, value_handle, status = data
 
 
     def update_temperature(self, notify=False, indicate=False):
         # Write the local value, ready for a central to read.
         temp_deg_c = self._get_temp()
         print("write temp %.2f degc" % temp_deg_c);
         self._ble.gatts_write(self._handle, struct.pack("<h", int(temp_deg_c * 100)))
         if notify or indicate:
             for conn_handle in self._connections:
                 if notify:
                     # Notify connected centrals.
                     self._ble.gatts_notify(conn_handle, self._handle)
                 if indicate:
                     # Indicate connected centrals.
                     self._ble.gatts_indicate(conn_handle, self._handle)
 
 
     def _advertise(self, interval_us=500000):
         self._ble.gap_advertise(interval_us, adv_data=self._payload)
 
 
     def _get_temp(self):
 ## modified for AZ-Delivery
 ## replace internal temperature sensor with DHT20 and OLED
 #         conversion_factor = 3.3 / (65535)
 #         reading = self._sensor_temp.read_u16() * conversion_factor
 #
 #         return 27 - (reading - 0.706) / 0.001721
         measurements = dht20.measurements
         tempC = measurements['t']
         humRH = measurements['rh']
         print("Temperature: " + str(tempC))
         print("Humidty: " + str(humRH))
         print(">-----------<")
         #Write data to display
         oled.fill(0)
         oled.text("Pico W, DHT20 ",6,0)
         oled.text("Temp:" + str(tempC),6,14)
         oled.text("Humi:" + str(humRH),6,42)
         oled.show()
         return tempC
 ##
 
 
 def demo():
     ble = bluetooth.BLE()
     temp = BLETemperature(ble)
     counter = 0
     led = Pin('LED', Pin.OUT)
     while True:
         if counter % 10 == 0:
             temp.update_temperature(notify=True, indicate=False)
         led.toggle()
         time.sleep_ms(1000)
         counter += 1
 
 
 if __name__ == "__main__":
     demo()

Wichtig ist, dass das MicroPython-Beispielprogramm ble_advertising.py auf den Pico W kopiert wird. Ansonsten erhält man bei der Zeile „from ble_advertising import advertising_payload“ eine Fehlermeldung.

Die gegenüber dem Beispielprogramm vorgenommenen Änderungen befinden sich zu Beginn beim Importieren und Instanziieren des DHT20 und des OLEDs, sowie in der Funktion _get_temp jeweils zwischen zwei Kommentarzeichen (## hash tag ##). 

Mein modifiziertes Programm läuft nach banalen Fehlermeldungen überraschend schnell, Temperatur und Luftfeuchtigkeit werden auf dem OLED angezeigt und die interne LED des Pico blinkt im Sekundentakt. Auf dem nachfolgenden Bildschirmfoto noch einmal die modifizierte selbstdefinierte Funktion _get_temp und die Datenausgabe in der Shell von Thonny.

Aber wird die Temperatur auch über Bluetooth auf dem Smartphone angezeigt? Dafür installiere ich über den Play Store die APP LightBlue auf dem Smartphone und später auch auf meinem Android-Tablet. Selbstverständlich ist Bluetooth aktiviert.

Hier zunächst das Logo der APP LightBlue.

Anbieter ist die Firma PunchThrough Design.

Der Name erklärt das (für mich) bedrohlich wirkende Logo.


Nach dem Start scannt die APP den Nahbereich nach BT-fähigen Geräten. Neben von früher bekannten Geräten, oder solchen mit schwachen Signalen, wird der Pico sofort angezeigt.

Ich tippe unten rechts auf CONNECT. Ein neuer Bildschirm erscheint, bei dem ich bei meiner vorgewählten Schriftgröße zunächst weiter nach unten scrollen muss.

Ganz unten finde ich unter ENVIRONMENTAL SENSING einen kleinen Pfeil für die Temperatur-Anzeige. Mein Fingerdruck auf den Pfeil öffnet den nächsten Bildschirm. Und auch hier muss ich weiter nach unten scrollen.

Unter READ/INDICATED VALUES befindet sich die Schaltfläche SUBSCRIBE/UNSUBSCRIBE. Nachdem ich den Server Pico28:xx abonniert habe, werden im 10-Sekunden-Takt die Temperatur und die Datum-Zeit-Gruppe ausgegeben. Zunächst eine kryptische Angabe. Nach Umstellen des Data Format auf „Signed Little-Endian“ erscheint die Temperatur in Hundertstel Grad Celsius, also 2391 bedeutet 23,91°C.

Nun kommt mein Android-Tablet zum Einsatz. Auch dort scanne ich nach BT-Geräten und finde keinen Pico. Das war für mich das erwartete Ergebnis. So hatte ich den Text aus der o.g. Broschüre verstanden. Der Pico W als Server bietet zunächst seine Dienste an. Dafür ist das Modul ble_advertising.py zuständig. Das passiert so lange, wie kein Client (Smartphone oder Tablet) den Dienst abonniert hat. Das hatte ich mit Tippen auf SUBSCRIBE jedoch getan. Also, wenn das Smartphone mit dem Pico W verbunden ist, stoppt dieser sein Dienstangebot.

Nun trenne ich das Smartphone mit UNSUBSCRIBE und (zweimal Pfeil oben zurück) DISCONNECT. Nun bietet der Server wieder allen Clients seine Dienste an, bis ich auf dem Tablet SUBSCRIBE drücke und mein Smartphone den Pico W nicht mehr erkennt.

Bis zu diesem Punkt habe ich bereits viele Stunden Recherche und Lektüre zum Thema Bluetooth investiert und dennoch stehe ich gefühlt am Anfang. Ich hoffe, ich konnte Ihnen den Einstieg erleichtern. In Sachen Robot Car mit Pico W und Bluetooth habe ich Martin O’Hanlon von der Raspberry Pi Foundation (Autor der APP BlueDot für die Raspberry Pi Mikro Computer/Python, siehe Blog vom 06. Juni 2022) angeschrieben, ob er seine APP für MicroPython anpasst. Seine Antwort ist vielversprechend, aber mit einer zeitnahen Lösung ist nicht zu rechnen.

Viel Spaß bei Ihren ersten Versuchen mit dem Raspberry Pi Pico W und Bluetooth.

Hier geht's mit Teil 2 der Blogreihe weiter: Teil 2 - Robot Car und Controller

DisplaysProjekte für anfängerRaspberry piSensoren

Lascia un commento

Tutti i commenti vengono moderati prima della pubblicazione