Ratgeber · 16 Min. Lesezeit

App Inventor Arduino Bluetooth: Eigene Android-App mit HC-05

Arduino per Bluetooth mit App Inventor steuern: HC-05 anschließen, ListPicker, Button- und Slider-Blöcke, LED, Relais, Servo, Sensordaten, APK und Android 12.

Den Arduino mit App Inventor per Bluetooth zu steuern, ist der schnellste Weg zu einer eigenen Android-App, ohne eine einzige Zeile Java oder Kotlin zu schreiben. Im kostenlosen, browserbasierten MIT App Inventor ziehst du Buttons, Schieberegler und Textfelder auf den Bildschirm und legst mit Blöcken, die wie Puzzleteile ineinandergreifen, fest, was sie tun. Das Handy verbindet sich mit einem HC-05-Bluetooth-Modul am Arduino; jedes Tippen in der App wandert als kurzer Textbefehl zum Arduino, und der Arduino schickt seine Sensorwerte auf demselben Weg zurück ans Handy.

Am Ende dieser Anleitung hast du eine Fernsteuer-App, die wirklich funktioniert: einen ListPicker, der sich aus einer Liste mit dem HC-05 verbindet, Buttons, die eine LED und ein Relais ein- und ausschalten, zwei Schieberegler (Slider) für LED-Helligkeit und Servowinkel sowie Labels, die Temperatur und Luftfeuchtigkeit eines DHT11 live anzeigen. Du gehst Schritt für Schritt durch den Arduino-Code, jeden App-Inventor-Block, das Erstellen der APK und die Lösung für das Bluetooth-Berechtigungsproblem seit Android 12. Falls du das HC-05 noch nie benutzt hast, wirf zuerst einen Blick in die Anleitung zum HC-05-Bluetooth-Modul.

HC-05-Bluetooth-Modul
Das HC-05 ist ein klassisches Bluetooth-Modul (SPP) und genau das, womit die BluetoothClient-Komponente von App Inventor spricht; es baut eine drahtlose serielle Verbindung zwischen Handy und Arduino auf.

Was ist App Inventor, und wie spricht es mit dem Arduino?

MIT App Inventor ist eine kostenlose Entwicklungsumgebung für Apps vom Massachusetts Institute of Technology (MIT); du meldest dich mit deinem Google-Konto an und arbeitest direkt im Browser. Es gibt zwei Ansichten: Im Designer gestaltest du das Aussehen der App, indem du Komponenten hineinziehst, und im Blocks-Editor schreibst du mit bunten Blöcken Regeln wie „wenn der Button gedrückt wird, tu dies“. Zum Testen ohne Installation dient die App MIT AI2 Companion aus dem Play Store; am Ende erzeugt ein Klick eine installierbare APK-Datei.

Auf der Bluetooth-Seite erledigt die Komponente BluetoothClient die Arbeit. Sie nutzt das SPP (Serial Port Profile) des klassischen Bluetooth, und genau dieses Profil spricht auch das HC-05. So entsteht ein unsichtbares serielles Kabel zwischen Handy und Arduino: Schickt die App mit dem Block SendText „L1“, liest der Arduino diese zwei Zeichen mit bt.read(), als hättest du sie in den seriellen Monitor getippt. Alles, was der Arduino mit bt.print() sendet, landet beim Block ReceiveText im Handy. Auf dem Arduino brauchst du keine spezielle Bluetooth-Bibliothek.

EbeneAufgabeIn diesem Projekt
Oberfläche (Designer)Komponenten auf dem BildschirmListPicker, 5 Buttons, 2 Slider, Labels
Logik (Blocks)Blöcke, die auf Ereignisse reagierenClick-, PositionChanged- und Timer-Ereignisse
BluetoothClientSPP-Verbindung, Daten senden und empfangenConnect, SendText, ReceiveText
HC-05Brücke zwischen Bluetooth und UART9600 Baud, PIN 1234
ArduinoWertet Befehle aus, steuert Ausgänge, liest den SensorLED, Relais, Servo, DHT11

Das brauchst du

BauteilAnzahlHinweis
Arduino Uno (oder Nano)1Code und Pins sind bei beiden gleich
Bluetooth-Modul HC-05 oder HC-061Klassisches Bluetooth; das HM-10 (BLE) funktioniert so nicht
Widerstände 1 kΩ und 2 kΩje 1Spannungsteiler für den RXD-Pin des HC-05 (2,2 kΩ geht auch)
LED und 220-Ω-Widerstandje 1Dimmbare LED (D5, PWM)
5-V-Relaismodul1Zum Schalten von Lampe oder Ventilator
Servomotor SG9010–180° per Schieberegler
Temperatur- und Feuchtigkeitssensor DHT111Daten für die Anzeige auf dem Handy
Android-Smartphone1Das HC-05 funktioniert nicht mit dem iPhone
Steckbrett und Jumperkabel—Gemeinsame Masse (GND) ist Pflicht
Arduino Uno
Arduino Uno
HC-06
HC-06
SG90
SG90
DHT11
DHT11
LED
LED

Schaltung: HC-05, LED, Relais, Servo und DHT11 anschließen

Das HC-05 hat einen Spannungsregler auf der Platine, daher verträgt der VCC-Pin 5 V, die Datenpins arbeiten aber mit 3,3-V-Logik. Das 3,3-V-Signal vom TXD-Pin des Moduls liest der Arduino problemlos; das 5-V-TX-Signal des Arduino solltest du dem RXD-Pin dagegen über einen Spannungsteiler zuführen: D11 → 1 kΩ → RXD, RXD → 2 kΩ → GND. So kommen an RXD 5 × 2 / 3 ≈ 3,3 V an. Wir schließen das HC-05 per SoftwareSerial an D10 und D11 an statt an die Hardware-Serial-Pins 0 und 1 des Uno; so kannst du mit angeschlossenem Modul Sketches hochladen und den seriellen Monitor weiter zur Fehlersuche nutzen. Den LED-Vorwiderstand prüfst du mit dem LED-Vorwiderstandsrechner.

