Project tutorial
Arduino Gmail Clock

Arduino Gmail Clock © GPL3+

The number of unread emails and the hour on a 16x2 LCD display.

  • 250 views
  • 0 comments
  • 1 respect

Components and supplies

Apps and online services

About this project

I started learning programming languages some years ago with Arduino, now I'm developing iOS apps that is a bit more difficult than Arduino. Yesterday I was tidying my bedroom and I found the shoebox with my Arduino kit inside and since I'm a little bit more expert in this topic I have though to build something with this small board.

Now we are in 2019 and internet is the centre of our lives, why it can't be the centre of my project? In fact this projects depends 100% by internet.

The Gmail Sync Method

Since the Ethernet Shield doesn't support SSL (nowadays required for basically every login service) I had to use a php script in a server (it may be local or not). This php script gets the number of unread emails from the Gmail server's response (in XML) and it prints off the number in this format (useful for Arduino parsing) mailXX where XX is the number of unread emails, here's the script:

<?php
function check_email($username, $password)
{ 
   //url to connect to
   $url = "https://mail.google.com/mail/feed/atom"; 
   // sendRequest 
   $curl = curl_init();
   curl_setopt($curl, CURLOPT_URL, $url);
   curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1);
   curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
   curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
   curl_setopt($curl, CURLOPT_USERPWD, $username . ":" . $password);
   curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
   curl_setopt($curl, CURLOPT_ENCODING, "");
   $curlData = curl_exec($curl);
   curl_close($curl);
   //returning retrieved feeds
   return $curlData;
}
$feeds = check_email("YOUR@EMAIL.ADDRESS", "YOURPASSWORD");
$xmlobjc = new SimpleXMLElement($feeds);
echo "mail" . $xmlobjc->fullcount[0];
?>

How Arduino Gets The Data

For the time I have copy-pasted the code from the UdpNtpClient and it worked perfectly, and for getting the number of unread emails from the php script I have copy-pasted the code from WebClient :P.

But Arduino needs to extract the value from the HTTP response string, so I have included the TextFinder library and with it installed I just wrote

finder.find("mail"); 
long value1 = finder.getValue(); 

to get the value immediately after the word "mail".

The Sync Frequency

Arduino updates the time every 10 second for 10 times, at the 10th time also syncs the unread email number. So every 100 seconds the number changes according to the unread emails.

Security

When you open Google from your browser you probably will see this:

This means that "somebody entered to your account with your password in a suspicious mode" and that's true. In fact my php code uses a very basic and insecure method to get the unread emails number. So be careful, load the php file in your computer or in a trusted sever without sharing the IP address.

How to build it

As you can see it's very simple, just snap the Ethernet Shield in your Arduino and connect the LCD display (I use one from the Arduino Starter Kit) according to this schematic:

Configure the server (locally, on macOS)

I use the preinstalled Apache 2 server on my iMac, but you can put the php file in every server, you only need the IP address. To configure the server in macOS:

  • Download the php file
  • Put it the /Library/WebServer/ dir
  • Open the terminal and type sudoapachectlrestart

To test it type 172.0.0.1/nameofthefile.php in your browser and you will see a string like mail43

Remember to put your email and password in the php file and the server's IP address in the sketch!

Command S, Command R!

Now you just have to load the.ino file and you will see something like this:

TO-DOs

I think my project will be awesome with a 3D printed enclosure

Other Projects

Go check my GitHub page here to see some Swift-related projects

Code

PHP CodePHP
The server-side code
<?php
function check_email($username, $password)
{ 
    //url to connect to
    $url = "https://mail.google.com/mail/feed/atom"; 
 
    // sendRequest 
    $curl = curl_init();
    curl_setopt($curl, CURLOPT_URL, $url);
    curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($curl, CURLOPT_USERPWD, $username . ":" . $password);
    curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
    curl_setopt($curl, CURLOPT_ENCODING, "");
    $curlData = curl_exec($curl);
    curl_close($curl);
 
    //returning retrieved feeds
    return $curlData;
 
}
$feeds = check_email("YOUR@EMAIL.ADDRESS", "YOURPASSWORD");
 
$xmlobjc = new SimpleXMLElement($feeds);
 
echo "mail" . $xmlobjc->fullcount[0];
?>
ArduinoGMailClockArduino
/*
 
 Arduino Gmail Clock
 
 scritto un pomeriggio del 2019 da FRancesco
 
 This code is in the public domain.
 
 */
 
#include <SPI.h>
#include <Ethernet.h>
#include <EthernetUdp.h>
#include <LiquidCrystal.h>
#include <TextFinder.h>
 

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
unsigned int localPort = 8888;       // porta locale
 
char timeServer[] = "time.nist.gov"; // server dell'orario

 
const int NTP_PACKET_SIZE = 48; 
 
byte packetBuffer[ NTP_PACKET_SIZE]; 

EthernetUDP Udp;

char server[] = "192.168.0.100";
IPAddress ip(192, 168, 0, 177);
IPAddress myDns(192, 168, 0, 1);

EthernetClient client;

TextFinder  finder( client ); //inizializza il parsing

unsigned long beginMicros, endMicros;
unsigned long byteCount = 0;
bool printWebData = true;

const int rs = 7, en = 6, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

// variabili di utility
int refresh = 0;
String tempo = "";

