IMAP Mailbox counter + Incoming phone display

I made a little sketch that displays some information about my mailbox using IMAP. It also gives me some information when a call arrives at my asterisks PBX box. For this it works together with Superfecta (See here)

I've just some code from different auteur on the net (ntptime etc) and glued it together with the code I wrote myself.

I plpan on updating the IMAP code, so that the sender and the subject is displayed when a new mail arrives.

In the code be sure to put your own server adresses and username, password and mailboxname.

Hardware is a 20*4 LCD (Hitachi compatible), DFRobot ethernetshield, DFRobot Duemilanove 328p




The code on the Asterisks Box

<?php
//this file is designed to be used as an include that is part of a loop.
//If a valid match is found, it should give $caller_id a value
//available variables for use are: $thenumber
//retreive website contents using get_url_contents($url);
//this data source created by Zorka  01/18/2011

//configuration / display parameters
//The description cannot contain "a" tags, but can contain limited HTML. Some HTML (like the a tags) will break the UI.
$source_desc = "This source will send the number and the Caller ID to a webenabled Arduino.
Enter the URL of the Arduino in the format `url:port`.
This datasource should be one of the last data sources on your list, as it does not provide any data of its own, and can only send what information has been collected before it is run.
This data source requires Superfecta Module version 2.2.3 or higher.";
$source_param = array();
$source_param['URL_address']['desc'] = 'Specify the URL:Port to the Arduino installation. (Example: 192.168.1.222:8080)';
$source_param['URL_address']['type'] = 'text';
$source_param['URL_address']['default'] = '';

if($usage_mode == 'post processing')
{
    if ($run_param['URL_address'] !='')
   {
       $thenumberformated = $thenumber;

      $url=$run_param['URL_address'].'/ASTERISK_IN|'.$first_caller_id.'|'.$thenumber;

        if($debug)
      {
          print 'Send to Arduino: '.$run_param['URL_address'].'

';
      }
                
      $value = get_url_contents($url);
    }
}
?>

and the Arduino code (part 1)

#include <SPI.h>
#include <Client.h>
#include <Server.h>
#include <Ethernet.h>
#include <String.h>
#include <Udp.h>
#include <Time.h>
#include <LiquidCrystal.h>

/*##########################################################################################
# user adjustable parameters
##########################################################################################*/
const int timezone = 1;
const int displaytime = 20000;
const int timesync = 60;

LiquidCrystal lcd(8, 9, 4,5 , 6, 7);
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
byte ip[] = { 192,168,1,222 };
byte gw[] = { 192,168,1,254 };

Server server(80);

byte timeServer[] = {192, 168, 1, 254};
byte imapServer[] = {192, 168, 1, 100};

Client imapClient(imapServer, 143);

/*##########################################################################################
##########################################################################################*/

unsigned long timeout=100000;
const char responseOK[] = "ARDUINO OK";

String mailMessages;
String newMessages;

int updateTimer;
unsigned long int timer1;
time_t prevDisplay;
unsigned int localPort = 8888;
const int NTP_PACKET_SIZE= 48;
byte packetBuffer[ NTP_PACKET_SIZE];
boolean numberDisplay = false;
String line1;
String line2;
String line3;
String line4;

short updated;
boolean      popClientConnected = false;

/*########################################################################################*/

void setup()
{
  
  lcd.begin(20, 4);
  lcd.setCursor(4,1);
  lcd.print("MultiDisplay");

  Ethernet.begin(mac, ip, gw);
  server.begin();
  
  Udp.begin(localPort);
  setSyncInterval(timesync);         
  setSyncProvider(SetNetworkTime);

  Serial.begin(9600);
  Serial.println("Reset");
  delay(2500);
}

/*########################################################################################*/

void loop()
{
  phoneClient();
  
  if (updated != 0) {
     updateDisplay();
     updated = 0;
  }

  if( now() != prevDisplay)
  {
    prevDisplay = now();
    digitalClockDisplay();  
  }
  
  if (millis() - timer1 > displaytime && numberDisplay) 
  {
    if (!imapClient.connected()) 
      connectClient();
    else
    {
      getImapStatus();
    }
    numberDisplay = false;
  }

  if (imapClient.available())
  {
    imapRead("*", false);
    getImapStatus();
  }

  if (millis() - timeout > 60000) 
  {
    if (!imapClient.connected()) 
      connectClient();
    else
    {
      getImapStatus();
      timeout = millis();
    }
  }

//  now();
}

/*########################################################################################*/

