This forum uses cookies
This forum makes use of cookies to store your login information if you are registered, and your last visit if you are not. Cookies are small text documents stored on your computer; the cookies set by this forum can only be used on this website and pose no security risk. Cookies on this forum also track the specific topics you have read and when you last read them. Please confirm that you accept these cookies being set.

Netatmo
#1
Updated version of Netatmo script with HTTPS (http is not allowed by netatmo anymore)

Task
How to get my Netatmo weather station readings into my KNX network using LogicMachine?

Things to prepare in advance Netatmo function
  • Add the following function in Common Functions or User Library
  • Fill in the script with client_idclient_secretusername and password
  • Rename object names with your own objects
  • Rename module names to match configuration in Netatmo

V2
Code:
require 'ltn12'
require 'socket.http'
json = require("json")
https = require 'ssl.https'

function refresh_netatmo()
 local netatmo_debug = true
 local client_id = "xxx"
 local client_secret = "xxx"
 local username = "xxx"
 local password = "xxx"
 local scope = "read_station"
 -- optional device_id
 local device_id = "xxx"
 local request_token_url = "https://api.netatmo.net/oauth2/token"
 local request_device_list = "https://api.netatmo.net/api/devicelist"
 local response_body = { }

 local export_data = {}

 if (netatmo_debug) then
   alert("netatmo start")
 end
 
 local request_body = "grant_type=password&client_id=" .. client_id .."&client_secret=" .. client_secret .. "&username=" .. username .. "&password=" .. password .. "&scope=" .. scope

 local body, code, hdrs, stat = https.request
 {
   url = request_token_url;
   method = "POST";
   headers =
   {
     ["Content-Type"] = "application/x-www-form-urlencoded";
     ["Content-Length"] = #request_body;
   };
   source = ltn12.source.string(request_body);
   sink = ltn12.sink.table(response_body);
 }

 if (code ~= 200) then
   alert("netatmo auth error : "..tostring(code)..","..tostring(body))
   return
 end

 local response_decode = json.decode(table.concat(response_body))
 local access_token = response_decode.access_token
 if (netatmo_debug) then
   alert("netatmo token %s",access_token)
 end


 -- request for all devices
 local request_body = "access_token=" .. access_token .. "&app_type=app_station"
 -- request to limit to only one device :
 -- local request_body = "access_token=" .. access_token .. "&app_type=app_station&device_id=" .. device_id
 
 local response_body = { }

 local body, code, hdrs, stat = https.request
 {
   url = request_device_list;
   method = "POST";
   headers =
   {
     ["Content-Type"] = "application/x-www-form-urlencoded";
     ["Content-Length"] = #request_body;
   };
   source = ltn12.source.string(request_body);
   sink = ltn12.sink.table(response_body);
 }

 if (code ~= 200) then
   alert("netatmo devicelist error : "..tostring(code)..","..tostring(body))
   return
 end

 local response_decode = json.decode(table.concat(response_body))

 -- Main module
 if (netatmo_debug) then
   alert("netatmo main module")
 end

 grp.write("netatmo temperature interieure",response_decode.body.devices[1].dashboard_data.Temperature,dt.float16)
 grp.write("netatmo humidite interieure",response_decode.body.devices[1].dashboard_data.Humidity,dt.scale)
 grp.write("netatmo pression",response_decode.body.devices[1].dashboard_data.Pressure,dt.uint16)
 grp.write("netatmo CO2",response_decode.body.devices[1].dashboard_data.CO2,dt.float16)
 grp.write("netatmo sonometre",response_decode.body.devices[1].dashboard_data.Noise,dt.uint8)
 grp.write("netatmo temperature interieure minimum",response_decode.body.devices[1].dashboard_data.min_temp,dt.float16)
 grp.write("netatmo temperature interieure maximum",response_decode.body.devices[1].dashboard_data.max_temp,dt.float16)
 grp.write("netatmo pression absolue",response_decode.body.devices[1].dashboard_data.AbsolutePressure,dt.uint16)

 grp.write("netatmo salon temperature",response_decode.body.devices[1].dashboard_data.Temperature,dt.float16)
 grp.write("netatmo salon humidite",response_decode.body.devices[1].dashboard_data.Humidity,dt.scale)
 grp.write("netatmo salon CO2",response_decode.body.devices[1].dashboard_data.CO2,dt.uint16)

 -- search for additional modules by name
 
 for index, value in ipairs(response_decode.body.modules) do
   if (netatmo_debug) then
     alert("netatmo module " .. tostring(index) .. ":" .. tostring(value.module_name))
   end
   if (value.module_name == "Pluviomètre") then
     if (netatmo_debug) then
       alert("netatmo module match pluviometre")
     end
     grp.write("netatmo pluviometre",value.dashboard_data.Rain,dt.float16)
     grp.write("netatmo pluviometre 1h",value.dashboard_data.sum_rain_1,dt.float16)
     grp.write("netatmo pluviometre 24h",value.dashboard_data.sum_rain_24,dt.float16)

   elseif (value.module_name == "Extérieur") then
     if (netatmo_debug) then
       alert("netatmo module match exterieur")
     end
     grp.write("netatmo temperature exterieure",value.dashboard_data.Temperature,dt.float16)
     grp.write("netatmo humidite exterieure",value.dashboard_data.Humidity,dt.float16)
     grp.write("netatmo temperature exterieure minimum",value.dashboard_data.min_temp,dt.float16)
     grp.write("netatmo temperature exterieure maximum",value.dashboard_data.max_temp,dt.float16)

   elseif (value.module_name == "Chambre") then
     if (netatmo_debug) then
       alert("netatmo module match Chambre")
     end
     grp.write("netatmo chambre temperature",value.dashboard_data.Temperature,dt.float16)
     grp.write("netatmo chambre CO2",value.dashboard_data.CO2,dt.float16)
     grp.write("netatmo chambre humidite",value.dashboard_data.Humidity,dt.scale)
   
   elseif (value.module_name == "Bureau") then
     if (netatmo_debug) then
       alert("netatmo module match Bureau")
     end
     grp.write("netatmo bureau temperature",value.dashboard_data.Temperature,dt.float16)
     grp.write("netatmo bureau CO2",value.dashboard_data.CO2,dt.float16)
     grp.write("netatmo bureau humidite",value.dashboard_data.Humidity,dt.scale)
         
   elseif (value.module_name == "Studio") then
     if (netatmo_debug) then
       alert("netatmo module match Studio")
     end
     grp.write("netatmo studio temperature",value.dashboard_data.Temperature,dt.float16)
     grp.write("netatmo studio CO2",value.dashboard_data.CO2,dt.float16)
     grp.write("netatmo studio humidite",value.dashboard_data.Humidity,dt.scale)
   
   end
 
 end

 if (netatmo_debug) then
   alert("netatmo end")
 end
 
 
