Search

Twitter API 1.1 update for the candy machine

Twitter API 1.1 update for the candy machine

**************************************
Author’s note:
PLEASE NOTE THAT I NOW USE AN L293 MOTOR DRIVER IC RATHER THAN JUST A TRANSISTOR
PLEASE DO NOT RUN THIS CODE WITHOUT MODIFYING YOUR CIRCUIT TO MATCH

I do this so that I can move the motor forwards for 2 seconds to dispense the candy and then reverse for 1 second which pulls any candy that has not yet fell back inside the machine so it can be moved safely without the candy falling out everywhere.
I will include an updated schematic, as well as the current version of my code in the next day or so. If I forget, feel free to remind me :)
The updated version is pretty cool – it telnets to a networked HP printer and updates the LCD display on the printer with the name of whoever tweeted me :D
A silly but fun hack that could easily be extended or retasked for other uses.
**************************************

I realised that I have not yet updated my blog to show how I have managed to get around the recent change to the way the Twitter API 1.1 works.

The 1.1 API strictly enforces authorization (I know, I spell it authorisation) before you can do a twitter search, previously you could do a basic authentication and it would work.

The way I got around it was to let the candy machine ask my server for the latest tweet and on my server use the ‘t’ package by Erik Michaels-Ober, a utility that allows you to do twitter 1.1 API calls from the command line.

To install t you must first install the prerequisites, which will only take a moment or two.
Once you have the prerequisites installed, you can simply type gem install t and begin the authorisation process.

When you have completed this stage you are almost done. Soon the sweet, sweet taste of Skittles (try the sour ones, the purple ones are out of this world!) will be but a tweet away :)

One thing I had to change is that the www-data user cannot run ‘t’ as $HOME is unset for security which means that there is nowhere for the config file to go. If you use the -P flag you can set the profile location which neatly sidesteps this issue t -P /var/www/.trc (mine isn’t there!)

So for clarity, the process is:
The Arduino asks my server for a web page containing the latest tweet
My server authenticates and queries twitter
If there has been a recent tweet it gets converted to a simple version the Arduino can understand and returned to the Arduino. If not, my server returns
The Arduino parses the returned string, first by size (the returned will be more than 3 characters long if there has been a tweet).
If the string is less than 12 characters long then the Arduino just goes back to the start after a delay.
If the string is 12 or more characters long then we have a tweet.
The first character is always < so we can safely skip that one. The complete line is composed of the tweet ID, character 0x07 (bell in ASCII, Ctrl-G)the sender eg @gregoryfenton, character 0x07 and the contents of the tweet followed by character 0x7F to mark the end of the line. I split the string and separate the parts into individual variables so I can do other stuff such as display the sender and message if required.The server code is: file: parsetwitter.php< ?php $needle = "maker_space AND candy"; $tmpfile = "/var/www/lasttweet.php";@include($tmpfile);// lasttweet.php will set up the following variables: // $tID : ID of last tweet // $tFrom: twitter ID of sender // $tMsg : message if(!isset($tID)) $tID = "0"; if(!isset($tFrom)) $tFrom = ""; if(!isset($tMsg)) $tMsg = "";$t = "`which t`";exec("$t -P /var/www/.trc search all \"$needle\" -n 1 -l", $tweets);$tweet = explode(" ", $tweets[0]);if($tweet[0] != $tID) { $r = str_replace("\\","\\\\",$tweet); $r = str_replace("\"","\\\"",$r); $r = str_replace("\$","\\\$",$r); $r = str_replace("\`","\\\`",$r); $data = "“;
printf (“< $r[0]%c$r[2]%c$r[3]%c%c", 7, 7, 7, 0x7f); file_put_contents($tmpfile, $data); } else { printf ("
Still with me? Here is the Arduino code:

#include
#include
#include

////////////////////////////////////////////////////////////////////////
//CONFIGURE
////////////////////////////////////////////////////////////////////////
char server[] = "example.com"; //domain name of the server you will connect to

//The location to go to on the server
//make sure to keep HTTP/1.0 at the end, this is telling it what type of file it is
String location = "/parsetwitter.php HTTP/1.0";

// if need to change the MAC address (Very Rare)
byte mac[] =
{
0xDE, 0xAD, 0xFA, 0xCE, 0xFA, 0xDE
};
////////////////////////////////////////////////////////////////////////

EthernetClient client;

int tweetPinA = 8, tweetPinB = 9, LED = 13;

char inString[32]; // string for incoming serial data
int stringPos = 0; // string index counter
boolean startRead = false; // is reading?

void setup()
{
wdt_disable();
Ethernet.begin(mac);
Serial.begin(9600);
pinMode(tweetPinA, OUTPUT);
digitalWrite(tweetPinA, LOW);
pinMode(tweetPinB, OUTPUT);
digitalWrite(tweetPinB, LOW);
pinMode(LED, OUTPUT);
digitalWrite(LED, LOW);
wdt_enable(WDTO_8S);
}

void loop()
{
int i = 0;
String pageValue = connectAndRead(); //connect to the server and read the output

Serial.println(pageValue); //print out the findings.

for(i = 0; i < 3; i++) { wdt_reset(); delay(5000); //wait (5x6) seconds before connecting again } }String connectAndRead() { //connect to the server Serial.println("connecting...");//port 80 is typical of a www page if (client.connect(server, 80)) { wdt_reset();Serial.println("connected"); client.print("GET "); client.println(location); client.print("HOST: "); client.println(server); client.println("User-Agent: Candy Machine Tweet Scanner/1.0.1"); client.println("Connection: close"); client.println();//Connected - Read the page wdt_reset(); return readPage(); //go and read the output } else { wdt_reset(); return "connection failed"; }}String readPage() { //read the page, and capture & return everything between '<' and '>'

stringPos = 0;
memset( &inString, 0, 32 ); //clear inString memory

while(true)
{
if (client.available())
{
wdt_reset();
char c = client.read();

if (c == '< ' ) { //'<' is our begining character startRead = true; //Ready to start reading the part } else if(startRead) { if(c != '>' && stringPos < 16) { //'>' is our ending character
inString[stringPos] = c;
stringPos ++;
}
else
{
//got what we need here! We can disconnect now
wdt_reset();
startRead = false;
client.stop();
client.flush();
Serial.println("disconnecting.");
if(stringPos > 12) // someone tweeted us!!!
{
wdt_reset();
digitalWrite(LED, HIGH);
Serial.println("We have received a tweet!");
digitalWrite(tweetPinA, HIGH);
digitalWrite(tweetPinB, LOW);
delay(2000);
wdt_reset();
digitalWrite(tweetPinA, LOW);
digitalWrite(tweetPinB, HIGH);
delay(1000);
wdt_reset();
digitalWrite(tweetPinA, LOW);
digitalWrite(tweetPinB, LOW);
digitalWrite(LED, LOW);
}
return inString;
}
}
}

}
}

Related posts

Leave a Comment