MSBandMon aimable employeur ayant fort courtoisement accepté de m’envoyer une nouvelle fois au MVP Summit, j’ai pu mettre la main sur un chatoyant Microsoft Band 2, la nouvelle mouture du bracelet connecté de l’éditeur/constructeur, pour la modique somme de 250$ + taxes.

Je vous passe les détails sur les capacités natives du bracelet, mais mes premières impressions sont globalement positives. Tout n’est pas parfait, mais certaines fonctionnalités sont très très sympa. L’objet de cet article est de décrire comment développer et déployer ma première application Microsoft Band, dont toutes les ressources développeur sont regroupées ici.

La première chose à savoir : on ne déploie pas directement d’application sur le bracelet. Aha, intéressant. Mais comment fait-on alors ? Nativement, le bracelet doit être apparié à une application mobile iOS, Android ou Windows, avec laquelle le bracelet dialogue via Bluetooth. Le bracelet n’est donc pas autonome. Ensuite, il existe en réalité 2 façons d’interagir avec le Band :

  • développer une application mobile (iOS, Android ou Windows, donc)
  • utiliser les WebTiles, via l’application Microsoft Health

Dans notre exemple, c’est la deuxième option que nous allons utiliser. Cet article a été très largement inspiré par le post de Scott Hanselman. Les WebTiles sont d’ailleurs son idée. Mais qu’est-ce qu’une WebTile ? En fait, chaque application Band est en fait une tuile accessible via l’interface très simple du device. L’idée est d’utiliser Microsoft Health pour uploader une application rudimentaire, dont les fonctionnalités sont à ce jour extrêmement bridées : lire le contenu d’une API REST (Json ou XML) et afficher son contenu sur le bracelet. Donc ici, pas d’accès au SDK Microsoft Band, simplement la consommation d’une API externe et l’affichage de quelques informations.

Mon besoin fonctionnel est très simple : le comptage de points à la belote est… perturbant pour le néophyte. Je veux donc lui afficher un pense-bête qui lui affiche les infos suivantes :

Valeur à l’atout Valeur non-atout
Valet 20 2
Neuf 14 0
As 11 11
10 10 10
Roi 4 4
Dame 3 3
Huit 0 0
Sept 0 0

 

Pour afficher ces infos à l’utilisateur, il va donc me falloir exposer une API.

Mon service WebApi

Pour exposer mon service, je n’ai besoin que de quelques minutes pour créer mon service ASP.NET WebApi et l’exposer sur Azure WebSites. Le code, lui, est rudimentaire. Mon point d’entrée est une simple méthode Get sans authentification qui renvoie une liste de valeurs.

using System.Collections.Generic;
using System.Web.Http;
using Belote.Engine;

namespace Belote.Api.Controllers
{
 public class CartesController : ApiController
 {
 // GET api/cartes
 public IEnumerable<Valeur> Get()
 {
 return new Valeur[] {
 Valeur.As,
 Valeur.Roi,
 Valeur.Dame,
 Valeur.Valet,
 Valeur.Dix,
 Valeur.Neuf,
 Valeur.Huit,
 Valeur.Sept };
 }
 }
}

Quant à ma classe Valeur, il s’agit d’un simple DTO auquel j’ai ajouté des propriétés statiques pour chacune de mes valeurs :

namespace Belote.Engine
{
 public class Valeur
 {
 public static Valeur Sept => new Valeur { Nom = "Sept", ValeurAtout = 0, ValeurNonAtout = 0 };
 public static Valeur Huit => new Valeur { Nom = "Huit", ValeurAtout = 0, ValeurNonAtout = 0 };
 public static Valeur Neuf => new Valeur { Nom = "Neuf", ValeurAtout = 14, ValeurNonAtout = 0 };
 public static Valeur Dix => new Valeur { Nom = "Dix", ValeurAtout = 10, ValeurNonAtout = 10 };
 public static Valeur Valet => new Valeur { Nom = "Valet", ValeurAtout = 20, ValeurNonAtout = 2 };
 public static Valeur Dame => new Valeur { Nom = "Dame", ValeurAtout = 3, ValeurNonAtout = 3 };
 public static Valeur Roi => new Valeur { Nom = "Roi", ValeurAtout = 4, ValeurNonAtout = 4 };
 public static Valeur As => new Valeur { Nom = "As", ValeurAtout = 11, ValeurNonAtout = 11 };