void setup()
{
  lcd.begin(16, 2);
  lcd.print("Caricamento...");
  lcd.setCursor(1,1);
  lcd.print("Caricamento...");
  

  Serial.begin(9600);
  while (!Serial) {
    ; 
  }
 
 
  // inizializza
  if (Ethernet.begin(mac) == 0) {
    Serial.println("Failed to configure Ethernet using DHCP");
    for (;;)
      ;
  }
  Udp.begin(localPort);
}

void loop()
{
  // controllo tempo 
  sendNTPpacket(timeServer); // manda un pacchetto al server e aspetta una risposta dopo 1 secondo
  
  delay(1000);

  // handling dell'errore di connessione alla rete locale
  if (Ethernet.begin(mac) == 0) {
    lcd.clear();
    lcd.print("Errore DHCP");
    Serial.println("Failed to configure Ethernet using DHCP");

    if (Ethernet.hardwareStatus() == EthernetNoHardware) {
      Serial.println("Ethernet shield was not found.  Sorry, can't run without hardware. :(");
      while (true) {
        delay(1); 
      }
    }
    if (Ethernet.linkStatus() == LinkOFF) {
      Serial.println("Ethernet cable is not connected.");
      lcd.clear();
      lcd.print("Cavo non connesso");
    }

    Ethernet.begin(mac, ip, myDns);
  } else {
    // la connessione alla LAN  avvenuta con successo
    Serial.print("  DHCP assigned IP ");
    Serial.println(Ethernet.localIP());
  }

  // se ha ricevuto un pacchetto in risposta
  if ( Udp.parsePacket() ) {
    Serial.println("pacchetto ricevuto");
    lcd.clear();
    lcd.setCursor(0,1);
    lcd.print("Elaborazione...");

    Udp.read(packetBuffer, NTP_PACKET_SIZE); 
 
    unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
    unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);

    unsigned long secsSince1900 = highWord << 16 | lowWord;
    Serial.print("Seconds since Jan 1 1900 = " );
    Serial.println(secsSince1900);
 

    Serial.print("Unix time = ");

    const unsigned long seventyYears = 2208988800UL;

    unsigned long epoch = secsSince1900 - seventyYears;
    // print Unix time:
    Serial.println(epoch);
    
    Serial.print("The UTC time is ");
    Serial.print((epoch  % 86400L) / 3600); 
    tempo = String((epoch  % 86400L) / 3600);

    Serial.print(':');
    tempo = tempo + ":";
    if ( ((epoch % 3600) / 60) < 10 ) {

      Serial.print('0');
      tempo = tempo + String(0);
    }
    Serial.print((epoch  % 3600) / 60); 
    tempo = tempo + String((epoch % 3600) / 60);
                                        
    Serial.print(':');
    if ( (epoch % 60) < 10 ) {

      Serial.print('0');
      //tempo = tempo + ":" + String(0);
    }
    Serial.println(epoch % 60); 
    //tempo = tempo + ":" + String(epoch % 60);
    lcd.clear(); //pulisce lo schermo
    lcd.setCursor(0,0); //imposta il cursore
    lcd.print("      " + tempo); // stampa il tempo al centro del display (impostabile anche nel cursore)
  }
  tempo = ""; // azzerra la stringa del tempo

  // se le 10 richieste di tempo sono state eseguite procede al controllo delle mail
  if (refresh == 10) {
    delay(1000);
  Serial.print("connecting to ");

  Serial.print(server);
  Serial.println("...");

  if (client.connect(server, 80)) {
    Serial.print("connected to ");
    Serial.println(client.remoteIP());
    // Make a HTTP request:
    client.println("GET /test.php HTTP/1.1");
    client.println("Host: www.google.com");
    client.println("Connection: close");
    client.println();
    char c = client.read(); //responso
    finder.find("mail"); //trova il valore immediatamente successivo alla parola "mail"
    long value1 = finder.getValue(); 
    Serial.println(String(value1) + " email non lette"); 
    lcd.setCursor(0,1);
    lcd.print(String(value1) + " email non lette"); //stampa la stringa
  } else {
    // if you didn't get a connection to the server:
    Serial.println("connection failed");
  }
  beginMicros = micros();
  refresh = 0;
  }
  
  // wait ten seconds before asking for the time again
  delay(10000); // richiede il tempo ogni 10 secondi per 10 volte quindi le mail si aggiorneranno dopo 100 secondi
  refresh++;
}
 
//funzione presa da WebClient per mandare i pacchetti udp

unsigned long sendNTPpacket(char* 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.beginPacket(address, 123); //NTP requests are to port 123
  Udp.write(packetBuffer, NTP_PACKET_SIZE);
  Udp.endPacket();
}

Schematics

Schematic
arduino_gmail_clock_qQJwuNrRaE.fzz

Comments

Similar projects you might like

Arduino Brake Rotor Clock

Project tutorial by xXarduino_11Xx

  • 399 views
  • 0 comments
  • 1 respect

Android Things Word Clock

Project tutorial by Daniele Bonaldo

  • 21,081 views
  • 7 comments
  • 119 respects

Arduino nano stepper motor clock

Project showcase by garysat

  • 56 views
  • 0 comments
  • 0 respects

Alarm Clock

Project tutorial by 4 Makers

  • 1,721 views
  • 0 comments
  • 6 respects
Add projectSign up / Login