Email to LCD By Way of Arduino

There are plenty of tutorials out there for this, but I’ve taken a particular tack to pull the data down on the Raspberry Pi which, because it’s fundamentally torturous, I’ve not seen anyone else take. So here goes…

The idea is that I use Tasker on my phone to set GeoFences, and then using the email plugin for it, send a message to a spare account [one that I originally set up for the motion detection]. I then haul down the email, parse out the body, and then send it down over the serial port to the LCD connected to the Arduino. All of which is so that I can “impress” my wife to [I can almost hear her eyes rolling] with a fundamentally daft piece of technology while I’m out of the house :). Let the “I’m in the pub!” messages ensue….

The easiest way to do the serial communication is using the pySerial library. Unfortunately, I don’t know Python at all, and so reverted to Perl as my scripting glue of choice. Getting this combination working was one of the trickiest steps of the whole process, as the Debian version of Perl is a little strange to navigate. I installed cpanimus, and then tried to install Inline-Python. This failed, complaining about a missing library, so I then installed python-dev via apt-get [which, in Raspberry Pi life-on-an-SD-card terms, is massive – 43mb]. I repeated the Inline-Python install which then worked fine, only to discover that there aren’t a plethora of examples explaining basics like passing in variables to inline methods.

Next step was which POP3 library to go with. I tried about 4, before settling on POP3Client [installed via sudo cpanm]. BTW, I’m not using TLS, because I’ve found it to be a little bit hit and miss with my ISP, and there are enough things that can go wrong with this project already. Needless to say you should use it wherever possible. You probably want an account dedicated for this anyway.

Before getting on to talk about the serial port comms, it’s worth taking a minute over the connecting of the LCD. I can’t solder for toffee, and managed to break the first LCD I tried [not sure how]. FWIW, this is just a random 16×2 LCD which supports HD44780, and which I ordered up from a crew called HobbyTronics [great service]. The dodgy carpentry was just a way of stabilising the display. What I ended up doing was putting a blob of solder on the end of each pin, and then pull it through from the back. There’s actually a piece of cardboard underneath to firm up the contacts – not exactly production quality, but hey, it works :).

Serial port communication is fundamentally unreliable. I experimented for quite a while with this: the termination of the data is a given, but I also tried delimiting the start of the message as well. Regardless, the repeated padding prequel data worked for me. I can imagine that this is going to be very display-dependent.

A couple more gotchas. The POP client appends what I initially thought was binary data to the string containing the body of the email message, which was appearing as a corrupt character on the LCD. It’s actually a control character, which I globally substitute out.

Having done all my sketch development and testing on the Mac, I then hit the hardy perennial of power consumption problems with the Raspberry Pi, because I have both USB ports occupied [WiFi and the Arduino]. At the standard 150 milliseconds that the scrolling method example on the Arduino website suggests, the text was borderline unreadable, so I tuned this down to 350 milliseconds. Finally, I found that the scrolling text wrapped on me, if I just offset by the length of the display string [again, as per the example]. I was running out of steam by this point, so I just subtracted the width of the display from the length of the string.

On to the code. First the POP3 to serial port client, that I run every minute as a cron job on the Raspberry Pi:

#!/usr/bin/perl
use Mail::POP3Client;
$pop = new Mail::POP3Client( USER     => "your\@email.com",
                               PASSWORD => "yourPassword",
                               HOST     => "your.email.server.com" ) || die "failed: $!\n";
$messageCount = $pop->Count();
#print "$messageCount messages\n";

# just confirming the message counter starts at 1.
# The newest message is at the bottom so we will set the body array to that value:
$textForLED = $pop->Body($messageCount);
# appended character removal:
$textForLED =~ s/(\r\n)//g;

# Only read the newest message; housekeeping is delete everything else that might be there:
for( $i = 1; $i Delete($i);
}
$pop->Close();

if ($messageCount == 0)
{
   # This is vestigial: as I run the script every minute, I don't want to display
   # any filler content if there is no email.
   #print "message count is zero\n";
   # http://numbersapi.com/number/type
   #$randNum = int(rand(5000));
   #$textForLED = `curl -s http://numbersapi.com/$randNum/trivia`;
   #print $textForLED;
}

else
{
   # this was for debug purposes:
   open (LOGFILE, ">>/home/pi/temp_sensor/logdata.txt");
   print LOGFILE "Email content: $textForLED, \n";
   close (LOGFILE);
   # Add the character to terminate:

   $textForLED = $textForLED . "^";

   for ($repeatCount = 0; $repeatCount<= 1; $repeatCount++)
   {
      serialPipe($textForLED);
   }

# This indentation can't be changed for inline code:
use Inline Python => q{

def serialPipe(textIn):
   #print 'Hi, %s.' % textIn
   import serial
   import time
   ser = serial.Serial('/dev/ttyACM0', 115200)
   for x in range(0, 5):
      ser.write('*************************************')
      time.sleep(1)
   ser.write(textIn)
   #ser.write('test message^');
};
}

