Guides · 19 min de lecture

App Inventor Arduino Bluetooth : ton appli Android avec HC-05

Piloter Arduino en Bluetooth avec App Inventor : câblage du HC-05, ListPicker, blocs boutons et curseurs, LED, relais, servo, capteurs, APK et Android 12.

Piloter un Arduino en Bluetooth avec App Inventor est le moyen le plus rapide de créer ta propre appli Android sans écrire une seule ligne de Java ou de Kotlin. Dans MIT App Inventor, l'outil gratuit du MIT qui fonctionne dans le navigateur, tu glisses des boutons, des curseurs et des zones de texte sur l'écran, puis tu définis leur comportement avec des blocs qui s'emboîtent comme des pièces de puzzle. Le téléphone se connecte à un module Bluetooth HC-05 relié à l'Arduino ; chaque appui dans l'appli part vers l'Arduino sous forme d'une courte commande texte, et l'Arduino renvoie ses mesures au téléphone par le même chemin.

À la fin de ce guide, tu auras une appli de télécommande qui fonctionne vraiment : un ListPicker qui se connecte au HC-05 depuis une liste, des boutons qui allument et éteignent une LED et un relais, deux curseurs (Slider) pour la luminosité de la LED et l'angle du servo, et des étiquettes qui affichent en direct la température et l'humidité d'un DHT11. Tu verras étape par étape le code Arduino, chaque bloc App Inventor, la création de l'APK et la solution au problème d'autorisations Bluetooth apparu avec Android 12. Si tu n'as jamais utilisé le HC-05, jette d'abord un œil au guide du module Bluetooth HC-05.

Module Bluetooth HC-05
Le HC-05 est un module Bluetooth classique (SPP), exactement le type avec lequel dialogue le composant BluetoothClient d'App Inventor ; il crée une liaison série sans fil entre le téléphone et l'Arduino.

Qu'est-ce qu'App Inventor et comment communique-t-il avec Arduino ?

MIT App Inventor est un environnement gratuit de création d'applis développé par le Massachusetts Institute of Technology (MIT) ; tu te connectes avec ton compte Google et tu travailles dans le navigateur. Il propose deux vues : dans le Designer, tu prépares l'apparence de l'appli en faisant glisser des composants, et dans l'éditeur Blocks, tu écris avec des blocs colorés des règles comme « quand on appuie sur le bouton, fais ceci ». Pour tester l'appli sans l'installer, on utilise l'appli MIT AI2 Companion du Play Store ; une fois le travail terminé, un clic génère un fichier APK installable.

Côté Bluetooth, c'est le composant BluetoothClient qui fait le travail. Il utilise le profil SPP (Serial Port Profile, profil de port série) du Bluetooth classique, justement celui du HC-05. Résultat : un câble série invisible entre le téléphone et l'Arduino. Quand l'appli envoie « L1 » avec le bloc SendText, l'Arduino lit ces deux caractères avec bt.read(), comme si tu les avais tapés dans le moniteur série. Tout ce que l'Arduino envoie avec bt.print() arrive dans le bloc ReceiveText du téléphone. Côté Arduino, aucune bibliothèque Bluetooth particulière n'est nécessaire.

CoucheRôleDans ce projet
Interface (Designer)Composants visibles à l'écranListPicker, 5 Button, 2 Slider, Label
Logique (Blocks)Blocs qui réagissent aux événementsÉvénements Click, PositionChanged et Timer
BluetoothClientConnexion SPP, envoi et réception de donnéesConnect, SendText, ReceiveText
HC-05Pont entre Bluetooth et UART9600 bauds, code PIN 1234
ArduinoInterprète les commandes, pilote les sorties, lit le capteurLED, relais, servo, DHT11

Matériel nécessaire

MatérielQuantitéRemarque
Arduino Uno (ou Nano)1Code et broches identiques sur les deux
Module Bluetooth HC-05 ou HC-061Bluetooth classique ; le HM-10 (BLE) ne fonctionne pas de cette façon
Résistances de 1 kΩ et 2 kΩ1 de chaquePont diviseur pour la broche RXD du HC-05 (2,2 kΩ convient aussi)
LED et résistance de 220 Ω1 de chaqueLED à luminosité réglable (D5, PWM)
Module relais 5 V1Pour commander une lampe ou un ventilateur
Servomoteur SG901Commande de 0 à 180° par curseur
Capteur de température et d'humidité DHT111Données à afficher sur le téléphone
Téléphone Android1Le HC-05 ne fonctionne pas avec l'iPhone
Breadboard et fils de connexion—Une masse (GND) commune est indispensable
Arduino Uno
Arduino Uno
HC-06
HC-06
SG90
SG90
DHT11
DHT11
LED
LED

