Guide · 18 min di lettura

App Inventor Arduino Bluetooth: crea la tua app Android con HC-05

Controlla Arduino via Bluetooth con App Inventor: collegamento HC-05, ListPicker, blocchi per pulsanti e cursori, LED, relè, servo, sensori, APK e Android 12.

Controllare Arduino via Bluetooth con App Inventor è il modo più rapido per creare la tua app Android senza scrivere una sola riga di Java o Kotlin. In MIT App Inventor, lo strumento gratuito del MIT che funziona nel browser, trascini sullo schermo pulsanti, cursori ed etichette di testo e stabilisci cosa fanno con blocchi che si incastrano come tessere di un puzzle. Il telefono si collega a un modulo Bluetooth HC-05 cablato ad Arduino; ogni tocco nell'app arriva ad Arduino come un breve comando di testo, e Arduino rimanda al telefono le letture dei sensori per la stessa strada.

Alla fine di questa guida avrai un'app di controllo remoto che funziona davvero: un ListPicker che si collega all'HC-05 da un elenco, pulsanti che accendono e spengono un LED e un relè, due cursori (Slider) per la luminosità del LED e l'angolo del servo, ed etichette che mostrano in tempo reale temperatura e umidità di un DHT11. Vedrai passo dopo passo il codice Arduino, ogni blocco di App Inventor, la creazione dell'APK e la soluzione al problema dei permessi Bluetooth arrivato con Android 12. Se non hai mai usato l'HC-05, dai prima un'occhiata alla guida al modulo Bluetooth HC-05.

Modulo Bluetooth HC-05
L'HC-05 è un modulo Bluetooth classico (SPP), proprio il tipo con cui dialoga il componente BluetoothClient di App Inventor; crea un collegamento seriale senza fili tra telefono e Arduino.

Che cos'è App Inventor e come comunica con Arduino?

MIT App Inventor è un ambiente gratuito per lo sviluppo di app creato dal Massachusetts Institute of Technology (MIT); accedi con il tuo account Google e lavori direttamente nel browser. Ha due viste: nel Designer prepari l'aspetto dell'app trascinando i componenti, mentre nell'editor Blocks scrivi con blocchi colorati regole come «quando si preme il pulsante, fai questo». Per provare l'app senza installarla si usa l'app MIT AI2 Companion del Play Store; a lavoro finito, un clic genera un file APK installabile.

Per il Bluetooth il lavoro lo fa il componente BluetoothClient. Usa il profilo SPP (Serial Port Profile, profilo di porta seriale) del Bluetooth classico, che è proprio quello dell'HC-05. Il risultato è un cavo seriale invisibile tra telefono e Arduino: quando l'app invia «L1» con il blocco SendText, Arduino legge quei due caratteri con bt.read(), come se li avessi scritti nel Monitor seriale. Tutto ciò che Arduino invia con bt.print() arriva al blocco ReceiveText del telefono. Su Arduino non serve alcuna libreria Bluetooth specifica.

LivelloCompitoIn questo progetto
Interfaccia (Designer)Componenti visibili sullo schermoListPicker, 5 Button, 2 Slider, Label
Logica (Blocks)Blocchi che reagiscono agli eventiEventi Click, PositionChanged e Timer
BluetoothClientConnessione SPP, invio e ricezione dei datiConnect, SendText, ReceiveText
HC-05Ponte tra Bluetooth e UART9600 baud, PIN 1234
ArduinoInterpreta i comandi, pilota le uscite, legge il sensoreLED, relè, servo, DHT11

Materiale necessario

MaterialeQuantitàNota
Arduino Uno (o Nano)1Codice e pin sono uguali su entrambi
Modulo Bluetooth HC-05 o HC-061Bluetooth classico; l'HM-10 (BLE) non funziona in questo modo
Resistenze da 1 kΩ e 2 kΩ1 ciascunaPartitore di tensione per il pin RXD dell'HC-05 (va bene anche 2,2 kΩ)
LED e resistenza da 220 Ω1 ciascunoLED con luminosità regolabile (D5, PWM)
Modulo relè da 5 V1Per accendere carichi come una lampada o un ventilatore
Servomotore SG901Controllo da 0 a 180° con un cursore
Sensore di temperatura e umidità DHT111Dati da mostrare sul telefono
Telefono Android1L'HC-05 non funziona con l'iPhone
Breadboard e cavetti jumper—Una GND comune è indispensabile
Arduino Uno
Arduino Uno
HC-06
HC-06
SG90
SG90
DHT11
DHT11
LED
LED

