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
#41
Thanks!!! Works
Reply
#42
I have used the old method for some years too, but since july I've got the same "401. auth error" as mentioned over here. Thanx for sharing new updated code and instructions. It was not 100% clear to me where to put the code exactly (Before, after, replacing old code)? I replaced the "token", tried to put it before, replacing and after the old user ID/token code with no luck).
Are there new Netatmo instructions with updated code and step by step instructions anywhere available?
Schneider Wiser (homeLynk), Power Tags, DALI, Multitouch Pro, Panasonic Heating pump, Flexit balansed ventilation, HUE integration, Lemus Speaker system. Tibber integration.
Reply
#43
I use this code

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

netatmo_debug = false

client_id = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
client_secret = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
refresh_token_org = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" -- get this token from the netatmo dev page, generate first auth and refresh_token

request_token_url = "https://api.netatmo.net/oauth2/token"
request_url = "https://api.netatmo.net/api"
response_body = { }

if (netatmo_debug) then
  log("netatmo start")
end


-- get auth token from refresh token
-- https://github.com/akbooer/Netatmo/blob/master/L_Netatmo.lua#L430
function refresh_token()
    refresh = storage.get('netatmo_refresh_1', refresh_token_org)
 
  local request_body = "grant_type=refresh_token&client_id=" .. client_id .."&client_secret=" .. client_secret .. "&refresh_token=" .. refresh

  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
    if (netatmo_debug) then
      log("netatmo auth error: "..tostring(code)..", "..tostring(body))
    end
    return
  end

  local response_decode = json.decode(table.concat(response_body))
  local access_token = response_decode.access_token
  if response_decode.refresh_token then
        storage.set('netatmo_refresh_1', response_decode.refresh_token)
  end
  if (netatmo_debug) then
    log(response_body)
    log("netatmo token %s",access_token)
  end
  return "access_token=" .. access_token 
end


-- init
if not init then
  if (netatmo_debug) then
      log("netatmo init")
    end
    request_body = refresh_token()
  init = true
end
if not request_body and netatmo_debug then
    log("netatmo token error")
end


