Thermostat Logging / Datamining

So, I’m not so fancy as to have a Nest thermostat or anything, but I do have access to two WiFi enabled thermostats that have a closed-source app for iOS and Android, and a closed source web app. These tools are nice, but lack a lot of useful features. The company who made these did, however, release a public API which is pretty useful. Unfortunately, the thermostats never really caught on in the developer or the consumer world. There are a few people online who do work on them, and I’ve managed to figure a few things out.

The thermostats I have access to are marketed under either Radio Thermostat CT50 or Filtrete 3M-50.

The API has a few versions (I haven’t been able to tell a significant difference) that is published here.

–Update-– That link is now broken – Radio Thermostat have since taken down their API documentation. Here’s a copy of the API documentation.

The API works great–but the thermostats do take a bit of time to respond to any GET or POST actions. For instance, my python script that polls them takes about 5 seconds to come back with any data.

So, I set up a mySQL database, user, and table for my project.  Easy enough. Then I wrote a script in Python to grab a few bits of information from the thermostat, like current temperature, commanded temperature, fan state, and thermostat state. Each thermostat has the ability to store a name for itself, so that’s in there too.

But I wanted the ability to compare my data to outside temperature (ie, get a DeltaT) in order to see the outside temperature’s effect on the inside.  So, I looked around, and remembered some work I’d done with Weather Underground.  They have a free API that allows me up to 10 calls a minute!  I’d only use about 1 every 5 minutes.  So I signed up for that and read through the documentation and was able to get what I wanted and much, much more.  That API can be found here.

My simple python script to grab this:

#!usr/bin/env python

import radiotherm
#much thanks to Michael Hrivnak <mhrivnak@hrivnak.org> for his simple library!
#i wrote a similar thing in java when i did this project version 1, this is way easier.
#plus I learned mySQL, Python, php, and other stuff during this project. vs my old stupid method
import MySQLdb
import time
import urllib2
import json #jaaaaaaaaason

#this small script grabs the temp for where the thermostats are located:raleigh, nc
#weather underground key:131beb0f35b8df99
#wunderground gives nice json! examples can be found on their website. most of this script is directly from their website.
f = urllib2.urlopen('http://api.wunderground.com/api/******************/geolookup/conditions/q/NC/Raleigh.json')
json_string = f.read()
parsed_json = json.loads(json_string)
temp_f = parsed_json['current_observation']['temp_f']
f.close()

#logging into the mysql server
#the ol classic pw!
db = MySQLdb.connect(host="localhost",
user="monitor",
passwd="*************",
db="Temps")

cur = db.cursor() #setting the cursor for the sql database

#start to use this nice library.
def getinfo(ip):
tstat = radiotherm.get_thermostat(ip)
#tstat.temp & dicts use dicts as output.

temp = tstat.temp['raw'] #this grabs the raw value of temp from the therm and puts into a float
FanState = tstat.fstate['raw'] #this grabs the raw value of fan on or off
ThermState = tstat.tstate['raw'] #this grabs raw value of thermostat commanding cool, heat, off
tname = tstat.name['raw'] #name of thermostat given by the radio thermostat company
comm = tstat.t_cool['raw'] #commanded temp, not sure the difference b/w t_cool and it_cool
return {'temp':temp, 'FanState':FanState ,'ThermState':ThermState,'ThermName':tname,'comm':comm}

def writeinfo(dict):
try:
cur.execute("INSERT INTO tempdat VALUES (CURDATE(),NOW(),%s,%s,%s,%s,%s,%s)", (dict['ThermName'],dict['temp'],dict['ThermState'],dict['FanState'],temp_f,dict['comm'])

db.commit()
print "nData Committed!" , dict['ThermName']except:
print "Error in committing, rolling back!"
db.rollback()

#while 1: #used to have it run in a while loop, cron is waaaaaaaay better.

#these IPs are internal LAN addresses that won't change. I've set them up as static in my router.
#The database entries will automatically know which is downstairs and upstairs
writeinfo(getinfo('192.168.0.13'))
writeinfo(getinfo('192.168.0.16'))

#this was for tshooting/seeing the database grow, too big now! =P

#cur.execute ("SELECT * FROM tempdat")

#print "nDate Time Zone Temperature ThermState FanState Outside Commanded"
#print "============================================================================================"

#for reading in cur.fetchall():
#print str(reading[0])+" "+str(reading[1])+" "+
# reading[2]+" "+str(reading[3])+" "+str(reading[4])+" "+ str(reading[5])+" "+str(reading[6])+" "+str(reading[7])

#time.sleep(300) #more for the old dumb while loop

db.close()