Circuito: collegamento di HC-05, LED, relè, servo e DHT11

La scheda dell'HC-05 ha un regolatore, quindi il pin VCC accetta 5 V, ma i pin dati lavorano con logica a 3,3 V. Arduino legge senza problemi il segnale a 3,3 V del pin TXD del modulo; il segnale TX a 5 V di Arduino, invece, deve arrivare al pin RXD attraverso un partitore di tensione: D11 → 1 kΩ → RXD, RXD → 2 kΩ → GND. Così su RXD arrivano 5 × 2 / 3 ≈ 3,3 V. Colleghiamo l'HC-05 a D10 e D11 con SoftwareSerial invece che ai pin seriali hardware dell'Uno (0 e 1): in questo modo puoi caricare il codice con il modulo collegato e continuare a usare il Monitor seriale per il debug. Puoi verificare la resistenza del LED con il calcolatore di resistenza per LED.

CollegamentoArduino UnoESP32Raspberry Pi Pico
HC-05 VCC5VNon serve (Bluetooth integrato)VBUS (5 V)
HC-05 GNDGND—GND
HC-05 TXDD10 (RX di SoftwareSerial)—GP1 (UART0 RX)
HC-05 RXDD11, tramite partitore 1 kΩ / 2 kΩ—GP0 (UART0 TX), senza partitore
LED (+ 220 Ω)D5 (PWM)GPIO 2 (LED sulla scheda)GP15
IN del modulo relèD7GPIO 26GP14
Segnale del servo (arancione)D9— (si può aggiungere con ESP32Servo)GP13
Dati del DHT11D2GPIO 4GP16
Rispetta tre regole: tutte le GND (Arduino, HC-05, relè, servo ed eventuale alimentazione esterna) devono essere collegate tra loro. Non dare mai 5 V senza partitore al pin RXD dell'HC-05; il modulo può resistere per un po', ma col tempo rischia di guastarsi. Un servo in movimento può assorbire per un istante diverse centinaia di milliampere; se Arduino è alimentato via USB, quel picco fa calare la tensione, l'HC-05 perde la connessione oppure Arduino si riavvia. Alimentare servo e relè con una sorgente a 5 V separata risolve il problema alla radice.

Protocollo di comunicazione: cosa invierà il telefono?

Prima di scrivere il codice bisogna decidere quale «lingua» parleranno telefono e Arduino. In questo progetto ogni comando è formato da una lettera, seguita da un numero e infine da un carattere di a capo (\n, ASCII 10). L'a capo è fondamentale: i dati Bluetooth possono arrivare a pezzi, e se «S1» e «35» arrivano separati, Arduino aspetta l'a capo ed elabora «S135» come un unico comando. Visto che i comandi sono testo leggibile, puoi provarli anche a mano con qualsiasi app terminale Bluetooth.

ComandoDirezioneSignificato
L1 / L0Telefono → ArduinoAccendere il LED al massimo / spegnerlo
P0 … P255Telefono → ArduinoLuminosità del LED (valore di analogWrite)
R1 / R0Telefono → ArduinoEccitare / rilasciare il relè
S0 … S180Telefono → ArduinoAngolo del servo (gradi)
24.5;41Arduino → telefonoTemperatura (°C) e umidità (%), separate da un punto e virgola

Invece del testo, App Inventor può anche inviare un singolo byte (0–255) con il blocco Send1ByteNumber, che Arduino legge direttamente come numero. È un metodo breve e veloce, ma adatto a un solo cursore: se due cursori e quattro pulsanti inviano byte, Arduino non può capire se un 90 in arrivo sia un angolo del servo o una luminosità. Il formato lettera + numero + a capo occupa qualche byte in più, ma a 9600 baud passano circa 960 caratteri al secondo, quindi non noterai alcuna differenza.

Il codice per Arduino