 public string Nom { get; set; }
 public string Initiale => Nom.Substring(0, 1);
 public int ValeurAtout { get; set; }
 public int ValeurNonAtout { get; set; }

 }
}

J’ai ensuite déployé mon API vers le site http://belote.azurewebsites.net/ que j’ai créé à cet effet. La méthode elle-même est visible à l’adresse suivante : http://belote.azurewebsites.net/api/cartes, qui rend le résultat suivant (si on le demande en Json) :

[
 {"Nom":"As","Initiale":"A","ValeurAtout":11,"ValeurNonAtout":11},
 {"Nom":"Roi","Initiale":"R","ValeurAtout":4,"ValeurNonAtout":4},
 {"Nom":"Dame","Initiale":"D","ValeurAtout":3,"ValeurNonAtout":3},
 {"Nom":"Valet","Initiale":"V","ValeurAtout":20,"ValeurNonAtout":2},
 {"Nom":"Dix","Initiale":"D","ValeurAtout":10,"ValeurNonAtout":10},
 {"Nom":"Neuf","Initiale":"N","ValeurAtout":14,"ValeurNonAtout":0},
 {"Nom":"Huit","Initiale":"H","ValeurAtout":0,"ValeurNonAtout":0},
 {"Nom":"Sept","Initiale":"S","ValeurAtout":0,"ValeurNonAtout":0}
]

Voilà pour la partie service.

Génération de la WebTile

Nous allons maintenant nous attaquer à la partie intéressante, à savoir l’application elle-même et son déploiement vers le Band. La doc se trouve ici, et l’équipe du SDK a mis à disposition un assistant permettant de générer un fichier webtile, dont nous verrons la structure un peu plus tard. Cet assistant permet de générer en 5 étapes le fameux fichier webtile. Les étapes sont les suivantes.

1- Choisir un layout

image

Le premier choix à faire se fait entre :

  • une tuile mono-page : quand l’utilisateur cliquera sur la tuile une unique page sera affichée.
  • une tuile multi-page : même principe que le point précédent, mais l’utilisateur pourra également naviguer entre plusieurs pages (7 maximum)
  • une tuile-flux, permettant de s’abonner à un flux RSS ou ATOM

Nous allons choisir la 2e option, car nous voulons afficher pour chaque valeur de carte le nombre de points atout et non-atout qu’elle vaut, et naviguer entre ces valeurs de carte.

La deuxième option est le layout lui-même :

  • titre + texte scrollable
  • titre + contenu principal + contenu secondaire
  • titre + métrique chiffrée
  • liste de 3 lignes et leurs icônes
  • icône + titre + métrique chiffrée
  • titre principal + titre secondaire + icône large + métrique chiffrée

Il est très possible que cette liste de layouts évolue dans le temps. Pour le moment, nous allons utiliser le layout “titre + contenu principal + contenu secondaire”, afin d’afficher la valeur de la carte (As, Roi, Dame, etc.), le nombre de points qu’elle vaut à l’atout et le nombre de points qu’elle vaut en non-atout.

2- La source de données

image

Nous allons ici donner l’URL de mon service WebApi : http://belote.azurewebsites.net/api/cartes

3- Binding des données avec le layout

image

La vidéo suivante montre comment s’effectue ce binding :

C’est simple. A ceci-près que la génération a l’air encore un peu buggée. Nous y reviendrons quand on étudiera le contenu du fichier webtile.

4- Ajout d’une notification

2015-11-05_22-46-20

 

 

 

 

 

 

 

 

 

 

 

 

Cette étape permet d’envoyer au Band une notification, en fonction des valeurs de résultat renvoyés par le service REST consommé. Nos données étant statiques, nous allons sauter cette étape.

 

5- Les informations sur votre tuile

image

Ce sont les informations générales de votre tuile : nom, description, icône, couleurs…

