﻿<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Tag SendMessage - Constellation</title>
	<atom:link href="https://developer.myconstellation.io/tag/sendmessage/feed/" rel="self" type="application/rss+xml" />
	<link>https://developer.myconstellation.io/tag/sendmessage/</link>
	<description>Votre plateforme d&#039;interconnexion</description>
	<lastBuildDate>Thu, 19 Apr 2018 07:55:10 +0000</lastBuildDate>
	<language>fr-FR</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.0.11</generator>

<image>
	<url>https://developer.myconstellation.io/wp-content/uploads/2016/02/256x256-e1457476015859.png</url>
	<title>Tag SendMessage - Constellation</title>
	<link>https://developer.myconstellation.io/tag/sendmessage/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Nouvelle librairie Constellation pour Arduino / ESP8266 en version 2.0</title>
		<link>https://developer.myconstellation.io/blog/nouvelle-librairie-constellation-pour-arduino-esp8266-en-version-2-0/</link>
					<comments>https://developer.myconstellation.io/blog/nouvelle-librairie-constellation-pour-arduino-esp8266-en-version-2-0/#comments</comments>
		
		<dc:creator><![CDATA[Sebastien Warin]]></dc:creator>
		<pubDate>Tue, 13 Sep 2016 13:20:38 +0000</pubDate>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Subscribe]]></category>
		<category><![CDATA[SendMessage]]></category>
		<category><![CDATA[Arduino]]></category>
		<category><![CDATA[PushStateObject]]></category>
		<category><![CDATA[ESP8266]]></category>
		<category><![CDATA[REST]]></category>
		<category><![CDATA[ESP]]></category>
		<category><![CDATA[Package]]></category>
		<category><![CDATA[Messaging]]></category>
		<category><![CDATA[Message]]></category>
		<category><![CDATA[Console]]></category>
		<category><![CDATA[MessageCallback]]></category>
		<category><![CDATA[MessageContext]]></category>
		<category><![CDATA[Saga]]></category>
		<category><![CDATA[PurgeStateObject]]></category>
		<category><![CDATA[StateObjectLink]]></category>
		<category><![CDATA[PackageDescriptor]]></category>
		<category><![CDATA[HTTP]]></category>
		<category><![CDATA[Virtuel]]></category>
		<category><![CDATA[API]]></category>
		<guid isPermaLink="false">https://developer.myconstellation.io/?p=2546</guid>

					<description><![CDATA[<p>J’ai le plaisir de  vous annoncer l’arrivée de la nouvelle libraire Constellation pour Arduino/ESP en version 2.0. Cette nouvelle version amène beaucoup de nouveautés que je vous propose de découvrir dans cet article. La librairie a été testé avec succès</p>
<p>The post <a rel="nofollow" href="https://developer.myconstellation.io/blog/nouvelle-librairie-constellation-pour-arduino-esp8266-en-version-2-0/">Nouvelle librairie Constellation pour Arduino / ESP8266 en version 2.0</a> appeared first on <a rel="nofollow" href="https://developer.myconstellation.io">Constellation</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>J’ai le plaisir de  vous annoncer l’arrivée de la nouvelle libraire Constellation pour Arduino/ESP en version 2.0.</p>
<p>Cette nouvelle version amène beaucoup de nouveautés que je vous propose de découvrir dans cet article. La librairie a été testé avec succès sur différentes cartes animées par un ESP8266 (ESP-01, 05, 07 et D1 Mini) ainsi qu’un Arduino/Genuino MKR1000.</p>
<p>Pour la mise à jour, téléchargez la libraire ci-dessous et dézippez les fichiers dans le dossier “Constellation” dans votre répertoire de libraire Arduino.</p>

<p><u>Attention</u> : cette version 2.x de la librairie Constellation pour Arduino/ESP nécessite la version <a href="/constellation-platform/changelog/#05092016_Update_Server_18116249">1.8.1.16249</a> ou plus récente du serveur Constellation pour fonctionner correctement. Pour mettre à jour votre plateforme Constellation, lancez le <a href="/downloads/">Web Platform Installer</a>.</p>
<h3>Réception de message et StateObject “asynchrone”</h3>
<p>Il s’agit d’une grosse évolution par rapport à la version 1.x. Pour “récupérer” du serveur Constellation les messages à destination de votre package virtuel ou les StateObjects pour lequel votre package (virtuel) s’est abonné, il faut invoquer les actions “<a href="/client-api/rest-api/interface-rest-constellation/#Recevoir_des_messages">GetMessages</a>” et “<a href="/client-api/rest-api/interface-rest-constellation/#Subscribe">GetStateObjects</a>” sur l’interface REST.</p>
<p>Ces méthodes supportent le “long-polling” c’est à dire qu’elles mettent en attente la requête tant qu’il n’y a pas de messages ou StateObjects à retourner avec la notion de timeout (par défaut 60 secondes).</p>
<p>Le problème sur les versions 1.x de la libraire Arduino est que le client HTTP est “synchrone”, c’est à dire qu’il envoi la requête HTTP et attend la réponse du serveur pour traitement ce qui est incompatible avec du long-polling car cela bloquerait le code de l’Arduino. De ce fait, les anciennes versions spécifiées le “timeout” de ces requêtes à 1 seconde.</p>
<p>Ainsi jusqu’à maintenant, l’interrogation des messages et SO pouvaient bloquer jusqu’à 2 secondes votre Arduino (1 seconde pour le GetMessage et 1 seconde pour le GetStateObject) et engendrait donc 1 requêtes HTTP toutes les secondes entre votre ESP/Arduino et le serveur Constellation.</p>
<p>Dans cette nouvelle version, la librairie utilisent 3 clients HTTP différents : un pour toutes les requêtes synchrones, un pour la réception de message (<em>GetMessage</em>) et un pour la réception des StateObjects (<em>GetStateObjects</em>).</p>
<p>Le client synchrone est donc toujours disponible et il n’y a aucun blocage, aucune attente pour la réception de message et de SO. De plus il n’y a plus besoin de “poller” ou “flooder” le serveur d’une requête toute les secondes, en réactivant le long-polling le 2ème et 3ème client HTTP, on lance une requête toutes les minutes (60 sec par défaut) dans l’attente de message et SO.</p>
<p>De ce fait, il y a quelques modifications à apporter dans votre code !</p>
<p>Premièrement, vous ne devez plus passer la référence de votre client réseau mais plutôt spécifier le type de votre client dans le template de la classe Constellation. Par exemple, si vous utilisez un ESP8266 ou un Arduino MKR1000, vous utiliserez la classe “WifiClient “” :</p>
<p></p><pre class="crayon-plain-tag">/* Create the Constellation client */
Constellation&lt;WiFiClient&gt; constellation("constellation.monserveur.com", 8088, "MyVirtualSentine", "MyPackage", "MyAccessKey123!");</pre><p></p>
<p>Ensuite, il n’y a plus besoin d’invoquer la méthode “poll” dans votre boucle principale avec un timer, vous devez tout simplement appeler la méthode “loop” autant de fois que vous voulez :</p>
<p></p><pre class="crayon-plain-tag">void loop(void) {
  // Process incoming message &amp; StateObject updates
  constellation.loop();
}</pre><p></p>
<p>Cette méthode vérifie en fait si il y a eu une réponse sur le client utilisé pour la réception de message et sur le client pour la réception de SO afin de les dispatcher dans votre code.</p>
<h3>Support du PackageDescriptor</h3>
<p>Autre nouveauté majeure pour cette version 2, le support du “Package Descriptor”.</p>
<p>Pour rappel le “Package Descriptor” est un objet envoyé par un package au serveur pour décrire ses StateObjects et ses MessageCallbacks exposés par le package.</p>
<p>Le MessageCallback Explorer de la Console Constellation s’appuie sur le “Package Descriptor” de chaque package pour lister chaque MessageCallback avec un formulaire de test. Sans cette description cela serait impossible !</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/09/image.png"><img class="colorbox-2546"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="MessageCallback Explorer" src="https://developer.myconstellation.io/wp-content/uploads/2016/09/image_thumb.png" alt="MessageCallback Explorer" width="350" height="168" border="0" /></a></p>
<p>Les versions 1.x ne supportaient pas “Package Descriptor”, de ce fait il n’était pas possible d’explorer/découvrir les MessageCallbacks d’un package Arduino/ESP. Vous devez nécessairement connaitre par vous même les MC exposés par le package et le type des StateObjects qu’il pouvait publier.</p>
<p>Avec la version 2.0, l’Arduino/ESP envoie au serveur la description des MC exposés et des types utilisés par les SO et arguments des MC.</p>
<p>Dans la suite de cet article, vous découvrirez comment ajouter des types dans la description de votre package, mais n’oubliez jamais d’envoyer votre “Package Descriptor” en invoquant la méthode “declarePackageDescriptor”, typiquement une fois votre code Arduino initialisé (par exemple à la fin de la méthode <em>setup()</em>) :</p>
<p></p><pre class="crayon-plain-tag">// Declare the package descriptor
constellation.declarePackageDescriptor();</pre><p></p>
<h3>Amélioration du PushStateObject</h3>
<p>La méthode “PushStateObject” permet de publier un StateObject sur le serveur Constellation.</p>
<p>Tout d’abord la méthode expose des surcharges vous permettant de spécifier comme “value” de votre SO des int, uint, double, float, long et bool et supporte en paramètre optionnel le “lifetime”, c’st à dire la durée en seconde de “vie” de votre StateObject avant d’être considéré comme expiré.</p>
<p></p><pre class="crayon-plain-tag">// Dummy data
uint16_t lux = 123;

// Push a simple type on Constellation 
constellation.pushStateObject("DemoLux", lux);  

// Push a simple type on Constellation with lifetime of 20 seconds
constellation.pushStateObject("DemoLux", lux, 20);</pre><p></p>
<p>Vous pouvez toujours publier des StateObjects dont la valeur (value) est un objet complexe (formaté en JSON).</p>
<p>Le JSON peut être formaté sous forme d’une chaine de caractère avec la méthode “stringFormat” :</p>
<p></p><pre class="crayon-plain-tag">// Push a complex object on Constellation with stringFormat
constellation.pushStateObject("DemoLux", stringFormat("{ 'Lux':%d, 'Broadband':%d, 'IR':%d }", lux, full, ir));</pre><p></p>
<p>Vous pouvez également définir votre propre type pour ce StateObject, par exemple nommons cet objet “MyLuxData” :</p>
<p></p><pre class="crayon-plain-tag">constellation.pushStateObject("DemoLux", stringFormat("{ 'Lux':%d, 'Broadband':%d, 'IR':%d }", lux, full, ir), "MyLuxData");</pre><p></p>
<p>Sans oublier d’ajouter ce type “personnalisé” dans le “package descriptor”. Par exemple, dans le “setup()” et avant de faire un “declarePackageDescriptor”, on aurait décrit “MyLuxData” de la façon suivante :</p>
<p></p><pre class="crayon-plain-tag">constellation.addStateObjectType("MyLuxData", TypeDescriptor().setDescription("MyLuxData demo").addProperty("Broadband", "System.Int32").addProperty("IR", "System.Int32").addProperty("Lux", "System.Int32"));</pre><p></p>
<p>Pour finir, vous pouvez toujours publier un StateObject en construisant la valeur dans un objet JsonObject de façon suivante :</p>
<p></p><pre class="crayon-plain-tag">// Push a complex object on Constellation with JsonObject
const int BUFFER_SIZE = JSON_OBJECT_SIZE(5);
StaticJsonBuffer&lt;BUFFER_SIZE&gt; jsonBuffer;
JsonObject&amp; myStateObject = jsonBuffer.createObject();
myStateObject["Lux"] = lux;
myStateObject["Broadband"] = full;
myStateObject["IR"] = ir;
constellation.pushStateObject("DemoLux", myStateObject);</pre><p></p>
<p>Dans les surcharges de cette méthode, vous pouvez également spécifier le type de votre StateObject et/ou sa durée de vie :</p>
<p></p><pre class="crayon-plain-tag">constellation.pushStateObject("DemoLux", myStateObject, "MyLuxData", 20);</pre><p></p>
<p>Pour finir, nouveauté de la librairie 2.0, vous pouvez également spécifier des “meta-données” à vos StateObjects. Par exemple :</p>
<p></p><pre class="crayon-plain-tag">// Ajout de metadatas au StateObject
JsonObject&amp; metadatas = jsonBuffer.createObject();
metadatas["ChipId"] = ESP.getChipId();
metadatas["Timestamp"] = millis();
constellation.pushStateObject("DemoLux", myStateObject, "MyStateObject", 20, &amp;metadatas);</pre><p></p>
<h3>Les StateObjectLinks</h3>
<p>En version 1.x de la librairie Arduino, vous pouvez :</p>
<ul>
<li>interroger des StateObjects de la Constellation en invoquant la méthode “requestStateObjects” qui vous retourne les StateObjects à l’instant T correspondant à votre requête :</li>
</ul>
<p></p><pre class="crayon-plain-tag">// Example : print the all SO's value named "/intelcpu/0/load/0" and produced by the "HWMonitor" package (on all sentinels)
JsonArray&amp; cpus = constellation.requestStateObjects("*", "HWMonitor", "/intelcpu/0/load/0");
for(int i=0; i &lt; cpus.size(); i++) { 
  constellation.writeInfo("CPU on %s is currently %d %", cpus[i]["SentinelName"].asString(), cpus[i]["Value"]["Value"].as&lt;float&gt;());
}</pre><p></p>
<ul>
<li>vous abonnez aux mises à jour des StateObjects pour être notifié en temps réel des que les SO changent :</li>
</ul>
<p></p><pre class="crayon-plain-tag">// set a StateObject update callback and subscribe to SO
constellation.setStateObjectUpdateCallback([] (JsonObject&amp; so) {
constellation.writeInfo("StateObject updated ! StateObject name = %s", so["Name"].asString()); 
});
// Subscribe to SO named "/intelcpu/0/load/0" and produced by the "HWMonitor" package (on all sentinels)
constellation.subscribeToStateObjects("*", "HWMonitor", "/intelcpu/0/load/0");</pre><p></p>
<p>Vous pouvez invoquer plusieurs fois la méthode “subscribeToStateObjects” pour ajouter des abonnements à d’autre StateObjects mais il n’y a qu’un seul callback de réception des SO (défini par la méthode setStateObjectUpdateCallback). C’est à vous de “dispatcher” les SO reçus.</p>
<p>La nouveauté en 2.0 vient de l’ajout de la méthode “registerStateObjectLink” qui vous permet d’associer un callback à un abonnement laissant ainsi à la librairie la charge du “dispatch”.</p>
<p>Par exemple, on peut désormais écrire :</p>
<p></p><pre class="crayon-plain-tag">constellation.registerStateObjectLink("*", "HWMonitor", "/intelcpu/0/load/0", [](JsonObject&amp; so) {
  constellation.writeInfo("CPU on %s is currently %d %", so["SentinelName"].asString(), so["Value"]["Value"].as&lt;float&gt;());
});</pre><p></p>
<p>Ici on enregistre un “StateObject Link” sur tous les SO nommés « /intelcpu/0/load/0 » produits par le package “HWMonitor” de toutes les sentinelles de votre Constellation. Dès qu’un de ces StateObjects changent on exécutera le callback associé, qui ici écrit dans le log un message indiquant la nouvelle valeur du CPU.</p>
<p>Vous bien entendu enregistrer autant de StateObjectLink que vous souhaitez.</p>
<h3>Enregistrement des MessageCallbacks</h3>
<p>Le principe est le même que celui décrit ci-dessus pour les abonnements aux StateObjects.</p>
<p>En version 1.x, on devait définir un callback pour réception de message et invoquer la méthode “subscribeToMessage” :</p>
<p></p><pre class="crayon-plain-tag">// Set callback for all incoming messages
 constellation.setMessageReceiveCallback([](JsonObject&amp; json) { 
   constellation.writeInfo("Message receive ! Message key = %s", json["Key"].asString());     
 }); 
 // Subscribe to message
 constellation.subscribeToMessage();</pre><p></p>
<p>C’était donc à votre charge de “dispatcher” les messages reçus en fonction du “MessageKey”.</p>
<p>Désormais avec la version 2.0, vous pouvez enregistrer un callback pour un “MessageKey” donné. Par exemple :</p>
<p></p><pre class="crayon-plain-tag">constellation.registerMessageCallback("HelloWorld",
  [](JsonObject&amp; json) {
    constellation.writeInfo("Hello Constellation !");
 });</pre><p></p>
<p>Dans l’exemple ci-dessous, on ajoute/expose un MessageCallback “HelloWorld” qui écrit dans les logs !</p>
<p>Il n’y donc plus besoin de “dispatcher”, un MessageCallback est donc associé à un “MessageKey” unique et un callback. Il n’y a plus besoin non plus de faire un “subscribeToMessage” (cette méthode est invoquée implicitement par le <em>registerMessageCallback</em>).</p>
<p>De plus cette méthode ajoute implicitement les MessageCallbacks dans le Package Descriptor de sorte que chaque MC soit ainsi référencé dans la Constellation</p>
<p>(console)</p>
<p>Vous pouvez également passer un “MessageCallbackDescriptor” dans l’enregistrement de vos MC pour ajouter une description par exemple :</p>
<p></p><pre class="crayon-plain-tag">constellation.registerMessageCallback("HelloWorld",
  MessageCallbackDescriptor().setDescription("Say Hello to Constellation"),
  [](JsonObject&amp; json) {
    constellation.writeInfo("Hello Constellation !");
 });</pre><p></p>
<p>Et même définir les paramètres de vos MC :</p>
<p></p><pre class="crayon-plain-tag">constellation.registerMessageCallback("SayHello",
  MessageCallbackDescriptor().setDescription("Say hello !").addParameter("FirstName", "System.String").addParameter("LastName", "System.String"),
  [](JsonObject&amp; json) {
    constellation.writeInfo("Hello %s %s", json["Data"][0].asString(), json["Data"][1].asString()); 
 });</pre><p></p>
<p>Ici on déclare un MC nommé “SayHello” prenant deux paramètres de type String avec un texte de description. Dans la code nous verrons :</p>
<p>(console)</p>
<p>Tout comme les StateObjects, les types des arguments des MC peuvent être des types complexes.</p>
<p>Par exemple enregistrons un MC prenant un seul argument de type “SampleUserData” que nous allons décrire avec la méthode “addMessageCallbackType” comme un objet composé de deux propriétés de type String :</p>
<p></p><pre class="crayon-plain-tag">// Expose a MessageCallback with complex parameter :
constellation.registerMessageCallback("SayHello2",
  MessageCallbackDescriptor().setDescription("Say hello with complex object!").addParameter("User", "SampleUserData"),
  [](JsonObject&amp; json) {
    constellation.writeInfo("Hello %s %s", json["Data"][0]["FirstName"].asString(), json["Data"][0]["LastName"].asString()); 
});  
// and describe the complex parameter "SampleUserData"  
constellation.addMessageCallbackType("SampleUserData", TypeDescriptor().setDescription("This is a smaple user data").addProperty("FirstName", "System.String").addProperty("LastName", "System.String"));</pre><p></p>
<p>Enfin la méthode “registerMessageCallback” accepte également des callbacks prenant en paramètre le “MessageContext” :</p>
<p></p><pre class="crayon-plain-tag">constellation.registerMessageCallback("HelloWorld",
  MessageCallbackDescriptor().setDescription("Say Hello to Constellation"),
  [](JsonObject&amp; json, MessageContext ctx) {
    constellation.writeInfo("Message received from %s", ctx.sender.friendlyName);
 });</pre><p></p>
<p>L’objet “MessageContext” est défini de la façon suivante :</p>
<p></p><pre class="crayon-plain-tag">typedef struct {
    const char* sagaId;
    bool isSaga;
    const char* messageKey;
    MessageSender sender;
    ScopeType scope;
} MessageContext;

typedef struct {
    SenderType type;
    const char* friendlyName;
    const char* connectionId;
} MessageSender;</pre><p></p>
<p>Vous pouvez donc récupérer les informations sur l’émetteur (Sender) du message, le scope et l’identifiant de Saga si c’est une saga (isSaga = true).</p>
<h3>Support des Saga (messages avec réponse)</h3>
<p>Une <a href="/concepts/messaging-message-scope-messagecallback-saga/#Les_Sagas">saga</a> est un identifiant unique qu’on affecte à des messages pour les lier entre eux. Cela permet de faire des couples de message “Requête / Réponse”. Une “réponse” étant un message renvoyé à l’émetteur de la requête avec le même identifiant de saga pour que ce dernier puisse l’identifier comme la “réponse” à son message d’origine.</p>
<p>Vous pouvez exposer des MessageCallbacks qui “répondent”, c’est à dire des  MessageCallbacks qui retournent un message de réponse.</p>
<p>Par exemple, exposons un MC pour réaliser des Additions sur un Arduino. Vous enregistrerez un MC “Addition” prenant en parametre deux entiers et qui en retourne un (le résultat) :</p>
<p></p><pre class="crayon-plain-tag">constellation.registerMessageCallback("Addition",
  MessageCallbackDescriptor().setDescription("Do addition on this tiny device").addParameter("a", "System.Int32").addParameter("b", "System.Int32").setReturnType("System.Int32"),
  [](JsonObject&amp; json, MessageContext ctx) {        
    int a = json["Data"][0].as&lt;int&gt;();      
    int b = json["Data"][1].as&lt;int&gt;();
    int result = a + b;
    constellation.writeInfo("Addition %d + %d = %d", a, b, result);      
    if(ctx.isSaga) {
      constellation.writeInfo("Doing additoon for %s (sagaId: %s)", ctx.sender.friendlyName, ctx.sagaId);   
    // Return the result :
      constellation.sendResponse&lt;int&gt;(ctx, result);
    }
    else {
      constellation.writeInfo("No saga, no response !");
    }
 });</pre><p></p>
<p>Vous remarquerez dans le “MessageCallbackDescriptor” l’appel de la méthode “setReturnType” pour spécifier le type de retour (et que le fait qu’il s’agit d’un MC acceptant les sagas).</p>
<p>L’envoi de la réponse étant réalisé par la méthode sendReponse. Cette méthode a plusieurs surcharges :</p>
<p></p><pre class="crayon-plain-tag">template&lt;typename T&gt; bool sendResponse(MessageContext context, T data);
bool sendResponse(MessageContext context, const char* data, ...);
bool sendResponse(MessageContext context, JsonObject&amp; data);</pre><p></p>
<p>Notez aussi que vous devriez faire un “sendResponse” si et seulement le message reçu est associé à une saga, c’est à dire que le champs “isSaga” du contexte (MessageContext) est “vrai”. Sinon ca ne sert à rien de répondre <img class="wlEmoticon wlEmoticon-winkingsmile colorbox-2546" style="border-style: none;" src="https://developer.myconstellation.io/wp-content/uploads/2016/09/wlEmoticon-winkingsmile.png" alt="Clignement d'œil" /></p>
<p>Pour finir, cette nouvelle version supporte également l’envoi de message dans une saga. C’est à dire que vous pouvez envoyer un message qui attend une réponse et donc enregistrer un callback de traitement de la réponse.</p>
<p>Par exemple le package “NetworkTools” expose un MC “Ping” permettant de faire un ping. Le package retourne dans la saga un message contenant le temps en milliseconde du ping. On pourrait alors invoquer cette méthode depuis notre Arduino de la façon suivante :</p>
<p></p><pre class="crayon-plain-tag">const char* ip = "192.168.0.10";
// Send message in a saga and attach a callback for response :
constellation.sendMessageWithSaga([](JsonObject&amp; json) {
  constellation.writeInfo("Ping response in %s ms", json["Data"].asString()); 
}, Package, "NetworkTools", "Ping", "[ '%s' ]", ip);</pre><p></p>
<p>Ici on envoi un message au scope “Package” pour atteindre le(x) package(s) “NetworkTools” afin d’invoquer le MessageCallback “Ping” en passant en argument l’IP à pinger. Vous remarquerez qu’on utilise le formatage implicite des arguments.</p>
<p>La méthode n’est pas la traditionnelle “sendMessage” mais “sendMessageWithSaga” qui prend un argument supplémentaire : le callback de traitement de la réponse.</p>
<p>Ainsi quand le package “NetworkTools” répondra, on executera le callback associé qui ici affichera le temps de réponse de notre ping (Data) dans les logs Constellation (writeInfo).</p>
<p>De ce fait, avec cette nouvelle libraire vos Arduino/ESP peuvent invoquer des MC dans sagas pour exploiter la réponse mais également exposer des MC qui retournent des résultats.</p>
<h3>Autres nouveautés</h3>
<p>En vrac, vous disposez maintenant une méthode “purgeStateObjects” permettant de supprimer des StateObjects de votre package.</p>
<p>De plus la méthode “setDebugMode” accepte en argument l’énumération “DebugMode” composée des valeurs suivantes :</p>
<ul>
<li>“Quiet” (mode silencieux, la libraire ne produit aucune trace dans l’interface Serial)</li>
<li>“Normal” (mode par défaut, écrit quelques informations dans l’interface Serial)</li>
<li>“Verbose” (écrit beaucoup d’information dans l’interface Serial comme par exemple les requêtes et réponse HTTP v ers Constellation)</li>
</ul>
<p>Enfin les exemples fournis dans la libraire ont été complètement revus.</p>
<p>The post <a rel="nofollow" href="https://developer.myconstellation.io/blog/nouvelle-librairie-constellation-pour-arduino-esp8266-en-version-2-0/">Nouvelle librairie Constellation pour Arduino / ESP8266 en version 2.0</a> appeared first on <a rel="nofollow" href="https://developer.myconstellation.io">Constellation</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://developer.myconstellation.io/blog/nouvelle-librairie-constellation-pour-arduino-esp8266-en-version-2-0/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
		<item>
		<title>Envoyer des messages et invoquer des MessageCallbacks en Python</title>
		<link>https://developer.myconstellation.io/client-api/python-api/envoyer-des-messages-et-invoquer-des-messagecallbacks-en-python/</link>
					<comments>https://developer.myconstellation.io/client-api/python-api/envoyer-des-messages-et-invoquer-des-messagecallbacks-en-python/#respond</comments>
		
		<dc:creator><![CDATA[Sebastien Warin]]></dc:creator>
		<pubDate>Wed, 24 Aug 2016 09:47:10 +0000</pubDate>
				<category><![CDATA[Python API]]></category>
		<category><![CDATA[MessageScope]]></category>
		<category><![CDATA[Saga]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[SendMessage]]></category>
		<category><![CDATA[Message]]></category>
		<category><![CDATA[MessageCallback]]></category>
		<guid isPermaLink="false">https://developer.myconstellation.io/?p=2509</guid>

					<description><![CDATA[<p>Envoyer un message Pour envoyer un message et donc invoquer un MessageCallback depuis un package Python vous devez utiliser la méthode “Constellation.SendMessage”. Par exemple : [crayon-69756ad9ec6fd520137312/] Ici par exemple on envoi un message au package “SMS” pour invoquer le MessageCallback</p>
<p>The post <a rel="nofollow" href="https://developer.myconstellation.io/client-api/python-api/envoyer-des-messages-et-invoquer-des-messagecallbacks-en-python/">Envoyer des messages et invoquer des MessageCallbacks en Python</a> appeared first on <a rel="nofollow" href="https://developer.myconstellation.io">Constellation</a>.</p>
]]></description>
										<content:encoded><![CDATA[<h3>Envoyer un message</h3>
<p>Pour envoyer un message et donc <a href="/concepts/messaging-message-scope-messagecallback-saga/">invoquer un MessageCallback</a> depuis un package Python vous devez utiliser la méthode “<em>Constellation.SendMessage</em>”. Par exemple :</p>
<p></p><pre class="crayon-plain-tag">Constellation.SendMessage("SMS", "SendMessage", [ "+33676903634", "Bonjour Constellation" ])</pre><p></p>
<p>Ici par exemple on envoi un message au package “SMS” pour invoquer le MessageCallback “SendMessage” en passant en argument deux paramètres de type string.</p>
<p>Le MessageCallbacks Explorer de la Console Constellation permet de lister l’ensemble des MC déclarés par les packages de votre Constellation.</p>
<p>Par exemple, avec le package <a href="/package-library/nest/">Nest</a> déployé dans votre Constellation, on retrouvera un MessageCallback  “SetTargetTemperature” pour piloter la température de consigne d’un thermostat Nest.</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/09/image-21.png"><img class="colorbox-2509"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border: 0px;" title="image" src="https://developer.myconstellation.io/wp-content/uploads/2016/09/image_thumb-20.png" alt="image" width="350" height="99" border="0" /></a></p>
<p>Pour l’invoquer depuis notre code Python :</p>
<p></p><pre class="crayon-plain-tag">Constellation.SendMessage("Nest", "SetTargetTemperature", [ "thermostatId", 19 ], Constellation.MessageScope.package)</pre><p></p>
<p>On peut également passer en paramètre un objet complexe. Par exemple le MC “AreaArm” du package Paradox permet d’armer le système d’alarme en passant en paramètre un objet “ArmingRequestData” contenant le secteur à armer, le mode d’armement et le PIN.</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/09/image-22.png"><img class="colorbox-2509"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border: 0px;" title="image" src="https://developer.myconstellation.io/wp-content/uploads/2016/09/image_thumb-21.png" alt="image" width="350" height="121" border="0" /></a></p>
<p>Le code Python pour invoquer ce MC sera alors :</p>
<p></p><pre class="crayon-plain-tag">Constellation.SendMessage("Paradox", "AreaArm", { "Area":"All", "Mode":1, "PinCode":"0000" }, Constellation.MessageScope.package)</pre><p></p>
<p>Vous pouvez également passer plusieurs arguments à votre MC en combinant type simple et type complexe. Par exemple le MC “ShowNotification” du package <a href="/package-library/xbmc/">Xbmc</a> permettant d’afficher une notification sur une interface Kodi/XBMC prend deux paramètres : le nom d l’hôte XBMC (un type simple) et le détail de la notification à afficher (un type complexe) :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/09/image-23.png"><img class="colorbox-2509"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border: 0px;" title="image" src="https://developer.myconstellation.io/wp-content/uploads/2016/09/image_thumb-22.png" alt="image" width="350" height="143" border="0" /></a></p>
<p></p><pre class="crayon-plain-tag">Constellation.SendMessage("Xbmc", "ShowNotification", [ xbmcName, { "Title":"Hello Constellation", "Message":"Hello I'm Python" } ], Constellation.MessageScope.package)</pre><p></p>
<p>Les exemples de message ci-dessus sont tous envoyés à un package mais vous pouvez également envoyer vos messages à <a href="/concepts/messaging-message-scope-messagecallback-saga/">différents scopes</a>.</p>
<p>Par exemple pour envoyer le message “Demo” sans aucun paramètre au groupe A, on écrira :</p>
<p></p><pre class="crayon-plain-tag">Constellation.SendMessage("A", "Demo", {}, Constellation.MessageScope.group)</pre><p></p>
<p>Les scopes disponibles sont :</p>
<ul>
<li>group</li>
<li>package</li>
<li>sentinel</li>
<li>others</li>
<li>all</li>
</ul>
<p>Notez par ailleurs que le paramètre “MessageScope” de la méthode “SendMessage” est optionnel. Si il n’est pas spécifié le scope par défaut est “package”.</p>
<h3>Envoyer des messages avec réponse : les Sagas</h3>
<p>Si le MC que vous invoquez retourne un message de réponse, vous devez envoyer votre message dans une saga. Pour cela vous pouvez utiliser la méthode “SendMessageWithSaga” dans laquelle vous devrez spécifier la fonction qui sera invoquée lors de la réception de la réponse.</p>
<p>Par exemple reprenons le MessageCallback “AreaArm” du package Paradox :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/09/image-24.png"><img class="colorbox-2509"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border: 0px;" title="image" src="https://developer.myconstellation.io/wp-content/uploads/2016/09/image_thumb-23.png" alt="image" width="350" height="121" border="0" /></a></p>
<p align="left">Comme vous le constatez, ce MessageCallback retourne un “Boolean” pour indiquer si l’armement a bien été déclenché.</p>
<p align="left">On peut donc invoquer ce MC dans une saga et attacher un callback de réponse pour afficher dans le logs de notre package si l’armement a réussi :</p>
<p></p><pre class="crayon-plain-tag">Constellation.SendMessageWithSaga(lambda response:
   Constellation.WriteInfo("Arm result is %s" % response),
"Paradox", "AreaArm", { "Area":"All", "Mode":1, "PinCode":"0000" })</pre><p></p>
<p>Ici nous avons utilisé une fonction lambda pour simplifier la lecture mais vous pouvez également définir une fonction classique dans votre code.</p>
<p>Le paramètre “response” utilisé dans la fonction callback est l’objet de la réponse envoyé par le package qui a reçu votre message. Ici “response” est un “Boolean” car le MC “AreaArm” retourne un booléen mais il peut être de n’importe quel type (simple ou complexe).</p>
<p>Le MessageCallback Explorer de la Console Constellation vous donnera tous les détails.</p>
<p>The post <a rel="nofollow" href="https://developer.myconstellation.io/client-api/python-api/envoyer-des-messages-et-invoquer-des-messagecallbacks-en-python/">Envoyer des messages et invoquer des MessageCallbacks en Python</a> appeared first on <a rel="nofollow" href="https://developer.myconstellation.io">Constellation</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://developer.myconstellation.io/client-api/python-api/envoyer-des-messages-et-invoquer-des-messagecallbacks-en-python/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Envoyer des messages &#038; Invoquer des MessageCallbacks</title>
		<link>https://developer.myconstellation.io/client-api/net-package-api/envoyer-des-messages-invoquer-des-messagecallbacks/</link>
					<comments>https://developer.myconstellation.io/client-api/net-package-api/envoyer-des-messages-invoquer-des-messagecallbacks/#respond</comments>
		
		<dc:creator><![CDATA[Sebastien Warin]]></dc:creator>
		<pubDate>Wed, 16 Mar 2016 16:41:17 +0000</pubDate>
				<category><![CDATA[.NET API]]></category>
		<category><![CDATA[SendMessageProxy]]></category>
		<category><![CDATA[MessageScope]]></category>
		<category><![CDATA[SendMessage]]></category>
		<category><![CDATA[Messaging]]></category>
		<category><![CDATA[MessageContext]]></category>
		<category><![CDATA[Proxy]]></category>
		<guid isPermaLink="false">https://developer.myconstellation.io/?p=1379</guid>

					<description><![CDATA[<p>Avant de suivre la lecture de cet article vous devez avoir compris les concepts de base des MessageCallbacks. Créer un scope Un message Constellation est envoyé à un Scope qui représente le ou les destinataires du message. Un scope Constellation est</p>
<p>The post <a rel="nofollow" href="https://developer.myconstellation.io/client-api/net-package-api/envoyer-des-messages-invoquer-des-messagecallbacks/">Envoyer des messages &#038; Invoquer des MessageCallbacks</a> appeared first on <a rel="nofollow" href="https://developer.myconstellation.io">Constellation</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Avant de suivre la lecture de cet article vous devez avoir compris les <a href="/concepts/messaging-message-scope-messagecallback-saga/">concepts de base</a> des MessageCallbacks.</p>
<h3>Créer un scope</h3>
<p>Un message Constellation est envoyé à un Scope qui représente le ou les destinataires du message.</p>
<p>Un scope Constellation est décrit dans l&rsquo;API.NET par la classe “MessageScope”. Vous pouvez créer un scope avec la méthode statique “Create”.</p>
<p>Par exemple pour créer un scope vers les instances du package “MonPackage” de votre Constellation  :</p>
<p></p><pre class="crayon-plain-tag">MessageScope.Create("MonPackage")</pre><p></p>
<p>Par défaut le type de scope est “Package”. La ligne ci-dessus est donc identique à la ligne :</p>
<p></p><pre class="crayon-plain-tag">MessageScope.Create(MessageScope.ScopeType.Package, "MonPackage")</pre><p></p>
<p>Si vous souhaitez cibler une instance d’un package en particulier, vous devez spécifier la sentinelle sur laquelle est hébergée le package que vous ciblez :</p>
<p></p><pre class="crayon-plain-tag">MessageScope.Create("MaSentinelle/MonPackage")</pre><p></p>
<p>Si vous souhaitez cibler plusieurs packages :</p>
<p></p><pre class="crayon-plain-tag">MessageScope.Create(MessageScope.ScopeType.Package, "MonPackage", "MonAutrePackage", "EncoreUnAutrePackage")</pre><p></p>
<p>Bien entendu vous pouvez donner le nom d’une instance en particulier (sentinelle + package) ou juste le nom du package :</p>
<p></p><pre class="crayon-plain-tag">MessageScope.Create(MessageScope.ScopeType.Package, "MaSentinelle/MonPackage", "MonAutrePackage")</pre><p></p>
<p>Le scope “Sentinel” permet de cibler tous les packages sur une sentinelle donnée. Vous pouvez définir autant de sentinelle que vous souhaitez :</p>
<p></p><pre class="crayon-plain-tag">MessageScope.Create(MessageScope.ScopeType.Sentinel, "MaSentinelle", "MonAutreSentinelle")</pre><p></p>
<p>Le scope “Group” permet de cibler les packages qui <a href="/client-api/net-package-api/messagecallbacks/#Sabonner_et_recevoir_les_messages_dun_groupe">sont abonnés à un groupe</a>. Ici créons un scope pour tous les packages membre du groupe “GroupA” :</p>
<p></p><pre class="crayon-plain-tag">MessageScope.Create(MessageScope.ScopeType.Group, "GroupA")</pre><p></p>
<p>Vous pouvez bien sûr définir autant de groupe dans un scope que vous souhaitez :</p>
<p></p><pre class="crayon-plain-tag">MessageScope.Create(MessageScope.ScopeType.Group, "GroupA", "GroupB", "GroupC")</pre><p></p>
<p>Enfin vous pouvez créer des scopes pour cibler tous les clients connectés dans votre Constellation (All) ou tout le monde sauf l’émetteur (Others). Dans ces deux cas, il n’y a pas d’argument à spécifier :</p>
<p></p><pre class="crayon-plain-tag">MessageScope.Create(MessageScope.ScopeType.Others)</pre><p></p>
<h3>Envoyer un message avec le SendMessage</h3>
<p>La méthode de base pour envoyer un message dans Constellation est “<em>PackageHost.SendMessage</em>”.</p>
<p>Vous devez définir trois arguments pour envoyer un message :</p>
<ul>
<li>Le scope (les destinataires de votre message)</li>
<li>La clé du message (MessageKey)</li>
<li>Le contenu du message (Data)</li>
</ul>
<p>Comme vous le savez, on se sert des messages pour invoquer des méthodes d’autre packages. La clé du message est en fait le nom de la méthode (= le MessageCallback) à invoquer.</p>
<p>Prenons pour exemple les MessageCallbacks définis dans <a href="/client-api/net-package-api/messagecallbacks/">l’article précédent</a>.</p>
<p>Pour invoquer le MessageCallback “MyMethod” sans paramètre (Data = null) on pourrait écrire :</p>
<p></p><pre class="crayon-plain-tag">PackageHost.SendMessage(MessageScope.Create("MonPackage"), "MyMethod", null);</pre><p></p>
<p>Pour une méthode avec plusieurs paramètres, ils faut les encapsuler dans un tableau d’objet :</p>
<p></p><pre class="crayon-plain-tag">PackageHost.SendMessage(MessageScope.Create("MonPackage"), "MyMethodWithMultipleParameters", new object[] { "Un String", 123, true });</pre><p></p>
<p>Cela fonctionne aussi avec des objets complexes. Par exemple pour invoquer notre MessageCallback “Logon” :</p>
<p></p><pre class="crayon-plain-tag">PackageHost.SendMessage(MessageScope.Create("MonPackage"), "Logon", new { User = "seb", Password = "seb" });</pre><p></p>
<p>Avec l’API .NET on ne se sert généralement jamais de cette méthode “SendMessage” car vous avez à disposition le “SendMessageProxy” que nous allons découvrir ci-dessous.</p>
<h3>Envoyer un message avec un proxy dynamique</h3>
<p>La classe “SendMessageProxy” est un objet dynamique qui permet d’envoyer un message de la même manière que vous appelez une méthode en programmation .NET.</p>
<p>Pour créer un proxy dynamique vous devez au préalable avoir créer votre scope :</p>
<p></p><pre class="crayon-plain-tag">MessageScope scope = MessageScope.Create("MonPremierPackage");
dynamic proxy = new SendMessageProxy(scope);</pre><p></p>
<p>Pour simplifier le code, vous pouvez utiliser la méthode d’extension “GetProxy()” sur le MessageScope :</p>
<p></p><pre class="crayon-plain-tag">MessageScope scope = MessageScope.Create("MonPremierPackage");
dynamic proxy = scope.GetProxy();</pre><p></p>
<p>Attention, pour accéder aux méthodes d’extension du <em>MessageScope</em> vous devez ajouter le namespace “Constellation.Package” :</p>
<p></p><pre class="crayon-plain-tag">using Constellation.Package;</pre><p></p>
<p>Une fois le proxy  dynamique créé il suffit d’appeler &lsquo;”fictivement” une méthode pour envoyer le message.</p>
<p>Par exemple pour envoyer le message “MyMethod” avec un contenu du vide, on écrira simplement :</p>
<p></p><pre class="crayon-plain-tag">proxy.MyMethod();</pre><p></p>
<p>Si votre message doit contenir plusieurs arguments :</p>
<p></p><pre class="crayon-plain-tag">proxy.MyMethodWithMultipleParameters("Un String", 123, true);</pre><p></p>
<p>Ou encore avec notre MessageCallback “Logon” qui prend en argument un objet complexe :</p>
<p></p><pre class="crayon-plain-tag">proxy.Logon(new { User = "seb", Password = "seb" })</pre><p></p>
<p>Ainsi vous pouvez invoquer un MessageCallback de n’importe quel package de la même façon que vous invoquerez une méthode de votre code .NET. La méthode invoquée est la clé du message et les arguments sont inclus dans le contenu du message.</p>
<p>Bien sûr avec la méthode d’extension vous pouvez faire tout cela en une ligne de code : créer le scope, récupérer le proxy dynamique et envoyer le message :</p>
<p></p><pre class="crayon-plain-tag">MessageScope.Create("MonPremierPackage").GetProxy().Logon(new { User = "seb", Password = "seb" });</pre><p></p>
<p>Vous avez également à disposition la méthode “<em>CreateMessageProxy</em>” sur le PackageHost. Cette méthode permet de créer un scope et vous retourne le proxy dynamique.</p>
<p>Les deux lignes ci-dessous sont donc identiques :</p>
<p></p><pre class="crayon-plain-tag">dynamic proxy = MessageScope.Create("MonPremierPackage").GetProxy();
dynamic proxy = PackageHost.CreateMessageProxy("MonPremierPackage");</pre><p></p>
<p>De ce fait, pour invoquer nos trois MessageCallbacks, on peut écrire simplement :</p>
<p></p><pre class="crayon-plain-tag">PackageHost.CreateMessageProxy("MonPremierPackage").MyMethod();
PackageHost.CreateMessageProxy("MonPremierPackage").MyMethodWithMultipleParameters("Un String", 123, true);
PackageHost.CreateMessageProxy("MonPremierPackage").Logon(new { User = "seb", Password = "seb" });</pre><p></p>
<p>Tout comme la méthode “MessageScope.Create”, le “CreateMessageProxy” peut créer tout type de scope.</p>
<p>Par exemple, invoquons le MessageCallbacks “MyMessageCallback” avec deux arguments (un string et un datetime) sur tous les packages du groupe A et B de notre Constellation :</p>
<p></p><pre class="crayon-plain-tag">PackageHost.CreateMessageProxy(MessageScope.ScopeType.Group, "GroupA", "GroupB").MyMessageCallback("Mon Argument", DateTime.Now);</pre><p></p>
<h3>Invoquer un MessageCallback avec réponse – Utilisation des Sagas</h3>
<p>Lorsque vous envoyez un message dans un scope vous pouvez ajouter un identifiant de Saga sur ce scope. Cela indiquera au destinataire que vous souhaitez une réponse en retour (<a href="/client-api/net-package-api/messagecallbacks/#Repondre_a_une_saga">plus d’info</a>).</p>
<p>L’identifiant de Saga doit être aléatoire et unique. Vous avez une méthode d’extension “WithSaga” sur un MessageScope vous permettant de définir l’identifiant de la saga (SagaId) avec un GUID :</p>
<p></p><pre class="crayon-plain-tag">MessageScope.Create("MonPremierPackage").WithSaga();</pre><p></p>
<p>La méthode d’extension vous retourne le MessageScope, vous pouvez donc directement récupérer le proxy dynamique et envoyer votre message :</p>
<p></p><pre class="crayon-plain-tag">MessageScope.Create("MonPremierPackage").WithSaga().GetProxy().Logon(new { User = "seb", Password = "seb" });</pre><p></p>
<p>Pour la réception des réponses, vous avez une méthode “RegisterSagaResponseCallback” qui permet d’enregistrer la fonction à invoquer lors de la réponse :</p>
<p></p><pre class="crayon-plain-tag">PackageHost.RegisterSagaResponseCallback(sagaId, (reponse) =&gt;
{
      // Response pour la saga "sagaId"
});</pre><p></p>
<p>Pour simplifier le code, vous avez une méthode d’extension “OnSagaResponse” sur un MessageScope qui permet à la fois d’ajouter un identifiant de saga sur le scope (WithSaga) et d’enregistrer la fonction de retour.</p>
<p>De ce fait, vous pouvez en une seule ligne créer votre scope avec saga, définir le code qui sera invoqué à la réception la réponse, récupérer le proxy dynamique et invoquer votre MessageCallback avec ses paramètres :</p>
<p></p><pre class="crayon-plain-tag">MessageScope.Create("MonPremierPackage").OnSagaResponse((response) =&gt;
{
    // Reponse de la saga
}).GetProxy().Logon(new { User = "seb", Password = "seb" });</pre><p></p>
<p>Comme pour les MessageCallbacks, la méthode de réception d’une réponse d’une saga est invoquée dans un thread dédié dans lequel vous avez accès au contexte du message via la propriété “MessageContext.Current”.</p>
<p>Vous pouvez donc savoir quel est le package qui vous a répondu (<em>Sender</em>) ou encore quel était l’identifiant de la saga utilisée.</p>
<p>De plus, notez que la méthode <em>OnSagaResponse</em> est générique afin de pouvoir définir le type de retour (le cast sera réalisé automatiquement).</p>
<p>On peut donc écrire :</p>
<p></p><pre class="crayon-plain-tag">MessageScope.Create("MonPremierPackage").OnSagaResponse&lt;bool&gt;((response) =&gt;
{
    PackageHost.WriteInfo("Reponse de {0} pour la saga {1}",                 
        MessageContext.Current.SagaId,
        MessageContext.Current.Sender.FriendlyName);

    PackageHost.WriteInfo(response ? "OK" : "DENIED");

}).GetProxy().Logon(new { User = "seb", Password = "seb" });</pre><p></p>
<p>Notez également que si votre scope cible plusieurs packages (ex : si “MonPremierPackage” est déployé sur plusieurs sentinelles), votre fonction de traitement de la réponse sera invoquée plusieurs fois, pour chaque package qui répondra (car l’identifiant de Saga est le même).</p>
<h3>Utiliser les “Tasks” (awaitable) pour attendre la réponse d’une saga</h3>
<p>C’est une nouveauté de la 1.8 de Constellation. Pour bien comprendre, résumons ce que l’on connait déjà !</p>
<p>Lorsque vous invoquez une méthode sur le proxy dynamique, celui-ci envoie un message dans Constellation où la clé du message est le nom de la méthode invoquée et le contenu du message sont les paramètres de la méthode invoquée.</p>
<p>Ces deux lignes sont donc identiques :</p>
<p></p><pre class="crayon-plain-tag">PackageHost.SendMessage(MessageScope.Create("MonPackage"), "Logon", new { User = "seb", Password = "seb" });
MessageScope.Create("MonPremierPackage").GetProxy().Logon(new { User = "seb", Password = "seb" });</pre><p></p>
<p>Sur la 2ème ligne, vous invoquez dynamiquement la méthode “Logon” sur le <em>SendMessageProxy</em> (créé par la méthode GetProxy()) pour envoyer (<em>PackageHost.SendMessage</em>) le message “Logon”.</p>
<p>Ces deux lignes font donc bien la même chose. Dans les deux cas le message est envoyé dans un scope qui ne porte pas de “SagaId” (donc aucune réponse n’est attendue).</p>
<p>Je rappelle également que vous pouvez créer un scope et récupérer son proxy dynamique directement avec la méthode <em>PackageHost.CreateMessageProxy</em>. On peut donc encore simplifier le code par la ligne :</p>
<p></p><pre class="crayon-plain-tag">PackageHost.CreateMessageProxy("MonPremierPackage").Logon(new { User = "seb", Password = "seb" });</pre><p></p>
<p>D’un point de vue .NET, l’invocation dynamique de notre MessageCallback  “Logon » sur le proxy dynamique ne retourne rien, du moins il retourne “null”.</p>
<p></p><pre class="crayon-plain-tag">object result = PackageHost.CreateMessageProxy("MonPremierPackage").Logon(new { User = "seb", Password = "seb" });
// ici result = null</pre><p></p>
<p>Observez maintenant le code ci-dessous :</p>
<p></p><pre class="crayon-plain-tag">Task&lt;dynamic&gt; reponse = PackageHost.CreateMessageProxy("MonPremierPackage").Logon&lt;bool&gt;(new { User = "seb", Password = "seb" });</pre><p></p>
<p>Si vous examinez attentivement le MessageCallback que nous invoquons sur le proxy dynamique, on utilise une forme générique : au lieu d’avoir “Logon(xxxxx)”, on a ”Logon<strong>&lt;bool&gt;</strong>(xxxxx)<em>”</em></p>
<p>Le fait de définir un type générique indique au proxy dynamique que vous attendez une réponse et donc qu’il s’agit d’une saga !</p>
<p>Le type générique est le type de réponse que vous attendez. Ici le MessageCallback “Logon” que vous avons écrit dans l’article précédent renvoi un booléen (bool). Vous pouvez utiliser n’importe quel type de base ou types complexes.</p>
<p>Si c’est la réponse est un objet anonyme ou si vous n’avez pas la définition de l’objet de retour dans votre code,  vous pouvez utiliser un “dynamic” (ex <em>Logon<strong>&lt;dynamic&gt;</strong>(xxxx)</em>)<em>.</em></p>
<p>Quoi qu’il en soit il est obligatoire d’invoquer le MessageCallback  en utilisant la syntaxe générique pour que le proxy dynamique ajoute automatiquement un identifiant de saga (<em>WithSaga</em>) lors de l’envoi du message.</p>
<p>Revenons donc à notre appel :</p>
<p></p><pre class="crayon-plain-tag">Task&lt;dynamic&gt; reponse = PackageHost.CreateMessageProxy("MonPremierPackage").Logon&lt;bool&gt;(new { User = "seb", Password = "seb" });</pre><p></p>
<p>Le proxy dynamique nous retourne une ”Task&lt;dynamic&gt;”, c’est à dire une tache qui se charge d’envoyer et d’attendre la réception de la (première) réponse.</p>
<p>Vous pouvez bloquer le thread appelant jusqu&rsquo;à ce que l&rsquo;opération asynchrone soit terminée,  c’est à dire jusqu’à l’obtention de la réponse :</p>
<p></p><pre class="crayon-plain-tag">Task&lt;dynamic&gt; reponse = PackageHost.CreateMessageProxy("MonPremierPackage").Logon&lt;bool&gt;(new { User = "seb", Password = "seb" });
PackageHost.WriteInfo((bool)reponse.Result ? "OK" : "DENIED");</pre><p></p>
<h4>Ajouter des timeouts</h4>
<p>Comme vous bloquez le thread appelant, prenez garde de mettre des gardes fou car nous n’avez aucune garantie qu’un package va répondre à votre saga. La tache pourrait ne jamais être complétée! Vous devriez donc attendre un certain temps avant de considérer la tache “hors délai”.</p>
<p>Par exemple attendons pendant 3 secondes maximum pour une réponse à notre Saga “Logon” :</p>
<p></p><pre class="crayon-plain-tag">Task&lt;dynamic&gt; reponse = PackageHost.CreateMessageProxy("MonPremierPackage").Logon&lt;bool&gt;(new { User = "seb", Password = "seb" });
if (reponse.Wait(3000) &amp;&amp; reponse.IsCompleted)
{
    PackageHost.WriteInfo((bool)reponse.Result ? "OK" : "DENIED");
}
else
{
    PackageHost.WriteError("Aucune réponse !");
}</pre><p></p>
<h4>Async/Await</h4>
<p>Aussi vous pouvez utiliser le pattern async/await, très pratique pour les packages UI WPF/Winform :</p>
<p></p><pre class="crayon-plain-tag">public async void Logon()
{
    bool reponse = await PackageHost.CreateMessageProxy("MonPremierPackage").Logon&lt;bool&gt;(new { User = "seb", Password = "seb" });
    PackageHost.WriteInfo(reponse ? "OK" : "DENIED");
}</pre><p></p>
<h4>Résultat de la tache</h4>
<p>Notez bien que le proxy dynamique vous renverra toujours une “Task&lt;<strong>dynamic</strong>&gt;” quelque soit le type générique précisé au niveau de l’appel du MessageCallback (“bool” dans l’exemple du “Logon”).</p>
<p>Cependant le résultat de la tache (<em>Task.Result</em>) est bien du type que celui passé au niveau de l’appel du MessageCallback.</p>
<p>Si vous souhaitez toutefois récupérer une Task&lt;T&gt; où T est le type de retour de votre saga, vous devez créer une nouvelle tache pour réaliser le “cast” à la suite de la tache créée par Constellation.</p>
<p>Par exemple :</p>
<p></p><pre class="crayon-plain-tag">Task&lt;dynamic&gt; task = PackageHost.CreateMessageProxy("MonPremierPackage").Logon&lt;bool&gt;(new { User = "seb", Password = "seb" });
Task&lt;bool&gt; logonTask = task.ContinueWith&lt;bool&gt;(t =&gt; (bool)t.Result);</pre><p></p>
<h4>Annuler les taches</h4>
<p>Lorsque l’on créé des taches en .NET on peut avoir besoin de leurs associer un jeton d’annulation : le <em>CancellationToken</em>.</p>
<p>Pour cela, il vous suffit de passer un “CancellationToken” comme dernier argument de votre invocation du MessageCallback :</p>
<p></p><pre class="crayon-plain-tag">CancellationTokenSource source = new CancellationTokenSource(1000);
CancellationToken token = source.Token;
try
{
    Task&lt;dynamic&gt; reponse = PackageHost.CreateMessageProxy("ConstellationPackageConsole1").Logon&lt;bool&gt;(new { User = "seb", Password = "seb" }, token);
    PackageHost.WriteInfo("Result = {0}", reponse.Result);
}
catch (AggregateException ae)
{
    foreach (Exception e in ae.InnerExceptions)
    {
        if (e is TaskCanceledException)
            PackageHost.WriteError("Unable to compute mean: {0}", ((TaskCanceledException)e).Message);
        else
            PackageHost.WriteError("Exception: " + e.GetType().Name);
    }
}
finally
{
    source.Dispose();
}</pre><p></p>
<p>Dans l’exemple ci-dessus on crée un <em>CancellationToken</em> à partir d’un <em>CancellationTokenSource</em> que l’on passe en tant que dernier paramètre du MessageCallback.</p>
<p>Le <em>CancellationTokenSource</em> est ici construit pour annuler la tache après 1 seconde (1000 ms). Vous pouvez aussi annuler la tache en en appelant la méthode “Cancel” sur l&rsquo;objet <em>CancellationTokenSource</em> :</p>
<p></p><pre class="crayon-plain-tag">source.Cancel();</pre><p></p>
<p>Bien entendu, le proxy dynamique se sert de votre <em>CancellationToken</em> pour savoir quand annuler la tache. De plus notez bien que le proxy retire ce <em>CancellationToken</em> des paramètres du message (= le <em>CancellationToken</em> n’est pas envoyé dans le message !).</p>
<p>Prenez garde à bien gérer les exceptions, si la tache est annulée une exception “<em>TaskCanceledException</em>” est levée.</p>
<h4>Le contexte du message</h4>
<p>Dans une méthode marquée comme “MessageCallback” ou dans le callback de retour d’une saga (<em>OnSagaResponse</em>) vous pouvez toujours accéder au contexte de réception du message avec la propriété “<em>MessageContext.Current</em>”.</p>
<p>En effet les MessageCallbacks ou les callbacks de retour des sagas sont invoqués dans un thread à part ce qui permet de l’attacher au contexte de réception du message.</p>
<p>Cependant avec les taches, le résultat est dispatché dans le thread de l’appelant. Autrement dit, vous ne pouvez pas accéder au contexte courant (<em>MessageContext.Current</em>) !</p>
<p>La solution consiste à “demander” au proxy dynamique de vous “remplir” un contexte que vous avez initialisé au préalable.</p>
<p>Pour ce faire, commencez par déclarer un contexte vide (<em>MessageContext.None</em>) et passer l’instance comme dernier paramètre d&rsquo;un appel :</p>
<p></p><pre class="crayon-plain-tag">MessageContext context = MessageContext.None;
Task&lt;dynamic&gt; reponse = PackageHost.CreateMessageProxy("ConstellationPackageConsole1").Logon&lt;bool&gt;(new { User = "seb", Password = "seb" }, context);
PackageHost.WriteInfo("Result = {0} - Response received from : {1}", reponse.Result, context.Sender.FriendlyName);</pre><p></p>
<p>Une fois la tache complétée, la variable “context” sera remplie avec le contexte de la réponse lors de la réception. Vous pourrez donc accéder au contexte même dans vos taches.</p>
<p>Le MessageContext est toujours le dernière paramètr et le CancellationToken est donc l’avant dernier paramètre dans le cas où vous utilisez les deux :</p>
<p></p><pre class="crayon-plain-tag">CancellationTokenSource source = new CancellationTokenSource(1000);
CancellationToken token = source.Token;
MessageContext context = MessageContext.None;
try
{
    Task&lt;dynamic&gt; reponse = PackageHost.CreateMessageProxy("ConstellationPackageConsole1").Logon&lt;bool&gt;(new { User = "seb", Password = "seb" }, token, context);
    PackageHost.WriteInfo("Result = {0} - Response received from : {1}", reponse.Result, context.Sender.FriendlyName);
}
catch (AggregateException ae)
{
    foreach (Exception e in ae.InnerExceptions)
    {
        if (e is TaskCanceledException)
            PackageHost.WriteError("Unable to compute mean: {0}", ((TaskCanceledException)e).Message);
        else
            PackageHost.WriteError("Exception: " + e.GetType().Name);
    }
}
finally
{
    source.Dispose();
}</pre><p></p>
<h3>Générateur de code</h3>
<p>Comme l’ensemble des MessageCallbacks sont déclarés dans la Constellation (sauf si ils sont marqués comme “<a href="/client-api/net-package-api/messagecallbacks/#MessageCallback_cache">Hidden</a>”), il est possible de générer du code. Vous pouvez <a href="/constellation-platform/constellation-sdk/generateur-de-code/">lire un article très complet sur le sujet ici</a>.</p>
<p>Dans le menu contextuel de votre projet Visual Studio, sélectionnez “Generate Code” :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/03/image-125.png"><img class="colorbox-1379"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="Générer du code" src="https://developer.myconstellation.io/wp-content/uploads/2016/03/image_thumb-102.png" alt="Générer du code" width="424" height="330" border="0" /></a></p>
<p align="left">Sélectionnez votre Constellation et cliquez sur “Discover” :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/03/image-126.png"><img class="colorbox-1379"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="Générer du code" src="https://developer.myconstellation.io/wp-content/uploads/2016/03/image_thumb-103.png" alt="Générer du code" width="424" height="469" border="0" /></a></p>
<p align="left">Sélectionnez le ou les packages que vous souhaitez invoquer depuis votre package et cliquez sur “Generate”.</p>
<p align="left">Le générateur de code va créer différentes classes présentant votre Constellation avec les packages sélectionnés (MessageCallbacks et StateObjects).</p>
<p align="left">Dans notre cas nous allons inclure la définition des MessagesCallbacks de notre package “MonPremierPackage”.</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/03/image-127.png"><img class="colorbox-1379"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="Ajout du using" src="https://developer.myconstellation.io/wp-content/uploads/2016/03/image_thumb-104.png" alt="Ajout du using" width="424" height="132" border="0" /></a></p>
<p align="left">Commençons donc par ajouter le using vers le MessageCallbacks de MonPremierPackage :</p>
<p></p><pre class="crayon-plain-tag">using ConstellationPackageConsole1.MonPremierPackage.MessageCallbacks;</pre><p></p>
<p align="left">Dans la classe générée “MyConstellation” vous retrouverez la liste des sentinelles et packages de votre Constellation :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/03/image-128.png"><img class="colorbox-1379"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="Enumération générée" src="https://developer.myconstellation.io/wp-content/uploads/2016/03/image_thumb-105.png" alt="Enumération générée" width="424" height="65" border="0" /></a></p>
<p>Vous pourrez alors créer un scope personnalisé pour le package sélectionné :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/03/image-129.png"><img class="colorbox-1379"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="MessageScope généré par package" src="https://developer.myconstellation.io/wp-content/uploads/2016/03/image_thumb-106.png" alt="MessageScope généré par package" width="424" height="84" border="0" /></a></p>
<p align="left">Ce scope personnalisé contiendra l’ensemble des MessageCallbacks :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/03/image-130.png"><img class="colorbox-1379"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="image" src="https://developer.myconstellation.io/wp-content/uploads/2016/03/image_thumb-107.png" alt="image" width="424" height="69" border="0" /></a></p>
<p align="left">Et sur chaque MessageCallback, vous retrouvez les bons types de retour, les commentaires et les types complexes proprement générés :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/03/image-131.png"><img class="colorbox-1379"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="MessageCallbacks générés" src="https://developer.myconstellation.io/wp-content/uploads/2016/03/image_thumb-108.png" alt="MessageCallbacks générés" width="424" height="67" border="0" /></a></p>
<p>De ce fait, pour reprendre l’exemple du MessageCallback “Logon”, on pourra écrire le code :</p>
<p></p><pre class="crayon-plain-tag">var context = MessageContext.None;
var token = new CancellationTokenSource(5000).Token;
var user = new UserInfo() { User = "seb", Password = "seb" };

var task = MyConstellation.Packages.MonPremierPackage.CreateMonPremierPackageScope().Logon(user, token, out context);

PackageHost.WriteInfo("Logon user {0} - Result = {1} - Sender : {2}", user.User, task.Result, context.Sender.FriendlyName);</pre><p></p>
<p><a href="https://developer.myconstellation.io/wp-content/uploads/2016/03/image-132.png"><img class="colorbox-1379"  loading="lazy" style="background-image: none; float: none; padding-top: 0px; padding-left: 0px; margin-left: auto; display: block; padding-right: 0px; margin-right: auto; border-width: 0px;" title="Démonstration" src="https://developer.myconstellation.io/wp-content/uploads/2016/03/image_thumb-109.png" alt="Démonstration" width="424" height="205" border="0" /></a></p>
<p>N’hésitez pas <a href="/constellation-platform/constellation-sdk/generateur-de-code/">lire cet article très complet sur la génération de code C#</a> dans Constellation.</p>
<p>The post <a rel="nofollow" href="https://developer.myconstellation.io/client-api/net-package-api/envoyer-des-messages-invoquer-des-messagecallbacks/">Envoyer des messages &#038; Invoquer des MessageCallbacks</a> appeared first on <a rel="nofollow" href="https://developer.myconstellation.io">Constellation</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://developer.myconstellation.io/client-api/net-package-api/envoyer-des-messages-invoquer-des-messagecallbacks/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Consommer Constellation avec l&#8217;API Javascript</title>
		<link>https://developer.myconstellation.io/client-api/javascript-api/consommer-constellation-api-javascript/</link>
					<comments>https://developer.myconstellation.io/client-api/javascript-api/consommer-constellation-api-javascript/#respond</comments>
		
		<dc:creator><![CDATA[Sebastien Warin]]></dc:creator>
		<pubDate>Thu, 18 Aug 2016 14:41:46 +0000</pubDate>
				<category><![CDATA[Javascript API]]></category>
		<category><![CDATA[SendMessage]]></category>
		<category><![CDATA[ReceiveMessage]]></category>
		<category><![CDATA[Consumer]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[StateObject]]></category>
		<category><![CDATA[Saga]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[API]]></category>
		<guid isPermaLink="false">https://developer.myconstellation.io/?p=2327</guid>

					<description><![CDATA[<p>Connecter une page HTML avec l’API Javascript Vous pouvez soit utiliser le gestionnaire de package Nuget depuis Visual Studio pour installer la dernière version du package “Constellation.Javascript” et ses dépendances : Ou bien utiliser (ou copier en local) les scripts</p>
<p>The post <a rel="nofollow" href="https://developer.myconstellation.io/client-api/javascript-api/consommer-constellation-api-javascript/">Consommer Constellation avec l&rsquo;API Javascript</a> appeared first on <a rel="nofollow" href="https://developer.myconstellation.io">Constellation</a>.</p>
]]></description>
										<content:encoded><![CDATA[<h3>Connecter une page HTML avec l’API Javascript</h3>
<p>Vous pouvez soit utiliser le gestionnaire de package Nuget depuis Visual Studio pour installer la dernière version du package “Constellation.Javascript” et ses dépendances :</p>
<p align="center"><img class="colorbox-2327"  src="https://developer.myconstellation.io/wp-content/uploads/2016/07/image.png" alt="image" /></p>
<p>Ou bien utiliser (ou copier en local) les scripts des CDN en ajoutant dans votre code HTML les balises suivantes :</p>
<p></p><pre class="crayon-plain-tag">&lt;script type="text/javascript" src="https://code.jquery.com/jquery-2.2.4.min.js"&gt;&lt;/script&gt;
&lt;script type="text/javascript" src="https://ajax.aspnetcdn.com/ajax/signalr/jquery.signalr-2.2.2.min.js"&gt;&lt;/script&gt;
&lt;script type="text/javascript" src="https://cdn.myconstellation.io/js/Constellation-1.8.2.min.js"&gt;&lt;/script&gt;</pre><p></p>
<p>Une fois les scripts ajoutés dans votre page vous devez initialiser le client Constellation en spécifiant l’URL de votre serveur Constellation, la clé d’accès et le “Friendly name” de votre page :</p>
<p></p><pre class="crayon-plain-tag">var constellation = $.signalR.createConstellationConsumer("http://localhost:8088", "123456789", "Test API JS");</pre><p></p>
<p>Vous pouvez <a href="/constellation-platform/constellation-console/gerer-credentials-avec-la-console-constellation/">créer une clé d’accès depuis la Console Constellation</a> ou en <a href="/constellation-platform/constellation-server/fichier-de-configuration/#Section_credentials">éditant le fichier de configuration du serveur</a>.</p>
<p>Enfin ajoutons un handler sur le changement d’état de la connexion pour afficher le message “Je suis connecté” dans la console de votre navigateur par exemple lorsque la connexion à Constellation est établie :</p>
<p></p><pre class="crayon-plain-tag">constellation.connection.stateChanged(function (change) {
    if (change.newState === $.signalR.connectionState.connected) {
        console.log("Je suis connecté");
    }
});</pre><p></p>
<p>Il ne reste plus qu’à lancer la connexion en invoquant la méthode Start :</p>
<p></p><pre class="crayon-plain-tag">constellation.connection.start();</pre><p></p>
<p>Et voilà, votre page est connectée à votre Constellation.</p>
<h3>Envoyer des messages et invoquer des MessageCallbacks</h3>
<h4>Envoyer des messages</h4>
<p>Pour envoyer des messages et donc invoquer des MessageCallbacks vous devez utiliser la méthode “<em>constellation.server.sendMessage</em>” en spécifiant :</p>
<ul>
<li>Le scope</li>
<li>La clé du message</li>
<li>Le contenu du message (= les paramètres du MessageCallback)</li>
</ul>
<p>Par exemple, avec le package <a href="/package-library/nest/">Nest </a>déployé dans votre Constellation, on retrouvera un MessageCallback  “SetTargetTemperature” pour piloter la température de consigne d’un thermostat Nest.</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/09/image-21.png"><img class="colorbox-2327"  loading="lazy" title="image" src="https://developer.myconstellation.io/wp-content/uploads/2016/09/image_thumb-20.png" alt="image" width="350" height="99" border="0" /></a></p>
<p align="left">N’hésitez pas à utiliser le <a href="/constellation-platform/constellation-console/messagecallbacks-explorer/">MessageCallback Explorer</a> pour découvrir l’ensemble des MessageCallbacks exposés par les packages de votre Constellation.</p>
<p>Pour invoquer le MessageCallback  “SetTargetTemperature” depuis votre page Web en passant en paramètre l&rsquo;ID du thermostat et la température de consigne :</p>
<p></p><pre class="crayon-plain-tag">constellation.server.sendMessage({ Scope: 'Package', Args: ['Nest'] }, 'SetTargetTemperature', 'thermostatId', 19);</pre><p></p>
<p>Vous pouvez également passer plusieurs arguments à votre MC combinant type simple et type complexe.</p>
<p>Par exemple le MC “ShowNotification” du package <a href="/package-library/xbmc/">Xbmc </a>permettant d’afficher une notification sur une interface Kodi/XBMC prend deux paramètres : le nom d l’hôte XBMC (un type string) et le détail de la notification à afficher (un type complexe) :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/09/image-23.png"><img class="colorbox-2327"  loading="lazy" title="image" src="https://developer.myconstellation.io/wp-content/uploads/2016/09/image_thumb-22.png" alt="image" width="350" height="143" border="0" /></a></p>
<p></p><pre class="crayon-plain-tag">constellation.server.sendMessage({ Scope: 'Package', Args: ['Xbmc'] }, 'ShowNotification', xbmcName, { "Title":"Hello", "Message":"Hello from JS" });</pre><p></p>
<p>Bien entendu vous pouvez invoquer des MessageCallbacks de n’importe quel package, réel (programme Linux/Windows) ou virtuel (Arduino/ESP) ou même sur d’autres consommateurs (pages Web par exemple).</p>
<p>Ainsi vos pages Web peuvent, en envoyant des messages, invoquer des méthodes sur n&rsquo;importe quel système connecté dans votre Constellation.</p>
<p>Par exemple dans l’article sur les ESP/Arduinos, notre ESP8266 exposait un MC “Reboot” pour redémarrer la puce. Si l’on souhaite redémarrer notre Arduino/ESP depuis une page Web, il suffit d’envoyer un message sans paramètre au bon scope. Par exemple :</p>
<p></p><pre class="crayon-plain-tag">constellation.server.sendMessage({ Scope: 'Sentinel', Args: ['MyArduino'] }, 'Reboot');</pre><p></p>
<p>Ici le scope est “Sentinel” avec l’argument “MyArduino”, c’est à dire que le message “Reboot” sera envoyé à tous les packages de la sentinelle “MyArduino”.</p>
<p>Les <a href="/concepts/messaging-message-scope-messagecallback-saga/">scopes</a> peuvent être :</p>
<ul>
<li>Sentinel</li>
<li>Package</li>
<li>Group</li>
<li>Others</li>
<li>All</li>
</ul>
<p>La propriété “Args” de l’objet scope est un tableau contenant le nom des groupes, des sentinelles ou packages en fonction du type de scope sélectionné. Seuls les scopes “All” et “Others” n’ont pas besoin d’argument.</p>
<h4>Envoyer des messages avec réponse : les sagas</h4>
<p>Les <a href="https://developer.myconstellation.io/concepts/messaging-message-scope-messagecallback-saga/">Sagas</a> permettent de lier des messages et donc de créer des couples de “requêtes / réponses”.</p>
<p>Avec la libraire JavaScript, il est possible d’envoyer des messages dans une saga et d’enregistrer un callback pour traiter la réponse.</p>
<p>Par exemple, le package “<a href="/package-library/networktools/">NetworkTools</a>” expose un MC “Ping” permettant de réaliser un ping réseau. Le résultat du ping est retourné dans un message de réponse (un Int64 représentant le temps du réponse du ping) :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/09/image-25.png"><img class="colorbox-2327"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="image" src="https://developer.myconstellation.io/wp-content/uploads/2016/09/image_thumb-24.png" alt="image" width="350" height="155" border="0" /></a></p>
<p align="left">De ce fait pour réaliser un ping vers « www.google.fr » depuis une page Web :</p>
<p></p><pre class="crayon-plain-tag">constellation.server.sendMessageWithSaga(function(response) {
        console.log("Ping %s ms", response.Data);
    }, { Scope: 'Package', Args: ['NetworkTools'] }, 'Ping', "www.google.fr");</pre><p></p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/09/image-26.png"><img class="colorbox-2327"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="image" src="https://developer.myconstellation.io/wp-content/uploads/2016/09/image_thumb-25.png" alt="image" width="350" height="160" border="0" /></a></p>
<p align="left"><a href="/client-api/arduino-esp-api/recevoir-des-messages-et-exposer-des-methodes-messagecallback-sur-arduino-esp/#Exposer_des_MessageCallbacks_avec_reponse_les_sagas">Souvenez-vous de notre package virtuel de notre ESP8266 / Arduino</a>, on exposait un MessageCallback “Addition” capable de réaliser une addition locale (sur le CPU de l’Arduino ou ESP) en prenant en paramètre deux entiers. Le résultat était retourné dans la saga.</p>
<p></p><pre class="crayon-plain-tag">constellation.server.sendMessageWithSaga(function(response) {
        console.log("Le resultat de 40+2 par l'Arduino est %s", response.Data);
    }, { Scope: 'Sentinel', Args: ['MyArduino'] }, 'Addition', 40, 2);</pre><p></p>
<p>Ainsi vos pages Web peuvent invoquer des méthodes et exploiter la réponse de tous les systèmes connectés sur Constellation exposant des MessageCallbacks.</p>
<h3>Recevoir des messages</h3>
<p>Une page Web connectée sur Constellation peut elle même recevoir des messages et donc exposer des MessageCallbacks que d’autres consommateurs (autres pages Web) ou packages (réels et virtuels) pourront invoquer.</p>
<p>Ceci dit un consommateur tel qu’une page Web n’a pas réellement d’existence. Autrement dit elle n’a pas d’identité et donc ne peut recevoir que des messages adressés à un groupe qu’elle devra joindre.</p>
<p>Pour joindre un groupe vous devez utiliser la méthode “subscribeMessages“ (et “unSubscribeMessages” pour en sortir). Vous pouvez joindre autant de groupe que vous souhaitez.</p>
<p>Par exemple, pour ajouter votre page au groupe “Demo” :</p>
<p></p><pre class="crayon-plain-tag">constellation.server.subscribeMessages("Demo");</pre><p></p>
<p>Vous pourrez ensuite recevoir les messages envoyés dans ce groupe en ajoutant un handler sur le “onReceiveMessage” :</p>
<p></p><pre class="crayon-plain-tag">constellation.client.onReceiveMessage(function (message) {
    console.log("Message recu !", message);
});</pre><p></p>
<p>Dans ce handler vous recevrez TOUS les messages (quelque soit la clé du message).</p>
<p>Vous avez aussi un moyen plus simple consistant à définir un handler pour une clé de message spécifiquement via la méthode “registerMessageCallback”.</p>
<p>Par exemple :</p>
<p></p><pre class="crayon-plain-tag">constellation.client.registerMessageCallback("ChangeTitle", function (msg) {
    document.title = msg.Data;
});
constellation.client.registerMessageCallback("HelloWorld", function (msg) {
    alert("Hello World");
});</pre><p></p>
<p>Ici on enregistre deux MessageCallbacks.</p>
<p>Si votre page reçoit un MessageCallback “HelloWorld”, une alerte sera ouverte, si elle reçoit un MessageCallback “ChangeTitle”, le titre de votre page sera modifié avec l’argument passé dans le MC.</p>
<p>Imaginez par exemple que vous ouvrez une page Web en plein écran sur différents devices dont vous n’avez pas de contrôle (par exemple des écrans Dashboard). Sur cette page vous affichez différentes données en temps réel, par exemple basées sur les StateObjects Constellation.</p>
<p>Vous modifiez votre page et vous souhaitez donc la rafraîchir sur tous les navigateurs qui ont ouvert votre page pour recharger la nouvelle version.</p>
<p>Pour ce faire, vous pouvez facilement exposer un MessageCallback “ReloadMe” qui recharge la page avec le code :</p>
<p></p><pre class="crayon-plain-tag">constellation.client.registerMessageCallback("ReloadMe", function (msg) {
    location.reload();
});</pre><p></p>
<p>Puis vous ajoutez votre page dans le groupe “ControlPage” :</p>
<p></p><pre class="crayon-plain-tag">constellation.server.subscribeMessages("ControlPage");</pre><p></p>
<p>Dans ce fait, vous pouvez maintenant créer une page “cachée” avec un bouton pour invoquer le MessageCallback “ReloadMe” sur le groupe “ControlPage” afin de recharger toutes les navigateurs qui ont ouvert votre page par la ligne :</p>
<p></p><pre class="crayon-plain-tag">constellation.server.sendMessage({ Scope:'Group', Args:['ControlPage'] }, "ReloadMe", {});</pre><p></p>
<p>Bien entendu, comme vos pages HTML peuvent enregistrer autant de MessageCallbacks qu’elles souhaitent et que ces MessageCallbacks sont invocables depuis n’importe quel système connecté à Constellation, d’autres pages Web, des objets à base d’Arduino, ESP ou autre, des programmes Python, .NET, etc… vous pouvez imaginer tout type d’usage.</p>
<h3>Consommer des StateObjects</h3>
<p>Pour consommer des StateObjects produits par des packages (virtuels ou réels) de votre Constellation, vous avez deux méthodes : l’évènement “onUpdateStateObject” ou les StateObjectLinks.</p>
<p>La première méthode consiste à enregistre un ou plusieurs handlers sur l’évènement “onUpdateStateObject” :</p>
<p></p><pre class="crayon-plain-tag">constellation.client.onUpdateStateObject(function (stateobject) {
    console.log(stateobject);
});</pre><p></p>
<p>Les handlers seront déclenchés à chaque mise à jour ou interrogation des StateObjects de votre page quelque soit le StateObject.</p>
<p>Pour interroger un ou plusieurs StateObjects à un instant T vous disposez de la méthode “requestStateObjects”.</p>
<p>Pour vous abonner aux mises à jour d’un ou plusieurs StateObjects, vous disposez de la méthode “subscribeStateObjects” (et “unSubscribeStateObjects” pour vous désabonner).</p>
<p>Enfin la méthode “requestSubscribeStateObjects” réalise un “requestStateObjects” et un “subscribeStateObjects” c’est à dire que la méthode demande la valeur actuelle du ou des StateObjects et s’abonne auprès du serveur Constellation pour être notifiée des mises à jour.</p>
<p>Toutes ces méthodes prennent en paramètre : le nom de la sentinelle, le nom du package, le nom du StateObject et le type du StateObject. Vous pouvez utiliser le wildcard “*” pour ne pas appliquer de filtre (<a href="/concepts/stateobjects/">plus d’information ici</a>).</p>
<p>Par exemple, pour récupérer tous les StateObjects du package “Demo” quelque soit la sentinelle et pour s’abonner aux mises à jour de ces StateObjects :</p>
<p></p><pre class="crayon-plain-tag">constellation.server.requestSubscribeStateObjects("*", "Demo", "*", "*");</pre><p></p>
<p>L’autre méthode consiste à enregistrer un (ou plusieurs) StateObjectLink. Cela permet de lier une fonction à un abonnement.</p>
<p>Par exemple :</p>
<p></p><pre class="crayon-plain-tag">constellation.client.registerStateObjectLink("*", "HWMonitor", "/intelcpu/0/load/0", "*", function (so) {
    // Code A
});

constellation.client.registerStateObjectLink("*", "Demo", "*", "*", function (so) {
    // Code B
});</pre><p></p>
<p>Ci-dessus le code A sera invoqué dès qu’un SO nommé « /intelcpu/0/load/0” et produit par le package “HWMonitor” est modifié alors que le code B sera déclenché dès qu’un StateObject du package “Demo” est modifié.</p>
<p>The post <a rel="nofollow" href="https://developer.myconstellation.io/client-api/javascript-api/consommer-constellation-api-javascript/">Consommer Constellation avec l&rsquo;API Javascript</a> appeared first on <a rel="nofollow" href="https://developer.myconstellation.io">Constellation</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://developer.myconstellation.io/client-api/javascript-api/consommer-constellation-api-javascript/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Consommer Constellation avec Angular JS</title>
		<link>https://developer.myconstellation.io/client-api/javascript-api/consommer-constellation-angular-js/</link>
					<comments>https://developer.myconstellation.io/client-api/javascript-api/consommer-constellation-angular-js/#comments</comments>
		
		<dc:creator><![CDATA[Sebastien Warin]]></dc:creator>
		<pubDate>Fri, 19 Aug 2016 08:27:12 +0000</pubDate>
				<category><![CDATA[Javascript API]]></category>
		<category><![CDATA[Consumer]]></category>
		<category><![CDATA[Subscribe]]></category>
		<category><![CDATA[StateObject]]></category>
		<category><![CDATA[Saga]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[SendMessage]]></category>
		<category><![CDATA[ReceiveMessage]]></category>
		<category><![CDATA[AngularJS]]></category>
		<guid isPermaLink="false">https://developer.myconstellation.io/?p=2331</guid>

					<description><![CDATA[<p>Préparer la page AngularJS Vous pouvez soit utiliser le gestionnaire de package Nuget depuis Visual Studio pour installer la dernière version du package “Constellation.Angular” et ses dépendances : Ou bien utiliser (ou copier en local) les scripts des CDN en</p>
<p>The post <a rel="nofollow" href="https://developer.myconstellation.io/client-api/javascript-api/consommer-constellation-angular-js/">Consommer Constellation avec Angular JS</a> appeared first on <a rel="nofollow" href="https://developer.myconstellation.io">Constellation</a>.</p>
]]></description>
										<content:encoded><![CDATA[<h3>Préparer la page AngularJS</h3>
<p>Vous pouvez soit utiliser le gestionnaire de package Nuget depuis Visual Studio pour installer la dernière version du package “Constellation.Angular” et ses dépendances :</p>
<p align="center"><img class="colorbox-2331"  src="https://developer.myconstellation.io/wp-content/uploads/2016/07/image.png" alt="image" /></p>
<p>Ou bien utiliser (ou copier en local) les scripts des CDN en ajoutant dans votre code HTML les balises suivantes :</p>
<p></p><pre class="crayon-plain-tag">&lt;script type="text/javascript" src="https://code.jquery.com/jquery-2.2.4.min.js"&gt;&lt;/script&gt;
&lt;script type="text/javascript" src="https://ajax.aspnetcdn.com/ajax/signalr/jquery.signalr-2.2.2.min.js"&gt;&lt;/script&gt;
&lt;script type="text/javascript" src="https://cdn.myconstellation.io/js/Constellation-1.8.2.min.js"&gt;&lt;/script&gt;
&lt;script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.7/angular.min.js"&gt;&lt;/script&gt;
&lt;script type="text/javascript" src="https://cdn.myconstellation.io/js/ngConstellation-1.8.2.min.js"&gt;&lt;/script&gt;</pre><p></p>
<p>Dans votre code Javascript, vous devez créer un module Angular pour votre page que nous appelleront “MyDemoApp” et dans lequel nous injecterons le module “ngConstellation” :</p>
<p></p><pre class="crayon-plain-tag">var myDemoApp = angular.module('MyDemoApp', ['ngConstellation']);</pre><p></p>
<p>Vous devez également ajouter l’attribut “ng-app” sur la balise &lt;html&gt; de votre page pour lier votre page HTML à votre module Angular :</p>
<p></p><pre class="crayon-plain-tag">&lt;html xmlns="http://www.w3.org/1999/xhtml" ng-app="MyDemoApp"&gt;</pre><p></p>
<p>Enfin vous devez créer un contrôleur AngularJS dans lequel nous injecterons la factory “constellationConsumer” que nous appellerons dans notre code “constellation” :</p>
<p></p><pre class="crayon-plain-tag">myDemoApp.controller('MyController', ['$scope',  'constellationConsumer', function ($scope, constellation) {

}]);</pre><p></p>
<p>Sans oublier de lier votre corps de page (&lt;body&gt;) à ce contrôleur :</p>
<p></p><pre class="crayon-plain-tag">&lt;body ng-controller="MyController"&gt;</pre><p></p>
<p>Et voilà votre squelette est prêt !</p>
<p>Pour plus d’information sur AngularJS, je vous recommande la lecture de ce guide : <a title="https://docs.angularjs.org/misc/started" href="https://docs.angularjs.org/misc/started">https://docs.angularjs.org/misc/started</a></p>
<p>Pour résumer notre squelette page est donc :</p>
<p></p><pre class="crayon-plain-tag">&lt;!DOCTYPE html&gt;
&lt;html xmlns="http://www.w3.org/1999/xhtml" ng-app="MyDemoApp"&gt;
&lt;head&gt;
    &lt;title&gt;Test API AngularJS&lt;/title&gt;
    &lt;script type="text/javascript" src="https://code.jquery.com/jquery-2.2.4.min.js"&gt;&lt;/script&gt;
    &lt;script type="text/javascript" src="https://ajax.aspnetcdn.com/ajax/signalr/jquery.signalr-2.2.2.min.js"&gt;&lt;/script&gt;
    &lt;script type="text/javascript" src="https://cdn.myconstellation.io/js/Constellation-1.8.2.min.js"&gt;&lt;/script&gt;
    &lt;script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.7/angular.min.js"&gt;&lt;/script&gt;
    &lt;script type="text/javascript" src="https://cdn.myconstellation.io/js/ngConstellation-1.8.2.min.js"&gt;&lt;/script&gt;
    
    &lt;script&gt;
        var myDemoApp = angular.module('MyDemoApp', ['ngConstellation']);
        myDemoApp.controller('MyController', ['$scope',  'constellationConsumer', function ($scope, constellation) {

        }]);
    &lt;/script&gt;

&lt;/head&gt;
&lt;body ng-controller="MyController"&gt;

&lt;/body&gt;
&lt;/html&gt;</pre><p></p>
<h3>Connecter une page HTML à Constellation avec AngularJS</h3>
<p>Dans notre contrôleur AngularJS, nous allons initialiser le client Consumer en spécifiant l’URL de votre serveur Constellation, la clé d’accès et le “Friendly name” de votre page :</p>
<p></p><pre class="crayon-plain-tag">constellation.initializeClient("http://localhost:8088", "123456789", "TestAPI");</pre><p></p>
<p>Vous pouvez <a href="/constellation-platform/constellation-console/gerer-credentials-avec-la-console-constellation/">créer une clé d’accès depuis la Console Constellation</a> ou en <a href="/constellation-platform/constellation-server/fichier-de-configuration/#Section_credentials">éditant le fichier de configuration du serveur</a>.</p>
<p>Enfin ajoutons un handler sur le changement d’état de la connexion pour afficher le message “Je suis connecté” dans la console de votre navigateur par exemple lorsque la connexion à Constellation est établie :</p>
<p></p><pre class="crayon-plain-tag">constellation.onConnectionStateChanged(function (change) {
    if (change.newState === $.signalR.connectionState.connected) {
        console.log("Je suis connecté !");
    }
});</pre><p></p>
<p>Il ne reste plus qu’à lancer la connexion en invoquant la méthode “connect” :</p>
<p></p><pre class="crayon-plain-tag">constellation.connect();</pre><p></p>
<p>Et voilà, votre page AngularJS est connectée à votre Constellation.</p>
<h3>Envoyer des messages et invoquer des MessageCallbacks</h3>
<h4>Envoyer des messages</h4>
<p>Pour envoyer des messages et donc invoquer des MessageCallbacks vous devez utiliser la méthode “<em>constellation.sendMessage</em>” en spécifiant :</p>
<ul>
<li>Le scope</li>
<li>La clé du message</li>
<li>Le contenu du message (= les paramètres du MessageCallback)</li>
</ul>
<p>Par exemple, avec le package Nest déployé dans votre Constellation, on retrouvera un MessageCallback  “SetTargetTemperature” pour piloter la température de consigne d’un thermostat Nest.</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/09/image-21.png"><img class="colorbox-2331"  loading="lazy" title="image" src="https://developer.myconstellation.io/wp-content/uploads/2016/09/image_thumb-20.png" alt="image" width="350" height="99" border="0" /></a></p>
<p align="left">N’hésitez pas à utiliser le <a href="/constellation-platform/constellation-console/messagecallbacks-explorer/">MessageCallback Explorer</a> pour découvrir l’ensemble des MessageCallbacks exposés par les packages de votre Constellation.</p>
<p>Pour invoquer le MessageCallback  “SetTargetTemperature” depuis votre page Web en passant en paramètre l’ID du thermostat et la température de consigne :</p>
<p></p><pre class="crayon-plain-tag">constellation.sendMessage({ Scope: 'Package', Args: ['Nest'] }, 'SetTargetTemperature', 'my_thermostat_id', 19);</pre><p></p>
<p>En AngularJS, pour lier l’invocation de ce code à un bouton, vous devez simplement ajouter l’attribut “ng-click” sur votre bouton.</p>
<p>Par exemple, dans votre code HTML :</p>
<p></p><pre class="crayon-plain-tag">&lt;body ng-controller="MyController"&gt;
    &lt;button ng-click="SetNestTemperature()"&gt;Set Nest to 19°C&lt;/button&gt;
&lt;/body&gt;</pre><p></p>
<p>Et dans votre contrôleur :</p>
<p></p><pre class="crayon-plain-tag">$scope.SetNestTemperature = function () {
   constellation.sendMessage({ Scope: 'Package', Args: ['Nest'] }, 'SetTargetTemperature', 'my_thermostat_id', 19);
};</pre><p></p>
<p>Autre solution, exposer le client Consumer dans le scope AngularJS :</p>
<p></p><pre class="crayon-plain-tag">$scope.constellation = constellation;</pre><p></p>
<p>Et donc s&rsquo;en servir directement dans le template HTML :</p>
<p></p><pre class="crayon-plain-tag">&lt;body ng-controller="MyController"&gt;
    &lt;button ng-click="constellation.sendMessage({ Scope: 'Package', Args: ['Nest'] }, 'SetTargetTemperature', 'my_thermostat_id', 19)"&gt;Set Nest to 19°C&lt;/button&gt;
&lt;/body&gt;</pre><p></p>
<p>Allons un peu plus loin en ajoutant un champ permettant à l’utilisateur de définir la température de consigne.</p>
<p>Dans le template HTML :</p>
<p></p><pre class="crayon-plain-tag">Temperature : &lt;input type="number" ng-model="targetTemperature" /&gt;
&lt;button ng-click="SetNestTemperature()"&gt;Set target temperature&lt;/button&gt;</pre><p></p>
<p>Le champ “input” est de type “number” et est lié à la variable de scope (le modèle) que nous appellerons “targetTemperature”.</p>
<p>De ce  fait dans notre fonction “SetNestTemperature” nous pouvons récupérer la valeur définie par l’utilisateur :</p>
<p></p><pre class="crayon-plain-tag">$scope.SetNestTemperature = function () {
   constellation.sendMessage({ Scope: 'Package', Args: ['Nest'] }, 'SetTargetTemperature', 'my_thermostat_id', $scope.targetTemperature);
};</pre><p></p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/09/image-29.png"><img class="colorbox-2331"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="image" src="https://developer.myconstellation.io/wp-content/uploads/2016/09/image_thumb-28.png" alt="image" width="350" height="60" border="0" /></a></p>
<p>Comme pour l’<a href="/client-api/javascript-api/consommer-constellation-api-javascript/">API Javascript</a>, vous pouvez également passer plusieurs arguments à votre MC combinant type simple et type complexe. Si il y a plusieurs paramètres vous devez les stocker dans un tableau.</p>
<p>Par exemple le MC “ShowNotification” du package <a href="/package-library/xbmc/">Xbmc</a> permettant d’afficher une notification sur une interface Kodi/XBMC prend deux paramètres : le nom d l’hôte XBMC (un type string) et le détail de la notification à afficher (un type complexe) :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/09/image-23.png"><img class="colorbox-2331"  loading="lazy" title="image" src="https://developer.myconstellation.io/wp-content/uploads/2016/09/image_thumb-22.png" alt="image" width="350" height="143" border="0" /></a></p>
<p></p><pre class="crayon-plain-tag">constellation.sendMessage({ Scope: 'Package', Args: ['Xbmc'] }, 'ShowNotification', xbmcName, { "Title":"Hello", "Message":"Hello from JS" });</pre><p></p>
<p>Bien entendu vous pouvez invoquer des MessageCallbacks de n’importe quel package, réel (programme Linux/Windows) ou virtuel (Arduino/ESP, scripts, etc..) ou même sur d’autres consommateurs (pages Web par exemple).</p>
<p>Ainsi vos pages Web peuvent, en envoyant des messages, invoquer des méthodes sur n&rsquo;importe quel système connecté dans votre Constellation.</p>
<p>Par exemple dans l’article sur les ESP/Arduinos, notre ESP8266 exposait un MC “Reboot” pour redémarrer la puce. Si l’on souhaite redémarrer notre Arduino/ESP depuis une page Web, il suffirai d’envoyer un message sans paramètre au bon scope. Par exemple :</p>
<p></p><pre class="crayon-plain-tag">constellation.sendMessage({ Scope: 'Sentinel', Args: ['MyArduino'] }, 'Reboot');</pre><p></p>
<p>Ici le scope est “Sentinel” avec l’argument “MyArduino”, c’est à dire que le message “Reboot” sera envoyé à tous les packages de la sentinelle “MyArduino”.</p>
<p>Les <a href="/concepts/messaging-message-scope-messagecallback-saga/">scopes</a> peuvent être :</p>
<ul>
<li>Sentinel</li>
<li>Package</li>
<li>Group</li>
<li>Others</li>
<li>All</li>
</ul>
<p>La propriété “Args” de l’objet scope est un tableau contenant le nom des groupes, des sentinelles ou packages en fonction du type de scope sélectionné. Seuls les scopes “All” et “Others” n’ont pas besoin d’argument.</p>
<h4>Envoyer des messages avec réponse : les sagas</h4>
<p>Les <a href="https://developer.myconstellation.io/concepts/messaging-message-scope-messagecallback-saga/">Sagas</a> permettent de lier des messages et donc de créer des couples de “requêtes / réponses”.</p>
<p>Avec la libraire JavaScript, il est possible d’envoyer des messages dans une saga et d’enregistrer un callback pour traiter la réponse de ce message.</p>
<p>Par exemple, le package “NetworkTools” expose un MC “Ping” permettant de réaliser un ping réseau. Le résultat du ping est retourné dans un message de réponse (un Int64 représentant le temps du réponse du ping) :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/09/image_thumb2.png"><img class="colorbox-2331"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; margin: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="image_thumb2" src="https://developer.myconstellation.io/wp-content/uploads/2016/09/image_thumb2_thumb.png" alt="image_thumb2" width="244" height="110" border="0" /></a></p>
<p align="left">De ce fait pour réaliser un ping depuis une page Web, on pourrait proposer à l’utilisateur un champ pour saisir l’adresse à pinger et afficher le résultat dans un paragraphe.</p>
<p></p><pre class="crayon-plain-tag">&lt;body ng-controller="MyController"&gt;
   Host/IP : &lt;input ng-model="host" /&gt;
   &lt;button ng-click="Ping()"&gt;Ping&lt;/button&gt;
   &lt;p ng-show="pingResult"&gt;Result : {{pingResult}}ms&lt;/p&gt;
&lt;/body&gt;</pre><p></p>
<p>Vous remarquez que le paragraphe du n’est affiché (ng-show) que si la valeur de scope “pingResult” est définie, ce qui n’est pas le cas à l’ouverture de la page.</p>
<p>Déclarons enfin la méthode de scope “Ping” pour envoyer un message au package “NetworkTools” afin d’invoquer dans une saga sur le MC “Ping” avec en paramètre du message variable « $scope.host » qui est liée à la zone de texte (input) de votre vue HTML.</p>
<p>Comme il s’agit d’une saga, nous utilisons la méthode “sendMessageWithSaga” dans laquelle nous passons la fonction callback qui sera invoquée lors de la réponse. A la réception cette réponse, nous allons tous simplement stocker le résultat de la réponse (propriété Data) dans la variable de scope “pingResult”.</p>
<p>L’affectation de la réponse dans la variable de scope “pingResult” est réalisée dans un “$scope.$apply”, une fonction AngularJS qui permet d’indiquer au contrôleur AngularJS que des variables de scope ont été modifiées et donc qu’il faut rafraîchir la vue.</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/09/image-30.png"><img class="colorbox-2331"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="image" src="https://developer.myconstellation.io/wp-content/uploads/2016/09/image_thumb-29.png" alt="image" width="350" height="88" border="0" /></a></p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/09/image-31.png"><img class="colorbox-2331"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="image" src="https://developer.myconstellation.io/wp-content/uploads/2016/09/image_thumb-30.png" alt="image" width="350" height="90" border="0" /></a></p>
<p></p><pre class="crayon-plain-tag">scope.Ping = function () {
  constellation.sendMessageWithSaga(function(response) {
      $scope.$apply(function() {
        $scope.pingResult = response.Data;
      });
    }, { Scope: 'Package', Args: ['NetworkTools'] }, 'Ping', $scope.host);
};</pre><p></p>
<p>Ainsi vos pages Web peuvent invoquer des méthodes et exploiter la réponse de tous les systèmes connectés sur Constellation exposant des MessageCallbacks.</p>
<h3>Recevoir des messages</h3>
<p>Une page Web connectée sur Constellation peut elle même recevoir des messages et donc exposer des MessageCallbacks que d’autres consommateurs (autres pages Web) ou packages (réels et virtuels) pourront invoquer.</p>
<p>Ceci dit un consommateur tel qu’une page Web n’a pas réellement d’existence. Autrement dit elle n’a pas d’identité et donc ne peut recevoir que des messages adressés à un groupe qu’elle devra joindre.</p>
<p>Pour joindre un groupe vous devez utiliser la méthode “subscribeMessages“ (et “unSubscribeMessages” pour en sortir). Vous pouvez joindre autant de groupe que vous souhaitez.</p>
<p>Par exemple, pour ajouter votre page au groupe “Demo” :</p>
<p></p><pre class="crayon-plain-tag">constellation.subscribeMessages("Demo");</pre><p></p>
<p>Vous pourrez ensuite recevoir les messages envoyés dans ce groupe en ajoutant un handler sur le “onReceiveMessage” :</p>
<p></p><pre class="crayon-plain-tag">constellation.onReceiveMessage(function (message) {
    console.log("Message recu !", message);
});</pre><p></p>
<p>Dans ce handler vous recevrez TOUS les messages (quelque soit la clé du message).</p>
<p>Vous avez aussi un moyen plus simple consistant à définir un handler pour une clé de message spécifiquement via la méthode “registerMessageCallback”.</p>
<p>Par exemple :</p>
<p></p><pre class="crayon-plain-tag">constellation.registerMessageCallback("ChangeTitle", function (msg) {
    document.title = msg.Data;
});
constellation.registerMessageCallback("HelloWorld", function (msg) {
    alert("Hello World");
});</pre><p></p>
<p>Ici on enregistre deux MessageCallbacks.</p>
<p>Si votre page reçoit un MessageCallback “HelloWorld”, une alerte sera ouverte, si elle reçoit un MessageCallback “ChangeTitle”, le titre de votre page sera modifié avec l’argument passé dans le MC.</p>
<p>Bien entendu, comme vos pages HTML peuvent enregistrer autant de MessageCallbacks qu’elles souhaitent et que ces MessageCallbacks sont invocables depuis n’importe quel système connecté à Constellation, d’autres pages Web, des objets à base d’Arduino, ESP ou autre, des programmes Python, .NET, etc… vous pouvez imaginer tout type d’usage.</p>
<h3>Consommer des StateObjects</h3>
<p>Pour consommer des StateObjects produits par des packages (virtuels ou réels) de votre Constellation, vous avez deux méthodes : l’évènement “onUpdateStateObject” ou les StateObjectLinks.</p>
<p>La première méthode consiste à enregistre un ou plusieurs handlers sur l’évènement “onUpdateStateObject” :</p>
<p></p><pre class="crayon-plain-tag">constellation.onUpdateStateObject(function (stateobject) {
    console.log(stateobject);
});</pre><p></p>
<p>Les handlers seront déclenchés à chaque mise à jour ou interrogation des StateObjects de votre page quelque soit le StateObject.</p>
<p>Pour interroger un ou plusieurs StateObjects à un instant T vous disposez de la méthode “requestStateObjects”.</p>
<p>Pour vous abonner aux mises à jour d’un ou plusieurs StateObjects, vous disposez de la méthode “subscribeStateObjects” (et “unSubscribeStateObjects” pour vous désabonner).</p>
<p>Enfin la méthode “requestSubscribeStateObjects” réalise un “requestStateObjects” et un “subscribeStateObjects” c’est à dire que la méthode demande la valeur actuelle du ou des StateObjects et s’abonne auprès du serveur Constellation pour être notifiée des mises à jour.</p>
<p>Toutes ces méthodes prennent en paramètre : le nom de la sentinelle, le nom du package, le nom du StateObject et le type du StateObject. Vous pouvez utiliser le wildcard “*” pour ne pas appliquer de filtre (<a href="/concepts/stateobjects/">plus d’information ici</a>).</p>
<p>Par exemple, pour récupérer tous les StateObjects du package “Demo” quelque soit la sentinelle et pour s’abonner aux mises à jour de ces StateObjects :</p>
<p></p><pre class="crayon-plain-tag">constellation.requestSubscribeStateObjects("*", "Demo", "*", "*");</pre><p></p>
<p>L’autre méthode consiste à enregistrer un (ou plusieurs) StateObjectLink. Cela permet de lier une fonction à un abonnement.</p>
<p>Par exemple :</p>
<p></p><pre class="crayon-plain-tag">constellation.registerStateObjectLink("*", "HWMonitor", "/intelcpu/0/load/0", "*", function (so) {
    // Code A
});

constellation.registerStateObjectLink("*", "Demo", "*", "*", function (so) {
    // Code B
});</pre><p></p>
<p>Ci-dessus le code A sera invoqué dès qu’un SO nommé « /intelcpu/0/load/0” et produit par le package “HWMonitor” est modifié alors que le code B sera déclenché dès qu’un StateObject du package “Demo” est modifié.</p>
<p>Prenons un cas pratique, nous voulons afficher en temps réel la consommation de notre CPU. Comme expliqué ci-dessus, la consommation peut être connue avec le StateObject nommé « /intelcpu/0/load/0” et produit par le package “HWMonitor”.</p>
<p>Nous allons donc ajouter un StateObjectLink et affecter la variable de scope “cpu” à chaque mise à jour de ce SO. Comme pour la réception de message, nous devons utiliser la fonction Angular “$scope.$apply” pour informer le contrôleur Angular que nous avons changé une variable de scope :</p>
<p>Aussi vous devez enregistrer vos SOLink une fois connecté :</p>
<p></p><pre class="crayon-plain-tag">constellation.onConnectionStateChanged(function (change) {
  if (change.newState === $.signalR.connectionState.connected) {
    constellation.registerStateObjectLink("*", "HWMonitor", "/intelcpu/0/load/0", "*", function (so) {
      $scope.$apply(function() {
        $scope.cpu = so.Value.Value;
      });
    });
  }
});</pre><p></p>
<p>Et dans notre template :</p>
<p></p><pre class="crayon-plain-tag">&lt;body ng-controller="MyController"&gt;
    &lt;p&gt;CPU : {{cpu}}&lt;/p&gt;
&lt;/body&gt;</pre><p></p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/09/image-33.png"><img class="colorbox-2331"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border: 0px;" title="image" src="https://developer.myconstellation.io/wp-content/uploads/2016/09/image_thumb-32.png" alt="image" width="350" height="64" border="0" /></a></p>
<p>Plutôt que stocker dans notre variable de scope la propriété “Value” de la valeur de notre StateObject, nous pouvons aussi stocker le StateObject lui même :</p>
<p></p><pre class="crayon-plain-tag">$scope.cpu = so;</pre><p></p>
<p>De ce fait dans le template nous pouvons afficher différentes informations contenu dans notre StateObject  :</p>
<p></p><pre class="crayon-plain-tag">&lt;body ng-controller="MyController"&gt;
    &lt;p&gt;CPU on {{cpu.SentinelName }} at {{cpu.LastUpdate}} is &lt;strong&gt;{{cpu.Value.Value}} {{cpu.Value.Unit}}&lt;/strong&gt;&lt;/p&gt;
&lt;/body&gt;</pre><p></p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/09/image-32.png"><img class="colorbox-2331"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="image" src="https://developer.myconstellation.io/wp-content/uploads/2016/09/image_thumb-31.png" alt="image" width="350" height="50" border="0" /></a></p>
<p>Alors bien sûr le format de la date ou encore la précision de la valeur mesurée par le package HWMonitor ne sont très lisibles. Nous pouvons ajouter des <a href="https://docs.angularjs.org/api/ng/filter/filter">filtres AngularJS</a> directement dans notre template pour rendre notre page plus “user-friendly”.</p>
<p>Utilisons le filtre “date” pour formater la date et “number” pour limiter le nombre de chiffre après la virgule :</p>
<p></p><pre class="crayon-plain-tag">&lt;p&gt;CPU on {{cpu.SentinelName }} at {{cpu.LastUpdate | date : 'dd//MM/yyyy @ hh:mm:ss' }} is &lt;strong&gt;{{cpu.Value.Value | number:2}} {{cpu.Value.Unit}}&lt;/strong&gt;&lt;/p&gt;</pre><p></p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/09/image-34.png"><img class="colorbox-2331"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border: 0px;" title="image" src="https://developer.myconstellation.io/wp-content/uploads/2016/09/image_thumb-33.png" alt="image" width="350" height="69" border="0" /></a></p>
<p>C’est toute la magie d’AngularJS <img class="wlEmoticon wlEmoticon-winkingsmile colorbox-2331" style="border-style: none;" src="https://developer.myconstellation.io/wp-content/uploads/2016/09/wlEmoticon-winkingsmile-1.png" alt="Clignement d'œil" /></p>
<p>Allons encore un peu plus loin !</p>
<p>Ici nous avons lié notre variable de scope “cpu” au StateObject nommé « /intelcpu/0/load/0” et produit par le package “HWMonitor”. Mais n’oubliez pas que <a href="/concepts/stateobjects/">l’unicité d’un StateObject</a> est obtenu avec le triplet : Sentinelle + Package + Nom.</p>
<p>Autrement dit il peut y avoir plusieurs SO qui correspondent à ce filtre dans le cas où vous avez déployé le package HWMonitor sur plusieurs sentinelles.</p>
<p>Dans ce cas, la valeur du SO est sans cesse écrasée et notre page devient illisible :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/09/cpus.gif"><img class="colorbox-2331"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border: 0px;" title="cpus" src="https://developer.myconstellation.io/wp-content/uploads/2016/09/cpus_thumb-gap.jpg" data-gif="https://developer.myconstellation.io/wp-content/uploads/2016/09/cpus_thumb.gif" alt="cpus" width="350" height="58" border="0" /></a></p>
<p>Nous allons gérer ce cas en créant une variable de scope qui contiendra les différents StateObjects de nos CPUs.</p>
<p>Dans votre scope, commençons par déclarer une variable de scope nommée “cpus” en l’initialisant avec un objet vide :</p>
<p></p><pre class="crayon-plain-tag">$scope.cpus = {}</pre><p></p>
<p>Modifions notre StateObjectLink pour stocker le StateObject dans notre objet “cpus” sous la propriété du nom de la sentinelle de notre StateObject.</p>
<p></p><pre class="crayon-plain-tag">constellation.registerStateObjectLink("*", "HWMonitor", "/intelcpu/0/load/0", "*", function (so) {
  $scope.$apply(function() {
    $scope.cpus[so.SentinelName.replace("-", "")] = so;
  });
});</pre><p></p>
<p>C’est à dire que notre variable de scope “cpus” est un objet avec des propriétés du nom de la sentinelle et qui contient le StateObject de son CPU associé.</p>
<p>Attention le nom de la sentinelle est utilisée comme nom de propriété de notre objet JavaScript et vous n’êtes pas sans savoir que les “-“ (entre autre) ne sont pas autorisés en JS ce qui explique que nous les effaçons avec le “replace”.</p>
<p>Ainsi si je veux afficher dans mon template le CPU de ma machine nommée ”PC-SEB_UI” (= propriété “PCSEB_UI”), je devrais écrire :</p>
<p></p><pre class="crayon-plain-tag">&lt;p&gt;CPU on {{cpus.PCSEB_UI.SentinelName }} at {{cpus.PCSEB_UI.LastUpdate | date : 'dd//MM/yyyy @ hh:mm:ss' }} is &lt;strong&gt;{{cpus.PCSEB_UI.Value.Value | number:2}} {{cpus.PCSEB_UI.Value.Unit}}&lt;/strong&gt;&lt;/p&gt;</pre><p></p>
<p>Il ni a plus d’effet indésirable de voir les StateObjects chevaucher constamment.</p>
<p>Mais on peut aller encore plus loin car notre variable “cpus” contient tous les SO de la consommation de CPU produits par l’ensemble des packages HWMonitor de notre Constellation.</p>
<p>Il suffit d’itérer sur cette variable pour afficher le SO de chaque propriété de notre objet. Avec AngularJS vous pouvez utiliser la directive “<a href="https://docs.angularjs.org/api/ng/directive/ngRepeat">ng-repeat</a>” :</p>
<p></p><pre class="crayon-plain-tag">&lt;p ng-repeat="cpu in cpus"&gt;CPU on {{cpu.SentinelName }} at {{cpu.LastUpdate | date : 'dd//MM/yyyy @ hh:mm:ss' }} is &lt;strong&gt;{{cpu.Value.Value | number:2}} {{cpu.Value.Unit}}&lt;/strong&gt;&lt;/p&gt;</pre><p></p>
<p style="text-align: left;" align="center">Nous obtenons une page capable d&rsquo;afficher en temps réel la consommation de toutes nos machines Windows dans une simple page HTML :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/09/cpus2.gif"><img class="colorbox-2331"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border: 0px;" title="cpus2" src="https://developer.myconstellation.io/wp-content/uploads/2016/09/cpus2_thumb-gap.jpg" data-gif="https://developer.myconstellation.io/wp-content/uploads/2016/09/cpus2_thumb.gif" alt="cpus2" width="350" height="256" border="0" /></a></p>
<p>The post <a rel="nofollow" href="https://developer.myconstellation.io/client-api/javascript-api/consommer-constellation-angular-js/">Consommer Constellation avec Angular JS</a> appeared first on <a rel="nofollow" href="https://developer.myconstellation.io">Constellation</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://developer.myconstellation.io/client-api/javascript-api/consommer-constellation-angular-js/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>Créer une application mobile multi-plateforme connectée à Constellation avec Cordova</title>
		<link>https://developer.myconstellation.io/client-api/mobile/application-mobile-multi-plateforme-avec-cordova/</link>
					<comments>https://developer.myconstellation.io/client-api/mobile/application-mobile-multi-plateforme-avec-cordova/#respond</comments>
		
		<dc:creator><![CDATA[Sebastien Warin]]></dc:creator>
		<pubDate>Fri, 19 Aug 2016 08:28:47 +0000</pubDate>
				<category><![CDATA[Javascript API]]></category>
		<category><![CDATA[Mobile]]></category>
		<category><![CDATA[StateObject]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[API]]></category>
		<category><![CDATA[SendMessage]]></category>
		<category><![CDATA[Consumer]]></category>
		<category><![CDATA[Cordova]]></category>
		<guid isPermaLink="false">https://developer.myconstellation.io/?p=2335</guid>

					<description><![CDATA[<p>La plateforme Apache Cordova (anciennement PhoneGap) permet de créer des applications mobiles (Android, Windows Phone, iPhone, Blackberry, …) en utilisant les technologies Web (HTML, JS, CSS). Couplée à la libraire JavaScript Constellation, il devient très facile de créer une application</p>
<p>The post <a rel="nofollow" href="https://developer.myconstellation.io/client-api/mobile/application-mobile-multi-plateforme-avec-cordova/">Créer une application mobile multi-plateforme connectée à Constellation avec Cordova</a> appeared first on <a rel="nofollow" href="https://developer.myconstellation.io">Constellation</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>La plateforme <a href="http://cordova.apache.org/">Apache Cordova</a> (anciennement PhoneGap) permet de créer des applications mobiles (Android, Windows Phone, iPhone, Blackberry, …) en utilisant les technologies Web (HTML, JS, CSS).</p>
<p align="center"><img class="colorbox-2335"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="cordova_logo_normal_dark" src="https://developer.myconstellation.io/wp-content/uploads/2016/09/cordova_logo_normal_dark.png" alt="cordova_logo_normal_dark" width="240" height="71" border="0" /></p>
<p>Couplée à la <a href="/client-api/javascript-api/">libraire JavaScript Constellation</a>, il devient très facile de créer une application mobile pour votre smartphone ou tablette connectée à Constellation.</p>
<h3>Installer Cordova</h3>
<p>Cordova utilise nodejs, l&rsquo;installation est donc très simple et rapide :</p>
<ol>
<li>Installer <a href="http://nodejs.org/">NodeJS</a> si vous ne l&rsquo;avez pas déjà</li>
<li>Depuis le terminal (ou cmd pour windows) lancez la commande :</li>
</ol>
<p></p><pre class="crayon-plain-tag">npm install -g cordova</pre><p></p>
<p>Et voila Cordova est installé, mais il vous faut maintenant installer les SDK spécifiques aux plateformes que vous comptez utiliser.</p>
<p>Pour plus d’information, quelques ressources :</p>
<ul>
<li><a href="https://www.grafikart.fr/tutoriels/cordova/apache-cordova-installation-432">Installer et configurer Cordova</a></li>
<li><a href="http://cordova.apache.org/#getstarted">Guide de démarrage Cordova</a></li>
<li><a href="https://cordova.apache.org/docs/fr/latest/guide/platforms/android/">Guide pour la plate-forme Android</a></li>
</ul>
<h3>Créer un projet Cordova</h3>
<p>Lancez une invite de commande Windows et tapez la ligne suivante pour créer votre projet :</p>
<p></p><pre class="crayon-plain-tag">cordova create Demo</pre><p></p>
<p>Ensuite ajoutez le ou les plateformes cibles de votre application. Par exemple, développons une application pour Android :</p>
<p></p><pre class="crayon-plain-tag">cd Demo
cordova platform add android</pre><p></p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/09/image-154.png"><img class="colorbox-2335"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="image" src="https://developer.myconstellation.io/wp-content/uploads/2016/09/image_thumb-149.png" alt="image" width="350" height="311" border="0" /></a></p>
<p>Pour démarrer votre application sur l’émulateur Android ou sur votre terminal Android (connecté en USB) :</p>
<p></p><pre class="crayon-plain-tag">cordova run android</pre><p></p>
<h4>Tester votre application sur l’émulateur</h4>
<p>En utilisant le “<em>Android Virtual Device (AVD) Manager</em>” créez un device que l’on nommera ici “SmartphoneDemo” sous Android 5.1.1 :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/09/image-165.png"><img class="colorbox-2335"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="image" src="https://developer.myconstellation.io/wp-content/uploads/2016/09/image_thumb-160.png" alt="image" width="250" height="364" border="0" /></a></p>
<p align="left">Vous pouvez ensuite cliquer sur le bouton “Start” pour lancer le device virtuel :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/09/image-160.png"><img class="colorbox-2335"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="image" src="https://developer.myconstellation.io/wp-content/uploads/2016/09/image_thumb-155.png" alt="image" width="254" height="161" border="0" /></a></p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/09/image-161.png"><img class="colorbox-2335"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="image" src="https://developer.myconstellation.io/wp-content/uploads/2016/09/image_thumb-156.png" alt="image" width="250" height="432" border="0" /></a></p>
<p>Enfin lancez la commande suivante pour déployer et démarrer votre application dans l’émulateur :</p>
<p></p><pre class="crayon-plain-tag">cordova run android</pre><p></p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/09/image-162.png"><img class="colorbox-2335"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="image" src="https://developer.myconstellation.io/wp-content/uploads/2016/09/image_thumb-157.png" alt="image" width="354" height="229" border="0" /></a></p>
<h4>Debugger votre application avec l’inspecteur Chrome</h4>
<p>Dans un nouvel onglet Chrome, rendez-vous sur <a title="chrome://inspect/#devices" href="chrome://inspect/#devices">chrome://inspect/#devices</a>. Vous pourrez alors inspecter votre application Cordova :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/09/image-163.png"><img class="colorbox-2335"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="image" src="https://developer.myconstellation.io/wp-content/uploads/2016/09/image_thumb-158.png" alt="image" width="350" height="220" border="0" /></a></p>
<p align="left">Ainsi vous profiterez de tous les outils de debugging Web pour votre application mobile.</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/09/image-164.png"><img class="colorbox-2335"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="image" src="https://developer.myconstellation.io/wp-content/uploads/2016/09/image_thumb-159.png" alt="image" width="354" height="211" border="0" /></a></p>
<h4>Déployer votre application sur votre téléphone</h4>
<p>En connectant votre téléphone Android en USB ( sans oublier d’activer le debugging USB dans les paramètres de votre téléphone) vous pouvez, toujours avec la commande :</p>
<p></p><pre class="crayon-plain-tag">cordova run android</pre><p></p>
<p>… lancer votre application sur votre téléphone et utiliser l’inspecteur Chrome pour la debugger à distance.</p>
<p>Autrement vous pouvez aussi utiliser la commande :</p>
<p></p><pre class="crayon-plain-tag">cordova build android</pre><p></p>
<p>… pour générer le fichier APK, l’équivalent de l’installeur de votre application, qu’il faudra copier et lancer sur votre téléphone ou tablette Android.</p>
<h3>Connecter votre application Cordova à Constellation</h3>
<p>La structure d’une application Cordova est la suivante :</p>
<ul>
<li>Une page “index.html”, la page de démarrage de votre application</li>
<li>Des dossiers css, img et js pour ranger respectivement les feuilles de style CSS, les images et les scripts JS</li>
</ul>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/09/image-166.png"><img class="colorbox-2335"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="image" src="https://developer.myconstellation.io/wp-content/uploads/2016/09/image_thumb-161.png" alt="image" width="350" height="293" border="0" /></a></p>
<p align="left">En clair votre application mobile se développe comme une véritable application Web. Vous pouvez ensuite <a href="http://cordova.apache.org/docs/en/latest/guide/cli/#add-plugins">ajouter des plugins</a> pour accéder fonctionnalités du téléphone depuis votre code JavaScript (téléphonie, SMS, contacts, GPS, Bluetooth, Wifi, appareil photo, etc..).</p>
<h4 align="left">Ajouter les librairies Constellation</h4>
<p align="left">Comme il s’agit d’une application Web, connecter une application Cordova à Constellation revient à <a href="/getting-started/connectez-vos-pages-web-constellation/">connecter une page Web à Constellation</a>.</p>
<p align="left">Vous pouvez donc inclure les libraires en utilisant les CDN (en prenant soin de spécifier le schème explicitement, par exemple ‘https’) :</p>
<p></p><pre class="crayon-plain-tag">&lt;script type="text/javascript" src="https://code.jquery.com/jquery-2.2.4.min.js"&gt;&lt;/script&gt;
&lt;script type="text/javascript" src="https://ajax.aspnetcdn.com/ajax/signalr/jquery.signalr-2.2.1.min.js"&gt;&lt;/script&gt;
&lt;script type="text/javascript" src="https://cdn.myconstellation.io/js/Constellation-1.8.1.min.js"&gt;&lt;/script&gt;</pre><p></p>
<p align="left">Par contre afin d’améliorer les performances de votre application mobile, il est recommandé d’embarquer ces libraires dans votre application.</p>
<p align="left">Pour cela téléchargez (<em>clique-droit &gt; Enregistrer sous …</em>) dans le dossier “js” les librairies JavaScript suivantes :</p>
<ul>
<li>
<div align="left"><a href="https://code.jquery.com/jquery-2.2.4.min.js">https://code.jquery.com/jquery-2.2.4.min.js</a></div>
</li>
<li>
<div align="left"><a href="https://ajax.aspnetcdn.com/ajax/signalr/jquery.signalr-2.2.1.min.js">https://ajax.aspnetcdn.com/ajax/signalr/jquery.signalr-2.2.1.min.js</a></div>
</li>
<li>
<div align="left"><a href="https://cdn.myconstellation.io/js/Constellation-1.8.1.min.js">https://cdn.myconstellation.io/js/Constellation-1.8.1.min.js</a></div>
</li>
</ul>
<p>Puis ajoutez-les dans votre page “index.html” de cette façon:</p>
<p></p><pre class="crayon-plain-tag">&lt;script type="text/javascript" src="js/jquery-2.2.4.min.js"&gt;&lt;/script&gt;
&lt;script type="text/javascript" src="js/jquery.signalr-2.2.1.min.js"&gt;&lt;/script&gt;
&lt;script type="text/javascript" src="js/Constellation-1.8.1.min.js"&gt;&lt;/script&gt;</pre><p></p>
<h4 align="left">Connecter votre application</h4>
<p align="left">Tout d’abord dans le ficher “config.xml” à la racine de votre projet Cordova, ajoutez ces quelques lignes :</p>
<p></p><pre class="crayon-plain-tag">&lt;allow-intent href="ws://"/&gt;
&lt;allow-intent href="*" /&gt;
&lt;access origin="*" subdomains="true" /&gt;</pre><p></p>
<p align="left">Cela permet d’autoriser le container Cordova à accéder à des ressources externes comme le serveur Constellation !</p>
<p align="left">Aussi dans votre page principale,<em> index.html</em>, modifiez le “Content-Security-Policy” par :</p>
<p></p><pre class="crayon-plain-tag">&lt;meta http-equiv="Content-Security-Policy" content="default-src *; style-src 'self' 'unsafe-inline'; script-src * 'unsafe-inline' 'unsafe-eval';"&gt;</pre><p></p>
<p align="left">On autorise ainsi notre page à exploiter des services et scripts externes.</p>
<p align="left">Dans le fichier de script principal (<em>app.js</em>), créez un client “Consumer” en spécifiant l’adresse de votre serveur Constellation, une clé d’accès et un friendly name :</p>
<p></p><pre class="crayon-plain-tag">constellation: $.signalR.createConstellationConsumer("http://constellation.monServer.com:8088", "MaCle123!", "Demo Cordova"),</pre><p></p>
<p align="left">Dans la fonction “onDeviceReady” lancez la connexion au serveur Constellation par la ligne :</p>
<p></p><pre class="crayon-plain-tag">app.constellation.connection.start();</pre><p></p>
<p align="left">Pour finir dans la fonction “<em>initialize</em>” attachez un handler sur le changement d’état de la connexion Constellation. L’idée étant d’afficher le texte “Connected to Constellation” à la place du message “Device is Ready” du sample Cordova.</p>
<p></p><pre class="crayon-plain-tag">app.constellation.connection.stateChanged(function (change) {
  if (change.newState === $.signalR.connectionState.connected) {
    $('.received').text('connected to constellation');
  }
});</pre><p></p>
<p align="left">En démarrant l’application dans l’émulateur, votre application se connectera au hub “Consumer” de votre Constellation :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/09/image-167.png"><img class="colorbox-2335"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="image" src="https://developer.myconstellation.io/wp-content/uploads/2016/09/image_thumb-162.png" alt="image" width="250" height="432" border="0" /></a></p>
<p align="left">Vous pouvez maintenant envoyer des messages et invoquer des MessageCallbacks de vos différents packages, recevoir des messages pour que les autres clients de la Constellation puissent invoquer des méthodes de votre application mobile par exemple, interroger ou suivre en temps réel des StateObjects publiés par les packages de votre Constellation.</p>
<p align="left">Quelques exemples ci-après &#8230;</p>
<h4 align="left">Afficher en temps réel des StateObjects</h4>
<p align="left">Reprenons l’exemple du StateObject “/intelcpu/0/load/0” produit par le package “HWMonitor” et correspondant à la consommation de votre CPU.</p>
<p align="left">Pour cela nous allons enregistrer <a href="/client-api/javascript-api/consommer-constellation-api-javascript/#Consommer_des_StateObjects">StateObjectLink</a> sur ce StateObject en ciblant une sentinelle en particulier. Ici la sentinelle UI de mon ordinateur se nomme “PC-SEB_UI”.</p>
<p align="left">Vous pouvons écrire :</p>
<p></p><pre class="crayon-plain-tag">app.constellation.connection.stateChanged(function (change) {
  if (change.newState === $.signalR.connectionState.connected) {
    $('.received').text('connected to constellation');
    app.constellation.client.registerStateObjectLink("PC-SEB_UI", "HWMonitor", "/intelcpu/0/load/0", "*", function (so) {
      $("#cpu").text(Math.round(so.Value.Value * 100) / 100);
    });
  }
});</pre><p></p>
<p align="left">Sans oublier d’ajouter le “span” dans lequel afficher notre consommation :</p>
<p></p><pre class="crayon-plain-tag">&lt;h2&gt;PC-SEB CPU: &lt;span id="cpu"&gt;0&lt;/span&gt; %&lt;/h2&gt;</pre><p></p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/09/image-168.png"><img class="colorbox-2335"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="image" src="https://developer.myconstellation.io/wp-content/uploads/2016/09/image_thumb-163.png" alt="image" width="250" height="432" border="0" /></a></p>
<p align="left">Et voilà comment en quelques lignes afficher des StateObjects en temps réel dans une application mobile multi-plateforme.</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/09/DemoCordova.gif"><img class="colorbox-2335"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="DemoCordova" src="https://developer.myconstellation.io/wp-content/uploads/2016/09/DemoCordova_thumb-gap.jpg" data-gif="https://developer.myconstellation.io/wp-content/uploads/2016/09/DemoCordova_thumb.gif" alt="DemoCordova" width="350" height="400" border="0" /></a></p>
<p align="left">Dans cet exemple nous affichons la consommation CPU capturée par le package HWMonitor mais nous pouvons bien sûr afficher n’importe quel StateObject : des capteurs de température, état d’une zone de l’alarme, position de votre voiture, volume de l’ampli, consommation électrique, état d’une lampe, etc.…</p>
<h4 align="left">Invoquer des MessageCallbacks</h4>
<p align="left">Tout comme n’importe quel “consommateur”, votre application mobile multi-plateforme peut envoyer des messages et donc invoquer des MessageCallbacks.</p>
<p align="left">Pour découvrir les MessageCallbacks de votre Constellation, vous pouvez utiliser le <a href="/constellation-platform/constellation-console/messagecallbacks-explorer/">MessageCallback Explorer</a> de la Console Constellation.</p>
<p align="left">Par exemple, après avoir déployé le package “WindowsControl” sur une sentinelle Windows, vous pouvez invoquer des MC pour arrêter votre Windows, verrouiller la session, se déconnecter, redémarrer ou encore mettre en veille la machine.</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/10/image.png"><img class="colorbox-2335"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border: 0px;" title="image" src="https://developer.myconstellation.io/wp-content/uploads/2016/10/image_thumb.png" alt="image" width="350" height="185" border="0" /></a></p>
<p align="left">Ajoutons à notre application Android la capacité de verrouiller notre PC Windows. Pour cela vous pouvez cliquer sur l’icone <img class="colorbox-2335"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border: 0px;" title="image" src="https://developer.myconstellation.io/wp-content/uploads/2016/10/image-20.png" alt="image" width="20" height="19" border="0" /> pour générer le code d’invocation de ce MC en sélectionnant le langage de votre choix, dans notre cas, “Javascript” :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/10/image-2.png"><img class="colorbox-2335"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border: 0px;" title="image" src="https://developer.myconstellation.io/wp-content/uploads/2016/10/image_thumb-2.png" alt="image" width="350" height="217" border="0" /></a></p>
<p align="left">Dans notre page “index.html”, ajoutons un simple bouton (ou lien) HTML :</p>
<p></p><pre class="crayon-plain-tag">&lt;a id="lockPC" href="#" class="btn"&gt;LOCK MY PC&lt;/a&gt;</pre><p></p>
<p align="left">Et dans notre fichier Javascript, invoquons le MessageCallback “&rsquo;LockWorkStation” lorsque l’utilisateur clique sur notre bouton :</p>
<p></p><pre class="crayon-plain-tag">$("#lockPC").click(function () 
  constellation.server.sendMessage({ Scope: 'Package', Args: ['PC-SEB_UI/WindowsControl'] }, 'LockWorkStation', {});
});</pre><p></p>
<p>Notez que dans le code ci-dessus, à l’inverse de l’exemple donné par le générateur de code de la Console Constellation, nous avons défini le nom de l’instance du package et non le nom du package seul. En effet, en envoyant un message au scope de type Package ”WindowsControl”, votre message sera reçu par toutes les instances du package “WindowsControl” quelque soit la sentinelle. Autrement dit, toutes les sentinelles Windows qui exécutent le package “WindowsControl” seront verrouillées. Pour cibler votre sentinelle en particulier, nous avons indiqué ici le nom de l’instance, c’est à dire le couple “Sentinelle + Package”, ici “PC-SEB_UI/WindowsControl”.</p>
<p>Aussi, d’un point de vue visuel, Cordova n’inclut pas de framework CSS à l’inverse <a href="/client-api/javascript-api/application-mobile-multi-plateforme-avec-ionic-et-angular-js/">d’Ionic </a>par exemple. De ce fait tout est à votre charge. Ici nous avons créer un lien (&lt;a&gt;) sur lequel nous avons appliqué la classe CSS “btn”. Vous pouvez, pour l’exemple, utiliser des générateurs tel que <a href="http://www.cssbuttongenerator.com/">celui-ci</a> ou encore <a href="http://www.bestcssbuttongenerator.com/">celui-la</a> pour générer la classe “btn”.</p>
<p>Et voilà, notre application Android est maintenant capable de verrouiller notre poste Windows et d’afficher la consommation CPU en temps réel :</p>
<p align="center">(screen here)</p>
<h3>Pour aller plus loin …</h3>
<p>Donc vous avez pu le découvrir dans cet article, réaliser des applications mobiles (ou tablettes) pour Android, iOS, Windows ou autre est relativement facile avec des plateformes comme Cordova. En utilisant la <a href="/client-api/javascript-api/">libraire JavaScript Constellation</a>, vous pouvez donc développer des applications mobile connectées à Constellation en quelques minutes.</p>
<p>Une fois que votre application mobile est connectée à votre Constellation, elle peut suivre en temps réel tous les StateObjects produits par les packages de votre Constellation et invoquer des méthodes de ces packages en envoyant des messages.</p>
<p>De ce fait vous êtes libre de créer vos propres applications de supervision ou de contrôle de vos systèmes, services, réalisations, de votre domotique, etc…</p>
<p>Par exemple, vous créer un objet connecté avec un Raspberry et du Python ou bien un Arduino ou ESP8266, et vous pouvez créer facilement l’enrichir avec une application mobile. Ou bien vous ajoutez des lampes Hue et un media-center Kodi et vous décidez de créer une applications mobile unique pour tout contrôler en utilisant Constellation comme centralisateur.</p>
<p>Pour ma part je vous recommande vivement d’utiliser Ionic plutôt que Cordova. En effet, <a href="/client-api/javascript-api/application-mobile-multi-plateforme-avec-ionic-et-angular-js/">Ionic</a> n’est ni plus ni moins qu’une surcouche à Cordova qui intègre le framework AngularJS et un framework CSS. Grace à Ionic vous pouvez développer des applications plus riche et beaucoup plus rapidement.</p>
<p>The post <a rel="nofollow" href="https://developer.myconstellation.io/client-api/mobile/application-mobile-multi-plateforme-avec-cordova/">Créer une application mobile multi-plateforme connectée à Constellation avec Cordova</a> appeared first on <a rel="nofollow" href="https://developer.myconstellation.io">Constellation</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://developer.myconstellation.io/client-api/mobile/application-mobile-multi-plateforme-avec-cordova/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Créer une application mobile multi-plateforme connectée à Constellation avec Ionic</title>
		<link>https://developer.myconstellation.io/client-api/mobile/application-mobile-multi-plateforme-avec-ionic-et-angular-js/</link>
					<comments>https://developer.myconstellation.io/client-api/mobile/application-mobile-multi-plateforme-avec-ionic-et-angular-js/#respond</comments>
		
		<dc:creator><![CDATA[Sebastien Warin]]></dc:creator>
		<pubDate>Fri, 19 Aug 2016 08:29:16 +0000</pubDate>
				<category><![CDATA[Javascript API]]></category>
		<category><![CDATA[Mobile]]></category>
		<category><![CDATA[StateObject]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[SendMessage]]></category>
		<category><![CDATA[AngularJS]]></category>
		<category><![CDATA[Consumer]]></category>
		<category><![CDATA[Cordova]]></category>
		<category><![CDATA[Ionic]]></category>
		<guid isPermaLink="false">https://developer.myconstellation.io/?p=2337</guid>

					<description><![CDATA[<p>// En cours  de rédaction &#8230; intro install / base / link hello world (request SO &#38; send msg) déploiement</p>
<p>The post <a rel="nofollow" href="https://developer.myconstellation.io/client-api/mobile/application-mobile-multi-plateforme-avec-ionic-et-angular-js/">Créer une application mobile multi-plateforme connectée à Constellation avec Ionic</a> appeared first on <a rel="nofollow" href="https://developer.myconstellation.io">Constellation</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>// En cours  de rédaction &#8230;</p>
<ul>
<li>intro</li>
<li>install / base / link</li>
<li>hello world (request SO &amp; send msg)</li>
<li>déploiement</li>
</ul>
<p>The post <a rel="nofollow" href="https://developer.myconstellation.io/client-api/mobile/application-mobile-multi-plateforme-avec-ionic-et-angular-js/">Créer une application mobile multi-plateforme connectée à Constellation avec Ionic</a> appeared first on <a rel="nofollow" href="https://developer.myconstellation.io">Constellation</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://developer.myconstellation.io/client-api/mobile/application-mobile-multi-plateforme-avec-ionic-et-angular-js/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Envoyer des messages et invoquer des MessageCallbacks depuis un Arduino/ESP</title>
		<link>https://developer.myconstellation.io/client-api/arduino-esp-api/envoyer-des-messages-et-invoquer-des-messagecallbacks-depuis-arduino-esp/</link>
					<comments>https://developer.myconstellation.io/client-api/arduino-esp-api/envoyer-des-messages-et-invoquer-des-messagecallbacks-depuis-arduino-esp/#respond</comments>
		
		<dc:creator><![CDATA[Sebastien Warin]]></dc:creator>
		<pubDate>Tue, 23 Aug 2016 13:20:13 +0000</pubDate>
				<category><![CDATA[Arduino / ESP API]]></category>
		<category><![CDATA[Message]]></category>
		<category><![CDATA[MessageCallback]]></category>
		<category><![CDATA[Saga]]></category>
		<category><![CDATA[SendMessage]]></category>
		<category><![CDATA[Arduino]]></category>
		<category><![CDATA[ESP8266]]></category>
		<category><![CDATA[ESP]]></category>
		<guid isPermaLink="false">https://developer.myconstellation.io/?p=2461</guid>

					<description><![CDATA[<p>Envoyer des messages Pour envoyer des messages et invoquer des méthodes (MessageCallbacks) d’autres packages (ou consommateurs, pages Web, apps mobile, etc… ), vous pouvez utiliser la méthode “sendMessage” : [crayon-69756ad9ef219847040383/] C’est une fonction “variadic“ qui peut prendre plusieurs arguments qui</p>
<p>The post <a rel="nofollow" href="https://developer.myconstellation.io/client-api/arduino-esp-api/envoyer-des-messages-et-invoquer-des-messagecallbacks-depuis-arduino-esp/">Envoyer des messages et invoquer des MessageCallbacks depuis un Arduino/ESP</a> appeared first on <a rel="nofollow" href="https://developer.myconstellation.io">Constellation</a>.</p>
]]></description>
										<content:encoded><![CDATA[<h3>Envoyer des messages</h3>
<p>Pour envoyer des <a href="/concepts/messaging-message-scope-messagecallback-saga/">messages et invoquer des méthodes (MessageCallbacks)</a> d’autres packages (ou consommateurs, pages Web, apps mobile, etc… ), vous pouvez utiliser la méthode “sendMessage” :</p>
<p></p><pre class="crayon-plain-tag">constellation.sendMessage(scope, args, messageKey, data);</pre><p></p>
<p>C’est une fonction “variadic“ qui peut prendre plusieurs arguments qui seront utilisés pour formater le contenu (data) du message :</p>
<p></p><pre class="crayon-plain-tag">constellation.sendMessage(scope, args, messageKey, data, ...);</pre><p></p>
<p>Par exemple pour envoyer un message “DemoMessage” avec en contenu un objet contenant deux propriétés (c’est à dire invoquer le MessageCallback “DemoMessage” en passant en paramètre un objet à deux propriétés) au package “MyCsharpPackage“ :</p>
<p></p><pre class="crayon-plain-tag">constellation.sendMessage(Package, "MyCsharpPackage", "DemoMessage", "{ A: '%s', B: %d  }",  myStringVal, myIntVal);</pre><p></p>
<p>Autre exemple : envoyer un message “SignalReceive” au groupe “IR” (dans lequel plusieurs packages ou consommateurs peuvent s’inscrire) avec en paramètre une valeur de type ”long” formatée en hexadécimal :</p>
<p></p><pre class="crayon-plain-tag">unsigned long value = results.value; // the IR signal decoded
constellation.sendMessage(Group, "IR", "SignalReceive", "%#x", value);</pre><p></p>
<h4>Le scope</h4>
<p>Le scope permet de définir les destinataires du message (<a href="/concepts/messaging-message-scope-messagecallback-saga/">plus d’information ici</a>).</p>
<p>Dans la libraire Arduino/SP, l’argument Scope est une énumération définie de la façon suivante :</p>
<p></p><pre class="crayon-plain-tag">enum ScopeType : uint8_t {
  None = 0,
  Group = 1,
  Package = 2,
  Sentinel = 3,
  Other = 4,
  All = 5
};</pre><p></p>
<p>L’argument “args” spécifie les arguments du scope, par exemple le ou les noms des packages, des sentinelles ou des groupes où envoyer le message. Pour cibler une instance d’un package vous spécifierez le nom de l’instance complet “SENTINEL/Package” (<a href="/concepts/messaging-message-scope-messagecallback-saga/">plus d’information ici</a>).</p>
<p>Si vous avez plusieurs “args” vous devez les séparer par des virgules. Par exemple pour envoyer un message “HelloWorld” au groupe A et au groupe B :</p>
<p></p><pre class="crayon-plain-tag">constellation.sendMessage(Group, "A,B", "HelloWorld", "{}");</pre><p></p>
<h4>Le contenu (Data) du message</h4>
<p>Dans la <a href="/concepts/messaging-message-scope-messagecallback-saga/">philosophie des MessageCallbacks</a>, le contenu du message (Data) permet de stocker les arguments d’une fonction (MessageCallback) à invoquer.</p>
<p>Si vous invoquez un MC sans paramètre, vous devez spécifier un objet vide “{}” :</p>
<p></p><pre class="crayon-plain-tag">constellation.sendMessage(Package, "DemoPackage", "HelloWorld", "{}");</pre><p></p>
<p>Si vous avez plusieurs paramètres à passer, vous formaterez vos arguments dans un tableau :</p>
<p></p><pre class="crayon-plain-tag">constellation.sendMessage(Package, "DemoPackage", "SayHello", "[ 'Sebastien', 'Warin' ]");</pre><p></p>
<p>Vous pouvez également envoyer en tant qu’argument un objet complexe, par exemple :</p>
<p></p><pre class="crayon-plain-tag">constellation.sendMessage(Package, "DemoPackage", "SayHello", "{ 'FirstName':'Sebastien', 'LastName':'Warin' }");</pre><p></p>
<p>Ou bien même un mixte, par exemple un MC prenant en paramètre un objet complexe et un entier :</p>
<p></p><pre class="crayon-plain-tag">constellation.sendMessage(Package, "DemoPackage", "SayHello", "[ { 'FirstName':'Sebastien', 'LastName':'Warin' }, 42 ]");</pre><p></p>
<p>Ici le contenu du message est formaté en JSON via une chaine de caractère mais vous pouvez également passer un JsonObject à cette méthode :</p>
<p></p><pre class="crayon-plain-tag">const int BUFFER_SIZE = JSON_OBJECT_SIZE(2);
StaticJsonBuffer&lt;BUFFER_SIZE&gt; jsonBuffer;
JsonObject&amp; data = jsonBuffer.createObject();
myStateObject["FirstName"] = "Sebastien";
myStateObject["LastName"] = "Warin";
constellation.sendMessage(Package, "DemoPackage", "SayHello", data);</pre><p></p>
<p>Notez aussi que la Console Constellation liste les MessageCallbacks déclarés par l’ensemble des packages de votre Constellation et vous génère le code pour chaque API.</p>
<p>Par exemple, si vous souhaitez invoquer le MessageCallback “PushNote” du package “PushBullet” qui vous permettra d’envoyer une notification sur un smartphone vous pouvez cliquez sur l’icone de génération de code :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/08/image-66.png"><img class="colorbox-2461"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="image" src="https://developer.myconstellation.io/wp-content/uploads/2016/08/image_thumb-55.png" alt="image" width="350" height="147" border="0" /></a></p>
<p align="left">Sélectionnez ensuite le langage “Arduino” pour avoir le modèle correspondant :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/08/image-67.png"><img class="colorbox-2461"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="image" src="https://developer.myconstellation.io/wp-content/uploads/2016/08/image_thumb-56.png" alt="image" width="350" height="220" border="0" /></a></p>
<p>Ainsi pour envoyer une notification sur mon smartphone depuis un Arduino/ESP :</p>
<p></p><pre class="crayon-plain-tag">constellation.sendMessage(Package, "PushBullet", "PushNote", "[ 'Demo from Arduino', 'Ceci est une demo', 'Device', '' ]");</pre><p></p>
<p>Bien entendu, n’importe quel package ou consommateur peut recevoir des messages. Vous pouvez donc invoquer des méthodes C#, Python, JS, etc.. depuis un Arduino/ESP.</p>
<h3>Envoyer des messages avec réponse : les Sagas</h3>
<p>Les <a href="/concepts/messaging-message-scope-messagecallback-saga/">Sagas</a> permettent de lier des messages et donc de créer des couples de “requêtes / réponses”.</p>
<p>Avec la libraire Arduino/ESP, il est possible d’envoyer des messages dans une saga afin d’enregistrer un callback de traitement de la réponse.</p>
<p>Par exemple, le package “NetworkTools” expose entre autre un MessageCallback “Ping” permettant de pinger une machine. Si le MC est invoqué dans une saga, le package répondra dans la saga un message contenant le temps de réponse du ping.</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/09/image-19.png"><img class="colorbox-2461"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="image" src="https://developer.myconstellation.io/wp-content/uploads/2016/09/image_thumb-19.png" alt="image" width="350" height="106" border="0" /></a></p>
<p>De ce fait, si nous souhaitons invoquer cette méthode depuis notre Arduino et traiter la réponse, nous pouvons écrire :</p>
<p></p><pre class="crayon-plain-tag">const char* ip = "192.168.0.10";
constellation.sendMessageWithSaga([](JsonObject&amp; json) {
    constellation.writeInfo("Ping response in %s ms", json["Data"].as&lt;char *&gt;()); 
  }, Package, "NetworkTools", "Ping", "[ '%s' ]", ip);</pre><p></p>
<p>La signature de la méthode “<em>sendMessageWithSaga</em>” est la même que la méthode “<em>sendMessage</em>” présentée ci-dessus à la seule différence qu’elle prend comme 1er argument un callback vers une fonction traitant la réponse ici passée en tant que lambda.</p>
<p>Dans l’exemple ci-dessus, votre Arduino envoie donc un message “Ping” avec une adresse IP en paramètre au(x) package(s) “NetworkTools” en associant un n° de saga. Ce package exécutera le ping et vous retournera un message de réponse avec le résultat du ping. Cette réponse sera traitée par la fonction lambda qui dans l’exemple affichera dans les logs Constellation le résultat du ping.</p>
<p>Ainsi vos Arduino/ESP peuvent très facilement invoquer des méthodes (MessageCallback) avec ou sans retour des différents packages (virtuels ou non) ou consommateurs de votre Constellation; scripts Javascripts, Powershell, Bash, programmes .NET, Python, etc…</p>
<p>The post <a rel="nofollow" href="https://developer.myconstellation.io/client-api/arduino-esp-api/envoyer-des-messages-et-invoquer-des-messagecallbacks-depuis-arduino-esp/">Envoyer des messages et invoquer des MessageCallbacks depuis un Arduino/ESP</a> appeared first on <a rel="nofollow" href="https://developer.myconstellation.io">Constellation</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://developer.myconstellation.io/client-api/arduino-esp-api/envoyer-des-messages-et-invoquer-des-messagecallbacks-depuis-arduino-esp/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>L&#8217;interface REST « Constellation »</title>
		<link>https://developer.myconstellation.io/client-api/rest-api/interface-rest-constellation/</link>
					<comments>https://developer.myconstellation.io/client-api/rest-api/interface-rest-constellation/#comments</comments>
		
		<dc:creator><![CDATA[Sebastien Warin]]></dc:creator>
		<pubDate>Tue, 16 Aug 2016 08:51:20 +0000</pubDate>
				<category><![CDATA[REST API]]></category>
		<category><![CDATA[Saga]]></category>
		<category><![CDATA[AccessKey]]></category>
		<category><![CDATA[HTTP]]></category>
		<category><![CDATA[Virtuel]]></category>
		<category><![CDATA[Credential]]></category>
		<category><![CDATA[Authorization]]></category>
		<category><![CDATA[group]]></category>
		<category><![CDATA[Request]]></category>
		<category><![CDATA[API]]></category>
		<category><![CDATA[Subscribe]]></category>
		<category><![CDATA[SendMessage]]></category>
		<category><![CDATA[PushStateObject]]></category>
		<category><![CDATA[Package]]></category>
		<category><![CDATA[REST]]></category>
		<category><![CDATA[WriteLog]]></category>
		<category><![CDATA[Setting]]></category>
		<category><![CDATA[Settings]]></category>
		<category><![CDATA[PurgeStateObject]]></category>
		<category><![CDATA[MessageCallback]]></category>
		<category><![CDATA[PackageDescriptor]]></category>
		<guid isPermaLink="false">https://developer.myconstellation.io/?p=2296</guid>

					<description><![CDATA[<p>L’interface REST “Constellation” est une API HTTP permettant d’exposer les fonctionnalités de base pour les packages “virtuels”. Avec cette interface vous pourrez via des requêtes HTTP : Publier, consommer ou purger des StateObjects Envoyer et recevoir des messages Récupérer les</p>
<p>The post <a rel="nofollow" href="https://developer.myconstellation.io/client-api/rest-api/interface-rest-constellation/">L&rsquo;interface REST « Constellation »</a> appeared first on <a rel="nofollow" href="https://developer.myconstellation.io">Constellation</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>L’interface REST “Constellation” est une API HTTP permettant d’exposer les fonctionnalités de base pour les <a href="/concepts/sentinels-packages-virtuels/">packages “virtuels”</a>.</p>
<p>Avec cette interface vous pourrez via des requêtes HTTP :</p>
<ul>
<li>Publier, consommer ou purger des StateObjects</li>
<li>Envoyer et recevoir des messages</li>
<li>Récupérer les settings du package « virtuel »</li>
<li>Produire des logs</li>
<li>Déclarer le “Package Descriptor” (MessageCallbacks exposés ou les types utilisés par les MC ou SO)</li>
</ul>
<p>De ce fait un script Bash ou Powershell, une page PHP, un Arduino, ESP ou NetDuino, bref n’importe quel système, objet ou langage pouvant effectuer des appels HTTP peut être considéré comme un package (dit virtuel) de votre Constellation et produire ou consommer des StateObjects, envoyer ou recevoir des messages, écrire des logs, etc…</p>
<h3>Généralités</h3>
<h4>Construction de l’URL</h4>
<p>L’URL est :  &lt;Root URI&gt;/rest/constellation/&lt;action&gt;?&lt;paramètres&gt;</p>
<p>Partons du principe que votre Constellation est exposée en HTTP sur le port 8088 (sans path). On retrouvera dans le <a href="/constellation-server/fichier-de-configuration/">fichier de configuration</a> la section suivante :</p>
<p></p><pre class="crayon-plain-tag">&lt;listenUris&gt;
  &lt;uri listenUri="http://+:8088/" /&gt;
&lt;/listenUris&gt;</pre><p></p>
<p>La “Root URI “ est donc “<strong>http://&lt;ip ou dns&gt;:8088/</strong>”.</p>
<p>Par exemple si nous sommes en local, nous pourrions écrire :</p>
<p></p><pre class="crayon-plain-tag">http://localhost:8088/rest/constellation/xxxxx</pre><p></p>
<h4>Authentification</h4>
<p>Comme pour toutes les requêtes vers Constellation vous devez impérativement spécifier dans <u>les headers HTTP</u> <strong>ou</strong> dans <u>les paramètres de l’URL</u> (querystring), les paramètres “SentinelName”, “PackageName” et “AccessKey” pour l’authentification.</p>
<p>Ici votre “<a href="/concepts/sentinels-packages-virtuels/">package virtuel</a>” doit être déclaré dans la <a href="/constellation-platform/constellation-server/fichier-de-configuration/">configuration</a> de votre Constellation comme un véritable package, c’est à dire avec une sentinelle (dite virtuelle) et un package qui peut contenir des settings, etc…</p>
<p>Par exemple :</p>
<p></p><pre class="crayon-plain-tag">&lt;sentinels&gt;
  &lt;sentinel name="MyVirtualSentinel" credential="Standard"&gt;
    &lt;packages&gt;        
      &lt;package name="MyVirtualPackage" enable="true"&gt;
        &lt;settings&gt;
          &lt;setting key="IntSetting" value="42" /&gt;
          &lt;setting key="StringSetting" value="sample config value" /&gt;
        &lt;/settings&gt;
      &lt;/package&gt;
    &lt;/packages&gt;
  &lt;/sentinel&gt;
&lt;/sentinels&gt;</pre><p></p>
<p>On a ici déclaré une sentinelle virtuelle “MyVirtualSentinel” qui contient le package virtuelle “MonPackageVirtuel”. Ce package <a href="/concepts/securite-accesskey-credential-authorization/">utilise implicitement l’AccessKey</a> du credential “Standard” déclaré au niveau de la sentinelle.</p>
<p>De ce fait, pour chaque appel on passera les paramètres suivants (dans l’URL ou dans les headers) :</p>
<ul>
<li>SentinelName = MyVirtualSentinel</li>
<li>PackageName = MyVirtualPackage</li>
<li>AccessKey = MyAccessKey (en partant du principe que l’AccessKey déclaré pour le credential “Standard” est “MyAccessKey”)</li>
</ul>
<p>Pour la suite de cet article nous passerons tous les paramètres dans l’URL, ainsi chaque appel sera sous la forme :</p>
<p></p><pre class="crayon-plain-tag">http://localhost:8088/rest/constellation/&lt;action&gt;?SentinelName=MyVirtualSentinel&amp;PackageName=MyVirtualPackage&amp;AccessKey=MyAccessKey&amp;&lt;paramètres&gt;</pre><p></p>
<h4>Check Access</h4>
<p>Toutes les API REST de Constellation exposent une méthode en GET “CheckAccess” qui retourne un code HTTP 200 (OK). Cela permet de tester la connexion et l’authentification au serveur Constellation.</p>
<ul>
<li>Action : “CheckAccess” (GET)</li>
<li>Paramètres : aucun</li>
</ul>
<p>Exemple :</p>
<p></p><pre class="crayon-plain-tag">http://localhost:8088/rest/constellation/CheckAccess?SentinelName=MyVirtualSentinel&amp;PackageName=MyVirtualPackage&amp;AccessKey=MyAccessKey</pre><p></p>
<h3>Publier des StateObjects</h3>
<ul>
<li>Action : “PushStateObject” (GET ou POST)</li>
<li>En GET, voici les paramètres de l’URL :
<ul>
<li><u>name</u> : le nom du StateObject</li>
<li><u>value</u> : la valeur du StateObject</li>
<li><u>type</u> (optionnel) : le type du StateObject</li>
<li><u>lifetime</u> (optionnel – par défaut 0) : la durée de vie (en seconde) du StateObject avant d’être marqué “expiré”. (0 = durée de vie infinie)<!--EndFragment--></li>
</ul>
</li>
</ul>
<p>Pour publier un StateObject vous devez obligatoirement spécifier son nom (name) et sa valeur (value). La valeur peut être un type simple (un Int, String, bool, etc..) ou un objet complexe formaté en JSON. Optionnellement vous pouvez spécifier le type et la durée de vie de votre SO (en seconde).</p>
<p>Par exemple publions un StateObject nommé “Temperature” dont la valeur est le nombre “21” :</p>
<p></p><pre class="crayon-plain-tag">http://localhost:8088/rest/constellation/PushStateObject?SentinelName=MyVirtualSentinel&amp;PackageName=MyVirtualPackage&amp;AccessKey=MyAccessKey&amp;name=Temperature&amp;value=21</pre><p></p>
<p>Autre exemple avec un objet complexe contenant deux propriété (Temperature et Humidity) dont la durée de vie est de 60 secondes et le type nommé “TemperatureHumidity” :</p>
<p></p><pre class="crayon-plain-tag">http://localhost:8088/rest/constellation/PushStateObject?SentinelName=MyVirtualSentinel&amp;PackageName=MyVirtualPackage&amp;AccessKey=MyAccessKey&amp;name=Temperature&amp;value={ Temperature: 21, Humidity: 72 }&amp;type=TemperatureHumidity&amp;lifetime=60</pre><p></p>
<p>Si la valeur du StateObject est trop grande pour être passée dans l’URL ou si vous souhaitez ajouter des métadonnées (metadatas) à votre StateObject vous pouvez “poster” le StateObject dans le corps de la requête HTTP en utilisant le verbe “POST” (sans oublier de définir le Content-Type à “application/json”).</p>
<p>Pour publier par un POST le même StateObject en lui ajoutant deux métadonnées :</p>
<p></p><pre class="crayon-plain-tag">POST http://localhost:8088/rest/constellation/PushStateObject?SentinelName=MyVirtualSentinel&amp;PackageName=MyVirtualPackage&amp;AccessKey=MyAccessKey
Host: localhost:8088
Content-Length: 189
Content-Type: application/json

{
  "Name" : "Temperature",
  "Value" : { Temperature: 21, Humidity: 72 },
  "Type" : "TemperatureHumidity",
  "Lifetime" : 60,
  "Metadatas": { "ChipId":"ABC123", "Room":"Garden" }
}</pre><p></p>
<h3>Purger ses StateObjects</h3>
<p>Un package peut supprimer ses StateObjects qu’il produit avec la méthode “PurgeStateObjects”.</p>
<ul>
<li>Action : “PurgeStateObjects” (GET)</li>
<li>Paramètres:
<ul>
<li><u>name</u> (optionnel – par défaut “*”) : le nom du StateObject</li>
<li><u>type</u> (optionnel – par défaut “*”) : le type du StateObject</li>
</ul>
</li>
</ul>
<p>Vous pouvez spécifier le nom du StateObject à supprimer et/ou son type. Par défaut ces deux paramètres sont définis à “*”. C’est à dire que si vous ne précisez rien, tous les StateObjects du package seront purgés.</p>
<ul><!--EndFragment--></ul>
<p>Par exemple pour purger tous les StateObjects de notre package virtuel (instance MyVirtualSentinel/MyVirtualPackage):</p>
<p></p><pre class="crayon-plain-tag">http://localhost:8088/rest/constellation/PurgeStateObjects?SentinelName=MyVirtualSentinel&amp;PackageName=MyVirtualPackage&amp;AccessKey=MyAccessKey</pre><p></p>
<p>Pour purger tous les StateObjects de type “Temperature” de cette même instance :</p>
<p></p><pre class="crayon-plain-tag">http://localhost:8088/rest/constellation/PurgeStateObjects?SentinelName=MyVirtualSentinel&amp;PackageName=MyVirtualPackage&amp;AccessKey=MyAccessKey&amp;type=Temperature</pre><p></p>
<p>Ou pour supprimer le StateObject nommé “Demo” :</p>
<p></p><pre class="crayon-plain-tag">http://localhost:8088/rest/constellation/PurgeStateObjects?SentinelName=MyVirtualSentinel&amp;PackageName=MyVirtualPackage&amp;AccessKey=MyAccessKey&amp;name=Demo</pre><p></p>
<h3>Ecrire des logs</h3>
<p>Les packages peuvent écrire des logs qui seront remontés dans le hub Constellation.</p>
<ul>
<li>Action : “WriteLog” (GET)</li>
<li>Paramètres:
<ul>
<li><u>message</u> : texte du log</li>
<li><u>level</u> (optionnel – par défaut “Info”) : le niveau du log (Info, Warn ou Error)</li>
</ul>
<p><!--EndFragment--></li>
</ul>
<p>Exemple d’un message “Info” :</p>
<p></p><pre class="crayon-plain-tag">http://localhost:8088/rest/constellation/WriteLog?SentinelName=MyVirtualSentinel&amp;PackageName=MyVirtualPackage&amp;AccessKey=MyAccessKey&amp;message=Hello World</pre><p></p>
<p>Exemple pour produire un message d’erreur (Error) :</p>
<p></p><pre class="crayon-plain-tag">http://localhost:8088/rest/constellation/WriteLog?SentinelName=MyVirtualSentinel&amp;PackageName=MyVirtualPackage&amp;AccessKey=MyAccessKey&amp;message=Il y  a une erreur ici&amp;level=Error</pre><p></p>
<h3>Récupérer ses settings</h3>
<p>Les settings sont récupérés en invoquant la méthode “GetSettings”.</p>
<ul>
<li>Action : “GetSettings” (GET)</li>
<li>Paramètres:  aucun</li>
</ul>
<p>Par exemple pour récupérer les settings (dictionnaire de clé / valeur) définis pour notre package virtuel :</p>
<p></p><pre class="crayon-plain-tag">http://localhost:8088/rest/constellation/GetSettings?SentinelName=MyVirtualSentinel&amp;PackageName=MyVirtualPackage&amp;AccessKey=MyAccessKey</pre><p></p>
<h3>Envoyer des messages</h3>
<ul>
<li>Action : “SendMessage” (GET ou POST)</li>
<li>En GET, voici les paramètres de l’URL :
<ul>
<li><u>scope</u> : le type de scope (All, Other, Group, Sentinel ou Package)</li>
<li><u>args</u> : les arguments du scope (par exemple le nom du groupe, de la sentinelle, du package ou de l’instance du package – plusieurs valeurs possibles séparées par des virgules)</li>
<li><u>key</u> : la clé du message (= la méthode à invoquer)</li>
<li><u>data</u> : le contenu du message (= les arguments de la méthode)</li>
<li><u>sagaId</u> (optionnel) : l’identification de la saga si le message est envoyé dans une saga</li>
</ul>
</li>
</ul>
<p>Vous pouvez également invoquer cette action en POST. Le corps de votre requête contiendra l’objet JSON suivant :</p>
<p></p><pre class="crayon-plain-tag">{
  "Scope" : { "Type" : "&lt;type&gt;", Args: [ "&lt;arg1&gt;", "&lt;args2&gt;", .... ], "SagaId":"Identifiant de la Saga" },
  "Key" : "&lt;Key&gt;",
  "Data" : "&lt;Data&gt;"
}</pre><p></p>
<p>La propriété “SagaId” dans le JSON ci-dessus est optionnelle.</p>
<p>Par exemple pour envoyer un message au package Nest en invoquant la méthode (key) “SetTargetTemperature” avec en paramètre le nombre “21” :</p>
<p></p><pre class="crayon-plain-tag">http://localhost:8088/rest/constellation/SendMessage?SentinelName=Consumer&amp;PackageName=Demo&amp;AccessKey=MaCleDeTest123&amp;scope=Package&amp;args=Nest&amp;key=SetTargetTemperature&amp;data=21</pre><p></p>
<p>Ce même MessageCallback “SetTargetTemperature” du package Nest peut être invoqué dans une saga afin de recevoir un accusé de réception :</p>
<p></p><pre class="crayon-plain-tag">http://localhost:8088/rest/constellation/SendMessage?SentinelName=Consumer&amp;PackageName=Demo&amp;AccessKey=MaCleDeTest123&amp;scope=Package&amp;args=Nest&amp;key=SetTargetTemperature&amp;data=21&amp;sagaId=123456789</pre><p></p>
<p>Il faudra ensuite “récupérer” les messages reçus (voir dessous) pour lire la réponse à votre saga que nous avons ici identifié par la clé “123456789”.</p>
<h3>Recevoir des messages</h3>
<h4>Créer un abonnement de réception</h4>
<p>Tout d’abord pour recevoir des messages il faut s’abonner aux messages.</p>
<ul>
<li>Action : “SubscribeToMessage” (GET)</li>
<li>Paramètres :
<ul>
<li><u>subscriptionId</u> (optionnel) : identifiant de l’abonnement si déjà connu</li>
</ul>
</li>
</ul>
<p></p><pre class="crayon-plain-tag">http://localhost:8088/rest/constellation/SubscribeToMessage?SentinelName=Consumer&amp;PackageName=Demo&amp;AccessKey=MaCleDeTest123</pre><p></p>
<p>Vous obtiendrez en réponse l’ID de votre abonnement, le “Subscription Id”.</p>
<h4>Relever les messages</h4>
<ul>
<li>Action : “GetMessages” (GET)</li>
<li>Paramètres :
<ul>
<li><u>subscriptionId</u> : identifiant de l’abonnement</li>
<li><u>timeout</u> (optionnel – par défaut 60000) : temps maximal en milliseconde de la mise en attente de la requête (entre 1000ms et 120000ms)</li>
<li><u>limit</u> (optionnel – par défaut 0) : nombre maximum de message à retourner pour l’appel</li>
</ul>
</li>
</ul>
<p>Il s’agit d’une requête en “long-polling” c’est à dire que la requête sera “bloquée” sur le serveur tant qu’il n’y a pas de message reçu évitant ainsi de “flooder” en continue le serveur pour savoir si de nouveaux messages sont disponibles ou non. Par défaut la requête est bloquée 60 secondes maximum mais vous pouvez personnaliser cette valeur avec le paramètre “timeout”. Si il y a des messages disponibles, le serveur vous renvoi un tableau JSON avec les messages reçus. Si il n’y a pas de réponse dans le délai spécifié par le paramètre “timeout” (60 secondes par défaut), le tableau retourné sera vide.</p>
<p>A chaque réponse vous devez donc relancer une requête “GetMessages” pour “écouter” les prochains messages qui vont sont destinés.</p>
<p>Il est également possible de limiter le nombre de message dans la réponse avec le paramètre “limit” ce qui peut être utile sur de petits “devices” ne disposant pas de beaucoup de mémoire RAM pour désérialiser de gros tableaux JSON.</p>
<p>Exemple simple :</p>
<p></p><pre class="crayon-plain-tag">http://localhost:8088/rest/constellation/GetMessages?SentinelName=Consumer&amp;PackageName=Demo&amp;AccessKey=MaCleDeTest123&amp;subscriptionId=xxxxx</pre><p></p>
<p>Autre exemple en limitant le nombre de message à 2 par appel et en bloquant la requête pendant 10 secondes au maximum :</p>
<p></p><pre class="crayon-plain-tag">http://localhost:8088/rest/constellation/GetMessages?SentinelName=Consumer&amp;PackageName=Demo&amp;AccessKey=MaCleDeTest123&amp;subscriptionId=xxxxx&amp;timeout=10000&amp;limit=2</pre><p></p>
<h4>S’abonner à un groupe</h4>
<p>Vous pouvez vous abonner à des groupes pour recevoir les messages envoyés dans ces groupes par l’action “SubscribeToMessageGroup” en précisant le nom du groupe et votre ID d’abonnement.</p>
<ul>
<li>Action : “SubscribeToMessageGroup” (GET)</li>
<li>Paramètres :
<ul>
<li><u>group</u> : le nom du groupe à joindre</li>
<li><u>subscriptionId</u> (optionnel) : identifiant de l’abonnement si déjà connu</li>
</ul>
</li>
</ul>
<p></p><pre class="crayon-plain-tag">http://localhost:8088/rest/constellation/SubscribeToMessageGroup?SentinelName=Consumer&amp;PackageName=Demo&amp;AccessKey=MaCleDeTest123&amp;subscriptionId=xxxxx&amp;group=A</pre><p></p>
<p>Comme l’action “SubscribeToMessage”, cette action vous retourne l’ID d’abonnement à utiliser pour l’action “GetMessages”.</p>
<h3>Consommation de StateObjects</h3>
<h4>Request</h4>
<p>Cette méthode permet de récupérer la valeur actuelle d’un ou de plusieurs StateObjects.</p>
<ul>
<li>Action : “RequestStateObjects” (GET)</li>
<li>Paramètres :
<ul>
<li><u>sentinel</u> (optionnel – par défaut “*”): nom de la sentinelle</li>
<li><u>package</u> (optionnel – par défaut “*”) : nom du package</li>
<li><u>name</u> (optionnel – par défaut “*”) : nom du StateObject</li>
<li><u>type</u> (optionnel – par défaut “*”) : type du StateObject</li>
</ul>
</li>
</ul>
<p>Par exemple pour récupérer tous les StateObject de votre Constellation :</p>
<p></p><pre class="crayon-plain-tag">http://localhost:8088/rest/constellation/RequestStateObjects?SentinelName=Consumer&amp;PackageName=Demo&amp;AccessKey=MaCleDeTest123</pre><p></p>
<p>Ou seulement ceux produits par le package “HWMonitor” (quelque soit la sentinelle) :</p>
<p></p><pre class="crayon-plain-tag">http://localhost:8088/rest/constellation/RequestStateObjects?SentinelName=Consumer&amp;PackageName=Demo&amp;AccessKey=MaCleDeTest123&amp;package=HWMonitor</pre><p></p>
<p>Ou encore tous les StateObjects nommés “/intelcpu/load/0” et produits le package “HWMonitor” (quelque soit la sentinelle) :</p>
<p></p><pre class="crayon-plain-tag">http://localhost:8088/rest/constellation/RequestStateObjects?SentinelName=Consumer&amp;PackageName=Demo&amp;AccessKey=MaCleDeTest123&amp;package=HWMonitor&amp;name=/intelcpu/load/0</pre><p></p>
<h4>Subscribe</h4>
<p>Vous pouvez également vous abonner aux mises à jour des StateObjects.</p>
<p>Le principe est le même qu’avec les messages : il faut récupérer un ID d’abonnement et invoquer une méthode en long-polling pour recevoir les mises à jour.</p>
<h5>S’abonner à des StateObjects</h5>
<ul>
<li>Action : “SubscribeToStateObjects” (GET)</li>
<li>Paramètres :
<ul>
<li><u>subscriptionId</u> (optionnel) : identifiant de l’abonnement si déjà connu</li>
<li><u>sentinel</u> (optionnel – par défaut “*”): nom de la sentinelle</li>
<li><u>package</u> (optionnel – par défaut “*”) : nom du package</li>
<li><u>name</u> (optionnel – par défaut “*”) : nom du StateObject</li>
<li><u>type</u> (optionnel – par défaut “*”) : type du StateObject</li>
</ul>
</li>
</ul>
<p>En retour vous obtiendrez l’ID d’abonnement (un GUID).</p>
<p>Par exemple pour s’abonner au SO “/intelcpu/load/0”, produit le package “HWMonitor” sur la sentinelle “MON-PC” :</p>
<p></p><pre class="crayon-plain-tag">http://localhost:8088/rest/constellation/SubscribeToStateObjects?SentinelName=Consumer&amp;PackageName=Demo&amp;AccessKey=MaCleDeTest123&amp;sentinel=MON-PC&amp;package=HWMonitor&amp;name=/intelcpu/load/0</pre><p></p>
<p><strong>ATTENTION</strong> : si vous souhaitez “ajouter” des SO à votre abonnement vous devez <u>impérativement</u> préciser votre ID d’abonnement récupéré lors du 1er appel autrement vous allez créer un nouvel abonnement.</p>
<p>Par exemple pour “ajouter” le SO correspondant à la consommation RAM :</p>
<p></p><pre class="crayon-plain-tag">http://localhost:8088/rest/constellation/SubscribeToStateObjects?SentinelName=Consumer&amp;PackageName=Demo&amp;AccessKey=MaCleDeTest123&amp;sentinel=MON-PC&amp;package=HWMonitor&amp;name=/ram/load&amp;subscriptionId=&lt;subId&gt;</pre><p></p>
<h5>Relever les StateObjects mis à jour</h5>
<p>Pour récupérer les SO de votre abonnement qui ont changés entre deux appels vous devez invoquer l’action “GetStateObjects” en spécifiant l’ID de votre abonnement :</p>
<ul>
<li>Action : “GetStateObjects” (GET)</li>
<li>Paramètres :
<ul>
<li><u>subscriptionId</u> : identifiant de l’abonnement</li>
<li><u>timeout</u> (optionnel – par défaut 60000) : temps maximal en milliseconde de la mise en attente de la requête (entre 1000ms et 120000ms)</li>
<li><u>limit</u> (optionnel – par défaut 0) : nombre maximum de message à retourner pour l’appel</li>
</ul>
</li>
</ul>
<p>Comme pour les messages, vous pouvez limiter le nombre de SO (limit) et le timeout de la requête (timeout).</p>
<p></p><pre class="crayon-plain-tag">http://localhost:8088/rest/constellation/GetStateObjects?SentinelName=Consumer&amp;PackageName=Demo&amp;AccessKey=MaCleDeTest123&amp;subscriptionId=&lt;subId&gt;</pre><p></p>
<p>Notez que si un StateObject pour lequel vous êtes abonné change plusieurs fois entre deux appels “GetStateObjects”, vous obtiendrez la dernière valeur et non l’historique de tous les changements.</p>
<h3>Déclarer le “Package Descriptor”</h3>
<p>Action : “DeclarePackageDescriptor” (POST)</p>
<p>Le “<a href="/concepts/messaging-message-scope-messagecallback-saga/#Auto-description_des_MessageCallbacks">Package Descriptor</a>” permet décrire les MessagesCallbacks d’un package ainsi que les types utilisés par ses MC ou StateObjects.</p>
<p>Ainsi en publiant le PackageDescriptor, la Constellation aura connaissance des MessageCallbacks qu’expose un package ainsi que le type des StateObject qu’il publie. C’est grâce au Package Descriiptor que fonctionne le “MessageCallback Explorer” de la Console Constellation.</p>
<p>Le Package Descriptor est un objet JSON contenant :</p>
<ul>
<li>Le nom du package</li>
<li>La liste des MessageCallbacks du package</li>
<li>La liste des types utilisés par les MessageCallbacks du package</li>
<li>La liste des types utilisés par les StateObjects publiés par le package</li>
</ul>
<p>La structure de base est donc :</p>
<p></p><pre class="crayon-plain-tag">{
  "PackageName": "MyVirtualPackage",
  "MessageCallbacks": [],
  "MessageCallbackTypes": [],
  "StateObjectTypes": [],
}</pre><p></p>
<p>Chaque “MessageCallback” est un objet contenant :</p>
<ul>
<li><u>MessageKey</u> : la clé du message (le nom/clé du MessageCallback)</li>
<li><u>Description</u> (optionnel) : description du MessageCallback</li>
<li><u>ResponseType</u> (optionnel) : le type du message de retour dans le cas où le MC répond au Saga</li>
<li><u>Parameters</u> (optionnel) : la liste des paramètres du MC</li>
</ul>
<p>Un paramètre est décrit par un objet contenant :</p>
<ul>
<li><u>Name</u> : le nom du paramètre</li>
<li><u>TypeName</u> : le type du paramètre</li>
<li><u>Description</u> (optionnel) : la description du paramètre</li>
<li><u>Type</u> : le type de paramètre (doit être obligatoirement défini à 2 pour un paramètre d’un MC)</li>
<li><u>IsOptional</u> (optionnel) : booléen (true ou false) qui indique si le paramètre est optionnel ou non</li>
<li><u>DefaultValue</u> (optionnel) : la valeur par défaut du paramètre si optionnel</li>
</ul>
<p>Le type d’un paramètre peut être un type simple décrit par les types .NET (System.Int16, System.Int32, System.Int64, System.Double, System.Decimal, System.Float, System.Boolean, System.String) ou un type personnalisé.</p>
<p>Les types personnalisés utilisés dans les paramètres des MC seront décrits dans la propriété “MessageCallbackTypes” du Package Descriptor et les types personnalisés utilisés pour les StateObjects seront décrits dans la propriété “StateObjectTypes” du Package Descriptor.</p>
<p>Dans les deux cas il s’agit de la même structure de donnée.</p>
<p>La description d’un type est un objet contenant :</p>
<ul>
<li><u>TypeName</u> : le nom du type (l’identifiant)</li>
<li><u>TypeFullname</u> : le nom complet du type (utilisé pour identifier le nom complet d’un type .NET par exemple)</li>
<li><u>Description</u> (optionnel) : la description du type</li>
<li><u>IsGeneric</u> (optionnel) : booléen (true ou false) qui indique si le type est un type générique</li>
<li><u>IsArray</u> (optionnel) : booléen (true ou false) qui indique si le type est un tableau</li>
<li><u>GenericParameters</u> (optionnel) : la liste des types génériques si il s’agit d’un type générique ou d’un tableau</li>
<li><u>IsEnum</u> (optionnel) : booléen (true ou false) qui indique si le type est une énumération</li>
<li><u>EnumValues</u> (optionnel) : la liste des valeurs de l’énumérations si le type est une énumération</li>
<li><u>Properties</u> (optionnel) : la liste des propriétés du type</li>
</ul>
<p>Les propriétés d’un type tout comme les valeurs d’une énumération sont décrits de la même manière qu’un paramètre d’un MessageCallback déjà détaillé ci-dessus.</p>
<p>Seule la propriété “Type” change :</p>
<ul>
<li>Type = 0 : pour décrire une propriété</li>
<li>Type = 1 : pour décrire une valeur d’une énumération</li>
<li>Type = 2 : pour décrire une paramètre d’un MessageCallback comme expliqué précédemment</li>
</ul>
<h4>Exemple 1 – Package “NetworkTools”</h4>
<p>Voici le Package Descriptor du package “NetworkTools” :</p>
<p></p><pre class="crayon-plain-tag">{
   "PackageName":"NetworkTools",
   "MessageCallbacks":[  
      {  
         "MessageKey":"Ping",
         "Description":"Pings the specified host and return the response time.",
         "ResponseType":"System.Int64",
         "Parameters":[  
            {  
               "Name":"host",
               "TypeName":"System.String",
               "Description":"The host.",
               "Type":2,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"timeout",
               "TypeName":"System.Int32",
               "Description":"The timeout (5000ms by defaut).",
               "Type":2,
               "IsOptional":false,
               "DefaultValue":null
            }
         ]
      },
      {  
         "MessageKey":"CheckPort",
         "Description":"Check a port's status by entering an address and port number above and return the response time.",
         "ResponseType":"System.Int64",
         "Parameters":[  
            {  
               "Name":"host",
               "TypeName":"System.String",
               "Description":"The host.",
               "Type":2,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"port",
               "TypeName":"System.Int32",
               "Description":"The port.",
               "Type":2,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"timeout",
               "TypeName":"System.Int32",
               "Description":"The timeout (5000ms by defaut).",
               "Type":2,
               "IsOptional":false,
               "DefaultValue":null
            }
         ]
      },
      {  
         "MessageKey":"CheckHttp",
         "Description":"Checks the HTTP address and return the response time.",
         "ResponseType":"System.Int64",
         "Parameters":[  
            {  
               "Name":"address",
               "TypeName":"System.String",
               "Description":"The address.",
               "Type":2,
               "IsOptional":false,
               "DefaultValue":null
            }
         ]
      },
      {  
         "MessageKey":"ScanPort",
         "Description":"Scans TCP port range to discover which TCP ports are open on your target host.",
         "ResponseType":"System.Collections.Generic.Dictionary`2[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]",
         "Parameters":[  
            {  
               "Name":"host",
               "TypeName":"System.String",
               "Description":"The host.",
               "Type":2,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"startPort",
               "TypeName":"System.Int32",
               "Description":"The start port.",
               "Type":2,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"endPort",
               "TypeName":"System.Int32",
               "Description":"The end port.",
               "Type":2,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"timeout",
               "TypeName":"System.Int32",
               "Description":"The timeout (5000ms by defaut).",
               "Type":2,
               "IsOptional":false,
               "DefaultValue":null
            }
         ]
      },
      {  
         "MessageKey":"WakeUp",
         "Description":"Wakes up the specified host.",
         "ResponseType":"System.Boolean",
         "Parameters":[  
            {  
               "Name":"host",
               "TypeName":"System.String",
               "Description":"The host.",
               "Type":2,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"macAddress",
               "TypeName":"System.String",
               "Description":"The mac address.",
               "Type":2,
               "IsOptional":false,
               "DefaultValue":null
            }
         ]
      },
      {  
         "MessageKey":"DnsLookup",
         "Description":"Resolves a host name or IP address.",
         "ResponseType":"System.String[]",
         "Parameters":[  
            {  
               "Name":"host",
               "TypeName":"System.String",
               "Description":"The host.",
               "Type":2,
               "IsOptional":false,
               "DefaultValue":null
            }
         ]
      }
   ],
   "MessageCallbackTypes":[  
      {  
         "Description":null,
         "IsGeneric":true,
         "IsArray":false,
         "GenericParameters":[  
            "System.Int32",
            "System.Boolean"
         ],
         "IsEnum":false,
         "EnumValues":null,
         "TypeName":"Dictionary`2",
         "TypeFullname":"System.Collections.Generic.Dictionary`2[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]",
         "Properties":null
      },
      {  
         "Description":null,
         "IsGeneric":false,
         "IsArray":true,
         "GenericParameters":[  
            "System.String"
         ],
         "IsEnum":false,
         "EnumValues":null,
         "TypeName":"String[]",
         "TypeFullname":"System.String[]",
         "Properties":null
      }
   ],
   "StateObjectTypes":[  
      {  
         "Description":"Monitoring type",
         "IsGeneric":false,
         "IsArray":false,
         "GenericParameters":null,
         "IsEnum":false,
         "EnumValues":null,
         "TypeName":"MonitoringResult",
         "TypeFullname":"NetworkTools.MonitoringResult",
         "Properties":[  
            {  
               "Name":"ResponseTime",
               "TypeName":"System.Int64",
               "Description":"Gets or sets the response time in millisecond.",
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"State",
               "TypeName":"System.Boolean",
               "Description":"Gets or sets the state.",
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            }
         ]
      }
   ]
}</pre><p></p>
<h4>Exemple 2 – Package “Paradox”</h4>
<p>Autre exemple plus complet, le Package Descriptor du package “Paradox” :</p>
<p></p><pre class="crayon-plain-tag">{  
   "PackageName":"Paradox",
   "MessageCallbacks":[  
      {  
         "MessageKey":"AreaArm",
         "Description":"Arm the area.",
         "ResponseType":"System.Boolean",
         "Parameters":[  
            {  
               "Name":"request",
               "TypeName":"ParadoxOnConstellation.ArmingRequestData",
               "Description":"The request.",
               "Type":2,
               "IsOptional":false,
               "DefaultValue":null
            }
         ]
      },
      {  
         "MessageKey":"AreaDisarm",
         "Description":"Disarm the area.",
         "ResponseType":"System.Boolean",
         "Parameters":[  
            {  
               "Name":"request",
               "TypeName":"ParadoxOnConstellation.ArmingRequestData",
               "Description":"The request.",
               "Type":2,
               "IsOptional":false,
               "DefaultValue":null
            }
         ]
      },
      {  
         "MessageKey":"RefreshArea",
         "Description":"Refreshes the area.",
         "ResponseType":null,
         "Parameters":[  
            {  
               "Name":"area",
               "TypeName":"Paradox.Core.Area",
               "Description":"The area.",
               "Type":2,
               "IsOptional":false,
               "DefaultValue":null
            }
         ]
      },
      {  
         "MessageKey":"RefreshAll",
         "Description":"Refreshes all.",
         "ResponseType":null,
         "Parameters":[  

         ]
      }
   ],
   "MessageCallbackTypes":[  
      {  
         "Description":"Arming or disarming request",
         "IsGeneric":false,
         "IsArray":false,
         "GenericParameters":null,
         "IsEnum":false,
         "EnumValues":null,
         "TypeName":"ArmingRequestData",
         "TypeFullname":"ParadoxOnConstellation.ArmingRequestData",
         "Properties":[  
            {  
               "Name":"Area",
               "TypeName":"Paradox.Core.Area",
               "Description":"The number of area.",
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Mode",
               "TypeName":"Paradox.Core.ArmingMode",
               "Description":"The mode number.",
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"PinCode",
               "TypeName":"System.String",
               "Description":"The pin code.",
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            }
         ]
      },
      {  
         "Description":null,
         "IsGeneric":false,
         "IsArray":false,
         "GenericParameters":null,
         "IsEnum":true,
         "EnumValues":[  
            {  
               "Name":"All",
               "TypeName":"Paradox.Core.Area",
               "Description":null,
               "Type":0,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Area1",
               "TypeName":"Paradox.Core.Area",
               "Description":null,
               "Type":0,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Area2",
               "TypeName":"Paradox.Core.Area",
               "Description":null,
               "Type":0,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Area3",
               "TypeName":"Paradox.Core.Area",
               "Description":null,
               "Type":0,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Area4",
               "TypeName":"Paradox.Core.Area",
               "Description":null,
               "Type":0,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Area5",
               "TypeName":"Paradox.Core.Area",
               "Description":null,
               "Type":0,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Area6",
               "TypeName":"Paradox.Core.Area",
               "Description":null,
               "Type":0,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Area7",
               "TypeName":"Paradox.Core.Area",
               "Description":null,
               "Type":0,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Area8",
               "TypeName":"Paradox.Core.Area",
               "Description":null,
               "Type":0,
               "IsOptional":false,
               "DefaultValue":null
            }
         ],
         "TypeName":"Area",
         "TypeFullname":"Paradox.Core.Area",
         "Properties":null
      },
      {  
         "Description":null,
         "IsGeneric":false,
         "IsArray":false,
         "GenericParameters":null,
         "IsEnum":true,
         "EnumValues":[  
            {  
               "Name":"RegularArm",
               "TypeName":"Paradox.Core.ArmingMode",
               "Description":null,
               "Type":0,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"ForceArm",
               "TypeName":"Paradox.Core.ArmingMode",
               "Description":null,
               "Type":0,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"StayArm",
               "TypeName":"Paradox.Core.ArmingMode",
               "Description":null,
               "Type":0,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"InstantArm",
               "TypeName":"Paradox.Core.ArmingMode",
               "Description":null,
               "Type":0,
               "IsOptional":false,
               "DefaultValue":null
            }
         ],
         "TypeName":"ArmingMode",
         "TypeFullname":"Paradox.Core.ArmingMode",
         "Properties":null
      }
   ],
   "StateObjectTypes":[  
      {  
         "Description":null,
         "IsGeneric":false,
         "IsArray":false,
         "GenericParameters":null,
         "IsEnum":false,
         "EnumValues":null,
         "TypeName":"UserInfo",
         "TypeFullname":"ParadoxOnConstellation.UserInfo",
         "Properties":[  
            {  
               "Name":"Id",
               "TypeName":"System.Int32",
               "Description":"The identifier.",
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Type",
               "TypeName":"System.String",
               "Description":"The object type.",
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Name",
               "TypeName":"System.String",
               "Description":"The name.",
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"LastActivity",
               "TypeName":"System.DateTime",
               "Description":"The last activity.",
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            }
         ]
      },
      {  
         "Description":null,
         "IsGeneric":false,
         "IsArray":false,
         "GenericParameters":null,
         "IsEnum":false,
         "EnumValues":null,
         "TypeName":"DateTime",
         "TypeFullname":"System.DateTime",
         "Properties":[  
            {  
               "Name":"Date",
               "TypeName":"System.DateTime",
               "Description":null,
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Day",
               "TypeName":"System.Int32",
               "Description":null,
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"DayOfWeek",
               "TypeName":"System.DayOfWeek",
               "Description":null,
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"DayOfYear",
               "TypeName":"System.Int32",
               "Description":null,
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Hour",
               "TypeName":"System.Int32",
               "Description":null,
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Kind",
               "TypeName":"System.DateTimeKind",
               "Description":null,
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Millisecond",
               "TypeName":"System.Int32",
               "Description":null,
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Minute",
               "TypeName":"System.Int32",
               "Description":null,
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Month",
               "TypeName":"System.Int32",
               "Description":null,
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Now",
               "TypeName":"System.DateTime",
               "Description":null,
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"UtcNow",
               "TypeName":"System.DateTime",
               "Description":null,
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Second",
               "TypeName":"System.Int32",
               "Description":null,
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Ticks",
               "TypeName":"System.Int64",
               "Description":null,
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"TimeOfDay",
               "TypeName":"System.TimeSpan",
               "Description":null,
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Today",
               "TypeName":"System.DateTime",
               "Description":null,
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Year",
               "TypeName":"System.Int32",
               "Description":null,
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            }
         ]
      },
      {  
         "Description":null,
         "IsGeneric":false,
         "IsArray":false,
         "GenericParameters":null,
         "IsEnum":true,
         "EnumValues":[  
            {  
               "Name":"Sunday",
               "TypeName":"System.DayOfWeek",
               "Description":null,
               "Type":0,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Monday",
               "TypeName":"System.DayOfWeek",
               "Description":null,
               "Type":0,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Tuesday",
               "TypeName":"System.DayOfWeek",
               "Description":null,
               "Type":0,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Wednesday",
               "TypeName":"System.DayOfWeek",
               "Description":null,
               "Type":0,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Thursday",
               "TypeName":"System.DayOfWeek",
               "Description":null,
               "Type":0,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Friday",
               "TypeName":"System.DayOfWeek",
               "Description":null,
               "Type":0,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Saturday",
               "TypeName":"System.DayOfWeek",
               "Description":null,
               "Type":0,
               "IsOptional":false,
               "DefaultValue":null
            }
         ],
         "TypeName":"DayOfWeek",
         "TypeFullname":"System.DayOfWeek",
         "Properties":null
      },
      {  
         "Description":null,
         "IsGeneric":false,
         "IsArray":false,
         "GenericParameters":null,
         "IsEnum":true,
         "EnumValues":[  
            {  
               "Name":"Unspecified",
               "TypeName":"System.DateTimeKind",
               "Description":null,
               "Type":0,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Utc",
               "TypeName":"System.DateTimeKind",
               "Description":null,
               "Type":0,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Local",
               "TypeName":"System.DateTimeKind",
               "Description":null,
               "Type":0,
               "IsOptional":false,
               "DefaultValue":null
            }
         ],
         "TypeName":"DateTimeKind",
         "TypeFullname":"System.DateTimeKind",
         "Properties":null
      },
      {  
         "Description":null,
         "IsGeneric":false,
         "IsArray":false,
         "GenericParameters":null,
         "IsEnum":false,
         "EnumValues":null,
         "TypeName":"TimeSpan",
         "TypeFullname":"System.TimeSpan",
         "Properties":[  
            {  
               "Name":"Ticks",
               "TypeName":"System.Int64",
               "Description":null,
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Days",
               "TypeName":"System.Int32",
               "Description":null,
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Hours",
               "TypeName":"System.Int32",
               "Description":null,
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Milliseconds",
               "TypeName":"System.Int32",
               "Description":null,
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Minutes",
               "TypeName":"System.Int32",
               "Description":null,
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Seconds",
               "TypeName":"System.Int32",
               "Description":null,
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"TotalDays",
               "TypeName":"System.Double",
               "Description":null,
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"TotalHours",
               "TypeName":"System.Double",
               "Description":null,
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"TotalMilliseconds",
               "TypeName":"System.Double",
               "Description":null,
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"TotalMinutes",
               "TypeName":"System.Double",
               "Description":null,
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"TotalSeconds",
               "TypeName":"System.Double",
               "Description":null,
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            }
         ]
      },
      {  
         "Description":"Represent Zone information",
         "IsGeneric":false,
         "IsArray":false,
         "GenericParameters":null,
         "IsEnum":false,
         "EnumValues":null,
         "TypeName":"ZoneInfo",
         "TypeFullname":"ParadoxOnConstellation.ZoneInfo",
         "Properties":[  
            {  
               "Name":"IsOpen",
               "TypeName":"System.Boolean",
               "Description":"A value indicating whether this zone is open.",
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"IsTamper",
               "TypeName":"System.Boolean",
               "Description":"A value indicating whether this zone is tamper.",
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"InAlarm",
               "TypeName":"System.Boolean",
               "Description":"A value indicating whether this zone is in alarm.",
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"InFireAlarm",
               "TypeName":"System.Boolean",
               "Description":"A value indicating whether this zone is in fire alarm].",
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"SupervisionLost",
               "TypeName":"System.Boolean",
               "Description":"A value indicating whether this zone has supervision lost.",
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"LowBattery",
               "TypeName":"System.Boolean",
               "Description":"A value indicating whether this zone has low battery.",
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Id",
               "TypeName":"System.Int32",
               "Description":"The identifier.",
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Type",
               "TypeName":"System.String",
               "Description":"The object type.",
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Name",
               "TypeName":"System.String",
               "Description":"The name.",
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"LastActivity",
               "TypeName":"System.DateTime",
               "Description":"The last activity.",
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            }
         ]
      },
      {  
         "Description":null,
         "IsGeneric":false,
         "IsArray":false,
         "GenericParameters":null,
         "IsEnum":false,
         "EnumValues":null,
         "TypeName":"AreaInfo",
         "TypeFullname":"ParadoxOnConstellation.AreaInfo",
         "Properties":[  
            {  
               "Name":"IsFullArmed",
               "TypeName":"System.Boolean",
               "Description":null,
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"IsStayArmed",
               "TypeName":"System.Boolean",
               "Description":null,
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"ZoneInMemory",
               "TypeName":"System.Boolean",
               "Description":null,
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"HasTrouble",
               "TypeName":"System.Boolean",
               "Description":null,
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"IsReady",
               "TypeName":"System.Boolean",
               "Description":null,
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"IsInProgramming",
               "TypeName":"System.Boolean",
               "Description":null,
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"InAlarm",
               "TypeName":"System.Boolean",
               "Description":null,
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Strobe",
               "TypeName":"System.Boolean",
               "Description":null,
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Id",
               "TypeName":"System.Int32",
               "Description":"The identifier.",
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Type",
               "TypeName":"System.String",
               "Description":"The object type.",
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Name",
               "TypeName":"System.String",
               "Description":"The name.",
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"LastActivity",
               "TypeName":"System.DateTime",
               "Description":"The last activity.",
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            }
         ]
      }
   ]
}</pre><p></p>
<p>The post <a rel="nofollow" href="https://developer.myconstellation.io/client-api/rest-api/interface-rest-constellation/">L&rsquo;interface REST « Constellation »</a> appeared first on <a rel="nofollow" href="https://developer.myconstellation.io">Constellation</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://developer.myconstellation.io/client-api/rest-api/interface-rest-constellation/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>L&#8217;interface REST « Consumer »</title>
		<link>https://developer.myconstellation.io/client-api/rest-api/interface-rest-consumer/</link>
					<comments>https://developer.myconstellation.io/client-api/rest-api/interface-rest-consumer/#comments</comments>
		
		<dc:creator><![CDATA[Sebastien Warin]]></dc:creator>
		<pubDate>Fri, 12 Aug 2016 14:44:31 +0000</pubDate>
				<category><![CDATA[REST API]]></category>
		<category><![CDATA[REST]]></category>
		<category><![CDATA[Constellation]]></category>
		<category><![CDATA[StateObject]]></category>
		<category><![CDATA[AccessKey]]></category>
		<category><![CDATA[Consumer]]></category>
		<category><![CDATA[Package]]></category>
		<category><![CDATA[Request]]></category>
		<category><![CDATA[Message]]></category>
		<category><![CDATA[Subscribe]]></category>
		<category><![CDATA[MessageCallback]]></category>
		<category><![CDATA[Saga]]></category>
		<category><![CDATA[HTTP]]></category>
		<category><![CDATA[group]]></category>
		<category><![CDATA[SendMessage]]></category>
		<guid isPermaLink="false">https://developer.myconstellation.io/?p=2284</guid>

					<description><![CDATA[<p>L’interface REST “Consumer” permet à tout système, script, objet ou programme de “consommer” des éléments dans une Constellation sans devoir être déclaré comme un package. Un consommateur peut : Consommer des StateObjects (Request ou Subscribe) Envoyer ou recevoir des messages Généralités</p>
<p>The post <a rel="nofollow" href="https://developer.myconstellation.io/client-api/rest-api/interface-rest-consumer/">L&rsquo;interface REST « Consumer »</a> appeared first on <a rel="nofollow" href="https://developer.myconstellation.io">Constellation</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>L’interface REST “Consumer” permet à tout système, script, objet ou programme de “consommer” des éléments dans une Constellation sans devoir être déclaré comme un package.</p>
<p>Un consommateur peut :</p>
<ul>
<li>Consommer des StateObjects (Request ou Subscribe)</li>
<li>Envoyer ou recevoir des messages</li>
</ul>
<h3>Généralités</h3>
<h4>Construction de l’URL</h4>
<p>L’URL est :  &lt;Root URI&gt;/rest/consumer/&lt;action&gt;?&lt;paramètres&gt;</p>
<p>Partons du principe que votre Constellation est exposée en HTTP sur le port 8088 (sans path). On retrouvera dans le <a href="https://developer.myconstellation.io/constellation-server/fichier-de-configuration/">fichier de configuration</a> la section suivante :</p>
<p></p><pre class="crayon-plain-tag">&lt;listenUris&gt;
  &lt;uri listenUri="http://+:8088/" /&gt;
&lt;/listenUris&gt;</pre><p></p>
<p>La “Root URI “ est donc “<strong>http://&lt;ip ou dns&gt;:8088/</strong>”.</p>
<p>Par exemple si nous sommes en local, nous pourrions écrire :</p>
<p></p><pre class="crayon-plain-tag">http://localhost:8088/rest/consumer/xxxxx</pre><p></p>
<h4>Authentification</h4>
<p>Comme pour toutes les requêtes vers Constellation vous devez impérativement spécifier dans <u>les headers HTTP</u> <strong>ou</strong> dans <u>les paramètres de l’URL</u> (querystring), les paramètres “SentinelName”, “PackageName” et “AccessKey” pour l’authentification.</p>
<p>Dans le cas de l’API “Consumer”, la “SentinelName” est “Consumer” et le “PackageName” est le nom de votre choix que l’on considère comme un “FriendlyName”. Typiquement le “FriendlyName” est par exemple le nom de l’application/page qui se connecte.</p>
<p>L’AccessKey doit bien sur être déclarée et activée sur le serveur.</p>
<p>Ainsi chaque appel sera sous la forme :</p>
<p></p><pre class="crayon-plain-tag">http://localhost:8088/rest/consumer/&lt;action&gt;?SentinelName=Consumer&amp;PackageName=&lt;Friendly name&gt;&amp;AccessKey=&lt;access key&gt;&amp;&lt;paramètres&gt;</pre><p></p>
<h4>Check Access</h4>
<p>Toutes les API REST de Constellation exposent une méthode en GET “CheckAccess” qui retourne un code HTTP 200 (OK). Cela permet de tester la connexion et l’authentification au serveur Constellation.</p>
<ul>
<li>Action : “CheckAccess” (GET)</li>
<li>Paramètres : aucun</li>
</ul>
<p>Exemple :</p>
<p></p><pre class="crayon-plain-tag">http://localhost:8088/rest/consumer/CheckAccess?SentinelName=Consumer&amp;PackageName=Demo&amp;AccessKey=MaCleDeTest123</pre><p></p>
<h3>Envoyer des messages</h3>
<ul>
<li>Action : “SendMessage” (GET ou POST)</li>
<li>En GET, voici les paramètres de l’URL :
<ul>
<li><u>scope</u> : le type de scope (All, Other, Group, Sentinel ou Package)</li>
<li><u>args</u> : les arguments du scope (par exemple le nom du groupe, de la sentinelle, du package ou de l’instance du package – plusieurs valeurs possibles séparées par des virgules)</li>
<li><u>key</u> : la clé du message (= la méthode à invoquer)</li>
<li><u>data</u> : le contenu du message (= les arguments de la méthode)</li>
<li><u>sagaId</u> (optionnel) : l’identification de la saga si le message est envoyé dans une saga</li>
</ul>
</li>
</ul>
<p>Vous pouvez également invoquer cette action en POST. Le corps de votre requête contiendra l’objet JSON suivant :</p>
<p></p><pre class="crayon-plain-tag">{
  "Scope" : { "Scope" : "&lt;type&gt;", Args: [ "&lt;arg1&gt;", "&lt;args2&gt;", .... ], "SagaId":"Identifiant de la Saga" },
  "Key" : "&lt;Key&gt;",
  "Data" : "&lt;Data&gt;"
}</pre><p></p>
<p>La propriété “SagaId” dans le JSON ci-dessus est optionnelle.</p>
<p>Par exemple pour envoyer un message au package Nest en invoquant la méthode (key) “SetTargetTemperature” avec en paramètre le nombre “21” :</p>
<p></p><pre class="crayon-plain-tag">http://localhost:8088/rest/consumer/SendMessage?SentinelName=Consumer&amp;PackageName=Demo&amp;AccessKey=MaCleDeTest123&amp;scope=Package&amp;args=Nest&amp;key=SetTargetTemperature&amp;data=21</pre><p></p>
<p>Par exemple pour invoquer ce MessageCallback depuis cURL :</p>
<p></p><pre class="crayon-plain-tag">curl "http://localhost:8088/rest/consumer/SendMessage?SentinelName=Consumer&amp;PackageName=Demo&amp;AccessKey=MaCleDeTest123&amp;scope=Package&amp;args=Nest&amp;key=SetTargetTemperature&amp;data=21"</pre><p></p>
<p>Ce même MessageCallback “SetTargetTemperature” du package Nest peut être invoqué dans une saga afin de recevoir un un accusé de réception :</p>
<p></p><pre class="crayon-plain-tag">http://localhost:8088/rest/consumer/SendMessage?SentinelName=Consumer&amp;PackageName=Demo&amp;AccessKey=MaCleDeTest123&amp;scope=Package&amp;args=Nest&amp;key=SetTargetTemperature&amp;data=21&amp;sagaId=123456789</pre><p></p>
<p>Il faudra ensuite “récupérer” les messages reçus (voir dessous) pour lire la réponse à votre saga que nous avons ici identifié par la clé “123456789”.</p>
<p>Autre exemple avec un MessageCallback avec plusieurs paramètres :</p>
<p></p><pre class="crayon-plain-tag">http://localhost:8088/rest/consumer/SendMessage?SentinelName=Consumer&amp;PackageName=Demo&amp;AccessKey=MaCleDeTest123&amp;scope=Package&amp;args=MyPackage&amp;key=MethodeAvec3Params&amp;data=[ 'param 1', 123, true ]</pre><p></p>
<p>Attention le contenu du paramètre « args » doit être encodé. De ce fait, avec cURL :</p>
<p></p><pre class="crayon-plain-tag">curl "http://localhost:8088/rest/consumer/SendMessage?SentinelName=Consumer&amp;PackageName=Demo&amp;AccessKey=MaCleDeTest123&amp;scope=Package&amp;args=MyPackage&amp;key=MethodeAvec3Params&amp;data=%5B+%27param+1%27%2C+123%2C+true+%5D"</pre><p></p>
<p>Pour invoquer ce même MC avec un « POST » depuis cURL :</p>
<p></p><pre class="crayon-plain-tag">curl -H "Content-Type: application/json" -X POST -i -d '{ "Scope" : { "Scope" : "Package", Args: [ "MyPackage"] }, "Key" : "MethodeAvec3Params", "Data" : [ "param 1", 123, true ] }' "http://localhost:8088/rest/consumer/SendMessage?SentinelName=Consumer&amp;PackageName=Demo&amp;AccessKey=MaCleDeTest123"</pre><p></p>
<h3>Recevoir des messages</h3>
<h4>Créer un abonnement de réception</h4>
<p>Tout d’abord pour recevoir des messages il faut s’abonner aux messages.</p>
<ul>
<li>Action : “SubscribeToMessage” (GET)</li>
<li>Paramètres :
<ul>
<li><u>subscriptionId</u> (optionnel) : identifiant de l’abonnement si déjà connu</li>
</ul>
</li>
</ul>
<p></p><pre class="crayon-plain-tag">http://localhost:8088/rest/consumer/SubscribeToMessage?SentinelName=Consumer&amp;PackageName=Demo&amp;AccessKey=MaCleDeTest123</pre><p></p>
<p>Vous obtiendrez en réponse l’ID de votre abonnement, le “Subscription Id”.</p>
<h4>Relever les messages</h4>
<ul>
<li>Action : “GetMessages” (GET)</li>
<li>Paramètres :
<ul>
<li><u>subscriptionId</u> : identifiant de l’abonnement</li>
<li><u>timeout</u> (optionnel – par défaut 60000) : temps maximal en milliseconde de la mise en attente de la requête (entre 1000ms et 120000ms)</li>
<li><u>limit</u> (optionnel – par défaut 0) : nombre maximum de message à retourner pour l’appel</li>
</ul>
<p><!--EndFragment--></li>
</ul>
<p>Il s’agit d’une requête en “long-polling” c’est à dire que la requête sera “bloquée” sur le serveur tant qu’il n’y a pas de message reçu évitant ainsi de “flooder” en continue le serveur pour savoir si de nouveaux messages sont disponibles ou non. Par défaut la requête est bloquée 60 secondes maximum mais vous pouvez personnaliser cette valeur avec le paramètre “timeout”. Si il y a des messages disponibles, le serveur vous renvoi un tableau JSON avec les messages reçus. Si il n’y a pas de réponse dans le délai spécifié par le paramètre “timeout” (60 secondes par défaut), le tableau retourné sera vide.</p>
<p>A chaque réponse vous devez donc relancer une requête “GetMessages” pour “écouter” les prochains messages qui vont sont destinés.</p>
<p>Il est également possible de limiter le nombre de message dans la réponse avec le paramètre “limit” ce qui peut être utile sur de petits “devices” ne disposant pas de beaucoup de mémoire RAM pour désérialiser de gros tableaux JSON.</p>
<p>Exemple simple :</p>
<p></p><pre class="crayon-plain-tag">http://localhost:8088/rest/consumer/GetMessages?SentinelName=Consumer&amp;PackageName=Demo&amp;AccessKey=MaCleDeTest123&amp;subscriptionId=xxxxx</pre><p></p>
<p>Autre exemple en limitant le nombre de message à 2 par appel et en bloquant la requête pendant 10 secondes au maximum :</p>
<p></p><pre class="crayon-plain-tag">http://localhost:8088/rest/consumer/GetMessages?SentinelName=Consumer&amp;PackageName=Demo&amp;AccessKey=MaCleDeTest123&amp;subscriptionId=xxxxx&amp;timeout=10000&amp;limit=2</pre><p></p>
<h4>S’abonner à un groupe</h4>
<p>Vous pouvez vous abonner à des groupes pour recevoir les messages envoyés dans ces groupes par l’action “SubscribeToMessageGroup” en précisant le nom du groupe et votre ID d’abonnement.</p>
<ul>
<li>Action : “SubscribeToMessageGroup” (GET)</li>
<li>Paramètres :
<ul>
<li><u>group</u> : le nom du groupe à joindre</li>
<li><u>subscriptionId</u> (optionnel) : identifiant de l’abonnement si déjà connu</li>
</ul>
</li>
</ul>
<p></p><pre class="crayon-plain-tag">http://localhost:8088/rest/consumer/SubscribeToMessageGroup?SentinelName=Consumer&amp;PackageName=Demo&amp;AccessKey=MaCleDeTest123&amp;subscriptionId=xxxxx&amp;group=A</pre><p></p>
<p>Comme l’action “SubscribeToMessage”, cette action vous retourne l’ID d’abonnement à utiliser pour l’action “GetMessages”.</p>
<h3>Consommation de StateObjects</h3>
<h4>Request</h4>
<p>Cette méthode permet de récupérer la valeur actuelle d’un ou de plusieurs StateObjects.</p>
<ul>
<li>Action : “RequestStateObjects” (GET)</li>
<li>Paramètres :
<ul>
<li><u>sentinel</u> (optionnel – par défaut “*”): nom de la sentinelle</li>
<li><u>package</u> (optionnel – par défaut “*”) : nom du package</li>
<li><u>name</u> (optionnel – par défaut “*”) : nom du StateObject</li>
<li><u>type</u> (optionnel – par défaut “*”) : type du StateObject</li>
</ul>
</li>
</ul>
<p>Par exemple pour récupérer tous les StateObject de votre Constellation :</p>
<p></p><pre class="crayon-plain-tag">http://localhost:8088/rest/consumer/RequestStateObjects?SentinelName=Consumer&amp;PackageName=Demo&amp;AccessKey=MaCleDeTest123</pre><p></p>
<p>Ou seulement ceux produits par le package “HWMonitor” (quelque soit la sentinelle) :</p>
<p></p><pre class="crayon-plain-tag">http://localhost:8088/rest/consumer/RequestStateObjects?SentinelName=Consumer&amp;PackageName=Demo&amp;AccessKey=MaCleDeTest123&amp;package=HWMonitor</pre><p></p>
<p>Ou encore tous les StateObjects nommés “/intelcpu/load/0” et produits le package “HWMonitor” (quelque soit la sentinelle) :</p>
<p></p><pre class="crayon-plain-tag">http://localhost:8088/rest/consumer/RequestStateObjects?SentinelName=Consumer&amp;PackageName=Demo&amp;AccessKey=MaCleDeTest123&amp;package=HWMonitor&amp;name=/intelcpu/load/0</pre><p></p>
<h4>Subscribe</h4>
<p>Vous pouvez également vous abonner aux mises à jour des StateObjects.</p>
<p>Le principe est le même qu’avec les messages : il faut récupérer un ID d’abonnement et invoquer une méthode en long-polling pour recevoir les mises à jour.</p>
<h5>S’abonner à des StateObjects</h5>
<ul>
<li>Action : “SubscribeToStateObjects” (GET)</li>
<li>Paramètres :
<ul>
<li><u>subscriptionId</u> (optionnel) : identifiant de l’abonnement si déjà connu</li>
<li><u>sentinel</u> (optionnel – par défaut “*”): nom de la sentinelle</li>
<li><u>package</u> (optionnel – par défaut “*”) : nom du package</li>
<li><u>name</u> (optionnel – par défaut “*”) : nom du StateObject</li>
<li><u>type</u> (optionnel – par défaut “*”) : type du StateObject</li>
</ul>
</li>
</ul>
<p>En retour vous obtiendrez l’ID d’abonnement (un GUID).</p>
<p>Par exemple pour s’abonner au SO “/intelcpu/load/0”, produit le package “HWMonitor” sur la sentinelle “MON-PC” :</p>
<p></p><pre class="crayon-plain-tag">http://localhost:8088/rest/consumer/SubscribeToStateObjects?SentinelName=Consumer&amp;PackageName=Demo&amp;AccessKey=MaCleDeTest123&amp;sentinel=MON-PC&amp;package=HWMonitor&amp;name=/intelcpu/load/0</pre><p></p>
<p><strong>ATTENTION</strong> : si vous souhaitez “ajouter” des SO à votre abonnement vous devez <u>impérativement</u> préciser votre ID d’abonnement récupéré lors du 1er appel autrement vous allez créer un nouvel abonnement.</p>
<p>Par exemple pour “ajouter” le SO correspondant à la consommation RAM :</p>
<p></p><pre class="crayon-plain-tag">http://localhost:8088/rest/consumer/SubscribeToStateObjects?SentinelName=Consumer&amp;PackageName=Demo&amp;AccessKey=MaCleDeTest123&amp;sentinel=MON-PC&amp;package=HWMonitor&amp;name=/ram/load&amp;subscriptionId=&lt;subId&gt;</pre><p></p>
<h5>Relever les StateObjects mis à jour</h5>
<p>Pour récupérer les SO de votre abonnement qui ont changés entre deux appels vous devez invoquer l’action “GetStateObjects” en spécifiant l’ID de votre abonnement :</p>
<ul>
<li>Action : “GetStateObjects” (GET)</li>
<li>Paramètres :
<ul>
<li><u>subscriptionId</u> : identifiant de l’abonnement</li>
<li><u>timeout</u> (optionnel – par défaut 60000) : temps maximal en milliseconde de la mise en attente de la requête (entre 1000ms et 120000ms)</li>
<li><u>limit</u> (optionnel – par défaut 0) : nombre maximum de message à retourner pour l’appel</li>
</ul>
</li>
<li><!--EndFragment--></li>
</ul>
<p>Comme pour les message, vous pouvez limiter le nombre de SO (limit) et le timeout de la requête (timeout).</p>
<p></p><pre class="crayon-plain-tag">http://localhost:8088/rest/consumer/GetStateObjects?SentinelName=Consumer&amp;PackageName=Demo&amp;AccessKey=MaCleDeTest123&amp;subscriptionId=&lt;subId&gt;</pre><p></p>
<p>Notez que si un StateObject pour lequel vous êtes abonné change plusieurs fois entre deux appels “GetStateObjects”, vous obtiendrez la dernière valeur et non l’historique de tous les changements.</p>
<p>The post <a rel="nofollow" href="https://developer.myconstellation.io/client-api/rest-api/interface-rest-consumer/">L&rsquo;interface REST « Consumer »</a> appeared first on <a rel="nofollow" href="https://developer.myconstellation.io">Constellation</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://developer.myconstellation.io/client-api/rest-api/interface-rest-consumer/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
	</channel>
</rss>

<!--
Performance optimized by W3 Total Cache. Learn more: https://www.boldgrid.com/w3-total-cache/?utm_source=w3tc&utm_medium=footer_comment&utm_campaign=free_plugin

Mise en cache de page à l’aide de Disk: Enhanced 

Served from: developer.myconstellation.io @ 2026-01-25 01:59:06 by W3 Total Cache
-->