Home Assistant & Enedis

Dans le grand foutoir de la pseudo concurrence des fournisseurs d'électricité on trouve Enedis qui gère les infrastructures et vous colle d'autorité un compteur Linky. On ne va pas parler ici des polémiques que cela à suscité, sa dangerosité sanitaire est très certainement moindre que toutes les technologies que nous utilisons, tout au moins pourrais t'on s'interroger sur son cout global qui sera nécessairement répercuté sur les clients.

Ce qui m'intéresse ici c'est ce que l'on peut en faire. Enedis remonte en temps (presque) réel (toutes les heures) les informations de consommation et on peut donc imaginer qu'il est possible de récupérer facilement ces informations qui après tout nous appartiennent. En fait ce n'est pas si simple et il semblerait que ce soit tout le contraire, Enedis faisant tout pour en limiter l'usage à la consultation de son piètre site web, tout en ayant certainement une arrière pensé de monétisation possible... Ainsi, au fil du temps, les diverses extensions permettant la récupération de ces informations ont été mises en échec.

A ce jour, et d'après mes informations, la règle est que seule une société a la possibilité de demander un accès (gratuit pour l'instant) à l'API. Ca limite fortement nos habitudes de DIY !

Alors un développeur de la communauté (M4dm4rtig4n) a eu la riche idée, un projet personnel qui se sert de la façade légale de son employeur, de monter une passerelle d'accès : https://enedisgateway.tech. On lui fait confiance, il fera tout pour assurer la confidentialité des données, mais l'utilisation de cette passerelle sous entend de confier l'accès à vos données à cette société. Le risque est faible, les données peu sensibles, le jeton est révocable, et surtout rien ne vous force à utiliser cette passerelle qui pour l'instant est la seule solution fonctionnelle.

Dans la pratique

On commence, si ce n'est pas fait, par créer un compte sur le site Enedis et y associer votre compteur Linky. Attention, j'espère qu'Enedis maitrise mieux le réseau électrique que le CSS car il y a pas mal de bugs et il vaudra mieux faire tout ça avec Firefox, car aléatoirement ça ne passe pas sous Edge ou Chrome (qui est juste le navigateur le plus utilisé au Monde). Ensuite on se rend sur la passerelle (https://enedisgateway.tech) et on crée un token qui aura cette forme :

Votre token : 1ETPfWPjxmkHe2GfsggdfhdgfshgfhgfNRKnhdgfhMpOrGzKe3i

Vos points de livraison : 258465654641

Il ne faut pas oublier d'activer l'enregistrement de la consommation horaire et de sa collecte si on veut disposer des infos HP/HC. Une commande de test est fournie, elle permettra de vérifier que ça fonctionne avant de passer à la suite

curl -X POST https://enedisgateway.tech/api -H 'Authorization: 1ETPfWPjxmkHe2G2hj87w8shfgsdfghsdfghhsfghgfhjsfOrGzKe3i' -H 'Content-Type: application/json' -d '{"type": "consumption_load_curve","usage_point_id": "25464656546695","start": "2020-11-10","end": "2020-11-11"}'

A partir de là on peu repasser sous Home Assistant et installer dans HACS deux Custom repositories créés par un autre développeur de talent (saniho) de la communauté HACF, qui correspondent d'une part à un composant qui va créer un sensor personnalisé, et d'autre part une carte pour Lovelace.

Une fois ces deux installations terminées on redémarre Home Assistant, et on crée le sensor, ce qui nécessitera un nouveau redémarrage.

sensor:
    - platform: myEnedis
      token: fTEHWCldfsgsdfghsjdhjdFGHJFHSDHDSFGhfdfhNfWqwCE3
      code: 464554438199434
      heures_creuses: "[['00:00','05:00'], ['21:30', '24:00']]"
      hc_cout: 0.1337
      hp_cout: 0.1781
      scan_interval: 3600
      delay: 7200  # OPTION

Après un redémarrage et le temps que tout se mette en place, le sensor.myenedis devrait nous retourner ces informations :

attribution: ''
version: 1.0.2.5
lastSynchro: '2020-11-20T23:51:21.456065'
lastUpdate: '2020-11-20T23:51:21.456048'
timeLastCall: '2020-11-20T23:51:21.456021'
yesterday: 53347
last_week: 240629
day_1: 53347
day_2: 42741
day_3: 42420
day_4: 30767
day_5: 36311
day_6: 35932
day_7: 32130
daily:
  - 53.347
  - 42.741
  - 42.42
  - 30.767
  - 36.311
  - 35.932
  - 32.13
halfhourly: []
offpeak_hours: 19.947
peak_hours: 33.4
peak_offpeak_percent: 62.60895645490843
yesterday_HC_cost: 2.6669139000000004
yesterday_HP_cost: 5.94854
daily_cost: 8.6154539
current_week: 169275
last_month: 909684
current_month: 702447
last_year: null
current_year: 2670999
errorLastCall: >-
  {'error': 'result_404', 'enedis_return': {'error': 'no_data_found',
  'error_description': 'no measure found for this usage point', 'error_uri':
  'https://bluecoder.enedis.fr/api-doc/consulter-souscrire'}}
monthly_evolution: 0
unit_of_measurement: kWh
friendly_name: myEnedis

Vous pourrez utiliser ces données à souhait, ce sont des attributs, mais le plus simple reste de créer une carte custom et on y coller ça :

type: 'custom:content-card-linky'
entity: sensor.myenedis
showInTableUnit: false

Et le résultat est tout de suite bien plus lisible. Voilà. Et pour suivre le projet ça se passe ici sur HACF.

Alternatives

Ici je vous ai parlé d'une solution native dans Home Assistant. Mais les afficionados de NodeRed vous diront que non, que c'est nul et qu'il faut le faire en NR. Vu que je ne parle jamais de NodeRed, vous avez déjà compris que je ne suis pas fan, même si j'ai pas mal testé et que je trouve le concept génial, pour l'heure je préfère me cantonner au YAML, après tout j'en ai bien chié pour comprendre, et comme disais ma tante qui n'avais jamais eu de descendance, je ne vais pas jeter tout de suite le bébé avec l'eau du bain ! Mais bon, pour ceux qui veulent faire tout ça avec NodeRed, ça se passe ici, toujours sur HACF.

Une autre possibilité est de se servir de la prise Teleinfo que l'on trouve sur les compteurs, mêmes plus anciens. Il existe plusieurs montages DIY, certains à base ESP et même sous Tasmota. Mais ça on en reparlera bientôt.

EDIT 18/03/2021 : Cette intégration comporte deux dépendances de taille. Enedis dont la plateforme est instable et n'a aucune volonté de rendre ces donnes disponibles, tout au moins gratuitement et facilement. Du coup seul les professionnels peuvent y accéder, mais certains fournisseurs alternatifs commencent à proposer une API. L'autre dépendance c'est l'intermédiaire bénévole sur lequel s'appui cette intégration. Il faut de son mieux tout comme le développeur. Mais voir cette intégration cassé lors de chaque redémarrage, devoir régulièrement refaire un consentement, bref, pas envie de revivre l'époque Jeedom avec des plugins instables. Donc j'ai désactivé, je reste en observation, mais je m'appuie sur mon Shelly EM, peut être un peu moins précis mais bien plus fiable pour l'instant.

 

Home Assistant, Shelly & Energy

Il y a quelques avantages à choisir des modules Shelly plutôt que des chinoiseries. D'abord ces modules sont aux normes européennes, et ce n'est pas juste un adhésif CE posé par un mineur au fond d'une usine chinoise (pensez surtout aux assurances qui peuvent se montrer tatillonnes en cas de sinistre), le tarif est accessible et si vous avez une question (technique ou autre) le CEO de la boite vous répondra dans le fil Facebook de la marque ou par mail.

Une chose intéressante est également que beaucoup de ces modules remontent la consommation instantanée et cumulée. Je pensais naïvement que tous conservaient la consommation cumulée en cas de coupure secteur, mais, même si dixit le CEO c'était vaguement en projet en 2019, ce n'est toujours pas le cas et cette information sera perdue localement (sauf EM), bien qu'elle reste accessible sur le cloud Shelly via l'application idoine, mais impossible à récupérer via l'API.

Pour conserver cette information je me suis un peu torturé l'esprit depuis quelques jours en cherchant différentes solutions pour stocker et conserver ce chiffre, alors qu'en fait la solution était sous mes yeux et que je l'avait déjà utilisée quand j'avais déployé mon module de calcul des couts électrique globaux. La solution passe par l'intégration utility_meter: proposée de base par Home Assistant.

Utility Meter est une intégration qui va permettre de stocker le cumul d'une valeur sur une période donnée (hourlydailyweeklymonthlybimonthlyquarterly and yearly), ainsi que la même valeur sur la période n-1. Par exemple, si vous configurez en journalier,  à 13:45 vous pourrez afficher (ou utiliser) la valeur de consommation d'un compteur depuis minuit ainsi que celle à la même heure pour le jour précédent. Imaginez juste le code et les template qu'il aurait fallut imaginer sans cette intégration...

En ce qui me concerne, en prenant par exemple un Shelly 1PM qui pilote un convecteur, ce qui va m'intéresser est de connaitre la consommation cumulée en cours et celle pour le même jour l'an dernier.

Bien sur il est possible, avec un peu d'imagination et quelques lignes de code YAML, de stocker les années précédentes dans un input_number: ou même l'évolution dans une base de données et pour les plus maniaques d'utiliser Grafana pour afficher de beaux histogrammes. Même si ça ne changera probablement rien à la facture EdF, en partant du principe que si la domotique apporte un indéniable confort, de part le surcoût induit elle permet au final rarement réaliser de vraies économies.

En pratique

Dans cet exemple j'utilise l'intégration Shelly for Hass, mais il est toute à fait possible de faire la même chose avec d'autres types de modules, voire en intégrant les modules Shelly (ou autres) avec MQTT...

On crée nos entrées utility_meter: dans notre fichier de configuration : 

utility_meter:
  energy_total_yearly_ch_bureau:
    source: sensor.shelly_shplg_s_f8ccf83_total_consumption
    cycle: yearly
    
  energy_total_yearly_ch_cheminee:
    source: sensor.shelly_shsw_pm_68c63afaf521_total_consumption
    cycle: yearly
    
  energy_total_yearly_ch_salon:
    source: sensor.shelly_shsw_pm_68c63afaf658_total_consumption
    cycle: yearly
    
  energy_total_yearly_ch_cuisine:
    source: sensor.shelly_shsw_pm_68c63afaf1ca_total_consumption
    cycle: yearly

Ensuite on va pouvoir les utiliser directement pour les afficher, ici dans une carte ou j'ai utilisé le composant multiple-entity-row pour les besoins de l'affichage. Vous remarquerez l'utilisation de l'attribut last_period pour afficher l'année précédente.

entities:
  - entities:
      - attribute: last_period
        name: Année passée
        unit: kWh
    entity: sensor.energy_total_yearly_ch_cheminee
    name: Convecteur Cheminée
    secondary_info: last-changed
    show_state: true
    state_header: Année en cours
    type: 'custom:multiple-entity-row'
title: Consomation cumulée
type: entities

Bonus

Etant donné que j'avais dans un séjour ouvert trois convecteurs qui fonctionnent en même temps, j'ai créé deux sensor: pour regrouper ces informations afin de pouvoir afficher une seule ligne pour le séjour, un pour l'année en cours et un pour l'année précédente, qui de fait sera à zéro pour un moment. Attention, utility_meter: commence à compter au moment ou les entrées sont crées.

- platform: template
  sensors:
    energy_total_yearly_ch_sejour:
        friendly_name: "Total Séjour"
        unit_of_measurement: 'kWh'
        value_template: "{{ 
            (states('sensor.energy_total_yearly_ch_cheminee') | float) +
            (states('sensor.energy_total_yearly_ch_cuisinee') | float) +
            (states('sensor.energy_total_yearly_ch_salon') | float) }}"

- platform: template
  sensors:
    energy_total_yearly_ch_sejour_last_period:
        friendly_name: "Total Séjour (N-1)"
        unit_of_measurement: 'kWh'
        value_template: "{{ 
            (states('sensor.energy_total_yearly_ch_cheminee.attributes.last_period') | float) +
            (states('sensor.energy_total_yearly_ch_cuisinee.attributes.last_period') | float) +
            (states('sensor.energy_total_yearly_ch_salon.attributes.last_period') | float) }}"

 

 