VerbindungArduino UnoESP32Raspberry Pi Pico
HC-05 VCC5VNicht nötig (Bluetooth integriert)VBUS (5 V)
HC-05 GNDGND—GND
HC-05 TXDD10 (SoftwareSerial RX)—GP1 (UART0 RX)
HC-05 RXDD11, über 1 kΩ / 2 kΩ Teiler—GP0 (UART0 TX), ohne Teiler
LED (+ 220 Ω)D5 (PWM)GPIO 2 (Onboard-LED)GP15
Relaismodul IND7GPIO 26GP14
Servo-Signal (orange)D9— (mit ESP32Servo ergänzbar)GP13
DHT11 DatenD2GPIO 4GP16
Beachte drei Regeln: Alle GNDs (Arduino, HC-05, Relais, Servo und ggf. externe Versorgung) müssen miteinander verbunden sein. Lege an den RXD-Pin des HC-05 nie 5 V ohne Teiler; das Modul hält das eine Weile aus, kann aber mit der Zeit kaputtgehen. Ein Servo kann beim Bewegen kurzzeitig mehrere hundert Milliampere ziehen; läuft der Arduino über USB, bricht dadurch die Spannung ein, das HC-05 verliert die Verbindung oder der Arduino startet neu. Eine eigene 5-V-Versorgung für Servo und Relais löst das Problem an der Wurzel.

Das Protokoll: Was schickt das Handy?

Bevor du Code schreibst, legst du fest, welche „Sprache“ Handy und Arduino sprechen. In diesem Projekt besteht jeder Befehl aus einem Buchstaben, einer Zahl und am Ende einem Zeilenumbruch (\n, ASCII 10). Der Zeilenumbruch ist entscheidend: Bluetooth-Daten können in Stücken ankommen, und wenn „S1“ und „35“ getrennt eintreffen, wartet der Arduino auf den Zeilenumbruch und verarbeitet „S135“ als einen Befehl. Weil die Befehle lesbarer Text sind, kannst du sie auch von Hand mit jeder Bluetooth-Terminal-App ausprobieren.

BefehlRichtungBedeutung
L1 / L0Handy → ArduinoLED mit voller Helligkeit ein / aus
P0 … P255Handy → ArduinoLED-Helligkeit (analogWrite-Wert)
R1 / R0Handy → ArduinoRelais anziehen / abfallen lassen
S0 … S180Handy → ArduinoServowinkel (Grad)
24.5;41Arduino → HandyTemperatur (°C) und Feuchtigkeit (%), durch Semikolon getrennt

Statt Text kann App Inventor mit dem Block Send1ByteNumber auch ein einzelnes Byte (0–255) senden, das der Arduino direkt als Zahl liest. Das ist kurz und schnell, passt aber nur für einen einzigen Schieberegler: Senden zwei Slider und vier Buttons Bytes, kann der Arduino nicht erkennen, ob eine eintreffende 90 ein Servowinkel oder eine Helligkeit ist. Das Format Buchstabe + Zahl + Zeilenumbruch kostet ein paar Bytes mehr, aber bei 9600 Baud gehen rund 960 Zeichen pro Sekunde durch – den Unterschied merkst du nie.

Der Arduino-Code

Die Bibliotheken Servo und SoftwareSerial sind in der Arduino IDE bereits enthalten. Für den DHT11 installierst du im Bibliotheksverwalter die DHT sensor library (Adafruit); bei der Frage nach Abhängigkeiten wählst du Install all, damit auch Adafruit Unified Sensor dazukommt. Da wir die Pins 0 und 1 nicht belegen, musst du das HC-05 beim Hochladen nicht abziehen.

