Bonjour,
Le but de ce tuto sera de faire une passerelle pour les données de la netatmo vers emoncms.
J'en ai profité pour améliorer le script php classique d'interface entre la netatmo et la HC2
les versions disponibles ot du mal à gérer les installations netatmo avec plusieurs modules.
Ici j'ai cherché à améliorer les choses et ça fonctionne même lorsque l'on a plusieurs master device et plusieurs stations additionnelles.
En effet, savoir l'ordre des modules renvoyé par netatmo dans ces conditions est un peur hard.
J'ai ajouté plusieures pages de résultats au script PHP: une avec un json viewer intégré et un qui retourne le json complet.
J'ai aussi optimisé pour minimiser le nombre de requêtes faites à netatmo, histoire de ne pas se faire "jeter"
voici déjà la présentation de la plateforme emon CMS très puissante que j'utilise depuis plus d'un an:
http://emoncms.org/site/home
http://emoncms.org/site/docs/visualisations
Personellement je l'utilise pour remonter mes graphiques de valeurs diverses de ma HC2
- températures
- consommations eau, gaz, elec
- paramètres de ma VMC (T° Vitesse, rendement etc.)
J'ai partagé mon script avec un ami et comme il était enchanté, je fais l'effort de le mettre ici aussi ;-)
En effet, il suffit de configurer les variables dans le VD, créer un répertoire /netatmo dans www ou web ou html, y mettre le PHP et le répertoire jsoneditor et c'est parti, les données seront remontées automatiquement à emonCMS !
Voici déjà le script côté HC2:
Je l'ai mis derrière un bouton, car dans un main loop, une corruption json quelquepart et c'est tout qui plante.
Ce bouton dont être cliqué via GEA ou autre scheduler toutes les 10 minutes.
Voici le Virtual Device tout fait:
Grosse mise à jour à ce post: http://www.domotique-fibaro.fr/index.php/topic/3929-yagda-yet-another-graphic-data-analyser-netatmo-vmc-emoncms-json-viewer/#entry63238
Netatmo_V2.vfib
Attention, dans ce post ne figure que les scripts de la première version, voir plus loin dans le fil pour les versions suivantes !
-----------------------------------------------------------------------------------------
-- YAGDA - yet another graphic data analyser V2.01
-- Retreive Netatmo values for more than 2 modules, compute CO2 and push to EmonCMS
-- Sebastien Jauquet
-- Février 2015
-- Thanks to cedriclocqueneux, krikroff, i-magin and all contibutors to the netatmo code
-----------------------------------------------------------------------------------------
-- Instructions:
-- Create an free emoncms.org account
-- Retrieve your Write API Key from it
-- Create a Global variable (undefined) -> CO2_Max_Value to store the max value of CO2 of the house - if you dont need this, set CO2 to false (default: 0)
-- Install my netatmo.php in your webserver and write his address in the ip Address of this module
-- for each value you want to be pushed to emoncms, modify the section -- Push To EMONCMS -- below
-- Create a block scene or use gea to click this button each 10 minutes (to avoid rejection from the api of Netatmo)
local EmonCMS_Prefix = "NETATMO_" -- prefix of the id of the inpus to be created in emoncms (convenient for testing to not alter current feeds)
local PushToEmonCMS = true -- true = push to emoncms - false = do not push
local selfId = fibaro:getSelfId();
local thismodule=fibaro:getSelfId()
local domaine = fibaro:get(selfId, 'IPAddress')
local PushItem
local CO2_Max_Value_Local = 0 -- if you dont need this, set CO2 to false (default: 0)
local emoncms = Net.FHttp("emoncms.org",80)
local emoncms_api_key = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" -- your EMONCMS WRITE api Key
EmonCMS = {};
if (temperature_exterieure==nil) then temperature_exterieure = ""; end
if (humidite_exterieure==nil) then humidite_exterieure = ""; end
if (temperature_interieure==nil) then temperature_interieure = ""; end
if (humidite_interieure==nil) then humidite_interieure = ""; end
if (co2==nil) then co2 = ""; end
if (pression==nil) then pression = ""; end
if (bruit==nil) then bruit = ""; end
if (temperature_int_mod2==nil) then temperature_int_mod2 = ""; end
if (humidite_int_mod2==nil) then humidite_int_mod2 = ""; end
if (co2_mod2==nil) then co2_mod2 = ""; end
if (temperature_int_mod3==nil) then temperature_int_mod3 = ""; end
if (humidite_int_mod3==nil) then humidite_int_mod3 = ""; end
if (co2_mod3==nil) then co2_mod3 = ""; end
if (temperature_int_mod4==nil) then temperature_int_mod4 = ""; end
if (humidite_int_mod4==nil) then humidite_int_mod4 = ""; end
if (co2_mod4==nil) then co2_mod4 = ""; end
if(refreshUI==nil) then -- Loads in memory only the first occurence
function refreshUI(ext, bruit, titre, tempmod, co2mod, humidmod, lastupdate, laststatus)
fibaro:call(selfId,"setProperty","ui.ext.value",ext);
fibaro:call(selfId,"setProperty","ui.bruit.value",bruit);
fibaro:call(selfId,"setProperty","ui.titre.value",titre);
fibaro:call(selfId,"setProperty","ui.tempmod.value",tempmod);
fibaro:call(selfId,"setProperty","ui.co2mod.value",co2mod);
fibaro:call(selfId,"setProperty","ui.humidmod.value",humidmod);
fibaro:call(selfId,"setProperty","ui.lastupdate.value",lastupdate);
fibaro:call(selfId,"setProperty","ui.laststatus.value",laststatus);
end;
end
if(getExt==nil) then -- Loads in memory only the first occurence
function getExt(retry)
retry = retry or 0
-- Setting up the connection data
local FHTE = Net.FHttp(domaine, 80);
-- Netatmo extérieur
local response = FHTE:GET("/netatmo/netatmo.php?parameter=ext");
-- decoding json string to table
if (response~= nil) then
local result = nil;
result = json.decode(response);
if (result ~= nil) then
-- prevent: attempt to index field 'body' (a nil value)
if (result.body ~= nil) then
temperature_exterieure = result.body[1].value[1][1] or "n.c";
humidite_exterieure =result.body[1].value[1][2] or "n.c";
-- variable globale pour info sms
local msg = "Température extérieure : "..temperature_exterieure.."°C";
fibaro:setGlobal("tempext", msg);
return true;
else
fibaro:debug("Netatmo EXT: erreur le " .. os.date());
if (result.error ~= nil) then
fibaro:debug("error code: "..result.error.code..", message: "..result.error.message);
end
end
else
fibaro:debug("Netatmo EXT: erreur decodage json le " .. os.date());
end
else
fibaro:debug("Netatmo EXT:la reponse est null !");
end
if ((retry or 5)< 5) then
fibaro:debug("Retry #"..retry.."process, please wait...");
fibaro:sleep(5000);
return getInt(tonumber(retry+1));
else
return false;
end
end;
end
if(getInt==nil) then -- Loads in memory only the first occurence
function getInt(retry)
retry = retry or 0;
-- Setting up the connection data
local FHTE = Net.FHttp(domaine, 80);
-- Netatmo intérieur
local response = FHTE:GET("/netatmo/netatmo.php?parameter=int");
-- decoding json string to table
if (response~= nil) then
local result = nil;
result = json.decode(response);
if (result ~= nil) then
-- prevent: attempt to index field 'body' (a nil value)
if (result.body ~= nil) then
temperature_interieure = result.body[1].value[1][1] or "n.c";
humidite_interieure = result.body[1].value[1][3] or "n.c";
co2 = result.body[1].value[1][2] or "n.c";
pression = result.body[1].value[1][4] or "n.c";
bruit = result.body[1].value[1][5] or "n.c";
-- variable globale pour info sms
fibaro:setGlobal("tempint", "Température intérieure : "..temperature_interieure.."°C");
return true;
else
fibaro:debug("Netatmo INT: erreur le " .. os.date());
if (result.error ~= nil) then
fibaro:debug("error code: "..result.error.code..", message: "..result.error.message);
end
end
else
fibaro:debug("Netatmo INT: erreur decodage json le " .. os.date());
end
else
fibaro:debug("Netatmo INT:la reponse est null !");
end
if ((retry or 5)< 5) then
fibaro:debug("Retry #"..retry.."process, please wait...");
fibaro:sleep(5000);
return getExt(tonumber(retry+1));
else
return false;
end
end;
end
if(getMod2==nil) then -- Loads in memory only the first occurence
function getMod2(retry)
retry = retry or 0;
-- Setting up the connection data
local FHTE = Net.FHttp(domaine, 80);
-- Netatmo intérieur
local response = FHTE:GET("/netatmo/netatmo.php?parameter=mod2");
-- decoding json string to table
if (response~= nil) then
local result = nil;
result = json.decode(response);
if (result ~= nil) then
-- prevent: attempt to index field 'body' (a nil value)
if (result.body ~= nil) then
temperature_int_mod2 = result.body[1].value[1][1] or "n.c";
humidite_int_mod2 = result.body[1].value[1][2] or "n.c";
co2_mod2 = result.body[1].value[1][3] or "n.c";
-- variable globale pour info sms
-- fibaro:setGlobal("tempint", "Température intérieure : "..temperature_interieure.."°C");
return true;
else
fibaro:debug("Netatmo INT_mod2: erreur le " .. os.date());
if (result.error ~= nil) then
fibaro:debug("error code: "..result.error.code..", message: "..result.error.message);
end
end
else
fibaro:debug("Netatmo INT_mod2: erreur decodage json le " .. os.date());
end
else
fibaro:debug("Netatmo INT_mod2:la reponse est null !");
end
if ((retry or 5)< 5) then
fibaro:debug("Retry #"..retry.."process, please wait...");
fibaro:sleep(5000);
return getExt(tonumber(retry+1));
else
return false;
end
end;
end
if(getMod3==nil) then -- Loads in memory only the first occurence
function getMod3(retry)
retry = retry or 0;
-- Setting up the connection data
local FHTE = Net.FHttp(domaine, 80);
-- Netatmo intérieur
local response = FHTE:GET("/netatmo/netatmo.php?parameter=mod3");
-- decoding json string to table
if (response~= nil) then
local result = nil;
result = json.decode(response);
if (result ~= nil) then
-- prevent: attempt to index field 'body' (a nil value)
if (result.body ~= nil) then
temperature_int_mod3 = result.body[1].value[1][1] or "n.c";
humidite_int_mod3 = result.body[1].value[1][2] or "n.c";
co2_mod3 = result.body[1].value[1][3] or "n.c";
-- variable globale pour info sms
-- fibaro:setGlobal("tempint", "Température intérieure : "..temperature_interieure.."°C");
return true;
else
fibaro:debug("Netatmo INT_mod3: erreur le " .. os.date());
if (result.error ~= nil) then
fibaro:debug("error code: "..result.error.code..", message: "..result.error.message);
end
end
else
fibaro:debug("Netatmo INT_mod3: erreur decodage json le " .. os.date());
end
else
fibaro:debug("Netatmo INT_mod3:la reponse est null !");
end
if ((retry or 5)< 5) then
fibaro:debug("Retry #"..retry.."process, please wait...");
fibaro:sleep(5000);
return getExt(tonumber(retry+1));
else
return false;
end
end;
end
if(getMod4==nil) then -- Loads in memory only the first occurence
function getMod4(retry)
retry = retry or 0;
-- Setting up the connection data
local FHTE = Net.FHttp(domaine, 80);
-- Netatmo intérieur
local response = FHTE:GET("/netatmo/netatmo.php?parameter=mod4");
-- decoding json string to table
if (response~= nil) then
local result = nil;
result = json.decode(response);
if (result ~= nil) then
-- prevent: attempt to index field 'body' (a nil value)
if (result.body ~= nil) then
temperature_int_mod4 = result.body[1].value[1][1] or "n.c";
humidite_int_mod4 = result.body[1].value[1][2] or "n.c";
co2_mod4 = result.body[1].value[1][3] or "n.c";
-- variable globale pour info sms
-- fibaro:setGlobal("tempint", "Température intérieure : "..temperature_interieure.."°C");
return true;
else
fibaro:debug("Netatmo INT_mod4: erreur le " .. os.date());
if (result.error ~= nil) then
fibaro:debug("error code: "..result.error.code..", message: "..result.error.message);
end
end
else
fibaro:debug("Netatmo INT_mod4: erreur decodage json le " .. os.date());
end
else
fibaro:debug("Netatmo INT_mod4:la reponse est null !");
end
if ((retry or 5)< 5) then
fibaro:debug("Retry #"..retry.."process, please wait...");
fibaro:sleep(5000);
return getExt(tonumber(retry+1));
else
return false;
end
end;
end
function EmonCMS:Push(payloademon)
payloademon = "/input/post.json?json={" .. EmonCMS_Prefix .. payloademon .. "}&apikey=" .. emoncms_api_key
response, status, errorCode = emoncms:GET(payloademon);
fibaro:debug("Payload: " .. payloademon) ;
fibaro:debug("response: " .. response .. " Status: " .. status .. " errorcode: " .. errorCode) ;
fibaro:sleep(500);
end
local function main()
-- retrieve values from netatmo.php
local resInt, resExt, resMod2, resMod3, resMod4 = false, false, false, false, false;
local status, err = pcall(function () resInt = getInt(); end);
fibaro:debug("Récupération des données intérieures: " .. tostring(resInt));
if (status == false) then
fibaro:debug("err: "..tostring(err or 'n.c'));
end
local status, err = pcall(function () resExt = getExt(); end);
fibaro:debug("Récupération des données extérieures : " .. tostring(resExt));
if (status == false) then
fibaro:debug("err: "..tostring(err or 'n.c'));
end
local status, err = pcall(function () resMod2 = getMod2(); end);
fibaro:debug("Récupération des données intérieures Mod2: " .. tostring(resMod2));
if (status == false) then
fibaro:debug("err: "..tostring(err or 'n.c'));
end
local status, err = pcall(function () resMod3 = getMod3(); end);
fibaro:debug("Récupération des données intérieures Mod3: " .. tostring(resMod3));
if (status == false) then
fibaro:debug("err: "..tostring(err or 'n.c'));
end
local status, err = pcall(function () resMod4 = getMod4(); end);
fibaro:debug("Récupération des données intérieures Mod4: " .. tostring(resMod4));
if (status == false) then
fibaro:debug("err: "..tostring(err or 'n.c'));
end
refreshUI(
"Ext: "..temperature_exterieure.." °C - "..humidite_exterieure.." % - "..pression.." mbar",
"Bruit Rez: "..bruit.." dB",
"Rez - Emilien - Thomas - Parents",
temperature_interieure.." - "..temperature_int_mod2.." - "..temperature_int_mod3.." - "..temperature_int_mod4.." °C ",
co2.." - "..co2_mod2.." - "..co2_mod3.." - "..co2_mod4.." ppm",
humidite_interieure.." - "..humidite_int_mod2.." - "..humidite_int_mod3.." - "..humidite_int_mod4.." % ",
os.date("%H:%M"),
tostring(resInt).." "..tostring(resExt).." "..tostring(resMod2).." "..tostring(resMod3).." "..tostring(resMod4)
);
-- Push To EMONCMS --
if PushToEmonCMS == true then
payloademon = "temperature_exterieure:"..temperature_exterieure
EmonCMS:Push(payloademon);
payloademon = "humidite_exterieure:".. humidite_exterieure
EmonCMS:Push(payloademon);
payloademon = "pression:".. pression
EmonCMS:Push(payloademon);
payloademon = "bruit:".. bruit
EmonCMS:Push(payloademon);
payloademon = "temperature_interieure_Rez:".. temperature_interieure
EmonCMS:Push(payloademon);
payloademon = "temperature_int_mod2_Emilien:".. temperature_int_mod2
EmonCMS:Push(payloademon);
payloademon = "temperature_int_mod3_Thomas:".. temperature_int_mod3
EmonCMS:Push(payloademon);
payloademon = "temperature_int_mod4_Parents:".. temperature_int_mod4
EmonCMS:Push(payloademon);
payloademon = "humidite_interieure_Rez:".. humidite_interieure
EmonCMS:Push(payloademon);
payloademon = "humidite_int_mod2_Emilien:".. humidite_int_mod2
EmonCMS:Push(payloademon);
payloademon = "humidite_int_mod3_Thomas:".. humidite_int_mod3
EmonCMS:Push(payloademon);
payloademon = "humidite_int_mod4_Parents:".. humidite_int_mod4
EmonCMS:Push(payloademon);
payloademon = "co2_Rez:".. co2
EmonCMS:Push(payloademon);
payloademon = "co2_mod2_Emilien:".. co2_mod2
EmonCMS:Push(payloademon);
payloademon = "co2_mod3_Thomas:".. co2_mod3
EmonCMS:Push(payloademon);
payloademon = "co2_mod4_Parents:".. co2_mod4
EmonCMS:Push(payloademon);
end
-- Compute Value MAX CO2 Maison (For VMC Speed VD)
if CO2_Max_Value_Local == false then
fibaro:debug("not calculating nor storing CO2 Max Value")
else
CO2_Max_Value_Local = co2
if CO2_Max_Value_Local < co2_mod2 then CO2_Max_Value_Local = co2_mod2 end
if CO2_Max_Value_Local < co2_mod3 then CO2_Max_Value_Local = co2_mod3 end
if CO2_Max_Value_Local < co2_mod4 then CO2_Max_Value_Local = co2_mod4 end
fibaro:setGlobal("CO2_Max_Value", CO2_Max_Value_Local )
fibaro:debug("CO2_Max_Value: ".. CO2_Max_Value_Local )
end
end
main();