Friday, 5 July 2013

Step 5 - Adding a piechart

So now I have an Arduino project that:
  • Reads the temperature every 5 mins
  • Displays it on an LCD which updates just before every post
  • Posts the temperature to a Google datastore
  • Have created a Google web app using python that displays the results using a html front end

So the website is a bit boring, it 's just a table. Now I want to prettify it using jquery tabs and some of my own css but I also want to display my data graphically.

It was late when I decided to try this and so I literally tried the first example I found which happened to be a piechart. So the Idea was to have a table displaying the last 20 records on one tab and the piechart on the second tab. It wasn't too difficult to get it working however I don't use python much and so getting the correct syntax took a little googling.

Another fairly major issue was the fact that Google App Engine uses a query language called GQL which I believe stands for Google Query Language. This has a similar syntax to normal SQL but again I had to learn how to write (my rather simple queries) in python using examples from Google.
I'll probably refactor this and add to it many times and so don't be alarmed if the code looks terrible.
I want to log my progress.....Actually that might give me a new section to this project -- version control.... hmm I may do that next. If I do that then I'll just link to my project.

It'll be on Github coming soon.

Step 4 - serial lcd

I bought a serial enabled 16x2 LCD from amazon so that I could display the current temperature without having to go to my phone or computer. I guess that would be the reason but really it was just to see if I could. It turns out that it was very easy to get this working.

Note. I used a 09393 serial enabled 16x2 LCD. Some serial LCD don't work with the Arduino board so just make sure to do some research before buying one! I think you need one that has a TTL serial input. The link to it on Amazon is here.

There are quite a few examples and tutorials out there on the web and some did not work for me. Some required adding libraries and they did not work well for me. The simple built in Arduino code worked well and so I was happy using it. Here is the tutorial I followed. I 'll post up my updated sketch with a picture later.

Wednesday, 3 July 2013

Step 3 - Google App for my Arduino sketch

Googles documentation on creating apps is very good. The link to get you started is here.
To get you started you initially write the html as strings in the main python file but it is much cleaner to keep your html separate using templates and that's what I ended up doing.

My app folder looks like this:

-- temp_monitor
    -- stylesheets
        -- main.css
    -- templates
        -- new_temperature.html
    -- app.yaml
    -- favicon.ico
    -- monitor.py


Note. If you don't add a favicon.ico file every time you deploy your app you'll get an error in the log which is really annoying but harmless. DeGraeve is a great website to create your own icon.

I got the stylesheet from csstablegenerator.com. Just make sure that the CSS Class Name is the same as the class name in your div in the html.

The dates are read and written in UTC and I could not find a really easy way to change the timezone to e.g. 'Europe/London'. Because I use DateTimeProperty(auto_now_add=True) the date is effectively a created_at timestamp that I don't have to insert manually, which is exactly what I wanted. It would be nice to have something like DateTimeProperty(auto_now_add=True, time_zone='Europe/London') but I'm not sure it's possible or I don't know how to implement it. If anyone has any ideas I'd really like to know. So I'm happy for now to keep it simple. This is a useful blog about timezones.

app.yaml


application: temp-monitor
version: 1
runtime: python27
api_version: 1
threadsafe: true

handlers:
- url: /favicon\.ico
  static_files: favicon.ico
  upload: favicon\.ico

- url: /stylesheets
  static_dir: stylesheets

- url: /.*
  script: monitor.application

libraries:
- name: webapp2
  version: "2.5.1"
- name: jinja2
  version: latest

monitor.py


import webapp2
import cgi
import os
import jinja2
import datetime
from google.appengine.ext import db
from google.appengine.ext.webapp.util import run_wsgi_app


class Temperature(db.Model):
temperature_field = db.StringProperty(required=True)
date_field = db.DateTimeProperty(auto_now_add=True)

class PostFromArduino(webapp2.RequestHandler):
    def post(self):
        temperature = self.request.get("temperature")
        self.temperature = Temperature(temperature_field=temperature)
        self.temperature.put()
        self.redirect('/')

class MainPage(webapp2.RequestHandler):

    def get(self):
      jinja_environment = jinja2.Environment(autoescape = True,
        loader = jinja2.FileSystemLoader(os.path.join(
         os.path.dirname(__file__), 'templates')))
      template = jinja_environment.get_template('new_temperature.html')

      temp_query = Temperature.all()
      temp_query.order("-date_field")
      #temp = temp_query.fetch(10)

      template_values = {
        'temperatures': temp_query
      }

      self.response.out.write(template.render(template_values))


application = webapp2.WSGIApplication([
    ('/', MainPage),
    ('/post_from_arduino', PostFromArduino)
], debug=True)

def main():
    run_wsgi_app(application)
if __name__ == '__main__':
    main()


templates/new_temperature.html