function get_stationdata()
  if not request_body then return end
  --to limit to only one device : -- local request_body = "access_token=" .. access_token .. "&device_id=" .. device_id
  --https://dev.netatmo.com/dev/resources/technical/reference/weatherstation/getstationsdata
  local response_body = { }
  local body, code, hdrs, stat = https.request
  {
    url = request_url..'/getstationsdata';
    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
    if (netatmo_debug) then
      log("netatmo devicelist error: "..tostring(code)..", "..tostring(body)..", "..tostring(hdrs)..", "..tostring(stat))
    end
    return
  end
  local response_decode = json.decode(table.concat(response_body))
  if (netatmo_debug) then
        log(response_decode)
  end
end

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

Code:
require('user.nit_netatmo')
get_stationdata()
Reply
#44
Nice. It all seems to connect well and in debug mode I can see the data in table mode. So far so good.
Any code examples how you pull the data and put it into a grp.write for the different modules ? I only figured out the main module and I placed the code just at line "103" . Main station is responding well, but my lack of coding skills does not help if to get the other stations/modules from other rooms/outdoor/rain/Wind etc. I also see that from the Debug log that the tables of the modules (Outdoor, Rain, Wind, Additional room modules) are "Table: Nesting too deep" .
Schneider Wiser (homeLynk), Power Tags, DALI, Multitouch Pro, Panasonic Heating pump, Flexit balansed ventilation, HUE integration, Lemus Speaker system. Tibber integration.
Reply
#45
What do you have in logs?
------------------------------
Ctrl+F5
Reply
#46
Code:
etatmo Updater 5min 04.08.2023 10:29:34
* string: netatmo start
Netatmo Updater 5min 04.08.2023 10:29:34
* string: netatmo init
Netatmo Updater 5min 04.08.2023 10:29:34
* table:
[1]
  * string: {"access_token":"**************************","refresh_token":"*********************************|*****************************","scope":["read_station"],"expires_in":10800,"expire_in":10800}
Netatmo Updater 5min 04.08.2023 10:29:34
* arg: 1
  * string: netatmo token %s
* arg: 2
  * string: ***********************************
Netatmo Updater 5min 04.08.2023 10:29:34
* string: netatmo end
Netatmo Updater 5min 04.08.2023 10:29:35
* table:
["status"]
  * string: ok
["body"]
  * table:
   ["user"]
    * table:
     ["administrative"]
      * table:
       ["country"]
        * string: NB_NO
       ["unit"]
        * number: 0
       ["feel_like_algo"]
        * number: 0
       ["windunit"]
        * number: 2
       ["reg_locale"]
        * string: nb-NO
       ["pressureunit"]
        * number: 0
       ["lang"]
        * string: nb
     ["mail"]
      * string: *****@*****.no
   ["devices"]
    * table:
     [1]
      * table:
       ["last_setup"]
        * number: 1575399707
       ["_id"]
        * string: **:**:**:58:7e:36
       ["data_type"]
        * table:
         [1]
          * string: Temperature
         [2]
          * string: CO2
         [3]
          * string: Humidity
         [4]
          * string: Noise
         [5]
          * string: Pressure
       ["home_name"]
        * string: Rorstadvegen
       ["station_name"]
        * string: Rorstadvegen (Indoor1)
       ["dashboard_data"]
        * table:
         ["time_utc"]
          * number: 1691137647
         ["pressure_trend"]
          * string: up
         ["CO2"]
          * number: 474
         ["Humidity"]
          * number: 54
         ["date_max_temp"]
          * number: 1691100162
         ["max_temp"]
          * number: 23.2
         ["Temperature"]
          * number: 22.2
         ["Noise"]
          * number: 40
         ["Pressure"]
          * number: 1007.1
         ["date_min_temp"]
          * number: 1691132810
         ["min_temp"]
          * number: 22.1
         ["temp_trend"]
          * string: stable
         ["AbsolutePressure"]
          * number: 999.6
       ["home_id"]
        * string: ******b7d7e9e4d7
       ["module_name"]
        * string: Indoor1
       ["firmware"]
        * number: 201
       ["wifi_status"]
        * number: 51
       ["modules"]
        * table:
         [1]
          * table:
           ["reachable"]
            * bool: true
           ["last_setup"]
            * number: 1575399668
           ["firmware"]
            * number: 53
           ["data_type"]
            * table:
             nesting too deep
           ["battery_vp"]
            * number: 5332
           ["_id"]
            * string: **:**:**:58:ef:1c
           ["rf_status"]
            * number: 68
           ["last_seen"]
            * number: 1691137641
           ["last_message"]
            * number: 1691137648
           ["type"]
            * string: NAModule1
           ["battery_percent"]
            * number: 63
           ["dashboard_data"]
            * table:
             nesting too deep
           ["module_name"]
            * string: Outdoor
         [2]
          * table:
           ["reachable"]
            * bool: false
           ["last_setup"]
            * number: 1575402173
           ["firmware"]
            * number: 27
           ["data_type"]
            * table:
             nesting too deep
           ["battery_vp"]
            * number: 65535
           ["rf_status"]
            * number: 82
           ["last_seen"]
            * number: 1686170566
           ["last_message"]
            * number: 1686170566
           ["type"]
            * string: NAModule2
           ["battery_percent"]
            * number: 100
           ["_id"]
            * string: **:**:**:04:06:6a
           ["module_name"]
            * string: wind
         [3]
          * table:
           ["reachable"]
            * bool: true
           ["last_setup"]
            * number: 1575486620
           ["firmware"]
            * number: 14
           ["data_type"]
            * table:
             nesting too deep
           ["battery_vp"]
            * number: 4854
           ["_id"]
            * string: **:**:**:06:91:0e
           ["rf_status"]
            * number: 88
           ["last_seen"]
            * number: 1691137648
           ["last_message"]
            * number: 1691137648
           ["type"]
            * string: NAModule3
           ["battery_percent"]
            * number: 48
           ["dashboard_data"]
            * table:
             nesting too deep
           ["module_name"]
            * string: rain
         [4]
          * table:
           ["reachable"]
            * bool: true
           ["last_setup"]
            * number: 1581013343
           ["firmware"]
            * number: 53
           ["data_type"]
            * table:
             nesting too deep
           ["battery_vp"]
            * number: 5479
           ["_id"]
            * string: **:**:**:59:e9:48
           ["rf_status"]
            * number: 67
           ["last_seen"]
            * number: 1691137635
           ["last_message"]
            * number: 1691137648
           ["type"]
            * string: NAModule4
           ["battery_percent"]
            * number: 71
           ["dashboard_data"]
            * table:
             nesting too deep
           ["module_name"]
            * string: bedroom1
         [5]
          * table:
           ["reachable"]
            * bool: false
           ["last_setup"]
            * number: 1647974577
           ["firmware"]
            * number: 53
           ["data_type"]
            * table:
             nesting too deep
           ["battery_vp"]
            * number: 65535
           ["rf_status"]
            * number: 49
           ["last_seen"]
            * number: 1686622420
           ["last_message"]
            * number: 1686622465
           ["type"]
            * string: NAModule4
           ["battery_percent"]
            * number: 100
           ["_id"]
            * string: **:**:**:0c:03:00
           ["module_name"]
            * string: basement
       ["place"]
        * table:
         ["country"]
          * string: NO
         ["city"]
          * string: Oslo
         ["timezone"]
          * string: Europe/Oslo
         ["location"]
          * table:
           [1]
            * number: *.***************
           [2]
            * number: 62.*****************
         ["altitude"]
          * number: 63
       ["co2_calibrating"]
        * bool: false
       ["type"]
        * string: NAMain
       ["date_setup"]
        * number: 1575399707
       ["reachable"]
        * bool: true
       ["last_status_store"]
        * number: 1691137650
["time_server"]
  * number: 1691137775
["time_exec"]
  * number: 0.0466818809509277
Schneider Wiser (homeLynk), Power Tags, DALI, Multitouch Pro, Panasonic Heating pump, Flexit balansed ventilation, HUE integration, Lemus Speaker system. Tibber integration.
Reply
#47
Try these two logs, one should give you Co2, second will show what is deeper under 'modules'. 
Code:
log(response_decode.body.devices[1].dashboard_data.CO2)
log(response_decode.body.devices[1].modules)
I'm not sure if I used correct order. Yo can play like this by going deeper and deeper in the table.
------------------------------
Ctrl+F5
Reply
#48
I had the same issue, ended up with this solution.

Main module:
grp.write("Netatmo temp stue",response_decode.body.devices[2].dashboard_data.Temperature,dt.float16)
grp.write("Netatmo luftfuktighet stue",response_decode.body.devices[2].dashboard_data.Humidity,dt.scale)
grp.write("Netatmo trykk",response_decode.body.devices[2].dashboard_data.Pressure,dt.uint16)
grp.write("Netatmo CO2 Stue",response_decode.body.devices[2].dashboard_data.CO2,dt.float16)
grp.write("Netatmo db Stue",response_decode.body.devices[2].dashboard_data.Noise,dt.uint8)

Outside temp module:
grp.write("Netatmo temp ute",response_decode.body.devices[2].modules[1].dashboard_data.Temperature,dt.float16)
grp.write("Netatmo luftfuktighet ute",response_decode.body.devices[2].modules[1].dashboard_data.Humidity,dt.scale)
Reply
#49
Hi!

My netatmo script, the old one, doesnt work anymore because they changed there API etc..
I have tried diffrent things but it doesnt work....
Does anyone have a step by step and example script with main module and outdoor module example? 
Very nice if there is also in the script examples of how too grp.write to objects on the Logimachine Smile

Thanx!
Reply
#50
(23.11.2023, 14:35)stigen Wrote: Hi!

My netatmo script, the old one, doesnt work anymore because they changed there API etc..
I have tried diffrent things but it doesnt work....
Does anyone have a step by step and example script with main module and outdoor module example? 
Very nice if there is also in the script examples of how too grp.write to objects on the Logimachine Smile

Thanx!

Hi stigen,

in the first step you need to setup a Netatmo Developer account: https://dev.netatmo.com

Then create a application inside Netatmo development area to get the relevant tokens.

Then generate a new user script, name it "netatmo" and add the token in the following script:

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

netatmo_debug = true

client_id = "XXX"
client_secret = "xxx"
refresh_token_org = "xxx" -- get this token from the netatmo dev page, generate first auth and refresh_token

request_token_url = "https://api.netatmo.net/oauth2/token"
request_url = "https://api.netatmo.net/api"
response_body = { }

if (netatmo_debug) then
  log("netatmo start")
end


-- get auth token from refresh token
-- https://github.com/akbooer/Netatmo/blob/master/L_Netatmo.lua#L430
function refresh_token()
    refresh = storage.get('netatmo_refresh_1', refresh_token_org)
 
  local request_body = "grant_type=refresh_token&client_id=" .. client_id .."&client_secret=" .. client_secret .. "&refresh_token=" .. refresh

  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
    if (netatmo_debug) then
      log("netatmo auth error: "..tostring(code)..", "..tostring(body))
    end
    return
  end

  local response_decode = json.decode(table.concat(response_body))
  local access_token = response_decode.access_token
  if response_decode.refresh_token then
        storage.set('netatmo_refresh_1', response_decode.refresh_token)
  end
  if (netatmo_debug) then
    log(response_body)
    log("netatmo token %s",access_token)
  end
  return "access_token=" .. access_token 
end


-- init
if not init then
  if (netatmo_debug) then
      log("netatmo init")
    end
     request_body = refresh_token()
  init = true
end
if not request_body and netatmo_debug then
    log("netatmo token error")
end


function get_stationdata()
  if not request_body then return end
  --to limit to only one device : -- local request_body = "access_token=" .. access_token .. "&device_id=" .. device_id
  --https://dev.netatmo.com/dev/resources/technical/reference/weatherstation/getstationsdata
  local response_body = { }
  local body, code, hdrs, stat = https.request
  {
    url = request_url..'/getstationsdata';
    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
    if (netatmo_debug) then
      log("netatmo devicelist error: "..tostring(code)..", "..tostring(body)..", "..tostring(hdrs)..", "..tostring(stat))
    end
    return
  end
  local response_decode = json.decode(table.concat(response_body))
  if (netatmo_debug) then
        log(response_decode)
        log(response_decode.body.devices[1].modules[4].dashboard_data)
  end

--write station data to KNX
   
    grp.write("Netatmo_Main_CO2",response_decode.body.devices[1].dashboard_data.CO2)
    grp.write("Netatmo_Main_Humidity",response_decode.body.devices[1].dashboard_data.Humidity)
    grp.write("Netatmo_Main_Temp",response_decode.body.devices[1].dashboard_data.Temperature)
   
    grp.write("Netatmo_Aussen_Temp",response_decode.body.devices[1].modules[1].dashboard_data.Temperature)
    grp.write("Netatmo_Aussen_Humidity",response_decode.body.devices[1].modules[1].dashboard_data.Humidity)
    grp.write("Netatmo_Aussen_Battery",response_decode.body.devices[1].modules[1].battery_percent)
   
    grp.write("Netatmo_Bad_Temp",response_decode.body.devices[1].modules[2].dashboard_data.Temperature)
    grp.write("Netatmo_Bad_Humidity",response_decode.body.devices[1].modules[2].dashboard_data.Humidity)
    grp.write("Netatmo_Bad_Battery",response_decode.body.devices[1].modules[2].battery_percent)
    grp.write("Netatmo_Bad_CO2",response_decode.body.devices[1].modules[2].dashboard_data.CO2)
   
    grp.write("Netatmo_Küche_Temp",response_decode.body.devices[1].modules[3].dashboard_data.Temperature)
    grp.write("Netatmo_Küche_Humidity",response_decode.body.devices[1].modules[3].dashboard_data.Humidity)
    grp.write("Netatmo_Küche_Battery",response_decode.body.devices[1].modules[3].battery_percent)
    grp.write("Netatmo_Küche_CO2",response_decode.body.devices[1].modules[3].dashboard_data.CO2)
   
    grp.write("Netatmo_Rain",response_decode.body.devices[1].modules[4].dashboard_data.Rain)
    grp.write("Netatmo_Rain_24h",response_decode.body.devices[1].modules[4].dashboard_data.sum_rain_24)
    grp.write("Netatmo_Rain_1h",response_decode.body.devices[1].modules[4].dashboard_data.sum_rain_1)
    grp.write("Netatmo_Rain_Battery",response_decode.body.devices[1].modules[4].battery_percent)
end

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

In the next step you generate scheduled script (*/5****) and add the following code:

Code:
require('user.netatmo')
get_stationdata()

Run the scheduled script and looking inside the log which module is the right category (outdoor, rain, wind etc.) and adjust the second number ...body.devices[1].modules[4]... .Furthermore change the object name to your KNX group address name.

Now you are ready to go. I hope it helps.

Best Regards
Steffen 
Reply


Forum Jump: