Pages: [1]   Go Down
Author Topic: TwitterClient / Thermal Printer Mashup  (Read 689 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 23
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Okay, so I'm trying to figure out how to tailor the following code to suit my project needs, and even after doing a small LED project, I still consider myself an entire noob with anything Arduino.  smiley-roll-blue

I have taken parts of code from the TwitterClient example and the Thermal Printer library and came out with this:

Code:
/*
  Twitter Client with Strings
 
 This sketch connects to Twitter using an Ethernet shield. It parses the XML
 returned, and looks for <text>this is a tweet</text>
 
 You can use the Arduino Ethernet shield, or the Adafruit Ethernet shield,
 either one will work, as long as it's got a Wiznet Ethernet module on board.
 
 This example uses the DHCP routines in the Ethernet library which is part of the
 Arduino core from version 1.0 beta 1
 
 This example uses the String library, which is part of the Arduino core from
 version 0019.  
 
 Circuit:
 * Ethernet shield attached to pins 10, 11, 12, 13
 
 created 21 May 2011
 modified 9 Apr 2012
 by Tom Igoe
 
 This code is in the public domain.
 
 */
#include <SPI.h>
#include <Ethernet.h>
#include <SoftwareSerial.h>
#include <Thermal.h>

int printer_RX_Pin = 5;
int printer_TX_Pin = 6;

Thermal printer(printer_RX_Pin, printer_TX_Pin, 19200);



// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = {
  0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x01 };
IPAddress ip(192,168,1,20);

// initialize the library instance:
EthernetClient client;

const unsigned long requestInterval = 60000;  // delay between requests

char serverName[] = "api.twitter.com";  // twitter URL

boolean requested;                   // whether you've made a request since connecting
unsigned long lastAttemptTime = 0;            // last time you connected to the server, in milliseconds

String currentLine = "";            // string to hold the text from server
String tweet = "";                  // string to hold the tweet
boolean readingTweet = false;       // if you're currently reading the tweet

void setup() {
  
  printer.justify('C'); //sets text justification (right, left, center) accepts 'L', 'C', 'R'
  
  printer.setSize('S'); // set type size, accepts 'S', 'M', 'L'
  printer.println("*PRINTER IS FUNCTIONING*"); //print line
  printer.println("*WAITING FOR NETWORK*"); //print line
  
  printer.feed(); //advance one line
  printer.feed(); //advance one line
  printer.feed(); //advance one line
  printer.feed(); //advance one line
  printer.feed(); //advance one line
  printer.feed(); //advance one line
  // reserve space for the strings:
  currentLine.reserve(256);
  tweet.reserve(150);

 // Open serial communications and wait for port to open:
  Serial.begin(9600);
   while (!Serial) {
    ; // wait for serial port to connect. Needed for Leonardo only
  }


  // attempt a DHCP connection:
  Serial.println("Attempting to get an IP address using DHCP:");
  if (!Ethernet.begin(mac)) {
    // if DHCP fails, start with a hard-coded address:
    Serial.println("failed to get an IP address using DHCP, trying manually");
    Ethernet.begin(mac, ip);
  }
  Serial.print("My address:");
  Serial.println(Ethernet.localIP());
  // connect to Twitter:
  connectToServer();
}



void loop()
{
  if (client.connected()) {
    if (client.available()) {
      // read incoming bytes:
      char inChar = client.read();

      // add incoming byte to end of line:
      currentLine += inChar;

      // if you get a newline, clear the line:
      if (inChar == '\n') {
        currentLine = "";
      }
      // if the current line ends with <text>, it will
      // be followed by the tweet:
      if ( currentLine.endsWith("<text>")) {
        // tweet is beginning. Clear the tweet string:
        readingTweet = true;
        tweet = "";
      }
      // if you're currently reading the bytes of a tweet,
      // add them to the tweet String:
      if (readingTweet) {
        if (inChar != '<') {
          tweet += inChar;
        }
        else {
          // if you got a "<" character,
          // you've reached the end of the tweet:
          readingTweet = false;
          Serial.println(tweet);
       printer.println(tweet);  
          // close the connection to the server:
          client.stop();
        }
      }
    }  
  }
  else if (millis() - lastAttemptTime > requestInterval) {
    // if you're not connected, and two minutes have passed since
    // your last connection, then attempt to connect again:
    connectToServer();
  }
}

