[LUA] Quantité de précipitation avec OpenWeatherMap

Vous avez créé un script LUA dont vous êtes fier, un .sh génial, un programme Python hors du commun, un Tuto, c'est ici que vous pouvez les partager.
Vianncy
Messages : 27
Inscription : 16 janv. 2021, 18:30

[LUA] Quantité de précipitation avec OpenWeatherMap

Message par Vianncy »

Bonjour à tous et bonne année. ;)
J'ouvre ce topic suite à la remarque de Keros (sur ce topic: viewtopic.php?f=17&t=9892) afin de mieux mettre en avant et détailler ce tutoriel.
Avant toute chose, sachez que je débute en Lua et avec Domoticz. Je suis loin d'être un expert et je reste bien évidemment à l'écoute de toutes remarques et conseils. ;)

Passons aux choses sérieuse!
Comment récupérer des données cumulées de précipitations annoncées sur 2h, 4h, 6h, 12h (et d'autres, si l'on veut) ?

Prérequis:
Je suis partie du script de joebuz (viewtopic.php?p=82679#p82679) pour réaliser cette partie de script. Je vous conseil d'y jeter un œil attentif avant toute chose.
Naturellement, vous n’êtes pas obligé d'utiliser ce même code. Si vous avez déjà implémenté OPW dans votre Domoticz, vous ne voudriez pas tout perdre. Ne vous inquiétez pas, je vous préciserai, durant ce tuto, quelle partie il faudra ajouter et où. Le seul réel prérequis est d'avoir ces lignes (ou équivalentes) permettant d'obtenir un JSON des prévisions:

Code : Tout sélectionner

--json = (loadfile "/home/votrenomutilisé/domoticz/scripts/lua/JSON.lua")() -- For Linux
json = (loadfile "/home/pi/domoticz/scripts/lua/JSON.lua")() -- for PI
--json = (loadfile "/volume1/@appstore/domoticz/var/scripts/lua/JSON.lua")() -- For Syno

Code : Tout sélectionner

    config=assert(io.popen('/usr/bin/curl "https://api.openweathermap.org/data/2.5/onecall?lat='..lat..'&lon='..long..'&appid='..api..'&lang=fr&units=metric"'))
    blocjson = config:read('*all')
    config:close()
    jsonValeur = json:decode(blocjson)
C'est pourquoi, avant de vous attaquer à cette partie je ne peux que vous conseiller de bien suivre le tuto de Keros (rappel: viewtopic.php?f=17&t=9892) et de bien comprendre les différentes parties. Je pars du principe que ces notions sont acquises, je ne m'attarderai pas dessus.

Objectif:
L'objectif de notre projet est donc de récupérer les quantités de précipitions cumulées sur différents intervalles de temps. Puis, stocker ces données dans des Device de précipitation.

Problématique:
En discutant ici, je me suis rendu compte que plusieurs personnes désiraient avoir ces informations mais ne savaient pas comment faire. Effectivement, l'un des problèmes est que ces informations ne sont pas dans le JSON (en tout cas pas directement comme l'avoir avec d'autres informations comme le pourcentage d'humidité).

Réalisation:
Nous voilà à la partie la plus importante. La solution. :mrgreen:
Mais avant d'aller directement à la solution, je vais vous expliquer comment en arriver là. Cela vous permettra de bien/mieux comprendre mon code. Avouez que c'est plus intéressant de comprendre ce que l'on fait, non? :mrgreen:


Partie JSON:
Tout d'abord, regardons le JSON car une partie de la solution se trouve dedans.
tempsnip.png
tempsnip.png (5.68 Kio) Consulté 5802 fois
Vous pouvez voir qu'il existe des menus déroulants (des nœuds) qui se nomment "current", "minutely" et... "hourly". Oui, "hourly", c'est à des prévisions par heure.
Voilà c'est bon, le tuto est fini :mrgreen:
Non, évidemment que le tuto n'est pas fini. Mais presque. On voit que le noeud contient lui même d'autres nœuds nommé 0, 1, 2, 3...
Déroulons ces noeuds (ici le 40):
image_2021-01-17_175322.png
image_2021-01-17_175322.png (10.11 Kio) Consulté 5802 fois
Ainsi, ici, on retrouve les différentes infos correspondant aux prévisions dans 40h. C'est la dernière ligne qui nous intéresse. Elle nous donne la quantité de pluie prévue pour cette heure (j'ai choisi ce noeud car je n'avais pas de pluie annoncée avant :mrgreen: ). Attention, c'est bien la quantité de pluie prévue pour l'heure 40 seule, pas une quantité cumulée (voir: https://openweathermap.org/api/one-call-api).