Arduino (C++)
1#include <SoftwareSerial.h>
2#include <Servo.h>
3#include <DHT.h>
4
5SoftwareSerial bt(10, 11);       // RX, TX → HC-05 TXD, RXD (bölücü üzerinden / via divider)
6Servo servo;
7DHT dht(2, DHT11);               // DHT11 veri pini D2 / data pin D2
8
9const int LED_PIN = 5;           // PWM destekli pin / PWM-capable pin
10const int ROLE_PIN = 7;
11const int SERVO_PIN = 9;
12const int ROLE_ACIK = LOW;       // çoğu röle modülü LOW ile çeker / most relay modules are active LOW
13const int ROLE_KAPALI = HIGH;
14
15String komut = "";               // gelen satırın tamponu / buffer for the incoming line
16unsigned long sonGonderim = 0;
17
18void komutIsle(String k) {
19  k.trim();                                  // boşluk ve \r temizle / strip spaces and \r
20  if (k.length() == 0) return;
21  Serial.println(k);                         // hata ayıklama / debugging
22  char tur = k.charAt(0);                    // komut harfi / command letter
23  int deger = k.substring(1).toInt();        // harften sonraki sayı / number after the letter
24
25  switch (tur) {
26    case 'L':                                // L1 / L0 → LED aç, kapat / LED on, off
27      analogWrite(LED_PIN, deger == 1 ? 255 : 0);
28      break;
29    case 'P':                                // P0..P255 → parlaklık / brightness
30      analogWrite(LED_PIN, constrain(deger, 0, 255));
31      break;
32    case 'R':                                // R1 / R0 → röle / relay
33      digitalWrite(ROLE_PIN, deger == 1 ? ROLE_ACIK : ROLE_KAPALI);
34      break;
35    case 'S':                                // S0..S180 → servo açısı / servo angle
36      servo.write(constrain(deger, 0, 180));
37      break;
38  }
39}
40
41void setup() {
42  pinMode(LED_PIN, OUTPUT);
43  pinMode(ROLE_PIN, OUTPUT);
44  digitalWrite(ROLE_PIN, ROLE_KAPALI);       // açılışta röle kapalı / relay off at start
45  servo.attach(SERVO_PIN);
46  servo.write(90);                           // orta konum / centre position
47  dht.begin();
48  Serial.begin(9600);                        // Seri Monitör / Serial Monitor
49  bt.begin(9600);                            // HC-05 veri modu hızı / HC-05 data mode baud rate
50}
51
52void loop() {
53  // 1) Telefondan gelen komutları satır satır oku / read commands from the phone line by line
54  while (bt.available()) {
55    char c = bt.read();
56    if (c == '\n') {                         // satır bitti / line complete
57      komutIsle(komut);
58      komut = "";
59    } else if (komut.length() < 16) {        // aşırı uzun satırı kes / cap overlong lines
60      komut += c;
61    }
62  }
63
64  // 2) 2 saniyede bir sensör verisini gönder / send sensor data every 2 seconds
65  if (millis() - sonGonderim >= 2000) {
66    sonGonderim = millis();
67    float t = dht.readTemperature();
68    float h = dht.readHumidity();
69    if (!isnan(t) && !isnan(h)) {
70      bt.print(t, 1);                        // örnek / example: 24.5
71      bt.print(';');
72      bt.print(h, 0);                        // örnek / example: 41
73      bt.print('\n');                        // println değil, \r gitmesin / not println, no \r
74    }
75  }
76}
  • Zeilenpuffer: loop() hängt jedes eintreffende Zeichen an die Variable komut (Befehl) an; kommt \n, übergibt es die Zeile an komutIsle() und leert den Puffer. Alles über 16 Zeichen wird verworfen, damit Datenmüll den Speicher nicht füllt.
  • trim(): Manche Terminal-Apps hängen zusätzlich \r an das Zeilenende; trim() entfernt es samt Leerzeichen, sodass „L1\r“ trotzdem als „L1“ erkannt wird.
  • Buchstabe und Zahl: charAt(0) liefert den Befehlsbuchstaben, substring(1).toInt() die Zahl dahinter. constrain() begrenzt den Wert auf einen sicheren Bereich; selbst wenn das Handy versehentlich 300 schickt, wird der Servo nie über 180° gedrückt.
  • Senden ohne Blockieren: Der Sensor wird mit millis() alle 2 Sekunden gelesen. Weil kein delay() vorkommt, werden zwischendurch eintreffende Befehle ohne Verzögerung verarbeitet; Details in millis() statt delay().
  • print('\n') statt println: println() beendet die Zeile mit \r\n. App Inventor nutzt nur \n als Trennzeichen, also bliebe \r am Ende des Feuchtigkeitswerts hängen; nur \n zu senden hält das Zerlegen auf dem Handy sauber.
  • Low-aktives Relais: Die meisten Relaismodule ziehen an, wenn IN auf LOW geht. Zieht deins bei HIGH an, tausche einfach die Werte der Konstanten ROLE_ACIK (an) und ROLE_KAPALI (aus).
Teste die Arduino-Seite allein, bevor du zu App Inventor wechselst: Verbinde dich mit einer App wie Serial Bluetooth Terminal aus dem Play Store mit dem HC-05, tippe „L1“ und sende es; die LED sollte angehen und L1 im seriellen Monitor erscheinen. Laufen alle 2 Sekunden Zeilen wie „24.5;41“ durch, funktioniert auch der Rückkanal. Taucht später ein Problem auf, weißt du so sofort, ob der Fehler in der App oder in der Schaltung steckt.

Die Oberfläche in App Inventor gestalten (Designer)

  1. Öffne im Browser ai2.appinventor.mit.edu, melde dich mit deinem Google-Konto an und lege über Projects > Start new project ein Projekt namens BlueGraysRemote an.
  2. Ziehe aus der Gruppe Layout der Palette ein HorizontalArrangement herein und setze einen ListPicker (Text: Verbinden), einen Button (Text: Trennen) und ein Label (Text: Nicht verbunden) hinein.
  3. Füge darunter zwei weitere HorizontalArrangements hinzu: ins erste die Buttons LED an und LED aus, ins zweite Relais an und Relais aus. Mit Width auf Fill parent lassen sich die Buttons leichter antippen.
  4. Füge zwei Slider hinzu: für die Helligkeit MinValue 0, MaxValue 255, ThumbPosition 0; für den Servo MinValue 0, MaxValue 180, ThumbPosition 90. Setze über jeden ein Label, das sagt, wofür er da ist.
  5. Füge zwei weitere Labels für Temperatur und Feuchtigkeit hinzu und stelle ihre FontSize auf etwa 20.
  6. Füge aus der Gruppe Connectivity einen BluetoothClient hinzu; setze im Properties-Bereich DelimiterByte auf 10 und hake NoLocationNeeded an.
  7. Füge aus der Gruppe Sensors eine Clock hinzu; TimerInterval auf 200 und den Haken bei TimerEnabled entfernen. Den Timer schalten wir per Block ein, sobald die Verbindung steht.
KomponenteName (Rename)Wichtige Einstellung
ListPickerLP_ConnectText: Verbinden
Button × 5BTN_Disconnect, BTN_LedOn, BTN_LedOff, BTN_RelayOn, BTN_RelayOffWidth: Fill parent
SliderSLD_BrightnessMinValue 0, MaxValue 255
SliderSLD_ServoMinValue 0, MaxValue 180, ThumbPosition 90
LabelLBL_Status, LBL_Temp, LBL_HumFontSize 20 (für die Werte)
BluetoothClientBluetoothClient1DelimiterByte 10, NoLocationNeeded angehakt
ClockClock1TimerInterval 200, TimerEnabled aus

