The temperature is also continually graphed here
The Appengine code
#!/usr/bin/env python
#This is a Google Appengine Python script; it will only run properly on Google Appengine.
#This code processes data sent from an Arduino (only temperature and light readings)
#It will send a tweet when the light is turned on, and then again when the light is turned off. It is not designed for daylight.
#This code also sends the data from the Arduino to Xively so it can be graphed.
#NOTE: This page is not password protected, so if someone finds out your URL they can send false readings to the server. Keep your URL private.
#For this code to work properly, you also need a file called “app.yaml” in the same folder as this script, “app.yaml” must contain this code;
“””
application: appID
version: 1
runtime: python27
api_version: 1
threadsafe: no
handlers:
– url: /myscript
script: myscript.app
“””
#Do NOT include the “”” at the top and bottom
#Replace “appID” with the name of your application, you can create one at appengine.google.com
#Replace “myscript.app” with the filename of this script (leave .app on the end)
import webapp2 #Required by Google Appengine
from google.appengine.api import urlfetch #Required to send web requests to Xively
import datetime #This is required to determine the current date/time
from google.appengine.api import memcache #This is required for accessing memcache
import logging #Required for printing debugging information to Appengine
import tweepy #This is not included and must be downloaded manually from github.com/tweepy/tweepy
#This information is found on your Twitter account at dev.twitter.com/apps
consumer_key=”Your key”
consumer_secret=”Your secret”
access_token=”Your access token”
access_token_secret=”Your access token secret”
class MainHandler(webapp2.RequestHandler):
def get(self): #This function is called each time there is a HTTP GET request to this URL (/myscript)
temperature = self.request.get(‘temperature’) #This gets any data stored in the URL parameter ‘temperature’
if temperature:
#This code runs when the URL paramter ‘temperature’ is found (sent by the Arduino)
memcache.set(‘temperature’, temperature) #If the temperature was included in the HTTP request, save it into Memcache
#Memcache is temporary storage similar to RAM
light = self.request.get(‘light’) #Get the current light value from the ‘light’ URL parameter (sent from the Arduino)
lastlight = memcache.get(‘lastlight’) #Get the light value from the last request (if it exists)
#This is set later on in the code so we can compare the value between each request
#This code sends both the light and temperature to Xively (A free website which graphs your data)
urlfetch.set_default_fetch_deadline(40) #If the connection to Xively takes more than 40 seconds, cancel it (timeout)
toSend = ‘temperature, ‘ + temperature + “””
“”” + ‘light, ‘ + light #Construct the data (the temperature and light value) so it can be sent.
try:
url = ‘https://api.xively.com/v2/feeds/FEEDID.csv’ #Replace ‘FEEDID’ with the ID of your Xively page
result = ”
result = urlfetch.fetch(url=url,
method=urlfetch.PUT, #This tells Appengine to make a PUT request to Xively (which is the recommended way of sending it)
payload=toSend, #This tells Appengine to put the value of ‘toSend’ into the PUT request
headers={‘Pragma’: ‘no-cache’,
‘X-ApiKey’: ‘YOUR_API_KEY’}) #Replace ‘YOUR_API_KEY’ with your Xively API key
except:
logging.warning(‘Unable to reach xively’) #If we can’t connect to Xively, print a warning message into the Appengine logs
if str(lastlight) == ” or str(lastlight) == ‘None’: #This checks to see if the value of ‘lastlight’ is valid
lastlight = 0 #If the data isn’t valid, set it to ‘0’
if str(light) == ” or str(light) == ‘None’: #This checks the value of ‘light’ to ensure it’s valid
light = 0 #If it isn’t valid, make it ‘0’
light = int(light) #Ensure the variables are both integers
lastlight = int(lastlight)
memcache.set(‘lastlight’, light) #Save the value of ‘lastlight’ into memcache. This allows us to compare it with future values
lighton = False #Create boolean variables called ‘lighton’ and ‘confirmed’
confirmed = False
if light > 525: #If the light reading is more than 525, the light is turned on
#(You will most likely need to change this for your environment)
logging.debug(‘Light is ON’)
#This code runs when the light is CURRENTLY greater than 525 (eg, the light is on)
if lastlight > 525:
#This code runs when the light is CURRENTLY on AND it was on last time we checked
logging.debug(‘Confirmed’)
lighton = True #The light was on the last 2 times we checked, so that means we can be certain the light is really on
confirmed = True
else:
logging.debug(‘Light is OFF’)
if lastlight < 525:
#The light is currently off, and it was off last time we checked; we can be certain the light is really off
logging.debug(‘Confirmed’)
lighton = False
confirmed = True
if confirmed == False:
#The light has changed (eg, the light was turned on or off) but we will wait until we get another message from the Arduino..
#..so we can be certain about the change. (This stops the tweet from being triggered every time someone walks in front of the light sensor)
logging.debug(“Light status changed but waiting for another message from the Arduino”)
return
lasttweet = memcache.get(‘lasttweet’) #When we make a tweet saying ‘light on’ we set this to True, and we set..
#.. it to false whenever we tweet ‘light off’
auth = tweepy.OAuthHandler(consumer_key, consumer_secret) #These are needed for the Twitter library to work
auth.set_access_token(access_token, access_token_secret)
api = tweepy.API(auth)
logging.info(‘logged in as ‘ + str(api.me().name)) #Show the currently logged in user (to Twitter) into the Appengine logs
if lasttweet == True: #The last tweet sent was saying ‘lights on’
if lighton == True: #Currently, the lights are on
#Because the last tweet sent was saying ‘lights on’ and the lights are still on, we don’t need to Tweet again
logging.debug(“The light is on and a tweet was sent earlier”)
memcache.set(‘lasttweet’, True)
return
if lighton == False: #The last tweet sent was ‘lights on’ but the lights are now off, send a tweet.
logging.debug(“The light has been turned off, will send a tweet saying CLOSED”)
memcache.set(‘lasttweet’, False)
api.update_status(‘We turned off our lights at ‘ + str(datetime.datetime.now().time())[:5])
#This posts “We turned off our lights at 14:32” (or whatever time it is) to your Twitter account
return
if lasttweet == False: #The last tweet we sent said ‘lights off’
if lighton == True: #Currently the lights are on, and the last tweet said they were off..
#This means we need to send a tweet saying the lights are now on
logging.debug(“The light has been turned on, will send a tweet saying OPEN”)
memcache.set(‘lasttweet’, True)
api.update_status(‘We turned on our lights at ‘ + str(datetime.datetime.now().time())[:5] + ‘ and the temperature was ‘ + temperature + ‘.C’)
#This posts “We turned on our lights at 08:47 and the temperature was 23.42.C” for example
return
if lighton == False:
#The last tweet sent was saying ‘lights off’ and they’re still off, we don’t need to tweet again.
logging.debug(“The light is off and a tweet was sent earlier”)
memcache.set(‘lasttweet’, False)
return
if lasttweet == None:
#If the value of ‘lasttweet’ is missing, set it to False and then do nothing until the next message from the Arduino
logging.warning(“No lasttweet value, assuming False.”)
memcache.set(‘lasttweet’, False) #Sets ‘lasttweet’ to False in Memcache
return
else:
logging.warning(‘No temperature was sent’) #No temperature was sent, log a warning to the Appengine logs
#Your arduino should request “/myscript?temperature=22.64&light=453” (but substituting the current values in).
#This part of the code only runs when the “?temperature=” part is missing. Check the Arduino code.
app = webapp2.WSGIApplication([
(‘/myscript’, MainHandler) #Run the function ‘MainHandler’ every time the URL ‘/myscript’ is visited.
], debug=True)