and now the sketch:

#include 

// Connections:
// rs (LCD pin 4) to Arduino pin 12
// rw (LCD pin 5) to Arduino pin 11
// enable (LCD pin 6) to Arduino pin 10
// LCD pin 15 to Arduino pin 13
// LCD pins d4, d5, d6, d7 to Arduino pins 5, 4, 3, 2
LiquidCrystal lcd(12, 11, 10, 5, 4, 3, 2);

//int backLight = 13;    // pin 13 will control the backlight

void setup()
{
  //pinMode(backLight, OUTPUT);
  //digitalWrite(backLight, HIGH); // turn backlight on. Replace 'HIGH' with 'LOW' to turn it off.
  lcd.begin(16,2);              // columns, rows.  use 16,2 for a 16x2 LCD, etc.
  lcd.clear();                  // start with a blank screen
  lcd.setCursor(0,0);           // set cursor to column 0, row 0 (the first row)
  //lcd.print("About Bleeding");    // change this text to whatever you like. keep it clean.
  lcd.setCursor(0,1);           // set cursor to column 0, row 1
  //lcd.print("time!");
  delay(3000);
  Serial.begin(115200);
  
  // if you have a 4 row LCD, uncomment these lines to write to the bottom rows
  // and change the lcd.begin() statement above.
  //lcd.setCursor(0,2);         // set cursor to column 0, row 2
  //lcd.print("Row 3");
  //lcd.setCursor(0,3);         // set cursor to column 0, row 3
  //lcd.print("Row 4");
}

void loop()
{
   lcd.clear(); 
   String ledDisplay;  
   boolean endOfText = false;
   while ((Serial.available() > 0) && (endOfText == false))
   {
      //Serial.println('looping');
      char inByte = Serial.read();
      if (inByte != '^')
      {
          ledDisplay = ledDisplay + inByte;
      }
      else
      {
         for (int repeatCount = 0; repeatCount <=3; repeatCount++)
         {
            lcd.setCursor(0,0);
            lcd.print("***INCOMING!!!!***");
            delay(2000);
            for (int positionCounter = 0; positionCounter < 18; positionCounter++)
            {
              lcd.scrollDisplayLeft();
              delay(350);
            }
            delay(1000);
            lcd.clear();
         }       
         for (int repeatCount = 0; repeatCount <=4; repeatCount++)
         {
            lcd.setCursor(0,0);
            lcd.print(ledDisplay);
            delay(1000);
            for (int positionCounter = 0; positionCounter < (ledDisplay.length() -16); positionCounter++)
            {
              lcd.scrollDisplayLeft();
              delay(350);
            }
            delay(2000);
            lcd.clear();
            delay(1000);
         }
         for (int repeatCount = 0; repeatCount <=3; repeatCount++)
         {
            lcd.setCursor(0,0);
            lcd.print("***THAT IS ALL***");
            delay(2000);
            for (int positionCounter = 0; positionCounter < 17; positionCounter++)
            {
              lcd.scrollDisplayLeft();
              delay(350);
            }
            delay(1000);
            lcd.clear();
         }  
         endOfText = true;
         ledDisplay = "";
         delay(5000);
         lcd.clear();
      }
   }
   delay(1000);
}

2 thoughts on “Email to LCD By Way of Arduino

  1. It turns out that the Email Me Pro plugin does something to the format of the email that the POP client doesn’t like. The MIME separators end up appearing in the body of the message. I’ve had to hack the Perl to parse these out using this to drop the matching lines on the floor:

    if (($line =~ m/—-/) || ($line =~ m/Content/) || ($line =~ m/^\n/))

  2. Ok, I have continued to refine the Perl script. This is pretty finely tuned to parse emails from the gMail client and the Email Pro plugin on the latest version of Android. It doesn’t work however with the default email app, which is still returning garbage – discussed above, and undoubtedly down the format of the email it’s producing with the POP3Client is pretty unhappy about. Parsing HTML is a fundamentally bad idea in this way. The patterns I’ve used below work, but are fragile:

    foreach $line(@textForLED)
    {
    print “looking at line: $line\n”;
    if (!(($line =~ m/–/) || ($line =~ m/Content/) || ($line =~ m/^\n/) | ($line =~ m/^\

Comments are closed.