Skip to content

Commit 919ed43

Browse files
committed
added nest connector
1 parent 449dc3c commit 919ed43

File tree

3 files changed

+279
-0
lines changed

3 files changed

+279
-0
lines changed

config/nest.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"credentials": {
3+
"PIN": "NBCFUAG4",
4+
"Product_id": "89d2d205-3297-419f-9405-9115c33e7881",
5+
"Product_secret": "01XrOHyiXTLzgCX0e5VTcebGe",
6+
"access_token": "c.Msbr1TYGaNit1p6qPdklCuAH4usOM64JWH8hgKrEIByEdOzpDyesA5JiEU12m4NmGSaJ0IOldRzcY6qdOieCX54bC51tqAcFGaSCQiPgLdbvudy5WvAjjSd01u4QKP5nUeJY0gbhbatD4og6"
7+
},
8+
"url": {
9+
"_AUTH_REQ": "https://api.home.nest.com/oauth2/access_token",
10+
"_DEVICELIST_REQ": "https://developer-api.nest.com/devices?auth="
11+
}
12+
}

nest/NEST-CLASS.py

Lines changed: 267 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,267 @@
1+
import json
2+
import requests
3+
from bd_connect.connect_bd import get_json
4+
from config.setting import Setting
5+
from pprint import pprint
6+
7+
'''
8+
About:
9+
This module is a connector that connects any Nest device to the
10+
Building DepotV3.1 with the help of the bd connect program.
11+
12+
Configuration:
13+
To be able to have the program access your Nest data, you have
14+
to register your program as a Nest app in your Netatmo account at
15+
https://develper.nest.com. You have to go on create new product, choose
16+
the appropriate permissions and enter the required details in the
17+
nest_config.json file. The pin code can be received by clicking on
18+
the authorization url.
19+
20+
'''
21+
22+
class ClientAuth(object):
23+
'''
24+
Class definition to get the access token, it does not need to be
25+
refreshed
26+
'''
27+
def __init__(self, credentials_file = "nest"):
28+
'''
29+
Recieves the credentials from the config file and executes the
30+
setup function to get the access token
31+
32+
Args:
33+
credentials_file: The json file containing the Product ID, Product
34+
Secret, PIN and the access token (which is
35+
obtained from the other information if not
36+
present). It is in the config folder with the
37+
default name "nest".
38+
'''
39+
self.credentials_file = credentials_file
40+
self.setup()
41+
42+
def setup(self):
43+
'''
44+
Obtains the access token if present and calls the access_token()
45+
function if the access_token is not present, using the Product Id,
46+
Product Secret, and PIN.
47+
48+
Args as Data:
49+
Product_id: #product id of the registered product
50+
Product_secret: #product secret of the registered product
51+
PIN: #generated by clicking on the authorization url,
52+
must be updated after every use
53+
access_token: #needed for access. If it is not present, the
54+
other three args are used to generate it.
55+
'''
56+
credentials = Setting(self.credentials_file)
57+
self.urls = credentials.setting["url"]
58+
self._accessToken = credentials.setting["credentials"]["access_token"]
59+
# get the access token
60+
61+
if (self._accessToken == ""):
62+
# generate access token if it is not present
63+
self.code, self.client_id, self.client_secret = (
64+
credentials.setting["credentials"]["PIN"],
65+
credentials.setting["credentials"]["Product_id"],
66+
credentials.setting["credentials"]["Product_secret"])
67+
self.access_token()
68+
self.devices = dict() # generate an empty dictionary for all NEST
69+
# devices linked to the account
70+
71+
def access_token(self):
72+
'''
73+
Update the access_token if it is not present in the config file
74+
'''
75+
76+
url = self.urls["_AUTH_REQ"]
77+
params = {"code": self.code, "client_id": self.client_id,
78+
"client_secret": self.client_secret,
79+
"grant_type": "authorization_code"}
80+
81+
response = requests.post(url, params = params)
82+
try:
83+
self._accessToken = response.json()["access_token"]
84+
except:
85+
self._accessToken = None
86+
print(response)
87+
88+
class DeviceList(object):
89+
'''
90+
Class definition of Nest to obtain the Nest device data and
91+
update the data in the Building depot.
92+
'''
93+
94+
def __init__(self, authData):
95+
'''
96+
Initilize the auth token and obtain the device modules data
97+
of NEST
98+
Args as data:
99+
"authData": class object of ClientAuth provides
100+
access token.
101+
'''
102+
self.getAuthToken = authData._accessToken
103+
url = (authData.urls["_DEVICELIST_REQ"] + self.getAuthToken)
104+
header = {"Authorization": "Bearer " + self.getAuthToken}
105+
response = requests.get(url, headers = header, allow_redirects=True)
106+
try:
107+
self.devices = response.json()
108+
except:
109+
print(response)
110+
111+
def deviceByType(self, deviceType = "smoke_co_alarms"):
112+
'''
113+
Find the Nest data by device type (eg. thermostats,
114+
smoke_co_alarms). If none given finds all the data of the each
115+
Nest device connected to the given account
116+
117+
Args as data:
118+
"deviceType": device type (eg. thermostats, smoke_co_alarms)
119+
'''
120+
if deviceType == None: return self.devices
121+
try:
122+
return self.devices[deviceType]
123+
except:
124+
print("No devices of such type")
125+
return None
126+
127+
def deviceByID(self, deviceType = "smoke_co_alarms", deviceID = None):
128+
'''
129+
Find the Nest data by device ID, i.e. a specific device.
130+
If none given finds all the data of the each
131+
Nest device connected to the given account
132+
133+
Args as data:
134+
"deviceType": device type
135+
"deviceID": unique ID to identify the device
136+
'''
137+
if deviceType == None or deviceID == None: return self.devices
138+
try:
139+
return self.devices[deviceType][deviceID]
140+
except:
141+
print("Device ID does not exist or is not connected to this \
142+
account")
143+
return None
144+
145+
def deviceByName(self, deviceName = None):
146+
'''
147+
Find the Nest data by device Name, i.e. the name give to
148+
a specific Nest Device.If none given finds all the data of the each
149+
Nest device connected to the given account.
150+
151+
Nest has two names, name_long and name, we recommend using
152+
name_long as multiple devices of different types can have the
153+
same name.
154+
155+
Args as data:
156+
"deviceName": Name given to the specific device
157+
'''
158+
if deviceName == None: return self.devices
159+
for deviceType in self.devices:
160+
typeList = self.devices[deviceType]
161+
for deviceID in typeList:
162+
deviceData = typeList[deviceID]
163+
if (deviceData["name"] == deviceName or
164+
deviceData["name_long"] == deviceName):
165+
return deviceData
166+
print("No devices with given name")
167+
return None
168+
169+
def get_device_data(self, deviceType = "smoke_co_alarms",
170+
deviceID = None, deviceName = None):
171+
'''
172+
Obtain the data of all NEST devices of a particular device in the
173+
form of a dictionary.
174+
175+
Args as data:
176+
deviceType: the type of nest device (eg. thermostats,
177+
smoke_co_alarms)
178+
deviceID: unique ID of the device. The device type must be
179+
that of the device.
180+
deviceName: Name given to the device.
181+
182+
Returns:
183+
184+
{
185+
u"co_alarm_state": #whether the state is ok or not.
186+
187+
u"smoke_alarm_state": #whether the state is ok or not
188+
189+
U"battery_health": #whether the state is ok or not
190+
}
191+
192+
'''
193+
194+
if (deviceID != None and deviceType != None):
195+
data = self.deviceByID(deviceType, deviceID)
196+
elif (deviceName != None):
197+
data = self.deviceByName(deviceName)
198+
else:
199+
print("Please enter a valid deviceID or deviceName")
200+
data = None
201+
202+
if (data == None):
203+
return
204+
205+
nest_data = {}
206+
nest_data["co_alarm_state"] = data["co_alarm_state"]
207+
nest_data["smoke_alarm_state"] = data["smoke_alarm_state"]
208+
nest_data["battery_health"] = data["battery_health"]
209+
nest_data["mac_id"] = data["device_id"]
210+
return nest_data
211+
212+
def post_to_bd(self, deviceData):
213+
"""
214+
Post json object information to BD_Connect in this format
215+
data={"sensor_data":{<all sensor data>}}
216+
217+
Args as data:
218+
{<netatmo station data>}
219+
Returns:
220+
{
221+
"success": "True"
222+
"HTTP Error 400": "Bad Request"
223+
}
224+
"""
225+
data = {'sensor_data': {}}
226+
data['sensor_data'].update(deviceData)
227+
response = get_json(json.dumps(data))
228+
return response
229+
230+
if __name__ == "__main__":
231+
"""
232+
Reads the data from Nest Protect Devices and writes it to the building
233+
depot.
234+
235+
Returns:
236+
{
237+
"success": "True"
238+
"HTTP Error 400": "Bad Request"
239+
}
240+
else
241+
{
242+
"Error in Device Connection"
243+
}
244+
"""
245+
from sys import exit, stderr
246+
247+
try:
248+
auth = ClientAuth() # Get authentication key
249+
if (auth._accessToken == None):
250+
stderr.write("Please Enter the valid credentials to get\
251+
the access token")
252+
exit(1)
253+
254+
devList = DeviceList(auth) # Obtain the DEVICELIST
255+
nest_data = devList.deviceByType() # Get the data for the type of
256+
# devices
257+
for device_id in nest_data:
258+
try:
259+
device_data = devList.get_device_data(deviceID = device_id)
260+
resp = devList.post_to_bd(device_data)
261+
# Send Data to the BuildingDepot
262+
print "Response from connect_bd.py:\n", resp
263+
except Exception as e:
264+
print "Error in Sending data to connect_bd.py", e
265+
266+
except Exception as e:
267+
print "Error in Device Connection", e

nest/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)