Le librerie Servo e SoftwareSerial sono incluse nell'IDE di Arduino. Per il DHT11 installa DHT sensor library (Adafruit) dal Gestore librerie; quando ti chiede delle dipendenze, scegli Install all per aggiungere anche Adafruit Unified Sensor. Poiché non usiamo i pin 0 e 1, non serve scollegare l'HC-05 durante il caricamento.

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}
  • Buffer di riga: loop() aggiunge ogni carattere ricevuto alla variabile komut (comando); quando arriva \n passa la riga a komutIsle() e svuota il buffer. Oltre i 16 caratteri il resto viene scartato, così i dati spazzatura non riempiono la memoria.
  • trim(): Alcune app terminale aggiungono anche \r a fine riga; trim() lo elimina insieme agli spazi, quindi «L1\r» viene comunque riconosciuto come «L1».
  • Lettera e numero: charAt(0) restituisce la lettera del comando e substring(1).toInt() il numero che la segue. constrain() limita il valore a un intervallo sicuro: anche se il telefono inviasse per errore 300, il servo non verrebbe mai spinto oltre 180°.
  • Invio non bloccante: Il sensore viene letto ogni 2 secondi con millis(). Dato che non c'è delay(), i comandi che arrivano nel frattempo vengono gestiti senza ritardo; dettagli in millis() o delay().
  • print('\n') invece di println: println() chiude la riga con \r\n. App Inventor usa solo \n come delimitatore, quindi il \r resterebbe attaccato alla fine del valore di umidità; inviare solo \n mantiene pulita la suddivisione sul telefono.
  • Relè attivo basso: La maggior parte dei moduli relè si attiva quando IN va a LOW. Se il tuo si attiva con HIGH, basta scambiare i valori delle costanti ROLE_ACIK (acceso) e ROLE_KAPALI (spento).
Prima di passare ad App Inventor, prova da sola la parte Arduino: collegati all'HC-05 con un'app come Serial Bluetooth Terminal del Play Store, scrivi «L1» e invialo; il LED dovrebbe accendersi e L1 comparire nel Monitor seriale. Se ogni 2 secondi scorrono righe come «24.5;41», funziona anche il ritorno dei dati. Così, se più avanti qualcosa non va, capirai subito se il problema è nell'app o nel circuito.

Progettare l'interfaccia in App Inventor (Designer)

  1. Apri ai2.appinventor.mit.edu nel browser, accedi con il tuo account Google e crea un progetto chiamato BlueGraysRemote con Projects > Start new project.
  2. Dal gruppo Layout della Palette trascina un HorizontalArrangement e mettici dentro un ListPicker (Text: Connetti), un Button (Text: Disconnetti) e un Label (Text: Non connesso).
  3. Aggiungi sotto altri due HorizontalArrangement: nel primo i pulsanti Accendi LED e Spegni LED, nel secondo Accendi relè e Spegni relè. Impostando Width su Fill parent, i pulsanti si premono più facilmente.
  4. Aggiungi due Slider: per la luminosità MinValue 0, MaxValue 255, ThumbPosition 0; per il servo MinValue 0, MaxValue 180, ThumbPosition 90. Sopra ciascuno metti un Label che ne spieghi la funzione.
  5. Aggiungi altri due Label per temperatura e umidità e porta il loro FontSize a circa 20.
  6. Dal gruppo Connectivity aggiungi un BluetoothClient; nel pannello Properties imposta DelimiterByte a 10 e spunta NoLocationNeeded.
  7. Dal gruppo Sensors aggiungi un Clock; imposta TimerInterval a 200 e togli la spunta a TimerEnabled. Attiveremo il timer con i blocchi una volta stabilita la connessione.
ComponenteNome (Rename)Impostazione importante
ListPickerLP_ConnectText: Connetti
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 (per i valori)
BluetoothClientBluetoothClient1DelimiterByte 10, NoLocationNeeded spuntato
ClockClock1TimerInterval 200, TimerEnabled disattivato

Collegarsi all'HC-05 con un ListPicker

