-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
279 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
{ | ||
"credentials": { | ||
"PIN": "NBCFUAG4", | ||
"Product_id": "89d2d205-3297-419f-9405-9115c33e7881", | ||
"Product_secret": "01XrOHyiXTLzgCX0e5VTcebGe", | ||
"access_token": "c.Msbr1TYGaNit1p6qPdklCuAH4usOM64JWH8hgKrEIByEdOzpDyesA5JiEU12m4NmGSaJ0IOldRzcY6qdOieCX54bC51tqAcFGaSCQiPgLdbvudy5WvAjjSd01u4QKP5nUeJY0gbhbatD4og6" | ||
}, | ||
"url": { | ||
"_AUTH_REQ": "https://api.home.nest.com/oauth2/access_token", | ||
"_DEVICELIST_REQ": "https://developer-api.nest.com/devices?auth=" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,267 @@ | ||
import json | ||
import requests | ||
from bd_connect.connect_bd import get_json | ||
from config.setting import Setting | ||
from pprint import pprint | ||
|
||
''' | ||
About: | ||
This module is a connector that connects any Nest device to the | ||
Building DepotV3.1 with the help of the bd connect program. | ||
Configuration: | ||
To be able to have the program access your Nest data, you have | ||
to register your program as a Nest app in your Netatmo account at | ||
https://develper.nest.com. You have to go on create new product, choose | ||
the appropriate permissions and enter the required details in the | ||
nest_config.json file. The pin code can be received by clicking on | ||
the authorization url. | ||
''' | ||
|
||
class ClientAuth(object): | ||
''' | ||
Class definition to get the access token, it does not need to be | ||
refreshed | ||
''' | ||
def __init__(self, credentials_file = "nest"): | ||
''' | ||
Recieves the credentials from the config file and executes the | ||
setup function to get the access token | ||
Args: | ||
credentials_file: The json file containing the Product ID, Product | ||
Secret, PIN and the access token (which is | ||
obtained from the other information if not | ||
present). It is in the config folder with the | ||
default name "nest". | ||
''' | ||
self.credentials_file = credentials_file | ||
self.setup() | ||
|
||
def setup(self): | ||
''' | ||
Obtains the access token if present and calls the access_token() | ||
function if the access_token is not present, using the Product Id, | ||
Product Secret, and PIN. | ||
Args as Data: | ||
Product_id: #product id of the registered product | ||
Product_secret: #product secret of the registered product | ||
PIN: #generated by clicking on the authorization url, | ||
must be updated after every use | ||
access_token: #needed for access. If it is not present, the | ||
other three args are used to generate it. | ||
''' | ||
credentials = Setting(self.credentials_file) | ||
self.urls = credentials.setting["url"] | ||
self._accessToken = credentials.setting["credentials"]["access_token"] | ||
# get the access token | ||
|
||
if (self._accessToken == ""): | ||
# generate access token if it is not present | ||
self.code, self.client_id, self.client_secret = ( | ||
credentials.setting["credentials"]["PIN"], | ||
credentials.setting["credentials"]["Product_id"], | ||
credentials.setting["credentials"]["Product_secret"]) | ||
self.access_token() | ||
self.devices = dict() # generate an empty dictionary for all NEST | ||
# devices linked to the account | ||
|
||
def access_token(self): | ||
''' | ||
Update the access_token if it is not present in the config file | ||
''' | ||
|
||
url = self.urls["_AUTH_REQ"] | ||
params = {"code": self.code, "client_id": self.client_id, | ||
"client_secret": self.client_secret, | ||
"grant_type": "authorization_code"} | ||
|
||
response = requests.post(url, params = params) | ||
try: | ||
self._accessToken = response.json()["access_token"] | ||
except: | ||
self._accessToken = None | ||
print(response) | ||
|
||
class DeviceList(object): | ||
''' | ||
Class definition of Nest to obtain the Nest device data and | ||
update the data in the Building depot. | ||
''' | ||
|
||
def __init__(self, authData): | ||
''' | ||
Initilize the auth token and obtain the device modules data | ||
of NEST | ||
Args as data: | ||
"authData": class object of ClientAuth provides | ||
access token. | ||
''' | ||
self.getAuthToken = authData._accessToken | ||
url = (authData.urls["_DEVICELIST_REQ"] + self.getAuthToken) | ||
header = {"Authorization": "Bearer " + self.getAuthToken} | ||
response = requests.get(url, headers = header, allow_redirects=True) | ||
try: | ||
self.devices = response.json() | ||
except: | ||
print(response) | ||
|
||
def deviceByType(self, deviceType = "smoke_co_alarms"): | ||
''' | ||
Find the Nest data by device type (eg. thermostats, | ||
smoke_co_alarms). If none given finds all the data of the each | ||
Nest device connected to the given account | ||
Args as data: | ||
"deviceType": device type (eg. thermostats, smoke_co_alarms) | ||
''' | ||
if deviceType == None: return self.devices | ||
try: | ||
return self.devices[deviceType] | ||
except: | ||
print("No devices of such type") | ||
return None | ||
|
||
def deviceByID(self, deviceType = "smoke_co_alarms", deviceID = None): | ||
''' | ||
Find the Nest data by device ID, i.e. a specific device. | ||
If none given finds all the data of the each | ||
Nest device connected to the given account | ||
Args as data: | ||
"deviceType": device type | ||
"deviceID": unique ID to identify the device | ||
''' | ||
if deviceType == None or deviceID == None: return self.devices | ||
try: | ||
return self.devices[deviceType][deviceID] | ||
except: | ||
print("Device ID does not exist or is not connected to this \ | ||
account") | ||
return None | ||
|
||
def deviceByName(self, deviceName = None): | ||
''' | ||
Find the Nest data by device Name, i.e. the name give to | ||
a specific Nest Device.If none given finds all the data of the each | ||
Nest device connected to the given account. | ||
Nest has two names, name_long and name, we recommend using | ||
name_long as multiple devices of different types can have the | ||
same name. | ||
Args as data: | ||
"deviceName": Name given to the specific device | ||
''' | ||
if deviceName == None: return self.devices | ||
for deviceType in self.devices: | ||
typeList = self.devices[deviceType] | ||
for deviceID in typeList: | ||
deviceData = typeList[deviceID] | ||
if (deviceData["name"] == deviceName or | ||
deviceData["name_long"] == deviceName): | ||
return deviceData | ||
print("No devices with given name") | ||
return None | ||
|
||
def get_device_data(self, deviceType = "smoke_co_alarms", | ||
deviceID = None, deviceName = None): | ||
''' | ||
Obtain the data of all NEST devices of a particular device in the | ||
form of a dictionary. | ||
Args as data: | ||
deviceType: the type of nest device (eg. thermostats, | ||
smoke_co_alarms) | ||
deviceID: unique ID of the device. The device type must be | ||
that of the device. | ||
deviceName: Name given to the device. | ||
Returns: | ||
{ | ||
u"co_alarm_state": #whether the state is ok or not. | ||
u"smoke_alarm_state": #whether the state is ok or not | ||
U"battery_health": #whether the state is ok or not | ||
} | ||
''' | ||
|
||
if (deviceID != None and deviceType != None): | ||
data = self.deviceByID(deviceType, deviceID) | ||
elif (deviceName != None): | ||
data = self.deviceByName(deviceName) | ||
else: | ||
print("Please enter a valid deviceID or deviceName") | ||
data = None | ||
|
||
if (data == None): | ||
return | ||
|
||
nest_data = {} | ||
nest_data["co_alarm_state"] = data["co_alarm_state"] | ||
nest_data["smoke_alarm_state"] = data["smoke_alarm_state"] | ||
nest_data["battery_health"] = data["battery_health"] | ||
nest_data["mac_id"] = data["device_id"] | ||
return nest_data | ||
|
||
def post_to_bd(self, deviceData): | ||
""" | ||
Post json object information to BD_Connect in this format | ||
data={"sensor_data":{<all sensor data>}} | ||
Args as data: | ||
{<netatmo station data>} | ||
Returns: | ||
{ | ||
"success": "True" | ||
"HTTP Error 400": "Bad Request" | ||
} | ||
""" | ||
data = {'sensor_data': {}} | ||
data['sensor_data'].update(deviceData) | ||
response = get_json(json.dumps(data)) | ||
return response | ||
|
||
if __name__ == "__main__": | ||
""" | ||
Reads the data from Nest Protect Devices and writes it to the building | ||
depot. | ||
Returns: | ||
{ | ||
"success": "True" | ||
"HTTP Error 400": "Bad Request" | ||
} | ||
else | ||
{ | ||
"Error in Device Connection" | ||
} | ||
""" | ||
from sys import exit, stderr | ||
|
||
try: | ||
auth = ClientAuth() # Get authentication key | ||
if (auth._accessToken == None): | ||
stderr.write("Please Enter the valid credentials to get\ | ||
the access token") | ||
exit(1) | ||
|
||
devList = DeviceList(auth) # Obtain the DEVICELIST | ||
nest_data = devList.deviceByType() # Get the data for the type of | ||
# devices | ||
for device_id in nest_data: | ||
try: | ||
device_data = devList.get_device_data(deviceID = device_id) | ||
resp = devList.post_to_bd(device_data) | ||
# Send Data to the BuildingDepot | ||
print "Response from connect_bd.py:\n", resp | ||
except Exception as e: | ||
print "Error in Sending data to connect_bd.py", e | ||
|
||
except Exception as e: | ||
print "Error in Device Connection", e |
Empty file.