Montage : branchement du HC-05, de la LED, du relais, du servo et du DHT11

La carte du HC-05 possède un régulateur, sa broche VCC accepte donc 5 V, mais ses broches de données fonctionnent en logique 3,3 V. L'Arduino lit sans problème le signal 3,3 V de la broche TXD du module ; en revanche, le signal TX en 5 V de l'Arduino doit arriver sur la broche RXD à travers un pont diviseur de tension : D11 → 1 kΩ → RXD, RXD → 2 kΩ → GND. RXD reçoit ainsi 5 × 2 / 3 ≈ 3,3 V. On relie le HC-05 aux broches D10 et D11 avec SoftwareSerial plutôt qu'aux broches série matérielles du Uno (0 et 1) : tu peux ainsi téléverser du code module branché et garder le moniteur série pour le débogage. Tu peux vérifier la résistance de la LED avec le calculateur de résistance pour LED.

LiaisonArduino UnoESP32Raspberry Pi Pico
HC-05 VCC5VInutile (Bluetooth intégré)VBUS (5 V)
HC-05 GNDGND—GND
HC-05 TXDD10 (RX de SoftwareSerial)—GP1 (UART0 RX)
HC-05 RXDD11, via un pont 1 kΩ / 2 kΩ—GP0 (UART0 TX), sans pont
LED (+ 220 Ω)D5 (PWM)GPIO 2 (LED intégrée)GP15
IN du module relaisD7GPIO 26GP14
Signal du servo (orange)D9— (ajout possible avec ESP32Servo)GP13
Données du DHT11D2GPIO 4GP16
Respecte trois règles : toutes les masses (Arduino, HC-05, relais, servo et alimentation externe éventuelle) doivent être reliées entre elles. N'applique jamais 5 V sans pont diviseur sur la broche RXD du HC-05 ; le module peut tenir un moment, mais finir par lâcher. Un servo en mouvement peut tirer brièvement plusieurs centaines de milliampères ; si l'Arduino est alimenté en USB, ce pic fait chuter la tension, le HC-05 perd la connexion ou l'Arduino redémarre. Alimenter le servo et le relais avec une source 5 V séparée règle le problème à la racine.

Protocole de communication : qu'enverra le téléphone ?

Avant d'écrire du code, il faut décider quelle « langue » parleront le téléphone et l'Arduino. Dans ce projet, chaque commande se compose d'une lettre, suivie d'un nombre et enfin d'un caractère de retour à la ligne (\n, ASCII 10). Ce retour à la ligne est essentiel : les données Bluetooth peuvent arriver en morceaux, et si « S1 » et « 35 » arrivent séparément, l'Arduino attend le retour à la ligne et traite « S135 » comme une seule commande. Comme les commandes sont du texte lisible, tu peux aussi les tester à la main avec n'importe quelle appli de terminal Bluetooth.

CommandeSensSignification
L1 / L0Téléphone → ArduinoAllumer la LED à fond / l'éteindre
P0 … P255Téléphone → ArduinoLuminosité de la LED (valeur analogWrite)
R1 / R0Téléphone → ArduinoActiver / relâcher le relais
S0 … S180Téléphone → ArduinoAngle du servo (degrés)
24.5;41Arduino → téléphoneTempérature (°C) et humidité (%), séparées par un point-virgule

Au lieu de texte, App Inventor peut aussi envoyer un seul octet (0–255) avec le bloc Send1ByteNumber, que l'Arduino lit directement comme un nombre. C'est court et rapide, mais cela ne convient qu'à un seul curseur : si deux curseurs et quatre boutons envoient des octets, l'Arduino ne peut pas savoir si un 90 reçu est un angle de servo ou une luminosité. Le format lettre + nombre + retour à la ligne coûte quelques octets de plus, mais à 9600 bauds environ 960 caractères passent par seconde : tu ne verras jamais la différence.

Le code Arduino