EDIT 21/01/2021 : On peut parfois avoir besoin de changer la valeur d'un utility_meter: . Dans les Outils de développement / Services vous trouverez un service utility_meter.calibrate et utility_meter.reset. Sauf qu'il y a un petit bugg et seuls les utility_meter: qui ont une option tariffs: s'affichent. Qu'à cela ne tienne, il suffit de coller le nom de l'entité + TAB et ensuite changer la valeur :

entity_id: sensor.energy_total_yearly
value: 25550

 

 

 

Home Assistant & Visonic

Jadis, quand j'ai commencé à m'intéresser à la domotique, avec une Zibase, j'avais intégré les capteurs de mon système d'alarme Visonic Powermaster Pro. Ensuite sous Jeedom je les ai perdus, j'ai bien tenté avec un RFPLayer, qui dans l'absolu intégrait la techno ZiBase, de les retrouver, mais sans succès tant le plugin dédié et payant étant en dessous de tout. Un échec de plus pour Jeedom, peu importe que ce soit de leur faite ou celle de ZiBlue qui ne fournissait que peu d'informations, le résultat était négatif.

Sous Home Assistant j'ai bien essayé de me servir de la ZiBase pour récupérer ces informations, mais je n'ai pas trop insisté et j'ai fini par tout doubler avec des capteurs Xiaomi/Aqara.

Jusqu'à ce que je découvre la semaine dernière qu'il existait une intégration Visonic ! Mais pour ça il faut que ça communique. La centrale a des options que je n'ai pas et j'étais moyennement chaud pour commander une option RS232 à 80 € sur un site exotique. En lisant un peu j'ai fini par découvrir que cette option ne faisait qu'exposer physiquement le signal qui existe en TTL sur des broches accessibles. Alors j'ai fait des tests avec un câble RS232, USB/RS232 et j'ai même acheté un adaptateur Ethernet / RS232 (USR-TCP232-302) mais ça succès alors que certains disent y être parvenus, et même une pince pour sertir des connecteurs Dupont (l'enfer !), bref je me suis cassé le crane tout un week-end sans succès.

Reste une solution que je n'ai jamais explorée, utiliser un ESP_01 avec le firmware ESP-Link qui convertir les signaux TTL série afin de pouvoir les utiliser en Ethernet depuis l'intégration sous Home Assistant.

Communication

Alors d'abord il faut se procurer le module ESP NodeMCU. Ca doit pouvoir fonctionner avec d'autres ESP et d'autres firmwares mais je me suis contenté de suivre ce que j'ai trouvé. Ca vaut 1 €, c'est minuscule et ca peut tenir dans la centrale qui ainsi devient "WI-FI" !

Pour flasher le firmware ESP-Link il faut un adaptateur USB que je n'avais pas commandé pensant pouvoir le faire avec mon adaptateur USB éclaté. Certains ESP ont un bouton pour les passer en mode flashage, sur celui ci rien de tel, pas plus que sur l'adaptateur... C'est un peu le mystère laissé par les barbus, ne pas tout documenter sans quoi ce serait trop facile, ce genre de montage ça se mérite ! Bref, il faut shunter IO0 et GND avant d'insérer l'objet dans le port USB, ça permet de passer en mode programmation (je l'ai fait juste avec un câble Dupont...).

Maintenant il va falloir trouver un outil de flashage. Mais les barbus bossent sous Linux, et même s'il est possible de faire du Bash ou du Python sous Windows, ma machine ne s'est pas avérée très coopérative...

curl -L https://github.com/jeelabs/esp-link/releases/download/v2.2.3/esp-link-v2.2.3.tgz | \
    tar xzf -
cd esp-link-v2.2.3
esptool.py --port /dev/ttyUSB0 --baud 460800 write_flash -fs 4m -ff 40m \
    0x00000 boot_v1.5.bin \
    0x1000 user1.bin \
    0x7C000 esp_init_data_default.bin \
    0x7E000 blank.bin

Si la plupart des outils de flashage sous Windows fonctionnent, et même Tasmotizer, (Mathieu si tu me lis...), on va avoir besoin ici de flasher plusieurs fichiers .bin à des adresses particulières et le seul utilitaire qui a fonctionné est NodeMCU Firmware Programmer, qui selon les ESP utilisés permet de les fichiers flasher au bon endroit...

Une fois cette opération réussie (YES ! Ca m'a pris l'après midi...), on peu détacher l'ESP_01 de son support USB et aller le brancher dans la centrale. Il sera alimenté en 3.5 v par elle et servira d'interface TCP/Serie. Visonic a prévu des connecteurs dans la centrale afin d'y connecter des cartes optionnelles et couteuses, sauf que les signaux sont disponibles sur les connecteurs et que les cartes ne servent qu'à supporter des connecteurs... Des petits malins on fait un joli travail de recherche (voir les sources). Le connecteur qui nous intéresse est celui de gauche et en branchant un petit câble Dupont à 4 fils sur les 4 du haut à droite on sortira aisément GND TX RX et les 3.75 v nécessaires à l'alimentation de notre ESP.

Il ne reste plus qu'à connecter ça à notre ESP aux bons endroits, en inversant RX/TX et en faisant attention au connecteur d'alimentation car il n'y a pas de fusible...

Ensuite on se connecte en WI-FI sur son SSID (ESPxxx) et on renseigne le réseau WI-FI que l'on consacre aux IoT dans l'onglet WI-FI Station, il redémarre et on peu le pinguer... On pense à le mettre en réservation DHCP... Le seul réglage qui nous intéresse est la vitesse (9600 ou 38400 selon les modèles de centrales), et même si ce firmware permet de faire du MQTT et autres joyeusetées on désactive tout, il ne servira qu'à ça !

Intégration à Home Assistant

Cette intégration j'ai du la lancer 50 fois, mais quand on a la bonne communication ça fonctionne du premier coup. Elle permet beaucoup de choses, mais le mode standard qui me permet de voir et utiliser mes capteurs est suffisant. Je m'en contenterais car dans mes bricolages j'ai perdu le code installateur de la centrale ce qui va me limiter à l'avenir ! (code impossible à reseter). EDIT : Je viens d'apprendre qu'on peut justement le récupérer, grâce à une fonction non documentée de cette intégration...

On installe donc l'intégration Visonic, encore un excellent travail d'un passionné, et on renseigne l'IP et le port (23) de notre ESP. Et c'est tout, comme par magie les capteurs remontent ainsi que le panneau de commande. Il sera ainsi possible d'armer et désarmer la centrale depuis Home Assistant (Géoloc, présence pour l'armement et tag NFC pour le désarmement dans mon cas) et de savoir quel capteur à déclenché l'alarme dans une notification (Slack, TG ou SMS), mais aussi de conserver un log (CSV et/ou XML).

Ce qui m'embête c'est que je me retrouve avec d'un coté mes capteurs Xiaomi / Aqara qui me servaient à l'alarme HA, à couper le chauffage quand on ouvre les fenêtre ou allumer une lampe en cas de passage, et mes capteurs Visonic qui peuvent faire la même chose... Bref, j'aurais su avant je ne me serait pas lâché sur Ali Express...

Bonus

Allez c'est cadeau. Pour utiliser le logiciel de configuration PowerMax depuis Windows :

Téléchargez le logiciel ici (mot de passe du fichier Zip : PowerMaxPRO) et la doc (spartiate) se trouve ici. Et pour rediriger le port série depuis Windows je vous conseille ceci. Il vous faudra le code de téléchargement (par défait AAAA)  que vous trouverez dans la centrale.

Et pour retrouver le code installateur depuis l'intégration HA, vous décommentez les lignes 2322 à 2326 dans le fichier pyvisonic.py (supprimez le «#»), définissez le paramètre de l'enregistreur sur débogage, puis regardez votre fichier journal pour le code d'installation [Paramètres de processus], vous verrez votre code d'installation.... Pas si sécure que ça....

Sources

J'ai écrit ça rapidement, mais voici mes sources qui contiennent pas mal d'informations pour qui voudra se lancer dans l'expérience

 

Unifi Dream Machine Pro

Chez les afficionados de la marque on a généralement tous commencé par un AP WI-FI. Et puis comme ça fonctionnait bien et que c'était beau on s'est laissé aller pour un USG, et là c'était beau, mais pas exempt de bugs et surtout limité en CPU pour exploiter une fibre ou DPI/IPS. Il y a bien eu l'USG Pro, pas vraiment beaucoup plus puissant. Sur tous ces modèles le VPN n'a jamais été le point fort et quant à faire de la publication il n'y a rien d'autre qu'une possible translation de ports entrants comme sur un vulgaire routeur grand public, si cela pouvais se comprendre sur les modèles précédents, on aurait aimé un reverse proxy sur la machine censée nous faire rêver !


(source Unifi)

Mais il n'en est rien, il faut considérer l'UDM Pro, et c'est son positionnement marketing, comme un routeur d'accès avec des services (Contrôleur Unifi, Unifi Protect, contrôle d'accès, téléphonie IP, etc..). Si l'on souhaite publier des services on regardera plutôt du coté de pfsense ou autres Appliance qui font ça très bien. Et si on veut faire du VPN,  ce qui est par contre dans la cible du produit, ce sera IPSEC ou OpenVPN. Zerotier ayant été porté sur la gamme Edge, il y a des chances que quelqu'un fasse le portage sur l'UDM Pro, voire qu'Unifi le fasse, à moins qu'ils ne se laissent tenter par WireGuard...

A 319 € (HT) l'UDM est un produit intéressant qui combine donc plusieurs fonctions : 

  • un USG performant avec fonctionnalités de firewall avancées (IPS/IDS, DPI)
  • un switch 8-port Gigabit et un port 10G SFP+, un port WAN Gigabit et un second port WAN en 10G SFP+ (de quoi y raccorder les nouveaux produits en 2.5 GB et 10 GB actuellement en Early accès et profiter des offre fibre en 2.5 GB ou 10 GB proposées par certains FAI).
  • un contrôleur UniFi (= CloudKey ou CloudKey Gen2+).
  • un NVR UniFi Video avec emplacement disque dur 3.5″ ou 2.5".
  • d'autres contrôleurs à venir (contrôle d'accès, téléphonie IP, et certainement quelques autres projets dans les cartons...).
  • et enfin comme tous les Gen2 de la marque on est en présence d'un petit écran de contrôle en face avant. Petit gadget pour doigts de fée !

Si le contrôleur Unifi intégré pourrait très bien trouver sa place ailleurs (VM, Cloud, ...), l'enregistreur vidéo (Unifi Protect), qui est identique, mais plus puissant que celui que l'on trouve sur le CloudKey 2+, constitue un vrai plus si on veut gérer un grand nombre de caméras et stocker jusque à 14 TB de vidéos de surveillance. A noter qu'il existe chez Unifi un autre NVR plus puissant avec le support de 4 disques.

Le NVR

Ca c'était le bla bla marketing annoncé. Dans la pratique Unifi Protect sur l'UDM Pro me semble bien bogué pour un produit sorti il y plus de six mois. Ca commence avec le disque dur, quelque soit le modèle installé parfois il le voit, parfois pas, et quand il le voit il ne l'exploite pas (impossibilité d'enregistrer). Certains conseillent de le retirer et de le formater en ext4, pas mieux, de juste supprimer les partitions, là il est visible mais non exploitable. Pas très normal qu'on ne puisse pas lancer l'initialisation/formatage depuis l'interface. Et je passe sur les paramètres des caméras qui sont pris en compte depuis l'application mobile mais impossible depuis le portail web qui lui répond que la caméra n'est pas reconnue, alors qu'elle l'est bien sur... A cette heure je regrette ma CloudKey 2+ !

Le routeur

Le routeur d'accès qui lui remplacera l'USG reste à apprécier à l'usage, Ca remplace mais ça reste un USG dont je ne vais pas reprendre le détail ici, un une partie qui mériterais de la part d'Unifi quelques évolutions, avec notamment l'intégration à l'interface de tout ce qui n'apparait pas mais reste faisable en CLI.

2 ports WAN, mais un seul en 10 G !

A noter que le WAN1 qui est en 1 GB est toujours le port principal WAN et que si on souhaite faire du failover on le fera avec le WAN 2 qui lui est en 10 GB (SFP+) ou en 1 GB en utilisant un adaptateur UF-RJ45-1G. C'est d'autant plus bête qu'en utilisation normale on peut imagine une grosse fibre sur le WAN principal et un xDSL en secours. Ca reste du soft, et on peut imaginer une évolution du firmware, et pourquoi ne pas banaliser tous les ports en WAN/LAN comme le fait Cisco depuis plus de 10 ans sur des produits SMB de la gamme RV.

