Loupe

Afficher les prochains départs de ma gare RER/SNCF sur mon #Microsoft #Band

Dans cet article j’expliquerais comment créer une tuile supplémentaire pour votre Microsoft Band (v1 ou v2). Cette tuile permettra d’afficher les prochains passages de train dans votre gare SNCF préférée.

 

La démarche

Depuis quelque temps, Microsoft permet de créer via un assistant une tuile supplémentaire sur votre Microsoft Band en utilisant simplement un flux XML/JSON ou RSS.

Pour réaliser mon objectif je vais donc :

  • Utiliser les données temps réel fournies par la SNCF,
  • Créer un mini site-web que j’hébergerais facilement dans Azure pour exposer les données de façon “lisible”
  • Utiliser une Web API de ce site pour créer une WebTile pour le Microsoft Band.

Récupération des données

Pour récupérer les données je vais utiliser l’API de la SNCF et la première des actions est bien sûr de demander un username / password afin de pouvoir y accéder. Les personnes en charge sont vraiment très rapides pour vous répondre !

Je vais ensuite utiliser un HttpClient pour faire une requête en utilisant comme paramètre un identifiant unique de ma gare.

Cet identifiant correspond au code UIC facilement trouvable sur ce site de la SNCF : https://ressources.data.sncf.com/explore/dataset/sncf-gares-et-arrets-transilien-ile-de-france/?tab=table.

 

Pour créer le modèle à déserialiser, j’ai effectué une fois la requête à la main et j’ai utilisé le “paste special / as XML” de Visual Studio pour me générer en un clic les classes. J’utilise ensuite un XMLSerialiser classique.

 

private static async Task<passages> RetrievePassageAsync(string trainStationUICCode)
{
    var client = new HttpClient();

    // Conseillé dans la documentation
    client.DefaultRequestHeaders.Accept
        .ParseAdd("application/vnd.sncf.transilien.od.depart+xml;vers=1.0");

    //Création des informations de connexion
    var username = "user";
    var password = "pass";

    var byteArray = Encoding.ASCII.GetBytes(username + ":" + password);
    client.DefaultRequestHeaders.Authorization
        = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(byteArray));

    // Requete au serveur SNCF
    var uri = "http://api.transilien.com/gare/" + trainStationUICCode + "/depart/";

    var response = await client.GetAsync(uri);

    response.EnsureSuccessStatusCode();

    // lecture en tant que stream
    var responseAsString = await response.Content.ReadAsStringAsync();
    var memStream = new MemoryStream(Encoding.UTF8.GetBytes(responseAsString));

    // deserialization
    var serializer = new XmlSerializer(typeof (passages));
    var result = (passages) serializer.Deserialize(memStream);
    return result;
}

Attention de bien respecter la case lors de l’appel du service SNCF !

 

Le nombre d’appel à l’API est limité (20 appels par minute) et je vais donc mettre en place un cache au niveau serveur pour respecter ce besoin.

//Lecture dans le cache
var cacheContent = HttpContext.Current.Cache
    .Get(trainStationUICCode) as passages;

if (cacheContent != null)
{
    return Request.CreateResponse(HttpStatusCode.OK, cacheContent);
}

// appel effectif
var result = await RetrievePassageAsync(trainStationUICCode);

//Stockage pour plus tard.
HttpContext.Current.Cache
    .Add(trainStationUICCode, result, null, 
    DateTime.Now.AddSeconds(3), Cache.NoSlidingExpiration, CacheItemPriority.Normal, null);

 

Le rendu dans un navigateur est alors le suivant :

gare1

 

 

Exposition des données

L’assistant du site de création des WebTiles peut prendre en entrée l’XML correspondant à ma gare mais en choisissant cette solution je vais devoir créer chacune des pages en prenant les résultats un à un… ce qui est fastidieux.

Je vais donc exposer un flux RSS directement compréhensible par le wizard. J’en profite aussi pour calculer quelques propriétés sur les données entrantes (heure, est en retard).

// Création des éléments de flux
var feedItems = new List<SyndicationItem>();