Mit dem ListPicker zum HC-05 verbinden

Kopple das HC-05 zuerst in den Bluetooth-Einstellungen des Handys (PIN meist 1234, sonst 0000). Dieser Schritt ist Pflicht: BluetoothClient1.AddressesAndNames listet nur gekoppelte Geräte auf und sucht nicht nach neuen in der Nähe. Jeder Eintrag ist ein Text mit MAC-Adresse und danach dem Gerätenamen, etwa „98:D3:31:F5:2A:10 HC-05“. Du kannst den ganzen Text an den Connect-Block übergeben; App Inventor schneidet alles nach dem ersten Leerzeichen selbst ab. Der Block liefert true, wenn die Verbindung klappt, und false, wenn nicht.

  1. Setze in das Ereignis when LP_Connect.BeforePicking den Block set LP_Connect.Elements to BluetoothClient1.AddressesAndNames. Die Liste füllt sich bei jedem Öffnen neu mit den gekoppelten Geräten.
  2. Füge im Ereignis when LP_Connect.AfterPicking einen if-Block ein und stecke call BluetoothClient1.Connect address: LP_Connect.Selection in seine Bedingung.
  3. Setze im then-Teil LBL_Status.Text auf „Verbunden“ und starte das Einlesen mit set Clock1.TimerEnabled to true; im else-Teil schreibst du „Verbindung fehlgeschlagen“.
  4. Im Ereignis when BTN_Disconnect.Click zuerst set Clock1.TimerEnabled to false, dann call BluetoothClient1.Disconnect und zum Schluss LBL_Status.Text auf „Nicht verbunden“. Den Timer zuerst zu stoppen verhindert einen Lesezugriff und eine Fehlermeldung nach dem Trennen.
Sobald die Verbindung steht, hört die LED des HC-05 auf, schnell zu blinken, und blitzt stattdessen alle 2 Sekunden zweimal kurz auf. So erkennst du den Verbindungsstatus, ohne auf die App zu schauen; blinkt die LED wieder schnell, ist die Verbindung abgerissen.

Daten senden: Buttons und Schieberegler

Zum Senden genügt ein einziger Block: call BluetoothClient1.SendText text. Schreibst du „L1\n“ in einen Textblock, wandelt App Inventor das \n am Ende in einen Zeilenumbruch um. Senden ohne Verbindung führt zu Fehler 515, daher ist es eine gute Gewohnheit, jeden Sendevorgang in eine Prüfung if BluetoothClient1.IsConnected zu packen. Beim Slider hängst du die Zahl mit einem join-Block an Buchstabe und Zeilenumbruch: join("S", round(thumbPosition), "\n").

Ereignis (event)Gesendeter TextErgebnis am Arduino
BTN_LedOn.ClickL1\nLED leuchtet voll
BTN_LedOff.ClickL0\nLED geht aus
BTN_RelayOn.ClickR1\nRelais zieht an, die angeschlossene Lampe leuchtet
BTN_RelayOff.ClickR0\nRelais fällt ab
SLD_Brightness.PositionChangedjoin("P", round(thumbPosition), "\n")analogWrite(5, Wert)
SLD_Servo.PositionChangedjoin("S", round(thumbPosition), "\n")servo.write(Winkel)

Während du einen Slider mit dem Finger ziehst, feuert das Ereignis PositionChanged dutzende Male pro Sekunde, und thumbPosition liefert Kommawerte wie 87,4. Sendest du bei jedem Ereignis, geht derselbe Winkel immer wieder raus, der Puffer des HC-05 läuft voll und der Servo bewegt sich ruckelnd und verspätet. Die Lösung ist einfach: Lege eine Variable global lastAngle an; sende nur, wenn der mit round(thumbPosition) gerundete Wert davon abweicht, und aktualisiere dann die Variable. So gehen nur Daten raus, wenn sich der Winkel wirklich ändert. Für den Helligkeits-Slider machst du dasselbe mit global lastBrightness.

Daten empfangen: Sensorwerte auf dem Handy anzeigen

Der Arduino schickt alle 2 Sekunden eine Zeile „24.5;41“. In App Inventor gibt es kein Ereignis, das bei eintreffenden Daten von selbst auslöst; deshalb fragen wir mit der Komponente Clock in regelmäßigen Abständen nach: „Sind neue Daten da?“ Weil wir DelimiterByte im Designer auf 10 gesetzt haben, liest der Block ReceiveText mit -1 als numberOfBytes bis zum Zeilenumbruch und gibt die Zeile ohne \n zurück. Ein 200-ms-Timer schaut viel öfter nach, als Daten kommen (alle 2000 ms), daher staut sich im Puffer nichts.

  1. Setze in when Clock1.Timer eine Bedingung if BluetoothClient1.IsConnected.
  2. Füge darin eine zweite Bedingung hinzu: call BluetoothClient1.BytesAvailableToReceive > 0.
  3. Speichere die eintreffende Zeile mit initialize local line to call BluetoothClient1.ReceiveText numberOfBytes: -1 in einer lokalen Variablen.
  4. Zerlege die Zeile mit dem Block split text line at ";" in eine Liste: Aus „24.5;41“ wird die zweielementige Liste [24.5, 41]. Speichere das Ergebnis in einer lokalen Variablen namens parts.
  5. if length of list parts = 2: Setze LBL_Temp.Text auf join("Temperatur: ", select list item parts index 1, " °C") und LBL_Hum.Text auf join("Feuchte: ", select list item parts index 2, " %"). Die Prüfung der Elementanzahl verhindert, dass halb empfangene oder kaputte Zeilen Fehler auslösen.
