Connecting to Smart Home Devices

For those curious, below is the script library I have created so far for getting data back from my Nest thermostat. It requires walking through the first few steps of the guide @matthew.ayre posted in the sixth reply to this thread before you’re able to use it though. I have this saved as a script named ‘devices.nest’.

project_id = 'your-project-id-here'
client_id = 'your-client-id-here'
client_secret = 'your-client-secret-here'
redirect_uri = 'https://www.google.com'
device_id = 'your-device-id-here'
code = 'your-code-here'
scope = 'https://www.googleapis.com/auth/sdm.service'
basePath = '[default]Devices/Nest/'
accessTokenPath = basePath + 'Access Token'
refreshTokenPath = basePath + 'Refresh Token'
tokenTimePath = basePath + 'Token Timestamp'
namePath = basePath + 'Device Name'
humidityFbkPath = basePath + 'Current Humidity'
tempFbkPath = basePath + 'Current Temperature'
modeFbkPath = basePath + 'Current Mode'
stateFbkPath = basePath + 'Current State'
heatSpPath = basePath + 'Heat Setpoint'
coolSpPath = basePath + 'Cool Setpoint'
commsFbkPath = basePath + 'Comms'

# This can be called from the script console after configuring Google's security permissions to grant access to your Nest device
def getToken():
	url = 'https://www.googleapis.com/oauth2/v4/token?client_id=' + client_id + '&client_secret=' + client_secret + '&code=' + code + '&grant_type=authorization_code&redirect_uri=' + redirect_uri

	response = system.net.httpPost(url=url, postData={})
	json = system.util.jsonEncode(response)
	access_token = json['access_token']
	refresh_token = json['refresh_token']
	system.tag.writeAsync([accessTokenPath, refreshTokenPath], [access_token, refresh_token])
	comments = """Access token: %d
				Refresh token:  %d""" % (access_token, refresh_token)
	return comments

# Refresh the access token and write it to the Access Token memory tag
def refreshToken():
	url = 'https://www.googleapis.com/oauth2/v4/token'
	refresh_token = system.tag.readBlocking([refreshTokenPath])[0].value
	postParams = {
				'client_id'		: client_id,
				'client_secret'	: client_secret,
				'refresh_token'	: refresh_token,
				'grant_type'	: 'refresh_token'
				}
			
	response = system.net.httpPost(url, postParams)
	
	json = system.util.jsonDecode(response)
	access_token = json['access_token']
	timestamp = system.date.now()
	system.tag.writeAsync([accessTokenPath, tokenTimePath], [access_token, timestamp])
	comments = 'Access token: ' + access_token
	return comments

# Build out the headerValues argument used in most of the system.net.httpGet() API calls
def getHeaders():
	access_token = system.tag.readBlocking([accessTokenPath])[0].value
	return {
			'Content-Type'	: 'application/json',
			'Authorization'	: 'Bearer ' + access_token,
			}
	
# Convert celsius temperatures to fahrenheit
def cToF(temp):
	return (temp * 9/5) + 32

# Convert fahrenheit temperatures to celsius
def fToC(temp):
	return (temp - 32) * 5/9

# Write the current values return from the Nest API to my pre-defined tags.
def getCurrentValues():
	deviceName = system.tag.readBlocking([namePath])[0].value
	url = 'https://smartdevicemanagement.googleapis.com/v1/' + deviceName
	headers = getHeaders()
	response = system.util.jsonDecode(system.net.httpGet(url, headerValues=headers))
	
	paths =		[
				humidityFbkPath,
				tempFbkPath,
				coolSpPath,
				heatSpPath,
				modeFbkPath,
				stateFbkPath,
				commsFbkPath
				]
	
	traits = response['traits']
	sp = traits['sdm.devices.traits.ThermostatTemperatureSetpoint']
	comms = False
	if str(traits['sdm.devices.traits.Connectivity']['status']) == 'ONLINE':
		comms = True
	tempC = traits['sdm.devices.traits.Temperature']['ambientTemperatureCelsius']
	coolSpC = sp['coolCelsius']
	heatSpC = sp['heatCelsius']
	
	values =	[
				traits['sdm.devices.traits.Humidity']['ambientHumidityPercent'],
				cToF(tempC),
				cToF(coolSpC),
				cToF(heatSpC),
				traits['sdm.devices.traits.ThermostatMode']['mode'],
				traits['sdm.devices.traits.ThermostatHvac']['status'],
				comms
				]
	
	system.tag.writeAsync(paths, values)

I am hardcoding my constant variables at the top of the script and anything else that could change in the future I’m writing to memory tags. I have all my Nest related memory tags kept in a folder at [default]Devices/Nest/, personally.

I update the values by simply using a gateway event timer script that runs once a minute that looks something like this:

try:
	devices.nest.getCurrentValues()
except:
	devices.nest.refreshToken()

So far, my script only handles reading values back from the Nest. Eventually I’ll bother with writing data back out to the API, but this is all I care to do at the moment while I fuss with connecting the rest of my smart things to this project.

3 Likes