Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make pynest installable via pip, split pynest.py into an main program and a library, and move from urllibX to requests #9

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 1 addition & 119 deletions nest.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,125 +21,7 @@
import urllib2
import sys
from optparse import OptionParser

try:
import json
except ImportError:
try:
import simplejson as json
except ImportError:
print "No json library available. I recommend installing either python-json"
print "or simpejson."
sys.exit(-1)

class Nest:
def __init__(self, username, password, serial=None, index=0, units="F"):
self.username = username
self.password = password
self.serial = serial
self.units = units
self.index = index

def loads(self, res):
if hasattr(json, "loads"):
res = json.loads(res)
else:
res = json.read(res)
return res

def login(self):
data = urllib.urlencode({"username": self.username, "password": self.password})

req = urllib2.Request("https://home.nest.com/user/login",
data,
{"user-agent":"Nest/1.1.0.10 CFNetwork/548.0.4"})

res = urllib2.urlopen(req).read()

res = self.loads(res)

self.transport_url = res["urls"]["transport_url"]
self.access_token = res["access_token"]
self.userid = res["userid"]

def get_status(self):
req = urllib2.Request(self.transport_url + "/v2/mobile/user." + self.userid,
headers={"user-agent":"Nest/1.1.0.10 CFNetwork/548.0.4",
"Authorization":"Basic " + self.access_token,
"X-nl-user-id": self.userid,
"X-nl-protocol-version": "1"})

res = urllib2.urlopen(req).read()

res = self.loads(res)

self.structure_id = res["structure"].keys()[0]

if (self.serial is None):
self.device_id = res["structure"][self.structure_id]["devices"][self.index]
self.serial = self.device_id.split(".")[1]

self.status = res

#print "res.keys", res.keys()
#print "res[structure][structure_id].keys", res["structure"][self.structure_id].keys()
#print "res[device].keys", res["device"].keys()
#print "res[device][serial].keys", res["device"][self.serial].keys()
#print "res[shared][serial].keys", res["shared"][self.serial].keys()

def temp_in(self, temp):
if (self.units == "F"):
return (temp - 32.0) / 1.8
else:
return temp

def temp_out(self, temp):
if (self.units == "F"):
return temp*1.8 + 32.0
else:
return temp

def show_status(self):
shared = self.status["shared"][self.serial]
device = self.status["device"][self.serial]

allvars = shared
allvars.update(device)

for k in sorted(allvars.keys()):
print k + "."*(32-len(k)) + ":", allvars[k]

def show_curtemp(self):
temp = self.status["shared"][self.serial]["current_temperature"]
temp = self.temp_out(temp)

print "%0.1f" % temp

def set_temperature(self, temp):
temp = self.temp_in(temp)

data = '{"target_change_pending":true,"target_temperature":' + '%0.1f' % temp + '}'
req = urllib2.Request(self.transport_url + "/v2/put/shared." + self.serial,
data,
{"user-agent":"Nest/1.1.0.10 CFNetwork/548.0.4",
"Authorization":"Basic " + self.access_token,
"X-nl-protocol-version": "1"})

res = urllib2.urlopen(req).read()

print res

def set_fan(self, state):
data = '{"fan_mode":"' + str(state) + '"}'
req = urllib2.Request(self.transport_url + "/v2/put/device." + self.serial,
data,
{"user-agent":"Nest/1.1.0.10 CFNetwork/548.0.4",
"Authorization":"Basic " + self.access_token,
"X-nl-protocol-version": "1"})

res = urllib2.urlopen(req).read()

print res
from pynest.pynest import Nest

def create_parser():
parser = OptionParser(usage="nest [options] command [command_options] [command_args]",
Expand Down
Empty file added pynest/__init__.py
Empty file.
132 changes: 132 additions & 0 deletions pynest/pynest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
#! /usr/bin/python

# nest.py -- a python interface to the Nest Thermostat
# by Scott M Baker, [email protected], http://www.smbaker.com/
# updated by Bob Pasker [email protected] http://pasker.net
#
# Licensing:
# This is distributed unider the Creative Commons 3.0 Non-commecrial,
# Attribution, Share-Alike license. You can use the code for noncommercial
# purposes. You may NOT sell it. If you do use it, then you must make an
# attribution to me (i.e. Include my name and thank me for the hours I spent
# on this)
#
# Acknowledgements:
# Chris Burris's Siri Nest Proxy was very helpful to learn the nest's
# authentication and some bits of the protocol.

import urllib
import urllib2
import requests

try:
import json
except ImportError:
import simplejson as json

class Nest:
def __init__(self, username, password, serial=None, index=0, units="F", debug=False):
self.username = username
self.password = password
self.serial = serial
self.units = units
self.index = index
self.debug = debug

def login(self):

response = requests.post("https://home.nest.com/user/login",
data = {"username":self.username, "password" : self.password},
headers = {"user-agent":"Nest/1.1.0.10 CFNetwork/548.0.4"})

response.raise_for_status()

res = response.json()
self.transport_url = res["urls"]["transport_url"]
self.access_token = res["access_token"]
self.userid = res["userid"]
# print self.transport_url, self.access_token, self.userid

def get_status(self):
response = requests.get(self.transport_url + "/v2/mobile/user." + self.userid,
headers={"user-agent":"Nest/1.1.0.10 CFNetwork/548.0.4",
"Authorization":"Basic " + self.access_token,
"X-nl-user-id": self.userid,
"X-nl-protocol-version": "1"})

response.raise_for_status()
res = response.json()

self.structure_id = res["structure"].keys()[0]

if (self.serial is None):
self.device_id = res["structure"][self.structure_id]["devices"][self.index]
self.serial = self.device_id.split(".")[1]

self.status = res

#print "res.keys", res.keys()
#print "res[structure][structure_id].keys", res["structure"][self.structure_id].keys()
#print "res[device].keys", res["device"].keys()
#print "res[device][serial].keys", res["device"][self.serial].keys()
#print "res[shared][serial].keys", res["shared"][self.serial].keys()

def temp_in(self, temp):
if (self.units == "F"):
return (temp - 32.0) / 1.8
else:
return temp

def temp_out(self, temp):
if (self.units == "F"):
return temp*1.8 + 32.0
else:
return temp

def show_status(self):
shared = self.status["shared"][self.serial]
device = self.status["device"][self.serial]

allvars = shared
allvars.update(device)

for k in sorted(allvars.keys()):
print k + "."*(32-len(k)) + ":", allvars[k]

def show_curtemp(self):
temp = self.status["shared"][self.serial]["current_temperature"]
temp = self.temp_out(temp)

print "%0.1f" % temp

def _set(self, data, which):
if (self.debug): print json.dumps(data)
url = "%s/v2/put/%s.%s" % (self.transport_url, which, self.serial)
if (self.debug): print url
response = requests.post(url,
data = json.dumps(data),
headers = {"user-agent":"Nest/1.1.0.10 CFNetwork/548.0.4",
"Authorization":"Basic " + self.access_token,
"X-nl-protocol-version": "1"})

if response.status_code > 200:
if (self.debug): print response.content
response.raise_for_status()
return response

def _set_shared(self, data):
self._set(data, "shared")

def _set_device(self, data):
self._set(data, "device")

def set_temperature(self, temp):
return self._set_shared({
"target_change_pending": True,
"target_temperature" : self.temp_in(temp)
})

def set_fan(self, state):
return self._set_device({
"fan_mode": str(state)
})
2 changes: 2 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,6 @@
author_email='[email protected]',
url='http://www.smbaker.com/',
scripts=['nest.py'],
packages=['pynest'],
install_requires = ['requests']
)