Les bibliothèques Servo et SoftwareSerial sont fournies avec l'IDE Arduino. Pour le DHT11, installe DHT sensor library (Adafruit) depuis le gestionnaire de bibliothèques ; quand il propose les dépendances, choisis Install all pour ajouter aussi Adafruit Unified Sensor. Comme on n'utilise pas les broches 0 et 1, inutile de débrancher le HC-05 pendant le téléversement.

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}
  • Tampon de ligne : loop() ajoute chaque caractère reçu à la variable komut (commande) ; à l'arrivée de \n, il transmet la ligne à komutIsle() et vide le tampon. Au-delà de 16 caractères, le reste est ignoré, pour que des données parasites ne remplissent pas la mémoire.
  • trim() : Certaines applis de terminal ajoutent aussi \r en fin de ligne ; trim() le supprime avec les espaces, si bien que « L1\r » est toujours reconnu comme « L1 ».
  • Lettre et nombre : charAt(0) donne la lettre de la commande et substring(1).toInt() le nombre qui suit. constrain() ramène la valeur dans une plage sûre : même si le téléphone envoie 300 par erreur, le servo n'est jamais poussé au-delà de 180°.
  • Envoi non bloquant : Le capteur est lu toutes les 2 secondes grâce à millis(). Comme il n'y a pas de delay(), les commandes reçues entre-temps sont traitées sans attente ; détails dans millis() ou delay().
  • print('\n') au lieu de println : println() termine la ligne par \r\n. App Inventor n'utilise que \n comme séparateur, donc le \r resterait collé à la fin de la valeur d'humidité ; n'envoyer que \n garde un découpage propre sur le téléphone.
  • Relais actif à l'état bas : La plupart des modules relais s'activent quand IN passe à LOW. Si le tien s'active sur HIGH, il suffit d'échanger les valeurs des constantes ROLE_ACIK (marche) et ROLE_KAPALI (arrêt).
Avant de passer à App Inventor, teste le côté Arduino seul : connecte-toi au HC-05 avec une appli comme Serial Bluetooth Terminal du Play Store, tape « L1 » et envoie ; la LED doit s'allumer et L1 doit apparaître dans le moniteur série. Si des lignes comme « 24.5;41 » défilent toutes les 2 secondes, le retour des données fonctionne aussi. En cas de souci plus tard, tu sauras tout de suite si le problème vient de l'appli ou du montage.

Concevoir l'interface dans App Inventor (Designer)

  1. Ouvre ai2.appinventor.mit.edu dans ton navigateur, connecte-toi avec ton compte Google et crée un projet nommé BlueGraysRemote avec Projects > Start new project.
  2. Depuis le groupe Layout de la Palette, fais glisser un HorizontalArrangement et places-y un ListPicker (Text : Connecter), un Button (Text : Déconnecter) et un Label (Text : Non connecté).
  3. Ajoute en dessous deux autres HorizontalArrangement : dans le premier, les boutons Allumer LED et Éteindre LED ; dans le second, Allumer relais et Couper relais. Avec Width sur Fill parent, les boutons sont plus faciles à toucher.
  4. Ajoute deux Slider : pour la luminosité MinValue 0, MaxValue 255, ThumbPosition 0 ; pour le servo MinValue 0, MaxValue 180, ThumbPosition 90. Place au-dessus de chacun un Label qui indique son rôle.
  5. Ajoute deux autres Label pour la température et l'humidité et monte leur FontSize à environ 20.
  6. Depuis le groupe Connectivity, ajoute un BluetoothClient ; dans le panneau Properties, règle DelimiterByte sur 10 et coche NoLocationNeeded.
  7. Depuis le groupe Sensors, ajoute un Clock ; règle TimerInterval sur 200 et décoche TimerEnabled. On activera le minuteur par blocs une fois la connexion établie.
ComposantNom (Rename)Réglage important
ListPickerLP_ConnectText : Connecter
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 (pour les valeurs)
BluetoothClientBluetoothClient1DelimiterByte 10, NoLocationNeeded coché
ClockClock1TimerInterval 200, TimerEnabled désactivé

Se connecter au HC-05 avec un ListPicker

