PLUVIOMETRIE (ET ARROSAGE) AVEC NETATMO
firmware 4.x seulement
Partie 1 : récupérer l'historique
Netatmo est une station météo sur laquelle vous pouvez brancher un "pluviomètre" de la même marque. Afin d'exploiter les données de ce pluviomètre et vous pouvez utiliser l'application Netatmo ou son site web. Vous pouvez aussi installer le plugin Netatmo fourni par Fibaro. Ce dernier vous affichera uniquement les données à l'instant précis ou vous être entrain de le regarder.
Nous, nous voulons allez plus loin, nous voulons connaitre les quantités de pluie ayant eu lieu depuis : 1 jour, 1 semaine, 1 mois, cela dans l'optique de pouvoir gérer correctement notre arrosage.
Pour ce faire, il existe un grand nombre de script PHP, Google Script qui permet de gérer cela .. mais ... depuis la v4.x, Fibaro nous fait bénéficier de la librairie net.httpClient dans une scène et cette librairie nous permet de récupérer des données via HTTPS, ce qui auparavant n'était pas possible depuis notre HC2. Alors vu que nous avons, aujourd'hui, tout le nécessaire pour attaquer notre Netatmo directement depuis notre HC2, pourquoi s'en priver
Les données recueillies par votre Netatmo sont mis à diposition via des API que vous pouvez interroger quand bon vous semble à la seul condition d'avoir un compte Développeur Netatmo (ne vous inquiéter pas, vous n'aurez pas beson de développer, ni de répondre à des questions étranges).
Pour vous inscrire, c'est donc ici : https://auth.netatmo.com/fr-FR/access/signup
Suite à votre enregistrement, vous allez obtenir :
un id (exemple : 45b1931d19665803515b571c)
un code secret (exemple : lyRkJXZLIM8xShACtmQjsCQV4U3djL08Zq1hUStbUJ4)
Ces informations + votre login et mot de passe vont permettre d'accéder à vos informations.
Voici donc le script nécessaire, à vous de l'importer dans une nouvelle scène et de modifier les 4 premières lignes.
local n_client_id = "45b1931d19665803515b571c"
local n_client_secret = "lyRkJXZLIM8xShACtmQjsCQV4U3djL08Zq1hUStbUJ4"
local n_username = "______________@_____.com"
local n_password = "password"
local hc2_module_virtuel = 139 -- le module virtuel "Pluie"
local debug = true -- affiche ou non les message dans la console
local long_lat_adjust = 0.1 -- ajustement de la distance pour trouvé un pluviomètre
local version = 2.0
-- ------------------------------------------------------------------------
-- NE PAS TOUCHER
-- ------------------------------------------------------------------------
local force_use_rain_public = false
local loc = api.get("/settings/location")
local lat_ne = loc.latitude + long_lat_adjust
local lon_ne = loc.longitude + long_lat_adjust
local lat_sw = loc.latitude - long_lat_adjust
local lon_sw = loc.longitude - long_lat_adjust
local token = ""
local int_id = ""
local ext_id = ""
local ext_bat = 0
local rain_id = ""
local rain_bat = 0
local temperature_interieure = -1000
local temperature_exterieure = -1000
local co2 = -1000
local humidite_interne = -1000
local humidite_externe = -1000
local pression = -1000
local bruit = -1000
local rains = {hour = -1000, day = -1000, week = -1000, month = -1000}
-- ------------------------------------------------------------------------
-- Exécuté après chaque requète HTTP
-- ------------------------------------------------------------------------
function afterHttpRequest()
if (temperature_interieure > -1000) then end
if (temperature_exterieure > -1000) then end
if (co2 > -1000) then end
if (humidite_interne > -1000) then end
if (humidite_externe > -1000) then end
if (pression > -1000) then end
if (bruit > -1000) then end
if (rains["hour"] > -1000) then
if (rains["hour"] == -1) then
fibaro:call(hc2_module_virtuel, "setProperty", "ui.lblHeure.value", "n/a")
else
fibaro:call(hc2_module_virtuel, "setProperty", "ui.lblHeure.value", " "..rains["hour"])
end
end
if (rains["day"] > -1000) then
if (rains["day"] == -1) then
fibaro:call(hc2_module_virtuel, "setProperty", "ui.lblJour.value", "n/a")
else
fibaro:call(hc2_module_virtuel, "setProperty", "ui.lblJour.value", " "..rains["day"])
end
end
if (rains["week"] > -1000) then
if (rains["week"] == -1) then
fibaro:call(hc2_module_virtuel, "setProperty", "ui.lblSemaine.value", "n/a")
else
fibaro:call(hc2_module_virtuel, "setProperty", "ui.lblSemaine.value", " "..rains["week"])
end
end
if (rains["month"] > -1000) then
if (rains["month"] == -1) then
fibaro:call(hc2_module_virtuel, "setProperty", "ui.lblMois.value", "n/a")
else
fibaro:call(hc2_module_virtuel, "setProperty", "ui.lblMois.value", " "..rains["month"])
end
end
end
-- ------------------------------------------------------------------------
-- Affichage dans la console
-- ------------------------------------------------------------------------
function log(message, force)
force = force or false
if (debug or force) then
print(__convertToString(message))
end
end
-- ------------------------------------------------------------------------
-- Retourne le niveau de batterie en pourcent
-- ------------------------------------------------------------------------
function calcBat(bat, ext)
local max = 6000
local min = 4200
if (ext) then
max = 6000
min = 3600
end
if (bat > max) then bat = max end
return math.floor(bat * 100 / max)
end
-- ------------------------------------------------------------------------
-- Arrondi
-- ------------------------------------------------------------------------
local function roundToNthDecimal(num, n)
local mult = 10^(n or 0)
return math.floor(num * mult + 0.5) / mult
end
-- ------------------------------------------------------------------------
-- Interrogation de l'API
-- ------------------------------------------------------------------------
function getResponseData(url, body, func)
local http = net.HTTPClient()
http:request(url, {
options = {
method = 'POST',
headers = {
["Content-Type"] = "application/x-www-form-urlencoded;charset=UTF-8"
},
data = body
},
success = function(response)
func(json.decode(response.data))
afterHttpRequest()
end,
error = function(response) log(" ERROR !!! " .. url, true) end,
})
end
-- ------------------------------------------------------------------------
-- Mesures de l'unité interne
-- ------------------------------------------------------------------------
function getMesuresInt()
getResponseData("https://api.netatmo.net/api/getmeasure","access_token="..token.."&device_id="..int_id.."&scale=max&type=Temperature,CO2,Humidity,Pressure,Noise&date_end=last",
function(data)
log("----------========== Module intérieur ==========----------")
temperature_interieure = data.body[1].value[1][1]
co2 = data.body[1].value[1][2]
humidite_interne = data.body[1].value[1][3]
pression = data.body[1].value[1][4]
bruit = data.body[1].value[1][5]
log("temperature_interieure = " .. temperature_interieure)
log("co2 = " .. co2)
log("humidite_interne = " .. humidite_interne)
log("pression = " .. pression)
log("bruit = " .. bruit)
end
)
end
-- ------------------------------------------------------------------------
-- Mesure de l'unité externe
-- ------------------------------------------------------------------------
function getMesuresExt()
getResponseData("https://api.netatmo.net/api/getmeasure","access_token="..token.."&device_id="..int_id.."&module_id="..ext_id.."&scale=max&type=Temperature,Humidity&date_end=last",
function(data)
log("----------========== Module extérieur ==========----------")
temperature_exterieure = data.body[1].value[1][1]
humidite_externe = data.body[1].value[1][2]
log("temperature_exterieure = " .. temperature_exterieure)
log("humidite_externe = " .. humidite_externe)
end
)
end
-- ------------------------------------------------------------------------
-- Obtention des informations sur un pluviomètre proche
-- ------------------------------------------------------------------------
function getRainNear()
getResponseData("https://api.netatmo.net/api/getpublicdata","access_token="..token .. "&lat_ne="..lat_ne.."&lon_ne="..lon_ne.."&lat_sw="..lat_sw.."&lon_sw="..lon_sw,
function(data)
--log(data)
rains["week"] = -1
rains["month"] = -1
rains["hour"] = -1
rains["day"] = -1
log("----------========== D e v i c e s =========----------")
for _, v in pairs(data.body) do
for l, w in pairs(v.measures) do
if (type(w.rain_24h) ~= "nil") then
rains["day"] = w.rain_24h
rains["hour"] = w.rain_60min
end
end
end
if (rains["day"] == -1000) then
log("Impossible de trouver un pluviomètre à proximité, augmentez [long_lat_adjust]", true)
else
log("Pluie jour : " .. rains["day"])
log("Pluie heure : " .. rains["hour"])
end
end
)
end
-- ------------------------------------------------------------------------
-- Mesure du détecteur de pluie historique
-- ------------------------------------------------------------------------
function getMesuresRain(duree, variable)
local now = os.time();
getResponseData("https://api.netatmo.net/api/getmeasure","access_token="..token.."&device_id="..int_id.."&module_id="..rain_id.."&scale=1hour&type=sum_rain&real_time=true&date_begin="..os.date("!%c", (now - duree)),
function(data)
log("----------========== Pluie histo ==========----------")
local cumul = 0
for k, v in pairs(data.body) do
for l, w in pairs(v.value) do
cumul = cumul + w[1]
end
end
cumul = roundToNthDecimal(cumul, 2)
rains[variable] = cumul
log("rain["..variable.."] = " .. rains[variable])
end
)
end
-- ------------------------------------------------------------------------
-- Obtention des informations sur les devices
-- ------------------------------------------------------------------------
function getDevices()
getResponseData("https://api.netatmo.net/api/devicelist","access_token="..token,
function(data)
log("----------========== D e v i c e s =========----------")
for _, v in pairs(data.body.modules) do
if (v.data_type[1] == "Rain") then
rain_id = v._id
rain_bat = calcBat(v.battery_vp, true)
else
ext_id = v._id
ext_bat = calcBat(v.battery_vp, true)
end
end
int_id = data.body.devices[1]._id
getMesuresInt()
getMesuresExt()
if (rain_id ~= "" and not force_use_rain_public) then
getMesuresRain(60 * 60, "hour")
getMesuresRain(60 * 60 * 24, "day")
getMesuresRain(60 * 60 * 24 * 7, "week")
getMesuresRain(60 * 60 * 24 * 30, "month")
else
getRainNear()
end
end
)
end
-- ------------------------------------------------------------------------
-- Authentification
-- ------------------------------------------------------------------------
function auth(nextFunction)
local request_body = "grant_type=password&client_id=" .. n_client_id .. "&client_secret=" .. n_client_secret .. "&username=" .. n_username .. "&password=" .. n_password .. "&scope=read_station"
getResponseData("https://api.netatmo.net/oauth2/token", request_body,
function(data)
token = data.access_token
log(token)
nextFunction()
end
)
end
auth(getDevices)
log("Last request : " .. os.date("%x - %X"), true)
si vous avez l'âme d'un développeur ou d'un aventurier, la méthode à modifier est afterHttpRequest() sinon, rendez-vous au post suivant.
P.S. Merci à @PITP2 pour son support.
Edit : nouvelle version du script. Si ce dernier détecte que vous n'avez pas de pluviomètre, il va rechercher un pluviomètre à proximité de chez vous (uniquement les relevés de la dernière heure et jour). La distance de recherche peux être adaptée en ajustant la variable long_lat_adjust (0.1 par défaut). Il s'agit du cercle de recherche en latitude/longitude autour de chez vous.