Super... mais on fait quoi maintenant ? :?: Je m'en fiche qu'il pleuve 0.12 mm dans 40h ! :!: Et moi aussi :D .
Revenons à notre problématique: Une quantité de pluie cumulé en 2h (ou en autant de temps que vous voulez). Et comment on obtient ça ? Et bien, en additionnant les quantité de pluie pour ces 2 premières heures (dans ce cas).

C'est là où l'on va mettre les mains dans le cambouis. Allez! Passons à la partie sur le LUA!



Partie LUA:
Vous savez comment récupérer un JSON avec LUA (et donc Domoticz), comment l'ouvrir, le lire... On ne va pas revenir là-dessus.
J'ai besoin d'avoir, au maximum, le cumulé des précipitations prévues pour les 12 prochaines heures.
Il me faut donc parcourir les 12 prochaines prévisions horaires. C'est ce que je fais là:

Code : Tout sélectionner

    
     local somme = 0 -- Somme des quantité. Peut être placée en en-tête.
    
    for i=1, 12 do --On parcourt les 12 prochaines heures.
        if (jsonValeur.hourly[i].rain) then  --Pluie prévue ?
            somme = somme + jsonValeur.hourly[i].rain["1h"] --Si oui, on additionne la quantité annoncée à cette heure à la somme des quantités. Sinon, on ne fait rien.
        end 
        if (jsonValeur.hourly[i].snow) then  --Neige prévue ?
            somme =  somme + jsonValeur.hourly[i].snow["1h"] --Même principe.
        end

        if (i == 2) then
            quantiteDeuxHeures = somme
        elseif (i == 4) then
            quantiteQuatresHeures = somme
        
        elseif (i == 6) then
            quantiteSixHeures = somme
        
        elseif (i == 12) then
            quantiteDouzeHeures = somme
        end
        
    end
Je déclare une somme (somme des quantités de précipitations) égale à 0 au début. A chaque itération de ma boucle for, on regarde si une précipitation est prévue. Si oui, alors on additionne cette quantité à la somme.
Dans cette boucle, vous pouvez voir un bloc "if". Son but est de vérifier où l'on est. Par exemple, if (i == 2) then , cela signifie que l'on en est à la prévision pour la prochaine 2eme heure. A ce moment là, on a donc additionné les précipitations prévues pour la prochaine heure et cette seconde heure. On affecte donc sa valeur à la variable représentant la quantité pour les deux prochaines heures.
Je récupère les précipitations avec jsonValeur.hourly.rain["1h"]. Comprenez par là que la variable i, qui s’incrémenter à chaque parcours de la boucle (de 1 à 12), permet de récupérer les données correspondantes à cette heure. Ensuite, j'ai dû écrire ["1h"] pour pouvoir récupérer les données de précipitations seule.

Partie Domoticz:
Si l'on veut stocker ces valeurs dans des Devices, il faut les créer. J'ai utilisé des Devices Précipitaitons. Créez-en autant que besoin(4 dans le cas décrit dans ce tuto). Notez leur Idx.
Ensuite, dans le script LUA on déclare nos devices (enfin leur Idx plus précisement).

Code : Tout sélectionner

local deuxHeuresDeviceIdx       = 25 
local quatreHeuresDeviceIdx     = 26 
local sixHeuresDeviceIdx        = 27 
local douzeHeuresDeviceIdx      = 28
Maintenant mettons à jour nos Devices (cette partie se place après la boucle for de la somme):

