-
Notifications
You must be signed in to change notification settings - Fork 2
/
mynest.py
288 lines (241 loc) · 12.2 KB
/
mynest.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
import requests
import json
# As instructed here: https://developers.google.com/nest/device-access/get-started
# register for access to the Google API with a Google user account (the app account) ($5 charge)
# https://console.nest.google.com/device-access
# have your Nest device registered to a google user account (mine are the same, but need not be)
# (the device account).
# I have two nest thermostats, one is still in the old WorksWithNest setup.
# I set up the other one in my google account.
# Allow access to the device in the device account
# in google credentials setup an OAuth https://console.developers.google.com/apis/credentials
# put them here
oauth2clientid = 'your oauth2clientid'
clientsecret = 'your clientsecret'
# with the app account create a project and give it the OAuth credentials
# save that here
projectid = 'your projectid'
# from the device account give access to the nest for the app account (even if they are the same)
# with this URL (make sure it is all one line, replace project-id and oauth2-client-id)
# https://nestservices.google.com/partnerconnections/project-id/auth?
# redirect_uri=https://www.google.com&
# access_type=offline&
# prompt=consent&
# client_id=oauth2-client-id&
# response_type=code&
# scope=https://www.googleapis.com/auth/sdm.service
#
# you will get a response:
# https://www.google.com?code=authorization_code&scope=https://www.googleapis.com/auth/sdm.service
#
# save the code here:
authorization_code = 'your authorization_code'
# now this module is ready to use
# tokens are saved in a file and kept as module globals while running the module
access_token = ''
refresh_token = ''
# Now we can request an access code and refresh code
# this only works once, so we have to save/saved the results. See if we have results already
def request_tokens():
global oauth2clientid
global clientsecret
global access_token
global refresh_token
try:
with open('.mynest.json') as json_file:
data = json.load(json_file)
access_token = data['access_token']
refresh_token = data['refresh_token']
print('access token:', access_token)
print('refresh token:', refresh_token)
except FileNotFoundError:
request_token_url = 'https://www.googleapis.com/oauth2/v4/token'
params = {'client_id': oauth2clientid,
'client_secret': clientsecret,
'code': authorization_code,
'grant_type': 'authorization_code',
'redirect_uri': 'https://www.google.com'}
request_token_resp = requests.post(request_token_url, params=params)
print(json.dumps(request_token_resp.content, indent=4))
if request_token_resp.status_code != 200:
print(request_token_resp.status_code)
else:
access_token = request_token_resp.json()['access_token']
refresh_token = request_token_resp.json()['refresh_token']
print('access token:', access_token)
print('refresh token:', refresh_token)
# safe the tokens in a json file
with open('.mynest.json', 'w') as json_file:
json.dump(request_token_resp.json(), json_file)
# access token is valid for an hour then you need to request new one
def refresh_access():
global access_token
refresh_url = 'https://www.googleapis.com/oauth2/v4/token?'
params = {'client_id': oauth2clientid,
'client_secret': clientsecret,
'refresh_token': refresh_token,
'grant_type': 'refresh_token'}
refresh_resp = requests.post(refresh_url, params=params)
if refresh_resp.status_code != 200:
print(refresh_resp.status_code)
else:
print(json.dumps(refresh_resp.json(), indent=4))
access_token = refresh_resp.json()['access_token']
print('new access token:', access_token)
# now you can get data:
def get_device_status():
url = 'https://smartdevicemanagement.googleapis.com/v1/enterprises/' + projectid + '/devices'
headers = {'Content-Type': 'application/json', 'Authorization': 'Bearer ' + access_token}
resp = requests.get(url, headers=headers)
if resp.status_code != 200:
print(resp.status_code)
refresh_access()
print(access_token)
headers = {'Content-Type': 'application/json', 'Authorization': 'Bearer ' + access_token}
print(headers)
resp = requests.get(url, headers=headers)
print('content = ', json.dumps(resp.json(), indent=4))
nest = resp.json()
deviceid = nest['devices'][0]['name']
print('Device Type:', nest['devices'][0]['type'])
roomkey = nest['devices'][0]['assignee']
print('Device Traits:', json.dumps(nest['devices'][0]['traits'], indent=4))
print('Humidity:', nest['devices'][0]['traits']['sdm.devices.traits.Humidity']['ambientHumidityPercent'])
print('FanMode:', nest['devices'][0]['traits']['sdm.devices.traits.Fan']['timerMode'])
nestmode = nest['devices'][0]['traits']['sdm.devices.traits.ThermostatMode']['mode']
ecomode = nest['devices'][0]['traits']['sdm.devices.traits.ThermostatEco']['mode']
neststate = nest['devices'][0]['traits']['sdm.devices.traits.ThermostatHvac']['status']
# not bothering with HEATCOOL mode and returning two temperatures
ttarget = float('NAN')
if ecomode == 'OFF':
if nestmode == 'HEAT':
ttarget = nest['devices'][0]['traits']['sdm.devices.traits.ThermostatTemperatureSetpoint'][
'heatCelsius'] * 9 / 5 + 32
if nestmode == 'COOL':
ttarget = nest['devices'][0]['traits']['sdm.devices.traits.ThermostatTemperatureSetpoint'][
'coolCelsius'] * 9 / 5 + 32
temperature = nest['devices'][0]['traits']['sdm.devices.traits.Temperature'][
'ambientTemperatureCelsius'] * 9 / 5 + 32
return roomkey, deviceid, nestmode, neststate, ttarget, temperature, ecomode
# structures are quite limited, all you can get it the name
def get_structure_status():
url = 'https://smartdevicemanagement.googleapis.com/v1/enterprises/' + projectid + '/structures'
headers = {'Content-Type': 'application/json', 'Authorization': 'Bearer ' + access_token}
resp = requests.get(url, headers=headers)
if resp.status_code != 200:
print(resp.status_code)
refresh_access()
print('New access token:', access_token)
headers = {'Content-Type': 'application/json', 'Authorization': 'Bearer ' + access_token}
resp = requests.get(url, headers=headers)
print("Structure:", json.dumps(resp.json(), indent=4))
structure = resp.json()['structures'][0]['traits']['sdm.structures.traits.Info']['customName']
return structure
# rooms are quite limited, all you can get is the name
def get_room_status(roomid):
url = 'https://smartdevicemanagement.googleapis.com/v1/' + roomid
headers = {'Content-Type': 'application/json', 'Authorization': 'Bearer ' + access_token}
resp = requests.get(url, headers=headers)
if resp.status_code != 200:
print(resp.status_code)
refresh_access()
print('New access token:', access_token)
headers = {'Content-Type': 'application/json', 'Authorization': 'Bearer ' + access_token}
resp = requests.get(url, headers=headers)
print(resp.status_code)
roomname = resp.json()['traits']['sdm.structures.traits.RoomInfo']['customName']
return roomname
# execute a command
def set_eco_mode(deviceid, ecomode):
url = 'https://smartdevicemanagement.googleapis.com/v1/' + deviceid + ':executeCommand'
print('url:', url)
headers = {'Content-Type': 'application/json', 'Authorization': 'Bearer ' + access_token}
data = {'command': 'sdm.devices.commands.ThermostatEco.SetMode',
'params': {'mode': ecomode}}
# data = {'command': 'sdm.devices.commands.ThermostatMode.SetMode',
# 'params': {'mode': 'HEAT'}}
resp = requests.post(url, headers=headers, data=json.dumps(data))
print(resp.status_code)
print("execute_response:", resp.content)
def set_fan_mode(deviceid, fanmode):
url = 'https://smartdevicemanagement.googleapis.com/v1/' + deviceid + ':executeCommand'
print('url:', url)
headers = {'Content-Type': 'application/json', 'Authorization': 'Bearer ' + access_token}
data = {'command': 'sdm.devices.commands.Fan.SetTimer',
'params': {'timerMode': fanmode,
'duration': '1200s'}}
resp = requests.post(url, headers=headers, data=json.dumps(data))
print(resp.status_code)
print("execute_response:", resp.content)
def temperature_setheat(deviceid, setpoint):
url = 'https://smartdevicemanagement.googleapis.com/v1/' + deviceid + ':executeCommand'
print('url:', url)
headers = {'Content-Type': 'application/json', 'Authorization': 'Bearer ' + access_token}
data = {'command': 'sdm.devices.commands.ThermostatTemperatureSetpoint.SetHeat',
'params': {'heatCelsius': (setpoint-32)/9*5}}
resp = requests.post(url, headers=headers, data=json.dumps(data))
print("execute_response:", resp.content)
return resp.status_code
def temperature_setcool(deviceid, setpoint):
url = 'https://smartdevicemanagement.googleapis.com/v1/' + deviceid + ':executeCommand'
print('url:', url)
headers = {'Content-Type': 'application/json', 'Authorization': 'Bearer ' + access_token}
data = {'command': 'sdm.devices.commands.ThermostatTemperatureSetpoint.SetCool',
'params': {'coolCelsius': (setpoint-32)/9*5}}
resp = requests.post(url, headers=headers, data=json.dumps(data))
print("execute_response:", resp.content)
return resp.status_code
def temperature_setrange(deviceid, heatesetpoint, coolsetpoint):
url = 'https://smartdevicemanagement.googleapis.com/v1/' + deviceid + ':executeCommand'
print('url:', url)
headers = {'Content-Type': 'application/json', 'Authorization': 'Bearer ' + access_token}
data = {'command': 'sdm.devices.commands.ThermostatTemperatureSetpoint.SetRange',
'params': {
'heatCelsius': (heatesetpoint-32)/9*5,
'coolCelsius': (coolsetpoint-32)/9*5}}
resp = requests.post(url, headers=headers, data=json.dumps(data))
print("execute_response:", resp.content)
return resp.status_code
def set_hvac_mode(deviceid, mode):
url = 'https://smartdevicemanagement.googleapis.com/v1/' + deviceid + ':executeCommand'
print('url:', url)
headers = {'Content-Type': 'application/json', 'Authorization': 'Bearer ' + access_token}
data = {'command': 'sdm.devices.commands.ThermostatMode.SetMode',
'params': {
'mode': mode}}
resp = requests.post(url, headers=headers, data=json.dumps(data))
print("execute_response:", resp.content)
return resp.status_code
def main():
request_tokens()
roomid, deviceid, nestmode, neststate, ttarget, temperature, ecomode = get_device_status()
myhouse = get_structure_status()
myroom = get_room_status(roomid)
print('===============End Result============')
print('Myhouse:', myhouse)
print('Myroom:', myroom)
print('Temperature:', temperature)
print('NestMode:', nestmode)
print('NestState:', neststate)
print('TTarget:', ttarget)
print('ECO Mode: ', ecomode)
if ecomode == 'MANUAL_ECO':
set_eco_mode(deviceid, 'OFF')
set_hvac_mode(deviceid, 'HEAT')
if ttarget % 2 < 1:
temperature_setheat(deviceid, ttarget + 1)
else:
temperature_setheat(deviceid, ttarget - 1)
input('Check that temperature setpoint changed?')
set_hvac_mode(deviceid, 'COOL')
temperature_setcool(deviceid, 76)
answer = input('Should I run the fan for 20 minutes (y/N)?')
if answer == 'y':
set_fan_mode(deviceid, 'ON')
roomid, deviceid, nestmode, neststate, ttarget, temperature, ecomode = get_device_status()
print('Nest Mode:', nestmode)
print('ttarget:', ttarget)
set_hvac_mode(deviceid, 'HEAT')
if __name__ == '__main__':
main()
# end of file