end


v1
Code:
require 'ltn12'
require 'socket.http'
json = require("json")
https = require 'ssl.https'

function refresh_netatmo()
 local netatmo_debug = false
 local client_id = ""
 local client_secret = ""
 local username = ""
 local password = ""
 local scope = "read_station"
 -- optional
 --local device_id = ""
 local request_token_url = "https://api.netatmo.net/oauth2/token"
 local request_device_list = "https://api.netatmo.net/api/devicelist"
 local response_body = { }

 if (netatmo_debug) then
   alert("netatmo start")
 end
 
 local request_body = "grant_type=password&client_id=" .. client_id .."&client_secret=" .. client_secret .. "&username=" .. username .. "&password=" .. password .. "&scope=" .. scope

 local body, code, hdrs, stat = https.request
 {
   url = request_token_url;
   method = "POST";
   headers =
   {
     ["Content-Type"] = "application/x-www-form-urlencoded";
     ["Content-Length"] = #request_body;
   };
   source = ltn12.source.string(request_body);
   sink = ltn12.sink.table(response_body);
 }

 if (code ~= 200) then
   alert("netatmo auth error")
    error("netatmo auth error : "..tostring(code)..","..tostring(body))
   return
 end

 local response_decode = json.decode(table.concat(response_body))
 local access_token = response_decode.access_token
 if (netatmo_debug) then
   alert("netatmo token %s",access_token)
 end

 
 local request_body = "access_token=" .. access_token .. "&app_type=app_station"
 -- to limit to only one device :