Übergibst du ReceiveText -1, vergisst aber, DelimiterByte auf 10 zu setzen (Standard ist 0), wartet der Block auf ein 0-Byte, das nie kommt, und die App wirkt eingefroren. Und schickt der Arduino seine Zeile mit println(), landet das Zeichen \r am Ende des zweiten Werts; deshalb sendet der Code nur '\n'.
Bleib nicht bei reinem Text stehen: Du kannst LBL_Temp.TextColor rot färben, sobald die Temperatur 30 °C übersteigt, mit der Komponente Notifier eine Warnung öffnen oder auf einem Canvas ein Liniendiagramm der letzten Messwerte zeichnen.

Bluetooth-Berechtigungsproblem ab Android 12

Mit Android 12 (API 31) haben sich die Bluetooth-Berechtigungen geändert. Die alte BLUETOOTH-Berechtigung, die bei der Installation automatisch erteilt wurde, wurde durch BLUETOOTH_CONNECT und BLUETOOTH_SCAN ersetzt, die der Nutzer zur Laufzeit bestätigen muss; in den Einstellungen des Handys heißen sie Geräte in der Nähe. Fehlt die Berechtigung, öffnet App Inventor beim ersten Versuch den Berechtigungsdialog, stoppt aber den gerade laufenden Block. Das führt zu bekannten Symptomen: Die Liste öffnet sich beim ersten Tippen auf Verbinden leer, die Meldung „Error 908: The permission ... has been denied“ erscheint (mit BLUETOOTH_CONNECT oder BLUETOOTH_SCAN als Name), oder die App fragt nie wieder, wenn der Nutzer einmal abgelehnt hat.

  1. Prüfe im Ereignis when Screen1.Initialize die Android-Version: Ist select list item (split Screen1.PlatformVersion at ".") index 1 ≥ 12, gib call Screen1.AskForPermission den Wert BluetoothConnect aus der Permission-Liste. Unter Android 11 und älter gibt es diese Berechtigungen nicht, und dort danach zu fragen löst ebenfalls Fehler 908 aus – die Versionsprüfung ist also wichtig.
  2. Frage im Ereignis when Screen1.PermissionGranted als Nächstes BluetoothScan an, wenn die erteilte Berechtigung BLUETOOTH_CONNECT ist (contains text: permissionName, piece: "CONNECT"). AskForPermission nimmt immer nur eine Berechtigung entgegen, deshalb verkettest du sie so.
  3. Zeige im Ereignis when Screen1.PermissionDenied per Notifier eine Meldung mit dem Pfad „Einstellungen > Apps > BlueGraysRemote > Berechtigungen > Geräte in der Nähe > Zulassen“. Wenn du dieses Ereignis abfängst, sieht der Nutzer eine verständliche Erklärung statt eines englischen Fehlerfensters.
  4. Lass beim BluetoothClient im Designer NoLocationNeeded angehakt; damit teilt die App Android mit, dass sie Bluetooth nicht zur Standortbestimmung nutzt.
  5. Teste unbedingt auch mit der APK: Die Berechtigungen des AI2 Companion gehören zur Companion-App, deine APK fragt nach der Installation ihre eigenen Berechtigungen ab.
FehlerBedeutungLösung
Error 507: Unable to connect. Is the device turned on?Verbindung zum Modul fehlgeschlagenStromversorgung und Kopplung des HC-05 prüfen und sicherstellen, dass es nicht mit einem anderen Handy verbunden ist; klappt es weiterhin nicht, beim BluetoothClient den Haken bei Secure entfernen und erneut versuchen
Error 515: Not connected to a Bluetooth device.Senden oder Lesen ohne VerbindungSende- und Clock-Blöcke in eine IsConnected-Prüfung packen
Error 516: Unable to write: Broken pipeVerbindung mittendrin abgerissen (Strom weg, außer Reichweite)Clock stoppen, Disconnect aufrufen und neu verbinden; Servo und Relais separat versorgen
Error 908: The permission … has been deniedKeine Berechtigung „Geräte in der Nähe“ ab Android 12Per Block anfragen oder in den Einstellungen manuell erteilen
Die Liste ist leerModul nicht gekoppelt oder Berechtigung gerade erst angefragtHC-05 in den Handy-Einstellungen koppeln, nach dem Erteilen der Berechtigung erneut auf Verbinden tippen

App testen und APK erstellen

Während der Entwicklung musst du nicht nach jeder Änderung eine APK installieren. Installiere die App MIT AI2 Companion aus dem Play Store; wenn Computer und Handy im selben WLAN sind, wähle in App Inventor Connect > AI Companion und scanne den QR-Code oder gib den 6-stelligen Code vom Bildschirm ein. Jede Änderung im Designer oder in den Blöcken erscheint sofort auf dem Handy. Ist die App fertig, erzeugst du die installierbare Datei so:

  1. Wähle im Designer Screen1 aus und fülle AppName (der Name auf dem Handy), Icon (ein quadratisches PNG), VersionCode und VersionName aus.
  2. Wähle im oberen Menü Build > Android App (.apk). Das Kompilieren dauert meist ein bis zwei Minuten.
  3. Danach öffnet sich ein Fenster mit QR-Code und Download-Button. Du kannst den QR-Code mit dem Handy scannen und die Datei direkt laden oder die APK auf dem Computer speichern und per USB-Kabel aufs Handy kopieren. Der QR-Link gilt nur kurze Zeit (etwa 2 Stunden).
  4. Öffnest du die APK auf dem Handy, fragt Android, ob du dem Browser oder Dateimanager erlaubst, unbekannte Apps zu installieren. Zeigt Play Protect eine Warnung, kannst du über die Details trotzdem installieren; diese Warnung ist bei Apps außerhalb des Play Stores mit unbekannter Signatur üblich.
  5. Bestätige beim ersten Start der App die Berechtigung „Geräte in der Nähe“, tippe auf Verbinden und wähle das HC-05 aus der Liste.
