Node-RED. Ajouter un widget météo au Dashboard connecté à OpenWeatherMap avec du code HTML / Angular • Domotique et objets connectés à faire soi-même

Le node template-html du plugin Node-RED-Dashboard permet de créer des Widgets personnalisés avec du code HTML. Le node template permet d’ajouter du code HTML standard ou d’utiliser le framework Angularjs pour créer des widgets personnalisés.

Pour ce projet, nous allons créer un Widget qui affiche la météo du jour ainsi que les prévisions à 14 jours à partir des données récupérées via l’API du service OpenWeatherMap.org.

Si vous débutez avec Node-RED, je vous conseille de commencer par lire ces quelques articles d’initiation

Installer le Node OpenWeatherMap pour Node-RED

Ouvrez le gestionnaire de palette et cliquer sur l’onglet install.

Faire une recherche sur le mot clé weathermap puis installer le plugin node-red-node-openweathermap.

Le plugin OpenWeatherMap est livré avec 2 Nodes. Ils sont identiques à l’exception du premier Node qui accepte un déclencheur externe. C’est celui-ci que je vous conseille d’utiliser de manière à pouvoir actualiser régulièrement les prévisions météo. On pourra actualiser manuellement à l’aide d’un bouton ou à intervalle régulier à l’aide d’un node inject.

Installer le Node Dashboard pour Node-RED

Depuis le gestionnaire de plugin, allez sur l’onglet install puis faire une recherche sur le mot clé dashboard. Il en existe plusieurs, installer le plugin node-red-dahsboard.

Nous n’allons pas re-détailler les Nodes proposés par le plugin dans cet article. Pour en savoir plus, voici deux articles qui traitent en détail du sujet

Récupérer une clé API sur OpenWeatherMap

OpenWeatherMap est un service météo qui propose un service gratuit jusqu’à 60 appels / minutes ou 1 millions d’appels / mois. C’est largement suffisant pour un usage personnel ! OWM est d’ailleurs intégré à la plupart des logiciels domotiques Open Source (Domoticz, Jeedom, Home Assistant…). Il existe plusieurs offres payantes pour un usage professionnel.

Créer un compte (gratuit) et ouvrez votre page utilisateur. Depuis l’onglet API Keys, donner un nom à la clé d’API personnelle puis cliquer sur Generate

Copier la clé, elle est immédiatement activée et disponible. On peut créer autant de clé API que l’on souhaite sans dépasser la limite du plan gratuit (60 requêtes / minute).

Connecter Node-RED à OpenWeatherMap

Ajouter un Node OWM sur le flow et faites un double clic pour ouvrir le panneau de configuration. Configurer comme ceci

  • API Key coller votre clé personnelle créée précédemment
  • Language sélectionner la langue dans laquelle vous souhaitez la météo. Il reste malheureusement un peu d’anglais, mais le plus gros est déjà traduit correctement.
  • Réponse, choisir une option
    • Current weather la météo du jour
    • 5 day forecast prévision à 5 jours. En fait renvoi la prévision toutes les 3 heures sur 14 jours !
    • Combined ne fonctionne pas

  • Location indiquer le nom / pays ou les coordonnées GPS du lieu
  • Name donnez un nom au Node

Done pour enregistrer. Branchez un Debug et Déployer

Ouvrez le debug pour afficher la réponse au format JSON de l’API d’OWM. Ici la météo du jour.

Créer un Widget Météo avec un Node template HTML/Angular

Le node Template permet d’afficher sur le Dashboard du code HTML standard ou Angular de Google. Angular est un framework qui permet développer plus facilement des sites internets ou des applications mobiles (à l’aide d’Ionic par exemple).

Remarque. Angular est un framework qui évolue encore énormément et rapidement. A priori, le node Template est compatible avec Angular v4. Les nouvelles Directives (*ngIf au lieu de ng-if), nouveaux Pipes… ne sont pas (encore) disponibles.

Si vous débutez avec le plugin Dashboard, commencez par lire cet article qui explique comment créer un dashboard (onglets et groupes).

Ajouter un node Template et coller le code ci-dessous dans le champ code.

Météo du jour


Météo à Lyon le {{msg.payload.sunrise*1000 | date:'d/M'}} Température
{{msg.payload.tempc}}°C {{msg.payload.temp_minc}}°C {{msg.payload.temp_maxc}}°C Humidité {{msg.payload.humidity}} % Pression Atm. {{msg.payload.pressure}} mbar
Tendance
{{msg.payload.detail| uppercase}}
Lever du soleil à {{msg.payload.sunrise*1000 | date:"HH:MM"}}
Coucher du soleil à {{msg.payload.sunset*1000 | date:"HH:MM"}}

