Etant donné que chaque package peut (et devrait) déclarer la liste des MessageCallbacks détaillée (description, liste des paramètres, type de réponse, …) qu’il expose ainsi que la liste des types personnalisées qu’il utilise dans la signature de ses MessageCallbacks ou des StateObjects qu’il publie, il est donc possible de générer du code de manière automatique.

C’est grâce à cette description, que l’on nomme le “PackageDescriptor” que fonctionne le “MessageCallback Explorer” de la Console Constellation par exemple.

image

L’interface est capable de lister chaque MessageCallbacks  de chaque packages de votre Constellation avec un formulaire pour la saisie des paramètres (simples ou complexes) afin de tester simplement vos MC.

En cliquant sur le bouton image, le “MessageCallback Explorer” de la Console Constellation vous propose des “code snippets” pour différents langages (C#, Python, Arduino, JS, etc.).

image

Pourquoi générer du code ?

Comme vous le savez, en C# pour envoyer un message et donc invoquer un MC d’un autre package, vous devez créer un scope et invoquer le MC en utilisant un proxy dynamique.

Par exemple pour invoquer le MC “AreaArm” du package Paradox, on pourrait écrire :

Il est important de noter ici que la méthode “CreateMessageProxy” retourne un “proxy dynamique”, c’est à dire que la méthode invoquée, ici “AreaArm” sera la clé du message.

Autrement dit, comme tout est dynamique, il y a aucune aide ou auto-complétion. On pourrait très bien écrire ceci :

Votre package enverra un message “CeciEstUnExemple” au(x) package(s) Paradox de votre Constellation. Vous devez donc être vigilent sur le nom des MC invoqués car une erreur de frappe passera inaperçu !

Pour plus d’information sur l’envoi de messages & invocation de MessageCallbacks en C#, veuillez lire ceci.

Le “problème” est le même avec la consommation des StateObjects (lire ceci). Par exemple pour injecter dans votre code, le StateObject “/intelcpu/0/load/0” produit par le package “HWMonitor” sur la sentinelle “MON-PC”, on peut écrire :

Je peux donc ensuite exploiter la valeur de mon StateObject :

La propriété “Value” du StateObjectNotifier  me donne la valeur du StateObject et la propriété “Value” de ce StateObject me donne la valeur du StateObject. Vous pouvez utiliser la propriété “DynamicValue” directement sur le StateObjectNotifier  pour récupérer la valeur du SO sous forme d’un ”dynamic”.

Comme chaque StateObject est différent, je ne sais pas ne que je trouverai dedans (une valeur simple, un objet complexe, …). D’où l’intérêt d’utiliser le StateObject Explorer de la Console Constellation pour explorer les SO de votre Constellation.

Par exemple, le StateObject “/intelcpu/0/load/0” produit par le package “HWMonitor” est un objet complexe contenant 4 propriétés :

image

Alors que le StateObject de type “CarbonDioxideMeasurement” produit par le package “NetAtmo” est un entier :

image

C’est pour cela que dans votre code, la valeur d’un StateObject est “dynamique” : tout dépend du StateObject que vous consommez !

Que ce soit pour l’invocation de MessageCallback ou la consommation de StateObject, la forme “dynamique” permet de s’adapter à toutes les situations. En revanche vous perdez l’auto complétion ce qui peut vous ralentir mais aussi être une source d’erreur. D’où l’intérêt de générer du code dans votre package!

Générer du code depuis Visual Studio.

Le générateur de code inclut dans le SDK Constellation pour Visual Studio ne fonctionne que pour un projet C#.

Commencez tout d’abord par cliquer le bouton image “Generate Code” dans la barre de menu :

image

Le code sera généré pour le projet marqué comme projet de démarrage dans le cas où votre solution contient plusieurs projets.

Autrement, en cliquant-droit sur le projet de votre choix, sélectionnez “Generate Code” dans le sous-menu “Constellation” :

image

Vous serez amené à sélectionner dans la liste déroulante la Constellation à cibler. Pour configurer des connexions vers vos Constellations, lisez ceci.

Une fois le serveur Constellation sélectionné, cliquez sur “Connect and Discover”. Vous obtiendrez la liste de toutes vos sentinelles et packages de votre Constellation :

image

Sélectionnez tout simplement la liste des packages que vous souhaitez inclure dans votre code. Par exemple, ici nous allons générer du code pour les packages “DoorBell”, “LightSensor”, “IRRemote”,”Paradox”, “Pionner” et “Vera”.

Après avoir cliqué sur le bouton “Generate”, un message de confirmation vous indiquera le bon déroulé de l’opération :

image

Le SDK génère le code dans le fichier “MyConstellation.generated.cs” :

image

Attention, vous ne devez pas modifier ce code directement car ce fichier est écrasé à chaque fois que vous relancer une génération.

image

Utiliser le code généré

Organisation du code généré

Le code généré dans le fichier “MyConstellation.generated.cs” s’organise dans plusieurs espaces de nom (namespaces) :

  • Dans le namespace de votre assembly vous trouverez :
    • La classe statique “MyConstellation” représentant votre Constellation
    • Les classes utilitaires RealNameAttribute et RealNameExtension indispensable au fonctionnement du code généré
  • Des namespaces par package
    • VotreNamespace.NomDuPackage.StateObjects : code généré pour les StateObjects (si des StateObjects sont déclarés pour le package)
    • VotreNamespace.NomDuPackage.MessageCallbacks : code généré pour les MessageCallbacks (si des MessageCallbacks sont déclarés pour le package)

image

Des énumérations pour les sentinelles, packages et instances de votre Constellation

La classe statique “MyConstellation” contient trois énumérations :

  • Sentinels : contenant la liste des sentinelles de votre Constellation
  • Packages : contenant le liste des packages de votre Constellation
  • PackageInstances : contenant la liste des instances des packages de votre Constellation

Comme les noms de sentinelles ou packages peuvent contenir des caractères interdits en C# (comme par exemple les tirets), les valeurs des énumérations sont “nettoyées” et la valeur réelle se trouve dans l’attribut “RealName” que vous pouvez récupérer avec la méthode d’extension “GetRealName()”.

Dans notre exemple l’énumération “Sentinels” générée est la suivante :

De ce fait on peut manipuler les sentinelles et récupérer le nom réel avec la méthode “GetRealName()” :

De plus, dans cette classe vous trouverez des méthodes d’extension pour créer un “MessageScope” vers une de vos sentinelles, packages ou instances de package.

Par exemple pour créer un scope vers les packages “Hue” :

Ce qui est équivalent à :

Sauf qu’avec le code généré plus besoin de chercher le nom exact ni même de risquer de faire une erreur de frappe, car tout est énumération !

On peut également cibler une instance d’un package en particulier. Par exemple pour cibler précisément le package “Hue” déployé sur la sentinelle “SKYNET-SERVER” :

Code généré pour les StateObjects

Prenons un exemple simple :  dans le code généré ci-dessus j’ai sélectionné le package “Paradox”, un package permettant de connecter les système d’alarme Paradox dans Constellation.

Ce package publie plusieurs StateObjects :

  • Des StateObjects de type “AreaInfo” par secteur qui représente l’état d’un secteur (système armé ou non par exemple)
  • Des StateObjects de type “ZoneInfo” par zone qui représente l’état d’une zone (zone ouverte ou non par exemple)
  • Des StateObjects de type “UserInfo” par utilisateur qui représente l’état d’un utilisateur (nom de l’utilisateur, dernière activité, etc..)

image

Prenons par exemple le StateObject “ZoneInfo1” de ce package :

image

On y trouvera plusieurs informations sur l’état de cette zone.

Le code généré pour les StateObjects de ce package sera donc rangé dans le namespace : VotreNamespace.Paradox.StateObjects et contiendra :

  • Une énumération “ParadoxStateObjectNames” référençant le nom des StateObjects actuellement connus sur le serveur
  • Une classe “ParadoxStateObjectLinkAttribute” (spécialisation de la classe StateObjectLinkAttribute)
  • Des classes pour chaque types personnalisés du package, ici le générateur aura généré les classes “AreaInfo”, “ZoneInfo” et “UserInfo”
  • Une classe “ParadoxExtensions” contenant des méthodes d’extension pour convertir des StateObjects en type personnalisé

Voyons par exemple comment inclure notre StateObject de la zone “1” dans votre code C# avec le code généré.

Tout d’abord, il faut inclure le namespace :

Ensuite ajoutons un “StateObjectLink” de type “ParadoxStateObjectLink” où nous préciserons le nom du StateObject avec l’énumération :

Sans le code généré nous aurions écrit :

Je peux ensuite utiliser la méthode d’extension générée “AsZoneInfo()” pour convertir la valeur du StateObject en “ZoneInfo” (“ZoneInfo” étant un type personnalisé décrit par le package Paradox) :

image

Le générateur a “reproduit” ce type dans votre code généré avec les commentaires tel que spécifiés dans le PackageDescriptor du package Paradox.

Sans le code généré, vous devez travailler avec un objet dynamique, donc sans auto-complétion :

image

Bien entendu tous les Packages (virtuels ou non) peuvent déclarer des Packages Descriptor.

Prenez l’exemple d’un capteur d’électricité basé sur un ESP8266. En utilisant la librairie Constellation pour Arduino, le code C++ de ce package virtuel commence par déclarer le type “SEnergy.Electricity” :

Puis à chaque fois que le capteur détecte une consommation électrique il publie un StateObject de la façon suivante :

On retrouve bien ce StateObject sur la Console Constellation :

image

Après avoir sélectionné le package “SElectricity” dans le générateur de code, je peux très facilement exploiter ce StateObject avec auto-complétion, description, etc.. :

image

Par exemple pour suivre en temps réel la consommation électrique dans mon package C# avec le code généré à partir du capteur ESP8266 écrit en C++/Arduino :

image

Code généré pour les MessageCallbacks

Le principe est le même avec les MessagesCallbacks, le générateur de code va créer le code dans le namespace “VotreNamespace.NomDuPackage.MessagesCallbacks” :

  • Des classes pour chaque types personnalisés utilisés dans les MC du package
  • Une classe “(NomDuPackage)Scope” permettant de référencer les MC sous forme de méthodes .NET
  • Une classe “(NomDuPackage)Extensions” : classe d’extension pour créer un scope du package à partir d’un MessageScope ou des énumérations Sentinels, Packages, PackagesInstances générées par le générateur
MessageCallbacks avec ou sans paramètre

Prenons par exemple le package virtuel “IRremote”, un récepteur/émetteur d’infrarouge développé en Arduino/C++ sur un ESP8266. Ce package virtuel expose deux MessageCallbacks : “Restart” pour rebooter l’ESP et “SendCode” pour envoyer un signal IR.

En utilisant la librairie Constellation pour Arduino de ces deux MC se résume par ces quelques lignes de C++ :

Une fois l’ESP démarré, nos deux MessageCallbacks sont correctement référencés sur Console Constellation avec les listes des paramètres, types et description :

image

Dans Visual Studio, générons maintenant le code pour notre package “IRRemote” :

image

Ajoutons ensuite le namespace correspondant aux MessageCallbacks de notre package, ici “IRRemote” :

Vous pouvez ensuite utiliser l’énumération “Packages” (ou “PackagesIntances”) et accéder à la méthode d’extension “CreateIRRemoteScope” pour créer un scope spécifiquement pour notre package :

image

Vous avez également une méthode d’extension nommée “ToXXXXSCope()” sur un MessageScope. En clair vous avez plusieurs moyen de créer un scope spécifiquement pour votre package “IRremote” avec le code généré :

Ensuite sur la classe Scope généré pour votre package, ici “IRRemoteScope”, vous retrouverez vos MessageCallbacks sous forme de méthode .NET avec les paramètres et descriptions !

De ce fait vous disposez de l’auto complétion sans risque de faire des erreurs de frappe :

image

Ainsi pour envoyer un code IR sur l’Arduino/ESP depuis mon code C#, on pourrait écrire :

MessageCallbacks avec des paramètres complexes

Ici le package “IRRemote” expose un MC sans paramètre et un autre avec deux paramètres simples (string et long).

Mais le générateur est également capable de gérer les types complexes. Par exemple prenez le package “Xbmc” permettant de piloter des média-centers Xbmc/Kodi.

Le package expose différents MessageCallbacks pour lancer un média, mettre pause, piloter le volume et également pour afficher un message à l’écran via le MessageCallback nommé “ShowNotification”.

Ce MessageCallback prend deux paramètres : le nom de l’hôte Xbmc (un string) et la notification à afficher. Cette notification est un objet de type “Xbmc.NotificationRequest” :

image

Sur la Console Constellation, vous pouvez cliquer sur les types personnalisés pour afficher les détails du type, ici un objet avec quatre propriétés :

image

Lorsque vous générez le code C# pour ce package vous retrouverez bien le MC “ShowNotification” avec le type personnalisé en paramètre :

image

Le générateur a en effet reproduit le type personnalisé dans votre code C# :

image

Ainsi pour afficher une notification sur un hôte Kodi, je pourrais écrire très simplement :

MessageCallbacks avec réponse : les sagas

Une invocation d’un MessageCallback peut donner lieu à une réponse, on appelle cela les “Sagas”. Avec l’API.NET, n’hésitez pas à relire les articles dédiés : Invoquer un MessageCallback avec réponse et Répondre à une saga.

Prenons un exemple, le package “Vera” (interface pour les box domotique) expose des MC pour envoyer des ordres à des périphériques Z-Wave :

image

Vous remarquerez d’ailleurs que les MC “SetDimmableLevel” et “SetSwitchState” prennent en argument un type complexe comme expliqué dans le chapitre précédent.

Vous remarquerez également que ces trois MC retournent un message de réponse, ici de type “Boolean”. En effet le résultat de l’exécution de l’ordre Z-Wave par la Vera est retourné à l’appellent si celui-ci à attaché un numéro de Saga.

Ainsi dans le code généré, les méthodes générées pour ces MessageCallbacks retournent une Task<T> où T est le type de retour, ici un booléen :

image

Ainsi dans le C# on peut très facilement invoquer le MessageCallback et récupérer la réponse :

Pour plus d’information à ce sujet, je vous recommande la lecture de l’article : Invoquer un MessageCallback avec réponse.

Le générateur de code C#
Editer la page sur GitHub
Étiqueté avec :        

Démarrez la discussion sur le forum Constellation