P21 Balise Bluetooth Low Energy

De Wiki d'activités IMA

Objectifs du projet

Localiser des appareils mobiles grâce à des balises utilisant la technologie Bluetooth Low Energy. Un smartphone ou une tablette sera équipé d'une application permettant d'écouter les balises Bluetooth implémentant la technologie BLE. L'appareil devra se connecter à la balise et fournir son UUID. La balise se chargera ensuite de transférer les données collectées sur un ordinateur pour faire des études statistiques. On aura alors dans une base de données tous les utilisateurs connectés qui sont passé près de la balise relais. Dans un premier temps, on se contentera de transmettre des caractères vers la raspberry, puis on essaiera de transmettre de plus gros volume de données comme des photos. Main frame2.png

Le matériel et la technologie utilisée

Les beacons sont les dispositifs standards pour la localisation en intérieur. Le problème avec ce matériel est qu'il ne peut qu'émettre des données. Il ne permet pas de recevoir les informations provenant des appareils mobiles(typiquement l'UUID du téléphone). Or la réception des informations mobiles est importante pour pouvoir être collecté par l'ordinateur distant. On utilisera donc des Raspberry Pi munis d'un dongle Bluetooth BLE avec une stack bluez pour pouvoir recevoir des données venant des appareils mobiles appariés et les remonter vers l'ordinateur. Enfin, on va utiliser du Bluetooth low energy pour sa faible consommation électrique et sa légèreté par rapport au Bluetooth classique. Le tableau ci-dessous résume les différences entre le Bluetooth LE et le Bluetooth classique.

Bluetooth classique Bluetooth LE
Distance 100 m <100 m
vitesse de transmission 0.7 / 2.1 Mbits/s 0.27 Mbits/s
temps de latence (d'un état non connecté à un état connecté) 100 ms 6 ms
Nombre d'esclaves 7 Dépend de l'implémentation
temps pour envoyer des données 100 ms 3 ms
pic de courant <30 mA <15 mA
Puissance consommée 1 W 0.01 W à 0.5 W
taille des données 20 octets

Une trame Bluetooth LE a le profile suivant.


Bluetooth stack.png

On se servira du champs contenant la puissance du signal pour estimer la distance à laquelle l'utilisateur se trouve de la balise. Ensuite par triangularisation, on pourra déterminer la position approximative de l'utilisateur dans une salle.

Développement de l'application côté serveur

Comme annoncé, on utilise une Raspberry Pi munie du système d'exploitation Raspbian wheezy et de la stack bluetooth bluez. On rajoute dessus le serveur GATT bleno. Au démarrage de la raspberry, on active le dongle bluetooth à l'aide de la commande : hciconfig hi0 up ensuite, on lance le script du serveur. Ce dernier permet d'envoyer des trames d'advertising tant qu'une connexion n'est pas effectuée avec un périphérique. Lorsque l'on écrit sur le serveur, on récupère directement sur le terminal les données envoyées par le périphérique. (Voir section sur le développement côté mobile) Screenshot emission.png

Développement de l'application mobile

L'application mobile permet à l'utilisateur de découvrir les devices bluetooth aux alentours. Ils apparaissent à l'écran sous forme d'une liste déroulante. L'utilisateur peut alors cliquer sur le device de son pour pouvoir s'y connecter. Après la connexion, l'utilisateur a le choix entre plusieurs profile (correspond aux devices bluetooth). Ces profiles implémentent plusieurs services qui eux même implémentent plusieurs caractéristiques comme le montre la figure ci dessous.


Gatt structure.png


L'utilisateur devra choisir une caractéristique pour pouvoir lire ou écrire sur la Raspberry. Une vue "bench" a également été rajouté pour déterminer la vitesse d'écriture comme le montre la figure ci dessous.

200px



On constate que l'on envoie 7 octets/ms. Pour une image de 200 Ko soit un peu moins de 30 secondes pour traiter un client.

Journal de bord

25 Septembre 2014

Définition des objectifs du projet avec les Encadrants. Récupération d'une parti du matériel nécessaire

Semaine 1

Compréhension de la mise en marche de la RaspberryPi.

Installation du système d'exploitation RASPBIAN sur la carte SD.

Connection en SSH sur la Raspberry grâce au port Ethernet avec le logiciel Putty.


Photo2.png


Semaine 2

Installation de la stack Bluetooth Bluez sur le système Raspbian.

Prise en main des commandes Bluez


Photo1.png


Semaine 3

Mise en fonctionnement de la RaspberryPi en tant que iBeacon à l'aide des commandes Bluez et visualisation sur une application Android "nRF Master Control Panel".

Appliphoto3.jpg


Mise en fonctionnement de la RaspberryPi en tant que iBeacon à l'aide d'un programme javascript (Node.js).

Fichier adv.js :

<source lang="javascript">

   var uuid = 'e2c56db5dffb48d2b060d0f5a71096e0';
   var major = 0;
   var minor = 0;
   var meaquredPower = -59;
   bleno.startAdvertisingIBeacon(uuid, major, minor, measuredPower);

</source>



Après exécution de ce programme sur le terminal de la Raspberry, on récupère sur la même application :


Photoappli22.jpg

Semaine 4

Recherche sur le développement de l'application mobile et recherche sur la création d'un serveur GATT côté Raspberry.

Semaine 5

Pour créer des périphériques BLE disposant de services , nous utilisons bleno, un module Nodejs. Voici le programme serveur utilisé :


   var util = require('util');
   var bleno = require('bleno');
   var BlenoPrimaryService = bleno.PrimaryService;
   var BlenoCharacteristic = bleno.Characteristic;
   var BlenoDescriptor = bleno.Descriptor;
   console.log('bleno');
   var StaticReadOnlyCharacteristic = function() {
   StaticReadOnlyCharacteristic.super_.call(this, {
   uuid: 'fffffffffffffffffffffffffffffff1',
   properties: ['read'],
   value: new Buffer('armagan'),
   descriptors: [
   new BlenoDescriptor({
   uuid: '2901',
   value: 'user description'
   })
   ]
   });
   };
   util.inherits(StaticReadOnlyCharacteristic, BlenoCharacteristic);


   var DynamicReadOnlyCharacteristic = function() {
   DynamicReadOnlyCharacteristic.super_.call(this, {
   uuid: 'fffffffffffffffffffffffffffffff2',
   properties: ['read']
   });
   };
   util.inherits(DynamicReadOnlyCharacteristic, BlenoCharacteristic);
   DynamicReadOnlyCharacteristic.prototype.onReadRequest = function(offset, callback) {
   var result = this.RESULT_SUCCESS;
   var data = new Buffer('kevin');
   if (offset > data.length) {
   result = this.RESULT_INVALID_OFFSET;
   data = null;
   }
   callback(result, data);
   };
   var WriteOnlyCharacteristic = function() {
   WriteOnlyCharacteristic.super_.call(this, {
   uuid: 'fffffffffffffffffffffffffffffff3',
   properties: ['write', 'writeWithoutResponse']
   });
   };
   util.inherits(WriteOnlyCharacteristic, BlenoCharacteristic);
   WriteOnlyCharacteristic.prototype.onWriteRequest = function(data, offset, withoutResponse, callback) {
   console.log('WriteOnlyCharacteristic write request: ' + data.toString() + ' ' + offset + ' ' + withoutResponse);
   callback(this.RESULT_SUCCESS);
   };
   var NotifyOnlyCharacteristic = function() {
   NotifyOnlyCharacteristic.super_.call(this, {
   uuid: 'fffffffffffffffffffffffffffffff4',
   properties: ['notify']
   });
   };
   util.inherits(NotifyOnlyCharacteristic, BlenoCharacteristic);
   NotifyOnlyCharacteristic.prototype.onSubscribe = function(maxValueSize, updateValueCallback) {
   console.log('NotifyOnlyCharacteristic subscribe');
   this.counter = 0;
   this.changeInterval = setInterval(function() {
   var data = new Buffer(4);
   data.writeUInt32LE(this.counter, 0);
   console.log('NotifyOnlyCharacteristic update value: ' + this.counter);
   updateValueCallback(data);
   this.counter++;
   }.bind(this), 5000);
   };
   NotifyOnlyCharacteristic.prototype.onUnsubscribe = function() {
   console.log('NotifyOnlyCharacteristic unsubscribe');
   if (this.changeInterval) {
   clearInterval(this.changeInterval);
   this.changeInterval = null;
   }
   };
   NotifyOnlyCharacteristic.prototype.onNotify = function() {
   console.log('NotifyOnlyCharacteristic on notify');
   };
   function SampleService() {
   SampleService.super_.call(this, {
   uuid: 'fffffffffffffffffffffffffffffff0',
   characteristics: [
   new StaticReadOnlyCharacteristic(),
   new DynamicReadOnlyCharacteristic(),
   new WriteOnlyCharacteristic(),
   new NotifyOnlyCharacteristic
   ]
   });
   }
   util.inherits(SampleService, BlenoPrimaryService);
   bleno.on('stateChange', function(state) {
   console.log('on -> stateChange: ' + state);
   if (state === 'poweredOn') {
   bleno.startAdvertising('RaspberryPi', ['fffffffffffffffffffffffffffffff0']);
   } else {
   bleno.stopAdvertising();
   }
   });
   // Linux only events /////////////////
   bleno.on('accept', function(clientAddress) {
   console.log('on -> accept, client: ' + clientAddress);
   if (bleno.updateRssi) {
   bleno.updateRssi();
   }
   });
   bleno.on('disconnect', function(clientAddress) {
   console.log('on -> disconnect, client: ' + clientAddress);
   });
   bleno.on('rssiUpdate', function(rssi) {
   console.log('on -> rssiUpdate: ' + rssi);
   });
   //////////////////////////////////////
   bleno.on('advertisingStart', function(error) {
   console.log('on -> advertisingStart: ' + (error ? 'error ' + error : 'success'));
   if (!error) {
   bleno.setServices([
   new SampleService()
   ]);
   }
   });
   bleno.on('advertisingStop', function() {
   console.log('on -> advertisingStop');
   });
   bleno.on('servicesSet', function() {
   console.log('on -> servicesSet');
   });
   


Semaine 6


Après des recherches à propos du Bluetooth Low Energy sur Android, nous nous sommes basés sur le projet opensource disponible ici : [[1]]

Ce projet-ci permet de base de détecter les appareils BLE et de se connecter sur l'un de ces appareils. Après connection, nous avons accès aux services et aux caractéristiques disponible. Seulement la fonctionnalité Read est implémentée dans l'application. Notre but étant de pouvoir envoyer des informations vers le serveur GATT de la Raspberry, c'est à dire écrire (Write) sur les caractéristiques des services proposées par le serveur.


Semaine 7

Implémentation de la fonctionnalité "Ecrire" (Write) dans l'application. Selon les propriétés des caractéristiques proposées , un bouton Write ou Read apparaît. Lors de l'appui sur le bouton Write, une fenêtre de dialoge s'ouvre où l'utilisateur peut renseigner son nom et prénom et envoyer ses informations vers la Raspberry. Lors de l'appui sur le bouton Read, la valeur de la caractéristique d'affiche.


18 Novembre

Impossible de connecter plusieurs appareils en même temps. premiers bench de transmission sur la raspberry réalisé.

Bibliographie et liens

  • Getting Started with Bluetooth Low Energy, Tools and Techniques for Low-Power Networking By Kevin Townsend, Carles Cufí, Akiba, Robert Davidson, Publisher: O'Reilly Media [2]
  • Adafruit, pibeacon [3]

Matériel

* 1 RaspberryPi
* 1 Dongle Bluetooth 4.0
* 1 Samsung Galaxy Tab4
* 1 Portable Samsung GS3