Per prima cosa associa l'HC-05 dalle impostazioni Bluetooth del telefono (il PIN di solito è 1234, altrimenti 0000). Questo passaggio è indispensabile: BluetoothClient1.AddressesAndNames elenca solo i dispositivi associati e non cerca quelli nuovi nelle vicinanze. Ogni elemento è un testo con prima l'indirizzo MAC e poi il nome del dispositivo, come «98:D3:31:F5:2A:10 HC-05». Puoi passare l'intero testo al blocco Connect; App Inventor scarta da solo tutto ciò che segue il primo spazio. Il blocco restituisce true se la connessione riesce e false se fallisce.

  1. Nell'evento when LP_Connect.BeforePicking inserisci set LP_Connect.Elements to BluetoothClient1.AddressesAndNames. L'elenco si riempie di nuovo con i dispositivi associati ogni volta che si apre.
  2. Nell'evento when LP_Connect.AfterPicking aggiungi un blocco if e collega alla sua condizione call BluetoothClient1.Connect address: LP_Connect.Selection.
  3. Nella parte then dell'if imposta LBL_Status.Text su «Connesso» e avvia la lettura dei dati con set Clock1.TimerEnabled to true; nella parte else scrivi «Connessione fallita».
  4. Nell'evento when BTN_Disconnect.Click esegui prima set Clock1.TimerEnabled to false, poi call BluetoothClient1.Disconnect e infine imposta LBL_Status.Text su «Non connesso». Fermare prima il timer evita una lettura e un messaggio di errore dopo la chiusura della connessione.
Quando la connessione è stabilita, il LED dell'HC-05 smette di lampeggiare velocemente e fa invece due brevi lampi ogni 2 secondi. Così capisci lo stato della connessione senza guardare l'app; se il LED torna a lampeggiare veloce, la connessione è caduta.

Inviare dati: pulsanti e cursori

Per inviare basta un solo blocco: call BluetoothClient1.SendText text. Quando scrivi «L1\n» in un blocco di testo, App Inventor trasforma il \n finale in un carattere di a capo. Inviare senza connessione causa l'errore 515, perciò è buona abitudine racchiudere ogni invio in un controllo if BluetoothClient1.IsConnected. Per un cursore unisci il numero alla lettera e all'a capo con un blocco join: join("S", round(thumbPosition), "\n").

Evento (event)Testo inviatoRisultato su Arduino
BTN_LedOn.ClickL1\nIl LED si accende al massimo
BTN_LedOff.ClickL0\nIl LED si spegne
BTN_RelayOn.ClickR1\nIl relè scatta e la lampada collegata si accende
BTN_RelayOff.ClickR0\nIl relè si rilascia
SLD_Brightness.PositionChangedjoin("P", round(thumbPosition), "\n")analogWrite(5, valore)
SLD_Servo.PositionChangedjoin("S", round(thumbPosition), "\n")servo.write(angolo)

Mentre trascini un cursore con il dito, l'evento PositionChanged scatta decine di volte al secondo e thumbPosition restituisce valori decimali come 87,4. Se invii a ogni evento, lo stesso angolo parte più e più volte, il buffer dell'HC-05 si riempie e il servo si muove a scatti e in ritardo. La soluzione è semplice: crea una variabile global lastAngle; invia solo se il valore arrotondato con round(thumbPosition) è diverso da essa, poi aggiorna la variabile. In questo modo i dati partono solo quando l'angolo cambia davvero. Applica lo stesso trucco al cursore della luminosità con global lastBrightness.

Ricevere dati: mostrare i valori del sensore sul telefono

Arduino invia una riga «24.5;41» ogni 2 secondi. In App Inventor non esiste un evento che scatti da solo all'arrivo dei dati, quindi usiamo il componente Clock per controllare a intervalli regolari se ci sono dati nuovi. Avendo impostato DelimiterByte a 10 nel Designer, se passi -1 come numberOfBytes al blocco ReceiveText, questo legge fino al carattere di a capo e restituisce la riga senza \n. Un timer da 200 ms controlla molto più spesso di quanto arrivino i dati (ogni 2000 ms), quindi nel buffer non si accumula nulla.

  1. Inserisci una condizione if BluetoothClient1.IsConnected dentro when Clock1.Timer.
  2. Aggiungi al suo interno una seconda condizione: call BluetoothClient1.BytesAvailableToReceive > 0.
  3. Salva la riga ricevuta in una variabile locale con initialize local line to call BluetoothClient1.ReceiveText numberOfBytes: -1.
  4. Trasforma la riga in una lista con il blocco split text line at ";": «24.5;41» diventa la lista di due elementi [24.5, 41]. Conserva il risultato in una variabile locale chiamata parts.
  5. if length of list parts = 2, imposta LBL_Temp.Text su join("Temperatura: ", select list item parts index 1, " °C") e LBL_Hum.Text su join("Umidità: ", select list item parts index 2, " %"). Il controllo sul numero di elementi evita errori dovuti a righe ricevute a metà o danneggiate.