Sichere dein Projekt mit Projects > Export selected project (.aia) to my computer; die .aia-Datei kannst du mit Freunden teilen oder in ein anderes Konto übernehmen. Willst du die App bei Google Play veröffentlichen, nutze Build > Android App Bundle (.aab) und bewahre deinen Signaturschlüssel unbedingt mit Projects > Export keystore auf: Updates müssen mit demselben Schlüssel signiert sein. Erhöhe außerdem bei jedem Update den VersionCode um 1.

Dieselbe App mit dem ESP32 – ganz ohne HC-05

ESP32-Entwicklungsboard
Der klassische ESP32 hat Bluetooth Classic eingebaut; der BluetoothClient von App Inventor verbindet sich mit ihm genauso wie mit einem HC-05.

Der klassische ESP32 hat sowohl klassisches Bluetooth als auch BLE eingebaut. Die Bibliothek BluetoothSerial stellt den ESP32 dem Handy als SPP-Gerät vor, sodass du die eben gebaute App ohne jede Änderung nutzen kannst. Kopple in den Bluetooth-Einstellungen das Gerät „BlueGrays-ESP32“, wähle es in der App aus der Liste – fertig. Achtung: ESP32-S3, ESP32-C3 und ESP32-C6 unterstützen nur BLE; dort gibt es kein BluetoothSerial, und in App Inventor brauchst du die BluetoothLE-Erweiterung. Mehr zu BLE findest du im Artikel ESP32 Bluetooth und BLE.

Arduino (C++)
1#include "BluetoothSerial.h"
2#include <DHT.h>
3
4BluetoothSerial SerialBT;
5DHT dht(4, DHT11);               // DHT11 veri pini GPIO 4 / data pin GPIO 4
6
7const int LED_PIN = 2;           // çoğu DevKit'te kart üstü LED / onboard LED on most DevKits
8const int ROLE_PIN = 26;
9
10String komut = "";
11unsigned long sonGonderim = 0;
12
13void setup() {
14  pinMode(ROLE_PIN, OUTPUT);
15  digitalWrite(ROLE_PIN, HIGH);              // aktif LOW röle kapalı / active-LOW relay off
16  dht.begin();
17  SerialBT.begin("BlueGrays-ESP32");         // telefonda görünecek ad / name shown on the phone
18}
19
20void loop() {
21  while (SerialBT.available()) {
22    char c = SerialBT.read();
23    if (c == '\n') {
24      komut.trim();
25      int deger = komut.substring(1).toInt();
26      if (komut.startsWith("L")) {
27        analogWrite(LED_PIN, deger == 1 ? 255 : 0);              // LED aç, kapat / LED on, off
28      } else if (komut.startsWith("P")) {
29        analogWrite(LED_PIN, constrain(deger, 0, 255));          // parlaklık / brightness
30      } else if (komut.startsWith("R")) {
31        digitalWrite(ROLE_PIN, deger == 1 ? LOW : HIGH);         // röle / relay
32      }
33      komut = "";
34    } else if (komut.length() < 16) {
35      komut += c;
36    }
37  }
38
39  if (millis() - sonGonderim >= 2000) {      // Uno koduyla aynı biçim / same format as the Uno
40    sonGonderim = millis();
41    float t = dht.readTemperature();
42    float h = dht.readHumidity();
43    if (!isnan(t) && !isnan(h)) {
44      SerialBT.print(t, 1);
45      SerialBT.print(';');
46      SerialBT.print(h, 0);
47      SerialBT.print('\n');
48    }
49  }
50}

Der Code versteht dieselben Befehle wie die Uno-Version und sendet die Daten im selben Format „Temperatur;Feuchte“; S-Befehle ignoriert er, weil kein Servo angeschlossen ist. Die Servo-Bibliothek des Arduino läuft auf dem ESP32 nicht; für einen Servo installierst du die Bibliothek ESP32Servo und nutzt dieselben Aufrufe attach() und write(), zum Beispiel an GPIO 13. Versorge das Relaismodul über den VIN-Pin (5 V); schaltet sein IN-Eingang mit dem 3,3-V-Signal des ESP32 nicht zuverlässig, nimm ein 3,3-V-taugliches Relaismodul. Mehr dazu in Was ist ein Relaismodul?

Mit dem Raspberry Pi Pico und MicroPython

Raspberry Pi Pico
Der Raspberry Pi Pico arbeitet mit 3,3 V und lässt sich daher direkt an den RXD-Pin des HC-05 anschließen; ein Spannungsteiler ist nicht nötig.

Der normale Raspberry Pi Pico hat kein Bluetooth, also schließt du das HC-05 an die UART0-Pins (GP0 und GP1) an. Da die Pins des Pico mit 3,3 V arbeiten, brauchst du diesmal keinen Spannungsteiler; versorge das Modul über den VBUS-Pin, an dem die 5 V vom USB anliegen. Pico W und Pico 2 W haben zwar Bluetooth an Bord, MicroPython unterstützt dort aber nur BLE; um mit dem klassischen BluetoothClient von App Inventor zu sprechen, ist das HC-05 weiterhin der einfachste Weg. Der folgende Code versteht dieselben Befehle, steuert den Servo mit 50-Hz-PWM und sendet die Daten im gleichen Format; das Modul dht ist in der MicroPython-Firmware des Pico bereits enthalten.