Code : Tout sélectionner

    commandArray[deuxHeuresDeviceIdx]   = { ['UpdateDevice'] = deuxHeuresDeviceIdx..'|1|0;'..quantiteDeuxHeures }
    commandArray[quatreHeuresDeviceIdx] = { ['UpdateDevice'] = quatreHeuresDeviceIdx..'|1|0;'..quantiteQuatresHeures }
    commandArray[sixHeuresDeviceIdx]    = { ['UpdateDevice'] = sixHeuresDeviceIdx..'|1|0;'..quantiteSixHeures }
    commandArray[douzeHeuresDeviceIdx]  = { ['UpdateDevice'] = douzeHeuresDeviceIdx..'|1|0;'..quantiteDouzeHeures }
Et voilà. :D

Le code en entier:

Code : Tout sélectionner


local time                       = os.date("*t")       -- Si vous souhaitez exécuté ce script toutes les X min
local start_hour                 = '06:00'             -- Si vous souhaitez exécuté ce script tous les jours à 6h
local actual_hour                = os.date("%H:%M")
local deuxHeuresDeviceIdx       = 25 
local quatreHeuresDeviceIdx     = 26 
local sixHeuresDeviceIdx        = 27 
local douzeHeuresDeviceIdx      = 28

--------------------------------------------
----------- Variables à éditer -------------
-------------------------------------------- 

local api = 'myapikey' -- Remplacer par votre clé API
local lat = 'mylat' --  Remplacer par ici votre latittude
local long = 'mylong' -- Remplacer par votre longitude

--Sélectionner le chemin vers votre fichier JSON.lua en décommentant  la ligne pour votre système d'exploitation

--json = (loadfile "/home/votrenomutilisé/domoticz/scripts/lua/JSON.lua")() -- For Linux
json = (loadfile "/home/pi/domoticz/scripts/lua/JSON.lua")() -- for PI
--json = (loadfile "/volume1/@appstore/domoticz/var/scripts/lua/JSON.lua")() -- For Syno


--------------------------------------------
---------- Fin variables à éditer ----------
-------------------------------------------- 

commandArray = {}
  log(scriptName.." "..scriptVersion.." - "..actual_hour)
  log("heure: " ..time.hour)
  -- Les script_time sont exécutés toute les 1 minute par Domoticz
  -- Limite de l'API : 1000 appels/jour, il y a 1440 minutes/jour
  -- A modifier si vous souhaitez toutes les 5, 10, 30, ... minutes (ici 20 minutes)

  if (time.min % 20)==0 then                 -- pour exécuter le script toutes les X min
  --if actual_hour==start_hour then        -- pour exécuter le script à heure fixe

    -- L'appel et l'enregistrement des prévisions dans la variable jsonValeur
    config=assert(io.popen('/usr/bin/curl "https://api.openweathermap.org/data/2.5/onecall?lat='..lat..'&lon='..long..'&appid='..api..'&lang=fr&units=metric"'))
    blocjson = config:read('*all')
    config:close()
    jsonValeur = json:decode(blocjson)


    --------------------------------------------
    ---- Code à modifier selon vos besoins -----
    -------------------------------------------- 

    
    local somme = 0 -- Somme des quantité. Peut être placée en en-tête.
    
    for i=1, 12 do --On parcourt les 12 prochaines heures.
        if (jsonValeur.hourly[i].rain) then  --Pluie prévue ?
            somme = somme + jsonValeur.hourly[i].rain["1h"] --Si oui, on additionne la quantité annoncée à cette heure à la somme des quantités. Sinon, on ne fait rien.
        end 
        if (jsonValeur.hourly[i].snow) then  --Neige prévue ?
            somme =  somme + jsonValeur.hourly[i].snow["1h"] --Même principe.
        end

        if (i == 2) then 
            quantiteDeuxHeures = somme
        elseif (i == 4) then
            quantiteQuatresHeures = somme
        
        elseif (i == 6) then
            quantiteSixHeures = somme
        
        elseif (i == 12) then
            quantiteDouzeHeures = somme
        end
        
    end
    
    commandArray[deuxHeuresDeviceIdx]   = { ['UpdateDevice'] = deuxHeuresDeviceIdx..'|1|0;'..quantiteDeuxHeures }
    commandArray[quatreHeuresDeviceIdx] = { ['UpdateDevice'] = quatreHeuresDeviceIdx..'|1|0;'..quantiteQuatresHeures }
    commandArray[sixHeuresDeviceIdx]    = { ['UpdateDevice'] = sixHeuresDeviceIdx..'|1|0;'..quantiteSixHeures }
    commandArray[douzeHeuresDeviceIdx]  = { ['UpdateDevice'] = douzeHeuresDeviceIdx..'|1|0;'..quantiteDouzeHeures }

    --------------------------------------------
    --------- Fin code à modifier  -------------
    --------------------------------------------
  end
