Skip to content

Commit b6d19ca

Browse files
committed
First level of Thermostat support
1 parent 301d2a1 commit b6d19ca

3 files changed

Lines changed: 93 additions & 7 deletions

File tree

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,5 @@ lnetatmo.egg-info/
88
*.pyc
99

1010
__pycache__/
11+
12+
MANIFEST*

lnetatmo.py

Lines changed: 63 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -73,12 +73,13 @@ def getParameter(key, default):
7373
# Common definitions
7474

7575
_BASE_URL = "https://api.netatmo.com/"
76-
_AUTH_REQ = _BASE_URL + "oauth2/token"
77-
_GETMEASURE_REQ = _BASE_URL + "api/getmeasure"
78-
_GETSTATIONDATA_REQ = _BASE_URL + "api/getstationsdata"
79-
_GETHOMEDATA_REQ = _BASE_URL + "api/gethomedata"
80-
_GETCAMERAPICTURE_REQ = _BASE_URL + "api/getcamerapicture"
81-
_GETEVENTSUNTIL_REQ = _BASE_URL + "api/geteventsuntil"
76+
_AUTH_REQ = _BASE_URL + "oauth2/token"
77+
_GETMEASURE_REQ = _BASE_URL + "api/getmeasure"
78+
_GETSTATIONDATA_REQ = _BASE_URL + "api/getstationsdata"
79+
_GETTHERMOSTATDATA_REQ = _BASE_URL + "api/getthermostatsdata"
80+
_GETHOMEDATA_REQ = _BASE_URL + "api/gethomedata"
81+
_GETCAMERAPICTURE_REQ = _BASE_URL + "api/getcamerapicture"
82+
_GETEVENTSUNTIL_REQ = _BASE_URL + "api/geteventsuntil"
8283

8384

8485
#TODO# Undocumented (but would be very usefull) API : Access currently forbidden (403)
@@ -117,6 +118,10 @@ class NoDevice( Exception ):
117118
pass
118119

119120

121+
class AuthFailure( Exception ):
122+
pass
123+
124+
120125
class ClientAuth:
121126
"""
122127
Request authentication and keep access token available through token method. Renew it automatically if necessary
@@ -137,7 +142,8 @@ def __init__(self, clientId=_CLIENT_ID,
137142
clientSecret=_CLIENT_SECRET,
138143
username=_USERNAME,
139144
password=_PASSWORD,
140-
scope="read_station read_camera access_camera write_camera read_presence access_presence write_presence"):
145+
scope="read_station read_camera access_camera write_camera " \
146+
"read_presence access_presence write_presence read_thermostat write_thermostat"):
141147

142148
postParams = {
143149
"grant_type" : "password",
@@ -148,6 +154,8 @@ def __init__(self, clientId=_CLIENT_ID,
148154
"scope" : scope
149155
}
150156
resp = postRequest(_AUTH_REQ, postParams)
157+
if not resp: raise AuthFailure("Authentication request rejected")
158+
151159
self._clientId = clientId
152160
self._clientSecret = clientSecret
153161
self._accessToken = resp['access_token']
@@ -188,6 +196,54 @@ def __init__(self, authData):
188196
self.devList = self.rawData['devices']
189197
self.ownerMail = self.rawData['user']['mail']
190198

199+
200+
class ThermostatData:
201+
"""
202+
List the Thermostat and temperature modules
203+
204+
Args:
205+
authData (clientAuth): Authentication information with a working access Token
206+
"""
207+
def __init__(self, authData):
208+
self.getAuthToken = authData.accessToken
209+
postParams = {
210+
"access_token" : self.getAuthToken
211+
}
212+
resp = postRequest(_GETTHERMOSTATDATA_REQ, postParams)
213+
self.rawData = resp['body']['devices']
214+
if not self.rawData : raise NoDevice("No thermostat available")
215+
self.thermostat = { d['_id'] : d for d in self.rawData }
216+
for t,v in self.thermostat.items():
217+
v['name'] = v['station_name']
218+
for m in v['modules']:
219+
m['name'] = m['module_name']
220+
self.defaultThermostat = self.rawData[0]['station_name']
221+
self.defaultThermostatId = self.rawData[0]['_id']
222+
self.defaultModule = self.rawData[0]['modules'][0]
223+
224+
def getThermostat(self, name=None, tid=None):
225+
if tid:
226+
if tid in self.thermostat.keys():
227+
return self.thermostat[tid]
228+
else:
229+
return None
230+
elif name:
231+
for t in self.thermostat.values():
232+
if t['name'] == name: return t
233+
return None
234+
return self.thermostat[self.defaultThermostatId]
235+
236+
def moduleNamesList(self, name=None, tid=None):
237+
thermostat = self.getThermostat(name=name, tid=tid)
238+
return [m['name'] for m in thermostat['modules']] if thermostat else None
239+
240+
def getModuleByName(self, name, thermostatId=None):
241+
thermostat = self.getThermostat(tid=thermostatId)
242+
for m in thermostat['modules']:
243+
if m['name'] == name: return m
244+
return None
245+
246+
191247
class WeatherStationData:
192248
"""
193249
List the Weather Station devices (stations and modules)

samples/printThermostat

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#!/usr/bin/python3
2+
# encoding=utf-8
3+
4+
# 2018-02 : ph.larduinat@wanadoo.fr
5+
6+
# Thermostat basic sample
7+
8+
import sys
9+
import lnetatmo
10+
11+
authorization = lnetatmo.ClientAuth()
12+
thermostat = lnetatmo.ThermostatData(authorization)
13+
14+
15+
defaultThermostat = thermostat.getThermostat()
16+
if not defaultThermostat : sys.exit(1)
17+
defaultModule = thermostat.defaultModule
18+
19+
print('Thermostat name :', defaultThermostat['name'])
20+
print('Default module :', defaultModule['name'])
21+
print('Module measured temp :', defaultModule['measured']['temperature'])
22+
print('Module set point :', defaultModule['measured']['setpoint_temp'])
23+
print('Module battery : %s%%' % defaultModule['battery_percent'])
24+
for p in defaultModule['therm_program_list']:
25+
print("\tProgram: ", p['name'])
26+
for z in p['zones']:
27+
name = z['name'] if 'name' in z else '<noname>'
28+
print("\t%15s : %s" % (name, z['temp']))

0 commit comments

Comments
 (0)