Dans tous les cas, sur le papier, on reste sur de l'agrégation ou du failover utilisable en sortie, et pour l'instant c'est failover only (La seule solution intégrale d'agrégation via un tunnel restant l'OTB d'OVH ou sa version open source openMPTCP).

Quand au WI-FI contrairement à l'UDM, l'UDM Pro qui se place dans un rack n'intègre logiquement pas d'AP. Alors on est tout de même en droit de se demander pourquoi sur un produit qui est censé gérer des AP et des caméras en POE, on ne trouve aucun ports POE ? Je pense simplement qu'à la conception la question a bien du se poser, le marketing l'a emporté en argumentant que cela ferait vendre des commutateurs POE, produits sur lesquels la marge est certainement bien plus importante. C'est dommage car avec quelques ports POE l'UDM Pro aurait été presque parfait ! Business is business !

Un firmware intégré...

Contrairement aux habitudes prises avec Unifi, ici le firmware intègre tout, le firmware de la machine de base proprement dite (USG), le contrôleur Unfi Network, le contrôleur Unifi Protect et les autres applications... Si la bonne idée est de simplifier, on va voir que dans la pratique ce n'est pas si simple tant les versions sont évolutives chez eux...

Coïncidence, mon UDM Pro est arrivé le lendemain du jour ou j'ai mis à jour (par erreur) ma CloudKey 2+ avec le contrôleur avec 6.0.20. Mal m'en a pris car cette version, tout comme la suivante en 6.0.22 est tellement buggées qu'on peut aisément penser qu'elle a été lâchée en release par erreur (un stagiaire ?). Problème, la 6.0.x n'existe pas sur l'UDM Pro qui est en firmware 1.8 qui intègre le contrôleur en 5.x. Dès lors impossible de migrer une installation en 6.x vers du 5.x ! (il ne s'agit pas vraiment d'un process de migration mais une simple opération de backup/restaure, il faut donc que la source ait un niveau de release inférieur ou égal au contrôleur de destination).

Alors j'ai cherché, j'ai fini par installer la 1.8.1 RC3 qui n'apporte hélas pas de contrôleur en 6.x ... et pour finalement découvrir qu'il était possible de mettre à jour le contrôleur d'UDM Pro en SSH. Et pourquoi pas avec un bouton upload ? On a parfois l'impression qu'il y a chez Unifi pas mal d'ingés de l'ancien monde, ceux pour qui le CLI est et reste la seule option possible... Ce qui n'est pas très logique pour un constructeur qui se démarque avant tout par ses magnifiques interfaces !

ssh udm ...
unifi-os shell
cd /tmp
curl -o "unifi_sysvinit_all.deb" https://dl.ui.com/unifi/x.xx.xx_version/unifi_sysvinit_all.deb
dpkg -i unifi_sysvinit_all.deb 
rm unifi_sysvinit_all.deb 

Et comme je n'ai pas reçu ce produit du service de presse pour le tester, mais que je l'ai acheté pour l'utiliser, me voilà donc en principe dans la possibilité de migrer. Je fait un export du contrôleur et un export du NVR depuis la CK 2+ (je ne me pose pas la question d'exporter les vidéos de la CK 2+, mais il parait que c'est possible...). Ensuite je débranche l'USG et la CK 2+, c'est important. A partir de la il me suffira en principe d'importer le backup du contrôleur sur l'UDM Pro et ensuite le backup du NVR.

Dans la pratique c'est un peu plus compliqué. Si l'importation se passe bien le redémarrage annoncé ne s'opère pas. Je le fais manuellement au bout d'une heure. Mais au retour je ne peux me connecter localement, ni sur l'ancienne l'IP (192.168.1.1), ni sur l'IP de configuration importée (192.168.210.1). Par contre je peux le faire à distance (à noter que c'est un nouveau portail d'administration). Et là en fouillant je constate deux choses :

  • Le port 11 (SFP) qui assure la liaison avec mon USW-48 a perdu sa configuration en 1 GB FDX (et non il n'est pas auto sense...)
  • Que si l'IP LAN a bien été importée dans la configuration, c'est toujours l'ancienne IP qui répond, et de fait le système ne voit pas les autres équipements importés (SW, AP).

Réactiver le port SFP en FDX est facile, pour que l'IP LAN soit bien prise en compte j'ai finalement rentré l'ancienne à la place de la nouvelle, appliqué la configuration, et ensuite remis la nouvelle, et oh merveille ça fonctionne. Oh merveille mon cul, car c'est vraiment n'importe quoi.

A ce stade tout semble fonctionner, bien que dans cette version non finalisée (6.0.22) certaines choses sont à faire dans la nouvelle admin (VPN) tandis que pour d'autres actions il faudra revenir à l'ancienne interface. beta bug beta bug ! Enfin, tout sauf que si le WAN2 sait bien fonctionner en failover, contrairement à l'USG il est ici impossible de la basculer en agrégation (pas de réponse à ce sujet pour l'instant).

Il y a également depuis le 6.0.x des équipements WI-FI qui décrochent. C'est par exemple systématique sur les ampoules Xiaomi/Yeelight, j'ai tout retourner sans trouver de contournement. Et pour mémoire, quand on migre d'une 5.x vers une 6.0.20 il y a un Vlan only network - 0 qui se crée, je pense que c'est lié à la nouvelle façon de gérer le WI-FI Guest, en attendant il empêche toute connexion WIFI normale et il faut donc l'effacer ou le le changer d'ID (en 100 par exemple). Sur le 6.0 le WI-FI est géré différemment et on peu créer plus de 4 SSID, ce qui est par exemple plus souple pour les différencier en 2 ou 5 Ghz. et en isoler certains (IoT par exemple).

Domotique

Pour information les intégrations Unifi et Unifi Protect que l'on utilise dans Home Assistant fonctionnent et reconnaissent bien l'UDM. Petit hic il faut les réinstaller car je n'ai pas trouvé (pas trop cherché non plus) la façon de changer l'IP du contrôleur et du NVR (dans HA). Le résultat est que certaine entités peuvent changer de nom et qu'il faudra s'adapter.

Accéder au contrôleur depuis l'extérieur

Le plus simple pour administrer le contrôleur intégré à l'UDM est bien sur de passer par le cloud Unifi et l'application. Mais on peu vouloir y accéder directement depuis le port WAN. Pour cela on va commencer par suivre ces recommandations et ainsi créer une règle WAN Local :

Action : Accept
IPv4 Protocol : TCP
Rule Applied : Before pre-defined rules
Destination : Create a new port group with port 443 in the group

A partir de là on peut accéder au contrôleur sur son port par défaut (443) depuis l'extérieur. Sauf que le port par défaut n'est pas une bonne idée et on peut vouloir en faire autre chose. On va donc créer une règle dans Port Forwarding qui redirigera par exemple le port 8443 sur l'IP LAN du contrôleur, et ainsi on y accède via ce port. Au même endroit on peut créer une autre règle pour rediriger le port 443 vers une autre IP du LAN, et si on en a pas besoin on la redirige sur 127.0.0.1 afin de bloquer l'accès externe via le 443... Je sais c'est un peu tordu par les cheveux mais je n'ai pas trouvé mieux ! En ce qui me concerne j'en ai eu besoin pour cette solution de backup. Attention toutefois à verrouiller cet accès sur des IP sources pour plus de sécurité.

Conclusion

Par la force des choses je me retrouve :

  • en prod avec du matériel qui tourne intégralement sur des versions beta. Une pratique à éviter.
  • avec un enregistreur qui n'enregistre plus rien...
  • des équipements WI-FI qui décrochent.
  • avec une foule de bugs dont une agrégation de ports inopérante.

Vous l'aurez compris, la machine à rêver ne m'a pas fait rêver mais perdre beaucoup de temps et me retrouver dans une situation très instable !

  • EDIT 22/09/2020 14:00 : la v6.0.23 du contrôleur est sortie et ça règle bien plus de choses qu'annoncé. Dont mes déconnections avec les ampoules Xiaomi/Yeelight. En fait non, mais ça tient quelques heures au lieu de 5 minutes...
  • EDIT 22/09/2020 17:30 : S'agissant de l'enregistrement sur détection de présence (Protect) et de l'enregistrement il semblerait qu'un paramètre n'ait pas été pris en compte lors de la migration ou qu'il soit nouveau (sur chaque caméra, Recording/Motion Events/Motion Algorithm), il faut faire un choix et aucun des deux n'était sélectionné. Dès lors qu'un disque dur est bien reconnu on a donc bien les enregistrements.
  • EDIT 23/09/2020 04:37 : Il est possible d'intervertir WAN1/WAN2 afin que WAN1 (le principal) profite de l'interface 10 GB sur WAN1 (et sans passer par SSH). Par contre pour l'instant seul le support du mode Failover, pour le Load Balancing (supporté sur l'USG) il faudra repasser plus tard.
  • EDIT 23/09/2020 18:22 : En parlant de plus tard, le SNMP, un peu la base sur un routeur, est caché (New Seetings + search snmp), mais pour autant il ne fonctionne pas. Il parait que apt-get ... etc... On se marre !
  • EDIT 23/09/2020 19:30 : Passage de la 6.0.23 en release et sortie de la 6.0.24 en beta. Ca turbine chez Uniquiti, il faut dire que ça grogne partout ! Nouveaux firmwares UAP/USW. Nouvelles déconnexions sur les ampoules Xiaomi.
  • EDIT 29/09/2020 17:17 : S'agissant des ampoules Xiaomi, j'ai essayé tous les paramètres possibles et imaginable ainsi que les version beta de firmware sans obtenir de résultat. J'en conclu que quelque chose a vraiment changé dans cette version qui a plus une allure de beta que de release. J'ai donc honteusement ressorti un vieil AP Netgear...
  • EDIT 29/09/2020 17:17 : A la version 1.8.4 du firmware les choses sont rentrées dans l'ordre.
  • EDIT 26/01/2022 16:16 : Au fil du temps et des firmwares successifs, parfois chaotiques, les choses sont rentrées dans l'ordre et maintenant l'UDMP fonctionne très bien. Pour Unifi Protect un SSD augmentera nettement les performances.

J'espère pouvoir échanger avec Unifi et qu'ils sauront m'apporter des réponse satisfaisantes à tous ces problèmes. Je mettrais bien sur à jour cet article énervé en fonction de.

Bonus

Quand on accède en local à l'UDM via son IP on a bien sur une erreur SSL. Pour remédier à ça :

  1. On exporte le certificat autosigné unifi.local depuis Chrome vers un fichier .CER (un simple clic sur copier dans un fichier quand on visualise le certificat).
  2. Avec une console MMC on importe ce certificat dans "Trusted Root Certification Authorities" store.
  3. On édite C:\Windows\System32\drivers\etc\hosts et on ajoute IP_de_l'UDM > unifi.local (éventuellement avec HostMan).
  4. Après avoir relancé le navigateur on accès de à https://unifi.local

Sources

 

Home Assistant & BLE : Présence

Il y a quelques temps je vous avait déjà parlé de BLE (Bluetooth Low Energy) pour remonter des sondes de température Xiaomi. Le composant utilisé fonctionne bien et ça évolue, il n'y a rien à redire, sinon que ça ne gère pas la présence. Hors la notion de présence est importante en domotique.

Il y a plusieurs façons de gérer la présence dans Home Assistant

  • En géolocalisation en utilisant les API Google. Ça fonctionne bien au point de faire peur, mais ce n'est pas suffisamment réaction pour certaines actions. Par exemple si je veux ouvrir le portail, allumer des lampes et désactiver l'alarme lors de mon arrivée, il y a des chances que j'attende 5 minutes face au portail... Et que si j'ouvre le portail avec une télécommande l'alarme soit encore active lorsque je rentre dans la maison. C’est donc inutilisable pour cet usage.
  • Une application genre OwnTrack n'est pas beaucoup plus performante et consomme plus de batterie.
  • Un TAG RFID, ça fait le job mais il y a une interaction physique. Donc OK pour l'alarme, mais pas pour le portail...
  • Le WI-FI, en s’appuyant sur l'intégration Unifi (il y en a d'autres), c’est pas mal mais il me faudrait un AP à l'extérieur pour un meilleur résultat.
  • Un gardien ou un majordome serait idéal, mais je n'en ai pas les moyens !
  • J'ai pensé au ZigBee, mais la portée est trop courte et il me faudrait déporter un répéteur.
  • Il reste donc la voie du BLE que j'avais laissé de coté car l'intégration de base n'est pas à la hauteur de ce que j'avais avec un des meilleurs plugin sous Jeedom.