unsigned long sendNTPpacket(byte *address)
{
  // set all bytes in the buffer to 0
  memset(packetBuffer, 0, NTP_PACKET_SIZE);
  // Initialize values needed to form NTP request
  // (see URL above for details on the packets)
  packetBuffer[0] = 0b11100011;   // LI, Version, Mode
  packetBuffer[1] = 0;     // Stratum, or type of clock
  packetBuffer[2] = 6;     // Polling Interval
  packetBuffer[3] = 0xEC;  // Peer Clock Precision
  // 8 bytes of zero for Root Delay & Root Dispersion
  packetBuffer[12]  = 49;
  packetBuffer[13]  = 0x4E;
  packetBuffer[14]  = 49;
  packetBuffer[15]  = 52;

  // all NTP fields have been given values, now
  // you can send a packet requesting a timestamp:         
  Udp.sendPacket( packetBuffer,NTP_PACKET_SIZE,  address, 123); //NTP requests are to port 123
}

/*########################################################################################*/

unsigned long SetNetworkTime(void)  
{

  sendNTPpacket(timeServer); // send an NTP packet to a time server
  
  const unsigned long seventyYears = 2208988800UL;    
  unsigned long highWord;
  unsigned long lowWord ;  
  unsigned long secsSince1900; 
  unsigned long epoch=0; 

  delay(100);  
  if ( Udp.available() ) {  
    Udp.readPacket(packetBuffer,NTP_PACKET_SIZE);  // read the packet into the buffer
    highWord = word(packetBuffer[40], packetBuffer[41]);
    lowWord = word(packetBuffer[42], packetBuffer[43]);  
    secsSince1900 = highWord << 16 | lowWord; 
    epoch = secsSince1900 - seventyYears; 
    setTime(epoch);
   }
   else if (timeStatus() == timeNotSet){
      setTime(epoch);
   }

    return (epoch);
  }

/*########################################################################################*/

part 2

/*########################################################################################*/

void digitalClockDisplay()
{
  // digital clock display of the time

  time_t utc, local;

  utc = now();
  local = utc + timezone *60 * 60; 

  line1 = "";
  if (hour(local) < 10)
    line1 += "0";  
  line1 += hour(local);
  line1 += ":";

  if (minute() < 10)
    line1 += "0";
  line1 += minute();
  line1 += ":";

  if (second() < 10)
    line1 += "0";
  line1 += second();

  if (timeStatus() == timeNeedsSync)
    line1 += "* ";
  else
    line1 += "  ";
  
  if (day() < 10)
    line1 += "0";
    
  line1 += day();
  line1 += "/";
  if (month() < 10)
    line1 += "0";
  line1 += month();

  line1 += "/";  
  line1 +=year(); 

  bitWrite(updated, 0, 1);
}

/*########################################################################################*/

void printDigits(int digits, String line){
  if(digits < 10)
    line += '0';
  line += digits;
}

/*########################################################################################*/

void updateDisplay()
{
  if (bitRead(updated, 0) == 1)
  {
    lcd.setCursor(0,0);
    lcd.print("                    ");
    lcd.setCursor(0,0);
    lcd.print(line1);
  }

  if (bitRead(updated, 1) == 1)
  {
    lcd.setCursor(0,1);
    lcd.print("                    ");
    lcd.setCursor(0,1);
    lcd.print(line2);
  }
  
  if (bitRead(updated, 2) == 1)
  {
    lcd.setCursor(0,2);
    lcd.print("                    ");
    lcd.setCursor(0,2);
    lcd.print(line3);
  }
  
  if (bitRead(updated, 3) == 1)
  {
    lcd.setCursor(0,3);
    lcd.print("                    ");
    lcd.setCursor(0,3);
    lcd.print(line4);
  }
  
  updated = 0;
}

/*########################################################################################*/

void connectClient()
{
  String readCommand;
  
  Serial.println("Connecting...");
  if (imapClient.connect())
  {
    Serial.println("Connecting OK");
    readCommand = imapCommand("arduino login username password", "Login", (char *)responseOK, true);
    if (readCommand.length() <= 0)
    {
      imapClient.flush();
      imapClient.stop();
    }
    else
    {
      readCommand = imapCommand("arduino select mailboxname", "Mailbox", (char *)responseOK, false);
      if (readCommand.length() <= 0)
      {
        imapClient.flush();
        imapClient.stop();
      }
      else
      {
        readCommand = imapCommand("arduino idle", "IDLE", "+", true);
        if (readCommand.length() <= 0)
        {
          imapClient.flush();
          imapClient.stop();
        }
      }
    }
  }
  else
  {
    Serial.println("connection failed");
  }
}