--  local request_body = "access_token=" .. access_token .. "&app_type=app_station&device_id=" .. device_id
 
 local response_body = { }

 local body, code, hdrs, stat = https.request
 {
   url = request_device_list;
   method = "POST";
   headers =
   {
     ["Content-Type"] = "application/x-www-form-urlencoded";
     ["Content-Length"] = #request_body;
   };
   source = ltn12.source.string(request_body);
   sink = ltn12.sink.table(response_body);
 }

 if (code ~= 200) then
   error("netatmo devicelist error")
   return
 end

 local response_decode = json.decode(table.concat(response_body))

 -- Module int
 if (netatmo_debug) then
   alert("netatmo device 1")
 end

 grp.write("Netatmo Température intérieure",response_decode.body.devices[1].dashboard_data.Temperature,dt.float16)
 grp.write("Netatmo Humidité intérieure",response_decode.body.devices[1].dashboard_data.Humidity,dt.scale)
 grp.write("Netatmo Pression",response_decode.body.devices[1].dashboard_data.Pressure,dt.uint16)
 grp.write("Netatmo CO2",response_decode.body.devices[1].dashboard_data.CO2,dt.uint16)
 grp.write("Netatmo Sonomètre",response_decode.body.devices[1].dashboard_data.Noise,dt.uint8)
 grp.write("Netatmo Température intérieure minimum",response_decode.body.devices[1].dashboard_data.min_temp,dt.float16)
 grp.write("Netatmo Température intérieure maximum",response_decode.body.devices[1].dashboard_data.max_temp,dt.float16)
 grp.write("Netatmo Pression absolue",response_decode.body.devices[1].dashboard_data.AbsolutePressure,dt.uint16)
 
 -- Module ext
 if (netatmo_debug) then
   alert("netatmo module 1")
 end

 grp.write("Netatmo Température extérieure",response_decode.body.modules[1].dashboard_data.Temperature,dt.float16)
 grp.write("Netatmo Humidité extérieure",response_decode.body.modules[1].dashboard_data.Humidity,dt.float16)
 grp.write("Netatmo Température extérieure minimum",response_decode.body.modules[1].dashboard_data.min_temp,dt.float16)
 grp.write("Netatmo Température extérieure maximum",response_decode.body.modules[1].dashboard_data.max_temp,dt.float16)
 
 -- Module Pluvio
 if (netatmo_debug) then
   alert("netatmo module 2")
 end  
 
 grp.write("Netatmo Pluviomètre",response_decode.body.modules[2].dashboard_data.Rain,dt.float16)
 grp.write("Netatmo Pluviomètre 1h",response_decode.body.modules[2].dashboard_data.sum_rain_1,dt.float16)
 grp.write("Netatmo Pluviomètre 24h",response_decode.body.modules[2].dashboard_data.sum_rain_24,dt.float16)

 
 if (netatmo_debug) then
   alert("netatmo end")
 end
 
end

Use the function in your programs
Either in Event-based, Scheduled or Resident script run the function by command refresh_netatmo().

example : a scheduled script that run every minute with the content :

Code:
refresh_netatmo()


Matthieu
Reply
#2
(13.07.2015, 21:43)Matt Wrote: Updated version of Netatmo script with HTTPS (http is not allowed by netatmo anymore)