Pour palier à l'intégration BLE d'origine sous HA on dispose à ce jour de deux projets bien aboutis qui peuvent fonctionner soit de façon autonome sur un RPI, soit sous forme d'addon à installer directement dans Home Assistant. Dans les deux cas ils communiqueront avec HA en MQTT, et c'est un plus indéniable ! En ce qui me concerne j'ai testé les addon, mais un RPI0 indépendant sera idéal si on veut créer un réseau avec le second projet.

Monitor

Bluetooth Presence Monitor s'installe en ajoutant son dépôt dans le gestionnaire d'addon ou en partant du dépôt original si on veut l'installer à part. La configuration est simple :

mqtt:
  broker: 192.168.210.44
  port: 1883
  username: user
  password: password
  topic_root: presence
  publisher: ''
known:
  beacons:
    - 'F8:DE:32:B1:07:3D Tile'
  static:
    - '94:65:1D:D1:AD:96 5T'
    - '50:77:05:F6:0F:2F Note 9'
blacklist:
  - '58:2D:34:10:1D:4F'
  - '58:2D:34:10:12:77'
extra_arguments: '-a -x -b -tdr -r'

Par contre il faudra prendre soin d'aller régler le port BT dans le fichier /share/presence-monitor/behavior_preferences afin que cela ne rentre pas en confit avec un autre port (à ce niveau l'O/S ne gère pas le partage des ports comme celà pourrait être le cas sous Windows ou MacOS par exemple). Cela veut dire que si on a déjà une intégration qui utilise un port BT il faudra un dongle USB BT. Dans mon cas j'utilise une clé SENA TD100 que l'on trouve encore ici. C'est dans ce même fichier de configuration que l'on pourra ajuster tous les paramètres, fichier que l'on aurait aimé accessible depuis l'addon bien sur...

PREF_HCI_DEVICE=hci1

A partir de là on lance l'addon et on observe le log pour ajuster la configuration afin de choisir ce qui sera notifié au broker MQTT. Ensuite il faut créer un sensor: qui aura pour valeur le pourcentage d'éloignement ainsi qu'une très utile notion de départ / arrivée.

  - platform: mqtt
    state_topic: 'presence/homeassistant/tile'
    value_template: '{{ value_json.confidence }}'
    unit_of_measurement: '%'
    name: 'Tile BLE'
    icon: mdi:bluetooth

On va également créer un device_tracker: qui lui nous fournira un device tracker que l'on retrouvera comme d'habitude dans le fichier known_devices.yaml

  - platform: mqtt
    devices:
      TileBLE: 'presence/homeassistant/tile/device_tracker'
      name: "Tile BLE"
      icon: mdi:bluetooth

A ce stade ça fonctionne avec une prise en compte des équipements perfectibles, mais je n'ai pas creusé les paramètres avancés car entre temps je suis tombé sur Room Assistant. Par ailleurs mon TAG Tile ne semble pas être le meilleur pour cet usage et j'ai commandé un Nut 3.

Room Assistant

Room Assistant est à ce jour ce que j'ai trouvé de plus complet et de plus prometteur. L'installation de l'addon se fait depuis ce dépôt (ou ici si on installe à part) et on se concentrera sur le fichier de configuration, un lancement à vide nous permettant de repérer les adresses MAC des différents équipements.

Le gros avantage de Room Assistant est qu'il offre la possibilité de fonctionner en réseau, ce que l'on connaissait avec le plugin BLEA de Jeedom. Il sera ainsi possible de localiser les habitant d'un logement à la pièce près en se basant sur le signal BT/BLE. Je n'ai pour l'instant pas exploité cette possibilité, mon besoin étant le départ / arrivé de mes utilisateurs.

global:
  instanceName: canaletto_ble
  integrations:
    - homeAssistant
    - bluetoothLowEnergy
    - bluetoothClassic
    - xiaomiMi
homeAssistant:
  mqttUrl: 'mqtt://192.168.210.44:1883'
  mqttOptions:
    username: user
    password: password
bluetoothClassic:
  minRssi: '-20'
  hciDeviceId: 1
  addresses:
    - '94:65:2D:D4:XX:77'  # Mon mobile
bluetoothLowEnergy:
  hciDeviceId: 0
  onlyIbeacon: true
  timeout: 30  # Utile pour éviter les faux départs sur certains tags
  whitelist:
    - f8dedfgh73d  # Mon Tag Tile
  tagOverrides:
    f8dedfgh73d:
      name: Tile
xiaomiMi:
  hciDeviceId: 0
  sensors:
    - name: Clear Cuisine  # Xiaomi CGG1
      address: 582d3dfgsd6d
    - name: Clear SdB  # Xiaomi CGG1
      address: 582d3dgf3286
    - name: Clear Exterieur  # Xiaomi LYWSDCGQ
      address: 4c6dfgd1db75
    - name: Clear Square  # Xiaomi LYWSD02
      address: 3fdfg88270ca
    - name: Clear Clock  # Xiaomi CGD1
      address: 58sdfgsd3292
      bindKey: cc0d9dfgdsfgsdf4e7f495d27eacf5250e2e8
entities:
  behaviors:
    ble-f8desdb1073d-tracker:
      debounce:
        wait: 10.75
        maxWait: 20

On passe rapidement sur la classique config MQTT pour noter que si l'intégration bluetoothLowEnergy et xiaomiMi peuvent partager le même port BT (BLE dans les deux cas), ce port devra être différent pour du bluetoothClassic. Le développeur travaille au partage de port mais ce n'est pas pour l'instant possible.

L'intégration, la création, dans Home Assistant des sensors: est automatique via MQTT (présence, température, etc..), par contre il faudra manuellement créer les device_tracker: si on souhaite les exploiter.

  - platform: mqtt # Room-Assistant
    devices:
      ra_tile: 'room-assistant/device_tracker/ble-f8de32b1073d-tracker/state'
      name: "Tile BLE"
      icon: mdi:bluetooth
    payload_home: 'true'
    payload_not_home: 'false'
    source_type: bluetooth   

Ensuite il va falloir exploiter et pour le debug je me sert de Slack pour faire un log dynamique. On commence par deux automations pour simuler un départ et une arrivée (je me contente d'enlever la pile du Tile ou de le coller dans le micro onde... Je me sert ici du device_tracker:

- alias: Alarm Test Tile leave
  trigger:
    platform: state
    entity_id: device_tracker.ra_tile
    from: 'home'
    to: 'not_home'
  action:
  - service: notify.slack_hass_canaletto
    data:
      message: "{{now().strftime('%d/%m/%Y, %H:%M:%S')}} > TEST TILE Leave" 

- alias: Alarm Test Tile enter
  trigger:
    platform: state
    entity_id: device_tracker.ra_tile
    from: 'not_home'
    to: 'home'
  action:
  - service: notify.slack_hass_canaletto
    data:
      message: "{{now().strftime('%d/%m/%Y, %H:%M:%S')}} > TEST TILE Return" 

Mais, car il y a un mais, j'ai remarqué que visuellement mes deux icônes ne changeait pas d'état à la même vitesse, le sensor: étant plus rapide. Je fais donc une seconde paire d'automation avec lui...

- alias: Alarm Test Tile leave device
  trigger:
    platform: state
    entity_id: sensor.tile_room_presence
    from: 'canaletto_ble'
    to: 'not_home'

  action:
  - service: notify.slack_hass_canaletto
    data:
      message: "{{now().strftime('%d/%m/%Y, %H:%M:%S')}} > TEST TILE Leave Sensor" 

- alias: Alarm Test Tile enter device
  trigger:
    platform: state
    entity_id: sensor.tile_room_presence
    from: 'not_home'
    to: 'canaletto_ble'
  action:
  - service: notify.slack_hass_canaletto
    data:
      message: "{{now().strftime('%d/%m/%Y, %H:%M:%S')}} > TEST TILE Return Sensor" 

Et là on a une vraie surprise dans les résultats car on gagne 10 secondes ! Et 10 secondes sur une arrivée c'est hyper important car c'est à peu près le temps que je dois mettre pour aller du portail à la porte d'entrée...

14/09/2020, 23:12:41 > TEST TILE Leave using sensor:
14/09/2020, 23:12:52 > TEST TILE Leave using device_tracker:
14/09/2020, 23:13:01 > TEST TILE Return using sensor:
14/09/2020, 23:13:12 > TEST TILE Return using device_tracker:

Voilà, il va maintenant falloir faire des tests en live, l'idéal serait que le tag puisse être détecté quand je me gare devant le portail, mais pour ça il me faudra que j’équipe la clé SENA avec une antenne plus performante. Je trouve que les délais d'Accroche / Décroche des mobiles sont excellents et j'attend mon Nut pour d'autres tests.

Le support des capteurs Xiaomi est récent et pour l'instant l'information concernant le niveau de batterie n'est pas disponible pour tous contrairement à MiTemp. Mais ça devrait venir. Ce qui est amusant, sinon intéressant, c'est que dans cette intégration un capteur de température Xiaomi peut devenir un TAG et être vu par HA en tant que tel... Mon Tile ne fonctionnant pas très bien, j'ai donc pensé à laisser un CGG1 dans ma voiture...

Voilà pour ces petits tests, je suis bien sur disponible pour échanger sur TG ou ici dans les commentaires. N'hésitez pas à partager vos expériences afin que je puisse au besoin mettre à jour cet article.

EDIT : Je n'ai pas encore eu le temps de tester mais les informations trouvées ici me semblent pertinentes.

EDIT 2 : Pour  la géo loc l'application Life 360 semble ce qui se fait de mieux, il existe une intégration à HA. A combiner avec le reste.

EDIT 3 : Le composant Passive BLE Monitor dont je parlais ici a bien évolué et gère les tag Tile et Nut. Dont tout ce dont je par ici est un peu obsolète...

Et en WI-FI

Si gérer la présence en Bluetooth peut sembler évidente, à l'usage on s'aperçoit que le BT des mobiles décroche trop souvent, que celui des tags BLE n'est pas assez rapide et surtout que même avec une clé Sena et une antenne la portée est trop réduite. Finalement le WI-FI reste une très bonne solution, à condition d'avoir un AP gérable (Unifi avec intégration Unifi ou Unifi AP qui est légèrement plus rapide) et d'autres marques reconnues, Netgear par exemple. Ce qui est intéressant ici c'est que dès que l'AP voit le mobile (sa MAC, sans pour autant que le signal soit suffisant pour un appairage et qu'il ait une IP) HA est informé de la présence du device et peut ainsi gérer des automatismes. Le décrochage est long ce qui garantie l'absence de faux positifs mais l'accrochage est lui très rapide.

Sources

 

 

 
 

 

 

Home Assistant IR, AC & More...

