Anwendungen von Bluetooth
Hardware / Software
- Raspberry Pi Pico W
- Relaismodul (sb-Components)
- Relaismodul- 4 Relais (sb-Components)
- Micro USB Kabel
- Firmware MicroPython
- Thonny IDE
Anwendungen von Bluetooth
- Relaismodul (sb-Components)
- Relaismodul- 4 Relais (sb-Components)
- Micro USB Kabel
- Firmware MicroPython
- Thonny IDE
Der Pico W hat ja von Hause aus einen Funk-Chip mit WLAN-Unterstützung und Bluetooth. Nur leider ist Bluetooth nicht standardmäßig
aktiviert und die Fangemeinde musste lange warten, bis die Firmware dafür angepasst wurde. Zum Zeitpunkt, als ich das hier geschrieben habe,
gab es die Bluetooth-Unterstützung außer für C/C++ nur für MicroPython und nicht CircuitPython, welches ich sonst bevorzuge. Also habe ich mich
entschlossen, einige Experimente mit der aktuellen MicroPython Firmware zu unternehmen.
Bei meiner Suche im Internet, sind mir viele Beiträge wie etwa: "Pico W - jetzt mit Bluetooth" begegnet. Inhaltlich enthielten sie aber
1. Außer ein paar grundlegenden Erläuterungen kaum etwas für den Bastler Verwertbares.
2. Wenn, dann stand das Ein- und Ausschalten der Onboard-LED meist im Mittelpunkt.
Warum wurde z.B. nicht versucht ein oder mehrere elektrische Geräte (Netzspannung) über ein Relais zu schalten? Die Antwort findet man bei
Amazon. Funksteckdosen mit WLAN und/oder Bluetooth gibt es dort ab ca. 10 Euro, so dass der Aufwand an Gehirnschmalz kaum lohnt. Eine andere Anwendung
ist dann immer noch das allseits bekannte Roboter-Car. Aber auch dafür bietet Amazon die kompletten Bausätze an. Richtig "basteln" ist also
nicht mehr so einfach.
Trotzdem habe ich mich entschlossen, über den Einstieg 'Onboard-LED', zur Steuerung eines Relais mit Hilfe des Smartphones und schließlich
Steuerung des Relaismoduls mit vier Relais von sb-Components alles zum Nachmachen darzustellen.
Womit geht es los?
Zunächst geht es um den
Download und die Einrichtung des Pico W mit der Firmware MicroPython.
Laden Sie die neueste Version unter 'Firmware Releases' herunter und installieren sie wie folgt:
1. Nehmen Sie den Pico im ausgeschalteten Zustand zur Hand und drücken die BootSel-Taste (siehe Beschriftung auf der Platinenrückseite).
Die wird gehalten und der Pico erst dann (!!) über das USB-Kabel mit dem Rechner verbunden. Nach dem Verbinden des USB-Kabels kann die Taste
BootSel losgelassen werden. Nun öffnet sich im Filesystem ein Explorer-Fenster mit einem neuen Massenspeicher RPI-RP2.
2. Falls Ihr Pico W neu ist und noch nicht genutzt wurde, können Sie diesen Schritt überspringen. Wenn Sie den Pico W schon
für andere Zwecke genutzt haben und in den Auslieferungszustand zurücksetzen wollen, sollten Sie vorher noch die uf2-Datei
'flash_nuke.uf2' übertragen. Den Download-Button dafür finden Sie auf der Adafruitseite (grüner Button am Seitenende)
hier.
Öffnen Sie auf dem Rechner den Download-Ordner und ziehen die flash_nuke.uf2 Datei auf den Massenspeicher RPI-RP2.
Warten Sie, bis nach kurzer Zeit wieder der Massenspeicher RPI-RP2 im Explorer angezeigt wird. Der Speicher des Pico W ist jetzt vollständig
gelöscht.
3. Öffnen Sie jetzt auf dem Rechner den Download-Ordner und ziehen die uf2-Datei mit der MicroPython Firmware
auf den Massenspeicher RPI-RP2. Warten Sie bis die Firmware vollständig aufgespielt ist. Der Pico W wird ab jetzt nicht mehr im Dateiexplorer
angezeigt und wir nutzen von nun an den Editor 'Thonny', um den Pico zu programmieren.
4. Falls bei der ersten Benutzung von Thonny kein Board erkannt wird, muss in den Interpreter-Einstellungen die Port-Auswahl
überprüft werden und ggf. auf MicroPython (Raspberry Pi Pico W) eingestellt werden. Klicken Sie dazu ganz unten rechts
auf den 'Button'. Das Fenster sollte jetzt z.B. so aussehen:
In der unteren Kommandozeile wird der Controler z.B. mit "MicroPython v1.22.2 on 2024-02-22; Raspberry Pi Pico W with RP2040"
angezeigt.
Jetzt geht's mit Bluetooth los
Wir nutzen Bluetooth Low Energy, abgekürzt als BLE, eine Variante der drahtlosen Bluetooth-Technologie, die mit der Energieeinsparung als
besonderem Merkmal entwickelt wurde. Im Verbindungsstatus kann ein Gerät eine von zwei Rollen einnehmen - die zentrale Rolle oder die periphere Rolle.
Das Gerät, das eine Verbindung initiiert und vom Status "Initiating" in den Status "Connection" übergeht, übernimmt die zentrale Rolle.
Das Gerät in der Peripherierolle befindet sich zunächst im Werbestatus. Wenn es eine Verbindungsanfrage vom Zentralgerät akzeptiert,
wechselt es in den Verbindungsstatus. In dieser Anleitung richten wir den Raspberry Pi Pico W als Peripheriegerät ein und stellen später eine
Punkt-zu-Punkt-Kommunikation mit einem Android-Gerät über Bluetooth Low Energy her.
Dazu brauchen wir die beiden Dateien 'ble_advertising.py' und 'ble_simple_peripheral.py' . Sie können
sie aus den beiden Kästen unten kopieren oder von der
Github Seite zu MicroPython Beispielen
beziehen.
Zuerst der Quellcode von 'ble_advertising.py':
1 # Helpers for generating BLE advertising payloads.
2 from micropython import const
3 import struct
4 import bluetooth
5
6 # Advertising payloads are repeated packets of the following form:
7 # 1 byte data length (N + 1)
8 # 1 byte type (see constants below)
9 # N bytes type-specific data
10
11 _ADV_TYPE_FLAGS = const(0x01)
12 _ADV_TYPE_NAME = const(0x09)
13 _ADV_TYPE_UUID16_COMPLETE = const(0x3)
14 _ADV_TYPE_UUID32_COMPLETE = const(0x5)
15 _ADV_TYPE_UUID128_COMPLETE = const(0x7)
16 _ADV_TYPE_UUID16_MORE = const(0x2)
17 _ADV_TYPE_UUID32_MORE = const(0x4)
18 _ADV_TYPE_UUID128_MORE = const(0x6)
19 _ADV_TYPE_APPEARANCE = const(0x19)
20
21 # Generate a payload to be passed to gap_advertise(adv_data=...).
22 def advertising_payload(limited_disc=False, br_edr=False, name=None, services=None, appearance=0):
23 payload = bytearray()
24
25 def _append(adv_type, value):
26 nonlocal payload
27 payload += struct.pack("BB", len(value) + 1, adv_type) + value
28
29 _append(
30 _ADV_TYPE_FLAGS,
31 struct.pack("B", (0x01 if limited_disc else 0x02) + (0x18 if br_edr else 0x04)),
32 )
33
34 if name:
35 _append(_ADV_TYPE_NAME, name)
36
37 if services:
38 for uuid in services:
39 b = bytes(uuid)
40 if len(b) == 2:
41 _append(_ADV_TYPE_UUID16_COMPLETE, b)
42 elif len(b) == 4:
43 _append(_ADV_TYPE_UUID32_COMPLETE, b)
44 elif len(b) == 16:
45 _append(_ADV_TYPE_UUID128_COMPLETE, b)
46
47 # See org.bluetooth.characteristic.gap.appearance.xml
48 if appearance:
49 _append(_ADV_TYPE_APPEARANCE, struct.pack("<h", appearance))
50
51 return payload
52
53 def decode_field(payload, adv_type):
54 i = 0
55 result = []
56 while i + 1 < len(payload):
57 if payload[i + 1] == adv_type:
58 result.append(payload[i + 2 : i + payload[i] + 1])
59 i += 1 + payload[i]
60 return result
61
62 def decode_name(payload):
63 n = decode_field(payload, _ADV_TYPE_NAME)
64 return str(n[0], "utf-8") if n else ""
65
66 def decode_services(payload):
67 services = []
68 for u in decode_field(payload, _ADV_TYPE_UUID16_COMPLETE):
69 services.append(bluetooth.UUID(struct.unpack("<h", u)[0]))
70 for u in decode_field(payload, _ADV_TYPE_UUID32_COMPLETE):
71 services.append(bluetooth.UUID(struct.unpack("<d", u)[0]))
72 for u in decode_field(payload, _ADV_TYPE_UUID128_COMPLETE):
73 services.append(bluetooth.UUID(u))
74 return services
75
76 def demo():
77 payload = advertising_payload(
78 name="micropython",
79 services=[bluetooth.UUID(0x181A), bluetooth.UUID("6E400001-B5A3-F393-E0A9-E50E24DCCA9E")],
80 )
81 print(payload)
82 print(decode_name(payload))
83 print(decode_services(payload))
84
85 if __name__ == "__main__":
86 demo()
Und hier der Quellcode von 'ble_simple_peripheral.py':
1 # This example demonstrates a UART periperhal.
2 import bluetooth
3 import random
4 import struct
5 import time
6 from ble_advertising import advertising_payload
7
8 from micropython import const
9
10 _IRQ_CENTRAL_CONNECT = const(1)
11 _IRQ_CENTRAL_DISCONNECT = const(2)
12 _IRQ_GATTS_WRITE = const(3)
13
14 _FLAG_READ = const(0x0002)
15 _FLAG_WRITE_NO_RESPONSE = const(0x0004)
16 _FLAG_WRITE = const(0x0008)
17 _FLAG_NOTIFY = const(0x0010)
18
19 _UART_UUID = bluetooth.UUID("6E400001-B5A3-F393-E0A9-E50E24DCCA9E")
20 _UART_TX = (
21 bluetooth.UUID("6E400003-B5A3-F393-E0A9-E50E24DCCA9E"),
22 _FLAG_READ | _FLAG_NOTIFY,
23 )
24 _UART_RX = (
25 bluetooth.UUID("6E400002-B5A3-F393-E0A9-E50E24DCCA9E"),
26 _FLAG_WRITE | _FLAG_WRITE_NO_RESPONSE,
27 )
28 _UART_SERVICE = (
29 _UART_UUID,
30 (_UART_TX, _UART_RX),
31 )
32
33
34 class BLESimplePeripheral:
35 def __init__(self, ble, name="mpy-uart"):
36 self._ble = ble
37 self._ble.active(True)
38 self._ble.irq(self._irq)
39 ((self._handle_tx, self._handle_rx),) = self._ble.gatts_register_services((_UART_SERVICE,))
40 self._connections = set()
41 self._write_callback = None
42 self._payload = advertising_payload(name=name, services=[_UART_UUID])
43 self._advertise()
44
45 def _irq(self, event, data):
46 # Track connections so we can send notifications.
47 if event == _IRQ_CENTRAL_CONNECT:
48 conn_handle, _, _ = data
49 print("New connection", conn_handle)
50 self._connections.add(conn_handle)
51 elif event == _IRQ_CENTRAL_DISCONNECT:
52 conn_handle, _, _ = data
53 print("Disconnected", conn_handle)
54 self._connections.remove(conn_handle)
55 # Start advertising again to allow a new connection.
56 self._advertise()
57 elif event == _IRQ_GATTS_WRITE:
58 conn_handle, value_handle = data
59 value = self._ble.gatts_read(value_handle)
60 if value_handle == self._handle_rx and self._write_callback:
61 self._write_callback(value)
62
63 def send(self, data):
64 for conn_handle in self._connections:
65 self._ble.gatts_notify(conn_handle, self._handle_tx, data)
66
67 def is_connected(self):
68 return len(self._connections) > 0
69
70 def _advertise(self, interval_us=500000):
71 print("Starting advertising")
72 self._ble.gap_advertise(interval_us, adv_data=self._payload)
73
74 def on_write(self, callback):
75 self._write_callback = callback
76
77
78 def demo():
79 ble = bluetooth.BLE()
80 p = BLESimplePeripheral(ble)
81
82 def on_rx(v):
83 print("RX", v)
84
85 p.on_write(on_rx)
86
87 i = 0
88 while True:
89 if p.is_connected():
90 # Short burst of queued notifications.
91 for _ in range(3):
92 data = str(i) + "_"
93 print("TX", data)
94 p.send(data)
95 i += 1
96 time.sleep_ms(100)
97
98
99 if __name__ == "__main__":
100 demo()
Wenn Sie diese beiden Dateien auf ihrem Pico W gespeichert haben, können Sie mit dem Smartphone testen,
ob Sie eine Bluetooth-Verbindung aufbauen können. Starten Sie auf dem Pico W die Datei
ble_simple_peripheral.py. Dann gehen Sie auf dem Smartphone in "Einstellungen" --
"Verbindungen" -- "Bluetooth" und tippen auf "Scannen". Als verfügbares Gerät sollte
"mpy-uart" angezeigt werden. Dafür wählen Sie koppeln aus. Wenn die
Verbindung geklappt hat, werden in der Kommandozeile des Thonny-Explorers übertragene Pakete gedruckt, bis die Verbindung
mit "Disconnected 64" beendet wird. Damit wissen Sie, dass die Sache grundsätzlich funktioniert.
Als nächstes steuern wir die Onboard-LED des Pico W, d.h. schalten diese 'ein' und 'aus'. Dazu schreiben wir das folgende kleine
Programm. Kopieren Sie den Quellcode und speichern ihn z.B. unter 'onboard_led.py' auf dem Pico W.
1 from machine import Pin
2 import bluetooth
3 from ble_simple_peripheral import BLESimplePeripheral
4
5 led = Pin("LED", Pin.OUT) # Create a Pin for the onboard LED as output
6 led.off()
7 led_state = 0
8
9 # Create a Bluetooth Low Energy (BLE) object
10 ble = bluetooth.BLE()
11 # Create an instance of the BLESimplePeripheral class with the BLE object
12 sp = BLESimplePeripheral(ble)
13
14 # Define a callback function to handle received data
15 def on_rx(data):
16 print("Data received: ", data) # Print the received data
17 global led_state # Access the global variable led_state
18 if data == b'toggle\r\n': # Check if the received data
19 led.value(not led_state) # Toggle the LED state (on/off)
20 led_state = 1 - led_state # Update the state
21
22 # Start an infinite loop
23 while True:
24 if sp.is_connected(): # Check if a BLE connection is established
25 sp.on_write(on_rx) # Set the callback function for data reception
Hier ein paar Erläuterungen:
- In den Zeilen 1, 2 und 3 werden die notwendigen Module importiert.
- In Zeile 5 wird die LED definiert und in Zeile 6 ausgeschaltet (falls sie von einem vorhergehenden Durchgang noch leuchtet).
- In Zeile 7 wird ein Status festgelegt, der beim Ein- und Ausschalten zwischen '0' und '1' wechselt.
- Die Zeilen 9 bis 12 stellen die Bluetoothverbindung her.
- In den Zeilen 14 bis 20 ist die Funktion, welche die LED abwechselnd ein- und ausschaltet. Dieses 'Umschalten' nennt man 'toggle',
wofür es in MicroPython auch den Befehl 'toggle' gibt.
- Schließlich bilden die Zeilen 22 bis 25 eine Endlosschleife.
Nun folgt der Teil, mit dem wir die LED (und später die Relais) schalten.
Installieren Sie auf Ihrem Smartphone aus dem Play Store die App: "Serial Bluetooth Terminal" und starten sie.
Dann gehen Sie wie auf den Screenshots zu sehen vor.
Beim Pico W sollte jetzt bei jeder Betätigung des Button rechts unten die LED an- bzw. ausgeschaltet werden. Dafür sind Sie jetzt
noch nicht bis an die Decke gesprungen. Deshalb folgt eine kleine Zugabe, die Ihnen sicher gefällt. Anstelle der einzelnen LED wird jetzt
ein Neopixelring ein- und ausgeschaltet. Schauen Sie sich das zunächst im Video an.
Um den Neopixelring anzusprechen, habe ich das Programm 'onboard_led.py' etwas erweitert und unter dem Namen main.py
gespeichert. Zweitens brauchen wir noch eine class Neopixel, welche die Funktionen zur Ansteuerung des Neopixelrings
unter MicroPython enthält. Die befindet sich in der Datei neopixel.py. Beide Dateien können Sie hier kopieren
und auf den gleichen Pico W übertragen, den wir bisher benutzt haben.
# Datei enthält den Quellcode von:
#
# neopixel.py
#
# Klicken Sie auf den Button 'Code kopieren' und setzen ihn im Thonny ein.
#
# Speichen Sie die Datei als 'neopixel.py'
# Datei enthält den Quellcode von:
#
# main.py
#
# Klicken Sie auf den Button 'Code kopieren' und setzen ihn im Thonny ein.
#
# Speichen Sie die Datei als 'main.py'
Die Datei 'main.py' startet, sobald der Pico W mit Spannung versorgt wird. Nutzen Sie die Smartphon-App genau
wie beim Schalten der LED. Geben Sie in der Kommandozeile relay ein zum Ein - und Ausschalten. Im Video können Sie
sehen, dass ich den 'Speicher-Button M1' nutze. Drücken Sie diesen so lange, bis sich ein Edit-Menue öffnet. Dort tragen Sie bei
'Value' den Befehl relay ein und bestätigen die Eingabe oben rechts mit dem Haken. Von nun an brauchen Sie den
Befehl nicht mehr über die Tastatur eintragen. ( Warum den Befehl 'relay'? In Wahrheit hatte ich nicht die Datei 'onboard_led.py' erweitert,
sondern eine Datei, in der ich das Reaismodul geschaltet habe. Aber dazu kommen wir ja noch.)
Bluetooth Steckdosenleiste
Bei den Suche nach einer sinnvollen Anwendung fiel mir eine 6-fach Steckdosenleiste mit Schalter in die Hände. Die Überlegung war, auf drei
der Anschlüsse zu verzichten und an dem frei werdenden Platz alles nötige für die Blutooth-Steuerung unterzubringen.
Bildbox 2 (klick hier)
Zur Beruhigung evtl. DIN VDE 0100 Päpste: "Ich werde keine Anleitung zur Verkabelung geben, keine Fotos vom Innenleben zeigen und das Teil kommt auch
nicht in den Verkauf!" Trotzdem ist alles so ausgeführt, dass man bei der Benutzung nicht mit der Netzspannung in Berührung kommen kann. Und
jeder, der die erforderlichen elektrotechnischen Kenntnisse besitzt, kann den Aufbau eigenverantwortlich nachempfinden.
Was habe ich gemacht? Zunächst habe ich die von unten aufschraubbare Leiste so weit zerlegt, dass drei Steckdosen aus dem Gehäuse entfernt werden
konnten. Die Funktion des Ein/Aus-Schalters ist unverändert geblieben. In dem frei gewordenen Bereich sind eine Anschlussleiste für die Kabel
und ein 5V Mini-Netzteil für den Pico untergebracht. Das Relais des Pico-Moduls ist für 250V/10A ausgelegt. Der Pico W selbst befindet sich unter
der Abdeckung und ist mithilfe der Pin Header mit dem Relaismodul verbunden.
Funktionsweise: Wenn der Schalter der Steckdosenleiste eingeschaltet wird, ist der Pico W mit der 5V Spannung versorgt und er versucht,
die Bluetoothverbindung zum Smartphone aufzubauen. Dabei ist der Arbeitskontakt am Relais immer erst geöffnet, so dass an den Steckdosen keine
Spannung anliegt. Über die Smartphone-App lässt sich diese mit 'relay_on' bzw. 'relay_off' schalten. Im unteren Kasten sehen Sie den Quellcode
dafür. Speichern Sie die Datei als 'main.py' auf dem Pico W. Beachten Sie, dass sich auch weiterhin die beiden Dateien
'ble_advertising.py' und 'ble_simple_peripheral.py' auf dem Pico W befinden müssen.
1 from machine import Pin
2 import bluetooth
3 from ble_simple_peripheral import BLESimplePeripheral
4
5 led = Pin("LED", Pin.OUT) # Create a Pin for the onboard LED as output
6 led.off()
7
8 relay = Pin(6, Pin.OUT) #set pin GP18 for the Relay as output
9 relay(0) # Turn off Relay
10 relay_state = 0 # Initialize the relay state to 0 (off)
11
12 # Create a Bluetooth Low Energy (BLE) object
13 ble = bluetooth.BLE()
14 # Create an instance of the BLESimplePeripheral class with the BLE object
15 sp = BLESimplePeripheral(ble)
16
17 # Define a callback function to handle received data
18 def on_rx(data):
19 print("Data received: ", data) # Print the received data
20 global relay_state # Access the global variable relay1_state
21 if data == b'relay_on\r\n' and relay_state == 0: # Check if the received data is "lelay_on"
22 relay(1) # Turn on Relay
23 relay_state = 1
24 if data == b'relay_off\r\n' and relay_state == 1: # Check if the received data is "lelay_on"
25 relay(0) # Turn off Relay
26 relay_state = 0
27
28 # Start an infinite loop
29 while True:
30 if sp.is_connected(): # Check if a BLE connection is established
31 sp.on_write(on_rx) # Set the callback function for data reception
32
Schalten Sie jetzt die Steckdosenleiste ein und stellen Sie, wie bei den vorhergehenden Beispielen auch, eine Bluetoothverbindung über die
App "Serial Bluetooth Terminal" her. Damit Sie nicht immer die Smartphone-Tastatur brauchen, nutzen Sie die beiden
Speichertasten 'M1' und 'M2'. Geben Sie bei 'Value' entweder 'relay_on'
bzw. 'relay_off' ein und bestätigen jeweils mit dem Haken. Danach können Sie mit 'M1' bzw. 'M2' ein- und ausschalten.
Viel Spass und Erfolg beim Ausprobieren. Wenn Ihnen diese Anleitung gefallen hat, tragen Sie hier
bitte einen
Kommentar ein.
Zurück
Dazu brauchen wir die beiden Dateien 'ble_advertising.py' und 'ble_simple_peripheral.py' . Sie können sie aus den beiden Kästen unten kopieren oder von der Github Seite zu MicroPython Beispielen beziehen.
Zuerst der Quellcode von 'ble_advertising.py':
1 # Helpers for generating BLE advertising payloads. 2 from micropython import const 3 import struct 4 import bluetooth 5 6 # Advertising payloads are repeated packets of the following form: 7 # 1 byte data length (N + 1) 8 # 1 byte type (see constants below) 9 # N bytes type-specific data 10 11 _ADV_TYPE_FLAGS = const(0x01) 12 _ADV_TYPE_NAME = const(0x09) 13 _ADV_TYPE_UUID16_COMPLETE = const(0x3) 14 _ADV_TYPE_UUID32_COMPLETE = const(0x5) 15 _ADV_TYPE_UUID128_COMPLETE = const(0x7) 16 _ADV_TYPE_UUID16_MORE = const(0x2) 17 _ADV_TYPE_UUID32_MORE = const(0x4) 18 _ADV_TYPE_UUID128_MORE = const(0x6) 19 _ADV_TYPE_APPEARANCE = const(0x19) 20 21 # Generate a payload to be passed to gap_advertise(adv_data=...). 22 def advertising_payload(limited_disc=False, br_edr=False, name=None, services=None, appearance=0): 23 payload = bytearray() 24 25 def _append(adv_type, value): 26 nonlocal payload 27 payload += struct.pack("BB", len(value) + 1, adv_type) + value 28 29 _append( 30 _ADV_TYPE_FLAGS, 31 struct.pack("B", (0x01 if limited_disc else 0x02) + (0x18 if br_edr else 0x04)), 32 ) 33 34 if name: 35 _append(_ADV_TYPE_NAME, name) 36 37 if services: 38 for uuid in services: 39 b = bytes(uuid) 40 if len(b) == 2: 41 _append(_ADV_TYPE_UUID16_COMPLETE, b) 42 elif len(b) == 4: 43 _append(_ADV_TYPE_UUID32_COMPLETE, b) 44 elif len(b) == 16: 45 _append(_ADV_TYPE_UUID128_COMPLETE, b) 46 47 # See org.bluetooth.characteristic.gap.appearance.xml 48 if appearance: 49 _append(_ADV_TYPE_APPEARANCE, struct.pack("<h", appearance)) 50 51 return payload 52 53 def decode_field(payload, adv_type): 54 i = 0 55 result = [] 56 while i + 1 < len(payload): 57 if payload[i + 1] == adv_type: 58 result.append(payload[i + 2 : i + payload[i] + 1]) 59 i += 1 + payload[i] 60 return result 61 62 def decode_name(payload): 63 n = decode_field(payload, _ADV_TYPE_NAME) 64 return str(n[0], "utf-8") if n else "" 65 66 def decode_services(payload): 67 services = [] 68 for u in decode_field(payload, _ADV_TYPE_UUID16_COMPLETE): 69 services.append(bluetooth.UUID(struct.unpack("<h", u)[0])) 70 for u in decode_field(payload, _ADV_TYPE_UUID32_COMPLETE): 71 services.append(bluetooth.UUID(struct.unpack("<d", u)[0])) 72 for u in decode_field(payload, _ADV_TYPE_UUID128_COMPLETE): 73 services.append(bluetooth.UUID(u)) 74 return services 75 76 def demo(): 77 payload = advertising_payload( 78 name="micropython", 79 services=[bluetooth.UUID(0x181A), bluetooth.UUID("6E400001-B5A3-F393-E0A9-E50E24DCCA9E")], 80 ) 81 print(payload) 82 print(decode_name(payload)) 83 print(decode_services(payload)) 84 85 if __name__ == "__main__": 86 demo()
Und hier der Quellcode von 'ble_simple_peripheral.py':
1 # This example demonstrates a UART periperhal. 2 import bluetooth 3 import random 4 import struct 5 import time 6 from ble_advertising import advertising_payload 7 8 from micropython import const 9 10 _IRQ_CENTRAL_CONNECT = const(1) 11 _IRQ_CENTRAL_DISCONNECT = const(2) 12 _IRQ_GATTS_WRITE = const(3) 13 14 _FLAG_READ = const(0x0002) 15 _FLAG_WRITE_NO_RESPONSE = const(0x0004) 16 _FLAG_WRITE = const(0x0008) 17 _FLAG_NOTIFY = const(0x0010) 18 19 _UART_UUID = bluetooth.UUID("6E400001-B5A3-F393-E0A9-E50E24DCCA9E") 20 _UART_TX = ( 21 bluetooth.UUID("6E400003-B5A3-F393-E0A9-E50E24DCCA9E"), 22 _FLAG_READ | _FLAG_NOTIFY, 23 ) 24 _UART_RX = ( 25 bluetooth.UUID("6E400002-B5A3-F393-E0A9-E50E24DCCA9E"), 26 _FLAG_WRITE | _FLAG_WRITE_NO_RESPONSE, 27 ) 28 _UART_SERVICE = ( 29 _UART_UUID, 30 (_UART_TX, _UART_RX), 31 ) 32 33 34 class BLESimplePeripheral: 35 def __init__(self, ble, name="mpy-uart"): 36 self._ble = ble 37 self._ble.active(True) 38 self._ble.irq(self._irq) 39 ((self._handle_tx, self._handle_rx),) = self._ble.gatts_register_services((_UART_SERVICE,)) 40 self._connections = set() 41 self._write_callback = None 42 self._payload = advertising_payload(name=name, services=[_UART_UUID]) 43 self._advertise() 44 45 def _irq(self, event, data): 46 # Track connections so we can send notifications. 47 if event == _IRQ_CENTRAL_CONNECT: 48 conn_handle, _, _ = data 49 print("New connection", conn_handle) 50 self._connections.add(conn_handle) 51 elif event == _IRQ_CENTRAL_DISCONNECT: 52 conn_handle, _, _ = data 53 print("Disconnected", conn_handle) 54 self._connections.remove(conn_handle) 55 # Start advertising again to allow a new connection. 56 self._advertise() 57 elif event == _IRQ_GATTS_WRITE: 58 conn_handle, value_handle = data 59 value = self._ble.gatts_read(value_handle) 60 if value_handle == self._handle_rx and self._write_callback: 61 self._write_callback(value) 62 63 def send(self, data): 64 for conn_handle in self._connections: 65 self._ble.gatts_notify(conn_handle, self._handle_tx, data) 66 67 def is_connected(self): 68 return len(self._connections) > 0 69 70 def _advertise(self, interval_us=500000): 71 print("Starting advertising") 72 self._ble.gap_advertise(interval_us, adv_data=self._payload) 73 74 def on_write(self, callback): 75 self._write_callback = callback 76 77 78 def demo(): 79 ble = bluetooth.BLE() 80 p = BLESimplePeripheral(ble) 81 82 def on_rx(v): 83 print("RX", v) 84 85 p.on_write(on_rx) 86 87 i = 0 88 while True: 89 if p.is_connected(): 90 # Short burst of queued notifications. 91 for _ in range(3): 92 data = str(i) + "_" 93 print("TX", data) 94 p.send(data) 95 i += 1 96 time.sleep_ms(100) 97 98 99 if __name__ == "__main__": 100 demo()
Wenn Sie diese beiden Dateien auf ihrem Pico W gespeichert haben, können Sie mit dem Smartphone testen, ob Sie eine Bluetooth-Verbindung aufbauen können. Starten Sie auf dem Pico W die Datei ble_simple_peripheral.py. Dann gehen Sie auf dem Smartphone in "Einstellungen" -- "Verbindungen" -- "Bluetooth" und tippen auf "Scannen". Als verfügbares Gerät sollte "mpy-uart" angezeigt werden. Dafür wählen Sie koppeln aus. Wenn die Verbindung geklappt hat, werden in der Kommandozeile des Thonny-Explorers übertragene Pakete gedruckt, bis die Verbindung mit "Disconnected 64" beendet wird. Damit wissen Sie, dass die Sache grundsätzlich funktioniert.
Als nächstes steuern wir die Onboard-LED des Pico W, d.h. schalten diese 'ein' und 'aus'. Dazu schreiben wir das folgende kleine Programm. Kopieren Sie den Quellcode und speichern ihn z.B. unter 'onboard_led.py' auf dem Pico W.
1 from machine import Pin 2 import bluetooth 3 from ble_simple_peripheral import BLESimplePeripheral 4 5 led = Pin("LED", Pin.OUT) # Create a Pin for the onboard LED as output 6 led.off() 7 led_state = 0 8 9 # Create a Bluetooth Low Energy (BLE) object 10 ble = bluetooth.BLE() 11 # Create an instance of the BLESimplePeripheral class with the BLE object 12 sp = BLESimplePeripheral(ble) 13 14 # Define a callback function to handle received data 15 def on_rx(data): 16 print("Data received: ", data) # Print the received data 17 global led_state # Access the global variable led_state 18 if data == b'toggle\r\n': # Check if the received data 19 led.value(not led_state) # Toggle the LED state (on/off) 20 led_state = 1 - led_state # Update the state 21 22 # Start an infinite loop 23 while True: 24 if sp.is_connected(): # Check if a BLE connection is established 25 sp.on_write(on_rx) # Set the callback function for data reception
Hier ein paar Erläuterungen:
- In den Zeilen 1, 2 und 3 werden die notwendigen Module importiert.
- In Zeile 5 wird die LED definiert und in Zeile 6 ausgeschaltet (falls sie von einem vorhergehenden Durchgang noch leuchtet).
- In Zeile 7 wird ein Status festgelegt, der beim Ein- und Ausschalten zwischen '0' und '1' wechselt.
- Die Zeilen 9 bis 12 stellen die Bluetoothverbindung her.
- In den Zeilen 14 bis 20 ist die Funktion, welche die LED abwechselnd ein- und ausschaltet. Dieses 'Umschalten' nennt man 'toggle', wofür es in MicroPython auch den Befehl 'toggle' gibt.
- Schließlich bilden die Zeilen 22 bis 25 eine Endlosschleife.
Nun folgt der Teil, mit dem wir die LED (und später die Relais) schalten.
Installieren Sie auf Ihrem Smartphone aus dem Play Store die App: "Serial Bluetooth Terminal" und starten sie. Dann gehen Sie wie auf den Screenshots zu sehen vor.
Um den Neopixelring anzusprechen, habe ich das Programm 'onboard_led.py' etwas erweitert und unter dem Namen main.py gespeichert. Zweitens brauchen wir noch eine class Neopixel, welche die Funktionen zur Ansteuerung des Neopixelrings unter MicroPython enthält. Die befindet sich in der Datei neopixel.py. Beide Dateien können Sie hier kopieren und auf den gleichen Pico W übertragen, den wir bisher benutzt haben.
# Datei enthält den Quellcode von: # # neopixel.py # # Klicken Sie auf den Button 'Code kopieren' und setzen ihn im Thonny ein. # # Speichen Sie die Datei als 'neopixel.py'
# Datei enthält den Quellcode von: # # main.py # # Klicken Sie auf den Button 'Code kopieren' und setzen ihn im Thonny ein. # # Speichen Sie die Datei als 'main.py'
Die Datei 'main.py' startet, sobald der Pico W mit Spannung versorgt wird. Nutzen Sie die Smartphon-App genau wie beim Schalten der LED. Geben Sie in der Kommandozeile relay ein zum Ein - und Ausschalten. Im Video können Sie sehen, dass ich den 'Speicher-Button M1' nutze. Drücken Sie diesen so lange, bis sich ein Edit-Menue öffnet. Dort tragen Sie bei 'Value' den Befehl relay ein und bestätigen die Eingabe oben rechts mit dem Haken. Von nun an brauchen Sie den Befehl nicht mehr über die Tastatur eintragen. ( Warum den Befehl 'relay'? In Wahrheit hatte ich nicht die Datei 'onboard_led.py' erweitert, sondern eine Datei, in der ich das Reaismodul geschaltet habe. Aber dazu kommen wir ja noch.)
Bluetooth Steckdosenleiste
Bei den Suche nach einer sinnvollen Anwendung fiel mir eine 6-fach Steckdosenleiste mit Schalter in die Hände. Die Überlegung war, auf drei
der Anschlüsse zu verzichten und an dem frei werdenden Platz alles nötige für die Blutooth-Steuerung unterzubringen.
Bildbox 2 (klick hier)
Zur Beruhigung evtl. DIN VDE 0100 Päpste: "Ich werde keine Anleitung zur Verkabelung geben, keine Fotos vom Innenleben zeigen und das Teil kommt auch
nicht in den Verkauf!" Trotzdem ist alles so ausgeführt, dass man bei der Benutzung nicht mit der Netzspannung in Berührung kommen kann. Und
jeder, der die erforderlichen elektrotechnischen Kenntnisse besitzt, kann den Aufbau eigenverantwortlich nachempfinden.
Was habe ich gemacht? Zunächst habe ich die von unten aufschraubbare Leiste so weit zerlegt, dass drei Steckdosen aus dem Gehäuse entfernt werden
konnten. Die Funktion des Ein/Aus-Schalters ist unverändert geblieben. In dem frei gewordenen Bereich sind eine Anschlussleiste für die Kabel
und ein 5V Mini-Netzteil für den Pico untergebracht. Das Relais des Pico-Moduls ist für 250V/10A ausgelegt. Der Pico W selbst befindet sich unter
der Abdeckung und ist mithilfe der Pin Header mit dem Relaismodul verbunden.
Funktionsweise: Wenn der Schalter der Steckdosenleiste eingeschaltet wird, ist der Pico W mit der 5V Spannung versorgt und er versucht,
die Bluetoothverbindung zum Smartphone aufzubauen. Dabei ist der Arbeitskontakt am Relais immer erst geöffnet, so dass an den Steckdosen keine
Spannung anliegt. Über die Smartphone-App lässt sich diese mit 'relay_on' bzw. 'relay_off' schalten. Im unteren Kasten sehen Sie den Quellcode
dafür. Speichern Sie die Datei als 'main.py' auf dem Pico W. Beachten Sie, dass sich auch weiterhin die beiden Dateien
'ble_advertising.py' und 'ble_simple_peripheral.py' auf dem Pico W befinden müssen.
1 from machine import Pin
2 import bluetooth
3 from ble_simple_peripheral import BLESimplePeripheral
4
5 led = Pin("LED", Pin.OUT) # Create a Pin for the onboard LED as output
6 led.off()
7
8 relay = Pin(6, Pin.OUT) #set pin GP18 for the Relay as output
9 relay(0) # Turn off Relay
10 relay_state = 0 # Initialize the relay state to 0 (off)
11
12 # Create a Bluetooth Low Energy (BLE) object
13 ble = bluetooth.BLE()
14 # Create an instance of the BLESimplePeripheral class with the BLE object
15 sp = BLESimplePeripheral(ble)
16
17 # Define a callback function to handle received data
18 def on_rx(data):
19 print("Data received: ", data) # Print the received data
20 global relay_state # Access the global variable relay1_state
21 if data == b'relay_on\r\n' and relay_state == 0: # Check if the received data is "lelay_on"
22 relay(1) # Turn on Relay
23 relay_state = 1
24 if data == b'relay_off\r\n' and relay_state == 1: # Check if the received data is "lelay_on"
25 relay(0) # Turn off Relay
26 relay_state = 0
27
28 # Start an infinite loop
29 while True:
30 if sp.is_connected(): # Check if a BLE connection is established
31 sp.on_write(on_rx) # Set the callback function for data reception
32
Schalten Sie jetzt die Steckdosenleiste ein und stellen Sie, wie bei den vorhergehenden Beispielen auch, eine Bluetoothverbindung über die
App "Serial Bluetooth Terminal" her. Damit Sie nicht immer die Smartphone-Tastatur brauchen, nutzen Sie die beiden
Speichertasten 'M1' und 'M2'. Geben Sie bei 'Value' entweder 'relay_on'
bzw. 'relay_off' ein und bestätigen jeweils mit dem Haken. Danach können Sie mit 'M1' bzw. 'M2' ein- und ausschalten.
Viel Spass und Erfolg beim Ausprobieren. Wenn Ihnen diese Anleitung gefallen hat, tragen Sie hier
bitte einen
Kommentar ein.
Zurück
Bildbox 2 (klick hier)
1 from machine import Pin 2 import bluetooth 3 from ble_simple_peripheral import BLESimplePeripheral 4 5 led = Pin("LED", Pin.OUT) # Create a Pin for the onboard LED as output 6 led.off() 7 8 relay = Pin(6, Pin.OUT) #set pin GP18 for the Relay as output 9 relay(0) # Turn off Relay 10 relay_state = 0 # Initialize the relay state to 0 (off) 11 12 # Create a Bluetooth Low Energy (BLE) object 13 ble = bluetooth.BLE() 14 # Create an instance of the BLESimplePeripheral class with the BLE object 15 sp = BLESimplePeripheral(ble) 16 17 # Define a callback function to handle received data 18 def on_rx(data): 19 print("Data received: ", data) # Print the received data 20 global relay_state # Access the global variable relay1_state 21 if data == b'relay_on\r\n' and relay_state == 0: # Check if the received data is "lelay_on" 22 relay(1) # Turn on Relay 23 relay_state = 1 24 if data == b'relay_off\r\n' and relay_state == 1: # Check if the received data is "lelay_on" 25 relay(0) # Turn off Relay 26 relay_state = 0 27 28 # Start an infinite loop 29 while True: 30 if sp.is_connected(): # Check if a BLE connection is established 31 sp.on_write(on_rx) # Set the callback function for data reception 32
Viel Spass und Erfolg beim Ausprobieren. Wenn Ihnen diese Anleitung gefallen hat, tragen Sie hier bitte einen Kommentar ein.
Zurück