Se passi -1 a ReceiveText ma dimentichi di impostare DelimiterByte a 10 (il valore predefinito è 0), il blocco aspetta un byte 0 che non arriva mai e l'app sembra bloccata. E se Arduino invia la riga con println(), il carattere \r finisce alla fine del secondo valore; per questo il codice invia solo '\n'.
Non fermarti a mostrare i valori come testo: puoi colorare di rosso LBL_Temp.TextColor quando la temperatura supera i 30 °C, aprire un avviso con il componente Notifier oppure disegnare su un Canvas un grafico a linee delle ultime letture.

Il problema dei permessi Bluetooth da Android 12 in poi

Con Android 12 (API 31) i permessi Bluetooth sono cambiati. Il vecchio permesso BLUETOOTH, concesso automaticamente all'installazione, è stato sostituito da BLUETOOTH_CONNECT e BLUETOOTH_SCAN, che l'utente deve approvare mentre l'app è in esecuzione; nelle impostazioni del telefono compaiono come permesso Dispositivi nelle vicinanze. Se non è stato concesso, App Inventor apre la finestra del permesso al primo tentativo, ma interrompe il blocco in esecuzione. Il risultato sono sintomi ben noti: l'elenco si apre vuoto al primo tocco su Connetti, compare il messaggio «Error 908: The permission ... has been denied» (con BLUETOOTH_CONNECT o BLUETOOTH_SCAN come nome) oppure, se l'utente ha rifiutato una volta, l'app non lo chiede mai più.

  1. Nell'evento when Screen1.Initialize controlla la versione di Android: se select list item (split Screen1.PlatformVersion at ".") index 1 ≥ 12, passa a call Screen1.AskForPermission il valore BluetoothConnect dall'elenco Permission. Su Android 11 e precedenti questi permessi non esistono e chiederli provoca anch'esso l'errore 908, quindi il controllo della versione è importante.
  2. Nell'evento when Screen1.PermissionGranted, se il permesso concesso è BLUETOOTH_CONNECT (contains text: permissionName, piece: "CONNECT"), chiedi subito dopo BluetoothScan. AskForPermission accetta un solo permesso alla volta, quindi bisogna concatenarli così.
  3. Nell'evento when Screen1.PermissionDenied mostra con un Notifier un messaggio con il percorso «Impostazioni > App > BlueGraysRemote > Autorizzazioni > Dispositivi nelle vicinanze > Consenti». Gestire questo evento mostra all'utente una spiegazione chiara invece di una finestra di errore in inglese.
  4. Lascia spuntato NoLocationNeeded sul BluetoothClient nel Designer; questa impostazione comunica ad Android che l'app non usa il Bluetooth per determinare la posizione.
  5. Prova sempre anche con l'APK: i permessi dell'AI2 Companion appartengono all'app Companion, mentre il tuo APK chiede i propri permessi dopo l'installazione.
ErroreSignificatoSoluzione
Error 507: Unable to connect. Is the device turned on?Impossibile collegarsi al moduloControlla l'alimentazione dell'HC-05, l'associazione e che non sia collegato a un altro telefono; se non va ancora, togli la spunta a Secure nel BluetoothClient e riprova
Error 515: Not connected to a Bluetooth device.Invio o lettura senza connessioneRacchiudi i blocchi di invio e del Clock in un controllo IsConnected
Error 516: Unable to write: Broken pipeLa connessione è caduta a metà (alimentazione persa, fuori portata)Ferma il Clock, chiama Disconnect e ricollegati; alimenta a parte servo e relè
Error 908: The permission … has been deniedManca il permesso Dispositivi nelle vicinanze su Android 12+Chiedilo con i blocchi o concedilo a mano nelle Impostazioni
L'elenco si apre vuotoModulo non associato o permesso appena richiestoAssocia l'HC-05 dalle impostazioni del telefono e, dopo aver concesso il permesso, tocca di nuovo Connetti

Provare l'app e creare l'APK

