Probabilité de pluie et de neige en lua

Bonjour,
comme beaucoup, j’avais installé l’excellent script du blog Domotic and stupid geek stuff utilisant l’API de https://www.wunderground.com/.
Seul défaut à mon goût, script en bash à lancer via un crontab et aucune remontée de fonctionnement dans les logs de domoticz.
En revisitant les données délivrées par cette api, je me suis rendu compte qu’il y avait plein d’autres données, et notamment les probabilités de neige.
Et voila une occasion de réécrire ce script en lua, en ajoutant les probabilités de neige, en facilitant le choix des heures de probabilité, la possibilité d’etre notifié au delà d’un certain seuil de probabilité et … j’aime bien le lua.
probabilité neige et pluie

--[[
name : script_time_probabilite_pluie.lua
auteur : papoo
date de création : 04/02/2018
Date de mise à jour : 26/12/2017
Principe : Ce script a pour but d'interroger l'API du site https://www.wunderground.com/ toutes les heures afin de 
récuperer les calculs de probabilités de pluie et de neige sur 36 heures pour une ville donnée. Cette API utilise une clé gratuite pour 500 requêtes par heure
Il faut donc s'inscrire sur weatherunderground pour avoir accès à cette API 
avant l'utilisation de ce script, pensez à créer une variable utilisateur de type chaine pour y stocker votre clé API
pour créer/modifier une variable utilisateur : domoticz => Réglages => Plus d'options => Variables utilisateur
/probabilite-de-pluie-et-de-neige-en-lua/
http://easydomoticz.com/forum/viewtopic.php?f=17&t=2301#p20893
https://github.com/papo-o/domoticz_scripts/blob/master/Lua/script_time_probabilite_pluie.lua

Ce script utilise Lua-Simple-XML-Parser https://github.com/Cluain/Lua-Simple-XML-Parser
]]--
--------------------------------------------
------------ Variables à éditer ------------
-------------------------------------------- 
local nom_script = 'Probabilite Pluie'
local version = '1.17'
local debugging = true  			            -- true pour voir les logs dans la console log Dz ou false pour ne pas les voir
local pays='FRANCE'					    -- Votre pays, nécessaire pour l'API
local api_wu = 'api_weather_underground' 	    -- Nom de la variable utilisateur contenant l'API Weather Underground de 16 caractères préalablement créé (variable de type chaine)
local ville='Limoges'    			            -- Votre ville ou commune 
                                                -- L'api fournie 36 probabilités de pluie, 1 par heure.  
local proba_pluie_h = {}			            -- Ajoutez, modifiez ou supprimez les variables proba_pluie_h[] 
                                                -- en changeant le N° entre [] correspondant à l'heure souhaitée pour l'associer au device concerné dans dz
proba_pluie_h[1]=504    			            -- renseigner l'idx du device % probabilité pluie à 1 heure associé, nil si non utilisé 
proba_pluie_h[2]=505    			            -- renseigner l'idx du device % probabilité pluie à 2 heures associé, nil si non utilisé
proba_pluie_h[4]=639   				            -- renseigner l'idx du device % probabilité pluie à 4 heures associé, nil si non utilisé
proba_pluie_h[6]=506    			            -- renseigner l'idx du device % probabilité pluie à 6 heures associé, nil si non utilisé
proba_pluie_h[12]=507   			            -- renseigner l'idx du device % probabilité pluie à 12 heures associé, nil si non utilisé
proba_pluie_h[24]=508   			            -- renseigner l'idx du device % probabilité pluie à 24 heures associé, nil si non utilisé
                                                -- L'api fournie 36 probabilités de neige, 1 par heure.
local proba_neige_h={}				            -- comme pour la pluie Ajoutez, modifiez ou supprimez les variables proba_neige_h[] 
                                                -- en changeant le N° entre [] correspondant à l'heure souhaitée pour l'associer au device concerné dans dz	
proba_neige_h[1]=771    			            -- renseigner l'idx du device % probabilité neige à 1 heure associé, nil si non utilisé 
proba_neige_h[3]=772    		                -- renseigner l'idx du device % probabilité neige à 2 heures associé, nil si non utilisé
proba_neige_h[6]=773   				            -- renseigner l'idx du device % probabilité neige à 4 heures associé, nil si non utilisé
proba_neige_h[12]=774    			            -- renseigner l'idx du device % probabilité neige à 6 heures associé, nil si non utilisé
proba_neige_h[24]=738   			            -- renseigner l'idx du device % probabilité neige à 12 heures associé, nil si non utilisé
proba_neige_h[36]=775  				            -- renseigner l'idx du device % probabilité neige à 24 heures associé, nil si non utilisé

local seuil_notification= nil	                -- pourcentage au delà duquel vous souhaitez être notifié, nil si non utilisé

--------------------------------------------
----------- Fin variables à éditer ---------
-------------------------------------------- 
local pluie
local neige
--------------------------------------------
---------------- Fonctions -----------------
-------------------------------------------- 
function voir_les_logs (s,debugging)
    if (debugging) then 
		if s ~= nil then
        print (" ".. s .." ")
		else
		print ("aucune valeur affichable")
		end
    end
end	
---------------------------------------------------------------------------------
-- Lua-Simple-XML-Parser
---------------------------------------------------------------------------------
    XmlParser = {};
	self = {};

    function XmlParser:ToXmlString(value)
        value = string.gsub(value, "&", "&"); -- '&' -> "&"
        value = string.gsub(value, "<", "<"); -- '<' -> "<"
        value = string.gsub(value, ">", ">"); -- '>' -> ">"
        value = string.gsub(value, "\"", """); -- '"' -> """
        value = string.gsub(value, "([^%w%&%;%p%\t% ])",
            function(c)
                return string.format("&#x%X;", string.byte(c))
            end);
        return value;
    end

    function XmlParser:FromXmlString(value)
        value = string.gsub(value, "&#x([%x]+)%;",
            function(h)
                return string.char(tonumber(h, 16))
            end);
        value = string.gsub(value, "&#([0-9]+)%;",
            function(h)
                return string.char(tonumber(h, 10))
            end);
        value = string.gsub(value, """, "\"");
        value = string.gsub(value, "'", "'");
        value = string.gsub(value, ">", ">");
        value = string.gsub(value, "<", "<");
        value = string.gsub(value, "&", "&");
        return value;
    end

    function XmlParser:ParseArgs(node, s)
        string.gsub(s, "(%w+)=([\"'])(.-)%2", function(w, _, a)
            node:addProperty(w, self:FromXmlString(a))
        end)
    end

    function XmlParser:ParseXmlText(xmlText)
        local stack = {}
        local top = newNode()
        table.insert(stack, top)
        local ni, c, label, xarg, empty
        local i, j = 1, 1
        while true do
            ni, j, c, label, xarg, empty = string.find(xmlText, "<(%/?)([%w_:]+)(.-)(%/?)>", i)
            if not ni then break end
            local text = string.sub(xmlText, i, ni - 1);
            if not string.find(text, "^%s*$") then
                local lVal = (top:value() or "") .. self:FromXmlString(text)
                stack[#stack]:setValue(lVal)
            end
            if empty == "/" then -- empty element tag
                local lNode = newNode(label)
                self:ParseArgs(lNode, xarg)
                top:addChild(lNode)
            elseif c == "" then -- start tag
                local lNode = newNode(label)
                self:ParseArgs(lNode, xarg)
                table.insert(stack, lNode)
		top = lNode
            else -- end tag
                local toclose = table.remove(stack) -- remove top

                top = stack[#stack]
                if #stack < 1 then
                    error("XmlParser: nothing to close with " .. label)
                end
                if toclose:name() ~= label then
                    error("XmlParser: trying to close " .. toclose.name .. " with " .. label)
                end
                top:addChild(toclose)
            end
            i = j + 1
        end
        local text = string.sub(xmlText, i);
        if #stack > 1 then
            error("XmlParser: unclosed " .. stack[#stack]:name())
        end
        return top
    end

    function XmlParser:loadFile(xmlFilename, base)
        if not base then
            base = system.ResourceDirectory
        end

        local path = system.pathForFile(xmlFilename, base)
        local hFile, err = io.open(path, "r");

        if hFile and not err then
            local xmlText = hFile:read("*a"); -- read file content
            io.close(hFile);
            return self:ParseXmlText(xmlText), nil;
        else
            print(err)
            return nil
        end
    end

function newNode(name)
    local node = {}
    node.___value = nil
    node.___name = name
    node.___children = {}
    node.___props = {}

    function node:value() return self.___value end
    function node:setValue(val) self.___value = val end
    function node:name() return self.___name end
    function node:setName(name) self.___name = name end
    function node:children() return self.___children end
    function node:numChildren() return #self.___children end
    function node:addChild(child)
        if self[child:name()] ~= nil then
            if type(self[child:name()].name) == "function" then
                local tempTable = {}
                table.insert(tempTable, self[child:name()])
                self[child:name()] = tempTable
            end
            table.insert(self[child:name()], child)
        else
            self[child:name()] = child
        end
        table.insert(self.___children, child)
    end

    function node:properties() return self.___props end
    function node:numProperties() return #self.___props end
    function node:addProperty(name, value)
        local lName = "@" .. name
        if self[lName] ~= nil then
            if type(self[lName]) == "string" then
                local tempTable = {}
                table.insert(tempTable, self[lName])
                self[lName] = tempTable
            end
            table.insert(self[lName], value)
        else
            self[lName] = value
        end
        table.insert(self.___props, { name = name, value = self[name] })
    end

    return node
end
--------------------------------------------
-------------- Fin Fonctions ---------------
-------------------------------------------- 
commandArray = {}
time=os.date("*t")

--if time.min % 2 == 0 then -- exécution du script toutes les X minute(s) 
if ((time.min-1) % 60) == 0 then -- exécution du script toutes les heures à xx:01
	voir_les_logs("=========== ".. nom_script .." (v".. version ..") ===========",debugging)
local APIKEY = uservariables[api_wu]

    local rid = assert(io.popen("/usr/bin/curl -m8 http://api.wunderground.com/api/"..APIKEY.."/hourly/lang:FR/q/"..pays.."/"..ville..".xml"))
    voir_les_logs("--- --- --- http://api.wunderground.com/api/"..APIKEY.."/hourly/lang:FR/q/"..pays.."/"..ville..".xml",debugging)
    local testXml = rid:read('*all')
    rid:close()                    

local parsedXml = XmlParser:ParseXmlText(testXml)
	if (parsedXml) then local abr = parsedXml.response.hourly_forecast	
		for i in pairs(abr:children()) do 
				if proba_pluie_h[i] ~= nil then 
					pluie = tonumber(abr:children()[i]:children()[19]:value())
					voir_les_logs("--- --- --- Probabilite de pluie a ".. i .."h => " .. pluie,debugging)
					commandArray[#commandArray+1] = {['UpdateDevice'] = proba_pluie_h[i]..'|0|'.. pluie}
					if seuil_notification ~= nil and pluie > seuil_notification then
					commandArray[#commandArray+1] = {['SendNotification'] = 'Alerte : '.. pluie ..' % de probabilité de pluie dans '.. i ..'heure(s)'}
					
					end
				end
				if proba_neige_h[i] ~=nil then
					neige = tonumber(abr:children()[i]:children()[18]:children()[2]:value())
					voir_les_logs("--- --- --- probabilite de neige a ".. i .."h => " .. neige,debugging)
					commandArray[#commandArray+1] = {['UpdateDevice'] = proba_neige_h[i]..'|0|'.. neige}
					if seuil_notification ~= nil and neige > seuil_notification then
					commandArray[#commandArray+1] = {['SendNotification'] = 'Alerte : '.. neige ..' % de probabilité de neige dans '.. i ..'heure(s)'}
					end
                    --print(abr:children()[i]:children()[4]:value())
                end
		end
	end	
	voir_les_logs("========= Fin ".. nom_script .." (v".. version ..") =========",debugging)
end -- if time
return commandArray

si des fois cela peut vous servir

10 thoughts on “Probabilité de pluie et de neige en lua

  1. Bonjour Titof
    As tu bien créé une variable utilisateur contenant l’api et renseigné son nom ?

    local api_wu = ‘api_weather_underground’ — nom de la variable utilisateur contenant l’API Weather Underground de 16 caractères préalablement créé (variable de type chaine)

  2. bonjour
    j’ai un message d’erreur dans domoticz quand je regarde les log.
    le voila
    2017-05-10 21:09:00.015 Error: EventSystem: in /home/pi/domoticz/scripts/lua/script_time_probabilite_pluie.lua: …i/domoticz/scripts/lua/script_time_probabilite_pluie.lua:70: ‘)’ expected near ‘ »); — ‘ »
    Pouvez vous me dire d’ou ça vient
    merci d’avance

  3. la ligne 69 fait partie d’une fonction qui agit sur le contenu du fichier téléchargé
    sans fichier téléchargé dans le répertoire /tmp/ elle ne peut pas s’exécuter
    Il faudrait vérifier les droits du fichiers, au minimum chmod 644

  4. bonsoir
    ma cle API est bien la bonne car elle fonctionne sous domoticz pour récupérer les infos météo de ma ville
    accès extérieur: je ne passe pas car d’autre scripts fonctionnent
    et j’ai bien mis Limoges comme ville sans espace
    c’est surtout que dans les log j’ai l’erreur suivante qui remonte , comme s’il y avait un caractère manquant :
    Error: EventSystem: in /home/pi/domoticz/scripts/lua/script_time_probabilite_pluie.lua: …i/domoticz/scripts/lua/script_time_probabilite_pluie.lua:69: ‘)’ expected near ‘ »); — ‘ »‘

  5. c’est donc que la requête wget n’a pas aboutie
    plusieurs causes possible :
    clé API incorrecte, vous etes vous inscrit sur Weather Underground pour avoir votre propre clé API (les chiffres donnés dans le script ne sont qu’un exemple)
    accès extérieur bloqué (par feu?)
    erreur dans l’adresse Weather Underground
    espace dans la variable ville

  6. bonsoir
    dans le répertoire /tmp/
    il y a t’il un fichier nommé limoges.out ? si oui est il vide ou contient il quelque chose?

  7. bonsoir et merci pour votre intérêt
    local debbuging était déjà en true et le message d’erreur est celui que j’ai cite hier
    la clé est la bonne
    et j’ai essaye avec limoges toujours la même erreur
    visiblement il, j’avais pas exactement les même lignes donc j’ai recopie le code et commenter la ligne 221
    idem : Error: EventSystem: in /home/pi/domoticz/scripts/lua/script_time_probabilite_pluie.lua: …i/domoticz/scripts/lua/script_time_probabilite_pluie.lua:69: ‘)’ expected near ‘ »); — ‘ »‘

    je ne comprends pas
    merci

  8. Bonsoir,
    en mettant local debugging = true
    avez vous des informations dans les logs concernant le fonctionnement du script?
    votre clé API weatherunderground est elle correctement renseignée?
    la déclaration de votre ville est elle correcte et connue de weatherunderground (faire un essai avec Limoges qui fonctionne)
    décommentez la ligne 220 et commentez la ligne 221 comme ceci
    local fname ="/tmp/weather"..ville..".out"
    --local fname ="/media/Freebox/Trend/weather"..ville..".out"

  9. bonsoir
    j’ai tenter de faire fonctionner votre script, or domoticz me remonte une erreur, je ne comprend pas :
    EventSystem: in /home/pi/domoticz/scripts/lua/script_time_probabilite_pluie.lua: …i/domoticz/scripts/lua/script_time_probabilite_pluie.lua:69: ‘)’ expected near ‘ »); — ‘ »‘
    voici ce que j’ai a la ligne 69 :
    value = string.gsub(value, « \ » », «  » »); — ‘ »‘ -> «  » »

    sauriez vous d’ou vient le problème
    Merci d’avance pour votre aide
    cordialement

Laisser un commentaire