Pour gagner du temps, voici le code complet du flow que vous pouvez directement importer sur le flow

[{"id":"6504a840.b5f2b8","type":"ui_template","z":"12b9999b.7256a6","group":"d9fc5c5f.19c72","name":"Météo","order":1,"width":"0","height":"0","format":"

Météo du jour

\n
Météo à Lyon le {{msg.payload.sunrise*1000 | date:'d/M'}}\n\n \n \n Température\n \n \n
{{msg.payload.tempc}}°C\n \n \n \n \n {{msg.payload.temp_minc}}°C\n \n \n {{msg.payload.temp_maxc}}°C\n \n \n \n Humidité\n {{msg.payload.humidity}} %\n \n \n Pression Atm.\n {{msg.payload.pressure}} mbar\n \n \n
Tendance\n
{{msg.payload.detail| uppercase}}\n \n \n \n \n \n \n \n \n \n \n\n\n \n \n
Lever du soleil à {{msg.payload.sunrise*1000 | date:\"HH:MM\"}} \n \n
Coucher du soleil à {{msg.payload.sunset*1000 | date:\"HH:MM\"}}\n \n","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":true,"templateScope":"local","x":490,"y":100,"wires":[[]]},{"id":"f528240.040cbe","type":"debug","z":"12b9999b.7256a6","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":510,"y":220,"wires":[]},{"id":"38d477e5.da5688","type":"ui_template","z":"12b9999b.7256a6","group":"1e31c676.3642ea","name":"reponse","order":3,"width":0,"height":0,"format":"

Météo du jour

\n
Réponse décodée avec le pipe Angular json\n
{{msg.payload | json}}
\n","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":true,"templateScope":"local","x":500,"y":160,"wires":[[]]},{"id":"10528df7.922f02","type":"openweathermap","z":"12b9999b.7256a6","name":"Météo à Lyon","wtype":"current","lon":"","lat":"","city":"lyon","country":"france","language":"fr","x":280,"y":120,"wires":[["6504a840.b5f2b8","38d477e5.da5688","f528240.040cbe"]]},{"id":"d9fc5c5f.19c72","type":"ui_group","z":"","name":"Prévisions","tab":"e10674c.ce00988","order":1,"disp":true,"width":"12","collapse":false},{"id":"1e31c676.3642ea","type":"ui_group","z":"","name":"Réponse OpenWeatherMap","tab":"e10674c.ce00988","order":2,"disp":true,"width":"6","collapse":false},{"id":"e10674c.ce00988","type":"ui_tab","z":"","name":"Home","icon":"fa-fire","disabled":false,"hidden":false}]

Une fois déployé, voici ce que vous devez obtenir

Comment fonctionne ce code HTML ?

Le code HTML a été développé à l’aide du Framework Angular de Google. Difficile d’expliquer en détail tout le fonctionnement d’Angular. Il existe de très nombreux tutoriels ansi qu’une excellente documentation en ligne.

Comment afficher un titre et du texte

On utilise tout simplement des balises HTML pour afficher des titres (h1,h2,….)

De même pour afficher du texte, on utilise les balises HTML telles que

ou .

Comment extraire des données du payload Node-RED ?

Pour extraire une données du flux de messages Node-RED, il suffit d’utiliser le système de double accolades propre à Angular {{valeur}}

Cerise sur le gateau, Angular propose un système de mise en forme à la volée bien pratique appelé Pipe. Par exemple pour mettre en majuscule le texte, on ajoutera le pipe uppercase comme ceci

{{valeur | uppercase}}

Il existe déjà de nombreux Pipes

  • Mise en forme du texte : uppercase, lowercase, titlecase (ne fonctionne pas avec le Template Angular pour Node-RED)
  • date : conversion de date
  • number : mise en forme des nombres décimaux
  • json : affichage sous la forme d’un objet json lisible par l’homme

Le système de double accolade est utilisable n’importe où dans le code HTML. Cette ligne permet par exemple de concaténer un libellé avec l’heure de lever du soleil.

Lever du soleil à {{msg.payload.sunrise*1000 | date:"HH:MM"}}

Comment organiser les blocs en ligne et colonnes ?

Angular dispose d’un système de mise en page appelé Layout qui permet d’organiser les éléments en ligne (row) et colonne (column). Pour cela Angular fonctionne à l’aide de qui ne sont rien de plus que des blocs. On utilise le système de directives Angular, un système équivalent aux classes HTML pour passer des paramètres à la comme ceci


... Contenu de la div (du bloc)

Il est possible de combiner les lignes et les colonnes pour concevoir des affichages complexes.

Comment utiliser des icônes de la police FontAwesome ?

Vous avez certainement remarqué les icônes un peu partout sur le Widget. Elle proviennent de la police Open Source FontAwesome, version 4.7. Il n’y a aucune installation à faire pour pouvoir les utiliser sur le Dashboard Node-RED. Il suffit d’utiliser une balise comme ceci

Pour trouver les classes des icônes de la version 4.7, rendez-vous sur cette page

D’autres classes sont disponibles :

  • fa-lg light, icône de petite dimension
  • fa-2x taille double
  • fa-3x taille triple
  • fa-4x
  • fa-5x
  • fa-fw pour fixed width, permet d’ajouter une marge après l’icône ce qui évite de devoir gérer une marge
  • Orientations
    • fa-rotatate-* rotation de l’icone à 90, 180 ou 270°
    • fa-flip-horizontal ou fa-flip-vertical

Toutes les classes disponibles sont détaillées ici

Comment réaliser un affichage conditionnel ?

La directive ng-if (attention *ngIf n’est pas supporté) permet d’afficher (ou masquer) un élément lorsqu’une condition est remplie. Ici par exemple, on affiche l’icône ensoleillé si l’API renvoi le code météo 01d. La codification des conditions météos utilisée par OpenWeatherMap est disponible sur cette page.

Afficher les prévisions météo sur les 14 prochains jours

Voyons maintenant comment créer une liste répétée avec la directive ng-repeat. Créer un nouveau Node OWM et choisissez l’option 5 days forecast. L’API retourne bien les prévisions sur 14 jours toutes les 3 heures).

Créer un node Template et coller le code ci-dessous

Prévisions sur les 14 prochains jours


  Prévision du
  Température
  Pression Atm.
  Météo


  {{prevision.dt*1000 | date:"EEEE d MMMM à H:00":"":"fr-fr" }}
  
        
            
                
{{prevision.main.temp | number:1.0-0}}°C {{prevision.main.temp_min | number:1.0-0}}°C {{prevision.main.temp_max | number:1.0-0}}°C {{prevision.main.pressure}} mbar {{prevision.weather[0].description}}

Ou le code du flow

[{"id":"25bafe0e.b49272","type":"ui_template","z":"12b9999b.7256a6","group":"d9fc5c5f.19c72","name":"Prévisions","order":3,"width":"0","height":"0","format":"

Prévisions sur les 14 prochains jours

\n\n  Prévision du\n  Température\n  Pression Atm.\n  Météo\n\n\n  {{prevision.dt*1000 | date:\"EEEE d MMMM à H:00\":\"\":\"fr-fr\" }}\n  \n        \n            \n                
{{prevision.main.temp | number:1.0-0}}°C\n \n \n \n {{prevision.main.temp_min | number:1.0-0}}°C\n {{prevision.main.temp_max | number:1.0-0}}°C\n \n \n {{prevision.main.pressure}} mbar\n \n {{prevision.weather[0].description}}\n \n \n \n \n \n \n \n \n \n \n","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":true,"templateScope":"local","x":510,"y":280,"wires":[[]]},{"id":"c6442529.2d4f58","type":"openweathermap","z":"12b9999b.7256a6","name":"Prévisions à lyon","wtype":"forecast","lon":"","lat":"","city":"lyon","country":"france","language":"fr","x":290,"y":280,"wires":[["25bafe0e.b49272"]]},{"id":"d9fc5c5f.19c72","type":"ui_group","z":"","name":"Prévisions","tab":"e10674c.ce00988","order":1,"disp":true,"width":"12","collapse":false},{"id":"e10674c.ce00988","type":"ui_tab","z":"","name":"Home","icon":"fa-fire","disabled":false,"hidden":false}]

On retrouve la plupart des concepts expliqué précédemment.

Ici, l’API retourne un tableau au format JSON contenant 40 lignes.

Pour récupérer la pression atmosphérique on suivra le chemin

tableau[indice_ligne][main][pressure]

Pour la prévision

tableau[indice_ligne][weather][0][description]

Mettons ceci en pratique avec Angular à l’aide de la Directive ng-repeat qui permet de parcourir un tableau au format JSON

L’objet prevision contient chaque ligne du tableau. Pour afficher la pression atmosphérique, il suffit d’utiliser le système de double accolades d’Angular que l’on connait bien maintenant, et le tour est joué !

{{prevision.main.pressure}} mbar

Voici ce que ça donne

Flow complet du projet Node-RED

Pour gagner du temps, voici le code complet du flow qu’il vous suffit d’importer. N’oubliez pas de coller votre clé d’API et de changer la ville avant de déployer.

[{"id":"12b9999b.7256a6","type":"tab","label":"Flow 1","disabled":false,"info":""},{"id":"6504a840.b5f2b8","type":"ui_template","z":"12b9999b.7256a6","group":"d9fc5c5f.19c72","name":"Météo","order":1,"width":"0","height":"0","format":"

Météo du jour

\n
Météo à Lyon le {{msg.payload.sunrise*1000 | date:'d/M'}}\n\n \n \n Température\n \n \n
{{msg.payload.tempc}}°C\n \n \n \n \n {{msg.payload.temp_minc}}°C\n \n \n {{msg.payload.temp_maxc}}°C\n \n \n \n Humidité\n {{msg.payload.humidity}} %\n \n \n Pression Atm.\n {{msg.payload.pressure}} mbar\n \n \n
Tendance\n
{{msg.payload.detail| uppercase}}\n \n \n \n \n \n \n \n \n \n \n\n\n \n \n
Lever du soleil à {{msg.payload.sunrise*1000 | date:\"HH:MM\"}} \n \n
Coucher du soleil à {{msg.payload.sunset*1000 | date:\"HH:MM\"}}\n \n","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":true,"templateScope":"local","x":490,"y":100,"wires":[[]]},{"id":"f528240.040cbe","type":"debug","z":"12b9999b.7256a6","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":510,"y":220,"wires":[]},{"id":"25bafe0e.b49272","type":"ui_template","z":"12b9999b.7256a6","group":"d9fc5c5f.19c72","name":"Prévisions","order":3,"width":"0","height":"0","format":"

Prévisions sur les 14 prochains jours

\n\n  Prévision du\n  Température\n  Pression Atm.\n  Météo\n\n\n  {{prevision.dt*1000 | date:\"EEEE d MMMM à H:00\":\"\":\"fr-fr\" }}\n  \n        \n            \n                
{{prevision.main.temp | number:1.0-0}}°C\n \n \n \n {{prevision.main.temp_min | number:1.0-0}}°C\n {{prevision.main.temp_max | number:1.0-0}}°C\n \n \n {{prevision.main.pressure}} mbar\n \n {{prevision.weather[0].description}}\n \n \n \n \n \n \n \n \n \n \n","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":true,"templateScope":"local","x":510,"y":280,"wires":[[]]},{"id":"38d477e5.da5688","type":"ui_template","z":"12b9999b.7256a6","group":"1e31c676.3642ea","name":"reponse","order":3,"width":0,"height":0,"format":"

Météo du jour

\n
Réponse décodée avec le pipe Angular json\n
{{msg.payload | json}}
\n","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":true,"templateScope":"local","x":500,"y":160,"wires":[[]]},{"id":"dade1f8b.be12e","type":"ui_button","z":"12b9999b.7256a6","name":"","group":"1e31c676.3642ea","order":1,"width":0,"height":0,"passthru":false,"label":"Actualiser","tooltip":"","color":"","bgcolor":"","icon":"","payload":"","payloadType":"date","topic":"","x":80,"y":120,"wires":[["c6442529.2d4f58","10528df7.922f02"]]},{"id":"10528df7.922f02","type":"openweathermap","z":"12b9999b.7256a6","name":"Météo à Lyon","wtype":"current","lon":"","lat":"","city":"lyon","country":"france","language":"fr","x":280,"y":120,"wires":[["6504a840.b5f2b8","38d477e5.da5688","f528240.040cbe"]]},{"id":"c6442529.2d4f58","type":"openweathermap","z":"12b9999b.7256a6","name":"Prévisions à lyon","wtype":"forecast","lon":"","lat":"","city":"lyon","country":"france","language":"fr","x":290,"y":280,"wires":[["25bafe0e.b49272","f528240.040cbe"]]},{"id":"d9fc5c5f.19c72","type":"ui_group","z":"","name":"Prévisions","tab":"e10674c.ce00988","order":1,"disp":true,"width":"12","collapse":false},{"id":"1e31c676.3642ea","type":"ui_group","z":"","name":"Réponse OpenWeatherMap","tab":"e10674c.ce00988","order":2,"disp":true,"width":"6","collapse":false},{"id":"e10674c.ce00988","type":"ui_tab","z":"","name":"Home","icon":"fa-fire","disabled":false,"hidden":false}]

Mises à jour

27/07/2020 Première publication du tutoriel

Avez-vous aimé cet article ?