Sunday, January 29, 2012

Step Six: Getting Started with Google App Engine

In order to store all this useful data with minimal thinking about databases etc. Google App Engine is an easy choice.


Warning:

I hope that this post illustrates how using only 2-3 dozen lines of code, we have a 'free' web-based datastore for this project. What follows is a primer for future posts where we will tie everything together.


Google App Engine will allow us to easily handle the Arduino's requests, store data, and let us retrieve data to display in a web browser.


To get started with Google App Engine you can sign up at: appengine.google.com.


For the purposes of this blog/tutorial, I will assume that you have some working knowledge of App Engine, that you can gain by working through the python tutorial.


If you are very technical, hopefully you can likely stich together a working app using this blog and source code provided alone (without completing the tutorial).


Once you are up and running with the App Engine Launcher and have created your first application, it's quite simple to log data.


The Model:
class DailyWeatherEntry(db.Model):
date = db.IntegerProperty()
temp_entry = db.TextProperty()
humidity_entry = db.TextProperty()
view raw gistfile1.py hosted with ❤ by GitHub

Since database reads / writes are limited (and we want to keep within App Engine's free-quota limits), storing a day of entries in a single string will be a hacky-effective solution.

I am also storing the date as a unix timestamp integer to remove some complexity of working with timestamps when it's time to graph them.


Defining an API:
Quite simply, the Arduino will pass a temperature and humidity value. Our Google App Engine application will receive these values, and record them to the database. An example request might look like:
myproject.appspot.com/t=7205&h=4302 which represents an entry of 72.05 degrees F and 43.02% humidity. Timestamp isn't required because that is handled server side.



Handling Requests from the Arduino:
The following code is heavily commented, and all records are formatted to be super-friendly to use with Flot (javascript based graphing library) in future posts.
class Weather(webapp.RequestHandler):
def get(self):
temp = str(float(cgi.escape(self.request.get('t')))/100) #Convert from Arduino's 4 digit format
humidity = str(float(cgi.escape(self.request.get('h')))/100)
# Determine timestamp of now and one day ago to micro-manage database records
rightNow = int(time.time())
dayAgo = rightNow-86400
# Get a record that is within the last day
recent_record = DailyWeatherEntry.gql("WHERE date > :1 ORDER BY date DESC",dayAgo)
# Convert timestamp to a string for appending to other strings
rightNow = str(rightNow)
# If there is an existing record for the past day, append the well-formed entry (for easily graphing later)
if recent_record.count()!=0:
dayObj = recent_record[0] # First record if any exist
dayObj.temp_entry = dayObj.temp_entry + '['+rightNow+','+temp+'],' # Formatting here is for use with Flot (js graphing library)
dayObj.humidity_entry = dayObj.humidity_entry + '['+rightNow+','+humidity+'],'
dayObj.put() # This writes the new entry to the datastore
# Otherwise there isn't an entry within the past day, create a new one
else:
newEntry = DailyWeatherEntry(
date = int(time.time()),
temp_entry = '['+rightNow+','+temp+'],',
humidity_entry = '['+rightNow+','+humidity+'],'
)
newEntry.put()
self.response.headers.add_header("X-Arduino-Data", temp +','+ humidity )
view raw gistfile1.py hosted with ❤ by GitHub

The above code will be used to handle requests made from the Arduino. Note the use of the X-Arduino-Data header. This will be used for debugging the Arduino sketch.


Displaying Posts:
This code will be used to handle requests from the browser in order to display our temperature/humidity records from the datastore:
class ShowWeather(webapp.RequestHandler):
def get(self):
the_weather = db.GqlQuery(
"SELECT * FROM DailyWeatherEntry ORDER BY date ASC")
template_values = {
'weather' : the_weather,
#'debug' : debug
}
path = os.path.join(os.path.dirname(__file__), 'weather.html')
self.response.out.write(template.render(path, template_values))
view raw gistfile1.py hosted with ❤ by GitHub



Confused? Probably. We'll be pulling everything together in the next post(s).


TLDR;

In order to proceed you need a Google App Engine account and basic understanding of App Engine. We can make use of Google App Engine using only 2-3 dozen lines of code. The next few posts will bring everything together.

No comments:

Post a Comment