Contrôle d'un robot par une page web
J’ai acheté pour ma fille il y a quelque temps ce robot : MBot. C’est un robot basé sur un shield Arduino et pouvant être programmé via Scratch. Le modèle que j’ai choisi est celui avec la version Bluetooth, car je savais que cela allait me laisser plus de possibilités pour le hacker plus tard.
Il y a environ un an, j’ai aussi appris l’existence de deux APIs :
- L’API Web Bluetooth. Cette API permet de contrôler un appareil Bluetooth Low Energy (BLE) depuis une page web !
- Le Physical Web.
Je me suis donc posé la question suivante : et si je pouvais enrichir mon Mbot pour qu’il me propose d’interagir avec lui mais sans que j’ai d’application à installer. C’est ce que nous allons voir dans cet article !
Physical Web
Prenez un périphérique BLE. Faites lui émettre une URL avec la norme EddyStone. Vous obtiendrez un appareil Physical Web !
Le principe du Physical Web est très simple. Il s’agit juste d’un appareil BLE qui émet une URL. Vous pouvez le comparer grossièrement à un QR Code sauf que ce dernier est Bluetooth.
Comment ça marche ?
- L’appareil doit émettre une trame EddyStone URL de façon à ce que votre téléphone puisse la capter.
- Le navigateur du téléphone (ou une application compatible Physical Web) va interroger son service pour vérifier si l’URL exposée est une URL HTTPS et non blacklistée.
- Le service interroge la page.
- Les métas données sont renvoyés au service.
- Le service va pouvoir répondre au téléphone pour que ce dernier affiche une notification native sur le téléphone.
Voici à quoi ressemble une notification Physical Web :
Quel intérêt par rapport à un QR Code ?
En fait les intérêts sont nombreux :
- C’est aussi simple d’utilisation qu’un QR Code et ça permet plus !
- Contrairement à un QR Code, aucune application n’a besoin d’être installée pour capter la balise si ce n’est votre navigateur.
- Les sites malveillants ne seront pas exposés au public car ils auront été filtrés par le service.
- L’appareil qui émet l’URL pourra interagir avec le téléphone une fois que l’on y sera connecté.
- On pourra mettre à jour l’URL de l’appareil si on le souhaite contrairement à un QR Code.
- Les notifications sont silencieuses ! En effet, ce n’est pas parce que l’on est proche d’un appareil Physical Web que notre téléphone va passer son temps à sonner. L’utilisateur ne verra la notification que si ce dernier regarde les notifications de son téléphone !
Rappel sur le fonctionnement d’un appareil Bluetooth Low Energy
Un appareil via un serveur GATT Bluetooth va exposer un ensemble de services GATT. Chaque service va lui-même exposer des caractéristiques sur lesquelles on pourra lire / écrire / s’abonner. L’appareil, les services et les caractéristiques sont identifiées par un UUID qui est unique.
Maintenant que la partie théorie est passée, nous allons nous intéresser à notre cas d’utilisation : le Mbot.
Hack du protocole du Mbot
Afin de savoir quels services je dois appeler et quel type de données je dois transférer, je me suis lancé dans une opération de “reverse engineering” du Mbot pour comprendre comment l’utiliser. Je me suis appuyé sur cet article : Reverse Engineering a Bluetooth Low Energy Ligth Bulb qui m’a beaucoup aidé. Je vous conseille de le lire car il rentre un peu plus en détail que moi sur les étapes à suivre pour Hacker un appareil BLE.
Je me contenterai ici simplement de lister les étapes principales que j’ai suivies et les résultats que j’ai obtenus.
0. Avoir un téléphone Android 4.4+
Le téléphone Android est obligatoire car nous allons analyser les trames Bluetooth émises par l’application officielle Mbot. La fonctionnalité qui permet de “sniffer” les trames Bluetooth n’est disponible que depuis Android 4.4.
1. Préparation du téléphone
Il faut installer l’application Mbot et aussi l’application nRF Connect for Mobile. Cette dernière va nous permettre de connaître les services disponibles et donc de trouver les bons UUIDs.
2. Détection des services
À l’aide nRF, je me suis connecté à mon Mbot :
J’ai ensuite analysé les services Bluetooth qui étaient disponibles :
On peut voir que les UUID des services sont disponibles. À ce moment-là, je ne sais pas lequel choisir. Il faut donc cliquer sur les deux services pour analyser leurs caractéristiques.
En regardant les flèches sur la droite. On comprend facilement que le premier service expose une caractéristique en mode “notification” et une caractéristique en mode “écriture”. J’ai donc supposé que les UUID qui m’intéressaient étaient :
- Le Service avec l’UUID : 0000ffe1-0000-1000-8000-00805f9b34fb
- La caractéristique avec l’UUID : 0000ffe3-0000-1000-8000-00805f9b34fb
J’ai aussi noté que le nom de mon appareil était “Makeblock_LE“
3. Écoute des trames
Il faut maintenant configurer son téléphone pour écouter les trames Bluetooth : Paramètres->Options de développement->Journal snoop HCI Bluetooth
Le fait d’activer cette option fait que le téléphone va écrire dans un fichier de log les trames Bluetooth. Sur mon Nexus le fichier est disponible sous /sdcard/btsnoop_hci.log
mais sous mon Galaxy, le fichier est disponible sous /sdcard/Android/data/btsnoop_hci.log
4. Générer les fichiers de logs
Afin de comprendre et analyser au mieux les trames, j’ai procédé par étapes. J’ai ainsi généré plusieurs fichiers de logs afin d’isoler les instructions envoyées.
Voici par exemple, des fichiers de logs générés :
- Logs des moteurs : btsnoop_hci_motor.log
- Logs des leds RGB : btsnoop_hci_rbg.log
5. Analyse des trames
Afin d’analyser les trames, je me suis servi de WireShark.
J’ai ensuite injecté mes fichiers dans WireShark pour faire ressortir les trames qui m’intéressaient. Contrairement à l’exemple fourni sur l’article de “reverse engineering”. Les instructions envoyées ne sont pas des instructions BLE mais Bluetooth classiques. Heureusement pour moi, les instructions binaires restent les mêmes.
J’ai aussi eu la chance que le Mbot soit un projet open source. Ça m’a permis d’être sûr des instructions à regarder et comment les interpréter. J’ai pris pour exemple l’application Android : MeModule.java
6. Catalogue des instructions
Voici ce que j’ai pu comprendre. Une instruction Bluetooth du Mbot doit respecter le format suivant :
/* |
Chaque message fait 13 bytes à répartir comme suit :
var byte0 = 0xff, // Static header |
Fonctionnement de l’API
Maintenant que nous savons comment contrôler notre robot, il nous faut nous intéresser à l’API Web Bluetooth.
Avant toute chose, cette API est encore expérimentale et il faut encore l’activer dans Chrome : chrome://flags/#enable-web-bluetooth. Au moment où j’écris ces lignes, elle fonctionne sous Linux / Chrome OS / macOS / Android 5+ (Chromium) / Android 6+ (Chrome & Opera). Veuillez vous référer à cette page pour savoir ce qui est compatible : Tableau de compatibilité
Pour accéder à un appareil Bluetooth, il faut passer par plusieurs étapes :
- Rechercher l’appareil
- Se connecter
- Récupérer le service
- Récupérer la caractéristique
- Écrire / Lire
Toute l’API Web Bluetooth fonctionne sur des promesses JavaScript. Chaque appel à l’API renverra une promesse.
Rechercher l’appareil
let options = { |
En précisant le nom du service dans le champ optionalServices
, je pourrais me connecter au service. En effet, si on ne précise pas le nom du service, on ne pourra pas s’y connecter par la suite.
Connexion à l’appareil
device.gatt.connect() |
Une fois connecté, nous récupérerons un serveur qui nous permettra de récupérer le service.
Récupération du service
Deux possibilités s’offrent à nous pour nous connecter à notre service : Depuis l’objet device
ou à partir du serveur récupéré lors de la connexion.
// A partir du serveur |
/!\ Le UUID Service doit respecter le format suivant : 0000ffe1-0000-1000-8000-00805f9b34fb
. En effet, 0000ffe100001000800000805f9b34fb
ne sera pas reconnu. Il est donc important lors des connexions de faire attention à ça !
Caractéristiques
La caractéristique doit se récupérer sur l’objet service
// A partir du gatt (on doit s'être connecté préalablement) |
Lecture / Ecriture / Abonnement
On va pouvoir interagir de 3 façons avec une caractéristique :
// Lecture |
Helper
Tout ce code peut être généré grâce à François Beaufort qui a mis à disposition un générateur de code Web Bluetooth
Attention aux données
Les données manipulées sont des données binaires. Il convient donc de faire les transformations nécessaires pour lire / écrire correctement. Pour les données textuelles il faut utiliser les objets TextEncoder
et TextDecoder
pour encoder et décoder correctement vos données !
Démo
Voici un exemple de lecture des caractéristiques de n’importe quel appareil :
Live Output
Ce code est extrait du Device Information Characteristics Sample
Contrôle du Mbot
Maintenant que l’on a vu comment manipuler l’API, nous allons essayer de passer les instructions à notre robot pour l’animer.
Rappel sur le protocole du Mbot
Pour rappel, le Mbot répond aux contraintes suivantes :
- Nom : Makeblock_LE
- Service : 0000ffe1-0000-1000-8000-00805f9b34fb
- Caractéristique : 0000ffe3-0000-1000-8000-00805f9b34fb
- Format d’échange :
/* |
Comment donner à manger des données qui sont déjà binaires ?
Quand on regarde le format des instructions Bluetooth, on se rend compte qu’on ne manipule pas ici des chiffres ou des chaines de caractères mais bel et bien une instruction binaire. Comment faire pour que cette donnée soit transférée correctement au Mbot ?
C’est très simple, la fonction writeValue
d’une caractéristique attend un buffer et on va lui donner des données binaires.
Prenons en exemple l’instruction suivante : ff:55:09:00:02:0a:09:64:00:00:00:00:0a
Il s’agit d’une instruction moteur qui fait 13 bytes. Le buffer étant une puissance de 2, il va falloir compléter le buffer avec des 0 et ainsi préparer un buffer de 16 bytes.
Une des subtilités de l’utilisation d’un buffer est qu’il faut inverser par paire les bytes à envoyer, sinon la donnée n’est pas reçue dans l’ordre ! Ainsi pour envoyer ff:55:09:00:02:0a:09:64:00:00:00:00:0a
, je me retrouve à envoyer quelque chose comme ça : 0x55ff;0x0009;0x0a02;0x0964;0x0000;0x0000;0x000a;0x0000;
Voici donc le code associé à l’écriture de l’instruction précédente :
// UUIDs |
Résultat
Voici le résultat en vidéo
Vous pouvez accéder à l’application à l’adresse suivante : App Mbot-WebBluetooth (/!\ à bien avoir configuré son navigateur pour autoriser le Web Bluetooth)
Crédits
Le code source du projet est disponible ici : Mbot-webbluetooth
Pour aller plus loin :
- Communauté Google + : La communauté officielle
- Web Bluetooth Samples : Des exemples de code
- Communauté W3C : La communauté W3C dédié au Web Bluetooth
- Spec : La spécification / documentation officielle.
- Interact With BLE Device On The Web : Article d’introduction de Google pour apprendre à utiliser l’API.