Code:
require 'ltn12'
require 'socket.http'
json = require("json")
https = require 'ssl.https'

function refresh_netatmo()
 local netatmo_debug = false
 local client_id = ""
 local client_secret = ""
 local username = ""
 local password = ""
 local scope = "read_station"
 -- optional
 --local device_id = ""
 local request_token_url = "https://api.netatmo.net/oauth2/token"
 local request_device_list = "https://api.netatmo.net/api/devicelist"
 local response_body = { }

 if (netatmo_debug) then
   alert("netatmo start")
 end
 
 local request_body = "grant_type=password&client_id=" .. client_id .."&client_secret=" .. client_secret .. "&username=" .. username .. "&password=" .. password .. "&scope=" .. scope

 local body, code, hdrs, stat = https.request
 {
   url = request_token_url;
   method = "POST";
   headers =
   {
     ["Content-Type"] = "application/x-www-form-urlencoded";
     ["Content-Length"] = #request_body;
   };
   source = ltn12.source.string(request_body);
   sink = ltn12.sink.table(response_body);
 }

 if (code ~= 200) then
   alert("netatmo auth error")
    error("netatmo auth error : "..tostring(code)..","..tostring(body))
   return
 end

 local response_decode = json.decode(table.concat(response_body))
 local access_token = response_decode.access_token
 if (netatmo_debug) then
   alert("netatmo token %s",access_token)
 end

 
 local request_body = "access_token=" .. access_token .. "&app_type=app_station"
 -- to limit to only one device :
--  local request_body = "access_token=" .. access_token .. "&app_type=app_station&device_id=" .. device_id
 
 local response_body = { }

 local body, code, hdrs, stat = https.request
 {
   url = request_device_list;
   method = "POST";
   headers =
   {
     ["Content-Type"] = "application/x-www-form-urlencoded";
     ["Content-Length"] = #request_body;
   };
   source = ltn12.source.string(request_body);
   sink = ltn12.sink.table(response_body);
 }

 if (code ~= 200) then
   error("netatmo devicelist error")
   return
 end

 local response_decode = json.decode(table.concat(response_body))

 -- Module int
 if (netatmo_debug) then
   alert("netatmo device 1")
 end

 grp.write("Netatmo Température intérieure",response_decode.body.devices[1].dashboard_data.Temperature,dt.float16)
 grp.write("Netatmo Humidité intérieure",response_decode.body.devices[1].dashboard_data.Humidity,dt.scale)
 grp.write("Netatmo Pression",response_decode.body.devices[1].dashboard_data.Pressure,dt.uint16)
 grp.write("Netatmo CO2",response_decode.body.devices[1].dashboard_data.CO2,dt.uint16)
 grp.write("Netatmo Sonomètre",response_decode.body.devices[1].dashboard_data.Noise,dt.uint8)
 grp.write("Netatmo Température intérieure minimum",response_decode.body.devices[1].dashboard_data.min_temp,dt.float16)
 grp.write("Netatmo Température intérieure maximum",response_decode.body.devices[1].dashboard_data.max_temp,dt.float16)
 grp.write("Netatmo Pression absolue",response_decode.body.devices[1].dashboard_data.AbsolutePressure,dt.uint16)
 
 -- Module ext
 if (netatmo_debug) then
   alert("netatmo module 1")
 end

 grp.write("Netatmo Température extérieure",response_decode.body.modules[1].dashboard_data.Temperature,dt.float16)
 grp.write("Netatmo Humidité extérieure",response_decode.body.modules[1].dashboard_data.Humidity,dt.float16)
 grp.write("Netatmo Température extérieure minimum",response_decode.body.modules[1].dashboard_data.min_temp,dt.float16)
 grp.write("Netatmo Température extérieure maximum",response_decode.body.modules[1].dashboard_data.max_temp,dt.float16)
 
 -- Module Pluvio
 if (netatmo_debug) then
   alert("netatmo module 2")
 end  
 
 grp.write("Netatmo Pluviomètre",response_decode.body.modules[2].dashboard_data.Rain,dt.float16)
 grp.write("Netatmo Pluviomètre 1h",response_decode.body.modules[2].dashboard_data.sum_rain_1,dt.float16)
 grp.write("Netatmo Pluviomètre 24h",response_decode.body.modules[2].dashboard_data.sum_rain_24,dt.float16)

 
 if (netatmo_debug) then
   alert("netatmo end")
 end
 