/*########################################################################################*/

String imapCommand(String Command, char* Message, char *Response, boolean outputR)
{
  String dummy;
  
  Serial.print(Message);
  Serial.println("...");
  imapClient.println(Command);
//  while (imapClient.available() == 0);
  dummy=imapRead(Response, outputR);
  if (!outputR) dummy = "OK";
  Serial.print(Message);
  if (dummy.length() > 0) Serial.println(" OK");
  else Serial.println(" NK");
  return dummy;
}

/*########################################################################################*/

String imapRead(char *Response, boolean outputR)
{
  String readClient;
  unsigned long timer;
  
  timer = millis();
  
  while (millis() - timer < 5000 && !imapClient.available());
  
  if (imapClient.available())
  {
    while (imapClient.available()) 
    {
      char c = imapClient.read();
      if (outputR) readClient += c;
    }
    readClient = readClient.toUpperCase();
    if (readClient.indexOf(Response) > -1)
    {
      return readClient;
    }
    else
    {
      return "";
    }

  }
  else
  {
    return "";
  }
}

/*########################################################################################*/

void parseImap(String readCommand)
{
  String extract;
  int index = 0;
  int oldindex = 0;
  
  index = readCommand.indexOf("\n");
  while (index != -1)
  {
    extract = readCommand.substring(oldindex, index-1);

    if (extract.indexOf("EXISTS") > -1)
    {
      Serial.println(extract);
    }

    if (extract.indexOf("RECENT") > -1)
    {
      Serial.println(extract);
    }

    if (extract.indexOf("(MESSAGES ") > -1)
    {
        mailMessages = extract.substring(extract.indexOf("(MESSAGES ") + 10, extract.indexOf(")"));
        bitWrite(updated, 1, 1);
    }
            
    if (extract.indexOf("(UNSEEN ") > -1)
    {
        newMessages = extract.substring(extract.indexOf("(UNSEEN ") + 8, extract.indexOf(")"));
        bitWrite(updated, 2, 1);
    }

    if (updated > 0)
    {
      line2 = "Inbox  : " + mailMessages;
      line3 = "Unread : " + newMessages;
      line4 = "Mailbox info";
      bitWrite(updated, 3, 1);
    }


    oldindex = index+1;
    index = readCommand.indexOf("\n", oldindex);
  }
}

/*########################################################################################*/

void getImapStatus()
{
  String dummy;

  dummy = imapCommand("done", "DONE", (char *)responseOK, true);
  if (dummy.length() > 0) 
  {
    parseImap(dummy);
  }

  dummy = imapCommand("arduino status mailboxname (messages)", "STATUS messages", (char *)responseOK, true);

  if (dummy.length() > 0) 
  {
    parseImap(dummy);
  }

  dummy = imapCommand("arduino status mailboxname (unseen)", "STATUS unseen", (char *)responseOK, true);    
  if (dummy.length() > 0) 
  {
    parseImap(dummy);
  }
  
  dummy = imapCommand("arduino idle", "IDLE", "+", true);
  if (dummy.length() > 0) 
  {
    parseImap(dummy);
  }
 
}

/*########################################################################################*/

void phoneClient()
{
  String readString;

  Client client = server.available();
  if (client) {
    // an http request ends with a blank line
    boolean currentLineIsBlank = true;
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();

        readString += c;
        
        // if you've gotten to the end of the line (received a newline
        // character) and the line is blank, the http request has ended,
        // so you can send a reply
        if (c == '\n' && currentLineIsBlank) {
          // send a standard http response header
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println();

          if (readString.startsWith("GET /ASTERISK_IN|")) {
            if (readString.startsWith("GET / HTTP/1.1")) {
            } 
            else {
              line2 = readString.substring(17,readString.indexOf("|",17));
              bitWrite(updated, 1, 1);
              line3 = readString.substring(readString.indexOf("|",17)+1, readString.indexOf(" HTTP"));
              bitWrite(updated, 2, 1);
              line4 = "Incoming Call";
              bitWrite(updated, 3, 1);
              numberDisplay = true;
              timer1 = millis();
            }
          }

          break;
        }
        if (c == '\n') {
          // you're starting a new line
          currentLineIsBlank = true;
        } 
        else if (c != '\r') {
          // you've gotten a character on the current line
          currentLineIsBlank = false;
        }
      }
    }
    // give the web browser time to receive the data
    delay(1);
    // close the connection:
    client.stop();
  }
}