<!doctype html>
<html lang="en">
  <head>
  <link type="text/css" rel="stylesheet" href="/stylesheets/main.css" />
    <meta charset="utf-8"/>
    <title>Room Temperature Application</title>
  </head>
  <body>
    <h1>Room Temperature Application</h1>
    <div class='css_table'>
      <table>
        <tr>
        <td>Temperature ˚C</td>
        <td>Date</td>
        </tr>
        {% for temperature in temperatures.run(limit=10): %}
        <tr>
          <td>{{ temperature.temperature_field }}</td>
          <td>{{ temperature.date_field.strftime("%Y-%m-%d %H:%M:%S") }}</td>
        </tr>
        {% endfor %}
      </table>
    </div>  
  </body>
</html>

Step 2 - Arduino sketch

Below is the sketch I created, essentially merging the basic temperature sketch with some code I found
online for the post request. At the time of writing I believe that Arduino cannot convert a float to a string and I was scratching my head over this for quite a while. I don't have a C programming background and so that didn't help. Anyway I found a patch which did exactly what I wanted here however please note that it is probably not a great idea to patch Arduino files because an update could break it. Please post other ways to tackle this.


#include "SPI.h"
#include "Ethernet.h"

void postData();
void getTemp();

//Data
float temperature = 0.00;
int temperaturePin = 0;

// Enter a MAC address of your Arduino board that should be stuck to the bottom of the board
byte mac[] = {  0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX };
//Server to connect to
char serverName[] = "http://temp-monitor.appspot.com";
// Initialize the Ethernet client library
EthernetClient client;

void setup()
{
  Serial.begin(9600);
  // start the Ethernet connection:
  if (Ethernet.begin(mac) == 0)
  {
    while(true);
  }
  // give the Ethernet shield a second to initialize:
  delay(1000);
}

void loop()
{
  delay(60000);
  getTemp();
  postData();
}

void postData()
{
  String data = String("temperature="+ String(temperature,2));
  Serial.println(data);
  while(!client.connected())
  {
    client.connect(serverName, 80);
  }
  client.println("POST / HTTP/1.1"); # The first slash is the part of the url that the data will post to. The default slash will post to the default MainPage post method in your google app. This can be changed to whatever you want
  client.println("Host: temp-monitor.appspot.com");
  client.println("Connection: keep-alive");
  client.print("Content-Length: ");
  client.println(data.length());
  client.println("Cache-Control: max-age=0");
  client.println("Content-Type: application/x-www-form-urlencoded");
  client.println("Accept-Language: en-US,en;q=0.8");
  client.println();
  client.print(data);
  client.println();
  char c;
  while(client.available())
  {
    c = client.read();
  }
  client.stop();
}

float getVoltage(int pin){
  return (analogRead(pin) * .004882814);
}

void getTemp()
{
  //temperature = (((temperature - 0.5) * 100)*1.8) + 32;
  temperature = (getVoltage(temperaturePin) - .5) * 100;
}




Below is a simple diagram I took from another site Arduino Tutorial Bundle.


Step 1 - Google App Engine - GAE?

So I figured out that I wanted to use Google App Engine but I never even knew it existed before I did some research for this project, so where do I start? I contemplated not even posting these details as they are fairly straight forward.

Search for google app engine on Google and follow the continue links to hello world app. I don't think it's necessary for me to regurgitate this information. I will point out that I used python as I didn't want to use the other options.

So after you have stepped through that tutorial you will have a projects folder and the google app engine SDK.

I recommend that you register your application if you haven't already here. Make sure your happy with the name because you can't change it as far as I know.


Getting Started

I am starting this blog to record all the steps that I have taken in order to create my finished application. So what is this cloud project I hope to create? Well if you have seen some of my other posts at khawe-mind-dump you might have saw a post discussing my first Arduino app... the first one recorded anyway. This app took the temperature periodically and saved the result locally to a MySQL database.

However, I now want to build on this application to record results on the cloud but I want to build it up in small increments. After a bit of googling I decided that Google App Engine was my best fit as it has both front end and back end support and has something that resembles a database. Below are the steps I want to take:

  1. Book up on Google App engine. Create hello world app. Test locally.
  2. Create Google app account and push helloworld app to cloud.
  3. Book up on how to post to my google app from arduino.
  4. Use Arduino temperature logger sketch and amend it to use google app post. 
  5. Once I'm happy with it, I may want to create an enclosure.

Additional steps
  1. Add serial lcd. Output temperture.
  2. Add motion sensor.
  3. Replace temperature component with a better one which also detects humidity.
  4. Maybe add light sensor.
  5. Add additional values to cloud and lcd.
  6. Clean up google app code, requires more booking up e.g. use templates etc
Secondary

  1. I will want, at some point, to create a post back from a google app to display on my lcd but not sure if this should be incorporated in this project or if I should make a separate project for it.