end

Matthieu

Thx Matt
Reply
#3
Can i fill my email and password from the http://dev.netatmo.com website to the local username and password variables?
Reply
#4
(04.01.2016, 15:24)gjniewenhuijse Wrote: Can i fill my email and password from the http://dev.netatmo.com website to the local username and password variables?

Hi,

email and password are required but not enough.
You need to create your application (Create an app, the name doesn't matter) to get also a client ID and client Secret.
You need to input the 4 items in the code :
- user (email)
- password
- client ID
- client Secret

Best regards,
Matt
Reply
#5
How to get the outdoor air quality value with the API?
See attached image for the requested value.

Attached Files Thumbnail(s)
   
Reply
#6
(11.01.2016, 14:59)gjniewenhuijse Wrote: How to get the outdoor air quality value with the API?
See attached image for the requested value.

I am not sure you can do that, it's not something netatmo calcule, it's value from a third party.
Please share if you find a way to get it, I will update the code.
Reply
#7
I have to restart my netatmo Resident script (60 seconds) sometimes a week, else i didn't receive any values. No errors at all.
Reply
#8
There's no point in having it as a resident script, you can easily switch it to a scheduled one with lower interval (once in 5 or 10 minutes).
Reply
#9
I am using a schedule every minute without issue.
Reply
#10
thanks, i give it a try
Reply
#11
I added it in a scheduled script and its works fine, till today. I needed to restart my LM4 to get it working again. It looks like the scheduler was hanging.

Maybe the problem there's no timeout like? socket.http.TIMEOUT = 5
Reply
#12
(23.02.2016, 07:05)gjniewenhuijse Wrote: I added it in a scheduled script and its works fine, till today. I needed to restart my LM4 to get it working again. It looks like the scheduler was hanging.

Maybe the problem there's no timeout like? socket.http.TIMEOUT = 5

I had also the same problem. At this moment I am testing this sheduled script solution with 2 min interval.
But could you Edgars say something more about mechanism of resident scripting to have some knowledge "before the problem" to avoid it. My interval value before was 60s, but I am asking also for some information about the LM behaviour when resident script interval value is set to 0s. What's this mean? That the script will run and consume all available CPU power?
Reply
#13
0 timeout will use all CPU power if written incorrectly. It's mostly used for client-server, serial and similar scripts, where most of the time script is waiting for data or timeout via read/receive or similar calls.
Reply
#14
(11.05.2016, 12:38)admin Wrote: 0 timeout will use all CPU power if written incorrectly. It's mostly used for client-server, serial and similar scripts, where most of the time script is waiting for data or timeout via read/receive or similar calls.

And do you know why for this specific example(netatmo) using resident script with interval = 60s was too much? CPU usage was on maximum 60%.
Reply
#15
Hello Matt,

I did som more testing and found out the following: I managed to get the station data through api.netatmo.com/api/getstationsdata?access_token=.... and I got this for the wind gauge:

{
"_id":"....",
"type":"NAModule2",
"last_message":1463517535,
"last_seen":1463517535,
"dashboard_data":{
"WindAngle":239,
"WindStrength":2,
"GustAngle":237,
"GustStrength":3,
"time_utc":1463517522,
"WindHistoric":[{"WindStrength":2,"WindAngle":242,"time_utc":1463514196},{"WindStrength":2,"WindAngle":242,"time_utc":1463514497},{"WindStrength":2,"WindAngle":244,"time_utc":1463514805},{"WindStrength":2,"WindAngle":239,"time_utc":1463515106},{"WindStrength":2,"WindAngle":246,"time_utc":1463515407},{"WindStrength":2,"WindAngle":244,"time_utc":1463515709},{"WindStrength":2,"WindAngle":236,"time_utc":1463516010},{"WindStrength":2,"WindAngle":244,"time_utc":1463516311},{"WindStrength":2,"WindAngle":246,"time_utc":1463516619},{"WindStrength":2,"WindAngle":244,"time_utc":1463516920},{"WindStrength":2,"WindAngle":237,"time_utc":1463517221},{"WindStrength":2,"WindAngle":239,"time_utc":1463517522}
],
"date_max_wind_str":1463470072,
"date_max_temp":1463436297,
"date_min_temp":1463436297,
"min_temp":0,
"max_temp":0,
"max_wind_angle":273,
"max_wind_str":10
},
"data_type":["Wind"],
"module_name":"WIND GAUGE",
"last_setup":1462201564,
"battery_vp":6210,
"battery_percent":100,
"rf_status":75,"firmware":14}
],