Durante lo sviluppo non serve installare un APK dopo ogni modifica. Installa l'app MIT AI2 Companion dal Play Store; con computer e telefono sulla stessa rete Wi-Fi, scegli Connect > AI Companion in App Inventor e inquadra il QR code o inserisci il codice di 6 caratteri che compare sullo schermo. Ogni modifica fatta nel Designer o nei blocchi appare subito sul telefono. Quando l'app è pronta, crea il file installabile così:

  1. Seleziona Screen1 nel Designer e compila AppName (il nome mostrato sul telefono), Icon (un PNG quadrato), VersionCode e VersionName.
  2. Dal menu in alto scegli Build > Android App (.apk). La compilazione di solito richiede uno o due minuti.
  3. Al termine si apre una finestra con un QR code e un pulsante di download. Puoi inquadrare il QR code con il telefono per scaricare direttamente il file, oppure salvare l'APK sul computer e copiarlo sul telefono via cavo. Il link del QR code vale solo per poco tempo (circa 2 ore).
  4. Quando apri l'APK sul telefono, Android ti chiede di consentire al browser o al file manager di installare app sconosciute. Se Play Protect mostra un avviso, puoi proseguire con l'opzione per installare comunque nei dettagli; questo avviso è frequente con le app esterne al Play Store con una firma sconosciuta.
  5. Al primo avvio dell'app consenti il permesso Dispositivi nelle vicinanze, tocca Connetti e scegli l'HC-05 dall'elenco.
Fai un backup del progetto con Projects > Export selected project (.aia) to my computer; puoi condividere il file .aia con un amico o trasferirlo su un altro account. Se vuoi pubblicare l'app su Google Play, usa Build > Android App Bundle (.aab) e conserva assolutamente la tua chiave di firma con Projects > Export keystore: gli aggiornamenti vanno firmati con la stessa chiave. Ricorda anche di aumentare VersionCode di 1 a ogni aggiornamento.

La stessa app con un ESP32, senza HC-05

Scheda di sviluppo ESP32
L'ESP32 classico ha il Bluetooth Classic integrato; il BluetoothClient di App Inventor vi si collega proprio come a un HC-05.

L'ESP32 classico integra sia il Bluetooth classico sia il BLE. La libreria BluetoothSerial presenta l'ESP32 al telefono come dispositivo SPP, quindi puoi usare l'app appena creata senza cambiare nulla. Associa nelle impostazioni Bluetooth del telefono il dispositivo «BlueGrays-ESP32», sceglilo dall'elenco nell'app ed è fatta. Attenzione: ESP32-S3, ESP32-C3 ed ESP32-C6 supportano solo il BLE; non hanno BluetoothSerial e in App Inventor serve l'estensione BluetoothLE. Per lavorare con il BLE consulta la guida ESP32 Bluetooth e 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}

Il codice capisce gli stessi comandi della versione per Uno e invia i dati nello stesso formato «temperatura;umidità»; ignora i comandi S perché non c'è alcun servo collegato. La libreria Servo di Arduino non funziona sull'ESP32; per aggiungere un servo installa la libreria ESP32Servo e usa le stesse chiamate attach() e write(), per esempio sul GPIO 13. Alimenta il modulo relè dal pin VIN (5 V); se il suo ingresso IN non commuta in modo affidabile con il segnale a 3,3 V dell'ESP32, scegli un modulo relè compatibile con 3,3 V. Maggiori dettagli in Che cos'è un modulo relè?

Con il Raspberry Pi Pico e MicroPython

Raspberry Pi Pico
Il Raspberry Pi Pico lavora a 3,3 V, quindi si collega direttamente al pin RXD dell'HC-05 senza partitore di tensione.

Il Raspberry Pi Pico standard non ha il Bluetooth, quindi colleghi l'HC-05 ai pin UART0 (GP0 e GP1). Poiché i pin del Pico lavorano a 3,3 V, stavolta il partitore non serve; alimenta il modulo dal pin VBUS, che porta i 5 V dell'USB. Pico W e Pico 2 W hanno il Bluetooth integrato, ma MicroPython su queste schede supporta solo il BLE; per dialogare con il BluetoothClient classico di App Inventor, l'HC-05 resta la strada più semplice. Il codice seguente capisce gli stessi comandi, muove il servo con un PWM a 50 Hz e invia i dati nello stesso formato; il modulo dht è già incluso nel firmware MicroPython del Pico.

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)

