[LUA] Données Météo avec API Openweathermap
Publié : 01 avr. 2023, 09:29
Ma petite contribution pour les nouveaux inscrits sur Open Weather Map (mon code dzVents)
Code : Tout sélectionner
--[[ ~/home/pi/domoticz/scripts/dzVents/scripts/OpenWeatherMap.lua
author : gso
MAJ : 31/03/2023
création : 24/03/2023
Principe :
https://api.openweathermap.org/data/3.0/onecall?lat=48.0&lon=2.0&appid=[api_key]&units=metric&lang=fr&exclude=minutely,hourly
{"dt":1680069600,"temp":9.57,"feels_like":7.96,"pressure":1017,"humidity":79,"dew_point":5.89,"uvi":0,"clouds":100,"visibility":10000,"wind_speed":3.06,"wind_deg":204,"wind_gust":9.91
,"weather":[{"id":500,"main":"Rain","description":"légère pluie","icon":"10d"}],"pop":0.26
,"rain":{"1h":0.48}}]
,"alerts":[{"sender_name":"METEO-FRANCE","event":"Moderate thunderstorm warning","start":1680321640,"end":1680386400,"description":"Moderate damages may occur, especially in vulnerable or in exposed areas and to people who carry out weather-related activities.","tags":["Thunderstorm"]}]}
}
apiKey = to get on https://openweathermap.org/api and set in domoticz.variables with name "apikey_openweathermap" or set it in the code
]]--
-- local
local scriptName = 'OpenWeatherMap'
local scriptVersion = '1.0'
local uri = 'https://api.openweathermap.org/data/3.0/onecall'
local units = 'metric'
local lang = 'fr'
local exclude = 'minutely,hourly' --minutely,hourly,daily,alerts
local prefix = 'OWM'
local devices = { -- devices idx (to be changed accordingly), dz update device function
-- Temperature (°C if metric)
-- {idx = 0, cde = function (dz, idx, v) dz.devices(idx).updateTempHum(v.current.temp, v.current.humidity, dz.HUM_COMPUTE) end },
-- Dew Point (°C)
-- {idx = 0, cde = function (dz, idx, v) dz.devices(idx).updateTemperature(v.current.dew_point) end },
-- Pressure
{idx = 986, cde = function (dz, idx, v) dz.devices(idx).updatePressure(v.current.pressure) end }, -- pressure
--THB
{idx = 982, cde = function (dz, idx, v)
local pop = v.daily[2].pop -- probability of precipitation for tomorrow
local clouds = v.daily[2].clouds
local baro = dz.BARO_NOINFO
if pop >= 0.3 then baro = dz.BARO_RAIN
elseif clouds >= 75 then baro = dz.BARO_CLOUDY
elseif clouds >= 25 then baro = dz.BARO_PARTLY_CLOUDY
else baro = dz.BARO_SUNNY
end
dz.devices(idx).updateTempHumBaro(v.current.temp, v.current.humidity, dz.HUM_COMPUTE, v.current.pressure, baro)
end },
-- UV
{idx = 981, cde = function (dz, idx, v) dz.devices(idx).updateUV(v.current.uvi) end },
-- Clouds (%)
{idx = 977, cde = function (dz, idx, v) dz.devices(idx).updatePercentage(v.current.clouds) end },
-- Visibility (km)
{idx = 983, cde = function (dz, idx, v) dz.devices(idx).updateVisibility(v.current.visibility/1000) end },
-- Wind
{idx = 984, cde = function (dz, idx, v)
if v.current.wind_gust == nil then v.current.wind_gust = v.current.wind_speed end
degrees = v.current.wind_deg
local quadrants = {"NNE","NE","ENE","E","ESE","SE","SSE","S","SSW","SW","WSW","W","WNW","NW","NNW"}
local quad = 'N'
if degrees <= 348.75 and degrees > 11.25 then quad = quadrants[tonumber(math.floor((degrees - 11.25) / 22.5)+1)] end
dz.devices(idx).updateWind(degrees, quad, v.current.wind_speed, v.current.wind_gust, v.current.temp, v.current.feels_like)-- bearing(°), direction(N S NNW..), speed(m/s), gust(m/s), temperature(°C), chill(°C)
end },
-- Rain (rate in mm * 100 per hour, counter is total in mm)
{idx = 985, cde = function (dz, idx, v)
if v.current.rain ~= nil then dz.devices(idx).updateRain(v.current.rain['1h']*100, v.daily[1].rain)
elseif v.daily[1] ~= nil then dz.devices(idx).updateRain(0, v.daily[1].rain)
else dz.devices(idx).updateRain(0, 0) end
end },
-- Snow
{idx = 0, cde = function (dz, idx, v)
if v.current.snow ~= nil then dz.devices(idx).updateRain(v.current.snow['1h']*100, v.daily[1].snow)
elseif v.daily[1] ~= nil then dz.devices(idx).updateRain(0, v.daily[1].snow)
else dz.devices(idx).updateRain(0, 0) end
end }, --rate in mm * 100 per hour, counter is total in mm)
-- Meteo
{idx = 979, cde = function (dz, idx, v)
local txt = v.current.weather[1].description..' ('..v.current.weather[1].main..' - '..v.current.weather[1].id..')'
dz.devices(idx).updateText(txt)
end },
-- Moon
{idx = 989, cde = function (dz, idx, v)
-- local dt = os.date("%a %d %b à %X", v.daily[1].dt) -- UTC
local moonrise = os.date("%Hh%M", v.daily[1].moonrise) -- UTC
local moonset = os.date("%Hh%M", v.daily[1].moonset) -- UTC
local p = v.daily[1].moon_phase*100 -- 0 and 1 are 'new moon', 0.25 is 'first quarter moon', 0.5 is 'full moon' and 0.75 is 'last quarter moon'.
if p==0 or p==100 then phase = "Nouvelle Lune ➚"
elseif p<25 then phase = "Premier Croissant ➚"
elseif p==25 then phase = "Premier Quartier ➚"
elseif p<50 then phase = "Gibeuse Croissante ➚"
elseif p==50 then phase = "Pleine Lune ➘"
elseif p<75 then phase = "Gibeuse Décroissante ➘"
elseif p==75 then phase = "Dernier Quartier ➘"
elseif p<100 then phase = "Dernier Croissant ➘"
end
-- luminosity
p = 2*p
if p>100 then p = 200-p end
local txt = "Lever à "..moonrise.."\nCoucher à "..moonset.."\nPhase : "..phase.." ("..p.."%)"
dz.devices(idx).updateText(txt)
end },
-- Moon Phase (%)
{idx = 988, cde = function (dz, idx, v)
dz.devices(idx).updatePercentage(v.daily[1].moon_phase*100)
end },
-- Alerts
{idx = 987, cde = function (dz, idx, v)
if v.alerts ~= nil then
local txt = ''
for k, alert in ipairs(v.alerts) do
local from = os.date("%a %d %b à %X", alert['start'])
local to = os.date("%a %d %b à %X", alert['end'])
txt = txt..k..'. '..alert.event.."\n"
txt = txt..' du '..from.."\n"
txt = txt..' au '..to.."\n"
txt = txt..alert.description.."\n"
-- txt = txt..alert.sender_name -- Meteo France
txt = txt..' tags : '..table.concat(alert.tags, ', ')..'\n\n'
end
-- updateAlertSensor(level, text): Function. Level can be domoticz.ALERTLEVEL_GREY, ALERTLEVEL_GREEN, ALERTLEVEL_YELLOW, ALERTLEVEL_ORANGE, ALERTLEVEL_RED. Supports command options.
dz.devices(idx).updateAlertSensor(dz.ALERTLEVEL_RED, txt)
dz.notify('Alerte Météo', txt, dz.PRIORITY_HIGH) -- notify(subject, message, priority, sound) domoticz.PRIORITY_LOW, PRIORITY_MODERATE, PRIORITY_NORMAL, PRIORITY_HIGH, PRIORITY_EMERGENCY
else
dz.devices(idx).updateAlertSensor(dz.ALERTLEVEL_GREEN, "Pas d'alerte")
end
end },
}
-- LOOP
return {
active = true, -- false,
on = {
timer = { "every 10 minutes" },
httpResponses = { "OWMcallback" }, -- matches callback wildcard
},
logging = {
level = domoticz.LOG_ERROR, domoticz.LOG_INFO, --, domoticz.LOG_DEBUG, domoticz.LOG_MODULE_EXEC_INFO
marker = '-- '..scriptName..' v'..scriptVersion
},
-- LOOP
execute = function(dz, triggerItem)
local apiKey = dz.variables('apikey_openweathermap').value
local function errorMessage(message,notify) -- Add entry to log and notify to all subsystems
dz.log(message, dz.LOG_ERROR)
if notify then
-- dz.notify(message) -- notify(subject, message, priority, sound): Fonction. Envoi d’une notification (Prowl). La priorité sera choisie entre domoticz.PRIORITY_LOW, PRIORITY_MODERATE, PRIORITY_NORMAL, PRIORITY_HIGH, PRIORITY_EMERGENCY
end
end
-- MAIN
if triggerItem.isTimer then
local pos = 'lat=' .. dz.settings.location.latitude .. "&lon=" .. dz.settings.location.longitude
local url = uri .."?"..pos..'&appid='..apiKey..'&units='..units..'&lang='..lang..'&exclude='..exclude
-- errorMessage("DBG URL="..url)
dz.openURL({
url = url,
method = "GET",
callback= 'OWMcallback'
}).afterSec(1)
end
if triggerItem.isHTTPResponse then
if triggerItem.ok and triggerItem.isJSON then
local resultsTable = triggerItem.json
if resultsTable ~= nil and resultsTable.current ~= nil then
for k, d in ipairs(devices) do
if d['idx'] ~= 0 then d.cde(dz, d['idx'], resultsTable) end
end
end
else
errorMessage("Problem with response from OWM", false)
end
end
end --execute
}