MicroPython
1from machine import UART, Pin, PWM
2import dht
3import time
4
5bt = UART(0, baudrate=9600, tx=Pin(0), rx=Pin(1))   # GP0 → HC-05 RXD, GP1 ← HC-05 TXD
6led = PWM(Pin(15))
7led.freq(1000)
8role = Pin(14, Pin.OUT, value=1)                    # aktif LOW röle kapalı / active-LOW relay off
9servo = PWM(Pin(13))
10servo.freq(50)                                      # servo 50 Hz ister / servos need 50 Hz
11sensor = dht.DHT11(Pin(16))
12
13def komut_isle(k):
14    if not k:
15        return
16    tur, deger = k[0], int(k[1:] or 0)              # harf + sayı / letter + number
17    if tur == 'L':
18        led.duty_u16(65535 if deger == 1 else 0)
19    elif tur == 'P':
20        led.duty_u16(min(max(deger, 0), 255) * 257) # 0-255 → 0-65535
21    elif tur == 'R':
22        role.value(0 if deger == 1 else 1)
23    elif tur == 'S':
24        aci = min(max(deger, 0), 180)
25        servo.duty_ns(544000 + aci * 1856000 // 180)  # 544-2400 µs darbe / pulse
26
27tampon = b''
28son = time.ticks_ms()
29while True:
30    if bt.any():
31        tampon += bt.read()
32        while b'\n' in tampon:                      # tam satır geldi mi? / full line received?
33            satir, tampon = tampon.split(b'\n', 1)
34            try:
35                komut_isle(satir.decode().strip())
36            except ValueError:
37                pass                                # bozuk komutu atla / skip malformed command
38        if len(tampon) > 32:
39            tampon = b''                            # satır sonu hiç gelmedi / no newline arrived
40    if time.ticks_diff(time.ticks_ms(), son) >= 2000:
41        son = time.ticks_ms()
42        try:
43            sensor.measure()
44            bt.write('{:.1f};{}\n'.format(sensor.temperature(), sensor.humidity()))
45        except OSError:
46            pass                                    # sensör okunamadı / sensor read failed
47    time.sleep_ms(10)

Projektideen mit App Inventor und Arduino

  • Bluetooth-Auto: Lege die Richtungsbuttons auf die Buchstaben F, B, L und R und treibe die Motoren mit einem L298N an; alle Schritte stehen in Arduino-Roboterauto bauen.
  • Smart-Home-Panel: Steuere Lampe, Steckdose und Ventilator von einem Bildschirm aus mit einem vierkanaligen Relaismodul; Ideen liefert das Arduino-Smart-Home-Projekt.
  • Farbwähler-Lampe: Stelle Rot, Grün und Blau einer RGB-LED mit drei Slidern einzeln ein.
  • Roboterarm: Füge pro Gelenk einen Slider hinzu und steuere die Servomotoren vom Handy aus.
  • Gewächshaus-Monitor: Zeige Werte von DHT11 und Bodenfeuchtesensor auf dem Handy und ergänze einen Button, der die Pumpe startet, wenn die Erde trocken ist.
  • Sprachsteuerung: Baue mit der Komponente SpeechRecognizer von App Inventor eine App, die L1 sendet, wenn du „Licht an“ sagst.

Häufige Fehler und ihre Lösungen

  • Die App verbindet sich, aber die LED bleibt aus: TXD und RXD des HC-05 sind vertauscht, oder die SoftwareSerial-Pins im Code passen nicht zur Schaltung. TXD des Moduls muss an RX des Arduino (D10).
  • Befehle werden ignoriert: Im Textblock fehlt das \n; der Arduino wartet auf den Zeilenumbruch. Prüfe, ob die Befehle im seriellen Monitor ankommen.
  • Wirre Zeichen: Die Baudrate des HC-05 weicht von bt.begin() ab. Ab Werk hat das Modul 9600 Baud; wurde sie per AT-Befehl geändert, passe den Code an.
  • Der Servo zittert oder die Verbindung bricht ab: Der Servo zieht die 5-V-Schiene des Arduino herunter; versorge ihn aus einer eigenen 5-V-Quelle und verbinde die GNDs. Leichtes Zittern kann auch daher kommen, dass SoftwareSerial beim Empfangen kurz die Interrupts sperrt; dauerhaft hilft ein Arduino Mega oder ein ESP32 mit freien Hardware-Seriell-Ports. Gelegentlich springt der Servo auch kurz auf einen falschen Winkel: Die DHT-Bibliothek schaltet bei jeder Messung die Interrupts für etwa 5 ms ab, und ein Befehl, der genau dann eintrifft, kann verstümmelt werden; der nächste Befehl des Sliders korrigiert das.
  • Werte auf dem Handy hinken hinterher: Das Clock-Intervall ist länger als das Sendeintervall des Arduino, die Zeilen stauen sich. Halte TimerInterval kürzer als das Sendeintervall.
  • Die App friert ein: DelimiterByte steht noch auf 0, oder der Arduino beendet seine Zeilen nicht mit \n; ReceiveText(-1) wartet auf ein Trennzeichen, das nie kommt.
  • Auf dem iPhone geht nichts: Das HC-05 nutzt klassisches Bluetooth, das iOS nicht zulässt. Fürs iPhone brauchst du ein BLE-Modul (HM-10) oder einen ESP32.
Teile die Kette bei der Fehlersuche in zwei Hälften: Teste zuerst die Arduino-Seite mit Serial Bluetooth Terminal, dann die App-Inventor-App. Funktioniert das Terminal, die App aber nicht, liegt das Problem in den Blöcken; versagt auch das Terminal, prüfe Verdrahtung oder Arduino-Code. Pinnummern kontrollierst du am besten mit dem Pinbelegungs-Tool.

App Inventor und Arduino zu kombinieren ist die unterhaltsamste Art, App-Entwicklung und Elektronik in einem Projekt zu lernen. Hast du Verbindung und Protokoll einmal aufgebaut, wird aus demselben Grundgerüst eine Fernsteuerung für Auto, Smart Home oder Gewächshaus; es ändern sich nur die Buchstaben, die die Buttons senden. In der BlueGrays-App findest du die Projekte LED per Bluetooth vom Handy schalten und Bluetooth-Auto mit L298N Schritt für Schritt mit Schaltplänen und Code.

Häufige Fragen

Funktioniert eine App-Inventor-Bluetooth-App auf dem iPhone?

Mit HC-05 und HC-06 nicht. Diese Module nutzen klassisches Bluetooth (SPP), und iOS erlaubt normalen Apps keine solche serielle Verbindung. Für das iPhone musst du auf ein BLE-Modul wie das HM-10 oder auf einen ESP32 umsteigen; für HC-05-Projekte ist ein Android-Handy die problemloseste Wahl.

Warum ist die Bluetooth-Liste in App Inventor leer?

AddressesAndNames listet nur Geräte, die bereits mit dem Handy gekoppelt sind; kopple das HC-05 also zuerst in den Bluetooth-Einstellungen mit der PIN 1234. Ab Android 12 öffnet sich die Liste beim ersten Mal auch leer, wenn die Berechtigung „Geräte in der Nähe“ fehlt; erteile sie und tippe erneut auf Verbinden. Achte außerdem darauf, dass Bluetooth eingeschaltet ist.

Wie behebe ich den App-Inventor-Fehler 507?

Fehler 507 bedeutet „Unable to connect. Is the device turned on?“: Das Handy konnte keine Verbindung zum Modul aufbauen. Prüfe, ob das HC-05 Strom hat, seine LED schnell blinkt und es nicht mit einem anderen Handy verbunden ist. Hilft das nicht, entferne die Kopplung und kopple neu oder schalte beim BluetoothClient die Eigenschaft Secure aus.

Wie erstelle ich in App Inventor eine APK?

Öffne das Projekt und klicke im oberen Menü auf Build > Android App (.apk). Nach dem Kompilieren scannst du den QR-Code mit dem Handy oder lädst die APK auf den Computer und kopierst sie aufs Handy. Bei der Installation musst du das Installieren unbekannter Apps erlauben.

Kann sich App Inventor per Bluetooth mit einem ESP32 verbinden?

Ja. Mit der Bibliothek BluetoothSerial verhält sich der klassische ESP32 wie ein SPP-Gerät, und der BluetoothClient von App Inventor verbindet sich mit ihm wie mit einem HC-05. ESP32-S3 und ESP32-C3 unterstützen nur BLE, dort brauchst du die BluetoothLE-Erweiterung.

Kann ich meine App-Inventor-App bei Google Play veröffentlichen?

Ja. Die Option Android App Bundle (.aab) im Build-Menü erzeugt eine Datei, die du bei Google Play hochladen kannst; dafür brauchst du ein Google-Play-Entwicklerkonto. Updates müssen mit demselben Schlüssel signiert sein, sichere deinen Keystore daher mit Projects > Export keystore.

Alle Projekte ansehen
LED Blinken
#1Anfänger

LED Blinken

Das allererste Hallo der Elektronik: eine einzelne LED an- und ausschalten. Der Arduino schaltet die LED in kurzen Abständen ein und aus, das Licht blinkt also schnell. So siehst du ganz einfach, wie

4.6(179)
977
Temperatur und Luftfeuchtigkeit mit DHT11
#55Mittel

Temperatur und Luftfeuchtigkeit mit DHT11

Wie warm ist dein Zimmer, und ist die Luft feucht oder trocken? Der DHT11-Sensor misst Temperatur und Luftfeuchtigkeit, und der Arduino schreibt die Werte auf ein zweizeiliges LCD und aktualisiert sie

4.7(47)
64
LED per Bluetooth mit dem Handy steuern
#34Anfänger
Premium

LED per Bluetooth mit dem Handy steuern

Eine kleine Probe dafür, das Licht in deinem Zimmer vom Handy aus ein- und auszuschalten. Das Bluetooth-Modul leitet die Buchstaben, die du vom Handy schickst, an den Arduino weiter; ein Buchstabe sch

4.8(68)
88
Bluetooth-gesteuertes Auto mit L298N
#80Fortgeschritten
Premium

Bluetooth-gesteuertes Auto mit L298N

Mach dein Handy zur Fernbedienung und steuere dein eigenes Roboterauto. Der Arduino empfängt über ein Bluetooth-Modul die Befehle einer Fernsteuer-App auf dem Handy und treibt die Räder über einen Mot

5.0(38)
65
Verwendung von Servomotoren
#35Anfänger
Premium

Verwendung von Servomotoren

Der Arm eines kleinen Servomotors dreht sich nacheinander in drei Stellungen: ganz an den Anfang, genau in die Mitte und ganz ans Ende, mit jeweils zwei Sekunden Pause. Der Arduino sagt dem Motor, bei

4.7(48)
67
RGB-LED verwenden
#39Anfänger
Premium

RGB-LED verwenden

In einer einzigen LED stecken drei Farben: Die RGB-LED leuchtet erst rot, dann grün, dann blau, jede Farbe eine halbe Sekunde an und eine halbe Sekunde aus, und dann geht es von vorne los. Du brauchst

4.9(73)
98
220V Glühbirne mit Druckknopf (Push)
#19Fortgeschritten
Premium

220V Glühbirne mit Druckknopf (Push)

Solange du den Knopf gedrückt hältst, leuchtet eine echte 220-Volt-Glühbirne, und sobald du loslässt, geht sie aus. Das schwache Signal des Arduino kann die Birne nicht direkt einschalten, deshalb sit

4.4(30)
38
Einweg-Kommunikation zwischen 2 Arduinos
#57Mittel
Premium

Einweg-Kommunikation zwischen 2 Arduinos

Du bringst zwei Arduinos über ein einziges Kabel zum Reden: Drückst du den Knopf am einen, geht die LED am anderen an, drückst du noch einmal, geht sie aus. Die sendende Platine meldet den Knopfdruck

4.4(37)
50