6- Téléchargement du fichier webtile

image

Et voilà, c’est terminé ! Nous avons maintenant en notre possession un fichier webtile. Mais qu’est-ce que c’est ? Et qu’allons-nous en faire ?

Structure d’un fichier webtile

A l’instar de Nuget et ses fichiers nupkg, un ficher webtile n’est en réalité qu’un fichier zip dont l’extension a été renommée en .webtile. Maintenant que l’on sait ça, on peut l’ouvrir et regarder sous le capot :

image

La structure est donc très simple :

  • un fichier manifest.json qui décrit l’application et donc toutes les informations saisies dans l’assistant.
  • un répertoire icons qui contiendra… nos icônes. Notez que les grosses icônes sont au format png transparent, et font 46*46, les petites 23*23. Et si elles ne sont pas acceptées par le SDK, le Band n’affichera qu’un carré blanc.

Le contenu de notre manifest est le suivant :

{
 "manifestVersion": 1,
 "name": "Belote",
 "description": "Antisèche des valeurs de cartes à la belote",
 "version": 1,
 "versionString": "1",
 "author": "Nicholas Suter",
 "organization": "",
 "contactEmail": "",
 "tileIcon": {
 "46": "icons/tileIcon.png"
 },
 "icons": {},
 "refreshIntervalMinutes": 30,
 "resources": [
 {
 "url": "http://belote.azurewebsites.net/api/cartes",
 "style": "Simple",
 "content": {
 "_1_0nom": "[0].Nom",
 "_1_0valeuratout": "[0].ValeurAtout",
 "_1_0valeurnonatout": "[0].ValeurNonAtout",
 "_1_1nom": "[1].Nom",
 "_1_1valeuratout": "[1].ValeurAtout",
 "_1_1valeurnonatout": "[1].ValeurNonAtout",
 "_1_2nom": "[2].Nom",
 "_1_2valeuratout": "[2].ValeurAtout",
 "_1_2valeurnonatout": "[2].ValeurNonAtout",
 "_1_3nom": "[3].Nom",
 "_1_3valeuratout": "[3].ValeurAtout",
 "_1_3valeurnonatout": "[3].ValeurNonAtout",
 "_1_4nom": "[4].Nom",
 "_1_4valeuratout": "[4].ValeurAtout",
 "_1_4valeurnonatout": "[4].ValeurNonAtout",
 "_1_5nom": "[5].Nom",
 "_1_5valeuratout": "[5].ValeurAtout",
 "_1_5valeurnonatout": "[5].ValeurNonAtout",
 "_1_6nom": "[6].Nom",
 "_1_7nom": "[7].Nom",
 "_1_6valeuratout": "[6].ValeurAtout",
 "_1_6valeurnonatout": "[6].ValeurNonAtout"
 }
 }
 ],
 "pages": [
 {
 "layout": "MSBand_NoScrollingText",
 "condition": "true",
 "textBindings": [
 {
 "elementId": "1",
 "value": "{{_1_0nom}}"
 },
 {
 "elementId": "2",
 "value": "Valeur atout : {{_1_0valeuratout}}"
 },
 {
 "elementId": "3",
 "value": "Valeur non-atout : {{_1_0valeurnonatout}}"
 }
 ]
 },
 {
 "layout": "MSBand_NoScrollingText",
 "condition": "true",
 "textBindings": [
 {
 "elementId": "1",
 "value": "{{_1_1nom}}"
 },
 {
 "elementId": "2",
 "value": "Valeur atout : {{_1_1valeuratout}}"
 },
 {
 "elementId": "3",
 "value": "Valeur non-atout : {{_1_1valeurnonatout}}"
 }
 ]
 },
 {
 "layout": "MSBand_NoScrollingText",
 "condition": "true",
 "textBindings": [
 {
 "elementId": "1",
 "value": "{{_1_2nom}}"
 },
 {
 "elementId": "2",
 "value": "Valeur atout : {{_1_2valeuratout}}"
 },
 {
 "elementId": "3",
 "value": "Valeur non-atout : {{_1_2valeurnonatout}}"
 }
 ]
 },
 {
 "layout": "MSBand_NoScrollingText",
 "condition": "true",
 "textBindings": [
 {
 "elementId": "1",
 "value": "{{_1_3nom}}"
 },
 {
 "elementId": "2",
 "value": "Valeur atout : {{_1_3valeuratout}}"
 },
 {
 "elementId": "3",
 "value": "Valeur non-atout : {{_1_3valeurnonatout}}"
 }
 ]
 },
 {
 "layout": "MSBand_NoScrollingText",
 "condition": "true",
 "textBindings": [
 {
 "elementId": "1",
 "value": "{{_1_4nom}}"
 },
 {
 "elementId": "2",
 "value": "Valeur atout : {{_1_4valeuratout}}"
 },
 {
 "elementId": "3",
 "value": "Valeur non-atout : {{_1_4valeurnonatout}}"
 }
 ]
 },
 {
 "layout": "MSBand_NoScrollingText",
 "condition": "true",
 "textBindings": [
 {
 "elementId": "1",
 "value": "{{_1_5nom}}"
 },
 {
 "elementId": "2",
 "value": "Valeur atout : {{_1_5valeuratout}}"
 },
 {
 "elementId": "3",
 "value": "Valeur non-atout : {{_1_5valeurnonatout}}"
 }
 ]
 },
 {
 "layout": "MSBand_NoScrollingText",
 "condition": "true",
 "textBindings": [
 {
 "elementId": "1",
 "value": "{{_1_6nom}} - {{_1_7nom}}"
 },
 {
 "elementId": "2",
 "value": "Valeur atout : {{_1_6valeuratout}}"
 },
 {
 "elementId": "3",
 "value": "Valeur non-atout : {{_1_6valeurnonatout}}"
 }
 ]
 }
 ]
}

