Back to photostream

Arduino Powered Flickr Meter

View on Black

 

After viewing the Arduino powered internet meter at // vimeo.com/15312319, I decided to make my own, but with some improvements. Instead of checking gmail unread email counts like the video, I chose to write an interface to access Flickr using their REST protocol using python. Once I had the python code working on my laptop, I used google's app engine code.google.com/appengine/ to host my script, so that I didn't need to worry about needing a webserver to host the CGI executable.

 

I was also wanting to have the Arduino use DHCP to get it's IP address from my router, instead of having it hard-coded into the Arduino source code. A quick google search found 2 compatable DHCP client implementations, but I decided to use the implementation at blog.jordanterrell.com/post/Arduino-DHCP-Library-Version-.... I then based the rest of my sketch on their web client with DHCP client source code example.

 

An issue with the Arduino which I haven't been able to get around is that you cannot use a URL to access the server, you need to use an IP address. Because of this, additional code is required to go from the google search page to my google app engine application. I found an example at javagwt.blogspot.com/2010/10/arduino-ethernet-to-app-engi....

 

Once I had the Arduino connecting to my google app engine application, I just needed some glue logic to process the result returned by the script, to drive the panel meter, and some status LED's. The LED's show the following information:

 

- An IP address has been allocated to the Arduino / Arduino not connected to the network

- A connection has been made to the google app engine application

- An LED to indicate that the Arduino is participating in a 60 second delay to the next poll of the application.

 

The panel meter displays display counts up to 1000, so the 0.2 on the meter indicates that around 200 views have been recorded when this photograph was taken.

 

The source code loaded into the Arduino is as follows (sorry flickr removes formatting):

 

/*------------------------------------------------------------------------------

 

Arduino powered Flickr Meter

Jason Hilsdon, October 2010

 

Idea inspired from video by Matt Richardson (vimeo.com/15312319)

 

DHCP client library sourced from

blog.jordanterrell.com/post/Arduino-DHCP-Library-Version-...

 

Google App Engine connection code derived from

javagwt.blogspot.com/2010/10/arduino-ethernet-to-app-engi...

 

------------------------------------------------------------------------------*/

#include

#include "Dhcp.h"

#include

 

// hardware analog & digital pin assignments

int delayPin = 9; // delay LED blink

int noNetworkPin = 8; // not connected to network

int networkConnected = 7; // connected to network

int googleConnected = 6; // connected to google app engine application

int flickrMeter = 3; // pwm output

 

boolean delayStatus;

 

// network interface

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };

byte server[] = { 66, 102, 11, 104 }; // IP address to Google

boolean ipAcquired = false;

int readData[4];

int idx;

boolean startData = false;

 

// client connection to google

Client client(server, 80);

 

void setup()

{

// enable serial port monitor

Serial.begin(9600);

 

// I/O pin assignments

pinMode(noNetworkPin, OUTPUT);

pinMode(networkConnected, OUTPUT);

pinMode(delayPin, OUTPUT);

pinMode(googleConnected, OUTPUT);

pinMode(flickrMeter, OUTPUT);

 

// set I/O pin default values

digitalWrite(networkConnected, LOW);

digitalWrite(noNetworkPin, HIGH);

digitalWrite(delayPin, LOW);

digitalWrite(googleConnected, LOW);

analogWrite(flickrMeter, 0);

 

delayStatus = false;

 

// wait until network interface has valid IP address

while(true)

{

if(nicInit())

{

Serial.print("connecting to server: ");

printArray(&Serial, ".", server, 4, 10);

googleConnect();

break;

}

else

{

Serial.println("Unable to initialize network interface ...");

delay(1000);

}

}

}

 

// main program loop

void loop()

{

for(;;)

{

if(ipAcquired)

{

if (client.available())

{

// flickr view count has pipe symbol

// for prefix & suffix characters

// (to allow for parsing from HTML header)

char c = client.read();

char * cp = &c; // pointer to allow atoi()

if (c == '|')

{

if (startData)

{

startData = false;

idx--;

}

else

{

idx = 0;

startData = true;

return;

}

}

if (startData)

{

readData[idx] = atoi(cp);

idx++;

}

}

 

// if we have all the data from the web request,

// process it

if (!client.connected())

{

int viewCount = 0;

 

if (idx == 0)

{

// < 10 read count

viewCount = readData[0];

}

 

if (idx == 1)

{

// println();

}

 

// method to connect to google app engine to get result to process by Arduino

void googleConnect()

{

while(true)

{

if (client.connect())

{

digitalWrite(googleConnected, HIGH);

client.println("GET /service/currentvalue?point=test&email=gmail@gmail.com HTTP/1.1");

client.println("Host:googleappengineapp.appspot.com"); //here is your app engine url

client.println("Accept-Language:en-us,en;q=0.5");

client.println("Accept-Encoding:gzip,deflate");

client.println("Connection:close");

client.println("Cache-Control:max-age=0");

client.println();

break;

}

else

{

digitalWrite(googleConnected, LOW);

Serial.println("connection failed");

delay(1000);

}

}

}

 

// Method to calculate PWM value to send to analog port.

// PWM has 255 possible values, need to convert max value of 1000

// down to a value 0 ~ 255.

int PVMValue(int value)

{

 

return round((value / 1000.0) * 255.0);

}

 

// function to provide delay of minutes, with a 1 second blink

void Sleep(int seconds, boolean blink)

{

for(int i=0; i < seconds; i++)

{

if (blink)

{

Serial.println("Sleeping ...");

if (delayStatus)

{

digitalWrite(delayPin, LOW);

delayStatus = false;

}

else

{

digitalWrite(delayPin, HIGH);

delayStatus = true;

}

}

delay(1000);

}

}

 

Google app engine script is as follows (note won't compile due to flickr removing formatting):

 

import time

import string

import flickr

import hashlib

 

signatureParams = {}

 

def getData():

return flickr._dopost(signatureParams["method"], auth=True, date=signatureParams["date"])

 

def genSignature():

keys = signatureParams.keys()

keys.sort()

 

signature = flickr.API_SECRET

for k in keys:

signature = signature + k + signatureParams[k]

 

return hashlib.md5(signature).hexdigest()

 

def getDate():

utctoday = time.gmtime()

return "%s-%s-%s" % (utctoday.tm_year, string.zfill(utctoday.tm_mon, 2), string.zfill(utctoday.tm_mday, 2))

 

def main():

flickr.API_KEY="Flickr API Key goes here"

flickr.API_SECRET="Flickr API Key secret goes here"

token = flickr.userToken()

 

signatureParams["auth_token"] = token

signatureParams["api_key"] = flickr.API_KEY

signatureParams["method"] = "flickr.stats.getTotalViews"

signatureParams["date"] = getDate()

signatureParams["signature"] = genSignature()

 

data = getData()

 

print 'Content-Type: text/plain'

print ''

print "|" + str(data.rsp.stats.total.views) + "|"

 

if __name__ == "__main__":

main()

 

Photo Blog: Visual Clarity Photography

 

iOS Wallpaper Blog: iOS Wallpaper

 

Redbubble

9,786 views
4 faves
8 comments
Uploaded on October 31, 2010
Taken on October 31, 2010