Écrit par Laurent Ellerbach en Juin 2015
J’ai la chance de faire partie des beta-testeurs de la plateforme Constellation développé par Sébastien Warin. J’utilise cette plateforme pour orchestrer des services que je fais tourner sur des serveurs répartis à travers la France et dans Microsoft Azure.
La Constellation fonctionne à la fois sous Windows et Linux me permettant de connecter des RaspberryPi v1 tournant sur lesquels j’ai installé Mono. Un de ces boards me permet de gérer une serre qui se trouve dans le jardin. J’ai aussi des Netduino tournant sous .NET Microframework (implémentation open source d’un sous ensemble de .NET et tournant directement sur des processeurs sans OS). Sur un de ces Netduino, j’ai une carte de prototypage GSM Quectel M95 que j’utilise comme passerelle SMS avec un abonnement free à 2€.
La grande difficulté est la gestion de la réception et l’émission de SMS, tout se faisant en port série avec des commandes AT. Beaucoup de « plaisir » à faire fonctionner tout cela. Pour avoir un minimum de sécurité, je gère directement dans le board les numéros de téléphones autorisés ainsi que leur niveau d’accréditation. Après ce premier niveau de sécurité, pour des commandes avancées, un code de sécurité aléatoire est renvoyé, le message doit ensuite être renvoyé. Il est en effet possible de spoofer un SMS facilement, mais la réponse à l’expéditeur arrive toujours au numéro d’envoi. Cela me permet de gérer un très bon niveau de sécurité.
Comme il existe différente API pour se connecter à la Constellation, en .NET, Python, Javascript ou bien .NET Microframework, je peux facilement connecter mon board dans ma Constellation.
La Constellation me permet, au démarrage du board ou à chaque fois que je fais une mise à jour des paramètres sur le serveur de recevoir automatiquement les nouveaux settings. Au niveau du code, rien de plus simple :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
ConstellationProxy constellation = new ConstellationProxy("http://ipserver:port", "clédesurité", "NOMDUBOARD", "Notif"); constellation.SettingsReceived += constellation_SettingsReceived; constellation.RequestSettings(); static void constellation_SettingsReceived(System.Collections.Hashtable settings) { // Numéros de téléphones if (settings.Contains("PhoneNumbers")) { AuthorisedNumbers = settings["PhoneNumbers"].ToString().Split(';'); } //Privilèges d'access if (settings.Contains("Access")) { Access = settings["Access"].ToString().Split(';'); } } |
Constellation fourni une dll délivrée par Nuget permettant d’y avoir accès, une fois connecté et initialisé, il est possible de récupérer les paramètres dont j’ai besoin, dans mon cas, les numéros de téléphones et les privilèges d’accès.
A chaque SMS reçu et validé, j’envoie un message au groupe « SMS » qui a 3 propriétés, From (le numéro de téléphone de l’expéditeur), le Message (le corps du SMS) et le moment où le SMS a été reçu
1 |
constellation.SendMessage(new Scope(ScopeType.Group, "SMS"), "ReceiveSMS", new SMSNotif.SMS { From = mySMS.From, Message = mySMS.Message, Date = mySMS.Date }); |
J’ai d’autres packages tournant sur l’autres machines qui peuvent s’abonner à ce groupe et donc recevoir un événement lors de la réception d’un SMS. Leur consommation est également triviale :
1 2 3 4 5 6 7 |
[MessageCallback] public void ReceiveSMS(dynamic mySMS) { // Récupération des propriétés de l'objet string From = (string)mySMS.From; string Message = (string)mySMS.Message; } |
Quel rapport avec mon Nabaztag ?
C’est là que les choses deviennent intéressantes. Beaucoup se souviennent certainement des Nabaztag, ces lapins super sympas et connectés. Précurseurs des objets connectés, la société qui les a créée n’a malheureusement pas survécu. Mais le code des lapins a été publiés et on a vu des quelques serveurs s’ouvrir pour leur apporter une nouvelle vie.
J’utilise openJabNab.fr qui est géré par un groupe de passionnés et offrent un service de qualité proposant des API. Et c’est notamment cet aspect qui m’intéressait particulièrement. En effet, je compte utiliser la seconde vie de mon Nabaztag pour les notifications de ma Constellation.
Pour ce faire, il est nécessaire de paramétrer son Lapin en créant un compte, la manipulation est vraiment simple et rapide. Il faut ensuite activer des plugins. Celui que je vais utiliser est très simple, c’est le “Plugin TTS, envoi de texte au lapin”, son nom court est “tts”. Nous en aurons besoin. En regardant rapidement la documentation, la fonction est “say” et prends le paramètre “text” en entrée.
Le fonctionnement de l’ensemble des API est similaire, il faut d’abord récupérer un token puis l’utiliser dans l’appel de l’API. L’appel à l’URL suivante en remplaçant mylogin et mypassword par le login et mot de passe, retourne ensuite un XML.
http://openjabnab.fr/ojn_api/accounts/auth?login=mylogin&pass=myPassword
En cas d’erreur:
1 2 3 4 |
<?xml version="1.0" encoding="UTF-8"?> <api> <error>Access denied</error> </api> |
En cas de succès:
1 2 3 4 |
<?xml version="1.0" encoding="UTF-8"?> <api> <value>77a18144bb6adefbe29afdb16fb5e3ed</value> </api> |
Le token est la valeur value. L’appel de l’API text to speech se fait ensuite de la façon suivante:
L’adresse MAC du lapin doit être positionnée à la place de la chaîne 0123456789ab. Le texte qui sera lu sur le Nabaztag sera donc “je suis une lapine qui aime les lapins”. Vous recevez également une confirmation de ce type:
1 2 3 4 |
<?xml version="1.0" encoding="UTF-8"?> <api> <ok>Envoi de 'je suis une lapine qui aime les lapins' au lapin '0123456789ab'</ok> </api> |
Pour créer un Package, il suffit de créer un projet Constellation après l’installation du SDK Constellation pour Visual Studio.
Nous allons ensuite ajouter 4 settings, pour le login et mots de passe ainsi que pour les lapins. Je possède plusieurs Lapin et plutôt que de les appeler par leur adresse MAC, j’utilise un nom, je vais donc utiliser de façon vraiment simple un string contenant les noms séparés par des point-virgules et faire la même chose pour les adresses MAC. Côté des variables, lors de la lecture des settings, je stocke les informations dans des string et tableau de string:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
private string myLogin; private string myPassword; private string[] MACaddresses; private string[] FriendlyNames; private void UpdateSettings() { myLogin = PackageHost.GetSettingValue<string>("Login"); myPassword = PackageHost.GetSettingValue<string>("Password"); MACaddresses = PackageHost.GetSettingValue<string>("MACs").Split(';'); FriendlyNames = PackageHost.GetSettingValue<string>("Friendlys").Split(';'); PackageHost.WriteInfo("Package NabaztagNotif updated"); } |
Ensuite, je crée ma fonction de call back que j’appellerais depuis un autre package quand je voudrais envoyer un texte à mon lapin:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
[MessageCallback] public void Say(string MACaddress, string texttosend) { Try { WebClient instanceHTTP = new WebClient(); string strReq = "http://openjabnab.fr/ojn_api/accounts/auth?login=" + myLogin + "&pass=" + myPassword; Uri MyURI = new Uri(strReq); string retval = instanceHTTP.DownloadString(MyURI); // Recherche du mot "value" contenu dans le XML renvoyé if (retval.Contains("value")) { int start = retval.IndexOf("<value>"); int end = retval.IndexOf("</value>"); string token = retval.Substring(start + 7, end - start - 7); strReq = "http://openjabnab.fr/ojn_api/bunny/" + MACaddress + "/tts/say?text=" + WebUtility.HtmlEncode(texttosend) + "&token=" + token; MyURI = new Uri(strReq); retval = instanceHTTP.DownloadString(MyURI); if (retval.Contains("<ok>")) PackageHost.WriteInfo("Success sending message to Nabaztag {0}", nabaztagname); else PackageHost.WriteError("Error sending message to Nabaztag {0}", nabaztagname); } else { PackageHost.WriteError("Error sending message to Nabaztag {0}, error: authentication", nabaztagname); } } catch (Exception ex) { PackageHost.WriteError("Error sending message to Nabaztag {0}, error: {1}", nabaztagname, ex.ToString()); } } |
Il considère que le login et le mot de passe ont déjà été encodé pour l’URL. Il est nécessaire d’utiliser la fonction WebUtility.HtmlEncode s’ils ne le sont pas dans vos settings.
L’appel se fait de façon tout à fait classique comme cela (en considérant que le nom du package est “NabaztagNotif”):
1 |
PackageHost.CreateScope("NabaztagNotif").Proxy.Say("monlapin", “je suis un lapin qui aime les lapines”); |
Comme notre package est connecté à la Constellation, une simple page Javascript ou un script Python ou Powershell peuvent également envoyer des messages à notre Nabaztag.
Pour ma part, depuis mon board et l’API Constellation pour NETMF, à la réception de SMS, j’envoie un message au package NabaztagNotif me permettant de lire les SMS reçus.
Voilà un exemple d’utilisation de Constellation mais aussi d’API permettant de faire revivre vaux lapins.
Bon lapinage 🙂
Laurent Ellerbach, Evangelist Lead, Central and Eastern Europe, Microsoft
Démarrez la discussion sur le forum Constellation