void connectToServer() {
  // attempt to connect, and wait a millisecond:
  Serial.println("connecting to server...");
  if (client.connect(serverName, 80)) {
    Serial.println("making HTTP request...");
    // make HTTP GET request to twitter:
    client.println("GET /1/statuses/user_timeline.xml?screen_name=romantigram&count=1 HTTP/1.1");
    client.println("HOST: api.twitter.com");
    client.println();
  }
  // note the time of this connect attempt:
  lastAttemptTime = millis();
}  

What I want to do is have the Loop() segment scan for a new tweet, and if the tweet is indeed new, it'll print a timestamp, followed by the tweet text, formatted for readability, put through a few empty lines, and then wait for the newest tweet.

Currently, the printer is just printing the tweet as fast as it can pull it from Twitter's servers.

Any advice on how to get this to do what I'm after? Thank you!
« Last Edit: January 31, 2013, 08:19:27 am by kkachurak » Logged

UK
Offline Offline
Shannon Member
****
Karma: 223
Posts: 12630
-
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Suggest you ignore anything to do with printing and formatting for now and just focus on figuring out how to read tweets and recognise when a new tweet arrives. I don't know what format the tweet is going to come back in, but hopefully there will be a tweet ID in there. If so, you probably want to remember the last ID received and use the since_id URL parameter in the next request so that you only get new tweets subsequently.
Logged

I only provide help via the forum - please do not contact me for private consultancy.

Offline Offline
Newbie
*
Karma: 0
Posts: 23
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Alright, I totally agree. The printing part is easy, at least for now. Later, I will have to explore how to line-wrap the text appropriately.

I've done some digging and come up with this post (http://arduino.cc/forum/index.php/topic,93480.msg702532.html#msg702532) and they seem to get into what's called "textfinder" for comparing an existing tweet to a new tweet (or in some cases, an identical tweet that I want to ignore).

I don't think either instances of these TwitterClients rely on a tweet ID, unfortunately. Can anyone give me some guidance on TextFinder for comparing text?
« Last Edit: January 31, 2013, 08:34:01 am by kkachurak » Logged

NE PA
Offline Offline
Full Member
***
Karma: 5
Posts: 156
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

You can compare two strings with a simple if statement such as if(stringa == stringb). So all you would need to do is save the last tweet in a separate string and then compare each new tweet to it. When they aren't the same print the new tweet.
« Last Edit: January 31, 2013, 10:59:20 am by Quick5pnt0 » Logged


UK
Offline Offline
Shannon Member
****
Karma: 223
Posts: 12630
-
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Looking at samples of the XML document you get back from your URL request, it clearly includes a lot of information in addition to the text field you're using. Among other things, it includes an ID for each tweet. The Twitter API documentation at https://dev.twitter.com/docs/api/1/get/statuses/user_timeline describes how to use URL-encoded parameters to process a sequence of tweets based on their IDs - you could just read the most recent one tweet and look for the text to change, but it'd be a much less elegant approach.

Note that the Twitter API you'd be using is rate-limited; you may need to wait a couple of minutes between requests rather than the 60,000 ms that you have currently.
Logged

I only provide help via the forum - please do not contact me for private consultancy.

NE PA
Offline Offline
Full Member
***
Karma: 5
Posts: 156
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Edit: Nevermind, brain fart
« Last Edit: January 31, 2013, 11:51:04 am by Quick5pnt0 » Logged


Offline Offline
Newbie
*
Karma: 0
Posts: 23
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

if(tweeta == tweetb) means "equal to", right? What is the code for "not equal to"?

So I'm going to declare two "tweet" strings. In my loop, I should (steps)

1. Check tweet
2. Set tweet to tweeta (on startup this means tweetb is set to "")
3. If statement: If tweeta is not equal to tweetb, then print it.
4. Set tweetb to tweeta, so now they're identical.

As the loop runs again, it will continue to pull the same tweet, and since they're the same, it won't print. Obviously until a new tweet comes in. Am I on the right path here?
Logged

NE PA
Offline Offline
Full Member
***
Karma: 5
Posts: 156
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Sounds about right. You already have the new tweet string which is called "tweet". Just compare that to the lasttweet string. (Which you need to create)

Yes == is "equal to" and != is "not equal to". If you are interested you see the rest of the camparison operators in the Arduino Reference here: http://arduino.cc/en/Reference/HomePage
« Last Edit: January 31, 2013, 01:00:09 pm by Quick5pnt0 » Logged


UK
Offline Offline
Shannon Member
****
Karma: 223
Posts: 12630
-
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

You could be, using strcmp() to compare the old and new tweets - but if more than one tweet arrives per poll interval it would only handle the most recent one. Is that good enough?
Logged

I only provide help via the forum - please do not contact me for private consultancy.

Offline Offline
Newbie
*
Karma: 0
Posts: 23
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I went the route of (I hope) a simple string comparison.

Here's what I did:

Code:
/*
  Twitter Client with Strings
 
 This sketch connects to Twitter using an Ethernet shield. It parses the XML
 returned, and looks for <text>this is a tweet</text>
 
 You can use the Arduino Ethernet shield, or the Adafruit Ethernet shield,
 either one will work, as long as it's got a Wiznet Ethernet module on board.
 
 This example uses the DHCP routines in the Ethernet library which is part of the
 Arduino core from version 1.0 beta 1
 
 This example uses the String library, which is part of the Arduino core from
 version 0019. 
 
 Circuit:
 * Ethernet shield attached to pins 10, 11, 12, 13
 
 created 21 May 2011
 modified 9 Apr 2012
 by Tom Igoe
 
 This code is in the public domain.
 
 */
#include <SPI.h>
#include <Ethernet.h>
#include <SoftwareSerial.h>
#include <Thermal.h>

int printer_RX_Pin = 5;
int printer_TX_Pin = 6;

Thermal printer(printer_RX_Pin, printer_TX_Pin, 19200);



// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = {
  0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x01 };
IPAddress ip(192,168,1,20);

// initialize the library instance:
EthernetClient client;

const unsigned long requestInterval = 30000;  // delay between requests

char serverName[] = "api.twitter.com";  // twitter URL

boolean requested;                   // whether you've made a request since connecting
unsigned long lastAttemptTime = 0;            // last time you connected to the server, in milliseconds

String currentLine = "";            // string to hold the text from server
String tweeta = "";                  // string to hold the tweet
String tweetb = "";                  // string to hold the tweet
boolean readingTweet = false;       // if you're currently reading the tweet

void setup() {
 
  printer.justify('C'); //sets text justification (right, left, center) accepts 'L', 'C', 'R'
   
  printer.setSize('S'); // set type size, accepts 'S', 'M', 'L'
  printer.println("*PRINTER IS FUNCTIONING*"); //print line
  printer.println("*WAITING FOR NETWORK*"); //print line
   
  printer.feed(); //advance one line
  printer.feed(); //advance one line
  printer.feed(); //advance one line
  printer.feed(); //advance one line
  printer.feed(); //advance one line
  printer.feed(); //advance one line
  // reserve space for the strings:
  currentLine.reserve(256);
  tweeta.reserve(150);
  tweetb.reserve(150);

 // Open serial communications and wait for port to open:
  Serial.begin(9600);
   while (!Serial) {
    ; // wait for serial port to connect. Needed for Leonardo only
  }


  // attempt a DHCP connection:
  Serial.println("Attempting to get an IP address using DHCP:");
  if (!Ethernet.begin(mac)) {
    // if DHCP fails, start with a hard-coded address:
    Serial.println("failed to get an IP address using DHCP, trying manually");
    Ethernet.begin(mac, ip);
  }
  Serial.print("My address:");
  Serial.println(Ethernet.localIP());
  // connect to Twitter:
  connectToServer();
}