Commence par appairer le HC-05 dans les réglages Bluetooth du téléphone (code PIN généralement 1234, sinon 0000). Cette étape est obligatoire : BluetoothClient1.AddressesAndNames ne liste que les appareils appairés et ne recherche pas les nouveaux appareils à proximité. Chaque élément est un texte composé de l'adresse MAC puis du nom de l'appareil, par exemple « 98:D3:31:F5:2A:10 HC-05 ». Tu peux passer ce texte complet au bloc Connect ; App Inventor supprime lui-même tout ce qui suit le premier espace. Le bloc renvoie true si la connexion réussit et false sinon.

  1. Dans l'événement when LP_Connect.BeforePicking, place set LP_Connect.Elements to BluetoothClient1.AddressesAndNames. La liste se remplit à nouveau avec les appareils appairés à chaque ouverture.
  2. Dans l'événement when LP_Connect.AfterPicking, ajoute un bloc if et branche call BluetoothClient1.Connect address: LP_Connect.Selection dans sa condition.
  3. Dans la partie then du if, mets LBL_Status.Text sur « Connecté » et lance la lecture des données avec set Clock1.TimerEnabled to true ; dans la partie else, écris « Échec de connexion ».
  4. Dans l'événement when BTN_Disconnect.Click, fais d'abord set Clock1.TimerEnabled to false, puis call BluetoothClient1.Disconnect, et enfin mets LBL_Status.Text sur « Non connecté ». Arrêter le minuteur en premier évite une lecture et un message d'erreur après la fermeture de la liaison.
Une fois la connexion établie, la LED du HC-05 cesse de clignoter rapidement et émet deux brefs éclats toutes les 2 secondes. Tu connais ainsi l'état de la liaison sans regarder l'appli ; si la LED se remet à clignoter vite, la connexion est perdue.

Envoyer des données : boutons et curseurs

L'envoi se fait avec un seul bloc : call BluetoothClient1.SendText text. Quand tu écris « L1\n » dans un bloc texte, App Inventor transforme le \n final en caractère de retour à la ligne. Envoyer sans connexion provoque l'erreur 515 ; c'est donc une bonne habitude d'entourer chaque envoi d'un test if BluetoothClient1.IsConnected. Pour un curseur, tu colles le nombre à la lettre et au retour à la ligne avec un bloc join : join("S", round(thumbPosition), "\n").

Événement (event)Texte envoyéRésultat sur l'Arduino
BTN_LedOn.ClickL1\nLa LED s'allume à pleine luminosité
BTN_LedOff.ClickL0\nLa LED s'éteint
BTN_RelayOn.ClickR1\nLe relais colle, la lampe branchée s'allume
BTN_RelayOff.ClickR0\nLe relais se relâche
SLD_Brightness.PositionChangedjoin("P", round(thumbPosition), "\n")analogWrite(5, valeur)
SLD_Servo.PositionChangedjoin("S", round(thumbPosition), "\n")servo.write(angle)

Quand tu fais glisser un curseur du doigt, l'événement PositionChanged se déclenche des dizaines de fois par seconde et thumbPosition renvoie des valeurs décimales comme 87,4. Si tu envoies à chaque événement, le même angle part encore et encore, le tampon du HC-05 se remplit et le servo bouge par à-coups, avec du retard. La solution est simple : crée une variable global lastAngle ; n'envoie que si la valeur arrondie avec round(thumbPosition) est différente, puis mets la variable à jour. Ainsi, les données ne partent que lorsque l'angle change réellement. Applique la même astuce au curseur de luminosité avec global lastBrightness.

Recevoir des données : afficher les mesures sur le téléphone

L'Arduino envoie une ligne « 24.5;41 » toutes les 2 secondes. App Inventor n'a pas d'événement qui se déclenche tout seul à l'arrivée de données ; on utilise donc le composant Clock pour vérifier à intervalles réguliers s'il y a du nouveau. Comme DelimiterByte vaut 10 dans le Designer, donner -1 comme numberOfBytes au bloc ReceiveText lui fait lire jusqu'au retour à la ligne et renvoyer la ligne sans le \n. Un minuteur de 200 ms vérifie bien plus souvent que les données n'arrivent (toutes les 2000 ms), donc rien ne s'accumule dans le tampon.

  1. Place une condition if BluetoothClient1.IsConnected dans when Clock1.Timer.
  2. Ajoute à l'intérieur une seconde condition : call BluetoothClient1.BytesAvailableToReceive > 0.
  3. Range la ligne reçue dans une variable locale avec initialize local line to call BluetoothClient1.ReceiveText numberOfBytes: -1.
  4. Transforme la ligne en liste avec le bloc split text line at ";" : « 24.5;41 » devient la liste à deux éléments [24.5, 41]. Garde le résultat dans une variable locale nommée parts.
  5. if length of list parts = 2, mets LBL_Temp.Text sur join("Température : ", select list item parts index 1, " °C") et LBL_Hum.Text sur join("Humidité : ", select list item parts index 2, " %"). Vérifier le nombre d'éléments évite les erreurs dues à des lignes reçues à moitié ou corrompues.
Si tu passes -1 à ReceiveText mais oublies de régler DelimiterByte sur 10 (la valeur par défaut est 0), le bloc attend un octet 0 qui n'arrive jamais et l'appli semble figée. Et si l'Arduino envoie sa ligne avec println(), le caractère \r se retrouve à la fin de la deuxième valeur ; c'est pourquoi le code n'envoie que '\n'.
Ne t'arrête pas à l'affichage en texte : tu peux passer LBL_Temp.TextColor en rouge quand la température dépasse 30 °C, ouvrir une alerte avec le composant Notifier ou tracer sur un Canvas une courbe des dernières mesures.

Le problème d'autorisations Bluetooth sous Android 12 et plus

Les autorisations Bluetooth ont changé avec Android 12 (API 31). L'ancienne autorisation BLUETOOTH, accordée automatiquement à l'installation, a été remplacée par BLUETOOTH_CONNECT et BLUETOOTH_SCAN, que l'utilisateur doit accepter pendant l'exécution de l'appli ; dans les réglages du téléphone, elles apparaissent sous le nom Appareils à proximité. Si elle n'a pas été accordée, App Inventor ouvre la fenêtre d'autorisation à la première tentative, mais interrompt le bloc en cours. D'où des symptômes bien connus : la liste s'ouvre vide au premier appui sur Connecter, le message « Error 908: The permission ... has been denied » apparaît (avec BLUETOOTH_CONNECT ou BLUETOOTH_SCAN comme nom), ou bien, si l'utilisateur a refusé une fois, l'appli ne redemande plus jamais.

  1. Dans l'événement when Screen1.Initialize, vérifie la version d'Android : si select list item (split Screen1.PlatformVersion at ".") index 1 ≥ 12, donne à call Screen1.AskForPermission la valeur BluetoothConnect de la liste Permission. Ces autorisations n'existent pas sous Android 11 et versions antérieures, et les demander provoque là aussi l'erreur 908 : la vérification de version est donc importante.
  2. Dans l'événement when Screen1.PermissionGranted, si l'autorisation accordée est BLUETOOTH_CONNECT (contains text: permissionName, piece: "CONNECT"), demande ensuite BluetoothScan. AskForPermission n'accepte qu'une autorisation à la fois, il faut donc les enchaîner ainsi.
  3. Dans l'événement when Screen1.PermissionDenied, affiche avec un Notifier un message indiquant le chemin « Paramètres > Applications > BlueGraysRemote > Autorisations > Appareils à proximité > Autoriser ». Intercepter cet événement montre à l'utilisateur une explication claire au lieu d'une fenêtre d'erreur en anglais.
  4. Laisse NoLocationNeeded coché sur le BluetoothClient dans le Designer ; ce réglage indique à Android que l'appli n'utilise pas le Bluetooth pour déterminer la position.
  5. Teste toujours aussi avec l'APK : les autorisations de l'AI2 Companion appartiennent à l'appli Companion, alors que ton APK demande ses propres autorisations après l'installation.
ErreurSignificationSolution
Error 507: Unable to connect. Is the device turned on?Connexion au module impossibleVérifie l'alimentation du HC-05, l'appairage et qu'il n'est pas connecté à un autre téléphone ; si ça échoue encore, décoche Secure sur le BluetoothClient et réessaie
Error 515: Not connected to a Bluetooth device.Envoi ou lecture sans connexionEntoure les blocs d'envoi et du Clock d'un test IsConnected
Error 516: Unable to write: Broken pipeLiaison coupée en cours de route (plus d'alimentation, hors de portée)Arrête le Clock, appelle Disconnect et reconnecte-toi ; alimente séparément le servo et le relais
Error 908: The permission … has been deniedPas d'autorisation Appareils à proximité sous Android 12+Demande-la par blocs ou accorde-la à la main dans les Paramètres
La liste s'ouvre videModule non appairé ou autorisation tout juste demandéeAppaire le HC-05 dans les réglages du téléphone puis, après avoir accordé l'autorisation, appuie de nouveau sur Connecter

Tester l'appli et générer l'APK

Pendant le développement, inutile d'installer un APK à chaque modification. Installe l'appli MIT AI2 Companion depuis le Play Store ; avec l'ordinateur et le téléphone sur le même réseau Wi-Fi, choisis Connect > AI Companion dans App Inventor et scanne le QR code ou saisis le code de 6 caractères affiché à l'écran. Chaque modification faite dans le Designer ou dans les blocs apparaît aussitôt sur le téléphone. Une fois l'appli terminée, génère le fichier installable ainsi :

  1. Sélectionne Screen1 dans le Designer et renseigne AppName (le nom affiché sur le téléphone), Icon (un PNG carré), VersionCode et VersionName.
  2. Dans le menu du haut, choisis Build > Android App (.apk). La compilation prend en général une ou deux minutes.
  3. À la fin, une fenêtre s'ouvre avec un QR code et un bouton de téléchargement. Tu peux scanner le QR code avec le téléphone pour télécharger directement le fichier, ou enregistrer l'APK sur l'ordinateur et le copier sur le téléphone par câble. Le lien du QR code n'est valable que peu de temps (environ 2 heures).
  4. À l'ouverture de l'APK sur le téléphone, Android te demande d'autoriser le navigateur ou le gestionnaire de fichiers à installer des applis inconnues. Si Play Protect affiche un avertissement, tu peux poursuivre avec l'option d'installation malgré tout dans les détails ; cet avertissement est courant pour les applis hors Play Store dont la signature est inconnue.
  5. Au premier lancement de l'appli, accepte l'autorisation Appareils à proximité, appuie sur Connecter et choisis le HC-05 dans la liste.
Sauvegarde ton projet avec Projects > Export selected project (.aia) to my computer ; tu peux partager le fichier .aia avec un ami ou le transférer vers un autre compte. Si tu veux publier l'appli sur Google Play, utilise Build > Android App Bundle (.aab) et conserve absolument ta clé de signature avec Projects > Export keystore : les mises à jour doivent être signées avec la même clé. N'oublie pas non plus d'augmenter VersionCode de 1 à chaque mise à jour.

La même appli avec un ESP32, sans HC-05

Carte de développement ESP32
L'ESP32 classique intègre le Bluetooth Classic ; le BluetoothClient d'App Inventor s'y connecte exactement comme à un HC-05.

L'ESP32 classique intègre à la fois le Bluetooth classique et le BLE. La bibliothèque BluetoothSerial présente l'ESP32 au téléphone comme un appareil SPP : tu peux donc utiliser l'appli que tu viens de créer sans rien changer. Appaire l'appareil « BlueGrays-ESP32 » dans les réglages Bluetooth du téléphone, choisis-le dans la liste de l'appli, et c'est tout. Attention : les ESP32-S3, ESP32-C3 et ESP32-C6 ne gèrent que le BLE ; ils n'ont pas de BluetoothSerial et, côté App Inventor, il faut l'extension BluetoothLE. Pour travailler en BLE, consulte le guide ESP32 Bluetooth et 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}

Le code comprend les mêmes commandes que la version Uno et envoie les données au même format « température;humidité » ; il ignore les commandes S, faute de servo branché. La bibliothèque Servo d'Arduino ne fonctionne pas sur l'ESP32 ; pour ajouter un servo, installe la bibliothèque ESP32Servo et utilise les mêmes appels attach() et write(), par exemple sur le GPIO 13. Alimente le module relais par la broche VIN (5 V) ; si son entrée IN ne commute pas de façon fiable avec le signal 3,3 V de l'ESP32, choisis un module relais compatible 3,3 V. Plus de détails dans Qu'est-ce qu'un module relais ?

Avec le Raspberry Pi Pico et MicroPython

Raspberry Pi Pico
Le Raspberry Pi Pico fonctionne en 3,3 V : il se branche directement sur la broche RXD du HC-05, sans pont diviseur.

Le Raspberry Pi Pico standard n'a pas de Bluetooth : tu relies donc le HC-05 aux broches UART0 (GP0 et GP1). Comme les broches du Pico fonctionnent en 3,3 V, pas besoin de pont diviseur cette fois ; alimente le module par la broche VBUS, qui fournit les 5 V de l'USB. Les Pico W et Pico 2 W ont bien un Bluetooth intégré, mais MicroPython n'y gère que le BLE ; pour dialoguer avec le BluetoothClient classique d'App Inventor, le HC-05 reste la solution la plus simple. Le code ci-dessous comprend les mêmes commandes, pilote le servo en PWM à 50 Hz et envoie les données au même format ; le module dht est déjà inclus dans le firmware MicroPython du 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)

Idées de projets avec App Inventor et Arduino

  • Voiture pilotée en Bluetooth : Associe les boutons de direction aux lettres F, B, L et R et entraîne les moteurs avec un L298N ; toutes les étapes sont dans le guide fabriquer une voiture robot Arduino.
  • Tableau de bord domotique : Commande une lampe, une prise et un ventilateur depuis un seul écran avec un module relais à quatre canaux ; pour des idées, vois le projet de maison connectée Arduino.
  • Lampe à choix de couleur : Règle séparément le rouge, le vert et le bleu d'une LED RGB avec trois curseurs.
  • Bras robotisé : Ajoute un curseur par articulation et commande les servomoteurs depuis ton téléphone.
  • Surveillance de serre : Affiche sur le téléphone les mesures du DHT11 et du capteur d'humidité du sol, et ajoute un bouton qui lance la pompe quand la terre est sèche.
  • Commande vocale : Avec le composant SpeechRecognizer d'App Inventor, crée une appli qui envoie L1 quand tu dis « allume la lumière ».

Erreurs fréquentes et solutions

  • L'appli se connecte mais la LED reste éteinte : Les fils TXD et RXD du HC-05 sont inversés, ou les broches SoftwareSerial du code ne correspondent pas au montage. Le TXD du module doit aller sur le RX de l'Arduino (D10).
  • Les commandes sont ignorées : Le \n manque dans le bloc texte ; l'Arduino attend le retour à la ligne. Vérifie si les commandes reçues apparaissent dans le moniteur série.
  • Caractères incompréhensibles : La vitesse du HC-05 diffère de celle de bt.begin(). Le module sort d'usine à 9600 bauds ; si elle a été modifiée par commandes AT, adapte le code.
  • Le servo tremble ou la connexion coupe : Le servo fait chuter la ligne 5 V de l'Arduino ; alimente-le avec une source 5 V séparée et relie les masses. Un léger tremblement peut aussi venir de SoftwareSerial, qui bloque brièvement les interruptions pendant la réception ; pour une solution durable, utilise un Arduino Mega ou un ESP32, qui disposent de ports série matériels libres. De temps en temps, le servo peut aussi sauter brièvement à un mauvais angle : la bibliothèque DHT coupe les interruptions pendant environ 5 ms à chaque mesure, et une commande qui arrive à ce moment-là peut être corrompue ; la commande suivante du curseur rectifie la position.
  • Les valeurs arrivent en retard sur le téléphone : L'intervalle du Clock est plus long que celui d'envoi de l'Arduino, et les lignes s'accumulent. Garde TimerInterval plus court que l'intervalle d'envoi.
  • L'appli se fige : DelimiterByte est resté à 0, ou l'Arduino ne termine pas ses lignes par \n ; ReceiveText(-1) attend un séparateur qui ne vient jamais.
  • Rien ne marche sur iPhone : Le HC-05 utilise le Bluetooth classique, qu'iOS n'autorise pas. Pour un iPhone, il faut un module BLE (HM-10) ou un ESP32.
Pour dépanner, coupe la chaîne en deux : teste d'abord le côté Arduino avec Serial Bluetooth Terminal, puis l'appli App Inventor. Si le terminal fonctionne mais pas l'appli, le problème vient des blocs ; si le terminal échoue aussi, vérifie le câblage ou le code Arduino. Pour contrôler les numéros de broches, utilise l'outil de brochage.

Associer App Inventor et Arduino est la façon la plus ludique d'apprendre à la fois le développement d'applis et l'électronique. Une fois la connexion et le protocole en place, le même squelette devient la télécommande d'une voiture, d'une maison connectée ou d'une serre ; seules changent les lettres envoyées par les boutons. Dans l'appli BlueGrays, tu trouveras pas à pas, avec schémas et code, les projets allumer une LED depuis le téléphone en Bluetooth et voiture Bluetooth avec L298N.

Questions fréquentes

Une appli App Inventor Bluetooth fonctionne-t-elle sur iPhone ?

Pas avec un HC-05 ou un HC-06. Ces modules utilisent le Bluetooth classique (SPP), et iOS ne permet pas aux applis ordinaires d'ouvrir ce type de liaison série. Pour dialoguer avec un iPhone, il faut passer à un module BLE comme le HM-10 ou à un ESP32 ; pour les projets avec HC-05, un téléphone Android reste le choix le plus simple.

Pourquoi la liste Bluetooth est-elle vide dans App Inventor ?

AddressesAndNames ne liste que les appareils déjà appairés avec le téléphone : appaire donc d'abord le HC-05 dans les réglages Bluetooth avec le code 1234. Sous Android 12 et plus, la liste s'ouvre aussi vide la première fois si l'autorisation Appareils à proximité n'a pas été accordée ; accorde-la et appuie de nouveau sur Connecter. Vérifie aussi que le Bluetooth est activé.

