Skip to main content
cancel
Showing results for 
Search instead for 
Did you mean: 

Grow your Fabric skills and prepare for the DP-600 certification exam by completing the latest Microsoft Fabric challenge.

stevedep

Power M code to read Netatmo API data

Hi,

 

I am writing this to share my code to retrieve Netatmo Weather station data. Below you will find the code for the different queries as seen below:

stevedep_0-1613894751349.png

The code to get your token (pls note you will need to replace everything that has been pre-fixed with 'your_').

 

 

 

 

 

 

let
    token_url = "https://api.netatmo.com/oauth2/token",    
    api_base_url = "apiurl.com",
    qry_str = "?myparameter",

   body="grant_type=password&client_id=your_clientid&client_secret=your_client_secret&username=your_email&password=your_password",
   token  = Json.Document(Web.Contents(token_url,
   [ 
     Headers = [#"Content-Type"="application/x-www-form-urlencoded"],
     Content=Text.ToBinary(body)
   ]
   )),
   //token[access_token],
   
   tokenstring = "access_token="& Text.From( token[access_token])
in
    tokenstring

 

 

 

 

 

 

Create an app on the API website of Netatmo to obtain your login credentials:

stevedep_1-1613894933350.png

The code to get Measurements for your stations (it's currently looking back 5 days, see code 'date_begin'):

 

 

 

 

 

 

(devid as text) =>
let 
   date_end = Duration.TotalSeconds( DateTime.LocalNow() -#datetime(1970, 1, 1, 0, 0, 0)),
   date_begin = date_end - (60*60*24*5),

   requeststring = Token & "&device_id="&devid&"&scale=30min&type=co2&optimize=false&real_time=true&date_begin="&Text.From(Number.Round(date_begin))&"&date_end="&Text.From(Number.Round(date_end)),
   getstations = Json.Document(Web.Contents("https://api.netatmo.net/api/getmeasure",
   [ 
     Headers = [#"Content-Type"="application/x-www-form-urlencoded"],
     Content=Text.ToBinary(requeststring)
   ]
   )),
    body1 = getstations[body],
    #"Converted to Table" = Record.ToTable(body1),
    #"Extracted Values" = Table.TransformColumns(#"Converted to Table", {"Value", each Text.Combine(List.Transform(_, Text.From)), type text}),
    #"Changed Type" = Table.TransformColumnTypes(#"Extracted Values",{{"Name", Int64.Type}}),
    #"Added Custom" = Table.AddColumn(#"Changed Type", "DateTime", each #datetime(1970, 1, 1, 0, 0, 0) + #duration(0, 0, 0, [Name]
)),
    #"Sorted Rows" = Table.Sort(#"Added Custom",{{"DateTime", Order.Descending}}),
    
    #"Renamed Columns" = Table.RenameColumns(#"Sorted Rows",{{"Value", "CO2"}})
in
    #"Renamed Columns"

 

 

 

 

 

 

Code to get the measurements for your modules (also looking back 5 days, pls see date_begin):

 

 

 

 

 

 

(devid as text, modid as text) =>
let 
   date_end = Duration.TotalSeconds( DateTime.LocalNow() -#datetime(1970, 1, 1, 0, 0, 0)),
   date_begin = date_end - (60*60*24*5),

   requeststring = Token & "&module_id="&modid&"&device_id="&devid&"&scale=30min&type=co2&optimize=false&real_time=true&date_begin="&Text.From(Number.Round(date_begin))&"&date_end="&Text.From(Number.Round(date_end)),
   getstations = Json.Document(Web.Contents("https://api.netatmo.net/api/getmeasure",
   [ 
     Headers = [#"Content-Type"="application/x-www-form-urlencoded"],
     Content=Text.ToBinary(requeststring)
   ]
   )),
    body1 = getstations[body],
    #"Converted to Table" = Record.ToTable(body1),
    #"Extracted Values" = Table.TransformColumns(#"Converted to Table", {"Value", each Text.Combine(List.Transform(_, Text.From)), type text}),
    #"Changed Type" = Table.TransformColumnTypes(#"Extracted Values",{{"Name", Int64.Type}}),
    #"Added Custom" = Table.AddColumn(#"Changed Type", "DateTime", each #datetime(1970, 1, 1, 0, 0, 0) + #duration(0, 0, 0, [Name]
)),
    #"Sorted Rows" = Table.Sort(#"Added Custom",{{"DateTime", Order.Descending}}),
    #"Renamed Columns" = Table.RenameColumns(#"Sorted Rows",{{"Value", "CO2"}})
in
    #"Renamed Columns"

 

 

 

 

 

 

Code that brings it together (you will need to change the filter value, currently 'your_modulename'):

 

 

 

 

 

 

let
   
   getstations = Json.Document(Web.Contents("https://api.netatmo.net/api/getstationsdata",
   [ 
     Headers = [#"Content-Type"="application/x-www-form-urlencoded"],
     Content=Text.ToBinary(Token)
   ]
   )),
    body1 = getstations[body],
    devices = body1[devices],
    #"Converted to Table" = Table.FromList(devices, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
    #"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"_id", "station_name", "date_setup", "last_setup", "type", "last_status_store", "module_name", "firmware", "last_upgrade", "wifi_status", "reachable", "co2_calibrating", "data_type", "place", "home_id", "home_name", "dashboard_data", "modules"}, {"_id", "station_name", "date_setup", "last_setup", "type", "last_status_store", "module_name", "firmware", "last_upgrade", "wifi_status", "reachable", "co2_calibrating", "data_type", "place", "home_id", "home_name", "dashboard_data", "modules"}),
    #"Removed Other Columns" = Table.SelectColumns(#"Expanded Column1",{"_id", "station_name"}),
    #"Added Custom" = Table.AddColumn(#"Removed Other Columns", "CO2_Measurements", each fnGetMeasurements([_id])),
    #"Expanded CO2_Measurements" = Table.ExpandTableColumn(#"Added Custom", "CO2_Measurements", {"CO2", "DateTime", "Name"}, {"CO2", "DateTime", "Name"}),
    FinalStations = Table.RemoveColumns(#"Expanded CO2_Measurements",{"_id"}),
    mods = #"Expanded Column1",
    #"Expanded modules" = Table.ExpandListColumn(mods, "modules"),
    #"Expanded modules1" = Table.ExpandRecordColumn(#"Expanded modules", "modules", {"_id", "module_name"}, {"_id.1", "module_name.1"}),
    #"Removed Other Columns1" = Table.SelectColumns(#"Expanded modules1",{"_id", "_id.1", "module_name.1"}),
    #"Filtered Rows" = Table.SelectRows(#"Removed Other Columns1", each ([module_name.1] = "your_modulename")),
    #"Added Custom1" = Table.AddColumn(#"Filtered Rows", "CO2_Measurements", each fnGetMeasurementsModule([_id], [_id.1])),
    #"Renamed Columns1" = Table.RenameColumns(#"Added Custom1",{{"_id", "_modId"}}),
    #"Removed Columns" = Table.RemoveColumns(#"Renamed Columns1",{"_modId", "_id.1"}),
    #"Renamed Columns" = Table.RenameColumns(#"Removed Columns",{{"module_name.1", "station_name"}}),
    FinalModules = Table.ExpandTableColumn(#"Renamed Columns", "CO2_Measurements", {"CO2", "DateTime", "Name"}, {"CO2", "DateTime", "Name"}),
    FinalResult = Table.Combine({FinalModules,FinalStations})
in
    FinalResult

 

 

 

 

 

 

 

Please send me a message if you are interested in the dashboard that contains DAX like moving averages and day to day comparisons of the CO2 values. 

 

Enjoy!

Kind regards, Steve. 

 

 

Comments

Great article Steve.    This has been really helpful. 

 

Keen to now do my own charting and plotting for the weather.

Thanks for your article, @stevedep. I'd be very interested in having a look at the dashboard that contains DAX like moving averages and day to day comparisons of the CO2 values. 

Hello, I know this is an old thread.

Did anything changed on the Netatmo side?

I can't get the token to work, and I am not skilled enough to find out the rootcause, as I just copied/pasted the M Code and set my credentials on this code and as a result I get: 

DataSource.Error: Web.Contents failed to get contents from 'https://api.netatmo.com/oauth2/token' (400):
Details:
DataSourceKind=Web
DataSourcePath=https://api.netatmo.com/oauth2/token
Url=https://api.netatmo.com/oauth2/token

 

My datasource settings for this is

057Sophie_0-1703055284772.png

 

I just found this after digging on the netatmo dev site, might be the reason??? If yes I am not sure at all on how to move to the authorization code grant type

Client credentials grant type

https://api.netatmo.com/oauth2/token
Method: POST

!! This method will be deprecated in october 2022 !!
If you want to access data from another user's account, you MUST use the 
Authorization code grant type.

 

 

I am also having the same issue as @057Sophie , and chatGPT does not seem to be able to help either.

Does anyone know of a way to get data from Netatmo to Power BI automatically with the new authorization?