[Window 8.1 / WP 8.1] Utiliser le Bluetooth Low Energy avec vos app mobiles
1. Présentation
LE BLE
Pour rappel, le BLE (Bluetooth Low Energy) ou Bluetooth Smart est une technologie implémentée dans certains nouveaux appareils et qui optimise la consommation de batterie. Autre chose que l’on sait peu, c’est que ces appareils peuvent également servir de client et/ou serveur GATT. En mode serveur, cela signifie que l’appareil expose certains services, et qu’il les consomme s’il est client.
Windows 8.1 et Windows Phone 8.1
Dans les applications destinées au Store, il est désormais possible de gérer les communications avec les appareils BLE.
Mes premiers essais avec le BLE ont commencé avec la souris Arc Touch Mouse (Surface Edition) mais peu de services étaient disponibles et ceux-ci avaient une utilité limitée pour des scenarios complexes.
Je me suis donc tourné vers le Sensor Tag CC2541 de Texas Instrument qui n’est pas très cher et permet de commencer rapidement à jouer. De plus la documentation du fabricant est très complète (cf: http://processors.wiki.ti.com/images/a/a8/BLE_SensorTag_GATT_Server.pdf).
Il contient 6 capteurs : un accéléromètre, un magnétomètre, un gyroscope, des capteur d’humidité, de température, de pression et expose les services associés.
2. Let’s code
Dans cet article je vais vous montrer comment intégrer quelques fonctionnalités de consommation des services GATT du Sensor Tag. Les exemples de codes sont identiques que vous soyez dans une application Windows Phone 8.1 ou Windows 8.1. Il est donc possible de créer une Universal App ayant les mêmes fonctionnalités et mutualisant ce code.
Appairage
Appairer son appareil BLE à son device de développement est primordial puisque sans cela vous ne serez pas capable de le “découvrir” même s’il est allumé et positionné à côté.
Pour appairer, allumez votre appareil, allez dans les paramètres Bluetooth de Win8.1 ou WP8.1 et cliquer sur “Pairer”. Pour le Sensor tag, un code vous sera demandé et il s’agit par défaut du 0000.
Le Manifest et la déclaration des services GATT
Une fois vos appareils liés vous pouvez commencer à coder. Pour cela, créer une application Universal (ou pas d’ailleurs) et ouvrez le (ou les) manifests en mode code (via un clic droit).
Dans la partie Capabilities, ajoutez les lignes suivantes :
<Capabilities> <Capability Name="internetClient" /> <m2:DeviceCapability Name="bluetooth.genericAttributeProfile"> <m2:Device Id="any"> <!-- Humidity --> <m2:Function Type="serviceId:F000AA20-0451-4000-B000-000000000000"/> </m2:Device> </m2:DeviceCapability> </Capabilities>
Le service Id F000AA20-0451-4000-B000-000000000000 correspondant au service d’humidité.
Des mots-clés sont disponibles si vous souhaitez utiliser des services plus génériques tels que celui de l’indicateur de batterie si votre device l’expose :
<m2:Function Type="name:battery"/>
Cette étape est indispensable et son oubli peut provoquer de véritables crises de nerfs lors du débug de votre application.
L’initialisation du device
Dans le code behind de la votre MainPage, ajoutez les lignes suivantes :
InitDeviceAsync();
Puis rajoutez la méthode d’initialisation :
private async void InitDeviceAsync() { var serviceUIID = new Guid("F000AA20-0451-4000-B000-000000000000"); //Find the devices that expose the service var devices = await DeviceInformation.FindAllAsync(GattDeviceService.GetDeviceSelectorFromUuid(serviceUIID)); var device = devices.FirstOrDefault(d => d.Name == "TI BLE Sensor Tag"); if (device != null) { //Connect to the service var service = await GattDeviceService.FromIdAsync(device.Id); } }
Ce code utilise le service d’humidité et cherche tous les devices connus (appairés) qui l’exposent. Parmi ceux là nous ne récupérons que celui dont le nom correspond à notre capteur. Nous nous connectons ensuite au service du capteur en question.
Au premier lancement de l’application, l’appel de la méthode await GattDeviceService.FromIdAsync(device.Id); provoquera, sur Windows 8.1, un requête à l’utilisateur. Il doit en effet autoriser l’utilisation du device.
La lecture de données
Une fois le device reconnu et connecté nous allons cibler la caractéristique associée et récupérer toutes les valeurs que le device nous enverra :
if (service == null) return; //Get the service data characteristic var characData = service.GetCharacteristics(characUIID)[0]; //Subcribe value changed characData.ValueChanged += charac_ValueChanged; //Set configuration to notify await characData.WriteClientCharacteristicConfigurationDescriptorAsync(GattClientCharacteristicConfigurationDescriptorValue.Notify); //Get the configuration characteristic var config = service.GetCharacteristics(configUIID)[0]; //Write 1 to start the sensor await config.WriteValueAsync((new byte[] { 1 }).AsBuffer());
Nous pouvons alors lire et interpréter les valeurs retournées par de le device conformément à la documentation fournie par le constructeur :
private async void charac_ValueChanged(GattCharacteristic characteristic, GattValueChangedEventArgs args) { int a = await ShortUnsignedAtOffset(characteristic, 2); a = a - (a % 4); var humidityValue = ((-6f) + 125f * (a / 65535f)); Debug.WriteLine("Humidity : {0}", (humidityValue/100).ToString("P")); } private static async Task<int> ShortUnsignedAtOffset(GattCharacteristic characteristic, int offset) { var values = (await characteristic.ReadValueAsync()).Value.ToArray(); uint lowerByte = values[offset]; uint upperByte = values[offset + 1]; ; // Note: interpret MSB as signed. var longValue = (upperByte << 8) + lowerByte; return Convert.ToInt32(longValue); }
Relançons l’application et nous voyons alors dans la fenêtre de sortie, les valeurs du taux d’humidité.
Conclusion
Il est relativement facile de prendre en main le BLE et l’unification du code pour les Universal Apps permet de créer des applications dans les 2 Stores très rapidement.
Mais il reste encore quelques défauts :
- Pas de gestion du BLE en background pour nos applications, ce qui limite tout de même grandement son intérêt
- L’appairage reste une barrière pour certains utilisateurs
- Il faut souvent tâtonner pour découvrir les services et caractéristique d’un appareil en l’absence d’une documentation correcte du fabricant.
A vous de jouer.
Edit :
Cet article utilise des Guids de services et caractéristiques, mais si vous souhaitez utiliser des services plus génériques tels que l’indicateur de niveau de batterie, votre code sera moins obscur :
Dans le manifest :
<m2:Function Type="name:battery"/>
Dans votre code, vous pouvez alors récupérer plus aisément les services et caractéristiques :
DeviceInformation.FindAllAsync(GattDeviceService.GetDeviceSelectorFromUuid(GattServiceUuids.Battery)) et service.GetCharacteristics(GattCharacteristicUuids.BatteryLevel)[0];
Testez donc l’auto-complétion pour découvrir les services génériques disponibles.
Commentaires