Ce fichier contient 3 sections :

  • les informations globales à mon application, que j’ai saisies sur la dernière étape de l’assistant
  • un objet ressources, où sont déclarées l’URL de mon service REST, ainsi que la déclaration de variables _1_0nom, _1_0valeuratout, _1_0valeurnonatout, etc. et le mapping vers les valeurs retournées par mon service REST.
  • une liste de pages. Chaque page ayant un type de layout, et des bindings vers les variables décrites ci-dessus.

Il est donc parfaitement possible d’écrire nous-même un manifeste, ou encore mieux, de le générer. Je vous ai d’ailleurs dit plus haut que le fichier webtile généré par l’assistant était buggé. En réalité, le manifeste généré n’était pas tout à fait correct. J’ai dû reprendre à la main certaines propriétés value des bindings de mes pages, qui avaient sauté. Rien de grave, mais ça vaut le coup de vérifier le manifeste avant de l’uploader.

Uploader la Webtile sur le bracelet

La dernière étape consiste à installer l’application sur le Band. La procédure est encore rudimentaire, mais elle a le mérite d’être extrêmement simple. Dans mon cas, j’utilise Microsoft Health sur iOS. Pour commencer, il faut rendre accessible mon fichier webtile sur mon téléphone. Plusieurs possibilités : par mail, tout simplement, ou alors via un service type Dropbox, OneDrive…

Ouvrir le fichier webtile avec Microsoft Health

J’ai choisi de m’envoyer le fichier par mail. Depuis le client mail, j’ouvre le fichier avec Microsoft Health :

imageimageIMG_3041

IMG_3042IMG_3043IMG_3045

Et voilà !

Conclusion

Voilà, ma première application Microsoft Band est déployée. Et même si j’ai fortement détaillé toutes les opérations, ça ne prend en réalité que quelques minutes. Ici, nous n’avons vu que les WebTiles, qui n’exploitent aucune des fonctionnalités du bracelet. Et les limitations sont contraignantes. Je pense notamment à cette limitation à 7 écrans. Cela dit, je n’ai pas regardé si c’était une limitation de l’assistant ou du SDK lui-même. En revanche, ce qu’on peut imaginer, c’est de tirer profit des fonctionnalités de Cloud Api, qui propose des API Rest pour consommer les données remontées par le Band.

Et après, il y a le SDK et les applis mobiles. Et ça c’est une autre histoire.