foreach (var passagesTrain in result.train)
{
    passagesTrain.date.Time = passagesTrain.date
        .Value.Split(' ').LastOrDefault();

    if (string.IsNullOrEmpty(passagesTrain.etat))
    {
        passagesTrain.etat = "A L'HEURE";
        passagesTrain.EnRetard = false;
    }
    else
    {
        passagesTrain.etat = passagesTrain.etat.ToUpperInvariant();
        passagesTrain.EnRetard = true;
    }

    var feedItem = new SyndicationItem(
        // titre
        passagesTrain.date.Time + " - " + passagesTrain.miss,

        //contenu
        passagesTrain.etat,

        //lien alternatif
        new Uri(Request.Headers.Host, UriKind.RelativeOrAbsolute));
    feedItem.Summary 
        = new TextSyndicationContent(passagesTrain.EnRetard.ToString());

    feedItems.Add(feedItem);
}

// formattage RSS
var formatter = new Rss20FeedFormatter(new SyndicationFeed(feedItems));
var xws = new XmlWriterSettings { Encoding = Encoding.UTF8, Async = true };
var stringBuilder = new StringBuilder();
using (var xmlWriter = XmlWriter.Create(stringBuilder, xws))
{
    formatter.WriteTo(xmlWriter);
    await xmlWriter.FlushAsync();
}

// Création de la réponse HTTP
var responseMessage = new HttpResponseMessage(HttpStatusCode.OK);
responseMessage.Content
     = new StringContent(stringBuilder.ToString(), Encoding.UTF8);
responseMessage.Content.Headers.ContentType 
    = new MediaTypeHeaderValue("application/rss+xml");

return responseMessage;

 

Création de la Web Tile

La création de la WebTile se passe alors sur l’assistant Microsoft à cette adresse : https://developer.microsoftband.com/WebTile (clic clic clic comme disent les développeurs Sharepoint :p - Je rigole Gat !)

 

On commence par cliquer sur “Get Started” :

gare2

 

 

 

On choisit ensuite le type de source de données : dans notre cas c’est une “Feed tile” car elle est branchées sur un flux RSS. On choisit ensuite le template d’élément à afficher.

gare3

 

 

Sur la page suivante on indique simplement l’URL du flux RSS. La page suivante est plus intéressante car elle permet de construire l’affichage de votre application. Il faut glisser déposer les champs sur la représentation d’une page de votre Microsoft Band. Vous pouvez combiner des champs et ajouter du texte à la main. Pas la peine non plus de tous les remplir.

gare4

 

La page suivante permet de configurer des notifications à afficher sur des déclencheurs à indiquer à la main. Il faut cliquer sur le “+” pour en ajouter et il n’y a pas de limites à priori. Ici j’ajoute une notification si mon train est en retard. Les textes de la notification et les conditions peuvent être définies en glissant déposant les champs du flux RSS. Cela tombe bien, la description est un booleen indiquant si le train est en retard ! Attention, l’assistant n’a pas l’air d’aimer les valeurs avec des apostrophes : impossible de l’ajouter sur votre band si vous en mettez (par exemple si vous utilisez le texte “À L’HEURE”).

gare5

 

 

La dernière page permet de configurer l’application en elle même.

gare6

 

 

Déploiement sur le band

C’est la partie la plus simple ! Il s’agit d’un fichier “.webtile” que vous pouvez :

  1. mettre sur votre site web et ouvrir depuis un navigateur,
  2. copier-coller sur votre téléphone et ouvrir via l’explorateur de fichiers,
  3. Vous l’envoyer par mail!

Une fois ouverte, l’application Health se lance et vous propose de l’installer. Si votre service demande une authentification (basique) les identifiants seront demandés à ce moment (mais cela ne nous concerne pas ici).

 

Mais le problème c’est que…

L’intervalle de rafraichissement des données minimum est de 15 minutes et la valeur par défaut est de 30 minutes. Ce n’est pas assez et il faudra donc trouver une autre solution pour moi.

Cependant, si vous voulez le configurer, il faut aller ouvrir le fichier webtile produit par l’assistant (c’est un ZIP) et modifier le fichier “manifest.json” pour modifier la propriété “"refreshIntervalMinutes”.

gare8

 

 

 

Vous remarquerez au passage qu’une WebTile, ce n’est rien d’autre qu’un fichier de configuration et ses ressources (icônes) dans un ZIP :)

 

WP_20151117_13_24_45_Pro_LI

Photo de profil

Ces billets pourraient aussi vous intéresser

Vous nous direz ?!

Commentaires

comments powered by Disqus