Idee di progetti con App Inventor e Arduino

  • Macchinina controllata via Bluetooth: Associa i pulsanti di direzione alle lettere F, B, L e R e muovi i motori con un L298N; tutti i passaggi sono nella guida costruire una macchinina robot con Arduino.
  • Pannello per la casa intelligente: Controlla lampada, presa e ventilatore da un'unica schermata con un modulo relè a quattro canali; per qualche idea guarda il progetto di casa intelligente con Arduino.
  • Lampada con selettore di colore: Regola separatamente rosso, verde e blu di un LED RGB con tre cursori.
  • Braccio robotico: Aggiungi un cursore per ogni giunto e muovi i servomotori dal telefono.
  • Monitoraggio della serra: Mostra sul telefono i dati del DHT11 e del sensore di umidità del terreno e aggiungi un pulsante che avvia la pompa quando il terreno è secco.
  • Comando vocale: Con il componente SpeechRecognizer di App Inventor crea un'app che invia L1 quando dici «accendi la luce».

Errori comuni e soluzioni

  • L'app si collega ma il LED non si accende: I cavi TXD e RXD dell'HC-05 sono invertiti, oppure i pin di SoftwareSerial nel codice non corrispondono al circuito. Il TXD del modulo deve andare all'RX di Arduino (D10).
  • I comandi non vengono eseguiti: Nel blocco di testo manca il \n; Arduino aspetta l'a capo. Controlla se i comandi in arrivo compaiono nel Monitor seriale.
  • Caratteri senza senso: La velocità dell'HC-05 è diversa da quella di bt.begin(). Il modulo esce di fabbrica a 9600 baud; se è stata cambiata con i comandi AT, adatta il codice.
  • Il servo trema o la connessione cade: Il servo fa crollare la linea a 5 V di Arduino; alimentalo con una sorgente a 5 V separata e collega insieme le GND. Un leggero tremolio può dipendere anche da SoftwareSerial, che blocca per un attimo gli interrupt mentre riceve; come soluzione definitiva usa un Arduino Mega o un ESP32, che hanno porte seriali hardware libere. Ogni tanto il servo può anche scattare per un attimo a un angolo sbagliato: la libreria DHT disattiva gli interrupt per circa 5 ms a ogni lettura e un comando che arriva proprio in quel momento può corrompersi; il comando successivo del cursore rimette tutto a posto.
  • I valori sul telefono arrivano in ritardo: L'intervallo del Clock è più lungo di quello di invio di Arduino e le righe si accumulano. Tieni TimerInterval più breve dell'intervallo di invio.
  • L'app si blocca: DelimiterByte è rimasto a 0, oppure Arduino non chiude le righe con \n; ReceiveText(-1) aspetta un delimitatore che non arriva mai.
  • Su iPhone non funziona: L'HC-05 usa il Bluetooth classico, che iOS non consente. Per l'iPhone serve un modulo BLE (HM-10) o un ESP32.
Quando cerchi un guasto, dividi la catena in due: prova prima la parte Arduino con Serial Bluetooth Terminal, poi l'app di App Inventor. Se il terminale funziona ma l'app no, il problema è nei blocchi; se non funziona neanche il terminale, controlla i collegamenti o il codice Arduino. Per verificare i numeri dei pin usa lo strumento pinout.

Unire App Inventor e Arduino è il modo più divertente per imparare insieme sviluppo di app ed elettronica. Una volta impostati connessione e protocollo, lo stesso schema diventa il telecomando di una macchinina, di una casa intelligente o di una serra; cambiano solo le lettere inviate dai pulsanti. Nell'app BlueGrays trovi passo dopo passo, con schemi e codice, i progetti per accendere un LED dal telefono via Bluetooth e per la macchinina Bluetooth con L298N.

Domande frequenti

Un'app App Inventor con Bluetooth funziona su iPhone?

Con un HC-05 o un HC-06 no. Questi moduli usano il Bluetooth classico (SPP) e iOS non permette alle app comuni di aprire questo tipo di connessione seriale. Per comunicare con un iPhone devi passare a un modulo BLE come l'HM-10 o a un ESP32; per i progetti con HC-05 un telefono Android è la scelta più semplice.

Perché la lista Bluetooth è vuota in App Inventor?

AddressesAndNames elenca solo i dispositivi già associati al telefono, quindi associa prima l'HC-05 dalle impostazioni Bluetooth con il PIN 1234. Da Android 12 in poi la lista si apre vuota anche la prima volta se il permesso Dispositivi nelle vicinanze non è stato concesso; concedilo e tocca di nuovo Connetti. Assicurati anche che il Bluetooth sia attivo.