Pour piloter un climatiseur avec Home Assistant il existe plusieurs options, mais vu qu'il n'existe pas de protocole unifié (à par peut être KNX que l'on oublie pour des questions de coûts), ça va bien souvent se terminer en IR, là ou une option MQTT sur les interfaces WI-FI des constructeurs aurait été une bénédiction. En dehors de Dalkin qui dispose d'une intégration et Xiaomi (non importé), ces interfaces sont bien sur propriétaires et fermées.

Alors on se rabat sur l'infrarouge, ce qui n'est pas très sexy en 2020 ! D'ailleurs si vous voulez juste piloter une clim avec une application, plutôt que de payer cher une option WIFI du constructeur, pour 80/90 € offrez vous simplement un Tado ou un Sensibo, ça fera le job en mieux et ce sera compatible Alexa et Google Home, avec des intégrations Home Assistant (Tado | Sensibo) à la clé. Sauf que c’est du cloud et que je veux un pilotage local.

On va donc partir sur un Broadlink qui dispose d'une intégration. A la base ce gadget permet de piloter n’importe quel appareil IR depuis une application mobile. Ici on va faire la même chose, mais de puis Home Assistant, et on va voir qu'il existe plusieurs façons de faire, et accessoirement que j'ai perdu bien du temps en ne trouvant pas la seconde option tout de suite...

Intégration du Broadlink à Home Assistant

Ça c'est la première chose à faire dans tous les cas, sans perdre de vue que votre Broadlink sera sur l'application ou sur Home Assistant, pas les deux. Il est toutefois intéressant de l'ajouter une fois à l'application pour récupérer son IP et son adresse Mac.

  1. On supprime le Broadlink de l'application mobile.
  2. Sans le débrancher on lui fait un reset en appuyant 6 secondes avec un trombone.
  3. On ajoute le Broadlink au réseau avec l'application, mais sans le connecter au cloud Broadlink, pas maintenant, pas plus tard. On sort de l'application et on l'oublie.

Ensuite on ajoute ces quelques lignes au fichier configuration.yaml en reportant les infos précédament récupérées et on redémarre HA. Idéalement on place une réservation DHCP sur cette IP.

remote:
  - platform: broadlink
    name: rm4_mini
    type: rm4c_mini  # Ça c'est très important....
    host: 192.168.210.132
    mac: '24:AF:A2:30:0D:E2'

A partir de là on a deux possibilités. La première va consister à apprendre les codes IR et à les restituer. Pour les apprendre on va faire un petit script et se laisser guider par les notifications de Home Assistant pour presser sur les touches idoines au bon moment...

learn_tv_commands:
  alias: Apprentissage IR
  sequence:
  - data:
      command:
      - turn on
      - turn off
      - volume up
      - volume down
      - chanel up
      - chanel down
      device: television_sam
      entity_id: remote.sam
    entity_id: remote.rm4_mini
    service: remote.learn_command

Et on va se retrouver avec les fichier /config/.storage/broadlink_remote_24dfa2300de2_codes qui va contenir nos codes IR, fichier dans lequel il nous suffira d'aller récupérer les bons codes.

{
    "data": {
        "television_sam": {
            "chanel down": "JgDSAJOUEjcTNxQ1ExIUERMSExITERQ2FDYTNhMSExITEhMSFBETERQRExITEhM2FBETEhMSFDYUNRM3FDYTEhM2EzcTNhQABgKWkhQ2EzcUNRQRExITEhMSFBEUNRM3EzYUERMSFBEUERQRExITERQRExIUNhMSFBEUEBQ2EzYUNhM3FBETNhM3EzYVAAYBlpIUNhQ2FDUTEhQRFBEUERMRFDYUNhM2FBEUERQRExIUERQQFBEUERMSFDUVEBQRExIUNhQ1FDYUNhQQFDYUNhQ1FQANBQAAAAA=",
            "chanel up": "JgAYAZSTEzcTNhM3ExIUERMRFBETEhQ2FDUUNhQRExITERUQFBETEhQ2FBEUEBQ2ExIUERQRFDUTEhQ2FDUUERQ2FDUUNhQABgOUkxQ2EzcUNRMSExIUERQRFBAUNhQ2FDUUERQRFBEUERQRFBAUNhQRExIUNRQRFBETEhM2FRAVNRM3FBETNhQ2FDUVAAYClZIVNRQ2FDUVEBQRFBEUERMSFDUUNhQ2FBAVEBMSFBEUERQRFDUUERQRFDYTERUQFBEUNhMSFDUUNhMSFDUUNhM3FAAGApWTFDUUNhM3FBAUERQRFBETEhQ1FTUUNhQRExEVEBQRFBETEhQ1FRAUERQ2FBETERQREzcUERQ1FDYUERQ1FDYUNhQADQUAAAAAAAAAAAAAAAAAAA==",
            "turn off": "JgBGAJGVEzcTNhQ2ERQTEhMSExEUERM3EzcTNhMSExITEhEUExEUERM3ExITEhMREhMTEhMSEzYUERQ2ETkTNhQ2EjgTNhQADQU=",
            "turn on": "JgCMAJWTEzYTNhQ2FBETEhMSExEUERQ2EzYUNhQRFBETEhMSExEUERQ2ExITEhMRFBEUERQREzYUERQ2FDYTNhQ2FDYTNhQABgOVkhQ2FDYTNhQRFBEUERMSExITNhQ2EzYUERQRFBEUERMSExITNhQRFBETEhMSExEUERQ2ExITNhQ2FDYTNhQ2FDYTAA0FAAAAAAAAAAAAAA==",
            "volume down": "JgDSAJSTEzYTNxM3ExIRExMSExITEhM3ETgSOBMSExITERQRExITNxM2ExITNxEUExISEhMSExITEhM3ERMTNxM3EzYSOBEABgSWkxE5ETgTNxEUExITEhISEhMTNxM2EzcTEhMSExIRExMSEzcTNhITEzcRFBMSExIRExMSExITNxEUEjcTNxE4EzcTAAYDlZMTNxM2EzcTEhMSExITERQREzcTNxI3ExITEhMSExITERQ2EzcTEhM2ExITEhMSExETEhMSEzcTEhM2EzcTNxM2EwANBQAAAAA=",
            "volume up": "JgDSAJKVETgSOBE5ERQRExITEhMRFBE5ETgSOBEUERQRExITEhMRORE4EjgRFBEUERQRExITEhMRFBEUETgSOBE5ETgSOBIABgSVkxQ2EzYUNhMSExITERQRFBEUNhM2FDYUERMSExITERQRFDYTNhQ2FBETEhMSExITERQRFBETEhM2FDYUNhM2FDYUAAYClJQTNxM2FDYTEhITEhMSEhMSEzcSNxM3ExISExEUEhISExM3EjgROBITERQRFBEUERMSExITEhMROBI4EjgROBI4EQANBQAAAAA="
        }
    },
    "key": "broadlink_remote_24aca7a1dce2_codes",
    "version": 1
}

Ensuite on va créer un switch qui pourra d'ailleurs en contenir plusieurs... Et avec lesquels ont pourra interagir depuis des automation, scripts ou l'interface Lovelace...

- platform: broadlink
  host: 192.168.210.132
  mac: '24:AF:A2:30:0D:E2'
  type: rm4c_mini  # Toujours aussi important !
  timeout: 15
  switches:
    tv_on:
      friendly_name: "TV Power"
      command_on: 'JgCMAJWTEzYTNhQ2FBETEhMSExEUERQ2EzYUNhQRFBETEhMSExEUERQ2ExITEhMRFBEUERQREzYUERQ2FDYTNhQ2FDYTNhQABgOVkhQ2FDYTNhQRFBEUERMSExITNhQ2EzYUERQRFBEUERMSExITNhQRFBETEhMSExEUERQ2ExITNhQ2FDYTNhQ2FDYTAA0FAAAAAAAAAAAAAA=='
      command_off: 'JgDSAJKUFDYSOBI3ExITEhITEhMSExI2FDcSNxMSExITEhITEhMSExI3ExISExITEhITEhMSEjgSExI3EzcSOBI3EzcSNxMABgOVkxQ2EzcSOBMRFBETEhITExITNhQ2EjcUERQRFBETEhITExITNhMSExITEhMSExEUERM3ExISNxQ2EzcTNhQ2EzcTAAYClZQTNhQ2EzcTERQRFBETEhMSEzYUNhM3EhMSEhMSFBETEhITEjcTEhMSEhMSExITEhITNxITEjgSNxM3EjcTNxM3EgANBQAAAAA='

Ça c'était la version manuelle, c’est pratique car ça permet d'associer n’importe quel appareil piloté par une télécommande IR. Par contre c'est fastidieux et j'ai passé mon après-midi à me dire qu'il était impossible que quelqu'un n'ai pas fait mieux, à savoir une intégration ou je n'aurais qu'à choisir la référence de mon climatiseur pour le commander avec une carte Climate. Et ça existe !

SmarIR

SmartIR s'appuie sur le Broadlink, ou d'autres interfaces IR, qu'il s'agisse de Xiaomi, d'un ESP DIY ou d'un objet en MQTT. Pour le configurer il nous faut avoir intégré notre interface à HA, ici le Broadlink, et installer le composant depuis HACS.

Pour activer cette intégration on ajoute une entrée dans configuration.yaml :

smartir:

Une entrée dans switch.yaml :

- platform: broadlink
  host: 192.168.210.132
  mac: '24:AF:A2:30:0D:E2'
  type: rm4c_mini  # Toujours aussi important !

Et enfin une dernière dans climate.yaml ou l'on n'oubliera pas de reporter le bon code IR : 

- platform: smartir
  name: Office AC
  unique_id: office_ac
  device_code: 1260  # Ici le code IR pour les climatiseurs Toshiba
  controller_data: 192.168.210.132
  temperature_sensor: sensor.temperature  # Ici on peut associer un capteur de température externe
  humidity_sensor: sensor.humidity  # Ici on peut associer un capteur d'hygrométrie externe
  power_sensor: binary_sensor.ac_power

Un petit redémarrage et on est prêt à piloter notre climatiseur comme on le ferait pour n'importe quel thermostat, sauf qu'ici on dispose de toutes les commandes utiles (mixte, chauffage, refroidissement, de-humidification, ventilation) propre au modèle choisit (on ne voit pas

Mon projet portait sur la climatisation, mais avec SmartIR il est également possible de piloter des ventilateurs ou du matériel Audio / Vidéo, pourquoi pas votre magnétoscope VHS ! Et ce qui ne sera pas possible avec SmartIR le sera en mode manuel.

EDIT HA 0.115 : Broadlink est maintenant intégré à HA, donc on vire ce qui est dans configuration.yaml et switch.yaml et on adapte l'utilisation avec le device ID que l'on trouvera dans l'intégration, ici remote.ir_clim_remote :

- platform: smartir
  name: AC Sejour
  unique_id: ac_sejour
  device_code: 1260
  controller_data: remote.ir_clim_remote
  temperature_sensor: sensor.mi_t_carre
  humidity_sensor: sensor.mi_h_carre
  power_sensor: binary_sensor.ac_power

Sources

Home Assistant & SSL

Maintenant que votre serveur Home Assistant est en place, il va falloir le faire communiquer avec l'extérieur de la façon la plus sécurisée possible. Sur le principe on ouvre le port (TCP/8123 en général) sur le routeur et on redirige le flux vers le serveur local. Je ne vais pas vous faire un dessin, d'autres l'ont fait. Ensuite il va falloir d'occuper de la mise en place du certificat SSL

Pour faire court deux cas de figure se présentent.

Soit votre fournisseur d'accès vous met à disposition une IP fixe, soit non, et c’est hélas le cas de beaucoup. Certains comme Free fournissent maintenant une IP fixe partagée, dans ce cas il faut demander via l'interface une IP full range. Si vous disposez de votre propre nom de domaine, et ce n'est absolument pas obligatoire pour ce genre de site, par essence privé, on va privilégier Let's Encrypt.

  • IP Fixe + Nom de domaine : Add-on Let'sEncrypt.
  • IP Dhcp avec ou sans nom de domaine : Add-on DuckDNS

L'add-on Let's Encrypt

Il s'installe depuis le superviseur et peut s’appuyer sur les API d'OVH, Gandi et CloudFlare (et bien d'autres). Si tout est bien renseigné comme ci dessous par exemple, en quelques minutes vous obtenez votre certificat et le tour est joué.

email: [email protected]  # Pour Let's Encrypt
domains:
  - ha.domain.tld  #  Domaine don le DNS est chez CloudFlare
certfile: fullchain.pem
keyfile: privkey.pem
challenge: dns
dns:
  provider: dns-cloudflare
  cloudflare_email: [email protected]  # Votre compte Cloudflare
  cloudflare_api_token: vYffF-LzhdhdhdgfhjhjjFGJFDGJJGsfgFGJSgjf

L'add-on DuckDNS

Il s'installe depuis le superviseur et nécessitera la création d'un compte sur www.duckdns.org afin de préparer la configuration. L'avantage de cet add-on c'est qu'il va tenir informé DuckDNS de vos changements d'IP.

lets_encrypt:
  accept_terms: true
  certfile: fullchain.pem
  keyfile: privkey.pem
token: 952ddsfsdf5-b1sfse-43gfsdgsdfg81-10sgsgdsg2e
domains:
  - ha.domain.tld  # Le domaine choisit lors de la création du compte.
aliases: []
seconds: 300

Alternatives

Pourquoi se compliquer la vie ? Il y a qui aiment ça... Vous pouvez donc utiliser un autre service tout autant gratuit, par exemple...

  • La passerelle SSL d'OVH qui va jouer un rôle de reverse proxy également (à condition d'avoir une IP fixe,). Dans ce cas on a la choix localement d'utiliser un certificat auto signé soit pas de SSL.
  • L'intégration CloudFlare qui semble utilisable sans IP fixe. Voir également ici pour utiliser un certificat CloudFlare.

Reverse Proxy

Se protéger avec une reverse proxy est une très bonne idée. On peut bien sur installer en local NGINX (et le configurer...) ou utiliser un reverse proxy existant dans votre infrastructure (Synology, ou HA Proxy dans pfSense par exemple), mais le plus simple est de déléguer la chose à un reverse proxy CDN, je pense bien sur à CloudFlare, en utilisant ou pas leur certificats. Attention toutefois, CloudFlare n'autorise pas tous les ports, et notamment pas le 8123, il va donc falloir ruser, soit utiliser un port externe et un port interne, soit changer le port de Home Assistant.

Que vous utilisiez ou pas un reverse proxy, il faudra vous arranger pour localement outrepasser le reverse ou le port externe de votre routeur. Inutile en effet d'aller faire un tour sur Internet pour utiliser une requête locale. En plus en cas de panne internet ça ne marcherait plus. Pour ça il faut un DNS menteur local, ça peut être un fichier host sur un PC, un DNS local sous Linux ou Windows, mais je vous conseille plutôt d’installer l'excellent add-on AdGuard qui en plus de dépolluer vos pages web fera également ce travail grâce à sa fonction de réécriture DNS. Bien sur dans ce cas il faudra que votre DHCP local pointe sur ce DNS...

Exemple

Ici j'ai configuré de façon à se que l'accès externe passe par le reverse proxy de CloudFlare (sur le port 2096), ce qui protège mes IP, j'ai fait une redirection DNS locale via AdGuard et j'utilise une URL interne sur mon mobile ou mon accès local sur PC.

URL Home Assistant : https://ha.domain.tld:2096 (pour CloudFlare par exemple).

SSID : Mon SSID (c'est sert au client mobile à savoir s'il faut appeler l'URL interne).

URL Interne : https://ha.domain.tld:8123  (ce sera également l'url local depuis un PC.)

N'hésitez pas à commenter si vous avez des questions.

Home Assistant & ZigBee

ZigBee est un protocole de haut niveau permettant la communication d'équipements personnels ou domestiques équipés de petits émetteurs radios à faible consommation ; il est basé sur la norme IEEE 802.15.4 pour les réseaux à dimension personnelle (Wireless Personal Area Networks : WPAN). Wikipédia et Google vous raconteront le reste... Mais sous Home Assistant il y (principalement) trois façons d'approcher Zigbee :

Deconz / Phoscon

La clé Combee II dépend ici de l’environnement logiciel de son éditeur, qu'il soit installé de façon indépendante ou plus ou moins mergé à Home Assistant (ou une autre solution). C'est donc une une solution qui peut s'utiliser de façon autonome, ce qui était leur but de départ, remplacer simplement quelques passerelles propriétaires (Hue, Ikea, etc..). ils fournisse d'ailleurs des images RPI pour se passer de leur boitier et c'’est d'ailleurs ainsi que je l'avait monté sur un RPI2 auquel j'accédait depuis Jeedom, et auquel j'accède maintenant avec Home Assistant.

Le fait que ce soit autonome permet de réaliser des opérations sans passer par une plateforme domotique, tout en disposant des équipements sur une ou plusieurs solutions domotique. Par exemple, pour associer un interrupteur avec une ampoule, il est plus simple de le faire sous Phoscon, sachant que de toutes façons l'état de l'ampoule remontera dans Home Assistant et que je pourrais toujours l'éteindre avec une automation...

Enfin, les équipements sont également accessibles en parallèle depuis Alexa...

C’est donc la solution la plus proche d'une passerelle propriétaire, de ses avantages, de sa façon de fonctionner et d'évoluer. C’est celle que je conseillerais pour installer un HA chez un tiers, la plus grand public qui s'appuie sur des équipements l'ont peut facilement acquérir dans le commerce.

ZHA

Zigbee Home Automation est la solution la plus intégrée à Home Assistant. Elle s'appuie sur à peu près toutes les clés Zigbee du marché et fonctionne plutôt bien. Par contre ici on est sur une intégration fermée dans et pour HA. Elle supporte (à titre expérimental) même la Zigate dont j'avais fini par me débarrasser sous Jeedom...

Rien à ajouter de plus, pour faire simple et rester dans HA c’est la solution à adopter et l'on retrouvera les menus de configurations dans la configuration HA

zigbee2mqtt

C'est la solution à la mode, parce que MQTT est à la mode. Mais au delà de l'effet de mode, MQTT est le protocole qui fait son chemin et risque de devenir un standard bien au delà de nos petits bricolages domotique. Ici on passe par une passerelle que l'on va monter ou on le souhaite (RPI Zero indépendant, HA remote, etc...), qui va transmettre ses infos à un brooker qui lui aussi peut être n'importe ou (LAN/WAN) et notre HA ne sera qu'un client de ce brooker. L'étape suivante étant bien sur que les équipements intègrent ce protocole, ça arrive, notamment sur du DIY avec le firmware Tasmota et on peut imaginer que le marché adopte MQTT, c’est d'ailleurs le cas des équipements Shelly en WI-FI qui proposent (timidement) ce protocole de façon native, ou d'autres passerelles comme ble2mqtt...

Pour revenir à zigbee2mqtt le projet est très actif, plutot stable et c'est par exemple le seul qui propose les mises à jours bios de certains équipements. Pour ce test je l'ai monté sur un HA remote et j'ai utilisé une intégration sous forme d'addon. En fait simplement parce que j'avais ce HA remote sous la main, mais pour le coup la com ne se fait pas en remote mais en MQTT. C'est une solution ultra paramétrable, chaque équipement est ajustable à la source et les infos remonteront vers les clients, je dis bien les clients car on peut tout à fait imaginer qu'in équipement soit utilisable avec plusieurs solutions, un capteur de température vu par HA mais aussi par une solution externe, etc...

A noter que contrairement aux deux précédentes solution j'ai bien la remontée de l'état des piles sur les révisions récentes (fin 2019) des capteurs Aqara, ce n'est toujours pas les cas des deux solutions concurrentes, preuve de plus que le projet est très actif.

Enfin zigbee2mqtt s'appuie sur une clé DIY, ce qui veut dire qu'il faudra bricoler un peu et acheter quelques accessoires. Mais ça reste easy !

EDIT 22/01/2021 : Pensez à mettre à jour le firmware de vos clés, ça fonctionnera mieux avec les dernières versions...

Alternatives...

D'autres continuent à utiliser l'intégration Xiaomi avec la passerelle de première génération. Ça fonctionne, mais pour moi ce n'est pas une solution Zigbee, mais une solution Xiaomi qui repose sur l'utilisation d'un serveur Chinois, dépendant de la volonté de Xiaomi d'en laisser l'usage détourné possible, voire de la Chine de laisser passer ou non les flux. Si le fonctionnement se fait en local, c’est également un potentiel cheval de Troie, mais ça c'est un autre débat. Vous aurez compris que je ne suis pas fan.

EDIT 22/01/2021 : SLS, vous risquez d'en entendre parler cette année...

Conclusion

Conclusion il faut choisir. Choisir n'est jamais simple, et en l'espèce ce n'est pas moi qui vais vous dire quoi choisir ! Il faut tout de même savoir que si les produits les plus courants sont supportés par toutes les solutions, d'autres plus confidentiels ne le seront que par l'une ou l'autre.

Sources

 

Home Assistant & Google Agenda

Dans plusieurs articles je vous ai beaucoup parlé de planification. Simplement parce que quand on veut gérer du chauffage électrique c’est une composante obligatoire. J'avais d'abord reproché à HA de ne pas proposer un véritable agenda, j'ai écarté l'agenda Google pour ne pas être dépendant du net et j'ai ainsi pu constater qu'il était possible de définir ses propres planifications, du véritable sur mesure, interface comprise. C’est un peu lourd à faire, mais HA permet de faire absolument tout ce que l'on souhaite.

Et puis je me suis retrouvé sur une planification un peu plus complexe, et comme je suis un peu flemmard et que je voulais laisser à son utilisateur une grande part de liberté, je suis allé explorer Google Agenda. Et ma première surprise a été que cette intégration n'est pas totalement dépendante du net. En effet HA synchronise l'agenda et en conserve les entrées sur une durée configurable. Ce qui veut dire qu'il est possible d'envisager un cache local qui nous permettra une déconnexion plus ou moins longue du cloud. Donc dans ces conditions c'est jouable.

Préparation

Google Agenda sous HA fait partie des intégrations de base. Donc rien à ajouter si ce n'est une carte spécialisée (ou celle-ci) si l'on souhaite un visuel. Par contre il va falloir activer l'API Google Agenda sur la console développeur de votre compte Google comme indiqué sur l'intégration. Une fois que l'on a notre clé API et son secret on crée cette entrée dans le fichier de configuration.

google:
  client_id: !secret google_api_id
  client_secret: !secret google_api_secret
  track_new_calendar: true
google:
  client_id: !secret google_api_id
  client_secret: !secret google_api_secret
  track_new_calendar: true

Après avoir redémarré HA on doit se retrouver avec un fichier google_calendars.yaml qui contiendra lune entrée pour chaque calendriers. On pourra y ajouter une entré max_results: pour choisir le nombre de résultats synchronisés par calendrier qui par défaut est de 5.

- cal_id: [email protected]
  entities:
  - device_id: thermostat_bureau
    ignore_availability: true
    name: Thermostat (Bureau)
    track: true
    max_results: 7

Pour ma part j'ai fait le choix de créer un calendrier Google par thermostat, mais il est possible de les superposer, on peut également n'en utiliser qu'un seul, mais choisissez d'en créer un en plus de celui de base, même si aujourd'hui vous ne l'utilisez pas.

A partir de là on peut ajouter notre carte Lovelace et visualiser nos entrées. On notera le spider présent sur les événements en cours.

Maintenant il va falloir s'en servir pour des automations. Pour chaque événement on va disposer de plusieurs informations qui seront utilisables, soit directement, soit grâce à des templates :

message: Salle d'Eau
all_day: false
start_time: '2020-05-17 02:30:00'
end_time: '2020-05-17 03:00:00'
location: ''
description: '23'
offset_reached: false
friendly_name: Thermostat (SdB)

Ce qui va correspondre à :

Le message: correspond à l'entrée de l'agenda, on va pouvoir y coller plusieurs informations exploitables par un template, ou faire le choix plus esthétique de coller ces information dans le champs description: qui lui ne sera pas visible directement dans l'agenda Google ou sa réplique dans HA. Ici j'ai juste mis "23" pour indiquer que je vais passer mon thermostat à la température de consigne de 23°. Mais j'airais pu ajouter d'autres mots clé pour y associer d'autres actions à déclencher, voire utiliser un lieu, ce qui peut être intéressant pour des interactions liées à la géolocalisation. On est donc face à une solution souple et sans limites.

Exploitation

On va maintenant passer à l’exploitation en tant que trigger dans une automation. On peut le faire de façon simple avec le passage d'un état sur on ou sur off, ou plus complexe en décodant des informations liées grâce à un template, informations utilisables également en tant que condition ou pour des actions, voire pour créer un sensor: ou un binary-sensor: ce qui laisse pas mal de liberté en fonction des besoins et de l'imagination de chacun.

  trigger:
    platform: state
    entity_id: calendar.thermostat_andre
    to: 'on'

Ici par exemple je vérifie si une température est disponible dans le champ d'information avec un simple test > à 0, et dans le cas contraire j'applique la consigne globale définie dans un input_number:

  action:
  - service: climate.set_temperature
    entity_id: climate.thermostat_andre
    data_template:
      temperature: '{% if states.calendar.thermostat_andre.attributes.description | float > 0 %}
                      {{ states.calendar.thermostat_andre.attributes.description }}
                    {% else %}
                      {{ states.input_number.consigne_confort.state }} 
                    {% endif %}'

J'aurais bien entendu pu définir une autre option pour déclencher par exemple un ventilateur... seulement si la température est de de...

Restrictions

Il y a une chose que je n'ai pas vraiment résolue. Les jours fériés. J'aurais voulut appliquer la programmation du dimanche aux jours fériés. Pour ça sous HA on dispose de workday: qui fait très bien son job, mais sans y passer beaucoup de temps je n'ai pas trouvé une façon simple de le faire.

J'ai donc opté pour une solution de contournement. Il est très facile sous Google Agenda de superposer les calendriers, donc le plus simple est de superposer le calendrier des jours fériés à mes autres agendas et ainsi d'aller modifier manuellement les entrés répétés qui tombent sur un jour férié et bien sur de sauvegarder uniquement cette entrée. Le choix d'une tache manuelle à répéter chaque année en attendant de trouver mieux !

Inspirations

Une autre possibilité offerte par cette intégration nous permettre d'automatiser la création d’événement depuis Home Assistant. Pour quoi faire ? Pour l’heure je n'en sait rien, mais ça peut être une possibilité intéressante...

Alternatives

J'ai fait la même chose avec Microsoft 365. Ça fonctionne, un peu moins réactif, mais ça je pense que ça vient du composant. Par contre certains disent que l'API est moins stable, plus jeune, et nécessite plus souvent l'intervention des développeurs du composant. De toutes façons chaque dépendance extérieure affaiblit un système, quel qu'il soit.

Conclusion

Çà fait le job et même bien. Je regrette un peu de ne pas avoir testé avant, mais seulement un peu car faire tous ça à la main m'a permis de beaucoup explorer et d'apprendre plein de choses !

Edit

Il n'y a pas que Google Agenda dans la vie, allez voir ce projet de scheduler très prometteur...

Sources

 

Home Assistant & Energie

Jadis certains justifiaient l'achat d'un ordinateur personnel par la gestion des comptes familiaux, aujourd’hui d'autres viennent à la domotique en espérant faire des économies. Soyons sérieux, la domotique ça coûte de l'argent et il faut y venir dans un objectif de confort ! Il n'en reste pas moins que l'on peut s'amuser à calculer ce que l'on consomme, c’est ce que je vais vous montrer ici.

Home assistant dispose d'une fonctionnalité de base nommée utility_meter: Il s'agit en fait de compteurs qui fonctionnent en cycles (heure, jour, mois, trimestre, année), pour l'instant il manque le mode bi-mensuel et un mode paramétrable. L'idée est de se calquer sur une facturation, ou de créer une facturation, pour une location par exemple. Ce capteur suivra les valeurs d'un capteur source, réinitialisant automatiquement le compteur en fonction du cycle configuré. Lors de la réinitialisation, on stockera la valeur précédente du compteur, fournissant les moyens d'effectuer des opérations de comparaison (par exemple, "ai-je dépensé plus ou moins ce mois-ci?"), ou d'estimation de facturation. Certains fournisseurs de services ont des tarifs différents en fonction du temps / de la disponibilité des ressources / etc. Le compteur de services publics vous permet de définir les différents tarifs pris en charge par votre fournisseur. Lorsque les tarifs sont définis, une nouvelle entité apparaîtra indiquant le tarif actuel. Pour modifier le tarif, l'utilisateur doit appeler un service, généralement via une automatisation qui peut être basée sur le temps ou sur une autre source externe (par exemple un capteur REST).

Je n'ai pas trouvé beaucoup d'informations et j'y ai passé d'autant plus de temps que j'ai voulu l'adapter à mon abonnement électrique. Le plus simple ou j'ai deux tarifs, les Heures Pleines de 05:00 à 21:30, le reste étant des Heures Creuses (HC). Il est toutefois possible d'adapter facilement tout ça à des tarifs plus complexes comme Tempo ou EJP.

La première chose à faire est de décortiquer la facture EdF afin d'obtenir les valeurs de base. Pour cela chacun fera appel à Excel car au delà des tarifs fixes du kWh il existe un certain nombre de taxes locales et régionales qui font qu'en France personne ne paie vraiment son Electricité au même prix.

La liste des courses

Pour compter il va nous falloir un sensor: qui sache nous remonter cette information. J'ai pour ma part utilisé un Shelly EM, il propose deux comptages et on va ici utiliser uniquement le premier que j'ai branché sur l'arrivée EdF de la maison. Il y a plusieurs façons d'en extraire les informations (Intégration, MQTT, ...) ici je vais créer un sensor rest, simplement car c’est le premier exemple que j'ai trouvé et que c'est resté ainsi.

    - platform: rest
      name: Shelly EM EdF # Général
      resource: http://192.168.210.111/status
      # username: !secret shelly_usr
      # password: !secret shelly_pwd
      authentication: basic
      value_template: '{{ (value_json.emeters.0.total | float /1000)|round(3) }}' # Wh to kWh
      scan_interval: 300 # no point updating faster than this. The Shelly only updates every 5 minutes
      unit_of_measurement: kWh

Ensuite on va créer nos utility_meter:, dans mon ça j'en ai créé 5, ce qui va me permettre de gérer le jour, la semaine, le mois, le trimestre et l'année en cours. Ces compteurs se remettrons à zéro en début de cycle et si l'on souhaite traiter les informations au delà il conviendra d'en sauvegarder les valeurs dans un fichier extere (.CSV par exemple) ou une BDD.

utility_meter:
  energy_total_usage_daily:
    source: sensor.shelly_em_edf
    cycle: daily
    tariffs:
      - day
      - night

  energy_total_usage_weekly:
    source: sensor.shelly_em_edf
    cycle: weekly
    tariffs:
      - day
      - night

  energy_total_usage_monthly:
    source: sensor.shelly_em_edf
    cycle: monthly
    tariffs:
      - day
      - night

  energy_total_usage_quarterly:
    source: sensor.shelly_em_edf
    cycle: quarterly
    tariffs:
      - day
      - night

  energy_total_usage_yearly:
    source: sensor.shelly_em_edf
    cycle: yearly
    tariffs:
      - day
      - night

Comme vous le voyez j'ai créé deux tarifs, ne me demandez pas pourquoi je les ai nommés Jour et Nuit, mais en fait cela correspond à HP et HC que l'on retrouvera plus loin. Mais comme j'ai créé deux tarifs il va me falloir faire l'addition des deux comptages pour obtenir la consommation de la journée en kWH si je le souhaite. Dans l'absolu c’est inutile car le but est d'avoir des valeurs finales en Euros...

Pour faire tous nos calculs on va se servir de sensors et de templates, là ou systèmes auraient utilisé des scénarios et des variable. Bref, peu importe, ce qui compte c’est le résultat et que ce résultat soit dynamique. Voici donc de quoi obtenir la conso journalière en kWH dans un sensor, une simple addition qu'il conviendra de dupliquer pour les différentes périodes :

    - platform: template # Consommation journalière HP + HC
      sensors:
        energy_total_daily:
          friendly_name: 'Energie journalière consommée'
          entity_id:
            - sensor.energy_total_usage_daily_day
            - sensor.energy_total_usage_daily_night
          value_template: "{{ (states('sensor.energy_total_usage_daily_day')|float + states('sensor.energy_total_usage_daily_night')|float)|round(3) }}"
          unit_of_measurement: "kWh"

Ensuite on va créer d'autres sensor: afin de passer aux euros... Mais avant on va définir quelques input_number: afin d'y saisir les valeurs du prix du kWh et de l'abonnement au prorata des périodes HP et HC. Valeurs que l'on saisira dans une carte Lovelace que l'on verra plus loin.

  hp_daily_cost:
    name: HP - Cout journalier
    mode: box
    min: 0
    max: 100
    unit_of_measurement: "€/day"
    icon: mdi:currency-eur

  hp_energy_cost:
    name: HP - Coût du Kwh
    mode: box
    min: 0
    max: 100
    unit_of_measurement: "€/kWh"
    icon: mdi:currency-eur

  hc_daily_cost:
    name: HC - Cout journalier
    mode: box
    min: 0
    max: 100
    unit_of_measurement: "€/day"
    icon: mdi:currency-eur

  hc_energy_cost:
    name: HC - Coût du Kwh
    mode: box
    min: 0
    max: 100
    unit_of_measurement: "€/kWh"
    icon: mdi:currency-eur

Maintenant que l'on dispose de valeurs en kWh et de coûts on va pouvoir calculer ce que l'on consomme en HP et HC et additionner le tout pour obtenir une résultat journalier. Pour cela on va créer 3 sensor / template. On reste toujours sur la journée mais il faudra le dupliquer pour les autres cycles.

    - platform: template # Coût journalier HP
      sensors:
        hp_cost_today:
          friendly_name: 'HP Cost Today'
          entity_id:
            - sensor.energy_total_usage_daily_day
            - input_number.hp_daily_cost
            - input_number.hp_energy_cost
          value_template: "{{ (states('sensor.energy_total_usage_daily_day')|float * states('input_number.hp_energy_cost')|float + states('input_number.hp_daily_cost')|float)|round(2) }}"
          unit_of_measurement: "€"

    - platform: template # Coût journalier HC
      sensors:
        hc_cost_today:
          friendly_name: 'HC Cost Today'
          entity_id:
            - sensor.energy_total_usage_daily_night
            - input_number.hc_daily_cost
            - input_number.hc_energy_cost
          value_template: "{{ (states('sensor.energy_total_usage_daily_night')|float * states('input_number.hc_energy_cost')|float + states('input_number.hc_daily_cost')|float)|round(2) }}"
          unit_of_measurement: "€"

    - platform: template # Coût journalier HP + HC
      sensors:
        cost_today:
          friendly_name: "Aujourd'hui"
          entity_id:
            - sensor.hp_cost_today
            - sensor.hc_cost_today
          value_template: "{{ (states('sensor.hp_cost_today')|float + states('sensor.hc_cost_today')|float)|round(2) }}"
          unit_of_measurement: "€"

Je la fait un peu à l'envers, mais maintenant qu'on a nos bases de calculs on va avoir besoin de quelques automations, les deux premières vont nous servir à basculer nos UM entre HP et HC, un peu comme le faisait le fil signal fourni par EdF pour actionner le chauffe eau en heures creuses...

- id: set_night
  alias: 'Set Night'
  initial_state: true
  trigger:
    platform: time
    at: '21:30:00'
  action:
  - service: utility_meter.select_tariff ###### On passe en HC (nuit)
    data:
      entity_id:
      - utility_meter.energy_total_usage_daily
      - utility_meter.energy_total_usage_weekly
      - utility_meter.energy_total_usage_monthly
      - utility_meter.energy_total_usage_quarterly
      - utility_meter.energy_total_usage_yearly
      tariff: night

- id: set_day
  alias: 'Set Day'
  initial_state: true
  trigger:
    platform: time
    at: '05:00:00'
  action:
  - service: utility_meter.select_tariff ###### On passe en HP (jour)
    data:
      entity_id:
      - utility_meter.energy_total_usage_daily
      - utility_meter.energy_total_usage_weekly
      - utility_meter.energy_total_usage_monthly
      - utility_meter.energy_total_usage_quarterly
      - utility_meter.energy_total_usage_yearly
      tariff: day

Ensuite on va créer deux input_number: que l'on utilisera avec l'automation suivante pour conserver le coût cumulé et les coûts de la journée précédente. Encore une fois ce ne sont que des exemples, le reste étant à votre imagination...

  cumulative_energy_cost:
    name: Cumulative Energy Cost
    mode: box
    min: 0
    max: 5000
    unit_of_measurement: "€"
    icon: mdi:currency-eur

  yesterday_energy_cost:
    name: Yesterday Energy Cost
    mode: box
    min: 0
    max: 5000
    unit_of_measurement: "€"
    icon: mdi:currency-eur

Et comme un input_number: c’est pas joli sur Lovelace, on va leur associer des sensor:

    - platform: template # pour lovelace display à partir de l'input_number mis à jour à 23.59
      sensors:
        cost_yesterday_display:
          friendly_name: "Hier"
          entity_id:
            - input_number.yesterday_energy_cost
          value_template: "{{ (states('input_number.yesterday_energy_cost')|float)|round(2) }}"
          unit_of_measurement: "€"

L'automation finale que vous adapterez à vos envies et que l'on déclenchera en fin de journée va nous servir à plusieurs choses :

  • Stocker le cumul de consommation
  • Stocker le coût de la journée précédente
  • Envoyer une notification anxiogène sur ce que l'on vient de consommer...
  • Enregistrer un log avec toutes les valeurs possibles et imaginables...
- id: daily_energy_use_message
  alias: '000 - Daily Energy Use Message'
  trigger:
    platform: time
    at: '23:59:50'
  action:
  - service: input_number.set_value # Stocker le cumul de consommation...
    data_template:
      entity_id: input_number.cumulative_energy_cost
      value: "{{ states('input_number.cumulative_energy_cost')|float + states('sensor.cost_today')|float }}"

  - service: input_number.set_value # Stocker le coût de la journée précédente
    data_template:
      entity_id: input_number.yesterday_energy_cost
      value: "{{ states('sensor.cost_today')|float }}"

  - service: notify.slack_hass_canaletto
    data_template:
      title: '*Information*' # Envoyer un message en fin de journée...
      message: "La consommation de la journée écoulée est de {{ states('sensor.energy_total_daily') }} kWh., soit {{ states('sensor.cost_yesterday_display') }} €"

  - service: notify.file_notify_power # Ecrire un log exploitable dans un fichier .csv
    data_template:
      message: "{{ states('sensor.date') }},{{ states('sensor.energy_total_usage_daily_day') }},{{ states('sensor.energy_total_usage_daily_night') }},{{ states('sensor.energy_total_daily') }},{{ states('sensor.cost_today') }}"

Et ainsi recevoir un message du genre...

La consommation de la journée écoulée est de 25.561 kWh., soit 4.56 €

Voila pour le code. Maintenant on dispose de plein de nouveaux sensor: que l'on va pouvoir exploiter dans d'autres automations à imaginer, mais on va commencer par afficher ces informations sur une carte Lovelace et faire quelques graphiques... Comme c'est riche en formation j'ai choisi une carte qui se déplie, Fold-Entity-Row, et Multiple-Entity-Row pour compacter un peu les informations et dont voici le code :

entities:
  - entity: utility_meter.energy_total_usage_daily
    name: Tarif actuel
  - label: 'Coûts HP / HC :'
    type: section
  - entities:
      - entity: sensor.hp_cost_today
        name: HP
      - entity: sensor.hc_cost_today
        name: HC
    entity: sensor.cost_today
    icon: 'mdi:currency-eur'
    name: Journée en cours
    secondary_info: last-changed
    show_state: false
    type: 'custom:multiple-entity-row'
  - entities:
      - entity: sensor.hp_cost_weekly
        name: HP
      - entity: sensor.hc_cost_weekly
        name: HC
    entity: sensor.cost_weekly
    icon: 'mdi:currency-eur'
    name: Semaine en cours
    secondary_info: last-changed
    show_state: false
    type: 'custom:multiple-entity-row'
  - entities:
      - entity: sensor.hp_cost_monthly
        name: HP
      - entity: sensor.hc_cost_monthly
        name: HC
    entity: sensor.cost_monthly
    icon: 'mdi:currency-eur'
    name: Mois en cours
    secondary_info: last-changed
    show_state: false
    type: 'custom:multiple-entity-row'
  - entities:
      - entity: sensor.hp_cost_quarterly
        name: HP
      - entity: sensor.hc_cost_quarterly
        name: HC
    entity: sensor.cost_quarterly
    icon: 'mdi:currency-eur'
    name: Trimestre en cours
    secondary_info: last-changed
    show_state: false
    type: 'custom:multiple-entity-row'
  - entities:
      - entity: sensor.hp_cost_yearly
        name: HP
      - entity: sensor.hc_cost_yearly
        name: HC
    entity: sensor.cost_yearly
    icon: 'mdi:currency-eur'
    name: Année en cours
    secondary_info: last-changed
    show_state: false
    toggle: true
    type: 'custom:multiple-entity-row'
  - label: 'Coût cummulé :'
    type: section
  - entities:
      - entity: sensor.cost_today
        name: Aujourd'hui
      - entity: sensor.cost_yesterday_display
        name: Hier
    entity: sensor.cost_yearly
    icon: 'mdi:currency-eur'
    name: Journées
    secondary_info: last-changed
    show_state: false
    toggle: true
    type: 'custom:multiple-entity-row'
  - label: 'Coût :'
    type: section
  - entity: sensor.cost_yearly
    icon: 'mdi:currency-eur'
  - entities:
      - entity: input_number.hp_daily_cost
      - entity: input_number.hp_energy_cost
      - entity: input_number.hc_daily_cost
      - entity: input_number.hc_energy_cost
    head:
      label: Tarifs EDF
      type: section
    padding: 0
    type: 'custom:fold-entity-row'
  - entities:
      - entity: utility_meter.energy_total_usage_daily
        name: Tarif actuel
      - label: Journée en cours
        type: section
      - entity: sensor.energy_total_usage_daily_day
        name: Tarif HP
      - entity: sensor.energy_total_usage_daily_night
        name: Tarif HC
      - entity: sensor.energy_total_daily
        name: Total
      - label: Semaine en cours
        type: section
      - entity: sensor.energy_total_usage_weekly_day
        name: Tarif HP
      - entity: sensor.energy_total_usage_weekly_night
        name: Tarif HC
      - entity: sensor.energy_total_weekly
        name: Total
      - label: Mois en cours
        type: section
      - entity: sensor.energy_total_usage_monthly_day
        name: Tarif HP
      - entity: sensor.energy_total_usage_monthly_night
        name: Tarif HC
      - entity: sensor.energy_total_monthly
        name: Total
      - label: Trimestre en cours
        type: section
      - entity: sensor.energy_total_usage_quarterly_day
        name: Tarif HP
      - entity: sensor.energy_total_usage_quarterly_night
        name: Tarif HC
      - entity: sensor.energy_total_quarterly
        name: Total
      - label: Année en cours
        type: section
      - entity: sensor.energy_total_usage_yearly_day
        name: Tarif HP
      - entity: sensor.energy_total_usage_yearly_night
        name: Tarfif HC
      - entity: sensor.energy_total_yearly
        name: Total
      - type: divider
      - entity: input_number.cumulative_energy_cost
      - entity: input_number.yesterday_energy_cost
    head:
      label: Compteurs d'énergie
      type: section
    padding: 0
    type: 'custom:fold-entity-row'
  - entities:
      - entity: sensor.shelly_shem_0560de_1_current_consumption
        name: 'Maison : Consommation instantanée'
      - entity: sensor.shelly_shem_0560de_1_total_consumption
        name: 'Maison : Consommation cummulée'
    head:
      label: Equipements surveillés
      type: section
    padding: 0
    type: 'custom:fold-entity-row'
show_header_toggle: false
style: |
  ha-card {
    border: solid 2px var(--primary-color);
  }
theme: teal
title: Consommation électrique
type: entities

Encore une fois c'est a adapter à vos besoins. Coté graphiques je n'ai rien inventé non plus, j'ai juste adapté ce que j'ai trouvé en me servant de Mini-Graph-Card. Pour les graphiques suivants je suis allé chercher les informations MQTT après avoir configuré le Shelly EM en MQTT vers mon broker. Mais c’est juste pour l'exemple car j'aurais tout aussi bien put utiliser les valeurs du sensor: créé par l'intégration Shelly...

    - platform: mqtt
      name: "Shelly EM : Arrivée EdF"
      state_topic: "shellies/shellyem-0560DE/emeter/0/power"
      value_template: '{{ value|round(1) }}'
      qos: 1
      unit_of_measurement: "W"
      icon: mdi:gauge

    - platform: mqtt
      name: "Shelly EM : Baie Informatique"
      state_topic: "shellies/shellyem-0560DE/emeter/1/power"
      value_template: '{{ value|round(1) }}'
      qos: 1
      unit_of_measurement: "W"
      icon: mdi:gauge

    - platform: mqtt
      name: "Shelly EM : Voltage"
      state_topic: "shellies/shellyem-0560DE/emeter/0/voltage"
      qos: 1
      unit_of_measurement: "V"
      icon: mdi:flash

Pour mettre en évidence les heures creuses, on se fait un petit binary_sensor: dédié (on pourrait s'en servir dans l'automation plus haut...).

- platform: tod
  name: Heures Creuses
  after: '21:30'
  before: '05:00'

Et pour terminer, le code de la carte qui va générer mes 3 graphiques. C’est un peu compliqué car je suis parti d'un exemple ou l'auteur, bien plus chevronné que moi s'est servi de la luminosité en temps réel pour générer des valeurs Jour et Nuit afin de calculer sa productivité en énergie solaire.

cards:
  - color_thresholds:
      - color: '#039BE5'
        value: 0
      - color: '#0da035'
        value: 600
      - color: '#e0b400'
        value: 1200
      - color: '#e45e65'
        value: 2400
    color_thresholds_transition: hard
    entities:
      - sensor.shelly_em_arrivee_edf
      - color: 'rgba(0,0,255,1)'
        entity: binary_sensor.dark_outside
        show_line: false
        y_axis: secondary
    group: false
    hour24: true
    hours_to_show: 24
    line_width: 4
    name: Total
    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'
    style: |
      ha-card {
        border: solid 2px var(--primary-color);
      }
    type: 'custom:mini-graph-card'
  - color_thresholds:
      - color: '#039BE5'
        value: 0
      - color: '#0da035'
        value: 600
      - color: '#e0b400'
        value: 1200
      - color: '#e45e65'
        value: 2400
    color_thresholds_transition: hard
    entities:
      - sensor.shelly_em_baie_informatique
      - color: 'rgba(0,0,255,1)'
        entity: binary_sensor.dark_outside
        show_line: false
        y_axis: secondary
    group: false
    hour24: true
    hours_to_show: 24
    line_width: 4
    name: Baie Informatique
    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'
    style: |
      ha-card {
        border: solid 2px var(--primary-color);
      }
    type: 'custom:mini-graph-card'
  - color_thresholds:
      - color: '#039BE5'
        value: 0
      - color: '#0da035'
        value: 600
      - color: '#e0b400'
        value: 1200
      - color: '#e45e65'
        value: 2400
    color_thresholds_transition: hard
    entities:
      - sensor.shelly_em_voltage
      - color: 'rgba(0,0,255,1)'
        entity: binary_sensor.dark_outside
        show_line: false
        y_axis: secondary
    group: false
    hour24: true
    hours_to_show: 24
    line_width: 4
    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'
    style: |
      ha-card {
        border: solid 2px var(--primary-color);
      }
    type: 'custom:mini-graph-card'
type: vertical-stack

Voilà, à vous de jouer !

Bonus

Suite à une demande : Extraction en .csv et envoie par mail.

automation:
- id: '1901208243990'
  alias: 'Energy - Sensor values to file - Day'
  description: ''
  trigger:
  - platform: time 
    at: '23:59:55'     
  condition: []
  action:
  - service: notify.file_csv_month
    data_template:
      message: '{{now().strftime("%d.%m.%Y")}};{{now().strftime("%H:%M:%S")}};{{ states.sensor.linky_3a99d205_smartenergy_metering_summation_delivered.state}};kW/h'
  mode: single

- id: '1708208243990'
  alias: 'Energy - Sensor values to file - Mouth'
  description: ''
  trigger:
  - platform: time 
    at: '23:59:55'     
  condition:
  - condition: state
    entity_id: binary_sensor.dernier_jour_du_mois
    state: 'on'  
  action:
  - service: notify.file_csv_day
    data_template:
      message: '{{now().strftime("%d.%m.%Y")}};{{now().strftime("%H:%M:%S")}};{{ states.sensor.linky_3a99d205_smartenergy_metering_summation_delivered.state}};kW/h'
  - service: notify.mail
    # data_template:
    data:
      target: 
        - [email protected]
      message: 'Linky {{ now().strftime(''%H:%M:%S'')}}'
      title: Mise à jour Linky
      data:
        images:
          - '/share/linky_month.csv'

        html: >
          <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
          <html lang="en" xmlns="http://www.w3.org/1999/xhtml">
              <head>
                  <meta charset="UTF-8">
                  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
                  <meta name="viewport" content="width=device-width, initial-scale=1.0">
                  <title>Intruder alert</title>
                  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.5/css/bootstrap.min.css">
                  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css">
                  <style type="text/css">
                      @font-face {
                        font-family: 'Open Sans';
                        font-style: normal;
                        font-weight: 300;
                        src: local('Open Sans Light'), local('OpenSans-Light'), url(http://fonts.gstatic.com/s/opensans/v13/DXI1ORHCpsQm3Vp6mXoaTZS3E-kSBmtLoNJPDtbj2Pk.ttf) format('truetype');
                      }
                      h1,h2,h3,h4,h5,h6 {
                          font-family:'Open Sans',Arial,sans-serif;
                          font-weight:400;
                          margin:10px 0
                      }
                  </style>
              </head>
              <body>
                <div class="jumbotron jumbotron-fluid" style="background-color: white; color: blue;">
                    <div class="container py-0">
                        <h3>Mise à jour mensuelle : \\192.168.66.150\share
                        <br>
                        Pour plus de détails : https://ha.xx.xx:8123/energy</h3>
                    </div>
                </div>
              </body>
              <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
              <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.5/js/bootstrap.min.js"></script>
          </html>
  mode: single                  

Sources