#!/usr/bin/env python # -*- coding=utf-8 -*- #Code to add Netatmo stations to a csv file containing MAC addresses ############################################################## ###USAGE ### ###python get_ids_modules.py input_csv_file output_csv_file### ############################################################## import sys import requests import pandas def get_region(lat_ne, lon_ne, lat_sw, lon_sw): """ get mac addresses of station and outdoor temperature sensor using getpublicdata in given box. Some stations returned outside of this. username, password, client id and client secret have been redacted. You can generate these by creating a Netatmo developer account at https://dev.netatmo.com/. Parameters ---------- lat_ne : str(float or int) North eastern corner of rectangle. Latitude in degrees. lon_ne : str(float or int) North eastern corner of rectangle. Longitude in degrees. lat_sw : str(float or int) South western corner of rectangle. Latitude in degrees. lon_sw : str(float or int) South western corner of rectangle. Longitude in degrees. Raises ------ NameError Handled by code in case a search yields no stations Returns ------- dict containing station MAC addresses. """ #setting up contact with API payload = {'grant_type': 'password', 'username': "$user@example.com", 'password': "$password", 'client_id': "$client_id", 'client_secret': "$client_secret", 'scope': 'read_station'} try: #try to get access tokens response = requests.post("https://api.netatmo.com/oauth2/token", data=payload) response.raise_for_status() access_token = response.json()["access_token"] refresh_token = response.json()["refresh_token"] scope = response.json()["scope"] except requests.exceptions.HTTPError as error: print(error.response.status_code, error.response.text) params = { 'access_token': access_token, 'lat_ne' : lat_ne, 'lon_ne' : lon_ne, 'lat_sw' : lat_sw, 'lon_sw' : lon_sw, } ids = {} NoResponse = True retry_count = 0 while NoResponse: #try to get stations in given region, 5 attempts before moving on to next area try: #try to get stations response = requests.post("https://api.netatmo.com/api/getpublicdata", params=params) response.raise_for_status() data = response.json()["body"] for station in data: #find each value for each station _id = station['_id'] mod = [n for n in station['modules'] if n.startswith('02:')] location = station['place']['location'] altitude = station['place']['altitude'] if 'city' in station['place'].keys(): city = station['place']['city'] else: city = 'no city' ids[_id] = ({'module_name':mod, 'location':location, 'altitude':altitude, 'city':city, 'full_modules':station['modules']}) #Checking that some data has been returned if len(ids) == 0: #if everything works but we have no data returned in the given box, raise raise NameError('length') except requests.exceptions.HTTPError as error: #if there's an error, try four more times before moving on print(error.response.status_code, error.response.text) if retry_count < 5: retry_count += 1 else: return({}) except NameError: if retry_count < 5: retry_count += 1 else: return({}) else: NoResponse = False return(ids) def csvread(file_name): """ import a previously saved csv file, in this case the file of stations Parameters ---------- file_name : str Import a csv file containing Netatmo MAC addresses. Returns ------- dict containing MAC addresses """ file = pandas.read_csv(file_name, index_col=0).to_dict() return(file) def get_stations(): """ Call getregion to ensure all of UK is covered without calling the API to try and get data from the Atlantic Ocean. Returns ------- dict containing MAC addresses. """ master = {} areas = {49:[-7, -6, -5], 50: [-6, -5, -4, -3, -2, -1, 0, 1], 51: [-6, -5, -4, -3, -2, -1, 0, 1, 2], 52:[-6, -5, -4, -3, -2, -1, 0, 1, 2], 53: [-5, -4, -3, -2, -1, 0, 1], 54:[-8, -7, -6, -5, -4, -3, -2, -1, 0], 55: [-8, -7, -6, -5, -4, -3, -2, -1], 56:[-7, -6, -5, -4, -3, -2], 57:[-9, -8, -7, -6, -5, -4, -3, -2, -1], 58: [-8, -7, -6, -5, -4, -3, -2], 59: [-4, -3, -2, -1], 60: [-3, -2, -1, 0] } for lat in areas: j = 0 while j < len(areas[lat])-1: master.update(get_region(str(lat+1), str(areas[lat][j+1]), str(lat), str(areas[lat][j]))) j = j + 1 return(master) def mergedata(old_file, new_file): """ Combining current station list ('old') with new fresh data from the API ('new'), returning updated list ('merge') and saving csv file Parameters ---------- old_file : str path to file containing Netatmo MAC addressed new_file : str path to file where output MAC addresses should be saved. Can be (and is in my case) the same as 'old_file'. Returns ------- None. """ old = csvread(old_file) new = get_stations() merge = old.copy() merge.update(new) df = pandas.DataFrame.from_dict(merge) df.to_csv(new_file) print(str(len(merge)-len(old))+' new stations added') print(str(len(merge))+' stations in total') def main(): inp=sys.argv[1] out=sys.argv[2] mergedata(inp,out) if __name__ == "__main__": main()