return commandArray

N'oubliez pas que cela reste un tutoriel. Libre à vous d'adapter ce que j'ai fais selon vos besoins. Si vous voulez plus de données, moins de données, un intervalle de temps plus grand... Faites. Sachez simplement que les prévisions sont limité à 48h avec OWM dans sa version gratuite.
Dans mon cas, j'ai considéré comme précipitation neige et pluie indifféremment. Vous pouvez faire le distinguo si tel est votre envie/besoin. ;)

Cette version est une version "beta". Je ne l'ai pas encore testé en long, en large et en travers. Si vous rencontrez des problèmes avec n'hesitez pas à me faire remonter ça. N'hésitez pas non plus, si vous avez des questions.

Je pense ajouter à ce script les probabilités de précipitation. Si cela vous intéresse, je vous partagerai ça. ;)
Dernière modification par Vianncy le 27 janv. 2021, 00:33, modifié 9 fois.
Keros
Messages : 6638
Inscription : 23 juil. 2019, 20:57

Re: [LUA] Quantité de précipitation avec OpenWeatherMap

Message par Keros »

Super tuto bien expliqué. Merci pour le partage ;)
Comment bien utiliser le forum : Poser une question, Mettre un script, un fichier, une image ou des logs
Mes petits guides : Débuter en programmation, Le débogage, Le choix de matériel, Les sauvegardes
Ma présentation - Mes Tutos
Doudy
Messages : 457
Inscription : 07 mai 2016, 17:23

Re: [LUA] Quantité de précipitation avec OpenWeatherMap

Message par Doudy »

Tout à fait d'accord avec toi 👍
Merci ;)
Dernière modification par Keros le 18 janv. 2021, 12:27, modifié 1 fois.
Raison : Merci de ne pas citer le message précédent lors dune réponse directe
RaspberryPi - RFLink - Zwave - WH2600
Domoticz : 2020.2 | Dashticz : V3.12 Master | dzvents : 3.0.2 | Python : 3.7.3
Doudy
Messages : 457
Inscription : 07 mai 2016, 17:23

Re: [LUA] Quantité de précipitation avec OpenWeatherMap

Message par Doudy »

Vianncy a écrit : 17 janv. 2021, 18:40 Je pense ajouter à ce script les probabilités de précipitation. Si cela vous intéresse, je vous partagerai ça. ;)
Avec plaisir ;)

Je teste ton dernier script de suite.
RaspberryPi - RFLink - Zwave - WH2600
Domoticz : 2020.2 | Dashticz : V3.12 Master | dzvents : 3.0.2 | Python : 3.7.3
Doudy
Messages : 457
Inscription : 07 mai 2016, 17:23

Re: [LUA] Quantité de précipitation avec OpenWeatherMap

Message par Doudy »

Voilà, je commence les test.
Ma question : quel type de "Capteur Virtuel" pour les dispositifs suivants :

Pour le capteur "tempRessentiDeviceIdx", ton IDX 4, j'ai sélectionné le "Capteur Température"
Pour le Capteur "vtrDeviceIdx", ton IDX 13, j'ai sélectionné le "Capteur Vent+Température+Ressenti"
Pour le capteur "humDeviceIdx", ton IDX 14, j'ai sélectionné le "Capteur Humidité" au lieu de "Pourcentage" comme indiqué
Pour le capteur "cloudDeviceIdx", tin IDX 12, j'ai sélectionné le "Capteur Pourcentage"

Pour les capteurs 25,26,27,28 j'ai sélectionné un "Capteur Pourcentage"

Ta clé API se trouve dans ton script

Je continue ...
RaspberryPi - RFLink - Zwave - WH2600
Domoticz : 2020.2 | Dashticz : V3.12 Master | dzvents : 3.0.2 | Python : 3.7.3
Doudy
Messages : 457
Inscription : 07 mai 2016, 17:23

Re: [LUA] Quantité de précipitation avec OpenWeatherMap

Message par Doudy »

Voici le résultat :
Image
Image
Image
Pas d'erreur dans le script.
Maintenant il faut analyser les résultats...
RaspberryPi - RFLink - Zwave - WH2600
Domoticz : 2020.2 | Dashticz : V3.12 Master | dzvents : 3.0.2 | Python : 3.7.3
Vianncy
Messages : 27
Inscription : 16 janv. 2021, 18:30

Re: [LUA] Quantité de précipitation avec OpenWeatherMap

Message par Vianncy »

Doudy a écrit : 18 janv. 2021, 09:13 Voilà, je commence les test.
Ma question : quel type de "Capteur Virtuel" pour les dispositifs suivants :

Pour le capteur "tempRessentiDeviceIdx", ton IDX 4, j'ai sélectionné le "Capteur Température"
Pour le Capteur "vtrDeviceIdx", ton IDX 13, j'ai sélectionné le "Capteur Vent+Température+Ressenti"
Pour le capteur "humDeviceIdx", ton IDX 14, j'ai sélectionné le "Capteur Humidité" au lieu de "Pourcentage" comme indiqué
Pour le capteur "cloudDeviceIdx", tin IDX 12, j'ai sélectionné le "Capteur Pourcentage"

Pour les capteurs 25,26,27,28 j'ai sélectionné un "Capteur Pourcentage"
Je débute en Domoticz donc je suis loin d'être calé niveau capteur... J'ai choisi exactement les mêmes capteurs sauf pour humidité. Je ne sais pas/plus pourquoi je n'ai pas utilisé un capteur humidité (j'ai pas dû faire attention :oops: ). A tester, ça doit sans doute marcher. ;)

Pour les capteurs 25,26,27,28 je te conseille d'utiliser plutôt un capteur précipitation. Car ce sont des quantités que l'on récupère et non un pourcentage. ;)

Doudy a écrit : 18 janv. 2021, 09:13
Ta clé API se trouve dans ton script
Effectivement :oops:
Merci, j'ai corrigé ça ;)
Doudy
Messages : 457
Inscription : 07 mai 2016, 17:23

Re: [LUA] Quantité de précipitation avec OpenWeatherMap

Message par Doudy »

Vianncy a écrit : 18 janv. 2021, 09:27
Je débute en Domoticz donc je suis loin d'être calé niveau capteur...
Moi non plus je ne suis pas un spécialiste mais j'aurais nommé mes capteurs en commençant par IDX.
Il me semble que c'est plus facile à repérer et à classer

Code : Tout sélectionner

local IdxTempDevice
local IdxTempRessentieDevice
local IdxVtrDevice
local IdxRainDevice
local IdxSnowDevice
local IdxUvDevice
local IdxAtmDevice
local IdxHumDevice
local IdxCloudDevice
local IdxDeuxHeuresDevice
local IdxQuatreHeuresDevice
local IdxSixHeuresDevice
local IdxDouzeHeuresDevice
local IdxVingtquatreHeuresDevice
Ca c'est mon idée ;)
RaspberryPi - RFLink - Zwave - WH2600
Domoticz : 2020.2 | Dashticz : V3.12 Master | dzvents : 3.0.2 | Python : 3.7.3
Doudy
Messages : 457
Inscription : 07 mai 2016, 17:23

Re: [LUA] Quantité de précipitation avec OpenWeatherMap

Message par Doudy »

il y a

Code : Tout sélectionner

    commandArray[rainDeviceIdx] = { ['UpdateDevice'] = snowDeviceIdx..'|1|0;'..snow }
    log('MAJ snowDevice '..rainDeviceIdx..' : '..snow..'mm')
Il faut

Code : Tout sélectionner

    commandArray[snowDeviceIdx] = { ['UpdateDevice'] = snowDeviceIdx..'|1|0;'..snow }
    log('MAJ snowDevice '..snowDeviceIdx..' : '..snow..'mm')
il y a rainDeviceIdx il faut snowDeviceIdx
;)
RaspberryPi - RFLink - Zwave - WH2600
Domoticz : 2020.2 | Dashticz : V3.12 Master | dzvents : 3.0.2 | Python : 3.7.3
Vianncy
Messages : 27
Inscription : 16 janv. 2021, 18:30

Re: [LUA] Quantité de précipitation avec OpenWeatherMap

Message par Vianncy »

Doudy a écrit : 18 janv. 2021, 11:32
Vianncy a écrit : 18 janv. 2021, 09:27
Je débute en Domoticz donc je suis loin d'être calé niveau capteur...
Moi non plus je ne suis pas un spécialiste mais j'aurais nommé mes capteurs en commençant par IDX.
Il me semble que c'est plus facile à repérer et à classer

Code : Tout sélectionner

local IdxTempDevice
local IdxTempRessentieDevice
local IdxVtrDevice
local IdxRainDevice
local IdxSnowDevice
local IdxUvDevice
local IdxAtmDevice
local IdxHumDevice
local IdxCloudDevice
local IdxDeuxHeuresDevice
local IdxQuatreHeuresDevice
local IdxSixHeuresDevice
local IdxDouzeHeuresDevice
local IdxVingtquatreHeuresDevice
Ca c'est mon idée ;)

Comme je l'ai dit en préambule, 80% du code ne vient pas de moi mais de joebuz (ici: viewtopic.php?f=17&t=9892&start=20). Je pars du principe que vous êtes déjà passé par là, que vous avez implémenté et expérimenté ce code.
Je me suis occupé que de la partie des "quantités cumulés". Pour le reste des parties, elles ne sont pas obligatoire pour cette étape et si vous avez des questions dessus, je vous conseille plutôt de les poser dans ce topic: viewtopic.php?f=17&t=9892
Je l'utilise simplement comme base et mon but est d'expliquer comment "rajouter" à ce code. Je ne cherche pas à réinventer son code pour ne pas perdre ceux qui seraient plus en difficulté avec le code. Je cherche simplement à aller au plus simple pour tout le monde.
Si j'avais commencé ce projet "from scratch" (en partant de 0), effectivement j'aurais fais plusieurs choses différemment comme le nommage. Mais comme je pars du principe que les personnes ont peu ou prou ce code, je ne voulais pas tout modifier afin de rendre l'ajout plus simple et compréhensible. Le code entier sert avant tout à mieux orienter les personnes sur où ajouter les parties que j'explique. C'est pour ça que je m'efforce à bien expliquer les différentes parties. ;)
Je déconseille d'ailleurs de vouloir prendre le code entier et implémenter directement. Je conseillerai plutôt de commencer par le très bon tuto de Keros (viewtopic.php?f=17&t=9892) car je ne ré-explique pas ce qu'il a déjà assez bien expliquer dans son tuto.

Je cherche avant tout à donner des clefs et pas une solution "clef en main". Le but est que vous compreniez ce que j'ai fais, comment ça marche pour pouvoir l'adapter selon votre convenance.
Si tu penses que tel ou telle chose est mieux, alors fais. Je t'y encourage. C'est le but du code et du DIY. On explique comment faire le plus simplement possible afin que chacun puisse prendre les outils en main. Et libre à chacun d'ajouter sa petite touche. ;)


Concernant ton dernier message, ce n'est pas impossible que je me sois trompé effectivement (et ça semble être le cas :oops: ). Je te remercie d'avoir relevé cette erreur, je corrige ça dès que je peux. ;)

Edit: Effectivement j'ai fais un copié-collé pas fameux (voilà pourquoi je ne vous encourage pas à copier-coller :mrgreen: ) et je suis totalement passé à côté de cette erreur... Quel âne!
Encore merci à toi de m'avoir alerté de cette erreur, j'ai corrigé ça. ;)
Répondre