Come risolvere l'errore 507 di App Inventor?

L'errore 507 significa «Unable to connect. Is the device turned on?»: il telefono non è riuscito ad aprire la connessione con il modulo. Controlla che l'HC-05 sia alimentato, che il suo LED lampeggi velocemente e che non sia collegato a un altro telefono. Se il problema persiste, elimina l'associazione e ripetila, oppure prova a disattivare la proprietà Secure del BluetoothClient.

Come si crea l'APK con App Inventor?

Apri il progetto e fai clic su Build > Android App (.apk) nel menu in alto. Al termine della compilazione inquadra il QR code con il telefono oppure scarica l'APK sul computer e copialo sul telefono. Durante l'installazione dovrai consentire l'installazione di app sconosciute.

App Inventor può collegarsi a un ESP32 via Bluetooth?

Sì. Con la libreria BluetoothSerial l'ESP32 classico si comporta come un dispositivo SPP e il BluetoothClient di App Inventor vi si collega come a un HC-05. ESP32-S3 ed ESP32-C3 supportano solo il BLE, quindi su queste schede serve l'estensione BluetoothLE.

Posso pubblicare la mia app App Inventor su Google Play?

Sì. L'opzione Android App Bundle (.aab) del menu Build genera un file da caricare su Google Play; per farlo serve un account sviluppatore Google Play. Gli aggiornamenti devono essere firmati con la stessa chiave, quindi salva il tuo keystore con Projects > Export keystore.

Vedi tutti i progetti
LED lampeggiante
#1Principiante

LED lampeggiante

Il primissimo ciao dell'elettronica: accendere e spegnere un solo LED. L'Arduino accende e spegne il LED a intervalli brevissimi, così la luce lampeggia veloce. Vedi nel modo più semplice come la sche

4.6(179)
978
Temperatura e umidità con DHT11
#55Intermedio

Temperatura e umidità con DHT11

Quanti gradi ci sono nella tua stanza, e l'aria è umida o secca? Il sensore DHT11 misura temperatura e umidità, e l'Arduino scrive i valori su uno schermo LCD a due righe, aggiornandoli ogni paio di s

4.7(47)
64
Controllare un LED dal telefono tramite Bluetooth
#34Principiante
Premium

Controllare un LED dal telefono tramite Bluetooth

Una piccola prova per accendere e spegnere le luci della tua stanza dal telefono. Il modulo Bluetooth passa all'Arduino le lettere che invii dal telefono; una lettera accende il LED rosso, un'altra qu

4.8(68)
88
Auto controllata via Bluetooth con L298N
#80Avanzato
Premium

Auto controllata via Bluetooth con L298N

Trasforma il telefono in un telecomando e guida la tua auto robot. L'Arduino riceve tramite un modulo Bluetooth i comandi di un'app di controllo remoto sul telefono e fa girare le ruote con un driver

5.0(38)
65
Utilizzo del servomotore
#35Principiante
Premium

Utilizzo del servomotore

Il braccio di un piccolo servomotore ruota a turno in tre posizioni: tutto all'inizio, esattamente a metà e tutto alla fine, aspettando due secondi a ogni fermata. L'Arduino dice al motore a quale ang

4.7(48)
67
Utilizzo dei LED RGB
#39Principiante
Premium

Utilizzo dei LED RGB

Dentro un solo LED si nascondono tre colori: il LED RGB si accende rosso, poi verde, poi blu, ogni colore acceso per mezzo secondo e spento per mezzo secondo, e poi il giro ricomincia. Ti bastano un L

4.9(73)
98
Lampadina 220V con pulsante (Push)
#19Avanzato
Premium

Lampadina 220V con pulsante (Push)

Finché tieni premuto il pulsante, una vera lampadina da 220 volt resta accesa, e si spegne appena lo lasci. Il piccolo segnale dell'Arduino non può accendere la lampadina direttamente, quindi in mezzo

4.4(30)
38
Comunicazione unidirezionale tra 2 Arduino
#57Intermedio
Premium

Comunicazione unidirezionale tra 2 Arduino

Fai parlare due Arduino con un solo filo: premi il pulsante sull'uno e il LED dell'altro si accende, premi di nuovo e si spegne. La scheda che invia segnala la pressione con un breve messaggio, e quel

4.4(37)
50