void loop()
{
  if (client.connected()) {
    if (client.available()) {
      // read incoming bytes:
      char inChar = client.read();

      // add incoming byte to end of line:
      currentLine += inChar;

      // if you get a newline, clear the line:
      if (inChar == '\n') {
        currentLine = "";
      }
      // if the current line ends with <text>, it will
      // be followed by the tweet:
      if ( currentLine.endsWith("<text>")) {
        // tweet is beginning. Clear the tweet string:
        readingTweet = true;
        tweeta = "";
      }
      // if you're currently reading the bytes of a tweet,
      // add them to the tweet String:
      if (readingTweet) {
        if (inChar != '<') {
          tweeta += inChar;
        }
        else {
          // if you got a "<" character,
          // you've reached the end of the tweet:
          readingTweet = false;
          Serial.println(tweeta);
          if(tweeta != tweetb){
               printer.println(tweeta);
               printer.feed(); //advance one line
               printer.feed(); //advance one line
               printer.feed(); //advance one line
               printer.feed(); //advance one line
               printer.feed(); //advance one line
               printer.feed(); //advance one line
          }
          // close the connection to the server:
          client.stop();
        }
      }
    }   
      tweetb = tweeta;
  }

  else if (millis() - lastAttemptTime > requestInterval) {
    // if you're not connected, and two minutes have passed since
    // your last connection, then attempt to connect again:
    connectToServer();
  }
}

void connectToServer() {
  // attempt to connect, and wait a millisecond:
  Serial.println("connecting to server...");
  if (client.connect(serverName, 80)) {
    Serial.println("making HTTP request...");
    // make HTTP GET request to twitter:
    client.println("GET /1/statuses/user_timeline.xml?screen_name=romantigram&count=1 HTTP/1.1");
    client.println("HOST: api.twitter.com");
    client.println();
  }
  // note the time of this connect attempt:
  lastAttemptTime = millis();
}   

The serial monitor shows the correct tweets, but nothing prints, despite a print instruction in an "if" statement at line 132. What am I doing wrong here?
Logged

NE PA
Offline Offline
Full Member
***
Karma: 5
Posts: 156
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Looking it over real quick it seems like it should work. Maybe try putting a serial print in the tweeta != tweetb for loop to see if that part of the code is run at the proper time. Also try putting the tweetb = tweeta line right after the last printer.feed
« Last Edit: February 01, 2013, 11:14:56 pm by Quick5pnt0 » Logged


UK
Offline Offline
Shannon Member
****
Karma: 223
Posts: 12630
-
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Can you print to the printer? I mean, have you tested the code for that and proves it actually works correctly?
Logged

I only provide help via the forum - please do not contact me for private consultancy.

Offline Offline
Newbie
*
Karma: 0
Posts: 23
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Yes, the printer is working properly. And Quick5pnt0: putting tweetb = tweeta inside the conditional statement worked like an absolute charm. For the most part, the effect is precisely what I'm looking for. Thanks so much!

Now I'm moving on to formatting. Anything over roughly 32 characters gets automatically split up by the printer with no regard to where the break occurs. Obviously, I'd like to split up a tweet at a space. Is there a way to format the string so the printer prints at at the highest level of readability?
« Last Edit: February 02, 2013, 10:43:56 am by kkachurak » Logged

UK
Offline Offline
Shannon Member
****
Karma: 223
Posts: 12630
-
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Word wrapping is what you want. You can split the text into tokens (words) at whitespace, print each word in turn keeping track of the column number that you're up to - if the next word won't fit in the remaining columns, insert a line wrap. If the next word is to long to go on a single line, split it at the end of the current line.

The next level of complexity is to split words at the points where hyphens can be inserted, but that's much harder.
Logged

I only provide help via the forum - please do not contact me for private consultancy.

Pages: [1]   Go Up
Jump to: