﻿<?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 StateObjectLink - Constellation</title>
	<atom:link href="https://developer.myconstellation.io/tag/stateobjectlink/feed/" rel="self" type="application/rss+xml" />
	<link>https://developer.myconstellation.io/tag/stateobjectlink/</link>
	<description>Votre plateforme d&#039;interconnexion</description>
	<lastBuildDate>Thu, 19 Apr 2018 07:56:31 +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 StateObjectLink - Constellation</title>
	<link>https://developer.myconstellation.io/tag/stateobjectlink/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Créer une prise connectée avec un ESP8266</title>
		<link>https://developer.myconstellation.io/tutorials/creer-une-prise-connectee-avec-un-esp8266/</link>
					<comments>https://developer.myconstellation.io/tutorials/creer-une-prise-connectee-avec-un-esp8266/#respond</comments>
		
		<dc:creator><![CDATA[Lucas]]></dc:creator>
		<pubDate>Tue, 31 Oct 2017 11:29:46 +0000</pubDate>
				<category><![CDATA[Tutoriels]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[MessageCallback]]></category>
		<category><![CDATA[Switch]]></category>
		<category><![CDATA[StateObjectLink]]></category>
		<category><![CDATA[Arduino]]></category>
		<category><![CDATA[ESP8266]]></category>
		<category><![CDATA[ESP]]></category>
		<category><![CDATA[Domotique]]></category>
		<category><![CDATA[Relais]]></category>
		<category><![CDATA[XBMC]]></category>
		<category><![CDATA[Kodi]]></category>
		<guid isPermaLink="false">https://developer.myconstellation.io/?p=5668</guid>

					<description><![CDATA[<p>Par Lucas Dupuis La prise connectée est un élément phare de la domotique de la maison. Il permet d&#8217;allumer ou d&#8217;éteindre un équipement branché dessus ou encore de connaitre sa consommation en énergie. Dans mon cas, j&#8217;avais besoin d&#8217;allumer ou</p>
<p>The post <a rel="nofollow" href="https://developer.myconstellation.io/tutorials/creer-une-prise-connectee-avec-un-esp8266/">Créer une prise connectée avec un ESP8266</a> appeared first on <a rel="nofollow" href="https://developer.myconstellation.io">Constellation</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p><em>Par Lucas Dupuis</em></p>
<p>La prise connectée est un élément phare de la domotique de la maison. Il permet d&rsquo;allumer ou d&rsquo;éteindre un équipement branché dessus ou encore de connaitre sa consommation en énergie. Dans mon cas, j&rsquo;avais besoin d&rsquo;allumer ou d&rsquo;éteindre les enceintes de mon média center automatiquement lorsque ce dernier était démarré.</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2017/10/2016-08-08-16.32.30.jpg"><img class="colorbox-5668"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="Prise connectée" src="https://developer.myconstellation.io/wp-content/uploads/2017/10/2016-08-08-16.32.30_thumb.jpg" alt="Prise connectée" width="404" height="304" border="0" /></a></p>
<p align="left">Découvrons ensemble comment créer sa prise connectée avec un ESP8266.</p>
<p><span id="more-5668"></span></p>
<h2>Prérequis</h2>
<p>Pour ce tutoriel, il vous faut :</p>
<ul>
<li>Un bloc prise avec un interrupteur</li>
<li>Un transformateur AC/DC 5v</li>
<li>Un ESP-01 (ESP8266)</li>
<li>Un régulateur de tension 3.3v</li>
<li>Un relais 220V pilotable en 5v</li>
<li>Un transistor, des résistances, des leds, une diode, des condensateurs</li>
<li>Du fil électrique</li>
<li>Un pistolet à colle et une drémel</li>
<li>Un serveur Constellation</li>
</ul>
<h2>Etape 1 : Construire la prise</h2>
<p>Dans un premier temps, il nous faut un boitier abordable que nous pourrons ouvrir pour insérer notre ESP à l&rsquo;intérieur. Après quelques recherches, j&rsquo;ai opté pour le <a href="http://www.conrad.fr/ce/fr/product/778994/Prise-intermdiaire-commutable-Renkforce-778994-1-ple-argent">boitier Renkforce disponible chez Conrad</a> pour 3€ environ.</p>
<p>On commence donc par l’ouvrir pour la vider littéralement :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2017/10/2016-11-10-22.38.32.jpg"><img class="colorbox-5668"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="Prise Renkforce" src="https://developer.myconstellation.io/wp-content/uploads/2017/10/2016-11-10-22.38.20_thumb.jpg" alt="Prise Renkforce" width="204" height="271" border="0" /><img class="colorbox-5668"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="Prise Renkforce" src="https://developer.myconstellation.io/wp-content/uploads/2017/10/2016-11-10-22.38.32_thumb.jpg" alt="Prise Renkforce" width="204" height="271" border="0" /></a></p>
<p align="center"><img class="colorbox-5668"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="Démontage" src="https://developer.myconstellation.io/wp-content/uploads/2017/10/2016-11-10-22.41.28_thumb.jpg" alt="Démontage" width="244" height="184" border="0" /><a href="https://developer.myconstellation.io/wp-content/uploads/2017/10/2016-11-10-22.41.28.jpg"><img class="colorbox-5668"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="Prise démontée" src="https://developer.myconstellation.io/wp-content/uploads/2017/10/2016-11-10-22.44.15_thumb.jpg" alt="Prise démontée" width="244" height="184" border="0" /></a></p>
<p>Puis tous les supports plastique à l&rsquo;intérieur doivent être cassés pour libérer un maximum de place. Je les ai cassés avec une pince coupante et j&rsquo;ai fini de retirer le maximum de plastique avec un dremel. Sur cette photo j&rsquo;avais retiré une partie du fond de la prise pour un autre projet.</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2017/10/2016-12-18-11.25.15.jpg"><img class="colorbox-5668"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="Usinage" src="https://developer.myconstellation.io/wp-content/uploads/2017/10/2016-12-18-11.25.15_thumb.jpg" alt="Usinage" width="354" height="266" border="0" /></a></p>
<p>Il faut ensuite préparer un câblage avec le relais pour qu&rsquo;il s&rsquo;intercale entre l&rsquo;arrivée de la phase (mur) et la phase distribuée à l&rsquo;élément branché sur la prise. Mais il faut également garder en tête que l&rsquo;alimentation de l&rsquo;ESP doit être permanente :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2017/10/2016-08-10-22.52.19.jpg"><img class="colorbox-5668"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="Schéma" src="https://developer.myconstellation.io/wp-content/uploads/2017/10/2016-08-10-22.52.19_thumb.jpg" alt="Schéma" width="354" height="266" border="0" /></a></p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2017/10/Schma-relais.png"><img class="colorbox-5668"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="Schéma" src="https://developer.myconstellation.io/wp-content/uploads/2017/10/Schma-relais_thumb.png" alt="Schéma" width="350" height="321" border="0" /></a></p>
<p>Mon principal problème dans ce tutoriel a été de tout faire rentrer dans la prise. En effet, l&rsquo;alimentation + le relais prennent beaucoup de place et tout est rentré au chausse-pied, avec le câblage noyé dans la colle chaude afin d&rsquo;assurer l&rsquo;isolation.</p>
<p>Le transformateur alimente donc en 5v un régulateur de tension LM1117 3.3V avec deux condensateurs pour lisser du 3.3v pour l&rsquo;ESP01.</p>
<p>Il alimente également directement la bobine du relais dont le circuit est interrompu par un transistor NPN BC547 dont la base sera pilotée en saturation par un GPIO de l&rsquo;ESP.</p>
<p>L&rsquo;ESP pilote deux leds de statut : une rouge et une verte et possède également son dernier GPIO en input pour un bouton physique placé sur le dessus du boitier. Si vous avez suivi jusque-là et que vous connaissez l&rsquo;ESP01, vous aurez compris qu&rsquo;il est impossible de le programmer directement dans la prise, deux des 4 GPIO devant normalement être utilisés pour la communication série.</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2017/10/2016-08-07-16.00.46.jpg"><img class="colorbox-5668"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="2016-08-07 16.00.46" src="https://developer.myconstellation.io/wp-content/uploads/2017/10/2016-08-07-16.00.46_thumb.jpg" alt="2016-08-07 16.00.46" width="454" height="342" border="0" /></a></p>
<p>Pour combler le « trou » du bouton physique original, j&rsquo;ai choisi de coller par l&rsquo;intérieur du boitier un petit bout de plexiglas translucide. Je l&rsquo;ai ensuite percé pour faire passer les deux leds rouge et verte.</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2017/10/2016-12-18-18.27.32.jpg"><img class="colorbox-5668"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="2016-12-18 18.27.32" src="https://developer.myconstellation.io/wp-content/uploads/2017/10/2016-12-18-18.27.32_thumb.jpg" alt="2016-12-18 18.27.32" width="244" height="184" border="0" /></a><a href="https://developer.myconstellation.io/wp-content/uploads/2017/10/2016-08-22-23.08.43.jpg"><img class="colorbox-5668"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="2016-08-22 23.08.43" src="https://developer.myconstellation.io/wp-content/uploads/2017/10/2016-08-22-23.08.43_thumb.jpg" alt="2016-08-22 23.08.43" width="244" height="184" border="0" /></a></p>
<p align="left">Et voilà, on obtient une prise connectée par Wifi avec un ESP8266 avec un bouton poussoir et deux LEDs, reste plus qu’à le programmer !</p>
<h2>Etape 2 : la programmation</h2>
<p>La fonction de base de la prise est assez simple : couper le courant ou le laisser passer. Dans un premier temps, j&rsquo;ai uploadé un sketch de base Constellation avec Arduino sur l&rsquo;ESP01 à l&rsquo;extérieur de la prise. Je l&rsquo;ai ensuite branché dans la prise que j&rsquo;ai enfiché dans le mur. Bazinga, le régulateur 3.3v fait son job, l&rsquo;ESP boote, se connecte à mon réseau wifi et envoie un « hello world » dans la console Constellation. Pour découvrir comment connecter un ESP8266 à Constellation, <a href="https://developer.myconstellation.io/getting-started/connecter-un-arduino-ou-un-esp8266-constellation/">suivez ce guide</a>.</p>
<p>Ensuite, j&rsquo;ai utilisé la librairie Constellation <a href="https://developer.myconstellation.io/client-api/arduino-esp-api/recevoir-des-messages-et-exposer-des-methodes-messagecallback-sur-arduino-esp/">pour ajouter un MessageCallback</a> pour activer ou désactiver le GPIO de la prise, <a href="https://developer.myconstellation.io/client-api/arduino-esp-api/produire-des-stateobjects-depuis-arduino-esp/">couplé à un StateObject</a> pour maintenir l’état de la prise dans Constellation :</p>
<p></p><pre class="crayon-plain-tag">constellation.registerMessageCallback("Switch", MessageCallbackDescriptor().setDescription("Switch le statut du relais."),
  [](JsonObject &amp; json) {
    statutRelais = !statutRelais;
    digitalWrite(gpioRelais, statutRelais);
    constellation.pushStateObject("Status", stringFormat("{ 'IsActivated':%s }", statutRelais ? "true" : "false" ));
  });</pre><p></p>
<p align="left">Ainsi Constellation a toujours connaissance de l’état de la prise via le StateObject nommé “Status” :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2017/10/StateObject.png"><img class="colorbox-5668"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="StateObject de l'état de la prise" src="https://developer.myconstellation.io/wp-content/uploads/2017/10/StateObject_thumb.png" alt="StateObject de l'état de la prise" width="354" height="259" border="0" /></a></p>
<p align="left">Et tout le monde peut maintenant découvrir et utiliser le MessageCallback “Switch” exposé par notre ESP pour permuter l’état de notre prise :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2017/10/MessageCallback2-002.png"><img class="colorbox-5668"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border: 0px;" title="MessageCallback" src="https://developer.myconstellation.io/wp-content/uploads/2017/10/MessageCallback2-002_thumb.png" alt="MessageCallback" width="354" height="115" border="0" /></a></p>
<p align="left">Bingo, on a donc une prise 220V connectée à Constellation qu’on pourra piloter depuis une page Web, un programme Python ou autre.</p>
<p align="left">Pour vous donnez quelques idées, n’hésitez pas à relire ce tutoriel : <a href="https://developer.myconstellation.io/tutorials/creer-un-relais-connecte/">Créer un relais connecté</a>.</p>
<h2 align="left">Etape 3 : Lier sa prise connectée à l’état de son média-center</h2>
<p align="left">Dans ma Constellation, je dispose d&rsquo;un package « brain » développé en C# avec Visual Studio qui contient l’ensemble des règles de la maison (gestion du chauffages, lumières, volets, etc..).</p>
<p align="left">Je l’ai enrichi pour faire en sorte que si Kodi est en train de lire un média (audio ou vidéo) et que la prise n’est pas allumée, alors il invoque le MessageCallback pour allumer la prise. Et inversement pour l&rsquo;éteindre !</p>
<p align="left">J’ai donc dans une classe C#, ajouté <a href="https://developer.myconstellation.io/client-api/net-package-api/consommer-des-stateobjects/#Les_StateObjectLink">deux StateObjectLinks</a>, c’est à dire que j’ai deux propriétés de mon code C# qui sont liées à mes StateObjets représentant l’état de mon media-center de l’état de ma prise !</p>
<p align="left">Il me reste plus qu’à ajouter un handler sur le changement d’état du State Object de Kodi, afin d’ajouter deux conditions “if” :</p>
<ul>
<li>
<div align="left">Si la prise est éteinte alors que Kodi joue quelque chose (PlayerState différent de null) alors on allume la prise</div>
</li>
<li>
<div align="left">Si la prise est allumée alors que Kodi joue rien (PlayerState null) alors on éteint la prise</div>
</li>
</ul>
<p align="left">Pour allumer ou éteindre la prise, il suffit d’invoquer le MessageCallback “Switch” exposé par notre code Arduino <a href="https://developer.myconstellation.io/client-api/net-package-api/envoyer-des-messages-invoquer-des-messagecallbacks/">en créant un proxy vers notre package.</a></p>
<p></p><pre class="crayon-plain-tag">public class KodiDemo
{
    /// &lt;summary&gt;
    /// StateObject XBMC. Permet de connaitre les infos de lecture.
    /// &lt;/summary&gt;
    [StateObjectLink(Package = "Xbmc", Name = "Kodi Salon NUC")]
    public StateObjectNotifier KodiNotifier { get; set; }

    /// &lt;summary&gt;
    /// StateObject de l'ESP controlant le relais d'activation. Permet de synchroniser les infos de lecture avec la valeur du relais.
    /// &lt;/summary&gt;
    [StateObjectLink(Sentinel = "ESP8266-01-001", Package = "ESP_Relay_Button", Name = "Status")]
    public StateObjectNotifier PriseKodi { get; set; }

    public void Start()
    {
        this.KodiNotifier.ValueChanged += (s, e) =&gt;
        {
            if (this.PriseKodi.DynamicValue.Status == false
                &amp;&amp; e.IsNew == false
                &amp;&amp; e.OldState.DynamicValue.PlayerState == null
                &amp;&amp; e.NewState.DynamicValue.PlayerState != null)
            {
                // démarrage.
                PackageHost.WriteInfo("Activation de la prise.");
                PackageHost.CreateMessageProxy("ESP8266_01_002/ESP_Relay_Button").Switch();
            }

            if (this.PriseKodi.DynamicValue.Status == true
                &amp;&amp; e.IsNew == false
                &amp;&amp; e.OldState.DynamicValue.PlayerState != null
                &amp;&amp; e.NewState.DynamicValue.PlayerState == null)
            {
                PackageHost.WriteInfo($"Arret de la prise.");
                PackageHost.CreateMessageProxy("ESP8266_01_002/ESP_Relay_Button").Switch();
            }
        };
    }
}</pre><p></p>
<p>Et voilà comment en quelques lignes de C# et grâce à Constellation, mes enceintes seront automatiquement allumées ou éteintes selon que mon media-center diffuse ou non un média vidéo ou audio !</p>
<h2>Pour aller plus loin</h2>
<p>Pour aller plus loin, j&rsquo;ai ajouté quelques fonctionnalités intéressantes :</p>
<ul>
<li>J&rsquo;ai pluggé le bouton poussoir ajouté sur le dessus de la prise pour qu&rsquo;il change l&rsquo;état du relais et mette à jour le state objet en conséquence.</li>
<li>J&rsquo;ai ajouté la possibilité d&rsquo;associer les leds de façade au fonctionnement de la prise en m&rsquo;inspirant de ce qui existe sur les prises connectées du marché. La led rouge indique le statut de fonctionnement (power on / connexion au wifi en clignotant), la led verte indique l&rsquo;état du relais.</li>
<li>J&rsquo;ai ajouté également un mode « blind », je trouve que c&rsquo;est une fonctionnalité intéressante mais qui est absente des prises sur le marché : Quand il fait noir dans une pièce et que la prise se reconnecte au wifi, cela peut être gênant de la voir clignoter. Un package de « brain » peut alors gérer les leds directement en <a href="https://developer.myconstellation.io/showcases/connecter-volets-constellation-arduino-raspberry/">fonction de mes volets</a> <img src="https://s.w.org/images/core/emoji/14.0.0/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /></li>
<li>Ensuite, en cas de déconnection du wifi ou de coupure de courant, j&rsquo;ai prévu un bout de code permettant, au démarrage de l&rsquo;ESP, de requêter son propre StateObject. Cela permet à la prise de revenir à l&rsquo;état dans lequel elle était avant la coupure.</li>
<li>J&rsquo;ai également fait intervenir <a href="https://developer.myconstellation.io/tutorials/connecter-un-video-projecteur-dans-constellation/">l&rsquo;activation de mon projecteur</a>. Ce dernier push un StateObject. Si le média center est éteint, il envoie un paquet WOL via <a href="https://developer.myconstellation.io/package-library/networktools/">le package networktools</a> pour l&rsquo;allumer et envoie une notification de fermeture des volets du salon. Le démarrage de la lecture du média sur kodi pilote la prise d&rsquo;allumage des enceintes sans action manuelle. Ainsi, le démarrage du projecteur et la lecture sur kodi lancent l&rsquo;ambiance parfaite pour profiter de mes séries en un seul geste.</li>
</ul>
<p>The post <a rel="nofollow" href="https://developer.myconstellation.io/tutorials/creer-une-prise-connectee-avec-un-esp8266/">Créer une prise connectée avec un ESP8266</a> appeared first on <a rel="nofollow" href="https://developer.myconstellation.io">Constellation</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://developer.myconstellation.io/tutorials/creer-une-prise-connectee-avec-un-esp8266/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Synchroniser la lampe du bureau avec sa session Windows</title>
		<link>https://developer.myconstellation.io/tutorials/synchroniser-lampe-bureau-avec-session-windows/</link>
					<comments>https://developer.myconstellation.io/tutorials/synchroniser-lampe-bureau-avec-session-windows/#respond</comments>
		
		<dc:creator><![CDATA[Sebastien Warin]]></dc:creator>
		<pubDate>Sun, 14 May 2017 12:35:00 +0000</pubDate>
				<category><![CDATA[Tutoriels]]></category>
		<category><![CDATA[.NET]]></category>
		<category><![CDATA[IA]]></category>
		<category><![CDATA[Package]]></category>
		<category><![CDATA[StateObjectLink]]></category>
		<category><![CDATA[Vera]]></category>
		<category><![CDATA[Windows]]></category>
		<category><![CDATA[Z-Wave]]></category>
		<category><![CDATA[WindowsControl]]></category>
		<category><![CDATA[Lux]]></category>
		<category><![CDATA[LightSensor]]></category>
		<guid isPermaLink="false">https://developer.myconstellation.io/?p=4829</guid>

					<description><![CDATA[<p>L&#8217;un des avantages de Constellation est qu&#8217;il est très facile de faire « parler » des objets/systèmes entre eux. Dans ce tutoriel, nous allons lier notre lampe du bureau à notre session Windows. L&#8217;idée est très simple : lorsque vous déverrouillez (ou ouvrez) votre</p>
<p>The post <a rel="nofollow" href="https://developer.myconstellation.io/tutorials/synchroniser-lampe-bureau-avec-session-windows/">Synchroniser la lampe du bureau avec sa session Windows</a> appeared first on <a rel="nofollow" href="https://developer.myconstellation.io">Constellation</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>L&rsquo;un des avantages de Constellation est qu&rsquo;il est très facile de faire « parler » des objets/systèmes entre eux. Dans ce tutoriel, nous allons lier notre lampe du bureau à notre session Windows.</p>
<p>L&rsquo;idée est très simple : lorsque vous déverrouillez (ou ouvrez) votre session Windows on allumera automatiquement la lampe du bureau et lorsque vous verrouillez (ou fermez) votre session, la lampe s&rsquo;éteindra automatiquement.</p>
<p align="center"><img loading="lazy" class="aligncenter wp-image-4833 size-full colorbox-4829" title="Demo" src="https://developer.myconstellation.io/wp-content/uploads/2017/05/WindowsControl-gap.jpg" data-gif="https://developer.myconstellation.io/wp-content/uploads/2017/05/WindowsControl.gif" alt="Demo" width="450" height="253" /></p>
<p>On peut même aller plus loin si vous avez un capteur de luminosité connecté pour n&rsquo;allumer la lampe que lorsqu&rsquo;il fait trop sombre.</p>
<h3>Prérequis</h3>
<ul>
<li>Un serveur Constellation</li>
<li>Une lampe pilotable par Constellation</li>
<li>Le package <a href="/package-library/windowscontrol/">WindowsControl</a> déployé sur la sentinelle de l&rsquo;ordinateur Windows à synchroniser avec la lampe</li>
<li>Optionnellement un capteur de luminosité connecté dans Constellation</li>
<li>Le SDK Constellation pour Visual Studio</li>
</ul>
<h3>Etape 1 : piloter une lampe par Constellation</h3>
<p>Bien entendu il faut d&rsquo;abord pouvoir piloter une lampe par Constellation pour réaliser ce tutoriel !</p>
<p>Vous pouvez par exemple piloter un relais depuis un Raspberry en créant un package Python ou bien depuis un Arduino ou un ESP8266 comme vu <a href="/tutorials/creer-un-relais-connecte/">dans ce tutoriel</a>. Il suffit de créer une fonction pilotant un relais (simple manipulation d&rsquo;une sortie digitale) et d&rsquo;exposer cette fonction comme <a href="/concepts/messaging-message-scope-messagecallback-saga/">MessageCallback</a>. On pourra ainsi invoquer votre méthode pour ouvrir et fermer le relais et donc piloter une lampe depuis n&rsquo;importe quel système connecté dans votre Constellation.</p>
<p align="center"><img loading="lazy" class="alignnone size-full wp-image-4599 colorbox-4829" src="https://developer.myconstellation.io/wp-content/uploads/2017/05/image_thumb-58.png" alt="" width="350" height="198" srcset="https://developer.myconstellation.io/wp-content/uploads/2017/05/image_thumb-58.png 454w, https://developer.myconstellation.io/wp-content/uploads/2017/05/image_thumb-58-300x170.png 300w" sizes="(max-width: 350px) 100vw, 350px" /></p>
<p>Autre solution utiliser une carte de relais connectée par USB qu&rsquo;on pilotera avec le package <a href="/package-library/relayboard/">RelayBoard</a>. Ce package expose des MC permettant d&rsquo;ouvrir ou fermer les relais et publie l&rsquo;état de chacun d&rsquo;entre eux comme StateObject. Il ne reste plus qu&rsquo;à connecter une lampe sur l&rsquo;un des relais.</p>
<p align="center"><img loading="lazy" class="alignnone size-full wp-image-3530 colorbox-4829" title="RelayBoard" src="https://developer.myconstellation.io/wp-content/uploads/2016/10/image-143.png" alt="RelayBoard" width="176" height="180" /></p>
<p>On peut aussi utiliser des prises Wifi Belkin Wemo qu&rsquo;on connectera à Constellation avec le package <a href="/package-library/wemo/">Wemo</a>. Encore une fois ce package expose des MC permettant d&rsquo;allumer ou d’éteindre la charge connectée dessus et publie son état en tant que StateObject. Il suffit d&rsquo;y brancher une lampe !</p>
<p align="center"><img class="colorbox-4829"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border: 0px;" title="Prise Wemo Insight" src="https://developer.myconstellation.io/wp-content/uploads/2017/05/wemo.jpg" alt="Prise Wemo Insight" width="200" height="200" border="0" /></p>
<p>Dans la même idée, on peut utiliser des prises Somfy qu&rsquo;on connectera à Constellation avec le package <a href="/package-library/rfxcom/">RFXCOM </a>nécessitant une passerelle RFXcom connectée en USB. Le package expose un MessageCallback permettant d&rsquo;envoyer des ordres par radiofréquences aux équipements RTS (protocole Somfy) pour piloter par exemple des prises. Il n&rsquo;y a pas de retour d&rsquo;état sur ce protocole, donc il ne sera pas possible de récupérer son état mais on pourra allumer ou éteindre la prise et donc une lampe !</p>
<p align="center"><img class="colorbox-4829"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border: 0px;" title="Prise Somfy" src="https://developer.myconstellation.io/wp-content/uploads/2017/05/prise-telecommandee-interieure-variateur-100-w-rts-2401092-somfy.jpg" alt="Prise Somfy" width="200" height="200" border="0" /></p>
<p>Encore une autre possibilité, utiliser des prises ou des modules Z-Wave. Il faut pour cela un contrôleur Z-Wave qu&rsquo;on connectera à Constellation. Vous pouvez soit utiliser le package <a href="/package-library/jeedom/">Jeedom </a>ou soit le package <a href="/package-library/vera/">Vera</a>.</p>
<p align="center"><img class="colorbox-4829"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border: 0px;" title="Prise Z-Wave AN158" src="https://developer.myconstellation.io/wp-content/uploads/2017/05/an158.jpg" alt="Prise Z-Wave AN158" width="200" height="200" border="0" /></p>
<p>On pourrait également utiliser des lampes ou des ampoules connectées de la gamme Phillips Hue qu&rsquo;on connectera à Constellation grâce au package <a href="/package-library/hue/">Hue</a>.</p>
<p style="text-align: center;"><img loading="lazy" class="alignnone size-full wp-image-3598 colorbox-4829" src="https://developer.myconstellation.io/wp-content/uploads/2016/10/image-166.png" alt="" width="350" height="175" srcset="https://developer.myconstellation.io/wp-content/uploads/2016/10/image-166.png 350w, https://developer.myconstellation.io/wp-content/uploads/2016/10/image-166-300x150.png 300w" sizes="(max-width: 350px) 100vw, 350px" /></p>
<p>Pour ma part la lampe de mon bureau est contrôlée par une prise Z-Wave AN158 appairée sur une Vera Lite. Ce contrôleur Z-Wave est connecté à Constellation grâce au package <a href="/package-library/vera/">Vera</a>.</p>
<p>J&rsquo;ai donc dans ma Constellation des StateObjets pour chaque périphérique Z-Wave et des MessageCallbacks pour envoyer des ordres Z-Wave. Par exemple depuis le <a href="/constellation-platform/constellation-console/messagecallbacks-explorer/">MessageCallbacks Explorer</a>, on retrouve le MC « <em>SetSwitchState</em> » permettant de définir l&rsquo;état d&rsquo;un switch (On/Off) Z-Wave.</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2017/05/image-85.png"><img class="colorbox-4829"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border: 0px;" title="MessageCallbacks Explorer" src="https://developer.myconstellation.io/wp-content/uploads/2017/05/image_thumb-85.png" alt="MessageCallbacks Explorer" width="454" height="169" border="0" /></a></p>
<p style="text-align: left;" align="center">Depuis l&rsquo;API.net il me suffit d&rsquo;invoquer le code suivant pour allumer le device #42 :</p>
<p></p><pre class="crayon-plain-tag">PackageHost.CreateMessageProxy("Vera").SetSwitchState(new { DeviceID = 42, State = true });</pre><p></p>
<p>Vous pouvez appuyer sur le bouton <img loading="lazy" class="alignnone size-full wp-image-2961 colorbox-4829" src="https://developer.myconstellation.io/wp-content/uploads/2016/09/image_thumb-112.png" alt="" width="25" height="22" /> pour obtenir les exemples de code pour chaque MessageCallback. Par exemple toujours pour allumer le device Z-Wave #42 depuis un Arduino :</p>
<p></p><pre class="crayon-plain-tag">constellation.sendMessage(Package, "Vera", "SetSwitchState", "{ 'DeviceID':42, 'State':true }");</pre><p></p>
<p>Bref il existe différente méthode de piloter une lampe (ou n&rsquo;importe quelle charge) depuis Constellation, soit en mode DIY en créant vous-même votre package réel (C#, Python, &#8230;) ou virtuel (Arduino, ESP8266, Gadgeteer, &#8230;) ou bien en utilisant des technologies telles RTS de Somfy, le Z-Wave, les lampes et ampoules Philips, les prises Wifi de Belkin, etc&#8230; avec les packages déjà disponibles dans le <a href="/plateforme/package-repository/">catalogue en ligne</a>.</p>
<p>Et quand bien même il n&rsquo;existe pas de connecteur Constellation pour piloter votre lampe, libre à vous de créer votre propre package créant ainsi la passerelle, le connecteur entre Constellation et votre lampe.</p>
<h3>Etape 2 : connaitre l&rsquo;état de la session avec le package WindowsControl</h3>
<p>Maintenant que nous avons un MessageCallback pour piloter la lampe du bureau, faut-il encore savoir si la session est ouverte ou non.</p>
<p>Pour cela vous avez dans le catalogue en ligne, le package <a href="/package-library/windowscontrol/">WindowsControl</a> qui expose différent MessageCallbacks pour verrouiller ou fermer une session, pour arrêter ou redémarrer l&rsquo;ordinateur, pour contrôler le volume ou la luminosité (comme vu <a href="/tutorials/potentiometre-connecte-pour-controler-le-volume-ou-la-luminosite/">dans ce tutoriel</a>).</p>
<p>Ce package produit également un StateObject nommé « SessionLocked » de type booléen qui indique si la session est verrouillée (ou fermée) ou non.</p>
<p>Il suffit donc de <a href="/getting-started/telecharger-et-deployer-des-packages-sur-vos-sentinelles/">déployer ce package</a> depuis la <a href="/constellation-platform/constellation-console/package-repository/">Console Constellation</a> sur la sentinelle UI du PC à synchroniser avec votre lampe. On suivra ainsi ce StateObject pour savoir quel est l&rsquo;état de votre session et réagir tout changement d&rsquo;état.</p>
<h3>Etape 3 : synchroniser la lampe avec la session en C#</h3>
<p>Passons au chose sérieuse, nous avons d&rsquo;un côté un StateObject nous indiquant si la session est ouverte ou non et un MessageCallback nous permettant d&rsquo;allumer ou d&rsquo;éteindre la lampe du bureau, reste juste à créer le lien.</p>
<p>Pour cela nous allons <a href="/getting-started/creez-votre-premier-package-constellation-en-csharp/">créer un package .NET en C#</a> depuis Visual Studio.</p>
<p>Dans la classe principale (<em>Program</em>), nous allons ajouter un <a href="/client-api/net-package-api/consommer-des-stateobjects/">StateObjectLink</a>, c&rsquo;est à dire une propriété dans notre code liée au StateObject représentant l&rsquo;état de la session en ajoutant les lignes :</p>
<p></p><pre class="crayon-plain-tag">[StateObjectLink("WindowsControl", "SessionLocked")]
public StateObjectNotifier SessionLocked { get; set; }</pre><p></p>
<p>Prenez garde toutefois, si vous avez déployé le package WindowsControl sur plusieurs sentinelles de votre Constellation, le StateObjectLink ci-dessus sera lié à plusieurs StateObjects et non au StateObject de votre ordinateur à scruter. L’unicité d’un StateObject est obtenu par le triplet : “Sentinel + Package + Nom” car un nom de StateObject est unique pour une <a href="https://developer.myconstellation.io/concepts/instance-package-versioning-et-resolution/#Sentinel_Package_Instance_de_package">instance de package</a> (couple Sentinel / Package), de même qu’un package est unique pour une sentinelle et qu’une sentinelle est unique dans une Constellation.</p>
<p>De ce fait pour lier la propriété « <em>SessionLocked</em> » au StateObject « <em>SessionLocked</em> » de votre ordinateur on écrira :</p>
<p></p><pre class="crayon-plain-tag">[StateObjectLink("PC-SEB_UI", "WindowsControl", "SessionLocked")]
public StateObjectNotifier Session { get; set; }</pre><p></p>
<p>Dans l&rsquo;exemple ci-dessus, la machine est nommée « PC-SEB » et donc le nom de sa sentinelle « PC-SEB_UI » étant donné que le package WindowsControl est déployé sur la Sentinelle UI d&rsquo;où le suffixe « _UI » dans le nom de la sentinelle. Vous pouvez bien entendu vérifier le nom exacte de votre sentinelle sur la Console Constellation.</p>
<p>Maintenant que l&rsquo;état de la session de notre PC est synchronisé dans cette propriété .NET de notre code C#, nous allons ajouter un « handler » pour réagir au changement d&rsquo;état :</p>
<p></p><pre class="crayon-plain-tag">this.SessionLocked.ValueChanged += (s, e) =&gt;
{
    if ((bool)this.SessionLocked.DynamicValue)
    {
        PackageHost.WriteInfo("Verrouillage de la session : fermeture de la lampe");
    }
    else
    {
        PackageHost.WriteInfo("Session déverrouillée : allumage de la lampe");
    }
};</pre><p></p>
<p>Maintenant pour allumer la lumière, il suffit d&rsquo;envoyer un message pour déclencher le MessageCallback permettant de contrôler votre lampe. Comme expliqué ci-dessus, dans mon cas, la lampe sur mon bureau est contrôlée par une prise Z-Wave AN158 pilotable par le package Vera via le MessageCallback « <em>SetSwitchState</em>« .</p>
<p>On crée donc <a href="/client-api/net-package-api/envoyer-des-messages-invoquer-des-messagecallbacks/">un proxy dynamique vers le package</a> Vera et on invoque le MC comme on invoquerait une méthode .NET en passant en paramètre un objet contenant l&rsquo;ID du device Z-Wave et l&rsquo;état souhaité :</p>
<p></p><pre class="crayon-plain-tag">PackageHost.CreateMessageProxy("Vera").SetSwitchState(new { DeviceID = 42, State = true });</pre><p></p>
<p>Pour connaitre l&rsquo;ID du device Z-Wave on peut soit le rechercher dans le StateObjects Explorer et l&rsquo;écrire en dur dans notre code C#, ou soit ajouter un autre StateObjectLink afin de récupérer dynamiquement son Id (car contenu dans le StateObject du device).</p>
<p>Le code de notre package sera donc :</p>
<p></p><pre class="crayon-plain-tag">public class Program : PackageBase
{
    [StateObjectLink("Vera", "Lampe Bureau Seb")]
    public StateObjectNotifier LampeBureau { get; set; }

    [StateObjectLink("PC-SEB_UI", "WindowsControl", "SessionLocked")]
    public StateObjectNotifier SessionLocked { get; set; }

    static void Main(string[] args)
    {
        PackageHost.Start&lt;Program&gt;(args);
    }

    public override void OnStart()
    {
        this.SessionLocked.ValueChanged += (s, e) =&gt;
        {
            if ((bool)this.SessionLocked.DynamicValue)
            {
                PackageHost.WriteInfo("Verrouillage de la session : fermeture de la lampe");
                PackageHost.CreateMessageProxy("Vera").SetSwitchState(new { DeviceID = (int)this.LampeBureau.DynamicValue.Id, State = false });
            }
            else
            {
                PackageHost.WriteInfo("Session déverrouillée : allumage de la lampe");
                PackageHost.CreateMessageProxy("Vera").SetSwitchState(new { DeviceID = (int)this.LampeBureau.DynamicValue.Id, State = true });
            }
        };
    }
}</pre><p></p>
<p>On peut maintenant lancer notre package en mode « Debug On Constellation » pour le tester depuis Visual Studio tout en le connectant dans votre Constellation :</p>
<p><img loading="lazy" class="alignnone size-full wp-image-1675 aligncenter colorbox-4829" src="https://developer.myconstellation.io/wp-content/uploads/2016/03/image-196.png" alt="" width="104" height="34" /></p>
<p>Vous pouvez tester le fonctionnel de votre package : on verrouille la session, la lampe s&rsquo;éteint, on la déverrouille, la lampe s&rsquo;allume !</p>
<p>Une fois votre package testé et validé, vous pouvez <a href="/constellation-platform/constellation-sdk/publier-package-visual-studio/">le publier</a> dans votre Constellation et le déployer sur une de vos sentinelles (<a href="/getting-started/creez-votre-premier-package-constellation-en-csharp/#Publier_son_package_dans_Constellation">voir le guide</a>).</p>
<h3>Etape 4 : ajouter un capteur de luminosité</h3>
<p>Jusqu&rsquo;à présent dès que la session est déverrouillée la lampe du bureau s&rsquo;allume et dès qu&rsquo;on la ferme elle s’éteint. Seulement en pleine journée ce n&rsquo;est peut être pas très judicieux d&rsquo;allumer la lumière !</p>
<p>Pour cela nous pouvons ajouter une condition supplémentaire basée sur la luminosité ambiante.</p>
<p>On pourrait utiliser un capteur sans fil du marché comme le Chacon DIO54783 connecté via le package RFXcom ou bien un capteur Z-Wave via le package Vera ou Jeedom. On peut aussi concevoir son propre capteur avec un Arduino ou un ESP8266 <a href="/tutorials/creer-un-capteur-de-luminosite-dans-une-prise-220v/">comme vu dans ce tutoriel</a> ou avec un Raspberry Pi <a href="/tutorials/un-capteur-de-luminosite-exterieur-pilote-par-raspberry/">comme vu ici</a>.</p>
<p style="text-align: center;"><a href="/tutorials/creer-un-capteur-de-luminosite-dans-une-prise-220v/"><img loading="lazy" class="alignnone wp-image-4818 colorbox-4829" src="https://developer.myconstellation.io/wp-content/uploads/2017/05/image_thumb-84.png" alt="" width="351" height="312" srcset="https://developer.myconstellation.io/wp-content/uploads/2017/05/image_thumb-84.png 454w, https://developer.myconstellation.io/wp-content/uploads/2017/05/image_thumb-84-300x266.png 300w" sizes="(max-width: 351px) 100vw, 351px" /></a></p>
<p style="text-align: center;"><a href="/tutorials/un-capteur-de-luminosite-exterieur-pilote-par-raspberry/"><img loading="lazy" class="alignnone wp-image-4749 size-full colorbox-4829" src="https://developer.myconstellation.io/wp-content/uploads/2017/05/P1170883_thumb-1.jpg" alt="" width="354" height="227" srcset="https://developer.myconstellation.io/wp-content/uploads/2017/05/P1170883_thumb-1.jpg 354w, https://developer.myconstellation.io/wp-content/uploads/2017/05/P1170883_thumb-1-300x192.jpg 300w" sizes="(max-width: 354px) 100vw, 354px" /></a></p>
<p>Dans notre article, prenons par exemple l&rsquo;un des deux capteurs ci-dessus qui publient chacun un StateObject nommé « Lux » composé de 3 propriétés : Broadband, IR et Lux.</p>
<p>Pour intégrer cette « information » dans notre code C#, ajoutons un StateObjectLink vers le StateObject « Lux » :</p>
<p></p><pre class="crayon-plain-tag">[StateObjectLink("LightSensor", "Lux")]
public StateObjectNotifier LuxSensor { get; set; }</pre><p></p>
<p>On peut maintenant modifier la condition d&rsquo;allumage avec un « else if » qui vérifiera que la luminosité est inférieure à un seuil qu&rsquo;on <a href="/client-api/net-package-api/settings/">va déclarer dans les settings</a> Constellation de façon à pouvoir modifier cette valeur à la volée depuis la Console Constellation :</p>
<p></p><pre class="crayon-plain-tag">else if (this.LuxSensor.DynamicValue.Lux &lt; PackageHost.GetSettingValue&lt;int&gt;("DaylightThreshold"))</pre><p></p>
<p>Bien entendu comme tout setting, il est vivement recommandé de le déclarer dans le <a href="/concepts/package-manifest/">manifeste du package</a> (le fichier <em>PackageInfo.xml</em>). De plus on pourra y définir la valeur par défaut ici fixée à 50 (lux) :</p>
<p></p><pre class="crayon-plain-tag">&lt;Settings&gt;
  &lt;Setting name="DaylightThreshold" type="Int32" defaultValue="50" description="Seuil de luminosité minimale pour l'allumage de la lampe du bureau" /&gt;
&lt;/Settings&gt;</pre><p></p>
<p>Pour finir, prenons le cas où la session est déjà déverrouillée et la soirée arrivant, la luminosité passe en dessous du seuil : il faut alors allumer la lumière bien que l&rsquo;état de la session n&rsquo;a pas changé !</p>
<p>Pour cela nous allons ajouter un « handler » pour réagir à chaque mise à jour du StateObject « Lux » du capteur de luminosité. A chaque nouvelle mesure, si la valeur est inférieure au seuil défini dans les settings et que la session est bien déverrouillée, on allumera la lumière :</p>
<p></p><pre class="crayon-plain-tag">this.LuxSensor.ValueChanged += (s, e) =&gt;
{
    if (e.NewState.DynamicValue.Lux &lt; PackageHost.GetSettingValue&lt;int&gt;("DaylightThreshold") &amp;&amp; (bool) this.SessionLocked.DynamicValue == false)
    {
        PackageHost.WriteInfo("Session déverrouillée à la tombée de la nuit : allumage de la lampe");
        PackageHost.CreateMessageProxy("Vera").SetSwitchState(new { DeviceID = (int)this.LampeBureau.DynamicValue.Id, State = true });
    }
};</pre><p></p>
<p>Ainsi notre lumière de bureau est maintenant synchronisée à notre session et ne s&rsquo;allumera que si la luminosité est faible. Elle sera donc éteinte dès qu&rsquo;on ferme ou verrouille la session et s&rsquo;allumera si la luminosité baisse sous le seuil défini dans les settings alors que la session est déjà déverrouillée ou vient d&rsquo;être déverrouillée.</p>
<h3>Etape 5 : fermer la lampe en cas de déconnexion du PC</h3>
<p>Pour vraiment aller au fond des choses il y a encore un cas à gérer : que faire si le PC s’arrête proprement ou brutalement. En somme l&rsquo;idée est de fermer la lampe si le PC est déconnecté de Constellation, que ce soit suite à un arrêt de l&rsquo;ordinateur, un crash, une déconnexion quelconque, etc..</p>
<p>Pour savoir si le PC est bien connecté on va surveiller l&rsquo;état de la sentinelle UI de votre PC. Pour cela il faut se connecter sur le hub de contrôle.</p>
<p>L&rsquo;utilisation du hub de contrôle depuis un package C# est expliqué en détail <a href="/client-api/net-package-api/controlmanager/">dans cet article </a>que je vous recommande de lire.</p>
<p>La première étape consiste donc à déclarer dans le <a href="/concepts/package-manifest/">manifeste du package</a> (le fichier <em>PackageInfo.xml</em>) l&rsquo;utilisation du hub de contrôle par votre package en ajoutant l&rsquo;attribut suivant sur la balise <em>Package</em> :</p>
<p></p><pre class="crayon-plain-tag">EnableControlHub="true"</pre><p></p>
<p>De plus il faut également, sur votre package, définir une <a href="/constellation-platform/constellation-console/gerer-credentials-avec-la-console-constellation/">clé d&rsquo;accès ayant les droits d&rsquo;accès au hub de contrôle</a>. Vous pouvez vérifier la bonne connexion au hub de contrôle dans votre code par la propriété : « <em>PackageHost.HasControlManager</em>« .</p>
<p>Une fois connecté au hub de contrôle on va demander à recevoir les mises à jour des statuts des sentinelles de notre Constellation par la ligne :</p>
<p></p><pre class="crayon-plain-tag">PackageHost.ControlManager.RequestSentinelUpdates();</pre><p></p>
<p>Cela nous permet ensuite d&rsquo;attacher un « handler » qu&rsquo;on filtrera sur notre sentinelle (ici nommée « PC-SEB_UI »). On stockera dans la variable « pcConnected » un booléen indiquant si la sentinelle de notre PC est connectée ou non. Si notre sentinelle n&rsquo;est pas/plus connectée, on fermera immédiatement la lampe du bureau.</p>
<p></p><pre class="crayon-plain-tag">PackageHost.ControlManager.SentinelUpdated += (s, e) =&gt;
{
    if (e.Sentinel.Description.SentinelName == "PC-SEB_UI")
    {
        this.pcConnected = e.Sentinel.IsConnected;
        PackageHost.WriteInfo("Le PC de Seb est '{0}'", e.Sentinel.IsConnected ? "connecté" : "déconnecté");
        if (!this.pcConnected)
        {
            // Éteindre la lampe si le PC est déconnecté !
            PackageHost.CreateMessageProxy("Vera").SetSwitchState(new { DeviceID = (int)this.LampeBureau.DynamicValue.Id, State = false });
        }
    }
};</pre><p></p>
<p>De plus, dans la condition d&rsquo;allumage, on rajoutera le fait de vérifier que le PC est bien connecté avant de prendre la décision d&rsquo;allumer la lampe :</p>
<p></p><pre class="crayon-plain-tag">else if (this.pcConnected &amp;&amp; this.LuxSensor.DynamicValue.Lux &lt; PackageHost.GetSettingValue&lt;int&gt;("DaylightThreshold"))</pre><p></p>
<p>Et voilà, notre package est opérationnel ! La lampe est parfaitement synchronisée avec l&rsquo;état de notre session Windows en tenant compte de la luminosité ambiante et des différents cas de figure pouvant apparaître, comme le redémarrage, l’arrêt ou le crash de notre PC !</p>
<p>Le code final est :</p>
<p></p><pre class="crayon-plain-tag">public class Program : PackageBase
{
    // Nom de la sentinelle Windows à syncrhoniser avec la lampe
    private const string SEB_PC_SENTINEL_NAME = "PC-SEB_UI";
    
    // PC Connecté? oui ou non !
    private bool pcConnected = false;

    // Lien vers le SO de la lampe du bureau
    [StateObjectLink("Vera", "Lampe Bureau Seb")]
    public StateObjectNotifier LampeBureau { get; set; }

    // Lien vers l'état de la session Windows
    [StateObjectLink(SEB_PC_SENTINEL_NAME, "WindowsControl", "SessionLocked")]
    public StateObjectNotifier SessionLocked { get; set; }

    // Lien vers le capteur de luminosité
    [StateObjectLink("LightSensor", "Lux")]
    public StateObjectNotifier LuxSensor { get; set; }

    // Démarrage du package
    static void Main(string[] args)
    {
        PackageHost.Start&lt;Program&gt;(args);
    }

    // Méthode de démarrage de notre package
    public override void OnStart()
    {
        // Si accès au ControlHub
        if (PackageHost.HasControlManager)
        {
            // Demande de reception des mise à jour des sentinelles
            PackageHost.ControlManager.RequestSentinelUpdates();
            // En cas de mise à jour de l'état d'une sentinelle
            PackageHost.ControlManager.SentinelUpdated += (s, e) =&gt;
            {
                // Si cela concerne notre sentinelle
                if (e.Sentinel.Description.SentinelName == SEB_PC_SENTINEL_NAME)
                {
                    // On stocke dans la variable "pcConnected" l'état connecté ou déconnecté de notre PC
                    this.pcConnected = e.Sentinel.IsConnected;
                    PackageHost.WriteInfo("Le PC de Seb est '{0}'", e.Sentinel.IsConnected ? "connecté" : "déconnecté");
                    // Si le PC est maintenant déconnecté, on ferme la lampe !
                    if (!this.pcConnected)
                    {
                        SetLight(false);
                    }
                }
            };
        }
        else
        {
            // Pas d'accès au COntrolHub, on log une erreur ! Vérifiez votre clé d'accès !
            PackageHost.WriteError("Accès au ControlHub impossible !");
        }

        // En cas de mise à jour du StateObject "Lux" du package "LightSensor"
        this.LuxSensor.ValueChanged += (s, e) =&gt;
        {
            // Si le PC est connecté, que la luminosité actuelle est inférieure au seuil défini dans les settings et que la session est bien dévérouillée
            if (this.pcConnected &amp;&amp; e.NewState.DynamicValue.Lux &lt; PackageHost.GetSettingValue&lt;int&gt;("DaylightThreshold") &amp;&amp; (bool) this.SessionLocked.DynamicValue == false)
            {
                // On allume la lampe !
                SetLight(true);
                PackageHost.WriteInfo("Session dévérouillée à la tombée de la nuit : allumage de la lampe");
            }
        };

        // En cas de mise à jour du StateObject "SessionLocked" du package "WindowsControl"
        this.SessionLocked.ValueChanged += (s, e) =&gt;
        {
            // Si la session est vérouillée (ou fermée)
            if ((bool)this.SessionLocked.DynamicValue)
            {
                // On eteint la lampe
                SetLight(false);
                PackageHost.WriteInfo("Verrouillage de la session : fermeture de la lampe");
            }
            // Si le PC est connecté, que la luminosité actuelle est inférieure au seuil défini dans les settings et que la session est donc dévérouillée
            else if (this.pcConnected &amp;&amp; this.LuxSensor.DynamicValue.Lux &lt; PackageHost.GetSettingValue&lt;int&gt;("DaylightThreshold"))
            {
                // On allume la lampe !
                SetLight(true);
                PackageHost.WriteInfo("Session déverrouillée avec luminosité faible : allumage de la lampe");
            }
        };
    }

    private void SetLight(bool state)
    {
        // Pour allumer la lumière, on invoque le MC "SetSwitchState" du package "Vera" en passant l'ID de la lampe (récupérée par son StateObjet)
        PackageHost.CreateMessageProxy("Vera").SetSwitchState(new { DeviceID = (int)this.LampeBureau.DynamicValue.Id, State = state });
    }
}</pre><p></p>
<p>The post <a rel="nofollow" href="https://developer.myconstellation.io/tutorials/synchroniser-lampe-bureau-avec-session-windows/">Synchroniser la lampe du bureau avec sa session Windows</a> appeared first on <a rel="nofollow" href="https://developer.myconstellation.io">Constellation</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://developer.myconstellation.io/tutorials/synchroniser-lampe-bureau-avec-session-windows/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<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[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>
		<category><![CDATA[Subscribe]]></category>
		<category><![CDATA[SendMessage]]></category>
		<category><![CDATA[Arduino]]></category>
		<category><![CDATA[PushStateObject]]></category>
		<category><![CDATA[ESP8266]]></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>Consommer des StateObjects depuis l&#8217;API Python</title>
		<link>https://developer.myconstellation.io/client-api/python-api/consommer-des-stateobjects-en-python/</link>
					<comments>https://developer.myconstellation.io/client-api/python-api/consommer-des-stateobjects-en-python/#respond</comments>
		
		<dc:creator><![CDATA[Sebastien Warin]]></dc:creator>
		<pubDate>Wed, 24 Aug 2016 09:46:27 +0000</pubDate>
				<category><![CDATA[Python API]]></category>
		<category><![CDATA[StateObjectLink]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[StateObject]]></category>
		<guid isPermaLink="false">https://developer.myconstellation.io/?p=2507</guid>

					<description><![CDATA[<p>Pour consommer des StateObjects vous pouvez simplement déclarer une méthode acceptant en paramètre un StateObject et rajouter sur cette méthode le décorateur “Constellation.StateObjectLink” en spécifiant le lien vers le ou les StateObjects. Par exemple si vous voulez récupérer en temps</p>
<p>The post <a rel="nofollow" href="https://developer.myconstellation.io/client-api/python-api/consommer-des-stateobjects-en-python/">Consommer des StateObjects depuis l&rsquo;API Python</a> appeared first on <a rel="nofollow" href="https://developer.myconstellation.io">Constellation</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Pour consommer des StateObjects vous pouvez simplement déclarer une méthode acceptant en paramètre un StateObject et rajouter sur cette méthode le décorateur “<em>Constellation.StateObjectLink</em>” en spécifiant le lien vers le ou les StateObjects.</p>
<p>Par exemple si vous voulez récupérer en temps réel le StateObject correspondant à un thermostat Nest (partant de l’hypothèse où le package Nest est déployé dans votre Constellation).</p>
<p>Via le StateObjects Explorer de la Console Constellation, on retrouvera le StateObject ici nommé “Living Room” publié par le package Nest qui représente l’état du thermostat du salon :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/08/image-76.png"><img class="colorbox-2507"  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-65.png" alt="image" width="350" height="200" border="0" /></a></p>
<p>On peut donc écrire une méthode qui sera liée à ce StateObject pour afficher un message de log à chaque fois que l’état du thermostat sera mis à jour :</p>
<p></p><pre class="crayon-plain-tag">@Constellation.StateObjectLink(package = "Nest", name = "Living Room")
def OnNestTargetTemperatureChanged(stateObject):
    Constellation.WriteInfo("The Nest target temperature has changed to : %s°C" % stateObject.Value.target_temperature_c)</pre><p></p>
<p>Le décorateur “StateObjectLink” accepte les paramètres suivants : “sentinel”, “package”, “name” et “type”. Tous ces paramètres sont optionnels et par défaut défini à “*”, c’est à dire qu’aucun filtre n’est appliqué !</p>
<p>Une méthode décorée “StateObjectLink” doit accepter qu’un seul argument : le StateObject.</p>
<p>Un StateObject contient les propriétés suivantes :</p>
<ul>
<li><u>SentinelName</u> : nom de la sentinelle qui a produit le StateObject</li>
<li><u>PackageName</u> : nom du package qui a produit le StateObject</li>
<li><u>Name</u> : le nom du StateObject</li>
<li><u>UniqueId</u> : identifiant unique du StateObject dans la Constellation (concaténation des 3 propriétés ci-dessus)</li>
<li><u>Type</u> : type du StateObject</li>
<li><u>Lifetime</u> : durée de vie en seconde du StateObject avant d’être considéré “expiré” (0 si infini)</li>
<li><u>LastUpdate</u> : date de la dernière publication du StateObject</li>
<li><u>IsExpired</u> : indique si le StateObject est expiré (c’est à dire que DateTime.Now &gt;  LastUpdate  + Lifetime si et seulement si Lifetime &gt; 0)</li>
<li><u>Metadatas</u> : dictionnaire de clé / valeur</li>
<li><u>Value</u> : la valeur du StateObject (peut être un type simple ou un objet complexe)</li>
</ul>
<p><span style="text-decoration: underline;">Important</span> : la méthode sur laquelle est appliquée cet attribut sera invoquée au démarrage de votre package avec la valeur actuelle du ou des StateObjects (<em>Request</em>) puis à chaque mise à jour des StateObjects (<em>Subscribe</em>).</p>
<p>Autre exemple, affichons dans les logs de notre package Python la consommation des CPU de l’ensemble des sentinelles Windows connectées dans notre Constellation en utilisant le package HWMonitor :</p>
<p></p><pre class="crayon-plain-tag">@Constellation.StateObjectLink(package = "HWMonitor", name = "/intelcpu/0/load/0")
def CPUUpdated(stateobject):
    Constellation.WriteInfo("CPU on %s is currently %s %" % (stateobject.SentinelName, stateobject.Value.Value))</pre><p></p>
<p>Dans le cas où vous souhaiterez conserver la valeur de votre StateObject dans une variable de votre script Python pour pouvoir vous en servir dans d&rsquo;autre méthode, il suffit tout simplement d&rsquo;affecter le StateObject dans une variable globale depuis un StateObjectLink.</p>
<p>Reprenons l&rsquo;exemple du thermostat Nest ci-dessus. Commençons par déclarer cette variable globale au niveau de notre script :</p>
<p></p><pre class="crayon-plain-tag">global nestThermostat</pre><p></p>
<p>Puis ajoutons un StateObjectLink vers le StateObject du thermostat Nest pour mettre à jour notre variable globale :</p>
<p></p><pre class="crayon-plain-tag">@Constellation.StateObjectLink(package = "Nest", name = "Living Room")
def OnNestThermostatChanged(stateObject):
    global nestThermostat
    nestThermostat = stateObject.Value</pre><p></p>
<p>Ainsi la variable « <em>nestThermostat</em> » contiendra la dernière valeur du StateObject représentant le thermostat Nest. Vous pourrez y accéder depuis n&rsquo;importe quel endroit de votre script.</p>
<p>The post <a rel="nofollow" href="https://developer.myconstellation.io/client-api/python-api/consommer-des-stateobjects-en-python/">Consommer des StateObjects depuis l&rsquo;API 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/consommer-des-stateobjects-en-python/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Consommer des StateObjects</title>
		<link>https://developer.myconstellation.io/client-api/net-package-api/consommer-des-stateobjects/</link>
					<comments>https://developer.myconstellation.io/client-api/net-package-api/consommer-des-stateobjects/#respond</comments>
		
		<dc:creator><![CDATA[Sebastien Warin]]></dc:creator>
		<pubDate>Sun, 20 Mar 2016 14:18:48 +0000</pubDate>
				<category><![CDATA[.NET API]]></category>
		<category><![CDATA[StateObject]]></category>
		<category><![CDATA[StateObjectLink]]></category>
		<category><![CDATA[StateObjectNotifier]]></category>
		<category><![CDATA[StateObjectCollectionNotifier]]></category>
		<guid isPermaLink="false">https://developer.myconstellation.io/?p=1474</guid>

					<description><![CDATA[<p>Chaque package, virtuel ou non, peut publier des StateObjects dans votre Constellation. Découvrons dans cet article comment intégrer les valeurs de ces StateObjets dans votre code C#. La base : le Request &#38; Subscribe de StateObjects Le hub Constellation comporte deux méthodes</p>
<p>The post <a rel="nofollow" href="https://developer.myconstellation.io/client-api/net-package-api/consommer-des-stateobjects/">Consommer des StateObjects</a> appeared first on <a rel="nofollow" href="https://developer.myconstellation.io">Constellation</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Chaque package, virtuel ou non, peut <a href="/client-api/net-package-api/pushstateobject/">publier des StateObjects</a> dans votre Constellation. Découvrons dans cet article comment intégrer les valeurs de ces StateObjets dans votre code C#.</p>
<h3>La base : le Request &amp; Subscribe de StateObjects</h3>
<p>Le hub Constellation comporte deux méthodes :</p>
<ul>
<li>RequestStateObjects : permettant d’interroger « à un instant T »  des StateObjects de votre Constellation</li>
<li>SubscribeStateObjects : permettant de s&rsquo;abonner aux mises à jours des StateObjects de votre Constellation</li>
</ul>
<p>Ces deux méthodes acceptent jusqu’à 4 paramètres, tous optionnels :</p>
<p></p><pre class="crayon-plain-tag">string sentinel = "*", string package = "*", string name = "*", string type = "*"</pre><p></p>
<p>Vous devez définir le ou StateObjects que vous souhaitez récupérer (<em>Request</em>) ou suivre (<em>Subscribe</em>) en appliquant des filtres. Le wildcard “*” permet de tout sélectionner, c&rsquo;est à dire de ne pas filtrer.</p>
<p>Par exemple, pour récupérer tous les StateObjects du package “MonPackage” (et peut importe le nombre d’instance du package) :</p>
<p></p><pre class="crayon-plain-tag">PackageHost.RequestStateObjects(package: "MonPackage");</pre><p></p>
<p>Si vous souhaitez tous les StateObjects du package “MonPackage” qui tourne sur une sentinelle en particulier, nommée ci-dessous « MA-SENTINELLE » :</p>
<p></p><pre class="crayon-plain-tag">PackageHost.RequestStateObjects(sentinel:"MA-SENTINELLE", package: "MonPackage");</pre><p></p>
<p>Pour cibler un StateObject en participer sur une instance d&rsquo;un package :</p>
<p></p><pre class="crayon-plain-tag">PackageHost.RequestStateObjects(sentinel: "MA-SENTINELLE", package: "MonPackage", name:"MonStateObject");</pre><p></p>
<p>Bien entendu, vous pouvez définir la combinaison que vous souhaitez !</p>
<p>Par exemple, récupérons tous les StateObjects de type “HWMonitor.HardwareList” dans notre Constellation :</p>
<p></p><pre class="crayon-plain-tag">PackageHost.RequestStateObjects(type: "HWMonitor.HardwareList");</pre><p></p>
<p>Comme on sait que ce type de StateObject ne peut être publié que par le package “HWMonitor”, on pourrait écrire :</p>
<p></p><pre class="crayon-plain-tag">PackageHost.RequestStateObjects(package: "HWMonitor", type: "HWMonitor.HardwareList");</pre><p></p>
<p>Dans les deux cas (<em>Request</em> ou <em>Subscribe</em>) les StateObjects sont reçus un par un par l’événement .NET : “PackageHost.StateObjectUpdated”.</p>
<p>Par exemple, déployons le package”<a href="/getting-started/telecharger-et-deployer-des-packages-sur-vos-sentinelles/">HWMonitor</a>” et analysons le StateObject “Hardware” via le <a href="/constellation-platform/constellation-console/stateobjects-explorer/">StateObject Explorer</a> :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/03/image-133.png"><img class="colorbox-1474"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="Detail d'un StateObject dans la Console" src="https://developer.myconstellation.io/wp-content/uploads/2016/03/image_thumb-110.png" alt="Detail d'un StateObject dans la Console" width="424" height="466" border="0" /></a></p>
<p align="left">On retrouve un StateObject de type “HWMonitor.HardwareList” qui contient une liste du hardware de la machine.</p>
<p align="left">Dans notre package nous allons récupérer tous les StateObjects de type “HWMonitor.HardwareList” (donc autant de StateObjects que nous avons d’instance de ce package dans notre Constellation).</p>
<p align="left">On pourrait écrire :</p>
<p></p><pre class="crayon-plain-tag">PackageHost.StateObjectUpdated += (s, e) =&gt;
{
    PackageHost.WriteInfo("Hardware sur la machine {0}", e.StateObject.SentinelName);
    foreach (dynamic hw in e.StateObject.DynamicValue)
    {
        PackageHost.WriteInfo("{0} ({1})", hw.Name, hw.Identifier);
    }
};
PackageHost.RequestStateObjects(package: "HWMonitor", type: "HWMonitor.HardwareList");</pre><p></p>
<p>En testant notre package dans Constellation :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/03/image-134.png"><img class="colorbox-1474"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="Console log" src="https://developer.myconstellation.io/wp-content/uploads/2016/03/image_thumb-111.png" alt="Console log" width="424" height="92" border="0" /></a></p>
<p align="left">Notez qu&rsquo;ici nous avons utilisé la méthode « <em>RequestStateObjects</em> » c&rsquo;est à dire que nous récupérons tous les StateObjects du package HWMonitor (quelque soit la sentinelle) de type « HWMonitor.HardwareList » au moement de l&rsquo;invocation de la méthode.</p>
<p align="left">Allons un peu plus long en affichant en temps réel la consommation du CPU. Cette valeur est publiée dans le StateObject “/intelcpu/0/load/0” par le package HWMonitor.</p>
<p align="left">Pour suivre en temps réel la consommation du CPU des machines (sentinelles) sur lesquelles le package HWMonitor est déployé, on commence par s&rsquo;abonner à ce StateObject :</p>
<p></p><pre class="crayon-plain-tag">PackageHost.SubscribeStateObjects(package: "HWMonitor", name: "/intelcpu/0/load/0");</pre><p></p>
<p>Puis dans l’événement “<em>StateObjectUpdated</em>” il faudra différencier le traitement en fonction du StateObject reçu.</p>
<p>Le code final :</p>
<p></p><pre class="crayon-plain-tag">PackageHost.StateObjectUpdated += (s, e) =&gt;
{
    if (e.StateObject.Name == "Hardware")
    {
        PackageHost.WriteInfo("Hardware sur la machine {0}", e.StateObject.SentinelName);
        foreach (dynamic hw in e.StateObject.DynamicValue)
        {
            PackageHost.WriteInfo("{0} ({1})", hw.Name, hw.Identifier);
        }
    }
    else if (e.StateObject.Name == "/intelcpu/0/load/0")
    {
        PackageHost.WriteInfo("CPU de {0} = {1}%", e.StateObject.SentinelName, e.StateObject.DynamicValue.Value);
    }
};
PackageHost.RequestStateObjects(package: "HWMonitor", type: "HWMonitor.HardwareList");
PackageHost.SubscribeStateObjects(package: "HWMonitor", name: "/intelcpu/0/load/0");</pre><p></p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/03/image-135.png"><img class="colorbox-1474"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="Console log" src="https://developer.myconstellation.io/wp-content/uploads/2016/03/image_thumb-112.png" alt="Console log" width="424" height="116" border="0" /></a></p>
<p style="text-align: left;" align="center">Notez qu&rsquo;ici nous avons utilisé la méthode « <em>SubscribeStateObjects</em> » c&rsquo;est à dire que nous nous abonnons à tous les StateObjects nommés “/intelcpu/0/load/0” du package HWMonitor (quelque soit la sentinelle). C&rsquo;est un abonnement, donc à chaque modification des StateObjects respectant notre filtre, nous recevrons dans notre code les nouvelles valeurs des StateObjects.</p>
<p style="text-align: left;" align="center">Cependant, si les StateObjects changent peu fréquemment, nous n&rsquo;obtenons rien immédiatement. C&rsquo;est pourquoi il est parfois nécessaire de faire un <em>Request</em> suivi d&rsquo;un <em>Subscribe</em> pour obtenir la version actuelle du/des StateObject(s) et s&rsquo;abonner aux mises à jour futures.</p>
<h3>Les StateObjectLink</h3>
<p>Pour simplifier l’exploitation des StateObjects dans votre code, l&rsquo;API Constellation introduit la notion de “StateObjectLink”.</p>
<p>Avec l&rsquo;API.NET, il vous suffit simplement de déclarer une propriété .NET dans votre code que vous allez décorer avec l’attribut [<strong>StateObjectLink</strong>].</p>
<p>Votre propriété .NET peut être privée ou publique, d’instance ou statique. De plus le type de votre propriété .NET peut être :</p>
<ul>
<li>Un type de base</li>
<li>Un type complexe</li>
<li>Un dynamic</li>
<li>Un StateObject</li>
<li>Un StateObjectNotifier</li>
<li>Un StateObjectCollectionNotifier</li>
</ul>
<p>Par défaut seules les propriétés .NET <u>de l’instance de votre package</u> (IPackage) sont enregistrées. Si dans votre package vous instanciez des classes contenants des StateObjectsLink vous devez appeler la méthode “<em>PackageHost.RegisterStateObjectLinks</em>” en passant l’instance de votre classe pour l’enregistrement de ses StateObjectLinks (autrement les propriétés resteront nulles).</p>
<p></p><pre class="crayon-plain-tag">PackageHost.RegisterStateObjectLinks(monObjet);</pre><p></p>
<h4>Lier la valeur d&rsquo;un StateObject à une propriété NET</h4>
<p>Prenons l’exemple du StateObject “MyNumber” que vous avons <a href="/client-api/net-package-api/pushstateobject/">publié dans cet article</a> par la ligne :</p>
<p></p><pre class="crayon-plain-tag">PackageHost.PushStateObject("MyNumber", 123);</pre><p></p>
<p>Pour qu’un autre package puisse l’inclure dans son code, on peut simplement écrire :</p>
<p></p><pre class="crayon-plain-tag">[StateObjectLink(Name = "MyNumber")]
public int MyNumber { get; set; }</pre><p></p>
<p>Ici la propriété est de type “int” (car la valeur du StateObject est un int) et est liée à la valeur de ce StateObject.</p>
<p>Dès que le StateObject est mis à jour (<em>PushStateObject</em>) par le package qui la produit, votre propriété est également mise à jour de sorte que vous ayez toujours la dernière valeur du StateObject dans votre propriété.</p>
<p>Bien entendu la valeur du StateObject doit être compatible avec le type de la propriété liée (même type ou cast implicite possible), sinon la valeur du StateObject lié ne sera jamais affecté à votre propriété.</p>
<p>Vous pouvez également utiliser des types complexes. Par exemple prenons l’exemple déjà cité ci-dessus :</p>
<p></p><pre class="crayon-plain-tag">PackageHost.PushStateObject&lt;MyCustomObject&gt;("MyObject",  new MyCustomObject() { String = "test", Number = 123 });</pre><p></p>
<p>Pour créer le StateObjectLink depuis un autre package, on pourra écrire :</p>
<p></p><pre class="crayon-plain-tag">[StateObjectLink(Name = "MyObject")]
public MyCustomObject MyObject { get; set; }</pre><p></p>
<p>La propriété “MyObject” sera bien du type “MyCustomObject” et sera lié au StateObject nommé “MyObject”.</p>
<p>Cela sous entend que votre package ait la même définition du type “MyCustomObject” : soit en recopiant la classe ou soit en partageant une assembly commune. Notez toutefois que, comme Constellation connait la description des types utilisés par les StateObjects ou MessagesCallbacks, il est possible de générer le code (<a href="#Generer_du_code">lire ici</a>).</p>
<p>Maintenant si le StateObject est un type anonyme ou que vous n’avez pas la définition du type dans votre code, vous pouvez utiliser le type “dynamic”.</p>
<p>On pourrait alors écrire :</p>
<p></p><pre class="crayon-plain-tag">[StateObjectLink(Name = "MyObject")]
public dynamic MyObject { get; set; }</pre><p></p>
<p>Pour terminer reprenons notre StateObject “Hardware” publié par le package HWMonitor :</p>
<p></p><pre class="crayon-plain-tag">[StateObjectLink(Package = "HWMonitor", Type = "HWMonitor.HardwareList")]
private dynamic Hardware { get; set; }</pre><p></p>
<p>Et à tout moment dans votre code pour pourrez itérer sur cette liste :</p>
<p></p><pre class="crayon-plain-tag">foreach (dynamic hw in this.Hardware)
{
    PackageHost.WriteInfo("{0} ({1})", hw.Name, hw.Identifier);
}</pre><p></p>
<p>On pourrait reprendre également l’exemple du CPU mais nous aurions un problème : comment savoir quand le StateObject à été mis à jour pour afficher la nouvelle valeur ? C’est que nous verrons avec le <a href="#StateObjectNotifier_notification_de_mise_a_jour">StateObjectNotifier ci-dessous</a>.</p>
<h4>L’unicité des liens</h4>
<p>Dans les exemples ci-dessus, nous lions des propriétés .NET aux StateObjects de votre Constellation en utilisant seulement leurs noms (Name). Or comme vous le savez il peut y avoir, dans votre Constellation, plusieurs packages sur plusieurs sentinelles qui publient des StateObjects avec le même nom !</p>
<p>De ce fait, je peux par exemple écrire :</p>
<p></p><pre class="crayon-plain-tag">[StateObjectLink(Package = "MonPackage", Name = "MyObject")]
public dynamic MyObject { get; set; }</pre><p></p>
<p>Ici, je crée un lien entre cette propriété .NET et le<strong>s</strong> StateObjects nommés “MyObject” et publiés par le package “MonPackage”. Mais je ne sais pas combien d’instance du package “MonPackage” je trouverai dans ma Constellation (je pourrais déployer ce package sur toutes mes sentinelles).</p>
<p>L’unicité ne peut se faire qu&rsquo;avec le triplet : Nom de la sentinelle + Nom du package + Nom du StateObject.</p>
<p></p><pre class="crayon-plain-tag">[StateObjectLink(Sentinel = "MON-PC", Package = "MonPackage", Name = "MyObject")]
public dynamic MyObject { get; set; }</pre><p></p>
<p>Dans ce dernier cas j’ai la garantie de lier cette propriété .NET à un et un seul StateObject : celui nommé “MyObject” publié par le package “MonPackage” et déployé sur la sentinelle “MON-PC”.</p>
<p>Dans le cas où votre lien correspond à plusieurs StateObjects, chaque mise à jours de l’un d’entre eux est affectée à la propriété.</p>
<p>Ainsi si vous avez un package nommé “MonPackage” qui tourne sur deux sentinelles (disons “PC1” et “PC2”), votre propriété “MyObject” définie ci-dessous sera tantôt liée à la valeur du StateObject publié par le package sur PC1 tantôt sur l’instance de PC2.</p>
<p></p><pre class="crayon-plain-tag">[StateObjectLink(Package = "MonPackage", Name = "MyObject")]
public dynamic MyObject { get; set; }</pre><p></p>
<p>Soyez donc vigilant aux liens que vous créez, ou sinon utilisez les StateObject<strong>Collection</strong>Notifier comme nous le verrons <a href="#StateObjectCollectionNotifier_collection_de_StateObjectNotifier">dans la suite de cet article</a>.</p>
<h4>Lier le StateObject entier à une propriété .NET</h4>
<p>Jusqu’à présent nous avons lier des propriétés .NET avec <u>les valeurs</u> de StateObjects. Une fois la liaison établie, vous pouvez utiliser ces propriétés pour accéder à la valeur des StateObjects mais non au StateObject lui même.</p>
<p>Le StateObject contient à la fois la valeur du StateObject mais également les propriétés du StateObject comme son nom, le couple sentinelle/package qui l’a publié, sa date de publication, sa durée de vie (lifetime), son type ou encore des métadonnées (dictionnaire de string/object).</p>
<p>Pour cela, il suffit simplement de créer une propriété de type “StateObject”.</p>
<p>Par exemple pour le StateObject “Hardware” du package “HWMonitor” de la sentinelle “MON-PC” (pour n’avoir qu’une seule valeur), on peut écrire :</p>
<p></p><pre class="crayon-plain-tag">[StateObjectLink("MON-PC", "HWMonitor", "Hardware")]
private StateObject Hardware { get; set; }</pre><p></p>
<p>Vous aurez ensuite accès aux différentes propriétés de votre StateObject :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/03/image_thumb1.png"><img class="colorbox-1474"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="Un StateObject" src="https://developer.myconstellation.io/wp-content/uploads/2016/03/image_thumb1_thumb.png" alt="Un StateObject" width="424" height="272" border="0" /></a></p>
<p align="left">La valeur du StateObject peut être obtenue par la propriété “Value” ou “DynamicValue”.</p>
<p align="left">La propriété “DynamicValue” retourne la “Value” en tant qu’objet dynamique. Dans le cas d’un objet complexe, la “Value” sera de type JObject ou JArray.</p>
<p align="left">Il est donc conseillé de travailler directement avec la “DynamicValue” pour résoudre dynamiquement la valeur de votre StateObject.</p>
<p align="left">Vous disposez également d’une méthode GetValue&lt;T&gt; (ou son équivalent <em>TryGetValue</em>) qui se chargera de convertir votre valeur de StateObject en T .</p>
<h4>StateObjectNotifier : être notifié des mises à jour des StateObjects liés</h4>
<p>Jusqu’à présent nous lions des propriétés .NET avec la valeur d’un StateObject ou le StateObject lui même.</p>
<p>Dans les deux cas, vous pouvez accéder à tout moment à la dernière version de votre StateObject (ou sa valeur) publié dans votre Constellation car un <em>StateObjectLink</em> réalise implicitement un <em>RequestStateObjects</em> à l’initialisation de la propriété puis s’abonne aux StateObjects (<em>SubscribeStateObject</em>) pour mettre à jour en temps réel votre propriété dès que le ou les StateObjects liés sont mis à jour.</p>
<p>Seulement vous ne savez pas “quand” vos StateObject liés sont mis à jour, autrement dit quand est-ce que vos propriétés .NET sont mises à jour.</p>
<p>Pour cela il existe les <em>StateObjectNotifiers</em>. Le principe est simple, vous devez simplement créer une propriété liés de type StateObjectNotifier.</p>
<p>Reprenons le StateObject du CPU publié par le package HWMonitor sur “MON-PC” :</p>
<p></p><pre class="crayon-plain-tag">[StateObjectLink("MON-PC", "HWMonitor", "/intelcpu/0/load/0")]
private StateObjectNotifier CPU { get; set; }</pre><p></p>
<p>La classe StateObjectNotifier un container de StateObject. Elle comporte une propriété “Value” dans laquelle est contenu le StateObject.</p>
<p></p><pre class="crayon-plain-tag">StateObject stateObjectActuel = this.CPU.Value;</pre><p></p>
<p>On peut donc afficher la consommation à instant T :</p>
<p></p><pre class="crayon-plain-tag">PackageHost.WriteInfo("CPU = {0}%", this.CPU.Value.DynamicValue.Value);</pre><p></p>
<p>Pour détailler :</p>
<ul>
<li>this (l’instance courante)</li>
<li>.CPU (le StateObjectNofitier lié au StateObject de notre CPU)</li>
<li>.Value (l’objet StateObject en question)</li>
<li>.DynamicValue (la valeur du StateObject sous forme dynamique)</li>
<li>.Value (la propriété de l’objet publié par le package HWMonitor)</li>
</ul>
<p>Notez que le StateObjectNotifier comporte une propriété “DynamicValue” qui retourne la “DynamicValue” du StateObject (en clair : StateObjectNotifier.DynamicValue = StateObjectNotifier.Value.DynamicValue).</p>
<p>On peut donc simplifier  le code par :</p>
<p></p><pre class="crayon-plain-tag">PackageHost.WriteInfo("CPU = {0}%", this.CPU.DynamicValue.Value);</pre><p></p>
<p>Lorsque le (ou les) StateObjets liés sont mis à jour, l’instance du StateObjectNotifier reste inchangée, c’est seulement sa propriété Value qui est mis à jour. De ce fait il est possible de s’abonner à des événements sur un StateObjectNotifier.</p>
<p>A ce sujet, le StateObjectNotifier implémente l’interface bien connue en .NET et notamment dans le monde WPF : “<em>INotifyPropertyChanged</em>”.</p>
<p>De ce fait, un StateObjectNotifier comporte un événement “PropertyChanged” qui vous informera lorsque le StateObject change.</p>
<p></p><pre class="crayon-plain-tag">this.CPU.PropertyChanged += (s, e) =&gt;
{
    PackageHost.WriteInfo("Le StateObject a été mis à jour");
    PackageHost.WriteInfo("CPU = {0}%", this.CPU.DynamicValue.Value);
};</pre><p></p>
<p>Très pratique notamment pour rafraichir une interface graphique WPF (binding WPF).</p>
<p>De plus le <em>StateObjectNotifier </em>comporte un 2ème événement qui se déclenche lui aussi à la mise à jour du StateObject : le “<em>ValueChanged</em>”.</p>
<p>La différence avec le <em>PropertyChanged</em> réside dans l’EventArgs passé lorsque l’événement se déclenche :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/03/image_thumb5.png"><img class="colorbox-1474"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="ValueChanged d'un StateObjectNotifier" src="https://developer.myconstellation.io/wp-content/uploads/2016/03/image_thumb5_thumb.png" alt="ValueChanged d'un StateObjectNotifier" width="424" height="179" border="0" /></a></p>
<p align="left">Le “<em>StateObjectChangedEventArgs</em>” fourni trois propriétés :</p>
<ul>
<li>
<div align="left">NewState : la nouvelle version du StateObject</div>
</li>
<li>
<div align="left">OldState : l’ancienne version du StateObject</div>
</li>
<li>
<div align="left">IsNew : un booléen qui indique si c’est un “nouveau” StateObject (c’est à dire que OldState est null)</div>
</li>
</ul>
<p align="left">On peut donc comparer l’évolution du StateObject</p>
<p></p><pre class="crayon-plain-tag">this.CPU.ValueChanged += (s, e) =&gt;
{
    if (e.IsNew)
    {
         PackageHost.WriteInfo("CPU = {0}%", e.NewState.DynamicValue.Value);
    }
    else
    {
         double difference = (double)e.NewState.DynamicValue.Value - (double)e.OldState.DynamicValue.Value;
         PackageHost.WriteInfo("CPU = {0}% - TENDANDE: ", e.NewState.DynamicValue.Value, difference &gt; 0 ? "A LA HAUSSE" : "A LA BAISSE");
    }
};</pre><p></p>
<h4>StateObjectLink et Notifier personnalisés</h4>
<p>Notez que vous pouvez créer vos propres attributs “StateObjectLink” personnalisés en héritant de la classe “StateObjectLinkAttribute”.</p>
<p>De la même façon vous pouvez également créer vos propres StateObjectNotifier en créant simplement une classe qui hérite de “StateObjectNotifier”.</p>
<h4>StateObjectCollectionNotifier : collection de StateObjectNotifier</h4>
<p>Comme nous l’avons vu plus haut, si un StateObjectLink peut lier plusieurs StateObjects dans la même propriété .NET. Chaque mise à jour d’un des StateObjects “remplace” le précèdent !</p>
<p>Pour pouvoir lier plusieurs StateObjects dans une seule propriété .NET, nous pouvons utiliser les <em>StateObjectCollectionNotifiers</em>. La classe <em>StateObjectCollectionNotifier</em> est une <a href="https://msdn.microsoft.com/fr-fr/library/ms668604(v=vs.110).aspx">ObservableCollection</a> de StateObjectNotifier.</p>
<p>Prenons cet exemple :</p>
<p></p><pre class="crayon-plain-tag">[StateObjectLink("HWMonitor", "/intelcpu/0/load/0")]
public StateObjectCollectionNotifier CPUs { get; set; }</pre><p></p>
<p>Nous utilisons le constructeur du StateObjectLink où le 1er argument est le nom du package et le 2ème le nom du StateObject.</p>
<p>Pour faciliter la compréhension, on peut également utiliser les paramètres nommés :</p>
<p></p><pre class="crayon-plain-tag">[StateObjectLink(Package = "HWMonitor", Name = "/intelcpu/0/load/0")]
public StateObjectCollectionNotifier CPUs { get; set; }</pre><p></p>
<p>Nous créons donc un lien vers le StateObjects “/intelcpu/0/load/0” du package HWMonitor (celui qui correspond à la consommation du CPU).</p>
<p>On aura donc un StateObject par sentinelle où ce package est déployé.</p>
<p>Par exemple, dans ma Constellation on trouve 9 StateObjects qui correspond, un par machine (sentinelle) :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/03/image_thumb7.png"><img class="colorbox-1474"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="StateObject Explorer" src="https://developer.myconstellation.io/wp-content/uploads/2016/03/image_thumb7_thumb.png" alt="StateObject Explorer" width="424" height="251" border="0" /></a></p>
<p align="left">Comme il s’agit d’une collection de StateObjectNotifier, vous pouvez itérer pour chaque StateObject afin d’afficher par exemple le CPU de chaque sentinelle où le package “HWMonitor” est déployé :</p>
<p></p><pre class="crayon-plain-tag">foreach (StateObjectNotifier stateobject in this.CPUs)
{
     PackageHost.WriteInfo("CPU sur {0} = {1}%", stateobject.Value.SentinelName, stateobject.DynamicValue.Value);
}</pre><p></p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/03/image_thumb10.png"><img class="colorbox-1474"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="Console log" src="https://developer.myconstellation.io/wp-content/uploads/2016/03/image_thumb10_thumb.png" alt="Console log" width="424" height="104" border="0" /></a></p>
<p>Tout comme le StateObjectNotifier, la classe StateObjectCollectionNotifier comporte aussi l’évènement ValueChanged :</p>
<p></p><pre class="crayon-plain-tag">this.CPUs.ValueChanged += (s, e) =&gt;
{
     PackageHost.WriteInfo("CPU sur {0} = {1}%", e.NewState.SentinelName, e.NewState.DynamicValue.Value);
};</pre><p></p>
<h3>Générer du code</h3>
<p>Le principe est le même que <a href="/client-api/net-package-api/envoyer-des-messages-invoquer-des-messagecallbacks/#Generateur_de_code">la génération de code pour les MessageCallbacks</a>.</p>
<p>Ouvrez le générateur de code (clic-droit sur votre projet dans Visual Studio &gt; Constellation &gt; Generate Code) et sélectionnez votre Constellation puis cliquez sur “Discover”. Sélectionnez ensuite les packages que vous souhaitez ajouter dans votre code et cliquez sur “Generate”.</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/03/image-144.png"><img class="colorbox-1474"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="Générateur de code" src="https://developer.myconstellation.io/wp-content/uploads/2016/03/image_thumb-121.png" alt="Générateur de code" width="221" height="244" border="0" /></a></p>
<p align="left">Comme pour les MessageCallbacks, vous devez ajouter le namespace correspondant aux “StateObjects” du package que vous souhaitez manipuler.</p>
<p align="left">Par exemple pour inclure les StateObjects du package “MonPremierPackage” :</p>
<p></p><pre class="crayon-plain-tag">using ConstellationPackageConsole1.MonPremierPackage.StateObjects;</pre><p></p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/03/image-145.png"><img class="colorbox-1474"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="Using du code généré par package" src="https://developer.myconstellation.io/wp-content/uploads/2016/03/image_thumb-122.png" alt="Using du code généré par package" width="424" height="36" border="0" /></a></p>
<p align="left">Ensuite créez votre propriété .NET liée à un StateObject mais en utilisant le StateObjectLink généré par package.</p>
<p align="left">Exemple, pour les StateObjects du package “MonPremierPackage”, vous avez la classe “MonPremierPackageStateObjectLink”.</p>
<p align="left">Inutile de définir le “PackageName” sur ce StateObjectLink par il est nativement fixé par cet attribut personnalisé.</p>
<p align="left">Pour le nom du StateObject, vous pouvez utiliser l’énumération MonPremierPackageStateObjectNames générée par le générateur de code :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/03/image-146.png"><img class="colorbox-1474"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="StateObjectLink généré par package" src="https://developer.myconstellation.io/wp-content/uploads/2016/03/image_thumb-123.png" alt="StateObjectLink généré par package" width="424" height="65" border="0" /></a></p>
<p align="left">Par exemple, pour lier notre propriété “MonObject” au StateObject “MyObject” publié par le “MonPremierPackage” (<a href="/client-api/net-package-api/stateobjects/#Publiez_des_StateObjects">revoir l’exemple ici</a>), on peut écrire :</p>
<p></p><pre class="crayon-plain-tag">[MonPremierPackageStateObjectLink(MonPremierPackageStateObjectNames.MyObject)]
public StateObjectNotifier MonObject { get; set; }</pre><p></p>
<p align="left">Ensuite, sur chaque StateObject ou StateObjectNotifier, vous trouverez des méthodes d’extension permettant de convertir la valeur du StateObject dans le type généré dans votre code à partir de la description du package :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/03/image-147.png"><img class="colorbox-1474"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="Méthode d'extension générées sur les StateObject &amp; StateObjectLink" src="https://developer.myconstellation.io/wp-content/uploads/2016/03/image_thumb-124.png" alt="Méthode d'extension générées sur les StateObject &amp; StateObjectLink" width="424" height="214" border="0" /></a></p>
<p align="left">Par exemple, pour convertir votre StateObjectNotifier en “MyCustomObject”, le type du StateObject défini dans le package “MonPremierPackage” :</p>
<p></p><pre class="crayon-plain-tag">MyCustomObject myObject = this.MonObject.AsMonPremierPackageMyCustomObject();</pre><p></p>
<p align="left">Chaque type de StateObject décrit dans la Constellation est reproduit par le générateur de code dans votre projet.</p>
<p align="left">Vous retrouvez alors toutes les propriétés du StateObject proprement typées et documentées :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/03/image-148.png"><img class="colorbox-1474"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="Classes générées" src="https://developer.myconstellation.io/wp-content/uploads/2016/03/image_thumb-125.png" alt="Classes générées" width="424" height="86" border="0" /></a></p>
<p style="text-align: left;" align="center">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/consommer-des-stateobjects/">Consommer des StateObjects</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/consommer-des-stateobjects/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Créer des packages UI en Winform ou WPF</title>
		<link>https://developer.myconstellation.io/client-api/net-package-api/packages-ui-wpf-winform/</link>
					<comments>https://developer.myconstellation.io/client-api/net-package-api/packages-ui-wpf-winform/#respond</comments>
		
		<dc:creator><![CDATA[Sebastien Warin]]></dc:creator>
		<pubDate>Tue, 22 Mar 2016 16:12:30 +0000</pubDate>
				<category><![CDATA[.NET API]]></category>
		<category><![CDATA[Guide de démarrage]]></category>
		<category><![CDATA[Package]]></category>
		<category><![CDATA[MessageCallback]]></category>
		<category><![CDATA[StateObjectLink]]></category>
		<category><![CDATA[Sentinel UI]]></category>
		<category><![CDATA[WPF]]></category>
		<category><![CDATA[Winform]]></category>
		<category><![CDATA[UI]]></category>
		<category><![CDATA[XAML]]></category>
		<category><![CDATA[StateObject]]></category>
		<guid isPermaLink="false">https://developer.myconstellation.io/?p=1563</guid>

					<description><![CDATA[<p>Vous pouvez créer des applications graphiques et les déployer sur vos sentinelles UI grâce à Constellation. Chaque package UI pourra invoquer ou exposer des MessageCallbacks, consommer ou produire des StateObjects, etc… Hello World WPF Dans Visual Studio, vous créez un</p>
<p>The post <a rel="nofollow" href="https://developer.myconstellation.io/client-api/net-package-api/packages-ui-wpf-winform/">Créer des packages UI en Winform ou WPF</a> appeared first on <a rel="nofollow" href="https://developer.myconstellation.io">Constellation</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Vous pouvez créer des applications graphiques et les déployer sur vos sentinelles UI grâce à Constellation.</p>
<p>Chaque package UI pourra <a href="/client-api/net-package-api/envoyer-des-messages-invoquer-des-messagecallbacks/">invoquer</a> ou <a href="/client-api/net-package-api/messagecallbacks/">exposer</a> des MessageCallbacks, <a href="/client-api/net-package-api/consommer-des-stateobjects/">consommer</a> ou <a href="/client-api/net-package-api/stateobjects/">produire</a> des StateObjects, etc…</p>
<p><span id="more-1563"></span></p>
<h3>Hello World WPF</h3>
<p>Dans Visual Studio, vous créez un package WPF :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/03/image-153.png"><img class="colorbox-1563"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="Création d'un package UI" src="https://developer.myconstellation.io/wp-content/uploads/2016/03/image_thumb-130.png" alt="Création d'un package UI" width="424" height="294" border="0" /></a></p>
<p align="left">Le template est une application WPF classique :</p>
<p align="left"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/03/image-154.png"><img class="colorbox-1563"  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="Structure du package WPF" src="https://developer.myconstellation.io/wp-content/uploads/2016/03/image_thumb-131.png" alt="Structure du package WPF" width="244" height="204" border="0" /></a></p>
<p align="left">Le <em><a href="/client-api/net-package-api/les-bases-des-packages-net/#Fonctionnement_de_base">IPackage</a></em> de ce package est la classe “App” (App.xaml.cs). Ce package lance la fenêtre MainWindow au démarrage (méthode “OnStart”).</p>
<p align="left">La “MainWindow” est une Window WPF classique à l’exception que dans le constructeur, on enregistre automatiquement les <a href="/client-api/net-package-api/consommer-des-stateobjects/#StateObjectLink_et_Notifier_personnalises">[StateObjectLink]</a> et les <a href="/client-api/net-package-api/messagecallbacks/#Exposer_des_methodes">[MessageCallback]</a> de la classe. De plus on renvoie la description du package (dans le cas où vous avez ajoutez des MessageCallbacks).</p>
<p></p><pre class="crayon-plain-tag">public partial class MainWindow : Window
{
    public MainWindow()
    {
        PackageHost.RegisterStateObjectLinks(this);
        PackageHost.RegisterMessageCallbacks(this);
        PackageHost.DeclarePackageDescriptor();
        InitializeComponent();
    }

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        this.Title = string.Format("IsRunning: {0} - IsConnected: {1} - IsStandAlone: {2}", PackageHost.IsRunning, PackageHost.IsConnected, PackageHost.IsStandAlone);
        PackageHost.WriteInfo("I'm running !");
    }
}</pre><p></p>
<p align="left">Au chargement de la fenêtre on logge un message dans Constellation et on affiche quelques propriété sur l’état du package dans le titre de cette fenêtre !</p>
<p align="left">Ajoutons un simple label “Hello World” au centre de notre fenêtre :</p>
<p></p><pre class="crayon-plain-tag">&lt;Label x:Name="label" Content="Hello World" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="48"/&gt;</pre><p></p>
<p align="left">Le code XAML sera donc:</p>
<p></p><pre class="crayon-plain-tag">&lt;Window x:Class="MonPackageWPF.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525" Loaded="Window_Loaded"&gt;
    &lt;Grid&gt;
        &lt;Label x:Name="label" Content="Hello World" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="48"/&gt;
    &lt;/Grid&gt;
&lt;/Window&gt;</pre><p></p>
<p align="left">Pour tester notre package en debug sans être connecté à Constellation : “F5”</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/03/image-167.png"><img class="colorbox-1563"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="Debug du package en local" src="https://developer.myconstellation.io/wp-content/uploads/2016/03/image_thumb-144.png" alt="Debug du package en local" width="424" height="344" border="0" /></a></p>
<p align="left">Vous noterez que les <a href="/client-api/net-package-api/les-bases-des-packages-net/#Ecrire_des_logs">WriteLog</a> Constellation sont toujours afficher dans la fenêtre de sortie de Visual Studio.</p>
<p align="left">Maintenant pour lançons le debug de notre package dans Visual Studio tout en le connectant à Constellation (raccourci Ctrl+Alt+F8)</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/03/image-168.png"><img class="colorbox-1563"  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-145.png" alt="image" width="424" height="102" border="0" /></a></p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/03/image-169.png"><img class="colorbox-1563"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="Debug du package dans Constellation" src="https://developer.myconstellation.io/wp-content/uploads/2016/03/image_thumb-146.png" alt="Debug du package dans Constellation" width="424" height="228" border="0" /></a></p>
<h3 align="left">Invoquer des MessageCallbacks</h3>
<p align="left">Vous pouvez <a href="/client-api/net-package-api/envoyer-des-messages-invoquer-des-messagecallbacks/">invoquer</a> ou <a href="/client-api/net-package-api/messagecallbacks/">exposer</a> des MessageCallbacks comme n’importe quel package connecté dans votre Constellation.</p>
<p align="left">Pour <a href="/client-api/net-package-api/messagecallbacks/">exposer</a> des MessageCallbacks (des méthodes NET), il suffit d’ajouter l’attribut [MessageCallback] sur vos méthodes.</p>
<p align="left">Pour <a href="/client-api/net-package-api/envoyer-des-messages-invoquer-des-messagecallbacks/">invoquer</a> des MessageCallbacks, il faut créer un scope et envoyer le message. Grace au proxy dynamique, vous pouvez invoquer un MessageCallback comme vous invoquerez une méthode .NET.</p>
<p align="left">Dans cet exemple nous allons invoquer des MessageCallbacks des packages WindowsControl et GoogleTraffic. Vous pouvez <a href="/getting-started/telecharger-et-deployer-des-packages-sur-vos-sentinelles/">suivre le guide ici</a> pour déployer ces deux packages.</p>
<p align="left">En vous rendant sur la page “MessageCallbacks Explorer” de la Console, vous pouvez explorer les MC exposés par les packages.</p>
<p align="left">Par exemple, le package WindowsControl expose plusieurs MessageCallbacks pour arrêter, redémarrer, mettre en veille ou verrouiller l’ordinateur (= la sentinelle) sur lequel le package est déployé.</p>
<p align="left">Le package GoogleTraffic expose un MessageCallback “GetRoute” pour calculer le temps de route en spécifiant un point de départ et d’arrivée. Ce MessageCallback  est une saga pour vous retourner la réponse.</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/03/image-191.png"><img class="colorbox-1563"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="MessageCallbacks Explorer" src="https://developer.myconstellation.io/wp-content/uploads/2016/03/image_thumb-168.png" alt="MessageCallbacks Explorer" width="424" height="237" border="0" /></a></p>
<p align="left">Pour simplifier le développement et éviter de travailler avec des types dynamiques, nous allons auto-générer le code.</p>
<p align="left">Cliquez sur le bouton “Generate Code” :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/03/image-185.png"><img class="colorbox-1563"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="Génération de code" src="https://developer.myconstellation.io/wp-content/uploads/2016/03/image_thumb-162.png" alt="Génération de code" width="424" height="67" border="0" /></a></p>
<p align="left">Sélectionnez votre Constellation, cliquez sur “Discover” et sélectionnez les packages que vous souhaitez ajouter dans le code généré puis cliquez sur “Generate” :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/03/image-186.png"><img class="colorbox-1563"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="Génération de code" src="https://developer.myconstellation.io/wp-content/uploads/2016/03/image_thumb-163.png" alt="Génération de code" width="424" height="474" border="0" /></a></p>
<p align="left">Editez le code de la MainWindow (<em>MainWindow.xaml.cs</em>) pour ajouter le code généré des MessageCallbacks pour les packages GoogleTraffic et WindowsControl :</p>
<p></p><pre class="crayon-plain-tag">using MonPackageWPF.GoogleTraffic.MessageCallbacks;
using MonPackageWPF.WindowsControl.MessageCallbacks;</pre><p></p>
<p align="left">Dans la vue XAML, ajoutons deux boutons : l’un pour mettre en veille et l’autre pour faire un test d’itinéraire :</p>
<p></p><pre class="crayon-plain-tag">&lt;Button x:Name="btSleep" Content="Sleep !" HorizontalAlignment="Left" VerticalAlignment="Bottom" Margin="10" Width="75" Click="btSleep_Click"/&gt;
&lt;Button x:Name="btTestRoute" Content="Test Route" HorizontalAlignment="Center" VerticalAlignment="Bottom" Margin="10,0,0,10" Width="75" Click="btTestRoute_Click" /&gt;</pre><p></p>
<p align="left">Pour le premier bouton, nous allons sélectionner l’instance du package “WindowsControl” sur la sentinelle “PO_SEB” pour créer un scope afin d’invoquer le MessageCallback “Sleep” :</p>
<p></p><pre class="crayon-plain-tag">private void btSleep_Click(object sender, RoutedEventArgs e)
{
    MyConstellation.PackageInstances.PO_SEB_WindowsControl.CreateWindowsControlScope().Sleep();
}</pre><p></p>
<p align="left">Prenez garde à créer un scope sur une instance (sentinelle + package) car sinon, si vous créez un scope sur le package “WindowsControl”, toutes les sentinelles hébergeant ce package se mettront en veille !</p>
<p align="left">Pour le deuxième bouton, nous allons demander les différentes routes pour un “Lille-Paris”. Comme il s’agit d’une saga (message avec réponse) nous allons l’invoquer en “async/await” et afficher dans le label la meilleure route :</p>
<p></p><pre class="crayon-plain-tag">private async void btTestRoute_Click(object sender, RoutedEventArgs e)
{
    label.Content = "Calcul en cours ...";
    var route = await MyConstellation.Packages.GoogleTraffic.CreateGoogleTrafficScope().GetRoutes("lille", "paris");
    var bestRoute = route.OrderBy(r =&gt; r.TimeWithTraffic).FirstOrDefault();
    label.Content = $"{bestRoute.Name}\nDistance:{bestRoute.DistanceInKm}km\nTemps : {bestRoute.TimeWithTraffic}";
}</pre><p></p>
<p align="left">Lancer le debug dans Constellation : <img class="colorbox-1563"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="Debug On Constellation" src="https://developer.myconstellation.io/wp-content/uploads/2016/03/image-196.png" alt="Debug On Constellation" width="104" height="34" border="0" />  (ou Ctrl+Alt+F8).</p>
<p align="left">Premier test, en cliquant sur Sleep, vous allez envoyer un message pour invoquer le MessageCallback “Sleep” du package “WindowsControl” sur la sentinelle ici nommée “PO-SEB”. Ainsi le Windows “PO-SEB” se mettra instantanément en veille !</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/03/image-193.png"><img class="colorbox-1563"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="Test du MC &quot;Sleep&quot;" src="https://developer.myconstellation.io/wp-content/uploads/2016/03/image_thumb-170.png" alt="Test du MC &quot;Sleep&quot;" width="244" height="165" border="0" /></a></p>
<p align="left">Deuxième test, pour invoquer le MessageCallback “GetRoutes” du package GoogleTraffic :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/03/image-194.png"><img class="colorbox-1563"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="Test du MC &quot;GetRoutes&quot; en Async" src="https://developer.myconstellation.io/wp-content/uploads/2016/03/image_thumb-171.png" alt="Test du MC &quot;GetRoutes&quot; en Async" width="244" height="165" border="0" /></a><a href="https://developer.myconstellation.io/wp-content/uploads/2016/03/image-195.png"><img class="colorbox-1563"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="Réponse à la saga &quot;GetRoutes&quot;" src="https://developer.myconstellation.io/wp-content/uploads/2016/03/image_thumb-172.png" alt="Réponse à la saga &quot;GetRoutes&quot;" width="244" height="165" border="0" /></a></p>
<h3 align="left">Consommer des StateObjects dans votre vue XAML</h3>
<p align="left">Assurez-vous d’avoir dans votre Constellation au moins un package “HWMonitor” déployé sur une sentinelle. Au besoin, vous pouvez <a href="/getting-started/telecharger-et-deployer-des-packages-sur-vos-sentinelles/">suivre ce guide ici</a>.</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/03/image-197.png"><img class="colorbox-1563"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="HWMonitor" src="https://developer.myconstellation.io/wp-content/uploads/2016/03/image_thumb-173.png" alt="HWMonitor" width="424" height="223" border="0" /></a></p>
<p align="left">Pour comprendre en détail, la <a href="/client-api/net-package-api/consommer-des-stateobjects/">consommation des StateObjects</a> dans vos packages n’hésitez pas à relire <a href="/client-api/net-package-api/consommer-des-stateobjects/">cet article</a>.</p>
<p align="left">Par exemple, pour afficher en temps réel la consommation CPU (StateObject nommé “/intelcpu/0/load/0”) mesurée par le package HWMonitor sur sa sentinelle (ici “PO-SEB”), ajoutons un StateObjectLink :</p>
<p></p><pre class="crayon-plain-tag">[StateObjectLink("PO-SEB", "HWMonitor", "/intelcpu/0/load/0")]
public StateObjectNotifier CPU { get; set; }</pre><p></p>
<p align="left">Vous pouvez également générer du code en sélectionnant le package HWMonitor. Vous pourrez ensuite ajouter un “using” vers les StateObjects de ce package :</p>
<p></p><pre class="crayon-plain-tag">using MonPackageWPF.HWMonitor.StateObjects;</pre><p></p>
<p align="left">Cela vous permettra d’utiliser un le “HWMonitorStateObjectLink” avec des énumérations générées pour vos sentinelles et nom de StateObjects :</p>
<p></p><pre class="crayon-plain-tag">[HWMonitorStateObjectLink(MyConstellation.Sentinels.PO_SEB, HWMonitorStateObjectNames._intelcpu_0_load_0)]
public StateObjectNotifier CPU { get; set; }</pre><p></p>
<p align="left">Comme vous le savez, le StateObjectNotifier implémente l’interface INotifyPropertyChanged. Vous pouvez donc lier cette propriété dans votre vue XAML pour voir votre StateObject en temps réel sur votre interface.</p>
<p align="left">Nous allons modifier le label “Hello World” pour afficher en temps réel votre consommation CPU. Pour cela changeons le contenu (Content) du label avec la propriété “Value” du StateObject publié par le package HWMonitor.</p>
<p align="left">Cette propriété contient la valeur (ici de l’utilisation du CPU) avec un nombre décimal. Nous ajoutons également l’attribut “ContentStringFormat” pour n’afficher que 2 chiffres après la virgule.</p>
<p></p><pre class="crayon-plain-tag">&lt;Label x:Name="label" Content="{Binding Path=CPU.DynamicValue.Value}" ContentStringFormat="{}{0:N2}%" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="48"/&gt;</pre><p></p>
<p align="left">Pour pourvoir utiliser des propriétés .NET comme binding dans votre vue XAML, vous devez spécifier le DataContext de votre fenêtre vers votre classe MainWindow soit via le code (<em>this.DataContent = this</em>) ou soit directement dans votre vue XAML en ajoutant cette attribut sur l’élément Window :</p>
<p></p><pre class="crayon-plain-tag">DataContext="{Binding RelativeSource={RelativeSource Self}}"</pre><p></p>
<p align="left">Résultat, vous pouvez suivre en temps réel le CPU ici de la machine “PO-SEB” :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/03/image-200.png"><img class="colorbox-1563"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="Binding au CPU du package HWMonitor" src="https://developer.myconstellation.io/wp-content/uploads/2016/03/image_thumb-176.png" alt="Binding au CPU du package HWMonitor" width="424" height="284" border="0" /></a></p>
<p align="left">Allons un peu plus loin en ajoutons dans notre code C#, un nouveau StateObjectLink :</p>
<p></p><pre class="crayon-plain-tag">[HWMonitorStateObjectLink(HWMonitorStateObjectNames._intelcpu_0_load_0)]
public StateObjectCollectionNotifier CPUs { get; set; }</pre><p></p>
<p align="left">Ce “lien” ne précise que le nom du StateObject (ici “/intelcpu/0/load/0”) et le package (HWMonitorStateObjectLink est la classe générée qui spécifie implicitement le package à “HWMonitor).</p>
<p align="left">De ce fait, toutes les consommations CPU mesurées par les instances du package HWMonitor seront captées par ce “link” ! On utilisera donc un StateObject<strong>Collection</strong>Notifier car on aura autant de StateObjects qu’on a d’instance de ce package.</p>
<p align="left">Dans la vue XAML, ajoutons un menu déroulant (combobox) pour afficher le nom des sentinelles (= le nom des machines) des StateObjects de votre collection “CPUs” :</p>
<p></p><pre class="crayon-plain-tag">&lt;ComboBox x:Name="comboBox" ItemsSource="{Binding Path=CPUs}" DisplayMemberPath="Value.SentinelName" HorizontalAlignment="Left" Margin="10" VerticalAlignment="Top" /&gt;</pre><p></p>
<p align="left">Enfin, modifions une nouvelle fois notre label. Cette fois ci la valeur à afficher n’est pas celle du StateObject “CPU”, mais celle du StateObject sélectionné par la combobox :</p>
<p></p><pre class="crayon-plain-tag">&lt;Label x:Name="label" Content="{Binding ElementName=comboBox, Path=SelectedItem.DynamicValue.Value}" ContentStringFormat="{}{0:N2}%" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="48"/&gt;</pre><p></p>
<p align="left">On obtient donc la possibilité de suivre la consommation de chaque machine (= sentinelle) où le package HWMonitor est déployé :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/03/image-201.png"><img class="colorbox-1563"  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-177.png" alt="image" width="424" height="286" border="0" /></a></p>
<p align="left">Pour terminer on pourrait également ajouter un StateObjectLink qui contiendrait TOUS les StateObjects produits par les packages HWMonitor, peut importe le nom du StateObject et la sentinelle :</p>
<p></p><pre class="crayon-plain-tag">[HWMonitorStateObjectLink]
public StateObjectCollectionNotifier HWMonitor { get; set; }</pre><p></p>
<p align="left">Pour afficher toutes ces données, on peut utiliser un DataGrid lié à votre collection de StateObject “HWMonitor” :</p>
<p></p><pre class="crayon-plain-tag">&lt;DataGrid ItemsSource="{Binding HWMonitor}"&gt;&lt;/DataGrid&gt;</pre><p></p>
<p align="left">On obtiendrait une vue avec deux colonnes, la propriété DynamicValue et Value des StateObjectNotifier :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/03/image-198.png"><img class="colorbox-1563"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="DataGrid sur une collection de StateObjectNotifier" src="https://developer.myconstellation.io/wp-content/uploads/2016/03/image_thumb-174.png" alt="DataGrid sur une collection de StateObjectNotifier" width="424" height="426" border="0" /></a></p>
<p align="left">Pour rendre cela plus visuelle, définissions explicitement des colonnes avec le nom de la sentinelle, le nom du StateObject, la propriété “Name” de la valeur du StateObject  (le nom du compteur), la “Value” et l’unité de la mesure (Unit).</p>
<p align="left">En XAML cela se traduit par le code suivant :</p>
<p></p><pre class="crayon-plain-tag">&lt;DataGrid ItemsSource="{Binding HWMonitor}" AutoGenerateColumns="False" Margin="0, 0, 0, 40"&gt;
    &lt;DataGrid.Columns&gt;
        &lt;DataGridTextColumn Header="Sentinel" Binding="{Binding Path=Value.SentinelName}"&gt;&lt;/DataGridTextColumn&gt;
        &lt;DataGridTextColumn Header="StateObject name" Binding="{Binding Path=Value.Name}"&gt;&lt;/DataGridTextColumn&gt;
        &lt;DataGridTextColumn Header="Counter name" Binding="{Binding Path=DynamicValue.Name}"&gt;&lt;/DataGridTextColumn&gt;
        &lt;DataGridTextColumn Header="Value" Binding="{Binding Path=DynamicValue.Value}"&gt;&lt;/DataGridTextColumn&gt;
        &lt;DataGridTextColumn Header="Unit" Binding="{Binding Path=DynamicValue.Unit}"&gt;&lt;/DataGridTextColumn&gt;
    &lt;/DataGrid.Columns&gt;
&lt;/DataGrid&gt;</pre><p></p>
<p align="left">Le résultat :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/03/image-202.png"><img class="colorbox-1563"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="StateObjects des packages HWMonitor" src="https://developer.myconstellation.io/wp-content/uploads/2016/03/image_thumb-178.png" alt="StateObjects des packages HWMonitor" width="424" height="615" border="0" /></a></p>
<p align="left">Prenez garde car les StateObjects sont mis à jour dans le StateObjectsCollectionNotifier par des threads différents. Vous risquez donc d’avoir des exceptions du type “<em>An ItemsControl is inconsistent with its items source</em>”. Afin d’éviter ce genre d’erreur, utilisez la  méthode “<em>BindingOperations.EnableCollectionSynchronization</em>”.</p>
<p align="left">Pour cela, dans votre classe, ajoutez un objet de synchronisation :</p>
<p></p><pre class="crayon-plain-tag">private static object _syncLock = new object();</pre><p></p>
<p align="left">Puis dans le constructeur de votre fenêtre, après le <em>InitializeComponent()</em>, activez la synchronisation de la collection sur votre StateObjectCollectionNotifier (ici nommé ‘HWMonitor’) :</p>
<p></p><pre class="crayon-plain-tag">BindingOperations.EnableCollectionSynchronization(HWMonitor, _syncLock);</pre><p></p>
<p align="left">Si lancez votre package dans une Constellation avec plusieurs instances du packages HWMonitor sur vos différentes sentinelles, vous aurez une vision temps réel de l’ensemble de vos machines Windows avec seulement ces quelques lignes de XAML et Constellation :</p>
<p align="left"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/03/image-203.png"><img class="colorbox-1563"  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: 0px;" title="StateObjects des packages HWMonitor" src="https://developer.myconstellation.io/wp-content/uploads/2016/03/image_thumb-179.png" alt="StateObjects des packages HWMonitor" width="424" height="580" border="0" /></a></p>
<h3 align="left">Déployez votre package UI</h3>
<h4 align="left">Publier le package</h4>
<p align="left">Le sujet a été traité dans <a href="/getting-started/creez-votre-premier-package-constellation-en-csharp/#Publier_son_package_dans_Constellation">le guide de démarrage,</a> il suffit de cliquer-droit sur votre projet et sélectionner dans le menu Constellation “Publish On Constellation” ou directement depuis la toolbar :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/03/image-170.png"><img class="colorbox-1563"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="Publication du package" src="https://developer.myconstellation.io/wp-content/uploads/2016/03/image_thumb-147.png" alt="Publication du package" width="424" height="97" border="0" /></a></p>
<p align="left">Vous pourrez alors choisir le type de publication (Local ou Upload sur le serveur Constellation) :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/03/image-157.png"><img class="colorbox-1563"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="Publication du package" src="https://developer.myconstellation.io/wp-content/uploads/2016/03/image_thumb-134.png" alt="Publication du package" width="424" height="212" border="0" /></a></p>
<h4 align="left">Déployer le package sur une sentinelle UI</h4>
<p align="left">Vous devez impérativement déployer un package “UI” sur une sentinelle UI. Si vous tentez d’ajouter un package UI sur une sentinelle service, le package démarrera mais aucune fenêtre ne pourra être visible (le service ne peut pas interagir avec le bureau Windows).</p>
<p align="left">Les sentinelles UI ont le suffixe “_UI” dans leurs noms. Ici pour cette Constellation, il y a deux sentinelles connectées, l’une de type “Service” et l’autre “UI”, toutes deux sur la même machine (nommé “PO-SEB”).</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/03/image-171.png"><img class="colorbox-1563"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="Sentinelles connectées" src="https://developer.myconstellation.io/wp-content/uploads/2016/03/image_thumb-148.png" alt="Sentinelles connectées" width="424" height="263" border="0" /></a></p>
<p align="left">Pour ajouter notre package à la sentinelle UI, vous pouvez éditer la configuration de vos Constellation directement depuis Visual Studio :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/03/image-172.png"><img class="colorbox-1563"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="Ajout du package depuis Visual Studio" src="https://developer.myconstellation.io/wp-content/uploads/2016/03/image_thumb-149.png" alt="Ajout du package depuis Visual Studio" width="424" height="232" border="0" /></a></p>
<p align="left">Ou bien depuis la Console Constellation :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/03/image-173.png"><img class="colorbox-1563"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="Ajout du package dans une sentinelle UI" src="https://developer.myconstellation.io/wp-content/uploads/2016/03/image_thumb-150.png" alt="Ajout du package dans une sentinelle UI" width="424" height="263" border="0" /></a></p>
<p align="left">Pour déployer la configuration, cliquez sur le bouton “Save &amp; Deploy” depuis la Console, ou directement sur la page des “Packages” cliquez sur “Reload &amp; Deploy”.</p>
<p align="left">Votre package UI sera démarré et vous pourrez le contrôler depuis la Console comme pour les autres packages.</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/03/image-174.png"><img class="colorbox-1563"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="Contrôle du package UI sur la Console" src="https://developer.myconstellation.io/wp-content/uploads/2016/03/image_thumb-151.png" alt="Contrôle du package UI sur la Console" width="424" height="263" border="0" /></a></p>
<h4 align="left">Démarrer son package “manuellement”</h4>
<p align="left">Si vous créez une application à destination d’une borne d’affichage, comme un miroir, le package est démarré automatiquement par la sentinelle (comportement par défaut) et est relancé si le package plante !</p>
<p align="left">Cependant, si votre package est destiné à être utilisé par un utilisateur comme une application Windows classique vous voudriez certainement ne pas la lancer automatiquement au démarrage de la sentinelle. Au contraire vous voudriez que ce soit l’utilisateur qui décide de la lancer en lançant un raccourci Windows par exemple sans devoir se connecter sur la Console de votre Constellation.</p>
<p align="left">Pour cela vous pouvez lancer la sentinelle en passant un ordre en paramètre :</p>
<p></p><pre class="crayon-plain-tag">Constellation.Sentinel.UI.exe &lt;action&gt; &lt;package&gt;</pre><p></p>
<p align="left">Les actions peuvent être :</p>
<ul>
<li>
<div align="left">Start</div>
</li>
<li>
<div align="left">Stop</div>
</li>
<li>
<div align="left">Restart</div>
</li>
<li>
<div align="left">Reload</div>
</li>
</ul>
<p align="left">Par exemple, créons un raccourci sur le bureau vers :</p>
<p></p><pre class="crayon-plain-tag">Constellation.Sentinel.UI.exe Reload MonPackageWPF</pre><p></p>
<p align="left">Ainsi dès que vous double-cliquerez sur ce raccourci, la sentinelle téléchargera la dernière version du package sur le serveur et lancera votre package (Reload) :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/03/image-175.png"><img class="colorbox-1563"  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-152.png" alt="image" width="424" height="322" border="0" /></a></p>
<p align="left">Bien entendu, l’état du package sera automatiquement synchronisé dans la Constellation. Vous pourrez donc contrôler l’état du package depuis la Console par exemple.</p>
<p align="left">Par défaut, une sentinelle démarre tous les packages qui lui sont assignés. Si c’est un package destiné à être lancé manuellement par l’utilisateur, vous voudriez peut être ne pas lancer automatiquement le package. Vous pouvez donc définir l’attribut “autoStart” à false au niveau de la configuration de votre package.</p>
<p align="left">Aussi l’ordre d’arrêt d’un package doit provenir du hub de contrôle de Constellation, qui se chargera de communiquer l’ordre au package lui même (de s’arrêter) et à sa sentinelle (de tuer le package si il ne s’est pas arrêté dans le temps imparti).</p>
<p align="left">Seulement, dans un package UI de ce type, c’est à dire “application Windows classique”, l’utilisateur fermera naturellement l’application en cliquant sur la croix rouge en haut à droite !</p>
<p align="left">La sentinelle détectera la mort du processus du package alors qu’elle n’a pas eu l’ordre de Constellation d’arrêter le package ! Du point de vue de la sentinelle, c’est un arrêt brutal !</p>
<p align="left">Elle appliquera donc les options de récupération qui par défaut redémarre un package 30 secondes après un arrêt brutal :</p>
<p align="left"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/03/image-176.png"><img class="colorbox-1563"  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="RecoveryOption par défaut" src="https://developer.myconstellation.io/wp-content/uploads/2016/03/image_thumb-153.png" alt="RecoveryOption par défaut" width="424" height="46" border="0" /></a></p>
<p align="left">Les options par défaut sont définis dans la configuration de la Constellation :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/03/image-177.png"><img class="colorbox-1563"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="RecoveryOption par défaut" src="https://developer.myconstellation.io/wp-content/uploads/2016/03/image_thumb-154.png" alt="RecoveryOption par défaut" width="424" height="137" border="0" /></a></p>
<p align="left">Dans notre cas, nous allons redéfinir ces options de récupération au niveau du package lui même pour ne pas redémarrer un package suite à un arrêt forcé et ne pas démarrer automatiquement notre package au démarrage. La configuration du package sera :</p>
<p align="left"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/03/image-178.png"><img class="colorbox-1563"  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="Configuration d'un package UI" src="https://developer.myconstellation.io/wp-content/uploads/2016/03/image_thumb-155.png" alt="Configuration d'un package UI" width="424" height="134" border="0" /></a></p>
<p>The post <a rel="nofollow" href="https://developer.myconstellation.io/client-api/net-package-api/packages-ui-wpf-winform/">Créer des packages UI en Winform ou WPF</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/packages-ui-wpf-winform/feed/</wfw:commentRss>
			<slash:comments>0</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-22 03:08:25 by W3 Total Cache
-->