Comment corriger l'erreur 507 dans App Inventor ?

L'erreur 507 signifie « Unable to connect. Is the device turned on? » : le téléphone n'a pas pu ouvrir de connexion avec le module. Vérifie que le HC-05 est alimenté, que sa LED clignote rapidement et qu'il n'est pas connecté à un autre téléphone. Si le problème persiste, supprime l'appairage et refais-le, ou essaie de désactiver la propriété Secure du BluetoothClient.

Comment créer un APK avec App Inventor ?

Ouvre le projet et clique sur Build > Android App (.apk) dans le menu du haut. Une fois la compilation terminée, scanne le QR code avec le téléphone ou télécharge l'APK sur l'ordinateur puis copie-le sur le téléphone. Pendant l'installation, il faudra autoriser l'installation d'applis inconnues.

App Inventor peut-il se connecter à un ESP32 en Bluetooth ?

Oui. Avec la bibliothèque BluetoothSerial, l'ESP32 classique se comporte comme un appareil SPP, et le BluetoothClient d'App Inventor s'y connecte comme à un HC-05. Les ESP32-S3 et ESP32-C3 ne gèrent que le BLE : sur ces cartes, il faut l'extension BluetoothLE.

Peut-on publier une appli App Inventor sur Google Play ?

Oui. L'option Android App Bundle (.aab) du menu Build produit un fichier que tu peux envoyer sur Google Play ; il te faut pour cela un compte développeur Google Play. Les mises à jour doivent être signées avec la même clé, alors sauvegarde ton keystore avec Projects > Export keystore.

Voir tous les projets
Clignotement d'une LED
#1Débutant

Clignotement d'une LED

Le tout premier bonjour de l'électronique : allumer et éteindre une seule LED. L'Arduino allume et éteint la LED à intervalles très courts, la lumière clignote donc rapidement. Tu vois de la façon la

4.6(179)
978
Température et humidité avec DHT11
#55Intermédiaire

Température et humidité avec DHT11

Quelle température fait-il dans ta chambre, et l'air est-il humide ou sec ? Le capteur DHT11 mesure la température et l'humidité, et l'Arduino affiche les valeurs sur un écran LCD à deux lignes, mises

4.7(47)
64
Contrôler une LED depuis un téléphone via Bluetooth
#34Débutant
Premium

Contrôler une LED depuis un téléphone via Bluetooth

Une petite répétition pour allumer et éteindre les lumières de ta chambre depuis ton téléphone. Le module Bluetooth transmet à l'Arduino les lettres envoyées par ton téléphone ; une lettre allume la L

4.8(68)
88
Voiture contrôlée par Bluetooth avec L298N
#80Avancé
Premium

Voiture contrôlée par Bluetooth avec L298N

Transforme ton téléphone en télécommande et pilote ta propre voiture robot. L'Arduino reçoit, via un module Bluetooth, les ordres d'une appli de télécommande sur ton téléphone et fait tourner les roue

5.0(38)
65
Utilisation du servomoteur
#35Débutant
Premium

Utilisation du servomoteur

Le bras d'un petit servomoteur tourne tour à tour vers trois positions : tout au début, pile au milieu et tout au bout, en attendant deux secondes à chaque arrêt. L'Arduino indique au moteur l'angle à

4.7(48)
67
Utilisation d'une LED RVB
#39Débutant
Premium

Utilisation d'une LED RVB

Trois couleurs se cachent dans une seule LED : la LED RGB s'allume en rouge, puis en vert, puis en bleu, chaque couleur allumée une demi-seconde puis éteinte une demi-seconde, avant que tout recommenc

4.9(73)
98
Ampoule 220V avec bouton poussoir (Push)
#19Avancé
Premium

Ampoule 220V avec bouton poussoir (Push)

Tant que tu appuies sur le bouton, une vraie ampoule de 220 volts reste allumée, et elle s'éteint dès que tu relâches. Le petit signal de l'Arduino ne peut pas allumer l'ampoule directement : un relai

4.4(30)
38
Communication unidirectionnelle entre 2 Arduino
#57Intermédiaire
Premium

Communication unidirectionnelle entre 2 Arduino

Tu fais discuter deux Arduino par un seul fil : appuie sur le bouton de l'un et la LED de l'autre s'allume, appuie encore et elle s'éteint. La carte qui envoie signale l'appui par un court message, et

4.4(37)
50