How to implement Twitter's API v1.1 using OAuth on Arduino


#1

Hi,

I’m using an Arduino Uno board with the Ethernet Shield to get the last tweet (of Twitter) from a public user timeline (it’s mine) and display it on the Arduino serial monitor. I want the whole device to work without Python or Ruby and as it’s a stand alone project it won’t be used with a computer.
I create a client that connects to api.twitter.com and I use this GET command of the REST API v1.0 to obtain it:

client.print("GET /1/statuses/user_timeline.json?&screen_name=tuitduino&count=1 HTTP/1.1");
client.println("HOST: api.twitter.com");
client.println();

It works properly, but according to the Twitter’s API documentation (https://dev.twitter.com/docs/api/1.1/get/statuses/user_timeline), I must change my GET command to the new version 1.1. This is what I do:

client.print("GET /1.1/statuses/user_timeline.json?&screen_name=tuitduino&count=1 HTTP/1.1");
client.println("HOST: api.twitter.com");
client.println();

but it doesn’t work. According to the Twitter’s API documentation, I must use OAuth to access this information, that is, to authenticate and authorize an aplication, wich I must create (in my case I suppose that it have to be a website), to read or write tweets from a user account (mine’s) on behalf of it. The problem is that I don’t know how to integrate the GET HTTP request and the OAuth information with my Arduino code. I’ve seen the Twitter’s API documentation in depth and there are a few examples and libraries to do it “easily” but they are written for other programming languages, not for Arduino.
According to the documentation, I must implement a header, something like this:

Authorization: OAuth oauth_consumer_key="cCB46H0y6R8Hrx836WwAA", oauth_nonce="18106fa9ce0b1083367cfbd50720abea", oauth_signature="XXXXXXXXXXXXXXXXXXXXXXX", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1361444134", oauth_token="1004705586-tF4876Qu6qTwLMuTaCjbZCLTbFt4hDoRoCun3qW", oauth_version="1.0"

where the alphanumeric values are given to me from Twitter and XXXXXXXXXXXXXXXXXXXXXXX is a private value so I omitted it.

Does anybody has some idea to do it with Arduino? The GET method and the header. It’s very important for me because it’s for my final project.

Thanks,

Ger.


#2

I’ve not used it before, but I’ve heard of folks having success with this library: http://www.markkurossi.com/ArduinoTwitter/index.html


#3

Well, thanks a lot Taylor, although the download link of the library fails.
Ah and another thing: as I said you, I just want to get the last tweet from my public account with Arduino, and nothing more, so according to this steps (https://dev.twitter.com/docs/auth/obtaining-access-tokens), what is my case? My consumer app is a website I’ve created for this purpose.


#4

I think you might want to wait a few more days until we release a form of auth called app-only auth. It will drastically reduce your complexity to get the most recent tweets for a public account. Stay tuned to @twitterapi and our blog for when that gets released.


#5

hi,
there is any example for this library: http://www.markkurossi.com/ArduinoTwitter/index.html,
i’m trying to use this library with wifishield, after doing modification in the library for Wifishield.
but i can not get the post message, the only thing that it make it’s get time from twitter server.
i post a topics in arduino forum for this case please have a look; http://arduino.cc/forum/index.php/topic,156599.0.html


#6

Any updates on this? I have been trying to do exactly mentioned in the question.


#7

Hi @plantaexpre - I’m trying to adapt this Twitter Library from Ethernet to WiFi at this time. Would you mind sharing your version of the modified code? TIA!


#8

As @episod mentions up thread, [node:13439] makes this even easier, check it out.


#9

@froginthevalley
Sorry, i’m a programming-beginner and i don’t understand how to transfer the explanation in your link to my arduino micro controller. Isn’t there a example for an arduiono? I can’t find one…

@episod is there an update? i can’t find one…


#10

yes of course, just change Ethernet to WiFiclass (WifiClient client) in both file .h and .cpp

good luck, if you can t do it, just give me a mail direction and i can send you the files


#11

I’m trying to use Application-only authentication. I created the Base64 encoded bearer token credentials
This is my Arduino code to request the bearer token:

if (client.connect("api.twitter.com", 80)) { TextFinder finder(client, 2);
Serial.println("Obtaining bearer token...");
client.println("POST /oauth2/token HTTP/1.1");
client.println("Host: api.twitter.com");
client.println("User-Agent: My Twitter App v1.0.23");
client.println("Authorization: Basic [deliberately removed the base 64 encoding value here]");
client.println("Content-Type: application/x-www-form-urlencoded;charset=UTF-8");
client.println("Content-Length: 29");
client.println("Accept-Encoding: gzip");
client.println();
client.println("grant_type=client_credentials");
client.println();

while (client.connected()) {
  if (client.available()) {
    Serial.println("Client available");
    if (finder.getString("", "", message, 1000)) {
      Serial.println(message);
    }

But the message I get back is:

HTTP/1.1 302 Found cache-control: no-cache, no-store, must-revalidate, pre-check=0, post-check=0 content-length: 102 content-type: text/html; charset=utf-8 date: Thu, 11 Jul 2013 19:49:54 GMT expires: Tue, 31 Mar 1981 05:00:00 GMT last-modified: Thu, 11 Jul 2013 19:49:54 GMT location: https://api.twitter.com/oauth2/token pragma: no-cache server: tfe set-cookie: _twitter_sess=BAh7CToHaW...[cut]; domain=.twitter.com; path=/; HttpOnly set-cookie: guest_id=v1%3A137...[cut]; Domain=.twitter.com; Path=/; Expires=Sat, 11-Jul-2015 19:49:54 UTC status: 302 Found vary: Accept-Encoding x-frame-options: SAMEORIGIN x-mid: 597b55661eb83c9aab5dbc28eec5a8370546bf9b x-runtime: 0.00719 x-transaction: 0c6fada2dd093ea7 x-ua-compatible: IE=10,chrome=1 x-xss-protection: 1; mode=block You are being redirected.HTTP/1.0 400 Bad Request Content-Length: 0

I don’t have any experience in http requests. Any idea of what I did wrong?


#12

I found the problem:
The Twitter API requires you to connect through SSL, but the Arduino isn’t capable of doing this because it doesn’t have enough recources. So Application-only authorisation isn’t an option on Arduino!

Solution: I created a PHP script on my own server which makes the request, parses the JSON response and outputs the search result. I now make the Arduino connect to my server.

This is the PHP srcipt:

<?php ini_set('display_errors', 1); require_once('TwitterAPIExchange.php'); /** Set access tokens here - see: https://dev.twitter.com/apps/ **/ $settings = array( 'oauth_access_token' => "", 'oauth_access_token_secret' => "", 'consumer_key' => "", 'consumer_secret' => "" ); /** Perform a GET request and echo the response **/ $url = 'https://api.twitter.com/1.1/search/tweets.json'; $search_string = "Your search here"; $getfield = '?q=$search_string&count=1&include_entities=false'; $requestMethod = 'GET'; $twitter = new TwitterAPIExchange($settings); $json = $twitter->setGetfield($getfield) ->buildOauth($url, $requestMethod) ->performRequest(); $obj = json_decode($json, true); $tweet = $obj["statuses"][0]["text"]; echo "$tweet"; I based this on the code I found here: http://stackoverflow.com/questions/12916539/simplest-php-example-for-retrieving-user-timeline-with-twitter-api-version-1-1/15314662#15314662 This is my Arduino sketch: #include #include #include char ssid[] = ""; char pass[] = ""; WiFiClient client; char host[] = "Put the hostname of the server where the php script is here"; char tweet[140] = "", oldTweet[140] = ""; void foundHashtag() { Serial.println("Found the hashtag!"); } void setup() { WiFi.begin(ssid, pass); Serial.begin(9600); for(int i = 0; i < 140; i++) { oldTweet[i] = 0; tweet[i] = 0; } } void loop() { int i; Serial.println("Connecting to server..."); if (client.connect(host, 80)) { client.println("GET /index.php HTTP/1.1"); client.print("Host: "); client.println(host); client.println("User-Agent: Arduino/1.0"); client.println(); TextFinder finder(client); while (client.connected()) { if (client.available()) { if (finder.getString("", "", tweet, 140) != 0) { for (i = 0; i < 140; i++) if(oldTweet[i] != tweet[i]) break; if (i != 140) { Serial.println(tweet); foundHashtag(); for (i = 0; i < 140; i++) oldTweet[i] = tweet[i]; break; } } } } delay(1); client.stop(); } Serial.println("delay..."); delay (40000); // don't make this less than 30000 (30 secs), because you can't connect to the twitter servers faster (you'll be banned) } I based the code for the Arduino sketch on this article: http://labby.co.uk/2012/11/arduino-based-twitter-enabled-candy-machine-all-working-and-monitoring-twitter/ I hope that anyone finds this helpful. I would appreciate any ideas for further improvement!

#13

…ignore this. Got it working. Changed server.


#14

I found that very helpful @ArduinoDeurbel! However, I have done what you did and it doesn’t work.

I want Arduino to get the last tweet from my account (@tuitduino) through the PHP script where I wrote the oauth keys, the user, etc. and display the tweet in the serial monitor.

I installed “Wampserver2.4-x86” and I put it online. In the path “C:\wamp\www” I put the file “TwitterAPIExchange.php” and I created a text note called “tuitduino.txt” with this code:

<?php require_once('TwitterAPIExchange.php'); $settings = array( 'oauth_access_token' => "XXX", 'oauth_access_token_secret' => "XXX", 'consumer_key' => "XXX", 'consumer_secret' => "XXX" ); $url = 'https://api.twitter.com/1.1/statuses/user_timeline.json'; $getfield = '?screen_name=tuitduino'; $requestMethod = 'GET'; $twitter = new TwitterAPIExchange($settings); $json = $twitter->setGetfield($getfield) ->buildOauth($url, $requestMethod) ->performRequest(); $obj = json_decode($json, true); $tweet = $obj["statuses"][0]["text"]; echo "$tweet"; ?>

and I saved it as PHP file (“tuitduino.php”).

Then, I loaded my Arduino sketch:

#include <SPI.h>
#include <Ethernet.h>
#include <TextFinder.h>

byte Mac[] = { 0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x01 };
byte Ip[] = { 192, 168, 1, 3 };
byte Dns[] = { 62, 81, 16, 164 };
byte Gateway[] = { 192, 168, 1, 1 };
byte Subnet[] = { 255, 255, 255, 0 };

char host[] = “http://localhost/”;

EthernetClient client;

char tweet[140] = “”, oldTweet[140] = “”;

void setup()
{
Serial.begin(9600);
Ethernet.begin(Mac, Ip, Dns, Gateway, Subnet);
for (int i = 0; i < 140; i++)
{
oldTweet[i] = 0;
tweet[i] = 0;
}
delay(1000);
}

void loop()
{
int i;

Serial.println(“Connecting to server…”);

if (client.connect(host, 80))
{
Serial.println(“Connected”);

client.println("GET /tuitduino.php HTTP/1.1");
client.print("Host: ");
client.println(host);
client.println("User-Agent: Arduino/1.0");
client.println();

TextFinder finder(client);

while (client.connected())
{
  Serial.println("Client is still connected");
  
  if (client.available())
  {
    Serial.println("Client available");
    
    Serial.println("Searching for the last tweet...");
    if ( finder.getString("<tweet>", "</tweet>", tweet, 140) != 0 )
    {
      for (i = 0; i < 140; i++)
        if (oldTweet[i] != tweet[i])  break;
        if (i != 140)
        {
          Serial.println(tweet);
          for (i = 0; i < 140; i++)
              oldTweet[i] = tweet[i];
              break;
        }
        
    }
    Serial.println("End of finder");       
    
  }
  Serial.println("Client not available");
  
}

delay(1);

client.stop();
Serial.println("Client stopped");

}

else { Serial.println(“Connection failed”); }

delay (30000);

}

but I get the following response in the serial monitor:
Connecting to server…
Connected
Client stopped

It doesn’t find any tweet. I don’t understand it. Coud someone help me please?
And can I see the tweet by writing on the browser “localhost/tuitduino.php”? I write this but it’s all in blank.


#15

Solved. Issue closed.


#16

Do you mind telling how you fixed it? I’m trying to only get my last tweet also.


#17

someone I can speak my own is wrong with this code above?


#18

char host[]=“localhost”;
or
char host[]=“127.0.0.1”;


#19

finally managed to create the server, but not my arduino can read tweets
following message: client stopped
can someone help me?


#20

I’m also looking for some guidance on this. I have everything working up until the Arduino code - the serial monitor is putting out:

Connecting to server…
Connected
Client stopped

How did you manage to resolve this?