main.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 # coding=utf-8
3 """
4  Translates Netatmo Weather Station data to ROS.
5  The time between updates is one minute.
6  Value -1 in CO2, noise, pressure or battery_percent means no value.
7  This node expect the configuration path to be specified via private parameter configpath. If the path a file called
8  config.ini, it will be used. If this file is not found, the configuration values will be read from the following
9  files: username, password, client_id, client_secret and device_id.
10  Author: José Jaime Ariza (jariza@ieee.org).
11  Python version: 2.7
12 """
13 
14 import ConfigParser
15 import os.path
16 import requests
17 import rospy
18 import sys
19 from netatmo2ros.msg import WeatherdataArray, Weatherdata
20 
21 
22 def get_access_token(username, password, client_id, client_secret):
23  """
24  Get the Netatmo access token
25  :param username: Netamo username
26  :param password: Netamo password
27  :param client_id: Netamo Client ID
28  :param client_secret: Netamo Client Secret
29  :return: access token
30  """
31  # Query data
32  payload = {'grant_type': 'password',
33  'username': username,
34  'password': password,
35  'client_id': client_id,
36  'client_secret': client_secret,
37  'scope': 'read_station'}
38 
39  # Do the query
40  response = requests.post("https://api.netatmo.com/oauth2/token", data=payload)
41  response.raise_for_status()
42  if response.json()["scope"][0] != 'read_station':
43  raise ValueError("Unexpected scope: " + ' '.join(response.json()["scope"]))
44 
45  # Return access token
46  return response.json()["access_token"]
47 
48 
49 def get_station_values(access_token, device_id):
50  """
51  Get values from a station and it's modules
52  :param access_token: Netatmo access token
53  :param device_id: Netatmo device ID
54  :return: station weather data
55  """
56 
57  # Query data
58  params = {
59  'access_token': access_token,
60  'device_id': device_id
61  }
62 
63  # Do the query
64  response = requests.post("https://api.netatmo.com/api/getstationsdata", params=params)
65  response.raise_for_status()
66  device_data = response.json()["body"]["devices"][0]
67  if device_data["_id"] != device_id:
68  raise Exception("Unexpected device: " + device_data["_id"])
69 
70  # Populate indoor module data
71  output = WeatherdataArray()
72  wd = Weatherdata()
73  wd.name = str(device_data["module_name"])
74  wd.battery_percent = -1
75  wd.co2 = int(device_data["dashboard_data"]["CO2"])
76  wd.humidity = int(device_data["dashboard_data"]["Humidity"])
77  wd.noise = int(device_data["dashboard_data"]["Noise"])
78  wd.pressure = float(device_data["dashboard_data"]["Pressure"])
79  wd.temperature = float(device_data["dashboard_data"]["Temperature"])
80  wd.link_status = int(device_data["wifi_status"])
81  wd.last_seen = -1
82  wd.time_utc = long(device_data["dashboard_data"]["time_utc"])
83  output.wd.append(wd)
84 
85  # Populate outdoor modules data
86  for module_data in device_data["modules"]:
87  wd = Weatherdata()
88  wd.name = str(module_data["module_name"])
89  wd.battery_percent = int(module_data["battery_percent"])
90  wd.co2 = -1
91  wd.humidity = int(module_data["dashboard_data"]["Humidity"])
92  wd.noise = -1
93  wd.pressure = -1
94  wd.temperature = float(module_data["dashboard_data"]["Temperature"])
95  wd.link_status = int(module_data["rf_status"])
96  wd.last_seen = long(module_data["last_seen"])
97  wd.time_utc = -1
98  output.wd.append(wd)
99 
100  # Return data
101  return output
102 
103 
104 def publisher_loop(access_token, device_id):
105  """
106  Loop for publishing data in ROS
107  :param access_token: Netatmo access token
108  :param device_id: Netatmo Weather Station device ID
109  """
110 
111  while not rospy.is_shutdown():
112  station_data = get_station_values(access_token, device_id)
113  pub.publish(station_data)
114  rospy.sleep(10)
115 
116 
117 if __name__ == '__main__':
118  # ROS node initialization
119  pub = rospy.Publisher("weather", WeatherdataArray, queue_size=1)
120  rospy.init_node("netatmo2ros", anonymous=False)
121 
122  # Read configuration
123  config_path = rospy.get_param("~configpath")
124 
125  if os.path.isfile(os.path.join(config_path, "config.ini")):
126  # File.ini expected
127  config = ConfigParser.ConfigParser()
128  config.read(os.path.join(config_path, "config.ini"))
129  uname = config.get("user", "username")
130  passw = config.get("user", "password")
131  clientid = config.get("user", "client_id")
132  clientsecret = config.get("user", "client_secret")
133  deviceid = config.get("device", "device_id")
134  elif os.path.isdir(config_path):
135  # Directory with multiple files expected
136  with open(os.path.join(config_path, "username"), "r") as f:
137  uname = f.readline().rstrip()
138  with open(os.path.join(config_path, "password"), "r") as f:
139  passw = f.readline().rstrip()
140  with open(os.path.join(config_path, "client_id"), "r") as f:
141  clientid = f.readline().rstrip()
142  with open(os.path.join(config_path, "client_secret"), "r") as f:
143  clientsecret = f.readline().rstrip()
144  with open(os.path.join(config_path, "device_id"), "r") as f:
145  deviceid = f.readline().rstrip()
146  else:
147  sys.exit("Couldn't find configuration in path {0}.".format(config_path))
148 
149  # Get token and start loop
150  wd_access_token = get_access_token(uname, passw, clientid, clientsecret)
151  publisher_loop(wd_access_token, deviceid)
def get_access_token(username, password, client_id, client_secret)
Definition: main.py:22
def publisher_loop(access_token, device_id)
Definition: main.py:104
def get_station_values(access_token, device_id)
Definition: main.py:49


netatmo
Author(s): José Jaime Ariza
autogenerated on Mon Jun 10 2019 13:59:24