a:6:{s:5:"child";a:1:{s:0:"";a:1:{s:3:"rss";a:1:{i:0;a:6:{s:4:"data";s:4:"
  
";s:7:"attribs";a:1:{s:0:"";a:1:{s:7:"version";s:3:"2.0";}}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";s:5:"child";a:1:{s:0:"";a:1:{s:7:"channel";a:1:{i:0;a:6:{s:4:"data";s:113:"
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
  ";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";s:5:"child";a:4:{s:0:"";a:7:{s:5:"title";a:1:{i:0;a:5:{s:4:"data";s:12:"My Canaletto";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:11:"description";a:1:{i:0;a:5:{s:4:"data";s:0:"";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:4:"link";a:1:{i:0;a:5:{s:4:"data";s:20:"http://canaletto.fr/";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:4:"docs";a:1:{i:0;a:5:{s:4:"data";s:41:"http://www.rssboard.org/rss-specification";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:9:"generator";a:1:{i:0;a:5:{s:4:"data";s:22:"BlogEngine.NET 3.3.8.0";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:8:"language";a:1:{i:0;a:5:{s:4:"data";s:5:"en-US";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:4:"item";a:10:{i:0;a:6:{s:4:"data";s:145:"
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
    ";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";s:5:"child";a:7:{s:0:"";a:7:{s:5:"title";a:1:{i:0;a:5:{s:4:"data";s:39:"AutoDiscover &amp; AutoConfig IMAP/SMTP";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:11:"description";a:1:{i:0;a:5:{s:4:"data";s:12491:"<p style="text-align: justify;">En 2020, pour m'occuper pendant le confinement, j'avais &eacute;crit <a href="http://canaletto.fr/post/configuration-automatique-pop-imap" target="_blank" rel="noopener">un article</a> sur la configuration automatique des clients POP/IMAP. Ca fonctionnait sur Thunderbird, mais pas sur les clients Microsoft... Bon, les clients Microsoft il y en a de plusieurs sorte (Courrier, Outlook nouveau, ancien, 365, jadis Express et j'en passe) et la chose n'est (volontairement ?) pas simple. On va oublier les versions 365 qui m&ecirc;me si elles supportent IMAP le font mal et ne sont pas vraiment destin&eacute;s &agrave; cet usage mais plus &agrave; du MAPI.</p>
<p style="text-align: justify;">Pour cet article j'ai mont&eacute; un serveur <a href="https://www.cloudron.io/" target="_blank" rel="noopener">Cloudron</a>. Ce projet g&egrave;re tr&egrave;s bien le mail dans sa version de base gratuite. H&eacute;las il ne g&egrave;re pas la configuration des clients, ce qui est regrettable car il pourrait tr&egrave;s facilement int&eacute;grer ce qui suit afin d'&ecirc;tre totalement dans la philosophie du projet int&eacute;gr&eacute; !</p>
<p style="text-align: justify;">Il existe plusieurs fa&ccedil;ons de faire de l'AutoDiscovery ou de l'AutoConfig</p>
<h3 style="text-align: justify;">La m&eacute;thode RFC 6186</h3>
<p style="text-align: justify;">Elle se base sur des enregistrements DNS :</p>
<pre class="language-yaml"><code>_imap._tcp 300 IN SRV 0 0 0 .
_imaps._tcp 300 IN SRV 0 1 993 mail.domain.tld.
_pop3._tcp 300 IN SRV 0 0 0 .
_pop3s._tcp 300 IN SRV 10 1 995 mail.domain.tld.
_submission._tcp 300 IN SRV 0 0 0 .
_submissions._tcp 300 IN SRV 0 1 587 mail.domain.tld.</code></pre>
<p style="text-align: justify;"><a href="https://www.rfc-editor.org/rfc/rfc6186" target="_blank" rel="noopener">Normalis&eacute;e</a> mais visiblement trop simple est abandonn&eacute;e. Encore que <a href="https://social.technet.microsoft.com/Forums/en-US/daa5fd1f-883e-4ca9-8ebc-3b25576ced28/autodiscover-for-imap-account-on-outlook-20162019?forum=outlook" target="_blank" rel="noopener">certaines versions d'Outlook</a> utiliseraient &ccedil;a. Etrange.</p>
<h3 style="text-align: justify;">La m&eacute;thode Thunderbird&nbsp;</h3>
<p style="text-align: justify;">Thunderbird va chercher les param&egrave;tres dans un fichier XML sur l'url :<code></code></p>
<p style="text-align: justify;"><code>http://autoconfig.domain.tld/mail/config-v1.1.xml</code></p>
<h3 style="text-align: justify;">La m&eacute;thode Outlook</h3>
<p style="text-align: justify;">Outlook cherche l&rsquo;enregistrement DNS de type SRV :</p>
<p style="text-align: justify;"><code>_autodiscover._tcp.domain.tld 3600 IN SRV 10 10 443 autodiscover.domain.tld.</code></p>
<p style="text-align: justify;">qui va lui donner l'adresse ou interroger le fichier XML, donc un CNAME qui pointe sur le serveur web qui h&eacute;berger le fichier XML, ce qui au final donnera une requ&ecirc;te sur</p>
<p style="text-align: justify;"><code>https://autodiscover.domain.tld/AutoDiscover/AutoDiscover.xml</code></p>
<p style="text-align: justify;">Simple !&nbsp;Attention &agrave; bien respecter la casse du mot AutoDiscover... Et ne pas oublier que dans le cas Microsoft on travaille en HTTPS. Dans certains cas on pourrait faire pointer &ccedil;a sur n'importe quelle url, mais il semblerait que certaines vers ions d'Outlook (et il y en a !) cherchent une url qui commence par <code>autodiscover</code>...</p>
<h3 style="text-align: justify;">Un site pour les rassembler</h3>
<p style="text-align: justify;">Dans la m&eacute;thode qui va suivre on va utiliser un seul site capable de r&eacute;pondre aux url <code>autoconfig</code> et <code>autodiscover</code>, on renseignera donc ces enregistrement dans le dns :</p>
<pre class="language-yaml"><code>_autodiscover._tcp.domain.tld 1800 IN SRV 10 10 443 autodiscover.domain.tld.
autoconfig 1800 IN CNAME web_server.domain.tld.
autodiscover 1080 IN CNAME web_server.domain.tld.</code></pre>
<p style="text-align: justify;">Ensuite on cr&eacute;e un site web capable de r&eacute;pondre &agrave; ces deux url pour l'ensemble des domaines de messagerie pour lesquels on souhaite proposer ce service. Le site doit r&eacute;pondre en HTTP et HTTPS, <span style="text-decoration: underline;">mais surtout sans redirection automatique HTTP vers HTTPS</span>. Pour cet exemple j'ai utilis&eacute; un serveur web NGINX avec du PHP.</p>
<p style="text-align: justify;">On va utiliser ce code que j'ai trouv&eacute; <a href="https://david.mercereau.info/autoconfig-thunderbird-autodiscover-outlook-sur-messagerie-heberge-ispconfig/" target="_blank" rel="noopener">ici</a>, je l'ai utilis&eacute; tel que en adaptant les enregistrements DNS et les redirections pour NGINX que l'on verra apr&egrave;s le code. On copie donc ce code PHP dans autoconfig-mail.php :</p>
<pre class="language-php"><code>&lt;?php
 
/*
By David Mercereau
Licence Beerware
*/
 
function extract_domain($domain) {
    if(preg_match("/(?P&lt;domain&gt;[a-z0-9][a-z0-9\-]{1,63}\.[a-z\.]{2,6})$/i", $domain, $matches)) {
        return $matches['domain'];
    } else {
        return $domain;
    }
}
 
$domain = extract_domain($_SERVER['SERVER_NAME']);
$mailServeur='mail.'.$domain;
 
if (preg_match('/^\/mail\/config-v1\.1\.xml/', $_SERVER['REQUEST_URI'])) {
    header('Content-Type: text/xml');
    header('Content-Type: application/xml');
    ?&gt;
&lt;clientConfig version="1.1"&gt;
    &lt;emailProvider id="&lt;?= $domain ?&gt;"&gt;
      &lt;domain&gt;&lt;?= $domain ?&gt;&lt;/domain&gt;
      &lt;displayName&gt;&lt;?= $domain ?&gt;&lt;/displayName&gt;
      &lt;displayShortName&gt;&lt;?= $domain ?&gt;&lt;/displayShortName&gt;
      &lt;incomingServer type="imap"&gt;
         &lt;hostname&gt;&lt;?= $mailServeur ?&gt;&lt;/hostname&gt;
         &lt;port&gt;143&lt;/port&gt;
         &lt;socketType&gt;STARTTLS&lt;/socketType&gt;
         &lt;username&gt;%EMAILADDRESS%&lt;/username&gt;
         &lt;authentication&gt;password-cleartext&lt;/authentication&gt;
      &lt;/incomingServer&gt;
      &lt;outgoingServer type="smtp"&gt;
         &lt;hostname&gt;&lt;?= $mailServeur ?&gt;&lt;/hostname&gt;
         &lt;port&gt;587&lt;/port&gt;
         &lt;socketType&gt;STARTTLS&lt;/socketType&gt;
         &lt;username&gt;%EMAILADDRESS%&lt;/username&gt;
         &lt;authentication&gt;password-cleartext&lt;/authentication&gt;
      &lt;/outgoingServer&gt;
      &lt;documentation url="https://webmail.&lt;?= $domain ?&gt;"&gt;
          &lt;descr lang="fr"&gt;Connexion Webmail&lt;/descr&gt;
          &lt;descr lang="en"&gt;Webmail connexion&lt;/descr&gt;
      &lt;/documentation&gt;
      &lt;documentation url="http://projet.retzo.net/projects/hebergement/wiki"&gt;
        &lt;descr lang="fr"&gt;Documentation&lt;/descr&gt;
        &lt;descr lang="en"&gt;Generic settings page&lt;/descr&gt;
      &lt;/documentation&gt;
    &lt;/emailProvider&gt;
&lt;/clientConfig&gt;
    &lt;?php
} else {
    // Outlook
    //get raw POST data so we can extract the email address
    $data = file_get_contents("php://input");
    preg_match("/\&lt;EMailAddress\&gt;(.*?)\&lt;\/EMailAddress\&gt;/", $data, $matches);
 
    //set Content-Type
    header('Content-Type: text/xml');
    header('Content-Type: application/xml');
    echo '&lt;?xml version="1.0" encoding="utf-8" ?&gt;'; 
    ?&gt;
&lt;Autodiscover xmlns="http://schemas.microsoft.com/exchange/autodiscover/responseschema/2006"&gt;
   &lt;Response xmlns="http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a"&gt;
       &lt;Account&gt;
           &lt;AccountType&gt;email&lt;/AccountType&gt;
           &lt;Action&gt;settings&lt;/Action&gt;
           &lt;Protocol&gt;
               &lt;Type&gt;IMAP&lt;/Type&gt;
               &lt;Server&gt;&lt;?= $mailServeur ?&gt;&lt;/Server&gt;
               &lt;Port&gt;993&lt;/Port&gt;
               &lt;DomainRequired&gt;off&lt;/DomainRequired&gt;
               &lt;LoginName&gt;&lt;?php echo $matches[1]; ?&gt;&lt;/LoginName&gt;
               &lt;SPA&gt;off&lt;/SPA&gt;
               &lt;SSL&gt;on&lt;/SSL&gt;
               &lt;AuthRequired&gt;on&lt;/AuthRequired&gt;
           &lt;/Protocol&gt;
           &lt;Protocol&gt;
               &lt;Type&gt;POP3&lt;/Type&gt;
               &lt;Server&gt;&lt;?= $mailServeur ?&gt;&lt;/Server&gt;
               &lt;Port&gt;995&lt;/Port&gt;
               &lt;DomainRequired&gt;off&lt;/DomainRequired&gt;
               &lt;LoginName&gt;&lt;?php echo $matches[1]; ?&gt;&lt;/LoginName&gt;
               &lt;SPA&gt;off&lt;/SPA&gt;
               &lt;SSL&gt;on&lt;/SSL&gt;
               &lt;AuthRequired&gt;on&lt;/AuthRequired&gt;
           &lt;/Protocol&gt;
           &lt;Protocol&gt;
               &lt;Type&gt;SMTP&lt;/Type&gt;
               &lt;Server&gt;&lt;?= $mailServeur ?&gt;&lt;/Server&gt;
               &lt;Port&gt;587&lt;/Port&gt;
               &lt;DomainRequired&gt;off&lt;/DomainRequired&gt;
               &lt;LoginName&gt;&lt;?php echo $matches[1]; ?&gt;&lt;/LoginName&gt;
               &lt;SPA&gt;off&lt;/SPA&gt;
               &lt;Encryption&gt;TLS&lt;/Encryption&gt;
               &lt;AuthRequired&gt;on&lt;/AuthRequired&gt;
               &lt;UsePOPAuth&gt;off&lt;/UsePOPAuth&gt;
               &lt;SMTPLast&gt;off&lt;/SMTPLast&gt;
           &lt;/Protocol&gt;
       &lt;/Account&gt;
   &lt;/Response&gt;
&lt;/Autodiscover&gt;
    &lt;?php
}
 
?&gt;</code></pre>
<p style="text-align: justify;">Ensuite dans configuration NGINX on ajoute les redirections suivantes qui va permettre de servir la bonne version XML selon que la requ&ecirc;te utilise la m&eacute;thode Outlook ou Thunderbird (attention &agrave; la casse...) :</p>
<pre class="language-javascript"><code>location /AutoDiscover {
  rewrite ^/AutoDiscover/AutoDiscover.xml /autoconfig-mail.php;
}
location /mail {
  rewrite ^/mail/config-v1.1.xml /autoconfig-mail.php;
}</code></pre>
<p style="text-align: center;"><img src="http://canaletto.fr/image.axd?picture=/images/enjoy2.jpg" width="250" height="168" /></p>
<h3 style="text-align: left;">Sources</h3>
<ul style="list-style-type: circle;">
<li style="text-align: left;"><a href="https://github.com/cfoellmann/ISPC-resources/tree/master/guides/autodiscover" target="_blank" rel="noopener">https://github.com/cfoellmann/ISPC-resources/tree/master/guides/autodiscover</a></li>
<li style="text-align: left;"><a href="https://help.directadmin.com/item.php?id=661" target="_blank" rel="noopener">https://help.directadmin.com/item.php?id=661</a></li>
<li style="text-align: left;"><a href="https://testconnectivity.microsoft.com" target="_blank" rel="noopener">https://testconnectivity.microsoft.com</a></li>
<li style="text-align: left;"><a href="https://www.howto-outlook.com/howto/autodiscoverconfiguration.htm#cname" target="_blank" rel="noopener">https://www.howto-outlook.com/howto/autodiscoverconfiguration.htm#cname</a></li>
<li style="text-align: left;">https://www.awsmonster.com/2019/09/how-to-configure-autodiscover.html</li>
<li style="text-align: left;"><a href="https://learn.microsoft.com/fr-fr/exchange/troubleshoot/outlook-issues/issues-when-using-autodiscover-service" target="_blank" rel="noopener">https://learn.microsoft.com/fr-fr/exchange/troubleshoot/outlook-issues/issues-when-using-autodiscover-service</a></li>
<li style="text-align: left;"><a href="https://docs.directadmin.com/other-hosting-services/email/autodiscover.html" target="_blank" rel="noopener">https://docs.directadmin.com/other-hosting-services/email/autodiscover.html</a></li>
<li style="text-align: left;"><a href="https://david.mercereau.info/autoconfig-thunderbird-autodiscover-outlook-sur-messagerie-heberge-ispconfig/" target="_blank" rel="noopener">https://david.mercereau.info/autoconfig-thunderbird-autodiscover-outlook-sur-messagerie-heberge-ispconfig/</a></li>
<li style="text-align: left;"><a href="https://github.com/wdes/mail-autodiscover-autoconfig" target="_blank" rel="noopener">https://github.com/wdes/mail-autodiscover-autoconfig</a> (Apple inside...)</li>
<li style="text-align: left;"><a href="https://blog.ebak.fr/2022/03/05/Auto-configuration-des-clients-mails/#Autoconfig-Thunderbird" target="_blank" rel="noopener">https://blog.ebak.fr/2022/03/05/Auto-configuration-des-clients-mails/#Autoconfig-Thunderbird</a>&nbsp;</li>
</ul>
<p style="text-align: left;"><br />https://github.com/gronke/email-autodiscover<br />https://github.com/SpicyWeb-de/isp-mailConfig</p>";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:4:"link";a:1:{i:0;a:5:{s:4:"data";s:62:"http://canaletto.fr/post/autodiscover-and-autoconfig-imap-smtp";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:8:"comments";a:1:{i:0;a:5:{s:4:"data";s:70:"http://canaletto.fr/post/autodiscover-and-autoconfig-imap-smtp#comment";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:4:"guid";a:1:{i:0;a:5:{s:4:"data";s:69:"http://canaletto.fr/post.aspx?id=d03374ea-d6e8-464d-a0e8-80f3ef2a3efe";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:7:"pubDate";a:1:{i:0;a:5:{s:4:"data";s:33:"lun., 20 nov. 2023 23:08:00 +0100";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:8:"category";a:1:{i:0;a:5:{s:4:"data";s:2:"IT";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}s:34:"https://blogengine.io/schemas/tags";a:1:{s:3:"tag";a:6:{i:0;a:5:{s:4:"data";s:11:"Thunderbird";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:1;a:5:{s:4:"data";s:7:"Outlook";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:2;a:5:{s:4:"data";s:4:"Mail";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:3;a:5:{s:4:"data";s:4:"IMAP";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:4;a:5:{s:4:"data";s:12:"Autodiscover";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:5;a:5:{s:4:"data";s:10:"autoconfig";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}s:32:"http://purl.org/dc/elements/1.1/";a:1:{s:9:"publisher";a:1:{i:0;a:5:{s:4:"data";s:5:"Admin";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}s:52:"http://madskills.com/public/xml/rss/module/pingback/";a:2:{s:6:"server";a:1:{i:0;a:5:{s:4:"data";s:32:"http://canaletto.fr/pingback.axd";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:6:"target";a:1:{i:0;a:5:{s:4:"data";s:69:"http://canaletto.fr/post.aspx?id=d03374ea-d6e8-464d-a0e8-80f3ef2a3efe";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}s:38:"http://purl.org/rss/1.0/modules/slash/";a:1:{s:8:"comments";a:1:{i:0;a:5:{s:4:"data";s:1:"0";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}s:53:"http://madskills.com/public/xml/rss/module/trackback/";a:1:{s:4:"ping";a:1:{i:0;a:5:{s:4:"data";s:73:"http://canaletto.fr/trackback.axd?id=d03374ea-d6e8-464d-a0e8-80f3ef2a3efe";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}s:36:"http://wellformedweb.org/CommentAPI/";a:2:{s:7:"comment";a:1:{i:0;a:5:{s:4:"data";s:70:"http://canaletto.fr/post/autodiscover-and-autoconfig-imap-smtp#comment";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:10:"commentRss";a:1:{i:0;a:5:{s:4:"data";s:77:"http://canaletto.fr/syndication.axd?post=d03374ea-d6e8-464d-a0e8-80f3ef2a3efe";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}}}i:1;a:6:{s:4:"data";s:152:"
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
    ";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";s:5:"child";a:7:{s:0:"";a:7:{s:5:"title";a:1:{i:0;a:5:{s:4:"data";s:36:"Home Assistant, Zigbee &amp; Legrand";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:11:"description";a:1:{i:0;a:5:{s:4:"data";s:9877:"<p style="text-align: justify;">On m'a demand&eacute; r&eacute;cemment d'int&eacute;grer des appareils Legrand dans Home Assistant, je l'avais d&eacute;j&agrave; fait pour certains et j'en avais parl&eacute; dans <a href="http://canaletto.fr/post/home-assistant-zha-and-legrand" target="_blank" rel="noopener">cet article</a>. Aujourd'hui il s'agit d'int&eacute;grer des commandes sans fil vue come des t&eacute;l&eacute;commandes dans HA. Vous allez me demander quel est l'int&eacute;r&ecirc;t quand un simple bouton Ikea (E1743) &agrave; moins de 10 fait le job pour mes volets roulants. C'est purement esth&eacute;tique, quand on a un logement &eacute;quip&eacute; en Legrand C&eacute;liane ou Mosaic, on veut parfois que les commandes des volets soient dans la m&ecirc;me collection.</p>
<p style="text-align: center;"><img src="http://canaletto.fr/image.axd?picture=/images/legrand_vr.jpeg" width="249" height="249" /></p>
<p style="text-align: justify;">Soit, Legrand propose des commandes en Zigbee, il n'y a plus qu'&agrave; !</p>
<p style="text-align: justify;">Dans la pratique on va voir que ce n'est pas si simple, en tous cas bien moins simple qu'avec mon bouton Ikea &agrave; 10 &euro; ! Je pr&eacute;cise le prix car les commandes Legrand sont plut&ocirc;t &agrave; 80 &euro;. Mais quand on aime on ne compte pas.</p>
<p style="text-align: justify;">Il existe plusieurs type d'&eacute;quipements Zigbee chez Legrand</p>
<ul style="text-align: justify;">
<li>Ceux qui sont filaires, j'en ai parl&eacute; <a href="http://canaletto.fr/post/home-assistant-zha-and-legrand" target="_blank" rel="noopener">ici</a> (micro modules, contacteur DIN, prise connect&eacute;e, etc...)</li>
<li>La gamme des commandes sans fil &agrave; pile</li>
<li>La gamme des commandes sans fil sans piles (gamme Self-e). J'y reviendrait certainement, mais d'apr&egrave;s mes infos cette gamme supporte tous les canaux et serait mieux int&eacute;gr&eacute;e ZHA/Z2M.</li>
</ul>
<p style="text-align: justify;">Je me suis donc pench&eacute; sur la gamme avec pile.</p>
<p style="text-align: justify;">Premi&egrave;re observation, ces devices sont g&eacute;n&eacute;ralement livr&eacute;s avec un firmware de niveau 42 qui ne permet que l'utilisation du canal Zigbee 11. Don impossible &agrave; faire fonctionner sur mon ZHA qui est en 15. Je l'ai donc appair&eacute; sur mon Z2M en 11 et &ccedil;a fonctionne. Et l&agrave; je me suis dit que j'allais pouvoir mettre &agrave; jour ce firmware en OTA. Mais non, &ccedil;a ne fonctionne pas et on se retrouve dans la probl&eacute;matique des &eacute;quipements franco Fran&ccedil;ais qui n'int&eacute;ressent pas grand monde au niveau international (on pense par exemple &agrave; tout ce qui est li&eacute; &agrave; l'int&eacute;gration Overkiz...).</p>
<p style="text-align: justify;">Apr&egrave;s moultes lectures des forums de diverses plateformes domotique, la conclusion est que la mise &agrave; jour du firmware ne peut se faire qu'au travers d'une passerelle officielle Legrand !&nbsp;J&rsquo;ai donc achet&eacute; le kit qui comprend :</p>
<ul style="text-align: justify;">
<li>La prise Control qui sert de passerelle</li>
<li>Un inter sans fil</li>
<li>Une ampoule</li>
</ul>
<p style="text-align: center;"><img src="http://canaletto.fr/image.axd?picture=/images/legrand_pack.jpg" width="532" height="532" /></p>
<p style="text-align: justify;">Il faut bien sur installer l&rsquo;appli Legrand et ensuite tenter d&rsquo;associer la prise au WIFI. Facile ? Non, &ccedil;a m&rsquo;a pris de plombes car vu que leur process est trop long, le mobile qui se connecte &agrave; la prise pour la configurer repasse sur le WIFI normal ou il retrouve Internet, et perd la config en cours. Solution faire &ccedil;a avec un vieux mobile&hellip; Bref, un premier amateurisme car on fait facilement ce genre d'association avec la majorit&eacute; des objets mobile en WIFI !</p>
<p style="text-align: justify;">Bon, la logique de l&rsquo;appli est orient&eacute;e &eacute;lectricien tr&egrave;s grand public, avec une logique d'&eacute;lectricien qui n&rsquo;est pas n&eacute;cessairement la notre. C'est un choix, il faut s'y faire, mais n'oublions pas que nous sommes ici uniquement pour faire un mise &agrave; jour...</p>
<p style="text-align: justify;">Ensuite il faut ajouter les inter. Sauf que la il faut comprendre qu&rsquo;on ne peut pas ajouter un inter seul. Dans la logique Legrand si tu ajoute un inter, en fin de dialogue &ccedil;a te demande ce que tu veux commander, sans quoi &ccedil;a bloque et il n&rsquo;y a plus qu&rsquo;&agrave; forcer le red&eacute;marrage de l&rsquo;appli et recommencer...&nbsp;Je n&rsquo;avais pas de prise Legrand sous la main, mais au bout d&rsquo;un moment j&rsquo;ai fini par penser &agrave; appairer l&rsquo;ampoule. Et la je vois enfin l&rsquo;inter livr&eacute; et mon inter de volet roulant qui ne peut rien commander, c&rsquo;est le m&ecirc;me mais avec un firmware diff&eacute;rent.</p>
<p style="text-align: justify;">Mais souvenons nous que nous somme l&agrave; &agrave; jouer avec ce bazar dans le seul but de mettre &agrave; jour le firmware de ces putains d&rsquo;inter qui au del&agrave; de couter un rein ne fonctionnent (mal) que sur le canal 11.&nbsp;H&eacute;las il n&rsquo;y arien pour faire cette mise &agrave; jour, mon inter de VR apparait en 42 dans l&rsquo;appli et en 002a dans z2m, donc identique l&rsquo;un &eacute;tant en hexa.&nbsp;D&rsquo;apr&egrave;s ce que j&rsquo;ai pu lire, la mise &agrave; jour se fera, un jour, mais on ne peut pas la forcer. Il faut juste laisser branch&eacute;, en esp&eacute;rant que mon inter qui n&rsquo;est pas connect&eacute; &agrave; un appareil se mette &agrave; jour tout seul&hellip;</p>
<p style="text-align: justify;">Donc je laisse branch&eacute;, la suite pour bient&ocirc;t&hellip;</p>
<p style="text-align: justify;"><strong>EDIT un peu plus tard :</strong></p>
<ul style="text-align: justify;">
<li>L&rsquo;inter (0 677 73N) est pass&eacute; de 50 &agrave; 70</li>
<li>L&rsquo;inter VR (0 777 48LA) n&rsquo;a pas boug&eacute;&hellip;</li>
<li>Je testerais si on peut l&rsquo;appairer hors du canal 11 mais je commence &agrave; douter&hellip;</li>
</ul>
<p style="text-align: justify;"><strong>EDIT le lendemain :</strong></p>
<ul style="text-align: justify;">
<li>L&rsquo;inter s&rsquo;appaire bien sur un autre canal apr&egrave;s sa mise &agrave; jour. Test&eacute; en ZHA sur 15, mais ZHA ne le supporte pas et rien ne bouge, aucun event.</li>
<li>L&rsquo;inter VR ne s&rsquo;est toujours pas mis &agrave; jour. Un peu comme s&rsquo;il lui fallait une charge...</li>
</ul>
<p style="text-align: justify;"><strong>EDIT le lendemain soir :</strong></p>
<ul style="text-align: justify;">
<li>L&rsquo;inter VR est bien pass&eacute; de 42 &agrave; 70, mon ZHA qui est sur le canal 15 le voit mais n&rsquo;en fait rien. Quand &agrave; Z2M il n&rsquo;en veut plus ! Pire &ccedil;a me fait planter Z2M&hellip;</li>
</ul>
<p style="text-align: justify;"><strong>EDIT le sur lendemain midi :</strong></p>
<ul style="text-align: justify;">
<li>L&rsquo;inter VR qui ne veut toujours pas de ZHA ou Z2M s&rsquo;est appair&eacute; correctement sur deconz en canal 15, il retourne dans les event les valeurs suivantes :</li>
</ul>
<blockquote>
<p>Mont&eacute;e : <code>1002</code> / Mont&eacute;e puis rel&acirc;ch&eacute; : <code>1002/3002</code><br />Descente : <code>2002</code> / Descente puis rel&acirc;ch&eacute; : <code>2002/3003</code><br />Stop (Les deux en m&ecirc;me temps) : <code>3003</code></p>
</blockquote>
<p style="text-align: justify;">Ce comportement est identique &agrave; ce qu&rsquo;il &eacute;tait sous Z2M et contrairement &agrave; d'autres t&eacute;l&eacute;commandes (le on/off Ikea (E1743 par exemple) il manque le fait qu&rsquo;un second appui bref provoque un stop. Il faut donc bien appuyer au milieu pour faire un &laquo; stop &raquo; et ce n&rsquo;est pas toujours pris en compte (probl&egrave;me physique).</p>
<p style="text-align: justify;">Qu&rsquo;il ne soit pas support&eacute; sur ZHA est un fait, il faudrait d&eacute;velopper un quirk et &ccedil;a me d&eacute;passe. Je ne sais pas pourquoi il ne veut plus s&rsquo;appairer sur Z2M, mais c&rsquo;est peut &ecirc;tre li&eacute; &agrave; mon installation, ma cl&eacute;, que sais-je...</p>
<p style="text-align: justify;">Il y a des chances que l&rsquo;aventure Legrand va prendre fin et je que je retourne fissa ce Kit &agrave; Amazon !</p>
<h3 style="text-align: justify;">Homekit</h3>
<p style="text-align: justify;">A signaler toutefois que cette passerelle est Homekit. Ce qui veut dire que ses &eacute;quipements remontent dans Home Assistant. Mais ne r&ecirc;vez pas trop, si l&rsquo;ampoule remonte bien, et certainement tous les actionneurs connect&eacute;s (prises, modules DIN), pas les inter ! Mais j&rsquo;avais d&eacute;j&agrave; remarqu&eacute; &ccedil;a avec les t&eacute;l&eacute;commandes Tuya qui ne remontent pas via une passerelle Tuya Homekit. Il y a une forme de logique, Homekit sert &agrave; commander un &eacute;quipement, comme une t&eacute;l&eacute;commande, hors on ne commande pas une t&eacute;l&eacute;commande&hellip;</p>
<p style="text-align: justify;">Par contre &ccedil;a veut dire que les &eacute;quipements reconnus par Legrand vont remonter dans Homekit, ce qui peut &ecirc;tre une solution de contr&ocirc;le facile pour des produit pas reconnus par HA (Profalux, Bubendorf, Aldes, etc&hellip;).</p>
<h3 style="text-align: justify;">La suite</h3>
<p style="text-align: justify;">Je vous propose de poursuivre <a href="https://forum.hacf.fr/t/interrupteur-legrand-volet-roulant-celiane-mosaic/9137/24" target="_blank" rel="noopener">ici</a> et que chacun y apporte ses retours.</p>
<p style="text-align: center;"><img src="http://canaletto.fr/image.axd?picture=/images/ThatsAllFolks.jpg" width="275" height="275" /></p>";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:4:"link";a:1:{i:0;a:5:{s:4:"data";s:58:"http://canaletto.fr/post/home-assistant-zigbee-and-legrand";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:8:"comments";a:1:{i:0;a:5:{s:4:"data";s:66:"http://canaletto.fr/post/home-assistant-zigbee-and-legrand#comment";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:4:"guid";a:1:{i:0;a:5:{s:4:"data";s:69:"http://canaletto.fr/post.aspx?id=c9296c49-547e-42ae-b4be-7a9cedd65947";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:7:"pubDate";a:1:{i:0;a:5:{s:4:"data";s:33:"dim., 19 nov. 2023 17:14:00 +0100";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:8:"category";a:1:{i:0;a:5:{s:4:"data";s:9:"Domotique";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}s:34:"https://blogengine.io/schemas/tags";a:1:{s:3:"tag";a:7:{i:0;a:5:{s:4:"data";s:14:"Home Assistant";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:1;a:5:{s:4:"data";s:4:"HASS";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:2;a:5:{s:4:"data";s:7:"Legrand";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:3;a:5:{s:4:"data";s:6:"zigbee";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:4;a:5:{s:4:"data";s:3:"Z2M";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:5;a:5:{s:4:"data";s:3:"ZHA";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:6;a:5:{s:4:"data";s:11:"zigbee2mqtt";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}s:32:"http://purl.org/dc/elements/1.1/";a:1:{s:9:"publisher";a:1:{i:0;a:5:{s:4:"data";s:5:"Admin";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}s:52:"http://madskills.com/public/xml/rss/module/pingback/";a:2:{s:6:"server";a:1:{i:0;a:5:{s:4:"data";s:32:"http://canaletto.fr/pingback.axd";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:6:"target";a:1:{i:0;a:5:{s:4:"data";s:69:"http://canaletto.fr/post.aspx?id=c9296c49-547e-42ae-b4be-7a9cedd65947";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}s:38:"http://purl.org/rss/1.0/modules/slash/";a:1:{s:8:"comments";a:1:{i:0;a:5:{s:4:"data";s:1:"5";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}s:53:"http://madskills.com/public/xml/rss/module/trackback/";a:1:{s:4:"ping";a:1:{i:0;a:5:{s:4:"data";s:73:"http://canaletto.fr/trackback.axd?id=c9296c49-547e-42ae-b4be-7a9cedd65947";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}s:36:"http://wellformedweb.org/CommentAPI/";a:2:{s:7:"comment";a:1:{i:0;a:5:{s:4:"data";s:66:"http://canaletto.fr/post/home-assistant-zigbee-and-legrand#comment";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:10:"commentRss";a:1:{i:0;a:5:{s:4:"data";s:77:"http://canaletto.fr/syndication.axd?post=c9296c49-547e-42ae-b4be-7a9cedd65947";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}}}i:2;a:6:{s:4:"data";s:159:"
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
    ";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";s:5:"child";a:7:{s:0:"";a:7:{s:5:"title";a:1:{i:0;a:5:{s:4:"data";s:29:"Home Assistant &amp; Mi Boxer";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:11:"description";a:1:{i:0;a:5:{s:4:"data";s:14571:"<p style="text-align: justify;">J'avais <a href="https://amzn.to/46hQBZR" target="_blank" rel="noopener">achet&eacute; cette t&eacute;l&eacute;commande Mi Boxer</a> il y a quelques mois afin de g&eacute;rer les &eacute;clairages de mon s&eacute;jour, en me disant que les curseurs seraient plus pratiques que mon <a href="https://fr.aliexpress.com/item/1005002219929565.html" target="_blank" rel="noopener">Opple</a> avec ses 6 boutons actuelle. H&eacute;las elle n'&eacute;tait reconnue nulle part et avait termin&eacute; sa course dans le tiroir aux oubliettes du Zigbee...</p>
<p style="text-align: center;"><img src="http://canaletto.fr/image.axd?picture=/images/MiBoxer2.jpg" width="397" height="369" /></p>
<p style="text-align: justify;">C'&eacute;tait sans compter sur la t&eacute;nacit&eacute; de quelques amateurs de reverse engineering sur lesquels je suis tomb&eacute; il y a quelques semaines et qui on <a href="https://github.com/Koenkk/zigbee2mqtt/issues/10708" target="_blank" rel="noopener">fait un travail formidable</a> qui a aboutit &agrave; <a href="https://www.zigbee2mqtt.io/devices/FUT089Z.html#exposing-the-controls" target="_blank" rel="noopener">une extension</a> pour Zigbee2MQTT, ce qui rend cette t&eacute;l&eacute;commande enfin utilisable, tout au moins partiellement pour l'instant. Mais l'essentiel est l&agrave; !</p>
<p style="text-align: justify;"><strong>Ce qui fonctionne :</strong></p>
<ul style="text-align: justify;">
<li>7 boutons avec ON et OFF (deux actions et non un toggle). Celui du bas &agrave; droite n'est pas actif et je vous d&eacute;conseille de l'utiliser...</li>
<li>1 bouton avec ON et OFF (en haut)</li>
<li>1 bouton W (si on veut bricoler...)</li>
<li>La barre de r&eacute;glage de la luminosit&eacute;</li>
<li>La remont&eacute;e de l'&eacute;tat de la batterie</li>
</ul>
<p style="text-align: justify;"><strong>Ce qui ne fonctionne pas (pour l'instant) :</strong></p>
<ul style="text-align: justify;">
<li>La barre de r&eacute;glage des couleurs</li>
<li>La barre de r&eacute;glage de la temp&eacute;rature du blanc</li>
<li>Les touches RGB</li>
<li>Les touches de temporisation (en bas &agrave; droite)</li>
</ul>
<p style="text-align: justify;">Une fois la t&eacute;l&eacute;commande reconnue sous Z2M on peut commencer &agrave; cr&eacute;er des actions. On remarque tout de suite que l'affaire va manquer de <code>sensor:</code> et que certains ne fonctionnent pas. Pas de panique, il y a une solution comme je vais vous le d&eacute;monter avec l'<code>automation:</code> qui suit.&nbsp;</p>
<p style="text-align: justify;">J'ai fait un m&eacute;lange de <code>choose:</code> / <code>conditions:</code> / <code>trigger.id</code> . C'est un peu long, mais je la colle en entier ce qui vous &eacute;vitera une fastidieuse saisie. Il faudra tout de m&ecirc;me y coller vous <code>id:</code> et <code>entity:</code> ! Ah j'allais oublier, il faut aussi ajouter un petit <code>input_select:</code> ...</p>
<p style="text-align: justify;">J'ai tent&eacute; de faire &ccedil;a avec ControllerX que j'adore et qui me sert pour toutes mes t&eacute;l&eacute;commandes, mais pour l'instant c'est un &eacute;chec !</p>
<pre class="language-yaml"><code>alias: GUI - Mi Boxer
description: ""
trigger:
  - platform: state
    entity_id:
      - sensor.mi_boxeur_brightness
    id: bright
  - platform: device
    domain: mqtt
    device_id: 86c1403c24491ce021ac3ee081a86308
    type: button_short_press
    subtype: button_group_1_on
    discovery_id: 0x003c84fffec29c71_zone_1_button_on
    id: 1on
  - platform: device
    domain: mqtt
    device_id: 86c1403c24491ce021ac3ee081a86308
    type: button_short_press
    subtype: button_group_1_off
    discovery_id: 0x003c84fffec29c71_zone_1_button_off
    id: 1off
  - platform: device
    domain: mqtt
    device_id: 86c1403c24491ce021ac3ee081a86308
    type: button_short_press
    subtype: button_group_2_on
    discovery_id: 0x003c84fffec29c71_zone_2_button_on
    id: 2on
  - platform: device
    domain: mqtt
    device_id: 86c1403c24491ce021ac3ee081a86308
    type: button_short_press
    subtype: button_group_2_off
    discovery_id: 0x003c84fffec29c71_zone_2_button_off
    id: 2off
  - platform: device
    domain: mqtt
    device_id: 86c1403c24491ce021ac3ee081a86308
    type: button_short_press
    subtype: button_group_3_on
    discovery_id: 0x003c84fffec29c71_zone_3_button_on
    id: 3on
  - platform: device
    domain: mqtt
    device_id: 86c1403c24491ce021ac3ee081a86308
    type: button_short_press
    subtype: button_group_3_off
    discovery_id: 0x003c84fffec29c71_zone_3_button_off
    id: 3off
  - platform: device
    domain: mqtt
    device_id: 86c1403c24491ce021ac3ee081a86308
    type: button_short_press
    subtype: button_group_4_on
    discovery_id: 0x003c84fffec29c71_zone_4_button_on
    id: 4on
  - platform: device
    domain: mqtt
    device_id: 86c1403c24491ce021ac3ee081a86308
    type: button_short_press
    subtype: button_group_4_off
    discovery_id: 0x003c84fffec29c71_zone_4_button_off
    id: 4off
  - platform: device
    domain: mqtt
    device_id: 86c1403c24491ce021ac3ee081a86308
    type: button_short_press
    subtype: button_group_5_on
    discovery_id: 0x003c84fffec29c71_zone_5_button_on
    id: 5on
  - platform: device
    domain: mqtt
    device_id: 86c1403c24491ce021ac3ee081a86308
    type: button_short_press
    subtype: button_group_5_off
    discovery_id: 0x003c84fffec29c71_zone_5_button_off
    id: 5off
  - platform: device
    domain: mqtt
    device_id: 86c1403c24491ce021ac3ee081a86308
    type: button_short_press
    subtype: button_group_6_on
    discovery_id: 0x003c84fffec29c71_zone_6_button_on
    id: 6on
  - platform: device
    domain: mqtt
    device_id: 86c1403c24491ce021ac3ee081a86308
    type: button_short_press
    subtype: button_group_6_off
    discovery_id: 0x003c84fffec29c71_zone_6_button_off
    id: 6off
  - platform: device
    domain: mqtt
    device_id: 86c1403c24491ce021ac3ee081a86308
    type: button_short_press
    subtype: button_group_7_on
    discovery_id: 0x003c84fffec29c71_zone_7_button_on
    id: 7on
  - platform: device
    domain: mqtt
    device_id: 86c1403c24491ce021ac3ee081a86308
    type: button_short_press
    subtype: button_group_7_off
    discovery_id: 0x003c84fffec29c71_zone_7_button_off
    id: 7off
  - platform: device
    domain: mqtt
    device_id: 86c1403c24491ce021ac3ee081a86308
    type: button_short_press
    subtype: button_group_8_on
    discovery_id: 0x003c84fffec29c71_zone_8_button_on
    id: 8on
  - platform: device
    domain: mqtt
    device_id: 86c1403c24491ce021ac3ee081a86308
    type: button_short_press
    subtype: button_group_8_off
    discovery_id: 0x003c84fffec29c71_zone_8_button_off
    id: 8off
    
condition: []
action:
  - choose:
      - conditions: "{{ trigger.id in ['1on'] }}"
        sequence:
          - service: light.turn_on
            data: {}
            target:
              entity_id: light.shellydimmer_f3d426
          - service: input_select.select_option
            data:
              option: "1"
            target:
              entity_id: input_select.mi_boxer_select
      - conditions: "{{ trigger.id in ['1off'] }}"
        sequence:
          - service: light.turn_off
            data: {}
            target:
              entity_id: light.shellydimmer_f3d426

      - conditions: "{{ trigger.id in ['2on'] }}"
        sequence:
          - service: light.turn_on
            data: {}
            target:
              entity_id: light.shellydimmer_d3e57c
          - service: input_select.select_option
            data:
              option: "2"
            target:
              entity_id: input_select.mi_boxer_select
      - conditions: "{{ trigger.id in ['2off'] }}"
        sequence:
          - service: light.turn_off
            data: {}
            target:
              entity_id: light.shellydimmer_d3e57c

      - conditions: "{{ trigger.id in ['3on'] }}"
        sequence:
          - service: light.turn_on
            data: {}
            target:
              entity_id: light.ikea_e27_tv
          - service: input_select.select_option
            data:
              option: "3"
            target:
              entity_id: input_select.mi_boxer_select
      - conditions: "{{ trigger.id in ['3off'] }}"
        sequence:
          - service: light.turn_off
            data: {}
            target:
              entity_id: light.ikea_e27_tv

      - conditions: "{{ trigger.id in ['4on'] }}"
        sequence:
          - service: light.turn_on
            data: {}
            target:
              entity_id: light.lidl_led_stand
          - service: input_select.select_option
            data:
              option: "4"
            target:
              entity_id: input_select.mi_boxer_select
      - conditions: "{{ trigger.id in ['4off'] }}"
        sequence:
          - service: light.turn_off
            data: {}
            target:
              entity_id: light.lidl_led_stand

      - conditions: "{{ trigger.id in ['5on'] }}"
        sequence:
          - service: light.turn_on
            data: {}
            target:
              entity_id: light.dimmable_sm309
          - service: input_select.select_option
            data:
              option: "5"
            target:
              entity_id: input_select.mi_boxer_select
      - conditions: "{{ trigger.id in ['5off'] }}"
        sequence:
          - service: light.turn_off
            data: {}
            target:
              entity_id: light.dimmable_sm309

      - conditions: "{{ trigger.id in ['6on'] }}"
        sequence:
          - service: light.turn_on
            data: {}
            target:
              entity_id: light.shelly_bulb_1
          - service: input_select.select_option
            data:
              option: "6"
            target:
              entity_id: input_select.mi_boxer_select
      - conditions: "{{ trigger.id in ['6off'] }}"
        sequence:
          - service: light.turn_off
            data: {}
            target:
              entity_id: light.shelly_bulb_1

      - conditions: "{{ trigger.id in ['7on'] }}"
        sequence:
          - service: light.turn_on
            data: {}
            target:
              entity_id: light.led_strip_1
          - service: input_select.select_option
            data:
              option: "7"
            target:
              entity_id: input_select.mi_boxer_select
      - conditions: "{{ trigger.id in ['7off'] }}"
        sequence:
          - service: light.turn_off
            data: {}
            target:
              entity_id: light.led_strip_1

      - conditions: "{{ trigger.id in ['8on'] }}"
        sequence:
          - service: light.turn_on
            data: {}
            target:
              entity_id: 
                - light.shellydimmer_f3d426
                - light.shellydimmer_d3e57c
                - light.ikea_e27_tv
                - light.dimmable_sm309
                - light.shelly_bulb_1
                - light.lidl_led_stand
                - light.plug_tz_10_switch
                - light.led_strip_1
          - service: input_select.select_option
            data:
              option: "8"
            target:
              entity_id: input_select.mi_boxer_select
      - conditions: "{{ trigger.id in ['8off'] }}"
        sequence:
          - service: light.turn_off
            data: {}
            target:
              entity_id: 
                - light.shellydimmer_f3d426
                - light.shellydimmer_d3e57c
                - light.ikea_e27_tv
                - light.dimmable_sm309
                - light.shelly_bulb_1
                - light.lidl_led_stand
                - light.plug_tz_10_switch
                - light.led_strip_1
              
      - conditions: &gt;-
          {{ is_state('input_select.mi_boxer_select', '1') and trigger.id in ['bright'] }}
        sequence:
          - service: light.turn_on
            data:
              brightness_pct: "{{ trigger.to_state.state }}"
              transition: 0.2
            target:
              entity_id: light.shellydimmer_f3d426
            enabled: true

      - conditions: &gt;-
          {{ is_state('input_select.mi_boxer_select', '2') and trigger.id in ['bright'] }}
        sequence:
          - service: light.turn_on
            data:
              brightness_pct: "{{ trigger.to_state.state }}"
              transition: 0.2
            target:
              device_id: 1ff4112785e14b8b8cba18d45fec3b11
            enabled: true

      - conditions: &gt;-
          {{ is_state('input_select.mi_boxer_select', '3') and trigger.id in ['bright'] }}
        sequence:
          - service: light.turn_on
            data:
              brightness_pct: "{{ trigger.to_state.state }}"
              transition: 0.2
            target:
              entity_id: light.ikea_e27_tv
            enabled: true

      - conditions: &gt;-
          {{ is_state('input_select.mi_boxer_select', '4') and trigger.id in ['bright'] }}
        sequence:
          - service: light.turn_on
            data:
              brightness_pct: "{{ trigger.to_state.state }}"
              transition: 0.2
            target:
              entity_id: light.lidl_led_stand
            enabled: true

      - conditions: &gt;-
          {{ is_state('input_select.mi_boxer_select', '5') and trigger.id in ['bright'] }}
        sequence:
          - service: light.turn_on
            data:
              brightness_pct: "{{ trigger.to_state.state }}"
              transition: 0.2
            target:
              entity_id: light.dimmable_sm309
            enabled: true

      - conditions: &gt;-
          {{ is_state('input_select.mi_boxer_select', '6') and trigger.id in ['bright'] }}
        sequence:
          - service: light.turn_on
            data:
              brightness_pct: "{{ trigger.to_state.state }}"
              transition: 0.2
            target:
              entity_id: light.shelly_bulb_1
            enabled: true

      - conditions: &gt;-
          {{ is_state('input_select.mi_boxer_select', '7') and trigger.id in ['bright'] }}
        sequence:
          - service: light.turn_on
            data:
              brightness_pct: "{{ trigger.to_state.state }}"
              transition: 0.2
            target:
              entity_id: light.led_strip_1
            enabled: true
mode: restart</code></pre>
<p style="text-align: center;"><img src="http://canaletto.fr/image.axd?picture=/images/enjoy2.jpg" width="269" height="180" /></p>";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:4:"link";a:1:{i:0;a:5:{s:4:"data";s:52:"http://canaletto.fr/post/home-assistant-and-mi-boxer";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:8:"comments";a:1:{i:0;a:5:{s:4:"data";s:60:"http://canaletto.fr/post/home-assistant-and-mi-boxer#comment";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:4:"guid";a:1:{i:0;a:5:{s:4:"data";s:69:"http://canaletto.fr/post.aspx?id=569246a8-f03b-4657-90f7-6b063e6def16";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:7:"pubDate";a:1:{i:0;a:5:{s:4:"data";s:33:"jeu., 16 nov. 2023 21:29:00 +0100";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:8:"category";a:1:{i:0;a:5:{s:4:"data";s:9:"Domotique";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}s:34:"https://blogengine.io/schemas/tags";a:1:{s:3:"tag";a:8:{i:0;a:5:{s:4:"data";s:14:"Home Assistant";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:1;a:5:{s:4:"data";s:4:"HASS";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:2;a:5:{s:4:"data";s:6:"Hassio";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:3;a:5:{s:4:"data";s:6:"zigbee";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:4;a:5:{s:4:"data";s:11:"zigbee2mqtt";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:5;a:5:{s:4:"data";s:3:"Z2M";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:6;a:5:{s:4:"data";s:8:"Mi Boxer";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:7;a:5:{s:4:"data";s:6:"Remote";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}s:32:"http://purl.org/dc/elements/1.1/";a:1:{s:9:"publisher";a:1:{i:0;a:5:{s:4:"data";s:5:"Admin";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}s:52:"http://madskills.com/public/xml/rss/module/pingback/";a:2:{s:6:"server";a:1:{i:0;a:5:{s:4:"data";s:32:"http://canaletto.fr/pingback.axd";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:6:"target";a:1:{i:0;a:5:{s:4:"data";s:69:"http://canaletto.fr/post.aspx?id=569246a8-f03b-4657-90f7-6b063e6def16";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}s:38:"http://purl.org/rss/1.0/modules/slash/";a:1:{s:8:"comments";a:1:{i:0;a:5:{s:4:"data";s:1:"0";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}s:53:"http://madskills.com/public/xml/rss/module/trackback/";a:1:{s:4:"ping";a:1:{i:0;a:5:{s:4:"data";s:73:"http://canaletto.fr/trackback.axd?id=569246a8-f03b-4657-90f7-6b063e6def16";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}s:36:"http://wellformedweb.org/CommentAPI/";a:2:{s:7:"comment";a:1:{i:0;a:5:{s:4:"data";s:60:"http://canaletto.fr/post/home-assistant-and-mi-boxer#comment";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:10:"commentRss";a:1:{i:0;a:5:{s:4:"data";s:77:"http://canaletto.fr/syndication.axd?post=569246a8-f03b-4657-90f7-6b063e6def16";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}}}i:3;a:6:{s:4:"data";s:138:"
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
    ";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";s:5:"child";a:7:{s:0:"";a:7:{s:5:"title";a:1:{i:0;a:5:{s:4:"data";s:8:"RustDesk";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:11:"description";a:1:{i:0;a:5:{s:4:"data";s:15848:"<p style="text-align: justify;">Au fil des ans TeamViewer s&rsquo;est impos&eacute; dans l'IT. Au d&eacute;part pseudo gratuit ce produit offre maintenant de plus en plus de fonctionnalit&eacute;s (souvent inutiles) et son cout augmente d&rsquo;ann&eacute;es en ann&eacute;es. On pourrait imaginer le remplacer par AnyDesk, mais h&eacute;las leur politique est quasiment identique et ce serait reculer pour mieux sauter.</p>
<p style="text-align: justify;">Pendant le confinement certains en ont eu assez de se faire &ldquo;raquetter&rdquo;. Si le mot vous parait fort, constatez simplement les augmentations successives dont la derni&egrave;re de 20% que rien ne justifie &agrave; mes yeux, l'&eacute;diteur se justifiant quant &agrave; lui par l'ajout de fonctionnalit&eacute;s qui me sont inutiles. Entendons nous bien, tout a un prix et tout travail ou service m&eacute;rite une r&eacute;mun&eacute;ration, mais tout doit rester dans la nuance, m&ecirc;me quand on se retrouve dans une position de domination, ce qui est d'ailleurs le cas pour d'autres, comme Microsoft et ses derni&egrave;res augmentations au niveau 365 ou Azure...</p>
<p style="text-align: center;"><img style="text-align: center;" src="http://canaletto.fr/image.axd?picture=/images/rustedesk_000.png" /></p>
<p style="text-align: justify;">Bref, c'est donc ainsi qu'une petite &eacute;quipe de d&eacute;veloppeurs a cr&eacute;&eacute; <a href="https://rustdesk.com/" target="_blank" rel="noopener">RustDesk</a>. RustDesk offre les m&ecirc;mes fonctionnalit&eacute;s de base dans le cadre de l&rsquo;open source. Je teste Rustdesk depuis pr&egrave;s d&rsquo;un an et j&rsquo;estime que l&rsquo;heure est venue de franchir le pas.</p>
<p style="text-align: justify;">RustDesk est <a href="https://github.com/rustdesk/rustdesk/releases" target="_blank" rel="noopener">disponible</a> sous diff&eacute;rentes distributions Linux, MacOS, Windows, Android et IOS.</p>
<h2 style="text-align: justify;">Il existe plusieurs fa&ccedil;ons d&rsquo;utiliser RustDesk :</h2>
<h3 style="text-align: justify;">Version isol&eacute;e sans serveur</h3>
<p style="text-align: justify;">La plus simple et totalement gratuite, mais qui pr&eacute;sente quelques inconv&eacute;nients :</p>
<ul style="text-align: justify;">
<li>Pas de chiffrement, cela veut dire que toutes les infos circulent en clair (pas s&eacute;cure pour les clients, mauvaise pratique).</li>
<li>Lenteurs possibles car &ccedil;a utilise les serveurs publics, ce qui reste limit&eacute;.</li>
<li>Pas de carnet d&rsquo;adresse synchronis&eacute; entre les devices clients. Et l&agrave; &ccedil;a bloque car comme beaucoup de monde j'utilise un PC fixe au bureau et un laptop quand je me d&eacute;place, sur lequel je souhaite retrouver mon environnement de travail. Ils auraient pu envisager une synchronisation de type "drive", mais cela aurait pos&eacute; des questions de s&eacute;curit&eacute; car en plus de synchroniser les identifiants il faut stocker des mots de passe.</li>
</ul>
<h3 style="text-align: justify;">Version gratuite avec serveur</h3>
<p style="text-align: justify;">Toujours gratuit (en dehors du cout d'un serveur VPS (qui peut &ecirc;tre mutualis&eacute;)), et on r&eacute;sous la question du chiffrement :</p>
<ul style="text-align: justify;">
<li>Le serveur sert de relais (am&eacute;lioration de la vitesse) et de serveur de chiffrement afin de s&eacute;curiser les liens.</li>
</ul>
<h3 style="text-align: justify;">Version payante avec serveur priv&eacute;</h3>
<p style="text-align: justify;">La totale qui va <a href="https://rustdesk.com/pricing.html">couter quelques euros</a> (10 &euro; / mois pour deux utilisateurs, ou 20 &euro; /mois pour 20 utilisateurs + le serveur), mais &agrave; mon sens indispensable dans un cadre professionnel</p>
<ul style="text-align: justify;">
<li>Le serveur offre une console qui permet de lister les clients install&eacute;s et &eacute;ventuellement les partager
<ul>
<li>Seul l&rsquo;admin peut activer les partages &agrave; ce stade. Partager fait remonter les ID pour un autre utilisateur, mais le mot de passe associ&eacute; au device reste n&eacute;cessaire.</li>
</ul>
</li>
<li>Avoir des logs, qui se connecte &agrave; quoi (dispo pour chaque utilisateur), transferts de fichiers.</li>
<li>Changer l&rsquo;ID d&rsquo;un client</li>
<li>Utiliser un carnet d&rsquo;adresse qui sera synchronis&eacute; entre les clients de chaque utilisateur, mais non accessible &agrave; l&rsquo;admin.</li>
<li>Appliquer des strat&eacute;gies</li>
<li>Et d'autres fonctionnalit&eacute;s &agrave; venir car le projet est en constante &eacute;volution....</li>
</ul>
<p>Il n'existe pour l'instant pas de version Cloud et je n'ai pas le sentiment que ce soit dans l'ordre des priorit&eacute;s de l'&eacute;quipe.</p>
<h2 style="text-align: justify;">Installation</h2>
<p style="text-align: justify;">Je me place ici dans le cadre de la version serveur apr&egrave;s avoir acquis une licence.</p>
<p style="text-align: justify;">L'installation du serveur se fait sous Linux ou dans un container Docker. La proc&eacute;dure est d&eacute;crite <a href="https://rustdesk.com/docs/en/self-host/rustdesk-server-pro/" target="_blank" rel="noopener">ici</a> et je ne vais pas la reprendre. J'ai choisit Docker pour la facilit&eacute; d'un Compose...</p>
<p style="text-align: justify;">Cot&eacute; client, contrairement &agrave; TeamViewer qui fonctionne uniquement avec une infrastructure cloud, RustDesk fonctionne avec une infrastructure priv&eacute;e si l&rsquo;on veut disposer de toutes ses fonctionnalit&eacute;s. Quand on installe le client il va donc falloir configurer les informations li&eacute;es au serveur. Ce device sera alors uniquement accessible par des clients &eacute;galement configur&eacute;s pour ce serveur (tout au moins pour l&rsquo;instant car il y a des &eacute;volutions en cours).</p>
<p style="text-align: justify;">Pour configurer le client afin qu&rsquo;il soit reconnu par le serveur on a plusieurs solutions :</p>
<ul style="text-align: justify;">
<li>Soit on installe l&rsquo;exe normalement et on copie la config dans ID / Relay server</li>
</ul>
<blockquote><code class="language-powershell">Qfi0TWlxGWrUdfqdsfVENxxxxxxxxxxxxxxxxxxxxxxxqfsqdfN3boJye
</code></blockquote>
<p style="text-align: center;"><img src="http://canaletto.fr/image.axd?picture=/images/rustedesk_01.png" width="500" /></p>
<ul style="text-align: justify;">
<li>Soit on renomme l&rsquo;exe d&rsquo;installation afin d&rsquo;y int&eacute;grer la cl&eacute;, ce qui va donner quelque chose du genre:</li>
</ul>
<blockquote><code class="language-powershell">rustdesk-licensed-Qfi0TWlxGWrUkR5Vxxxxxxxdfsdfsdfsdfye.exe
</code></blockquote>
<ul style="text-align: justify;">
<li>Soit on cr&eacute;e un script de d&eacute;ploiement et ainsi appliquer la configuration apr&egrave;s l&rsquo;installation dans le cadre d&rsquo;un script PowerShell, on dispose alors de ces trois commandes, et on verra plus bas ce &agrave; quoi peut ressembler un script de d&eacute;ploiement&nbsp; :<br /><br /></li>
</ul>
<h3 style="text-align: justify;">Se connecter</h3>
<p style="text-align: justify;">En g&eacute;n&eacute;ral quand on utilise ce genre de produit, souvent pour de l'assistance client ou de la gestion de serveurs, il y a deux types d'installations :</p>
<ul>
<li style="text-align: center;">Le device client, le mien, sur lequel apr&egrave;s avoir configur&eacute; le serveur (chapitre pr&eacute;c&eacute;dent), je vais me connecter avec l'identifiant fournit par l'administrateur du serveur :&nbsp;<br /><img src="http://canaletto.fr/image.axd?picture=/images/rustedesk_02.png" width="500" /></li>
<li style="text-align: justify;">Le device distant auquel on va affecter (ou pas) un utilisateur</li>
</ul>
<h3 style="text-align: justify;">Affecter un device &agrave; un utilisateur</h3>
<p style="text-align: justify;">Si on affecte un device &agrave; un utilisateur, cet utilisateur (et uniquement lui) verra ce device distant monter dans son logiciel client. Il pourra &eacute;galement l&rsquo;ajouter &agrave; son carnet d&rsquo;adresse personnel. Si on ne l'affecte pas, tous les utilisateurs le verront, pourront l'ajouter &agrave; leur carnet d'adresse et s'y connecter (sous r&eacute;serve de disposer du mot de passe pr&eacute;alablement d&eacute;fini).</p>
<p style="text-align: justify;">Des fonctionnalit&eacute;s de groupe et de partage de groupe sont &eacute;galement pr&eacute;vues. Il est ainsi possible de partager les devises affect&eacute;s &agrave; un groupe &agrave; un autre utilisateur. A noter que pour l'instant <code>groupe = utilisateur</code> et que l'on ne peut pas directement affecter des devices &agrave; un groupe isol&eacute;. La solution consiste donc &agrave; cr&eacute;er un utilisateur virtuel qui partagera ses devices avec d'autres utilisateurs. Par exemple j'ai cr&eacute;&eacute; un utilisateur virtuel <em>Soci&eacute;t&eacute; A</em> qui partage ses devices avec les deux personnes charg&eacute;s de la maintenance de <em>Soci&eacute;t&eacute; A.</em> Ca consomme une licence utilisateur mais je n'ai pas trouv&eacute; mieux pour l'instant.</p>
<p style="text-align: center;"><img src="http://canaletto.fr/image.axd?picture=/images/rustedesk_03.png" /></p>
<p style="text-align: justify;">Il existe plusieurs fa&ccedil;ons pour y parvenir :</p>
<ul style="text-align: justify;">
<li>En se connectant avec son user/password (mais c&rsquo;est une tr&egrave;s mauvaise id&eacute;e que de faire &ccedil;a sur le PC d&rsquo;un client)</li>
<li>En l&rsquo;associant dans l&rsquo;interface d&rsquo;administrateur (mais seul l&rsquo;admin peut le faire)</li>
<li>En utilisant l&rsquo;API sur le client dans le cadre d&rsquo;un d&eacute;ploiement vie un script</li>
</ul>
<p style="text-align: justify;">Pour &ccedil;a il faut un token. Les tokens qui permettent l&rsquo;acc&egrave;s &agrave; l&rsquo;API sont d&eacute;livr&eacute;s par l&rsquo;admin.</p>
<pre class="language-powershell"><code>PS C:\Program Files\RustDesk&gt;.\RustDesk.exe  &ndash;assign &ndash;token "rapi_xxxxxxxxdyw==" &ndash;user_name &ldquo;admin&rdquo; | more</code></pre>
<h3 style="text-align: justify;">La console</h3>
<p style="text-align: justify;">Chaque utilisateur peut voir la liste de ses devices, l&rsquo;&eacute;tat de la connexion ainsi que diverses infos (par exemple :</p>
<blockquote>
<p style="text-align: justify;"><code>ip: <a href="http://82.65.xxx.xxx">82.65.xxx.xxx</a>;<br /> version: 1.2.3;<br /> cpu: Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz, 2.53GHz, 4/4 cores; mem: 8GB</code></p>
</blockquote>
<p style="text-align: justify;">Un log est &eacute;galement disponible tant pour les connections que pour les transferts de fichiers. Cette console est destin&eacute;e &agrave; &eacute;voluer pour plus de fonctionnalit&eacute;s.</p>
<p style="text-align: justify;">L'administrateur peut quant &agrave; lui, outre g&eacute;rer utilisateurs et devices, affecter des strat&eacute;gies aux utilisateurs et devices :</p>
<p style="text-align: center;"><img src="http://canaletto.fr/image.axd?picture=/images/rustedesk_04.png" /></p>
<h3 style="text-align: justify;">Script PowerShell d&rsquo;installation</h3>
<p style="text-align: justify;">On ne dispose pour l'instant pas de .msi et ce script est un peu simpliste (il en existe pour d'autres O/S <a href="https://rustdesk.com/docs/en/self-host/client-deployment/" target="_blank" rel="noopener">ici</a>). Pour faire simple je conseille d&rsquo;ouvrir une session PS en mode admin. Mais il est &eacute;galement possible de faire une &eacute;l&eacute;vation dans le script (voir &agrave; la fin). Pour l&rsquo;instant attention &agrave; indiquer la version de l'exe sur la bonne ligne&hellip;</p>
<pre class="language-yaml"><code>################################# VARIABLES #######################################
$rustdesk_pw="PasswordPermanent"  # Celui du device distant
$rustdesk_token="MonTocken"
$rustdesk_cfg="Qfi0TWlxxxxxxxxxxxxxxxxxxxxxxxxxxN3boJye" # Cl&eacute; de configuration
$ErrorActionPreference= 'silentlycontinue'
################################### SCRIPT ########################################

If (!(Test-Path C:\Temp))
{
    New-Item -ItemType Directory -Force -Path C:\Temp &gt; null
}
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
cd C:\Temp
Invoke-WebRequest "https://github.com/rustdesk/rustdesk/releases/download/1.2.3/rustdesk-1.2.3-x86_64.exe" -Outfile "rustdesk.exe" # Changer la version le cas &eacute;ch&eacute;ant

Start-Process .\rustdesk.exe --silent-install # -wait
$ServiceName = 'Rustdesk'
$arrService = Get-Service -Name $ServiceName -ErrorAction SilentlyContinue

if ($arrService -eq $null)
{
    Start-Sleep -seconds 20
}
cd $env:ProgramFiles\RustDesk\
$rustdesk_id = (.\RustDesk.exe --get-id | out-host)

.\RustDesk.exe --config $rustdesk_cfg | out-host
.\RustDesk.exe --password $rustdesk_pw | out-host
Start-Sleep -Seconds 5
.\RustDesk.exe --assign --token $rustdesk_token --user_name manu | out-host</code></pre>
<p style="text-align: justify;"><strong>El&eacute;vation</strong> (le cas &eacute;ch&eacute;ant &agrave; ajouter au d&eacute;but du script)</p>
<pre class="language-powershell"><code>if (-Not ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
    if ([int](Get-CimInstance -Class Win32_OperatingSystem | Select-Object -ExpandProperty BuildNumber) -ge 6000) {
        Start-Process PowerShell -Verb RunAs -ArgumentList "-NoProfile -ExecutionPolicy Bypass -Command `"cd '$pwd'; &amp; '$PSCommandPath';`"";
        Exit;
    }
}</code></pre>
<h3 style="text-align: justify;">Le cas des serveurs Windows et du RDP</h3>
<p style="text-align: justify;">Si on installe RustDesk sur un serveur Windows va se retrouver face &agrave; deux possibilit&eacute;s, activer ou pas le partage de session RDP (une probl&eacute;matique identique existe avec TeamViewer qui a choisit de fournir deux ID, cela concerne principalement les administrateurs de serveurs, qu&rsquo;ils soient premise ou cloud) :</p>
<p><img style="display: block; margin-left: auto; margin-right: auto;" src="http://canaletto.fr/image.axd?picture=/images/rustedesk_05.png" /></p>
<ul style="text-align: justify;">
<li><strong>Non activ&eacute; :</strong> RustDesk va proposer une ouverture de session, il est possible d&rsquo;enregistrer le mot de passe dans le client, et cette ouverture de session d&eacute;connectera l&rsquo;&eacute;ventuel utilisateur connect&eacute; en RDP.</li>
<li><strong>Activ&eacute; :</strong> Dans ce cas RustDesk partage la connexion RDP active et si on d&eacute;connecte la session RDP &ccedil;a d&eacute;connecte la session RustDesk (qui peut toutefois se reconnecter s&rsquo;il dispose des identifiants Windows.
<ul>
<li>Il existe toutefois un probl&egrave;me, dans ce mode rien ne permet actuellement de choisir la session sur laquelle va s&rsquo;op&eacute;rer le partage, il y a donc un risque de se concerter sur la session d&rsquo;un utilisateur actif dans le cas d&rsquo;un serveur de bureaux virtuels. (<a href="https://github.com/rustdesk/rustdesk-server-pro/issues/132" target="_blank" rel="noopener">ticket ouvert</a> en cours).</li>
</ul>
</li>
</ul>
<p style="text-align: justify;"><!-- notionvc: e35aebc7-b0a2-4f1b-b7d6-44dd44071be6 --></p>
<h2 style="text-align: justify;">Conclusion</h2>
<p style="text-align: justify;">RustDesk est constante &eacute;volution et j'y reviendrait certainement ici. En attendant j'ai d&eacute;ploy&eacute; une trentaine de devices sans observer de probl&egrave;mes particulier si je compare &agrave; mon classique TeamViewer.</p>
<p style="text-align: center;"><img src="http://canaletto.fr/image.axd?picture=/images/enjoyit.png" width="258" height="258" /></p>";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:4:"link";a:1:{i:0;a:5:{s:4:"data";s:33:"http://canaletto.fr/post/rustdesk";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:8:"comments";a:1:{i:0;a:5:{s:4:"data";s:41:"http://canaletto.fr/post/rustdesk#comment";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:4:"guid";a:1:{i:0;a:5:{s:4:"data";s:69:"http://canaletto.fr/post.aspx?id=e5d7b70a-11e0-4cc0-affb-00e324cf8389";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:7:"pubDate";a:1:{i:0;a:5:{s:4:"data";s:33:"lun., 23 oct. 2023 16:13:00 +0100";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:8:"category";a:2:{i:0;a:5:{s:4:"data";s:7:"IP & Co";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:1;a:5:{s:4:"data";s:2:"IT";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}s:34:"https://blogengine.io/schemas/tags";a:1:{s:3:"tag";a:4:{i:0;a:5:{s:4:"data";s:10:"TeamViewer";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:1;a:5:{s:4:"data";s:7:"AnuDesk";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:2;a:5:{s:4:"data";s:9:"Rustedesk";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:3;a:5:{s:4:"data";s:3:"RDP";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}s:32:"http://purl.org/dc/elements/1.1/";a:1:{s:9:"publisher";a:1:{i:0;a:5:{s:4:"data";s:5:"Admin";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}s:52:"http://madskills.com/public/xml/rss/module/pingback/";a:2:{s:6:"server";a:1:{i:0;a:5:{s:4:"data";s:32:"http://canaletto.fr/pingback.axd";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:6:"target";a:1:{i:0;a:5:{s:4:"data";s:69:"http://canaletto.fr/post.aspx?id=e5d7b70a-11e0-4cc0-affb-00e324cf8389";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}s:38:"http://purl.org/rss/1.0/modules/slash/";a:1:{s:8:"comments";a:1:{i:0;a:5:{s:4:"data";s:1:"0";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}s:53:"http://madskills.com/public/xml/rss/module/trackback/";a:1:{s:4:"ping";a:1:{i:0;a:5:{s:4:"data";s:73:"http://canaletto.fr/trackback.axd?id=e5d7b70a-11e0-4cc0-affb-00e324cf8389";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}s:36:"http://wellformedweb.org/CommentAPI/";a:2:{s:7:"comment";a:1:{i:0;a:5:{s:4:"data";s:41:"http://canaletto.fr/post/rustdesk#comment";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:10:"commentRss";a:1:{i:0;a:5:{s:4:"data";s:77:"http://canaletto.fr/syndication.axd?post=e5d7b70a-11e0-4cc0-affb-00e324cf8389";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}}}i:4;a:6:{s:4:"data";s:159:"
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
    ";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";s:5:"child";a:7:{s:0:"";a:7:{s:5:"title";a:1:{i:0;a:5:{s:4:"data";s:19:"RDP &amp; Guacamole";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:11:"description";a:1:{i:0;a:5:{s:4:"data";s:13329:"<p style="text-align: justify;">Et non, je ne suis h&eacute;las pas parti en vacances au Mexique d&eacute;guster du guacamole arros&eacute; de t&eacute;quila ! Mais j'ai trouv&eacute; la solution que je cherchait depuis longtemps pour s&eacute;curiser les acc&egrave;s RDP. Comme chacun le sait il n'est vraiment pas conseill&eacute; de laisser ouvert sur internet le port RDP qui est plut&ocirc;t vuln&eacute;rable. H&eacute;las pensant le confinement beaucoup de clients ont du mettre en place des solutions dans l'urgence et dans bien des cas il &eacute;tait impossible de verrouiller au minimum ce port sur une IP fixe....</p>
<p style="text-align: center;"><img src="http://canaletto.fr/image.axd?picture=/images/gua10.png" width="800" /></p>
<p style="text-align: justify;">Bien sur Microsoft a une solution (RDP Gateway), couteuse et complexe, donc pas adapt&eacute;e &agrave; de petites entreprises dont les couts IT explosent d&eacute;j&agrave;. Je restait donc en &eacute;veil &agrave; la recherche d'une solution quand je suis tomb&eacute; sur le projet open-source Guacamole en HTML5. Et surprise, celui ci fonctionne vraiment bien ! Le principe est simple et reprends celui des autres projets, une machine va servir de proxy afin d'exposer le RDP (mais aussi SSH, Telnet et VNC).</p>
<h3 style="text-align: justify;">Installation</h3>
<p style="text-align: justify;"><span style="text-align: justify;">S'il est possible d'installer Guacamole en natif comme c'est tr&egrave;s bien expliqu&eacute; ici, apr&egrave;s avoir test&eacute; diff&eacute;rentes options, par facilit&eacute; je vais faire &ccedil;a sous Docker en utilisant ce&nbsp;</span><a style="text-align: justify;" href="https://github.com/boschkundendienst/guacamole-docker-compose" target="_blank" rel="noopener">projet</a><span style="text-align: justify;">.</span></p>
<p style="text-align: justify;"><span style="text-align: justify;">Je vais donc monter une VM Linux Ubuntu et y configurer Docker et Docker Compose. Pour cette partie je vous laisse chercher, d'autres expliquent mieux que moi.</span></p>
<p><img style="text-align: justify; display: block; margin-left: auto; margin-right: auto;" src="http://canaletto.fr/image.axd?picture=/images/gua07.png" width="600" /></p>
<p style="text-align: justify;">Pour d&eacute;ployer Guacamole on a besoin de 3 services :</p>
<ul style="text-align: justify;">
<li>GUACD : Le c&oelig;ur de Guacamole qui va servir &agrave; connecter les diff&eacute;rents services (RDP, SSH, etc...)</li>
<li>PostgreSQL : Une base de donn&eacute;e (qui peut &ecirc;tre &eacute;galement MySQL ou encore l'utilisation d'une base externe)</li>
<li>Guacamole : Le composant FrontEnd qui va g&eacute;rer les connections, les services et les utilisateurs.</li>
</ul>
<p style="text-align: justify;"><strong>Docker Compose</strong></p>
<p style="text-align: justify;">L'auteur de l'int&eacute;gration a eu la bonne id&eacute;e de nous fournir un script d'installation. On va donc l'utiliser et on se servira de Docker Compose plus tard afin d'ajuster la configuration.</p>
<pre class="language-javascript"><code>sudo git clone "https://github.com/boschkundendienst/guacamole-docker-compose.git"
cd guacamole-docker-compose
./prepare.sh
sudo docker-compose up -d</code></pre>
<p style="text-align: justify;">Si tout se passe bien on peut se connecter sur <code>https://ip_serveur:8443/guacamole</code>. Le nom d'utilisateur par d&eacute;faut est <code>guacadmin</code> avec mot de passe <code>guacadmin</code>. La premi&egrave;re chose &agrave; faire est bien sur de le changer.</p>
<p style="text-align: justify;">On pourra facilement configurer un serveur RDP et s'y connecter pour avoir les premi&egrave;res impressions. Je trouve que le rendu RDP en HTML5 est fluide, m&ecirc;me en regardant des vid&eacute;os sur YouTube &agrave; une bonne r&eacute;solution. Attention &agrave; ne pas perdre de vue que c'est le serveur Guacamole qui doit encaisser le trafic entrant et sortant. Selon l'usage et le nombre de clients il faudra donc le dimensionner correctement.</p>
<p style="text-align: justify;">Je ne vais pas m'&eacute;tendre sur les diff&eacute;rentes options, l'interface et claire, la documentation &eacute;galement et d'autres en parlent tr&egrave;s bien.</p>
<h3 style="text-align: justify;">S&eacute;curisation</h3>
<p style="text-align: justify;">Il n'est bien sur pas question d'exposer ce serveur directement sur internet et je vais tester deux solutions de reverse proxy, je commence par &eacute;diter le fichier <code>docker-compose.yml</code> afin de supprimer le proxy Nginx pr&eacute;install&eacute; histoire de ne pas empiler les proxys. J'ajuste &eacute;galement en <code>8080:8080</code> pour une utilisation en direct et <code>REMOTE_IP_VALVE_ENABLED: 'true'</code>&nbsp; pour activer le proxy externe et <code>WEBAPP_CONTEXT: 'ROOT'</code> afin que Guacamole soit accessible en racine :</p>
<pre class="language-yaml"><code>version: '2.0'
networks:
  guacnetwork_compose:
    driver: bridge

services:
  # guacd
  guacd:
    container_name: guacd_compose
    image: guacamole/guacd
    networks:
      guacnetwork_compose:
    restart: always
    volumes:
    - ./drive:/drive:rw
    - ./record:/record:rw
  # postgres
  postgres:
    container_name: postgres_guacamole_compose
    environment:
      PGDATA: /var/lib/postgresql/data/guacamole
      POSTGRES_DB: guacamole_db
      POSTGRES_PASSWORD: 'ChooseYourOwnPasswordHere1234'
      POSTGRES_USER: guacamole_user
    image: postgres:15.2-alpine
    networks:
      guacnetwork_compose:
    restart: always
    volumes:
    - ./init:/docker-entrypoint-initdb.d:z
    - ./data:/var/lib/postgresql/data:Z

  guacamole:
    container_name: guacamole_compose
    depends_on:
    - guacd
    - postgres
    environment:
      REMOTE_IP_VALVE_ENABLED: 'true'   # On active ici l'utilisation via un proxy externe
      WEBAPP_CONTEXT: 'ROOT'
      GUACD_HOSTNAME: guacd
      POSTGRES_DATABASE: guacamole_db
      POSTGRES_HOSTNAME: postgres
      POSTGRES_PASSWORD: 'ChooseYourOwnPasswordHere1234'
      POSTGRES_USER: guacamole_user
    image: guacamole/guacamole
    volumes:
    - ./custom/server.xml:/home/administrator/guacamole-docker-compose/server.xml
    links:
    - guacd
    networks:
      guacnetwork_compose:
    ports:
    - 8080:8080
    restart: always</code></pre>
<p style="text-align: justify;">Je relance docker :</p>
<pre class="language-powershell"><code>administrator@guacamole:~/guacamole-docker-compose$ sudo docker-compose up -d</code></pre>
<p style="text-align: justify;">En local je me connecte maintenant en <code>http://ip_serveur:8080</code> sans SSL car le SSL sera g&eacute;r&eacute; par le proxy.</p>
<h4 style="text-align: justify;">Option 1 : pfsense</h4>
<p style="text-align: justify;">J'ai un pfsense install&eacute; avec HAProxy et Acme pour g&eacute;rer les certificats Lets'Encrypt, je vais donc me servir de ca pour publier le service. Sur HAProxy on configure le BackEnd et le FronteEnd qui lui utilisera le certificat pr&eacute;alablement cr&eacute;&eacute; avec Acme. Dans ma configuration je partage l'IP avec plusieurs sites et ce qui est important c'est d'activer l'option <code>forwardfor</code> qui permettra de transf&eacute;rer les adresses sources &agrave; Guacamole.</p>
<p style="text-align: justify;">Je mets ici le code de configuration qui sera utile &agrave; ceux qui n'utilisent pas HAProxy sous pfsense qui lui dispose d'une interface graphique. Comme on peut le constater le HTTP to HTTPS se fait au niveau du HAProxy et c'est lui &eacute;galement qui redirigera les requet&eacute;s HTTTP vers HTTPS et mon serveur sera accessible sur <code>https://guacamole.mondomaine.tld</code> :</p>
<pre class="language-markup"><code>global
  maxconn     10000
  stats socket /tmp/haproxy.socket level admin  expose-fd listeners
  uid     80
  gid     80
  nbproc      1
  nbthread      1
  hard-stop-after   15m
  chroot        /tmp/haproxy_chroot
  daemon
  tune.ssl.default-dh-param 1024
  server-state-file /tmp/haproxy_server_state

listen HAProxyLocalStats
  bind 127.0.0.1:2200 name localstats
  mode http
  stats enable
  stats admin if TRUE
  stats show-legends
  stats uri /haproxy/haproxy_stats.php?haproxystats=1
  timeout client 5000
  timeout connect 5000
  timeout server 5000

frontend Shared_WAN-merged
  bind      x.x.x.x:443 (IP WAN) name x.x.x.x:443 (IP WAN)   ssl crt-list /var/etc/haproxy/Shared_WAN.crt_list  
  mode      http
  log       global
  option    http-keep-alive
  option    forwardfor
  acl https ssl_fc
  http-request set-header   X-Forwarded-Proto http if !https
  http-request set-header   X-Forwarded-Proto https if https
  timeout client    30000
  acl     Admin var(txn.txnhost)      -m str -i admin.domain.tld
  acl     guacamole var(txn.txnhost)  -m str -i guacamole.domain.tld
  http-request set-var(txn.txnhost) hdr(host)
  use_backend Admin_ipvANY  if  Admin 
  use_backend Guacamole_8443_ipvANY  if  guacamole 

frontend http-to-https
  bind            x.x.x.x:80 (IP WAN) name x.x.x.x:80 (IP WAN)
  mode            http
  log             global
  option          http-keep-alive
  timeout client  30000
  http-request redirect code 301 location https://%[hdr(host)]%[path]  

backend Admin_ipvANY
  mode     http
  id       100
  log      global
  timeout  connect   30000
  timeout  server    30000
  retries  3
  server   admin 192.168.55.44:80 id 101  

backend Guacamole_8443_ipvANY
  mode     http
  id       102
  log      global
  timeout  connect   30000
  timeout  server    30000
  retries  3
  server   guacamole 192.168.66.55:8080 id 101</code></pre>
<h4 style="text-align: justify;">Option 2 : CloudFlared</h4>
<p style="text-align: justify;">Cette option est encore plus simple pour ceux qui disposent d'un domaine chez Cloudflare. On va utiliser les possibilit&eacute;s offertes gratuitement par Cloudflared et ajouter une couche de s&eacute;curit&eacute; suppl&eacute;mentaire.</p>
<p style="text-align: justify;">On commence par cr&eacute;er un tunnel CloudFlared avec une instance Docker suppl&eacute;mentaire (le code est fournit par le site de configuration Zero Trust de Cloudflare)</p>
<pre class="language-yaml"><code>docker run cloudflare/cloudflared:latest tunnel --no-autoupdate run --token eyJhIjoiZjk0YjdkZTBiMzFmYWNkNjZlshhsgfhsfghsgfhgfhssgfhsfgzRiMC00MmNlLWJjMghsfghsghsgfhsgfhsgfhsgmpaR00tyyretu(-yenebybvewWXpGaUxUazVNell0TnpRek56WXhNMlkxWXpFeiJ9</code></pre>
<p style="text-align: justify;">Ensuite une fois que le tunnel est mont&eacute;</p>
<p style="text-align: center;"><img src="http://canaletto.fr/image.axd?picture=/images/gua01.png" alt="" width="800" height="338" /></p>
<p style="text-align: justify;">On va publier et pointant sur l'ip priv&eacute;e et le port de notre serveur, cela va automatiquement cr&eacute;er l'entr&eacute;e DNS dans CloudFlare et g&eacute;rer la probl&eacute;matique du certificat. Ll sera accessible en SSL. :</p>
<p style="text-align: center;"><img src="http://canaletto.fr/image.axd?picture=/images/gua02.png" width="800" /></p>
<p style="text-align: justify;">Ensuite on va ajouter une couche de s&eacute;curit&eacute; suppl&eacute;mentaire en cr&eacute;ant une application de type SelfHosted &agrave; laquelle on affecte une policie qui impose un code suppl&eacute;mentaire lors d'une connexion. Ce code sera envoy&eacute; sur le mail de l'utilisateur sur une adresse individuelle ou un domaine sp&eacute;cifique. Ce n'est pas tout &agrave; fait du MFA, mais on consid&egrave;re que si l'utilisateur re&ccedil;oit bien le code sur son mail professionnel, il s'agit bien de lui et on peut lui permettre de saisir son login / password pour acc&eacute;der au service :</p>
<p style="text-align: center;"><img src="http://canaletto.fr/image.axd?picture=/images/gua03.png" width="600" /></p>
<p style="text-align: justify;">C'est la m&eacute;thode la plus simple et de nombreuses option sont exploitables, de m&ecirc;me qu'il est possible d'utiliser de nombreux providers externes d'authentification :</p>
<p style="text-align: center;"><img src="http://canaletto.fr/image.axd?picture=/images/gua04.png" width="600" /></p>
<p style="text-align: justify;">Lorsqu'il souhaite se connecter, l'utilisateur tombe sur un portail que l'on peu personnaliser aux couleurs de l'entreprise.</p>
<p style="text-align: justify;">Voil&agrave;, et surtout maintenant on retrouve bien les IP publiques dans le log de Guacamole :</p>
<p style="text-align: center;"><img src="http://canaletto.fr/image.axd?picture=/images/gua05.png" width="800" /></p>
<p style="text-align: justify;">Il n'y a plus qu'a ajuster les diff&eacute;rentes options de Guacamole et pour &ccedil;a la <a href="https://guacamole.apache.org/doc/gug/introduction.html" target="_blank" rel="noopener">documentation</a> est tr&egrave;s bien faite. Et bien sur si on se sert de Guacamole pour exposer des serveurs RDP accessibles sur l'internet on prendra soin de restreindre leur usage &agrave; l'IP publique du serveur Guacamole, ou mieux de faire transiter ce flux par un tunnel (Wireguard, Tailscale ou Zerotier par exemple que l'on peu facilement installer sur les deux serveurs).</p>
<p style="text-align: center;"><img src="http://canaletto.fr/image.axd?picture=/images/ThatsAllFolks.jpg" width="439" height="439" /></p>";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:4:"link";a:1:{i:0;a:5:{s:4:"data";s:42:"http://canaletto.fr/post/rdp-and-guacamole";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:8:"comments";a:1:{i:0;a:5:{s:4:"data";s:50:"http://canaletto.fr/post/rdp-and-guacamole#comment";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:4:"guid";a:1:{i:0;a:5:{s:4:"data";s:69:"http://canaletto.fr/post.aspx?id=07488d65-ada0-4c38-95a7-d5dc8f054d2c";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:7:"pubDate";a:1:{i:0;a:5:{s:4:"data";s:33:"ven., 30 juin 2023 15:04:00 +0100";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:8:"category";a:2:{i:0;a:5:{s:4:"data";s:7:"IP & Co";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:1;a:5:{s:4:"data";s:2:"IT";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}s:34:"https://blogengine.io/schemas/tags";a:1:{s:3:"tag";a:7:{i:0;a:5:{s:4:"data";s:10:"Cloudflare";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:1;a:5:{s:4:"data";s:11:"CloudFlared";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:2;a:5:{s:4:"data";s:9:"Guacamole";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:3;a:5:{s:4:"data";s:3:"RDP";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:4;a:5:{s:4:"data";s:3:"SSH";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:5;a:5:{s:4:"data";s:5:"Proxy";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:6;a:5:{s:4:"data";s:13:"Reverse Proxy";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}s:32:"http://purl.org/dc/elements/1.1/";a:1:{s:9:"publisher";a:1:{i:0;a:5:{s:4:"data";s:5:"Admin";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}s:52:"http://madskills.com/public/xml/rss/module/pingback/";a:2:{s:6:"server";a:1:{i:0;a:5:{s:4:"data";s:32:"http://canaletto.fr/pingback.axd";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:6:"target";a:1:{i:0;a:5:{s:4:"data";s:69:"http://canaletto.fr/post.aspx?id=07488d65-ada0-4c38-95a7-d5dc8f054d2c";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}s:38:"http://purl.org/rss/1.0/modules/slash/";a:1:{s:8:"comments";a:1:{i:0;a:5:{s:4:"data";s:1:"1";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}s:53:"http://madskills.com/public/xml/rss/module/trackback/";a:1:{s:4:"ping";a:1:{i:0;a:5:{s:4:"data";s:73:"http://canaletto.fr/trackback.axd?id=07488d65-ada0-4c38-95a7-d5dc8f054d2c";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}s:36:"http://wellformedweb.org/CommentAPI/";a:2:{s:7:"comment";a:1:{i:0;a:5:{s:4:"data";s:50:"http://canaletto.fr/post/rdp-and-guacamole#comment";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:10:"commentRss";a:1:{i:0;a:5:{s:4:"data";s:77:"http://canaletto.fr/syndication.axd?post=07488d65-ada0-4c38-95a7-d5dc8f054d2c";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}}}i:5;a:6:{s:4:"data";s:145:"
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
    ";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";s:5:"child";a:7:{s:0:"";a:7:{s:5:"title";a:1:{i:0;a:5:{s:4:"data";s:29:"Home Assistant &amp; Arrosage";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:11:"description";a:1:{i:0;a:5:{s:4:"data";s:14191:"<p style="text-align: justify;">Je n'ai pas vraiment la main verte et et mon jardin ressemble souvent &agrave; un no man's land, mais au printemps dernier une amie m'a convaincu de cr&eacute;er un carr&eacute; d'herbes aromatiques, l'id&eacute;e &agrave; fait son chemin et au centre on a m&ecirc;me plant&eacute; des plants de tomates qui produisent bien cet &eacute;t&eacute; ! Bon, vous imaginez bien que je ne vais pas ici vous conter ma vie priv&eacute;e mais plut&ocirc;t la part domotique de cette r&eacute;alisation !</p>
<p style="text-align: justify;">En Provence, si on veut un peu de verdure et esp&eacute;rer manger ses propres tomates, il n'y a pas de secret, il faut arroser ! J'ai donc commenc&eacute; par disposer un tuyau poreux sur mon carr&eacute;. Ensuite j'ai achet&eacute; un robinet Zigbee et pr&eacute;par&eacute; un petit scheduler qui me permet facilement d'activer ou pas la plage journali&egrave;re d'arrosage. J'ai fait quelque chose de simple en m'inspirant de ce que j'avais fait pour <a href="http://canaletto.fr/post/home-assistant-and-ecs" target="_blank" rel="noopener">mon chauffe eau</a>. Je publie ici le code suite &agrave; quelques demandes, m&ecirc;me si &ccedil;a n'a pas une grande valeur ajout&eacute;e.</p>
<p><img style="text-align: center; display: block; margin-left: auto; margin-right: auto;" src="http://canaletto.fr/image.axd?picture=/images/arrosage_1.png" width="400" /></p>
<p style="text-align: justify;">Pour l'instant &ccedil;a ne prends pas en compte les valeurs remont&eacute;s sur les capteurs de plantes car je n'en suis pas satisfait.</p>
<p style="text-align: justify;">L'offre en mati&egrave;re de capteurs de plantes n'est pas &eacute;norme :</p>
<ul style="text-align: justify;">
<li><strong>Le capteur Xiaomi</strong> (ou ses copies) qui fonctionnent en Bluetooth et que l'on trouve sur <a href="https://amzn.to/3r3MPV4" target="_blank" rel="noopener">Amazon</a> ou Ali Express : C'est ce qui fonctionne le "mieux", mais cela n&eacute;cessite un <a href="http://canaletto.fr/post/home-assistant-and-ble-proxy" target="_blank" rel="noopener">proxy BLE</a> &agrave; l'ext&eacute;rieur que l'on peut facilement se bricoler avec un ESP sous ESPHome.</li>
<li><strong>Le capteur Rehent</strong> en Zigbee que j'ai achet&eacute; chez Domadoo : Et l&agrave; c'est la d&eacute;convenue. Il est un peu encombrant mais ne pose pas de soucis particulier pour l'appairer en ZHA ou Z2M (ou sur une passerelle Tuya), sauf que si ce capteur remonte parfaitement la temp&eacute;rature du sol, l'humidit&eacute; du sol reste invariablement entre 75% et 85% (voir les sources au bas de cet article). Et bien sur chez Domadoo on est pas chez Amazon, le client a tort et l'&eacute;ventuel retour est &agrave; votre charge. Bref capteur et fournisseur &agrave; &eacute;viter ! Il semblerait qu'autres s&eacute;ries de ce capteur que l'on trouve chez AliExpress fonctionnent, mais l&agrave; il faudra aussi oublier le retour...</li>
</ul>
<p style="text-align: justify;">J'utilise une vanne Zigbee <a href="https://amzn.to/45QexEA" target="_blank" rel="noopener">Woox</a> qui alimente le tuyaux poreux (que je devrais remplacer par un un goute &agrave; goute). Pour avoir un r&eacute;seau Zigbee fiable &agrave; l'ext&eacute;rieur, j'ai install&eacute; sous la toiture de la terrasse des prises Zigbee dont le relais est HS mais qui continuent &agrave; remplir parfaitement leur r&ocirc;le de routeur Zigbee.</p>
<p style="text-align: justify;">Tout cela reste tr&egrave;s exp&eacute;rimental... Cot&eacute; int&eacute;gration j'utilise <a href="https://github.com/Olen/homeassistant-plant" target="_blank" rel="noopener">Home Assistant Plant</a> et la <a href="https://github.com/Olen/lovelace-flower-card" target="_blank" rel="noopener">carte</a> qui va avec.</p>
<h3 style="text-align: justify;">Automation</h3>
<p style="text-align: justify;">Une automation de schedule simple et visuelle :</p>
<pre class="language-yaml"><code>input_datetime:
  watering_start:
    has_date: false
    has_time: true
  watering_stop:
    has_date: false
    has_time: true

input_boolean:
  watering_day_monday:
    name: "WATERING : Lundi"
    icon: mdi:toggle-switch
  watering_day_tuesday:
    name: "WATERING : Mardi"
    icon: mdi:toggle-switch
  watering_day_wednesday:
    name: "WATERING : Mercredi"
    icon: mdi:toggle-switch
  watering_day_thursday:
    name: "WATERING : Jeudi"
    icon: mdi:toggle-switch
  watering_day_friday:
    name: "WATERING : Vendredi"
    icon: mdi:toggle-switch
  watering_day_saturday:
    name: "WATERING : Samedi"
    icon: mdi:toggle-switch
  watering_day_sunday:
    name: "WATERING : Dimanche"
    icon: mdi:toggle-switch

automation:

- id: 'xx8d0e1-fcb6-4412-abvxx-99c4d37be5xx'
  alias: 'WATERING ON'
  trigger:
  - platform: template
    value_template: '{{ states.sensor.time.state == states.input_datetime.watering_start.state[0:5] }}'
  condition:
    condition: or
    conditions:
      - '{{ (now().strftime("%a") == "Mon") and is_state("input_boolean.watering_day_monday", "on") }}'
      - '{{ (now().strftime("%a") == "Tue") and is_state("input_boolean.watering_day_tuesday", "on") }}'
      - '{{ (now().strftime("%a") == "Wed") and is_state("input_boolean.watering_day_wednesday", "on") }}'
      - '{{ (now().strftime("%a") == "Thu") and is_state("input_boolean.watering_day_thursday", "on") }}'
      - '{{ (now().strftime("%a") == "Fri") and is_state("input_boolean.watering_day_friday", "on") }}'
      - '{{ (now().strftime("%a") == "Sat") and is_state("input_boolean.watering_day_saturday", "on") }}'
      - '{{ (now().strftime("%a") == "Sun") and is_state("input_boolean.watering_day_sunday", "on")}}'
  action:
  - service: switch.turn_on
    entity_id: switch.vanne_woox_switch
  - service: notify.slack_hass_canaletto
    data:
      message: "{{now().strftime('%d/%m/%Y, %H:%M')}} &gt; WATERING | START | Soil : {{ states.sensor.soil_01_soil_moisture.state }}%" 


- id: 'zz9csdfsef-76dd-4fdd-9dzz-40bfsdq158zz'
  alias: 'WATERING OFF'
  trigger:
  - platform: template
    value_template: '{{ states.sensor.time.state == states.input_datetime.watering_stop.state[0:5] }}'
  action:
  - service: switch.turn_off
    entity_id: switch.vanne_woox_switch
  - service: notify.slack_hass_canaletto
    data:
      message: "{{now().strftime('%d/%m/%Y, %H:%M')}} &gt; WATERING | STOP | Soil : {{ states.sensor.soil_01_soil_moisture.state }}%"   </code></pre>
<p style="text-align: justify;">La carte Lovelace :</p>
<pre class="language-yaml"><code>type: vertical-stack
cards:
  - type: entities
    entities:
      - entities:
          - entity: automation.watering_on
            name: false
          - entity: sensor.energy_total_yearly_1pm_watering
            name: false
            unit: kWh
            format: precision2
          - entity: sensor.soil_01_soil_moisture
            name: false
        entity: switch.vanne_woox_switch
        name: Arrosage
        icon: mdi:watering-can-outline
        show_state: false
        state_color: true
        type: custom:multiple-entity-row
  - type: horizontal-stack
    cards:
      - type: custom:button-card
        color_type: card
        entity: input_boolean.watering_day_monday
        name: Lundi
        show_last_changed: false
        show_state: false
        tap_action:
          action: toggle
        state:
          - value: 'on'
            color: green
            icon: mdi:water-boiler
          - value: 'off'
            color: grey
            icon: mdi:water-boiler-off
        styles:
          card:
            - height: 60px
            - border-radius: 5px
            - font-size: 12px
      - type: custom:button-card
        color_type: card
        entity: input_boolean.watering_day_tuesday
        name: Mardi
        show_last_changed: false
        show_state: false
        tap_action:
          action: toggle
        state:
          - value: 'on'
            color: green
            icon: mdi:water-boiler
          - value: 'off'
            color: grey
            icon: mdi:water-boiler-off
        styles:
          card:
            - height: 60px
            - border-radius: 5px
            - font-size: 12px
      - type: custom:button-card
        color_type: card
        entity: input_boolean.watering_day_wednesday
        name: Mercredi
        show_last_changed: false
        show_state: false
        tap_action:
          action: toggle
        state:
          - value: 'on'
            color: green
            icon: mdi:water-boiler
          - value: 'off'
            color: grey
            icon: mdi:water-boiler-off
        styles:
          card:
            - height: 60px
            - border-radius: 5px
            - font-size: 12px
      - type: custom:button-card
        color_type: card
        entity: input_boolean.watering_day_thursday
        name: Jeudi
        show_last_changed: false
        show_state: false
        tap_action:
          action: toggle
        state:
          - value: 'on'
            color: green
            icon: mdi:water-boiler
          - value: 'off'
            color: grey
            icon: mdi:water-boiler-off
        styles:
          card:
            - height: 60px
            - border-radius: 5px
            - font-size: 12px
      - type: custom:button-card
        color_type: card
        entity: input_boolean.watering_day_friday
        name: Vendredi
        show_last_changed: false
        show_state: false
        tap_action:
          action: toggle
        state:
          - value: 'on'
            color: green
            icon: mdi:water-boiler
          - value: 'off'
            color: grey
            icon: mdi:water-boiler-off
        styles:
          card:
            - height: 60px
            - border-radius: 5px
            - font-size: 12px
      - type: custom:button-card
        color_type: card
        entity: input_boolean.watering_day_saturday
        name: Samedi
        show_last_changed: false
        show_state: false
        tap_action:
          action: toggle
        state:
          - value: 'on'
            color: green
            icon: mdi:water-boiler
          - value: 'off'
            color: grey
            icon: mdi:water-boiler-off
        styles:
          card:
            - height: 60px
            - border-radius: 5px
            - font-size: 12px
      - type: custom:button-card
        color_type: card
        entity: input_boolean.watering_day_sunday
        name: Dimanche
        show_last_changed: false
        show_state: false
        tap_action:
          action: toggle
        state:
          - value: 'on'
            color: green
            icon: mdi:water-boiler
          - value: 'off'
            color: grey
            icon: mdi:water-boiler-off
        styles:
          card:
            - height: 60px
            - border-radius: 5px
            - font-size: 12px
  - type: conditional
    conditions:
      - entity: automation.watering_on
        state: 'on'
    card:
      type: custom:vertical-stack-in-card
      cards:
        - type: horizontal-stack
          cards:
            - type: markdown
              content: '#### &lt;center&gt; Heure de d&eacute;but'
            - type: markdown
              content: '#### &lt;center&gt; Arrosage'
            - type: markdown
              content: '#### &lt;center&gt; Heure de Fin'
        - type: horizontal-stack
          cards:
            - entity: input_datetime.watering_start
              type: custom:time-picker-card
              name: D&eacute;but
              layout:
                align_controls: center
                embedded: true
              hide:
                name: true
                icon: true
            - type: glance
              show_state: true
              show_name: false
              entities:
                - switch.vanne_woox_switch
            - entity: input_datetime.watering_stop
              type: custom:time-picker-card
              layout:
                align_controls: center
                embedded: true
              hide:
                name: true
                icon: true
  - color_thresholds:
      - color: '#039BE5'
        value: 0
      - color: '#0da035'
        value: 19
      - color: '#e0b400'
        value: 25
      - color: '#e45e65'
        value: 2400
    color_thresholds_transition: hard
    entities:
      - entity: sensor.plant_01_moisture
        name: Humidit&eacute; du sol
      - entity: sensor.plant_01_temperature
        name: Temp&eacute;ratire du sol
      - color: rgba(0,0,255,1)
        entity: binary_sensor.night_reworked
        name: Nuit
        show_line: false
        y_axis: secondary
    group: false
    hour24: true
    hours_to_show: 24
    line_width: 2
    name: Humidit&eacute; et temp&eacute;rature du sol
    points_per_hour: 4
    show:
      extrema: true
      fill: fade
      icon: true
      labels: false
      name: true
      state: true
    state_map:
      - label: Day
        value: 'off'
      - label: Night
        value: 'on'
    type: custom:mini-graph-card
  - type: custom:flower-card
    entity: plant.jardin
    show_bars:
      - illuminance
      - humidity
      - moisture
      - conductivity
      - temperature
      - dli
    battery_sensor: sensor.demo_battery</code></pre>
<h3>Souces</h3>
<h4>Capteur Rehent</h4>
<ul>
<li><a href="https://smarthomescene.com/reviews/tuya-zigbee-plant-soil-sensor-gxm-01-review/">https://smarthomescene.com/reviews/tuya-zigbee-plant-soil-sensor-gxm-01-review/</a></li>
<li><a href="https://community.home-assistant.io/t/tze200-myd45weu-ts0601-with-zha-error-tuya-model/550381">https://community.home-assistant.io/t/tze200-myd45weu-ts0601-with-zha-error-tuya-model/550381</a></li>
<li><a href="https://community.jeedom.com/t/capteur-humidite-du-sol-en-zigbee/105716">https://community.jeedom.com/t/capteur-humidite-du-sol-en-zigbee/105716</a></li>
<li><a href="https://community.jeedom.com/t/demande-ajout-module-capteur-humidite-sol-tuya/101614/24">https://community.jeedom.com/t/demande-ajout-module-capteur-humidite-sol-tuya/101614/24</a></li>
</ul>
<p>&nbsp;</p>";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:4:"link";a:1:{i:0;a:5:{s:4:"data";s:52:"http://canaletto.fr/post/home-assistant-and-arrosage";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:8:"comments";a:1:{i:0;a:5:{s:4:"data";s:60:"http://canaletto.fr/post/home-assistant-and-arrosage#comment";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:4:"guid";a:1:{i:0;a:5:{s:4:"data";s:69:"http://canaletto.fr/post.aspx?id=73d63065-74d4-46d9-a913-740f09593ea0";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:7:"pubDate";a:1:{i:0;a:5:{s:4:"data";s:32:"mer., 7 juin 2023 20:21:00 +0100";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:8:"category";a:1:{i:0;a:5:{s:4:"data";s:9:"Domotique";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}s:34:"https://blogengine.io/schemas/tags";a:1:{s:3:"tag";a:6:{i:0;a:5:{s:4:"data";s:14:"Home Assistant";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:1;a:5:{s:4:"data";s:4:"HASS";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:2;a:5:{s:4:"data";s:5:"Plant";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:3;a:5:{s:4:"data";s:4:"Soil";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:4;a:5:{s:4:"data";s:8:"Arrosage";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:5;a:5:{s:4:"data";s:8:"Watering";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}s:32:"http://purl.org/dc/elements/1.1/";a:1:{s:9:"publisher";a:1:{i:0;a:5:{s:4:"data";s:5:"Admin";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}s:52:"http://madskills.com/public/xml/rss/module/pingback/";a:2:{s:6:"server";a:1:{i:0;a:5:{s:4:"data";s:32:"http://canaletto.fr/pingback.axd";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:6:"target";a:1:{i:0;a:5:{s:4:"data";s:69:"http://canaletto.fr/post.aspx?id=73d63065-74d4-46d9-a913-740f09593ea0";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}s:38:"http://purl.org/rss/1.0/modules/slash/";a:1:{s:8:"comments";a:1:{i:0;a:5:{s:4:"data";s:1:"1";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}s:53:"http://madskills.com/public/xml/rss/module/trackback/";a:1:{s:4:"ping";a:1:{i:0;a:5:{s:4:"data";s:73:"http://canaletto.fr/trackback.axd?id=73d63065-74d4-46d9-a913-740f09593ea0";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}s:36:"http://wellformedweb.org/CommentAPI/";a:2:{s:7:"comment";a:1:{i:0;a:5:{s:4:"data";s:60:"http://canaletto.fr/post/home-assistant-and-arrosage#comment";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:10:"commentRss";a:1:{i:0;a:5:{s:4:"data";s:77:"http://canaletto.fr/syndication.axd?post=73d63065-74d4-46d9-a913-740f09593ea0";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}}}i:6;a:6:{s:4:"data";s:131:"
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
    ";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";s:5:"child";a:7:{s:0:"";a:7:{s:5:"title";a:1:{i:0;a:5:{s:4:"data";s:34:"Home Assistant &amp; Plug Security";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:11:"description";a:1:{i:0;a:5:{s:4:"data";s:6180:"<p style="text-align: justify;">On utilise souvent des prises command&eacute;es uniquement pour mesurer la consommation de certains appareils. Ces prises sont toujours en position ON. Ces prises, si elles ne sont pas de trop mauvaise qualit&eacute; un m&eacute;canisme de s&eacute;curit&eacute; int&eacute;gr&eacute; qui les passent OFF en cas de surtension ou de surcharge. Et dans la pratique &ccedil;a arrive parfois et on constate plus tard que le lave linge ou le lave vaisselle s'est arr&ecirc;t&eacute;, ou pire dans le cas d'un cong&eacute;lateur.</p>
<p style="text-align: center;"><img src="http://canaletto.fr/image.axd?picture=/images/blitzwolf_bw_shp13_small.jpg" width="290" height="220" /></p>
<p style="text-align: justify;">Pour palier &agrave; cet inconv&eacute;nient on va cr&eacute;er une automation qui va r&eacute;armer la prise apr&egrave;s quelques minutes en OFF. Jusque l&agrave; c'est simple, mais il se peut &eacute;galement que le probl&egrave;me soit plus grave et qu'il ne faille pas forcer ind&eacute;finiment ce r&eacute;armement automatique. Etant donn&eacute; qu'on ne dispose g&eacute;n&eacute;ralement pas d'information sur la cause de ce passage en s&eacute;curit&eacute; on va consid&eacute;rer qu'au bout de "n" tentatives sur un temps donn&eacute; on ne r&eacute;arme plus. Pour &ccedil;a on va utiliser des compteurs (&agrave; cr&eacute;er avec un minimum &agrave; 0 et un maximum &agrave; 10) et on fera un reset de ceux-ci toutes les nuits...</p>
<p style="text-align: justify;">J'ai fix&eacute; ici arbitrairement &agrave; 5 le nombre de r&eacute;armements possibles.</p>
<p style="text-align: justify;"><span style="background-color: #f8cac6;"><strong>Attention :</strong> Je vous explique ici comment j'ai fait, mais un risque existe toujours et la mise en &oelig;uvre de cette solution est &agrave; vos risques (et p&eacute;rils). Je me d&eacute;gage ainsi de toute responsabilit&eacute;.</span></p>
<p style="text-align: justify;">On va faire &ccedil;a avec une seule automation que j'ai voulue la plus concise et qui servira &eacute;galement &agrave; notifier :</p>
<pre class="language-yaml"><code>automation:
- id: '2bd0ertyyf-2687-45f98f-aed0-to-off'
  alias: "Notify Plug Off"
  description: "Notification mise en s&eacute;curit&eacute; des prises"
  mode: single
  trigger:
    - platform: state
      entity_id: switch.bw_1
      to: "off"
      id: "Lave Vaisselle"
    - platform: state
      entity_id: switch.bw_2
      to: "off"
      id: "Lave Linge"
    - platform: state
      entity_id: switch.bw_3
      to: "off"
      id: "Seche Linge"
    - platform: state
      entity_id: switch.bw_4
      to: "off"
      id: "Congelateur"
    - platform: time
      at: "00:05:00"
      id: "Reset"
  condition: []
  action:
  - delay:
      hours: 0
      minutes: 5
      seconds: 0
      milliseconds: 0  
  - choose:
      - conditions: "{{ trigger.id in ['Lave Vaisselle'] and states('counter.plug_bw_1') | int &lt; 5 }}"
        sequence:
          - service: switch.turn_on
            target:
              entity_id: switch.bw_1
          - service: counter.increment
            target:
              entity_id: counter.plug_bw_1
          - service: notify.slack_hass_mondon
            data:
              message: "{{now().strftime('%d/%m/%Y, %H:%M:%S')}} &gt; R&eacute;armement n&deg;{{ states('counter.plug_bw_1')}} du {{ trigger.id }}"               

      - conditions: "{{ trigger.id in ['Lave Linge'] and states('counter.plug_bw_2') | int &lt; 5 }}"
        sequence:
          - service: switch.turn_on
            target:
              entity_id: switch.bw_2
          - service: counter.increment
            target:
              entity_id: counter.plug_bw_2
          - service: notify.slack_hass_mondon
            data:
              message: "{{now().strftime('%d/%m/%Y, %H:%M:%S')}} &gt; R&eacute;armement n&deg;{{ states('counter.plug_bw_2')}} du {{ trigger.id }}" 

      - conditions: "{{ trigger.id in ['Seche Linge'] and states('counter.plug_bw_3') | int &lt; 5 }}"
        sequence:
          - service: switch.turn_on
            target:
              entity_id: switch.bw_3
          - service: counter.increment
            target:
              entity_id: counter.plug_bw_3
          - service: notify.slack_hass_mondon
            data:
              message: "{{now().strftime('%d/%m/%Y, %H:%M:%S')}} &gt; R&eacute;armement n&deg;{{ states('counter.plug_bw_3')}} du {{ trigger.id }}" 

      - conditions: "{{ trigger.id in ['Congelateur'] and states('counter.plug_bw_4') | int &lt; 5 }}"
        sequence:
          - service: switch.turn_on
            target:
              entity_id: switch.bw_4
          - service: counter.increment
            target:
              entity_id: counter.plug_bw_3
          - service: notify.slack_hass_mondon
            data:
              message: "{{now().strftime('%d/%m/%Y, %H:%M:%S')}} &gt; R&eacute;armement n&deg;{{ states('counter.plug_bw_4')}} du {{ trigger.id }}" 

      - conditions: 
          - condition: or
            conditions:
              - "{{ trigger.id in ['Lave Vaisselle'] and states('counter.plug_bw_1') | int &gt;= 5 }}"
              - "{{ trigger.id in ['Lave Linge'] and states('counter.plug_bw_2') | int &gt;= 5 }}"
              - "{{ trigger.id in ['Seche Linge'] and states('counter.plug_bw_3') | int &gt;= 5 }}"
              - "{{ trigger.id in ['Congelateur'] and states('counter.plug_bw_4') | int &gt;= 5 }}"
        sequence:
          - service: notify.slack_hass_mondon
            data:
              message: "{{now().strftime('%d/%m/%Y, %H:%M:%S')}} &gt; Probl&egrave;me avec le {{ trigger.id }}. On ne r&eacute;arme plus, une v&eacute;rification s'impose." 

      - conditions: "{{ trigger.id in ['Reset'] }}"
        sequence:
          - service: counter.reset
            target:
              entity_id:
                - counter.plug_bw_1
                - counter.plug_bw_2
                - counter.plug_bw_3
                - counter.plug_bw_4</code></pre>
<p style="text-align: center;"><img src="http://canaletto.fr/image.axd?picture=/images/enjoy2.jpg" width="302" height="202" /></p>";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:4:"link";a:1:{i:0;a:5:{s:4:"data";s:57:"http://canaletto.fr/post/home-assistant-and-plug-security";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:8:"comments";a:1:{i:0;a:5:{s:4:"data";s:65:"http://canaletto.fr/post/home-assistant-and-plug-security#comment";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:4:"guid";a:1:{i:0;a:5:{s:4:"data";s:69:"http://canaletto.fr/post.aspx?id=3b6db46a-58aa-41b8-a651-23fda8859b7a";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:7:"pubDate";a:1:{i:0;a:5:{s:4:"data";s:32:"dim., 4 juin 2023 17:03:00 +0100";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:8:"category";a:1:{i:0;a:5:{s:4:"data";s:9:"Domotique";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}s:34:"https://blogengine.io/schemas/tags";a:1:{s:3:"tag";a:4:{i:0;a:5:{s:4:"data";s:4:"HASS";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:1;a:5:{s:4:"data";s:14:"Home Assistant";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:2;a:5:{s:4:"data";s:6:"Prises";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:3;a:5:{s:4:"data";s:5:"Plug ";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}s:32:"http://purl.org/dc/elements/1.1/";a:1:{s:9:"publisher";a:1:{i:0;a:5:{s:4:"data";s:5:"Admin";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}s:52:"http://madskills.com/public/xml/rss/module/pingback/";a:2:{s:6:"server";a:1:{i:0;a:5:{s:4:"data";s:32:"http://canaletto.fr/pingback.axd";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:6:"target";a:1:{i:0;a:5:{s:4:"data";s:69:"http://canaletto.fr/post.aspx?id=3b6db46a-58aa-41b8-a651-23fda8859b7a";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}s:38:"http://purl.org/rss/1.0/modules/slash/";a:1:{s:8:"comments";a:1:{i:0;a:5:{s:4:"data";s:1:"0";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}s:53:"http://madskills.com/public/xml/rss/module/trackback/";a:1:{s:4:"ping";a:1:{i:0;a:5:{s:4:"data";s:73:"http://canaletto.fr/trackback.axd?id=3b6db46a-58aa-41b8-a651-23fda8859b7a";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}s:36:"http://wellformedweb.org/CommentAPI/";a:2:{s:7:"comment";a:1:{i:0;a:5:{s:4:"data";s:65:"http://canaletto.fr/post/home-assistant-and-plug-security#comment";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:10:"commentRss";a:1:{i:0;a:5:{s:4:"data";s:77:"http://canaletto.fr/syndication.axd?post=3b6db46a-58aa-41b8-a651-23fda8859b7a";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}}}i:7;a:6:{s:4:"data";s:131:"
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
    ";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";s:5:"child";a:7:{s:0:"";a:7:{s:5:"title";a:1:{i:0;a:5:{s:4:"data";s:25:"Tailscale Access Controls";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:11:"description";a:1:{i:0;a:5:{s:4:"data";s:5420:"<p style="text-align: justify;">J'ai souvent parl&eacute; de Zerotier que j'utilise au quotidien, mais qui dans sa version gratuite comporte quelques limitations en terme de contr&ocirc;le d'acc&egrave;s dans un environnement mixant du site-to-site et des clients isol&eacute;s. J'ai donc voulut voir ce que proposait <a href="https://tailscale.com/" target="_blank" rel="noopener">Tailscale</a>, qui est un VPN manag&eacute; relativement similaire reposant sur Wireguard. Tous deux offrent des fonctionnalit&eacute;s gratuites et payantes. Si payer ne doit pas &ecirc;tre un probl&egrave;me dans un environnement de production, c'est un peu diff&eacute;rent en mode home lab.... d'autant plus que certaines fonctionnalit&eacute;s de la version gratuite ne se retrouvent que dans la <a href="https://tailscale.com/pricing/" target="_blank" rel="noopener">version Premium</a> &agrave; $18 /mois/utilisateur.</p>
<p style="text-align: center;"><img src="http://canaletto.fr/image.axd?picture=/images/tailscale.png" width="250" height="51" /></p>
<p style="text-align: justify;">La version gratuite des Tailscale est plut&ocirc;t g&eacute;n&eacute;reuse, elle propose 100 nodes et 3 utilisateurs (&agrave; condition de disposer d'un "custom domain" (je vais utiliser des comptes Microsoft 365, mais plusieurs autres possibilit&eacute;s sont disponibles : <a href="https://tailscale.com/kb/1013/sso-providers/" target="_blank" rel="noopener">SSO Identity Providers</a>). On peut donc disposer de 3 comptes sur un m&ecirc;me domaine. Je parle de comptes car nativement (et normalement) le contr&ocirc;le d'acc&egrave;s se fait sur l'utilisateur. Manque de chance j'ai besoin de g&eacute;rer 4 utilisateurs, et je ne suis pas pr&ecirc;t &agrave; payer 4 x $18, ce qui me ferait plus de $ 800 par an !</p>
<p style="text-align: justify;">J'ai donc cherch&eacute; &agrave; contourner et je vais finalement g&eacute;rer mes autorisations &agrave; partir des machines Tailscale que j'ai approuv&eacute;es (mode NFS pour ceux qui se souviennent). Dans cet usage je ne cherche pas faire communiquer les clients Tailscale entre eux mais &agrave; leur permettre d'acc&eacute;der &agrave; des ressources situ&eacute;es sur diff&eacute;rents subnets sur lesquels je souhaite restreindre les possibilit&eacute;s.</p>
<p><img style="display: block; margin-left: auto; margin-right: auto;" src="http://canaletto.fr/image.axd?picture=/images/tailscale-subnet.png" width="698" height="445" /></p>
<p style="text-align: justify;">Pour la suite on consid&egrave;re que le r&eacute;seaux Tailscale est configur&eacute; avec les nodes qui servent &agrave; joindre les subnets.</p>
<p style="text-align: justify;">Je vais cr&eacute;er deux utilisateurs :</p>
<pre class="language-yaml"><code>admin@canaletto.fr
user@canaletto.fr</code></pre>
<p style="text-align: justify;">Le premier compte qui sera &eacute;galement le mien va &eacute;galement me permettre de configurer et approuver les machines clientes.</p>
<p style="text-align: justify;">Le second servira &agrave; connecter mes utilisateurs et je pourrais approuver leurs machines. Ce compte &eacute;tant prot&eacute;g&eacute; en MFA, il n&eacute;cessitera une validation de ma part. Une fois la machine connect&eacute;e, je d&eacute;sactive l'expiration de la cl&eacute; et on passe au contr&ocirc;le s'acc&egrave;s :</p>
<pre class="language-yaml"><code>{
  "acls": [
    {"action": "accept", "src": ["admin@canaletto.fr"], "dst": ["*:*"]}, // Ici l'admin dispose de tous les droits
    
    // Autorisation par machines
    {
      "action": "accept",
      "src": ["azura", "lydia"],      // Ici deux clients Tailscale
      "dst": [
        "pipa:25,53",                 // On autorise le host qui supporte le DNS si on veut utiliser les noms courts...
        "mixa:80,443,445,3389",
        "nona:80,443,445,1443,3389",  // Ports autoris&eacute;s

        "lab-1:*",

        "192.168.2.12:80,443,9100,5001,3389", // Par IP + ports
        "192.168.6.0/24:*",                   // Par subnet
      ],
    },
  ],
  "hosts": {
    "azura": "100.1.2.3",        // Client Tailscale
    "lydia": "100.5.2.3",        // Client Tailscale

    "mixa":  "192.168.1.4",      // Host on subnet
    "nona":  "192.168.2.8",      // Host on subnet
    "pipa":  "192.168.2.1",      // Host on subnet

    "lab-1": "192.168.6.0/24", // subnet
  },

}</code></pre>
<p style="text-align: justify;"><strong>Dans l'ordre :</strong></p>
<ol style="text-align: justify;">
<li>J'autorise l'admin &agrave; tout voir.</li>
<li>Ensuite j'autorise les machines <code>azura</code> et <code>lydia</code> &agrave; acc&eacute;der uniquement aux hosts que j'aurais d&eacute;fini avec une restriction sur certains ports. C'est possible en d&eacute;finissant les hosts plus loin ou en se servant directement des adresses IP. L'ICMP (ping) est ouvert automatiquement vers les destinations autoris&eacute;es.</li>
<li>Je d&eacute;fini les clients et serveurs.</li>
</ol>
<p>Voil&agrave;. Je n'ai pas creus&eacute; toutes les possibilit&eacute; offertes par le contr&ocirc;le d'acc&egrave;s propos&eacute; par Tailscale, la liste est longue et le <a href="https://tailscale.com/kb/" target="_blank" rel="noopener">documentation</a> plut&ocirc;t bien faire. Id&eacute;es bienvenues !</p>
<p style="text-align: center;"><img src="http://canaletto.fr/image.axd?picture=/images/enjoy2.jpg" width="285" height="191" /></p>";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:4:"link";a:1:{i:0;a:5:{s:4:"data";s:50:"http://canaletto.fr/post/tailscale-access-controls";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:8:"comments";a:1:{i:0;a:5:{s:4:"data";s:58:"http://canaletto.fr/post/tailscale-access-controls#comment";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:4:"guid";a:1:{i:0;a:5:{s:4:"data";s:69:"http://canaletto.fr/post.aspx?id=41efab1a-c669-47a9-9b5f-5f67128e8eb2";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:7:"pubDate";a:1:{i:0;a:5:{s:4:"data";s:31:"mar., 2 mai 2023 20:24:00 +0100";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:8:"category";a:2:{i:0;a:5:{s:4:"data";s:7:"IP & Co";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:1;a:5:{s:4:"data";s:2:"IT";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}s:34:"https://blogengine.io/schemas/tags";a:1:{s:3:"tag";a:3:{i:0;a:5:{s:4:"data";s:3:"vpn";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:1;a:5:{s:4:"data";s:9:"TailScale";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:2;a:5:{s:4:"data";s:9:"WireGuard";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}s:32:"http://purl.org/dc/elements/1.1/";a:1:{s:9:"publisher";a:1:{i:0;a:5:{s:4:"data";s:5:"Admin";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}s:52:"http://madskills.com/public/xml/rss/module/pingback/";a:2:{s:6:"server";a:1:{i:0;a:5:{s:4:"data";s:32:"http://canaletto.fr/pingback.axd";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:6:"target";a:1:{i:0;a:5:{s:4:"data";s:69:"http://canaletto.fr/post.aspx?id=41efab1a-c669-47a9-9b5f-5f67128e8eb2";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}s:38:"http://purl.org/rss/1.0/modules/slash/";a:1:{s:8:"comments";a:1:{i:0;a:5:{s:4:"data";s:1:"0";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}s:53:"http://madskills.com/public/xml/rss/module/trackback/";a:1:{s:4:"ping";a:1:{i:0;a:5:{s:4:"data";s:73:"http://canaletto.fr/trackback.axd?id=41efab1a-c669-47a9-9b5f-5f67128e8eb2";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}s:36:"http://wellformedweb.org/CommentAPI/";a:2:{s:7:"comment";a:1:{i:0;a:5:{s:4:"data";s:58:"http://canaletto.fr/post/tailscale-access-controls#comment";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:10:"commentRss";a:1:{i:0;a:5:{s:4:"data";s:77:"http://canaletto.fr/syndication.axd?post=41efab1a-c669-47a9-9b5f-5f67128e8eb2";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}}}i:8;a:6:{s:4:"data";s:138:"
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
    ";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";s:5:"child";a:7:{s:0:"";a:7:{s:5:"title";a:1:{i:0;a:5:{s:4:"data";s:37:"Home Assistant &amp; Alarm, encore...";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:11:"description";a:1:{i:0;a:5:{s:4:"data";s:26973:"<p style="text-align: justify;">J'ai souvent parl&eacute; d'alarme ici, de t&eacute;l&eacute;commandes, de claviers et de sir&egrave;nes. Je pense cette fois &ecirc;tre parvenu &agrave; quelque chose de fonctionnel et je vais vous en parler. Pour faire face aux diff&eacute;rentes contraintes, notamment la gestion bizarre des t&eacute;l&eacute;commandes sous ZHA, il va falloir un peu ruser. Avant que vous me demandiez pourquoi je m'obstine sous ZHA alors que ces m&ecirc;mes t&eacute;l&eacute;commandes sont bien g&eacute;r&eacute;es sous Z2M, je vous r&eacute;pondrait que mon objectif est la simplification et donc d'&eacute;viter le plus possible les adons qui complexifient une installation, pas forc&eacute;ment pour moi ou je dispose de toutes les passerelles possibles, mais sur des installations que je g&egrave;re &agrave; distance ou je me dois de faire simple et fiable.</p>
<p><img style="display: block; margin-left: auto; margin-right: auto;" src="http://canaletto.fr/image.axd?picture=/images/Alarm_07.png" /></p>
<p style="text-align: justify;"><span style="background-color: #f8cac6;"><strong>Attention :</strong>&nbsp; on parle ici d'un syst&egrave;me de s&eacute;curit&eacute; DIY, donc non agr&eacute;e par les assurances et autres...&nbsp;Ca ne veut pas dire que &ccedil;a ne fonctionne pas, juste que &ccedil;a ne r&eacute;pond pas aux normes NF en vigueur dans ce domaine</span></p>
<p style="text-align: justify;">Afin de g&eacute;rer toutes les contraintes, je vais principalement m'appuyer sur deux <code>automations:</code>, quelques <code>scripts:</code> et un <code>alarm_control_panel:</code> virtuel.</p>
<p style="text-align: justify;"><strong>L'objectif est de g&eacute;rer :</strong></p>
<ul style="text-align: justify;">
<li>Un mode absent (away) (avec une variable pour simuler un peu de pr&eacute;sence).</li>
<li>Un mode pr&eacute;sent/nuit arm&eacute; (home) (plus ou moins utile mais mais &ccedil;a fait partie de tout syst&egrave;me d'alarme face au home jacking.</li>
<li>Un mode alerte (emergency) qui va permettre de d&eacute;clencher une action d'urgence en appuyant sur un bouton de t&eacute;l&eacute;commande ou m&eacute;daillon (je pense &agrave; mes vieux jours).</li>
</ul>
<p style="text-align: justify;"><strong>De l'armement / d&eacute;sarmement vont &eacute;galement d&eacute;couler :</strong></p>
<ul style="text-align: justify;">
<li>La fermeture compl&egrave;te ou partielle des volets roulants, leur r&eacute;ouverture coh&eacute;rente avec la programmation en cours et &eacute;ventuellement le passage en manuel des volets des chambres des enfants / invit&eacute;s s'ils sont pr&eacute;sents.</li>
<li>La gestion du climatiseur et des convecteurs avec passage en mode &eacute;co ou absent en fonction du type d'armement).</li>
<li>La gestion du chauffe eau en cas d'absence de longue dur&eacute;e.</li>
<li>La gestion des &eacute;clairages et la mise en veille des &eacute;crans et ordinateurs.</li>
<li>...</li>
</ul>
<p style="text-align: justify;">Etant donn&eacute; que j'ai deux syst&egrave;mes d'alarme qui fonctionnent en parall&egrave;le (Alarmo et Visonic), j'ai commenc&eacute; par cr&eacute;er une alarme virtuelle et je me servirait d'elle pour les diff&eacute;rentes actions.</p>
<pre class="language-yaml"><code>alarm_control_panel:
  - platform: manual
    name: Home Alarm Command
    code: 1234
    code_arm_required: false
    disarm_after_trigger: false
    arming_time: 0
    delay_time: 0
    trigger_time: 600
    disarmed:
      trigger_time: 0
    armed_home:
      arming_time: 0
      delay_time: 0</code></pre>
<h3 style="text-align: justify;">L'Armement / D&eacute;sarmement</h3>
<p style="text-align: justify;">L'armement / d&eacute;sarmement va pouvoir se faire de plusieurs fa&ccedil;ons :</p>
<ul style="text-align: justify;">
<li>Clavier &agrave; code</li>
<li>T&eacute;l&eacute;commande d&eacute;di&eacute;e</li>
<li>Application mobile</li>
<li>Tag RFID (pour d&eacute;sarmer dans mon cas)</li>
</ul>
<p style="text-align: justify;">J'ai volontairement &eacute;cart&eacute; les t&eacute;l&eacute;commandes radio en 433 Mhz dont j'avais parl&eacute; ici, d'une part parce qu'elles sont facilement piratables, et d'autre part parce qu'elles ne permettent pas de savoir qui a d&eacute;sarm&eacute; le syst&egrave;me.</p>
<p style="text-align: justify;">Je vais utiliser deux automations et les d&eacute;couper ce dessous/</p>
<ul style="text-align: justify;">
<li>La premi&egrave;re pour g&eacute;rer les armements / d&eacute;sarmements</li>
<li>La seconde pour g&eacute;rer le d&eacute;sarmement des t&eacute;l&eacute;commandes, claviers &agrave; code afin d'int&eacute;grer les particularit&eacute;s ZHA (en attendant une am&eacute;lioration de la part des d&eacute;veloppeurs de Home Assistant qui pour l'instant font la sourde oreille, parfois plus concentr&eacute;s sur les nouveaut&eacute;s que l'affinage de l'existant).</li>
</ul>
<p><img style="display: block; margin-left: auto; margin-right: auto;" src="http://canaletto.fr/image.axd?picture=/images/Alarm_10_panel.png" width="500" /></p>
<h3>Gestion de l'armement / d&eacute;sarmement et des boutons d'urgence</h3>
<p style="text-align: justify;"><strong>Les d&eacute;clencheurs</strong>&nbsp;: Ici on va empiler nos d&eacute;clencheurs d'armement, qu'ils soient g&eacute;r&eacute;s par ZHA, Z2M ou toute autre source. 3 par fonction, <code>armed_away, armed_home, triggered</code>, mais cela peut &eacute;galement &ecirc;tre un bouton virtuel pour Lovelace, voire n'importe quelle t&eacute;l&eacute;commande ou bouton poussoir.</p>
<pre class="language-yaml"><code>- id: 078fsdg412-3545-4f37-ba02-bccsfds5646sf
  alias: "Alarm : Global ON/OFF"
  mode: restart
  trigger:
    - platform: device
      device_id: c036b6547a0347878dcc6d06152267ab
      domain: alarm_control_panel
      entity_id: alarm_control_panel.lk_zb_keypad
      type: armed_away
      id: "KeyPad Away"
    - platform: device
      device_id: c036b6547a0347878dcc6d06152267ab
      domain: alarm_control_panel
      entity_id: alarm_control_panel.lk_zb_keypad
      type: armed_home
      id: "KeyPad Home"
    - platform: device
      device_id: c036b6547a0347878dcc6d06152267ab
      domain: alarm_control_panel
      entity_id: alarm_control_panel.lk_zb_keypad
      type: triggered
      id: "KeyPad Triggered"
    - platform: state
      entity_id: input_button.arm_alarm_away
      id: "Push Button Away"</code></pre>
<p style="text-align: justify;">Et un d&eacute;clencheur de d&eacute;sarmement activ&eacute; par une seconde automation que l'on verra plus loin :</p>
<pre class="language-yaml"><code>    - platform: state
      entity_id:
        - alarm_control_panel.home_alarm_command
      to: disarmed
      id: "Remote or Keypad"</code></pre>
<p style="text-align: justify;"><strong>Les conditions</strong> : Dans mon cas je n'en ai pas utilis&eacute;. Chacun adaptera.</p>
<pre class="language-yaml"><code>  condition:</code></pre>
<p style="text-align: justify;"><strong>Les actions</strong> :&nbsp;</p>
<p style="text-align: justify;">Je commence par arr&ecirc;ter les &eacute;ventuels scripts en cours. Cela est principalement utile quand on a ferm&eacute; la porte, arm&eacute; le syst&egrave;me et que l'on doit rapidement d&eacute;sarmer car on a oubli&eacute; quelque chose dans la maison.</p>
<pre class="language-yaml"><code>  action:
    - service: homeassistant.turn_off
      target:
        entity_id:
          - script.privacy_on
          - script.privacy_off
          - script.alarmo_after_arm
          - script.alarmo_after_disarm
          - script.alarm_actions_on_leave_common_tasks
          - script.alarm_actions_on_return_common_tasks</code></pre>
<p style="text-align: justify;">Ensuite on va utiliser <code>chose:</code> pour ex&eacute;cuter les diff&eacute;rentes actions en fonction de la source et de l'&eacute;tat.</p>
<p style="text-align: justify;">On commence par l'armement en mode absent :</p>
<ul style="text-align: justify;">
<li style="text-align: justify;">On envoie les bips d'armement sur la sir&egrave;ne. En MQTT pour l'instant car elle aussi est tr&egrave;s mal g&eacute;r&eacute;e sous ZHA</li>
<li style="text-align: justify;">On arme Alarmo</li>
<li style="text-align: justify;">On arme Visonic (en mode Home sans les PIR qui d&eacute;raillent).</li>
<li style="text-align: justify;">On arme notre panneau d'alarme virtuel qui nous servira au d&eacute;sarmement</li>
<li style="text-align: justify;">On arme &eacute;galement le clavier, &ccedil;a ne change rien &agrave; l'usage mais quand on se pr&eacute;sentera pour d&eacute;sarm&eacute; il apparaitra comme &eacute;tant arm&eacute;. Dans la pratique &ccedil;a relance de fait l'automation avec la m&ecirc;me automation, et donc &ccedil;a fausse le message, j'ai donc retir&eacute; cette option pour l'instant. (D'ailleurs si vous &ecirc;tes sous Z2M il le d&eacute;veloppeur d'Alarmo a fait <a href="https://community.home-assistant.io/t/zigbee2mqtt-control-alarmo-via-keypad/420016" target="_blank" rel="noopener">un joli travail</a> pour ce clavier).</li>
<li style="text-align: justify;">On inscrit un message texte dans un <code>input_text:</code> que l'on affiche dans Lovelace et qui nous permet de savoir qui fait quoi. A terme je remplacerait les <code>id:</code> par le pr&eacute;nom de l'utilisateur pour plus de lisibilit&eacute;.</li>
</ul>
<pre class="language-yaml"><code>    - choose:
        - conditions: "{{ trigger.id in ['KeyPad Away', 'Heiman RC1 Away', 'Heiman RC2 Away', 'Woox RC1 Away'] }}"
          sequence:
            - service: mqtt.publish
              data:
                topic: zigbee2mqtt/Sir&egrave;ne SMaBiT/set
                payload: &gt;-
                  {"squawk": {"state": "system_is_armed", "level": "veryhigh", "strobe": "true"}}     
            - service: alarm_control_panel.alarm_arm_away # ALARMO Away
              data:
                code: !secret alarm_code
              entity_id: alarm_control_panel.alarmo
            - service: alarm_control_panel.alarm_arm_home # VISONIC Home (ne jamais armer AWAY &agrave; cause des d&eacute;tecteurs HS)
              data:
                code: !secret alarm_code_visonic
              entity_id: alarm_control_panel.visonic_alarm
            - service: script.alarm_actions_on_leave_common_tasks
            - service: alarm_control_panel.alarm_arm_away # FAKE ALARM PANEL Away
              target:
                entity_id: alarm_control_panel.home_alarm_command
            - service: alarm_control_panel.alarm_arm_away # On arme le clavier afin qu'il apparaisse arm&eacute;
              data:
                code: !secret alarm_code_zha
              target:
                entity_id: 
                  - alarm_control_panel.lk_zb_keypad
            - service: input_text.set_value
              target:
                entity_id: input_text.last_arm
              data:
                value: "{{now().strftime('%d/%m/%Y, %H:%M:%S')}} &gt; Arm Away by : {{ trigger.id }}"                            </code></pre>
<p style="text-align: justify;">On fait la m&ecirc;me chose pour le mode home. Je fais l'impasse sur Visonic, par contre j'&eacute;met un son de confirmation sur un buzzer (on verra plus loin l'utilisation possible d'un TTS sur une enceinte.</p>
<pre class="language-yaml"><code>        - conditions: "{{ trigger.id in ['KeyPad Home', 'Heiman RC1 Home', 'Heiman RC2 Home', 'Woox RC1 Home'] }}"
          sequence:
            - service: alarm_control_panel.alarm_arm_home # ALARMO Home
              data:
                code: !secret alarm_code
              entity_id: alarm_control_panel.alarmo
            - service: alarm_control_panel.alarm_arm_home # FAKE ALARM PANEL Home
              target:
                entity_id: alarm_control_panel.home_alarm_command
            - service: alarm_control_panel.alarm_arm_home # On arme le clavier afin qu'il apparaisse arm&eacute;
              data:
                code: !secret alarm_code_zha
              target:
                entity_id: 
                  - alarm_control_panel.lk_zb_keypad

            - service: button.press
              target:
                entity_id: button.up_chime_play_buzzer
            - service: input_text.set_value
              target:
                entity_id: input_text.last_arm
              data:
                value: "{{now().strftime('%d/%m/%Y, %H:%M:%S')}} &gt; Arm Home by : {{ trigger.id }}"                                    </code></pre>
<p style="text-align: justify;">Ensuite on passe au d&eacute;sarmement du mode absent. On remarque que l'on &eacute;crit pas d'<code>input_text:</code> car ici on ne sait pas qui a fait quoi car l'ordre vient de la seconde automation que l'on verra plus loi. C'est donc elle qui &eacute;crira. Par contre on &eacute;met le son de d&eacute;sarmement sur la sir&egrave;ne.</p>
<pre class="language-yaml"><code>        - conditions: "{{ trigger.id in ['Remote or Keypad'] and is_state('alarm_control_panel.alarmo', 'armed_away') }}"
          sequence:              
            - service: alarm_control_panel.alarm_disarm
              data:
                code: !secret alarm_code
              entity_id:  
                - alarm_control_panel.alarmo
                - alarm_control_panel.visonic_alarm
            - service: mqtt.publish
              data:
                topic: zigbee2mqtt/Sir&egrave;ne SMaBiT/set
                payload: &gt;-
                  {"squawk": {"state": "system_is_disarmed", "level": "veryhigh", "strobe": "true"}}       </code></pre>
<p style="text-align: justify;">Pareil pour le mode Home. Ici on joue un son sur le buzzer.</p>
<pre class="language-yaml"><code>        - conditions: 
            - "{{ trigger.id in ['Push Button'] }}"
            - "{{ is_state('alarm_control_panel.alarmo', 'armed_home') }}"
          sequence:              
            - service: alarm_control_panel.alarm_disarm
              data:
                code: !secret alarm_code
              entity_id:  
                - alarm_control_panel.alarmo
            - service: button.press
              target:
                entity_id: button.up_chime_play_buzzer</code></pre>
<p style="text-align: justify;">On continue avec la gestion du bouton d'urgence :</p>
<ul style="text-align: justify;">
<li style="text-align: justify;">On joue un son pour confirmer</li>
<li style="text-align: justify;">On arme notre panneau d'alarme virtuel dans un mode inutilis&eacute; (Nuit) pour ensuite pouvoir d&eacute;sarmer.</li>
<li style="text-align: justify;">On envoie un SMS d'Au Secours, ou toute autre action &agrave; imaginer.</li>
<li style="text-align: justify;">On &eacute;crit un <code>input_text:</code> pour avoir une trace.</li>
</ul>
<pre class="language-yaml"><code>        - conditions: "{{ trigger.id in ['KeyPad Triggered', 'Heiman RC1 Triggered', 'Heiman RC2 Triggered', 'Woox RC1 Triggered'] and is_state('alarm_control_panel.alarmo', 'disarmed') }}"
          sequence:              
            - service: button.press
              target:
                entity_id: button.up_chime_play_chime
            - service: alarm_control_panel.alarm_arm_night # FAKE ALARM PANEL Night pour pouvoir d&eacute;sarmer
              target:
                entity_id: alarm_control_panel.home_alarm_command
            - service: notify.free_mobile_andre
              data:
                message: "{{ states.sensor.date_time.state}} &gt; TEST Alerte au secours par t&eacute;l&eacute;commande TEST"
            - service: input_text.set_value
              target:
                entity_id: input_text.last_arm
              data:
                value: "{{now().strftime('%d/%m/%Y, %H:%M:%S')}} &gt; Triggered by : {{ trigger.id }}"   </code></pre>
<p style="text-align: justify;">Enfin, on d&eacute;sarme cette alerte. A ce stade on peut aussi envoyer un SMS pour dire que c'&eacute;tait une fausse alerte... Je vais me contenter de jouer du buzzer...</p>
<pre class="language-yaml"><code>        - conditions: 
            - "{{ trigger.id in ['Remote or Keypad'] and is_state('alarm_control_panel.alarmo', 'disarmed') }}"
          sequence:              
            - service: button.press
              target:
                entity_id: button.up_chime_play_buzzer</code></pre>
<p style="text-align: center;"><img src="http://canaletto.fr/image.axd?picture=/images/Alarm_09.png" width="500" /></p>
<h3 style="text-align: justify;">Gestion des commandes de d&eacute;sarmement</h3>
<p style="text-align: justify;">Au risque de me r&eacute;p&eacute;ter, cette partie aurait pu &ecirc;tre int&eacute;gr&eacute;e &agrave; la premi&egrave;re automation, si ZHA ne posait pas probl&egrave;me... Je le ferait probablement, mais pour l'exemple on va pour l'instant scinder cette partie.</p>
<p style="text-align: center;"><img src="http://canaletto.fr/image.axd?picture=/images/Alarm_01_remote.png" width="395" height="287" /></p>
<p style="text-align: justify;">Donc, pour les t&eacute;l&eacute;commandes d'alarme sous ZHA on va devoir &eacute;couter un <code>event:</code>, s'en servir pour d&eacute;sarmer nos syst&egrave;me d'alarme mais &eacute;galement pour la d&eacute;sarmer et d&eacute;sarmer ses copines ainsi que le clavier. Simple ! J'avais explor&eacute; dans <a href="http://canaletto.fr/post/home-assistant-and-remote-alarm" target="_blank" rel="noopener">un pr&eacute;c&eacute;dent article plusieurs pistes</a> afin de ne prendre en compte qu'un seul de ses "<em>events</em>" (en + elle en envoie 3 ou 4 identiques selon l'humeur et le mod&egrave;le). J'ai un peu avanc&eacute; et on ne va pas les &eacute;couter dans l'automation, mais se servir de l'&eacute;tat temporaire d'un <code>binary_sensor:</code> que l'on va pouvoir temporiser et ainsi ne prendre en compte qu'un seul <code>event:</code></p>
<pre class="language-yaml"><code>template:
  - trigger:
      - platform: event
        event_type: zha_event
        event_data:
          device_ieee: a4:c1:38:96:0b:cf:c9:61 # Woox RC1
          command: 'arm'
          args:
            arm_mode: 0
            arm_mode_description: 'Disarm'
            code: ''
            zone_id: 0
    binary_sensor:
      name: Woox RC1 to Disarmed
      icon: "{{ (trigger.platform == 'event') | iif('mdi:remote-off', 'mdi:remote') }}"
      state: "{{ trigger.platform == 'event' }}"
      auto_off:
        seconds: 5</code></pre>
<p style="text-align: justify;"><strong>Les d&eacute;clencheurs</strong> : Ici on va &eacute;couter des actions de d&eacute;sarmement, que cela provienne d'un clavier, une t&eacute;l&eacute;commande (via leur <code>binary_sensor:</code>), ou en direct pour une source classique (tag RFID, MQTT, ...).</p>
<pre class="language-yaml"><code>- id: '2bd0ertyyf-43fa-45f98f-aed0-disarm'
  alias: "Alarm @ Remote Disarm"
  description: 'Disarm Remote Control panel'
  mode: single
  trigger:
    - platform: state
      entity_id: binary_sensor.heiman_rc1_to_disarmed
      to: "on"
      id: "Heiman RC 1"  
    - platform: tag
      tag_id: 2b855225-c999-4b5558123-6c7d12345641
      id: "TAG Jaune"
    - platform: device
      domain: mqtt
      device_id: 139eb4ce27246465b0d5aa7560a953601
      type: action
      subtype: disarm
      discovery_id: 0x84fd27fffe915905 action_disarm
      id: "Heiman RC2"</code></pre>
<p style="text-align: justify;"><strong>Les conditions</strong> : Aucune, mais on pourrait imagine un flag de blocage activ&eacute; &agrave; distance apr&egrave;s une alerte...</p>
<pre class="language-yaml"><code>condition:</code></pre>
<p style="text-align: justify;"><strong>Les actions</strong> : On utilise un chose: et on commence par :</p>
<ul style="text-align: justify;">
<li style="text-align: justify;">D&eacute;sarmer le panneau d'alarme virtuel, ce qui d&eacute;clenchera l'action idoine dans la premi&egrave;re automation.</li>
<li style="text-align: justify;">D&eacute;sarmer les t&eacute;l&eacute;commandes et claviers qui sont &eacute;galement des panneaux d'alarme, avec cette particularit&eacute; ZHA qui fait qu'il faut un code pour d&eacute;sarmer une t&eacute;l&eacute;commande...</li>
<li style="text-align: justify;">Ecrire un <code>input_text:</code> afin de savoir qui a d&eacute;sarm&eacute;.</li>
<li style="text-align: justify;">J'envoie un message dans Slack qui me sert de log. Ca va &eacute;galement m'informer &agrave; distance que quelqu'un est arriv&eacute; et a d&eacute;sarm&eacute;&nbsp;</li>
</ul>
<pre class="language-yaml"><code>  action:
    - choose: # DISARM
        - conditions: "{{ trigger.id in ['Push Button', 'KeyPad', 'Linkind RC', 'Heiman RC 1', 'Woox RC 1', 'TAG Porte', 'TAG Jaune', 'TAG Cl&eacute;', 'TAG Carte', 'Heiman RC2' ] }}"
          sequence:
            - service: alarm_control_panel.alarm_disarm   # FAKE ALARM PANEL to Command
              data:
                code: "1234"
              target:
                entity_id: alarm_control_panel.home_alarm_command
            - service: alarm_control_panel.alarm_disarm
              data:
                code: !secret alarm_code_zha
              target:
                entity_id: 
                  - alarm_control_panel.lk_zb_keypad
                  - alarm_control_panel.lk_zb_remote
                  - alarm_control_panel.heiman_remote
                  - alarm_control_panel.woox_01
            - service: input_text.set_value
              target:
                entity_id: input_text.last_disarm
              data:
                value: "{{now().strftime('%d/%m/%Y, %H:%M:%S')}} &gt; Disarm by : {{ trigger.id }}"
            - service: notify.slack_hass_canaletto
              data:
                message: "{{now().strftime('%d/%m/%Y, %H:%M:%S')}} &gt; Disarmed by : {{ trigger.id }}" </code></pre>
<p style="text-align: justify;">On peut &eacute;galement faire une place &agrave; une fonctionnalit&eacute; d&eacute;tourn&eacute;e du clavier. En effet au del&agrave; de l'amen&eacute;e Home, Away et Emergency, on peut &eacute;galement lui faire avaler n'importe quel code et effectuer une action pr&eacute;cise en fonction de celui ci. Ici si je saisit 33 et valide je vais allumer les projecteurs.</p>
<pre class="language-yaml"><code>    - choose:
        - conditions: "{{ trigger.id in ['KeyPad 33'] }}"
          sequence:
            - service: light.turn_off
              target:
                entity_id:
                  - light.groupe_de_projecteurs          
</code></pre>
<p style="text-align: justify;">Enfin j'ai quelques actions par d&eacute;faut, comme &eacute;teindre les sir&egrave;nes au cas ou... (&ccedil;a sent le debug...).</p>
<pre class="language-yaml"><code>    - service: mqtt.publish
      data:
        topic: zigbee2mqtt/Sir&egrave;ne SMaBiT/set
        payload: &gt;-
          {"warning": {"mode": "stop"}}
    - service: siren.turn_off
      target:
        entity_id:
          - siren.heiman_sirene_1
          - siren.heiman_sirene_2
          - siren.sirene_terrasse                
</code></pre>
<p style="text-align: justify;"><span style="text-decoration: line-through;">Et surtout <span style="background-color: #fbeeb8;">on ajoute un d&eacute;lai</span> car ces t&eacute;l&eacute;commandes ont la f&acirc;cheuse id&eacute;e d'envoyer 3 ou 4 <code>event:</code> identique pour chaque appui. Donc combin&eacute; au <code>mode: single</code> de cette automation, on va en capturer qu'un seul. Ce d&eacute;lais est bien sur &agrave; ajuster plus ou moins au pif...</span> Maintenant que je passe par des <code>binary_sensor:</code> temporis&eacute;s, je pense que ce d&eacute;lai est devenu inutile.</p>
<pre class="language-yaml"><code>    - delay : '00:00:08'</code></pre>
<h3 style="text-align: justify;">Les actions POST Armement / D&eacute;sarmement</h3>
<p style="text-align: justify;">On va utiliser deux scripts qui seront ex&eacute;cut&eacute;s par Alarmo apr&egrave;s l'armement et apr&egrave;s le d&eacute;sarmement. Chez moi ils vont servir &agrave; :</p>
<ul style="text-align: justify;">
<li style="text-align: justify;">Jouer une annonce vocale en TTS sur une enceinte ext&eacute;rieure pour annoncer l'&eacute;tat arm&eacute; ou d&eacute;sarm&eacute;.</li>
<li style="text-align: justify;">Activer ou d&eacute;sactiver la vid&eacute;o surveillance.</li>
<li style="text-align: justify;">Passer les volets en mode manuel et automatique au retour (voir l'automatisation des volets).</li>
<li style="text-align: justify;">G&eacute;rer le mode ECO/Absent du climatiseur et des convecteurs.</li>
<li style="text-align: justify;">G&eacute;rer les &eacute;clairages et le mode veille de mon PC.</li>
<li style="text-align: justify;">Et plus encore selon votre imagination....</li>
</ul>
<p><img style="display: block; margin-left: auto; margin-right: auto;" src="http://canaletto.fr/image.axd?picture=/images/Alarm_08.png" /></p>
<h3 style="text-align: justify;">Les notifications d'alarme et sir&egrave;nes</h3>
<ul style="text-align: justify;">
<li style="text-align: justify;">Notifications SMS pour l'intrusion, la d&eacute;tection incendie ou fuite d'eau. (notifications g&eacute;r&eacute;es par Alarmo).</li>
<li style="text-align: justify;">Sir&egrave;nes et projecteurs en cas d'intrusion :
<ul>
<li>la l&eacute;gislation autorise au maximum 3 minutes pour chaque lancement de sir&egrave;ne.</li>
<li>Pas de limite pour les projecteurs. Et &eacute;clairer comme en plein jour peut &eacute;galement faire fuir et permettra d'avoir des images bien nettes sur les cam&eacute;ras.</li>
<li>Si vous avez un syst&egrave;me audio multi room bien puissant, vous pouvez &eacute;galement envoyer une bonne salve d'AC-DC, &ccedil;a peu perturber... ou inciter les voisins &agrave; appeler la mar&eacute;chauss&eacute;e.</li>
<li>Les armes, explosifs et autres gaz toxiques sont &agrave; proscrire.</li>
</ul>
</li>
</ul>
<p style="text-align: justify;">Pour cela on va utiliser des scripts: qui seront lanc&eacute;s par Alarmo selon les conditions choisies (voir <a href="http://canaletto.fr/post/home-assistant-and-sirenes" target="_blank" rel="noopener">ici</a>).</p>
<p style="text-align: justify;">Etant donn&eacute; que j'ai des d&eacute;tecteurs d'ouverture sur mes volets roulants, je peux &eacute;galement imaginer l'&eacute;clairage ext&eacute;rieur avant de d&eacute;clencher l'alarme si un de ces volets est touch&eacute;. Il faut &ecirc;tre pr&eacute;venant et &eacute;clairer l'intrus. Cela peut se gr&eacute;er dans une partition secondaire d'Alarmo, ou simple une automation. Les cam&eacute;ras Unifi Protect (G4) font &eacute;galement de la d&eacute;tection de personne qui remonte dans Home Assistant.</p>
<p style="text-align: justify;">Voil&agrave;, ce n'est pas exhaustif, vos id&eacute;es son les bienvenues, ici ou sur <a href="https://forum.hacf.fr/t/alarme-encore/21838" target="_blank" rel="noopener">HACF</a>.</p>
<p style="text-align: justify;">&nbsp;</p>
<p style="text-align: justify;">&nbsp;</p>";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:4:"link";a:1:{i:0;a:5:{s:4:"data";s:56:"http://canaletto.fr/post/home-assistant-and-alarm-encore";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:8:"comments";a:1:{i:0;a:5:{s:4:"data";s:64:"http://canaletto.fr/post/home-assistant-and-alarm-encore#comment";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:4:"guid";a:1:{i:0;a:5:{s:4:"data";s:69:"http://canaletto.fr/post.aspx?id=9217dc3a-beac-408d-9078-45b874365a1a";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:7:"pubDate";a:1:{i:0;a:5:{s:4:"data";s:33:"lun., 13 mars 2023 00:01:00 +0100";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:8:"category";a:1:{i:0;a:5:{s:4:"data";s:9:"Domotique";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}s:34:"https://blogengine.io/schemas/tags";a:1:{s:3:"tag";a:5:{i:0;a:5:{s:4:"data";s:4:"HASS";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:1;a:5:{s:4:"data";s:6:"Hassio";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:2;a:5:{s:4:"data";s:6:"Alarme";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:3;a:5:{s:4:"data";s:6:"Alarmo";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:4;a:5:{s:4:"data";s:6:"Remote";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}s:32:"http://purl.org/dc/elements/1.1/";a:1:{s:9:"publisher";a:1:{i:0;a:5:{s:4:"data";s:5:"Admin";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}s:52:"http://madskills.com/public/xml/rss/module/pingback/";a:2:{s:6:"server";a:1:{i:0;a:5:{s:4:"data";s:32:"http://canaletto.fr/pingback.axd";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:6:"target";a:1:{i:0;a:5:{s:4:"data";s:69:"http://canaletto.fr/post.aspx?id=9217dc3a-beac-408d-9078-45b874365a1a";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}s:38:"http://purl.org/rss/1.0/modules/slash/";a:1:{s:8:"comments";a:1:{i:0;a:5:{s:4:"data";s:1:"5";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}s:53:"http://madskills.com/public/xml/rss/module/trackback/";a:1:{s:4:"ping";a:1:{i:0;a:5:{s:4:"data";s:73:"http://canaletto.fr/trackback.axd?id=9217dc3a-beac-408d-9078-45b874365a1a";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}s:36:"http://wellformedweb.org/CommentAPI/";a:2:{s:7:"comment";a:1:{i:0;a:5:{s:4:"data";s:64:"http://canaletto.fr/post/home-assistant-and-alarm-encore#comment";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:10:"commentRss";a:1:{i:0;a:5:{s:4:"data";s:77:"http://canaletto.fr/syndication.axd?post=9217dc3a-beac-408d-9078-45b874365a1a";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}}}i:9;a:6:{s:4:"data";s:166:"
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
    ";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";s:5:"child";a:7:{s:0:"";a:7:{s:5:"title";a:1:{i:0;a:5:{s:4:"data";s:43:"VMWare ESXi sur Nuc 9 &amp; SSD firmware...";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:11:"description";a:1:{i:0;a:5:{s:4:"data";s:10810:"<p style="text-align: justify;">Comme je vous en avait parl&eacute; <a href="http://canaletto.fr/post/vmware-esxi-nuc-9" target="_blank" rel="noopener">ici</a>, j'ai remplac&eacute; mon serveur ESXi HP ML350p par un Nuc 9. Depuis plus de 6 mois &ccedil;a fonctionne tr&egrave;s bien.</p>
<p style="text-align: justify;">Dans ce Nuc j'ai install&eacute; deux SSD NVMe Samsung 980 Pro. Les performance sont au top, mais voil&agrave; que plusieurs utilisateurs se plaignent que leurs SSD s'usent pr&eacute;matur&eacute;ment et finissent par passer en R/O. C'est d'autant plus f&acirc;cheux que sous ESX on ne dispose de rien pour surveiller les disques sur un NUC, celui ci ne remontant pas de donn&eacute;es IPML comme le ferait un vrai serveur. Apr&egrave;s avoir fait un peu la sourde oreille, Samsung a fini par sortir <a href="https://semiconductor.samsung.com/consumer-storage/support/tools/" target="_blank" rel="noopener">la mise &agrave; jour</a> idoine.</p>
<p style="text-align: center;"><img src="http://canaletto.fr/image.axd?picture=/images/nuc_ssd_updat_05.png" width="600" /></p>
<p style="text-align: justify;">Sous Windows il est tr&egrave;s facile de mettre &agrave; jour (ou de migrer) un SSD, il suffit de lancer Samsung Magician et le tour est jou&eacute; ! Sous VMWare ESXi rien de tout &ccedil;a et il va falloir le faire &agrave; la mano. Heureusement pour cela Samsung fournit &eacute;galement les firmawares sous la forme d'une ISO, il suffit, en principe, de le griller sur une cl&eacute; USB et de booter avec et de faire la mise &agrave; jour. Mais &ccedil;a c'est la th&eacute;orie. Dans la pratique j'ai appris &agrave; mes d&eacute;pends que cette cl&eacute; bas&eacute;e sur un vieux Linux &eacute;tait incapable de booter sur du mat&eacute;riel moderne, et quand elle boote certains disent m&ecirc;me qu'elle ne reconnait que les claviers PS2... Allons donc !</p>
<p style="text-align: justify;">Apr&egrave;s quelques recherches j'ai d&eacute;couvert qu'il existait un contournement possible mis en pratique par la communaut&eacute; Linux, mais nullement support&eacute;e par Samsung qui doit consid&eacute;rer que ses SSD sont destin&eacute;s uniquement &agrave; l'environnement Windows, tout comme VMWare qui a sa liste de hardware support&eacute;...</p>
<p style="text-align: justify;">L'astuce consiste &agrave; booter sous Linux, un Live CD Ubuntu. Facile, non pas si simple car ce live CD ne voulait lui non plus pas booter. Le bios de ce Nuc n'&eacute;tant pas de toute fraicheur j'en profite pour le mettre &agrave; jour sans plus de succ&egrave;s.</p>
<p><img style="display: block; margin-left: auto; margin-right: auto;" src="http://canaletto.fr/image.axd?picture=/images/nuc_ssd_updat_01.png" width="600" /></p>
<p style="text-align: justify;">J'ai fini par trouver que pour booter sous Ubuntu il fallait d&eacute;sactiver TPM et SGX. Ca ne s'invente pas mais j'ai fini par pouvoir booter mon Ubuntu Live.</p>
<p style="text-align: justify;">Une fois sur le desktop de mon Ubuntu je copie l'ISO de mise &agrave; jour (<code>Samsung_SSD_980_PRO_5B2QGXA7.iso</code>) que j'ai au pr&eacute;alable pr&eacute;par&eacute;e sur une autre cl&eacute; USB vers le r&eacute;pertoire Home et je monte le volume. Ensuite toujours depuis l'interface graphique j'extrait le fichier <code>initrd</code> un r&eacute;pertoire (<code>/home/samsung</code> par exemple). Ensuite je vais jusqu'&agrave; <code>/home/samsung/initrd/root/fumagician</code> et je peux lancer la mise &agrave; jour de mes SSD :</p>
<pre class="language-yaml"><code>sudo ./fumagicien</code></pre>
<p style="text-align: justify;">Je fais la mise &agrave; jour de mes deux SSD et je relance le Nuc. Attention, le bon num&eacute;ro de version n'apparaitra qu'&acirc;pres le prochain red&eacute;marrage. Donc m&ecirc;me si c'est un peu fastidieux, je vous conseille de relancer le Live CD pour v&eacute;rifier. De m&ecirc;me si vous avez d'autres machines &agrave; mettre &agrave; jour, vous pouvez sauvegarder <code>fumagician</code> sur une cl&eacute; pour &eacute;viter l'&eacute;tape de l'extraction.&nbsp;</p>
<p><img style="display: block; margin-left: auto; margin-right: auto;" src="http://canaletto.fr/image.axd?picture=/images/nuc_ssd_updat_02.png" width="600" /></p>
<p style="text-align: justify;">Il existe une autre m&eacute;thode en CLI pour les barbus, elle demandera toutefois de connecter le Live CE au r&eacute;seau si on veut &eacute;viter l'&eacute;tape de la cl&eacute; USB, mais in fine &ccedil;a revient au m&ecirc;me :</p>
<pre class="language-yaml"><code>wget https://semiconductor.samsung.com/resources/software-resources/Samsung_SSD_980_PRO_5B2QGXA7.iso
apt-get -y install gzip unzip wget cpio
mkdir /mnt/iso
sudo mount -o loop ./Samsung_SSD_980_PRO_5B2QGXA7.iso /mnt/iso/
mkdir /tmp/fwupdate
cd /tmp/fwupdate
gzip -dc /mnt/iso/initrd | cpio -idv --no-absolute-filenames
cd root/fumagician/
sudo ./fumagician</code></pre>
<p style="text-align: justify;">Voil&agrave; comment occuper (perdre) un apr&egrave;s-midi d'hiver !</p>
<p style="text-align: justify;">Attention toutefois, si vous avez cr&eacute;&eacute; un volume RAID, ce qui est discutable avec des SSD, il semblerait que vous ne puissiez les voir sans repasser le bios en AHCI.</p>
<p><img style="display: block; margin-left: auto; margin-right: auto;" src="http://canaletto.fr/image.axd?picture=/images/enjoyit.png" width="206" height="206" /></p>
<h3 style="text-align: left;">Sources</h3>
<ul>
<li style="text-align: left;"><span style="font-size: 10pt;"><a href="https://askubuntu.com/questions/1405963/ubuntu-22-04-failed-to-boot-on-intel-nuc-nuc9i9qnx-out-of-memory" target="_blank" rel="noopener">https://askubuntu.com/questions/1405963/ubuntu-22-04-failed-to-boot-on-intel-nuc-nuc9i9qnx-out-of-memory</a></span></li>
<li style="text-align: left;"><span style="font-size: 10pt;"><a href="https://www.phonandroid.com/samsung-ne-trouve-pas-de-solution-contre-la-degradation-rapide-de-ses-ssd-les-plus-performants.html" target="_blank" rel="noopener">https://www.phonandroid.com/samsung-ne-trouve-pas-de-solution-contre-la-degradation-rapide-de-ses-ssd-les-plus-performants.html</a></span></li>
<li style="text-align: left;"><span style="font-size: 10pt;"><a href="https://www.clubic.com/pro/entreprises/samsung/actualite-455880-samsung-publie-enfin-un-correctif-pour-ses-ssd-980-pro.html" target="_blank" rel="noopener">https://www.clubic.com/pro/entreprises/samsung/actualite-455880-samsung-publie-enfin-un-correctif-pour-ses-ssd-980-pro.html</a></span></li>
<li style="text-align: left;"><span style="font-size: 10pt;"><a href="https://semiconductor.samsung.com/resources/software-resources/Samsung_SSD_Firmware_Update_Utility_User_Manual_English.pdf" target="_blank" rel="noopener">https://semiconductor.samsung.com/resources/software-resources/Samsung_SSD_Firmware_Update_Utility_User_Manual_English.pdf</a></span></li>
<li style="text-align: left;"><span style="font-size: 10pt;"><a href="https://www.malekal.com/mettre-a-jour-firmware-ssd/" target="_blank" rel="noopener">https://www.malekal.com/mettre-a-jour-firmware-ssd/</a></span></li>
<li style="text-align: left;"><span style="font-size: 10pt;"><a href="https://semiconductor.samsung.com/consumer-storage/support/tools/" target="_blank" rel="noopener">https://semiconductor.samsung.com/consumer-storage/support/tools/</a></span></li>
<li style="text-align: left;"><span style="font-size: 10pt;"><a href="https://askubuntu.com/questions/1263336/unable-to-install-20-04-lts-on-intel-nuc-10i3fnh" target="_blank" rel="noopener">https://askubuntu.com/questions/1263336/unable-to-install-20-04-lts-on-intel-nuc-10i3fnh</a></span></li>
<li style="text-align: left;"><span style="font-size: 10pt;"><a href="https://help.ubuntu.com/rst/" target="_blank" rel="noopener">https://help.ubuntu.com/rst/</a></span></li>
<li style="text-align: left;"><span style="font-size: 10pt;"><a href="https://www.nextinpact.com/article/68212/nuc-9-pro-nuc9vxqnx-quartz-canyon-dintel-on-y-a-installe-deux-ssd-et-geforce" target="_blank" rel="noopener">https://www.nextinpact.com/article/68212/nuc-9-pro-nuc9vxqnx-quartz-canyon-dintel-on-y-a-installe-deux-ssd-et-geforce</a></span></li>
<li style="text-align: left;"><span style="font-size: 10pt;"><a href="https://www.storagereview.com/review/intel-nuc-9-pro-as-an-esxi-server" target="_blank" rel="noopener">https://www.storagereview.com/review/intel-nuc-9-pro-as-an-esxi-server</a></span></li>
<li style="text-align: left;"><span style="font-size: 10pt;"><a href="https://www.ubackup.com/enterprise-backup/esxi-recovery-mode.html" target="_blank" rel="noopener">https://www.ubackup.com/enterprise-backup/esxi-recovery-mode.html</a></span></li>
<li style="text-align: left;"><span style="font-size: 10pt;"><a href="https://bytespeed.com/nuc-bios-uefi-shell-update/" target="_blank" rel="noopener">https://bytespeed.com/nuc-bios-uefi-shell-update/</a></span></li>
<li style="text-align: left;"><span style="font-size: 10pt;"><a href="https://www.reddit.com/r/zfs/comments/fuqgoi/script_to_update_samsung_ssd_firmware/" target="_blank" rel="noopener">https://www.reddit.com/r/zfs/comments/fuqgoi/script_to_update_samsung_ssd_firmware/</a></span></li>
<li style="text-align: left;"><span style="font-size: 10pt;"><a href="https://apple.stackexchange.com/questions/387414/ssd-firmware-upgrade-requires-iso-on-a-pendrive-how-to-make-that-bootable" target="_blank" rel="noopener">https://apple.stackexchange.com/questions/387414/ssd-firmware-upgrade-requires-iso-on-a-pendrive-how-to-make-that-bootable</a></span></li>
<li style="text-align: left;"><span style="font-size: 10pt;"><a href="https://www.malekal.com/mettre-a-jour-firmware-ssd/" target="_blank" rel="noopener">https://www.malekal.com/mettre-a-jour-firmware-ssd/</a></span></li>
<li style="text-align: left;"><span style="font-size: 10pt;"><a href="https://blog.quindorian.org/2021/05/firmware-update-samsung-ssd-in-linux.html/" target="_blank" rel="noopener">https://blog.quindorian.org/2021/05/firmware-update-samsung-ssd-in-linux.html/</a></span></li>
<li style="text-align: left;"><span style="font-size: 10pt;"><a href="https://askubuntu.com/questions/1348219/how-to-update-samsung-ssd-firmware-from-ubuntu" target="_blank" rel="noopener">https://askubuntu.com/questions/1348219/how-to-update-samsung-ssd-firmware-from-ubuntu</a></span></li>
<li style="text-align: left;"><span style="font-size: 10pt;"><a href="https://www.youtube.com/watch?v=mAPWugrTO5Q" target="_blank" rel="noopener">https://www.youtube.com/watch?v=mAPWugrTO5Q</a></span></li>
<li style="text-align: left;"><span style="font-size: 10pt;"><a href="https://github.com/ventoy/Ventoy/issues/550" target="_blank" rel="noopener">https://github.com/ventoy/Ventoy/issues/550</a></span></li>
</ul>
<p>&nbsp;</p>";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:4:"link";a:1:{i:0;a:5:{s:4:"data";s:61:"http://canaletto.fr/post/vmware-esxi-nuc9-update-ssd-firmware";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:8:"comments";a:1:{i:0;a:5:{s:4:"data";s:69:"http://canaletto.fr/post/vmware-esxi-nuc9-update-ssd-firmware#comment";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:4:"guid";a:1:{i:0;a:5:{s:4:"data";s:69:"http://canaletto.fr/post.aspx?id=9efc2b9d-524d-442f-8beb-9d9b6e866358";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:7:"pubDate";a:1:{i:0;a:5:{s:4:"data";s:35:"dim., 12 févr. 2023 22:46:00 +0100";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:8:"category";a:1:{i:0;a:5:{s:4:"data";s:2:"IT";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}s:34:"https://blogengine.io/schemas/tags";a:1:{s:3:"tag";a:9:{i:0;a:5:{s:4:"data";s:7:"Samsung";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:1;a:5:{s:4:"data";s:3:"SSD";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:2;a:5:{s:4:"data";s:4:"NVMe";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:3;a:5:{s:4:"data";s:3:"ESX";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:4;a:5:{s:4:"data";s:4:"ESXi";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:5;a:5:{s:4:"data";s:6:"VMWare";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:6;a:5:{s:4:"data";s:5:"Linux";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:7;a:5:{s:4:"data";s:8:"Firmware";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}i:8;a:5:{s:4:"data";s:5:"NUC 9";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}s:32:"http://purl.org/dc/elements/1.1/";a:1:{s:9:"publisher";a:1:{i:0;a:5:{s:4:"data";s:5:"Admin";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}s:52:"http://madskills.com/public/xml/rss/module/pingback/";a:2:{s:6:"server";a:1:{i:0;a:5:{s:4:"data";s:32:"http://canaletto.fr/pingback.axd";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:6:"target";a:1:{i:0;a:5:{s:4:"data";s:69:"http://canaletto.fr/post.aspx?id=9efc2b9d-524d-442f-8beb-9d9b6e866358";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}s:38:"http://purl.org/rss/1.0/modules/slash/";a:1:{s:8:"comments";a:1:{i:0;a:5:{s:4:"data";s:1:"0";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}s:53:"http://madskills.com/public/xml/rss/module/trackback/";a:1:{s:4:"ping";a:1:{i:0;a:5:{s:4:"data";s:73:"http://canaletto.fr/trackback.axd?id=9efc2b9d-524d-442f-8beb-9d9b6e866358";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}s:36:"http://wellformedweb.org/CommentAPI/";a:2:{s:7:"comment";a:1:{i:0;a:5:{s:4:"data";s:69:"http://canaletto.fr/post/vmware-esxi-nuc9-update-ssd-firmware#comment";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:10:"commentRss";a:1:{i:0;a:5:{s:4:"data";s:77:"http://canaletto.fr/syndication.axd?post=9efc2b9d-524d-442f-8beb-9d9b6e866358";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}}}}}s:45:"http://backend.userland.com/blogChannelModule";a:2:{s:8:"blogRoll";a:1:{i:0;a:5:{s:4:"data";s:28:"http://canaletto.fr/opml.axd";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:5:"blink";a:1:{i:0;a:5:{s:4:"data";s:36:"https://canaletto.fr/syndication.axd";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}s:32:"http://purl.org/dc/elements/1.1/";a:2:{s:7:"creator";a:1:{i:0;a:5:{s:4:"data";s:7:"My name";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:5:"title";a:1:{i:0;a:5:{s:4:"data";s:12:"My Canaletto";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}s:40:"http://www.w3.org/2003/01/geo/wgs84_pos#";a:2:{s:3:"lat";a:1:{i:0;a:5:{s:4:"data";s:8:"0.000000";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}s:4:"long";a:1:{i:0;a:5:{s:4:"data";s:8:"0.000000";s:7:"attribs";a:0:{}s:8:"xml_base";s:0:"";s:17:"xml_base_explicit";b:0;s:8:"xml_lang";s:0:"";}}}}}}}}}}}}s:4:"type";i:128;s:7:"headers";a:14:{s:4:"date";s:29:"Sun, 26 Nov 2023 10:04:50 GMT";s:12:"content-type";s:19:"application/rss+xml";s:13:"cache-control";s:6:"public";s:13:"last-modified";s:29:"Mon, 20 Nov 2023 23:56:40 GMT";s:4:"etag";s:22:"W/"638361250000000000"";s:19:"content-disposition";s:24:"inline; filename=rss.xml";s:12:"x-powered-by";s:7:"ASP.NET";s:15:"cf-cache-status";s:7:"DYNAMIC";s:9:"report-to";s:233:"{endpoints:[{url:https:\/\/a.nel.cloudflare.com\/report\/v3?s=aZZVj5znwMVrqU%2Bn32L8cfd4HVN4ZOcLEhpiJsiXo7ELCb1ZG6QgG5YV8AsKh%2BNuq5djk8r4Y%2Bxd%2FGSGjoWnNStVjm7REaGbdNOUxu01aoD%2BaMKWHF9cOvqiwXkxpzk%3D}],group:cf-nel,max_age:604800}";s:3:"nel";s:52:"{success_fraction:0,report_to:cf-nel,max_age:604800}";s:6:"server";s:10:"cloudflare";s:6:"cf-ray";s:20:"82c14f401cb012b4-MRS";s:16:"content-encoding";s:2:"br";s:7:"alt-svc";s:17:"h3=:443; ma=86400";}s:5:"build";s:14:"20230304122624";s:5:"mtime";i:1700993090;s:3:"md5";s:32:"5aee2bbdb1d87fbc5607ccb26c505eb4";}