in my library script I added these lines:

  -- Module Wind
  if (netatmo_debug) then
    alert("netatmo module 2")
  end  

  grp.update("Netatmo Wind",response_decode.body.modules[2].dashboard_data.WindStrength,dt.float16)
  grp.update("Netatmo Wind Angle",response_decode.body.modules[2].dashboard_data.WindAngle,dt.float16)
  grp.update("Netatmo Gust",response_decode.body.modules[2].dashboard_data.GustStrength,dt.float16)
  grp.update("Netatmo Gust Angle",response_decode.body.modules[2].dashboard_data.GustAngle,dt.float16)
  grp.update("Netatmo Wind_max",response_decode.body.modules[2].dashboard_data.max_wind_str,dt.float16)
  grp.update("Netatmo Wind module battery",response_decode.body.modules[2].dashboard_data.battery_percent,dt.float16)

but everytime I call refresh_netatmo() function I do not get any data except from the main indoor and outdoor module. Can you please help me out here? I also do not get any data from your premade script for the rain sensor. I used it like you posted it here, except that I changed the number, because in Netatmo's documentation it is stated, that the rain module has number 3.

Thank you veru much for your help.

Peter
Reply
#16
Hi Peter,

I just saw that Netatmo deprecated the devicelist command.
If you can get the feedback from https://api.netatmo.net/api/devicelist, I can tell how to read it (if it's included).
I will need to rewrite the code with getstationdata later.

Matthieu
Reply
#17
(12.02.2016, 06:40)gjniewenhuijse Wrote: I have to restart my netatmo Resident script (60 seconds) sometimes a week, else i didn't receive any values. No errors at all.

I have the same problem with central statuses calculation (http://forum.logicmachine.net/showthread...ht=central). All works great until some time and at this moment I prepared auto disable/enable per 24hours. But please remove this issue in the next firmware because I don't know if 24hours is enough period.
Reply
#18
buuuudzik, maybe you can provide remote access to a device where resident script hangs? Because we cannot reproduce this issue locally.
Reply
#19
(24.08.2016, 11:25)admin Wrote: buuuudzik, maybe you can provide remote access to a device where resident script hangs? Because we cannot reproduce this issue locally.

At this moment unfortunately not but I can send you backup file from this LM4. In the Scheduled scripts there is a script for enabling/disabling this resident script(Central statuses).

I will send you backup file via private message.
Reply
#20
Is this script working for every one? Since yesterday 11:30 i received: connection refused.

I collect data every 5 minutes and only once a +- 8 hours its succesfully, others are always: connection refused.

Solved by netatmo
Reply


Forum Jump: