Idea: Home guardian sends e-mail when door stays open

K5CZ:
Please help the absolute beginner.

Is there any project for monitoring door/window stays open or other forms of home surveillance? My idea is to watch the closed garage door. If I go out of the garage and accidentally forget to close the door, so Ardunio mail me after adequate timeout. My smartphone receives e-mail immediately, so we'll know early about this incident.

I believe that this will require Arduino Ethernet with PoE and some NC contact.

Why not just close the door if it is left open too long?

wildbill:
If you have wifi in your house, it might be easier (though more expensive) to use a wifi shield - then you won't have to run ethernet cable to the garage.

Yes, but I'm beginner, first I want to try a simpler way...

wildbill:
You might also consider having the arduino close the door for you - then it can just send a scolding email to let you know it has taken care of the issue.

Good idea!

Arrch:
Why not just close the door if it is left open too long?

Sometimes it is necessary to keep the doors open long (BTW: it's too complicated, because there are no sensor to detect obstacle in the sliding door track and also there are no sensor to detect human inside garage).

K5CZ:
Sometimes it is necessary to keep the doors open long (BTW: it's too complicated, because there are no sensor to detect obstacle in the sliding door track and also there are no sensor to detect human inside garage).

You give it the ability to be disabled; I've done this with my garage.

Arrch:

K5CZ:
Sometimes it is necessary to keep the doors open long (BTW: it's too complicated, because there are no sensor to detect obstacle in the sliding door track and also there are no sensor to detect human inside garage).

You give it the ability to be disabled; I've done this with my garage.

OK, it makes sense.

wildbill:
If you have wifi in your house, it might be easier (though more expensive) to use a wifi shield - then you won't have to run ethernet cable to the garage.

You might also consider having the arduino close the door for you - then it can just send a scolding email to let you know it has taken care of the issue.

The Wifi Shields are killers in terms of cost at the moment - a much cheaper and more flexible way is to look at a TP-Link WNR703 router. $25 - You can get a USB/TTL breakout cable from it for $3 from EBAY.

This then acts like a Serial port to the arduino and anything sent out is caught by Linux on TP-link - the TP-Link can be hardwired ethernet or Wireless (or 3G if that floats your boat)

Using Standard linux it can then act to send emails, fire off prowl alerts etc.

Much cheaper than an ethernet shield and/or a wifi shield and much less resources required on the Arduino

Craig

I think it should send a voice mail instead, with Mr T doing the voices:
"I put the fool that left the door open!"

Today I received Arduino Uno and Ethernet shield, so I tried to write my first programs.

This is my very first attempt to write program for sending e-mails - the program works but not much good. When composed e-mail is too long, the Arduino or the Ethernet Shield (or someone else) losts strings and handshaking between Arduino and Mailserver do not ends succesfully. When #undef DEBUGON is used, I receive totally crippled email (missing 'From', 'To' and 'Subject'). I have no experience how to debug Arduino's program so be patient...

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

//serial line debugging is ON - else #undef DEBUGON for OFF
#define DEBUGON

//User-defined texts - if these in sum are too long or when contains \l\r  - mailing do not work!
String MyID             = "mail.mydomain.foo.com";
String MailFrom         = "arduinoguardian@mydomain.foo.com";
String MailTo           = "k5cz@mydomain.foo.com";
String MailSubject      = "Garage alarm: door not closed!";
String MailPrefaceText  = "This is an automated message - please do not reply directly to this email.";
String MailMainText     = "Garage door at street, city stays accidentally left open.";
String MailFooter       = "Please take appropriate steps to remedy the situation.";
String MailSignature    = "Regards, your Arduino";

//Global variables
String Message = "";

//Global constants

//Fill your MAC from sticker here
byte mac[] = { 
  0x00, 0x00, 0x00, 0x00, 0xFE, 0x00 };
// Mail server IP address
byte mailserver[] = { 
  10, 0, 0, 2 };
int smtpport = 25;  
EthernetClient client;

void setup() {
#ifdef DEBUGON
  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for Leonardo only
  }
  Serial.println("Waiting for DHCP lease ...");
#endif

  // start the Ethernet connection using DHCP:
  if (Ethernet.begin(mac) == 0) {
#ifdef DEBUGON
    Serial.println("Failed to configure IPv4 for using Dynamic Host Configuration Protocol!");
#endif
    // no point in carrying on, so do nothing forevermore:
    for(;;)
      ;
  }
#ifdef DEBUGON
  Serial.println("Dynamic Host Configuration Protocol passed");
  Serial.print("Board IP address = ");
  Serial.println(Ethernet.localIP());
  Serial.print("Network subnet mask = ");
  Serial.println(Ethernet.subnetMask());
  Serial.print("Network gateway IP address = ");
  Serial.println(Ethernet.gatewayIP());
  Serial.print("DNS IP address = ");
  Serial.println(Ethernet.dnsServerIP());
  Serial.print("MAC = ");
  for (byte thisByte = 0; thisByte < 6; thisByte++) {
    // print the value of each byte of the MAC address:
    Serial.print(mac[thisByte], HEX);
    if (thisByte < 5) {
      Serial.print(":");
    };
  };
  Serial.println();
#endif

  delay(1000);

#ifdef DEBUGON
  Serial.print("Connecting to mail server ");
  for (byte thisByte = 0; thisByte < 4; thisByte++) {
    // print the value of each byte of the MAC address:
    Serial.print(mailserver[thisByte], DEC);
    if (thisByte < 3) {
      Serial.print(".");
    };
  };
  Serial.println(" ...");
#endif

  if (client.connect(mailserver, smtpport)) {
    Message = String("EHLO ")+MyID;
#ifdef DEBUGON
    Serial.println("SMTP connection established. Start talking ...");
    Serial.println(Message);
#endif
    client.println(Message);
//    delay(250);

    Message = String("MAIL FROM:<")+MailFrom+String(">");
#ifdef DEBUGON
    Serial.println(Message);
#endif
    client.println(Message);
//    delay(250);

    Message = String("RCPT TO:<")+MailTo+String(">");
#ifdef DEBUGON
    Serial.println(Message);
#endif
    client.println(Message);
//    delay(250);

    Message = String("DATA");
#ifdef DEBUGON
    Serial.println(Message);
#endif
    client.println(Message);
//    delay(250);

    //MAIL HEADER
    Message = String("From:<")+MailFrom+String(">");
#ifdef DEBUGON
    Serial.println(Message);
#endif
    client.println(Message);
//    delay(250);

    Message = String("To:<")+MailTo+String(">");
#ifdef DEBUGON
    Serial.println(Message);
#endif
    client.println(Message);
//    delay(250);

    Message = String("Subject: ")+MailSubject;
#ifdef DEBUGON
    Serial.println(Message);
#endif
    client.println(Message);
//    delay(250);

#ifdef DEBUGON
    Serial.println();
#endif
    client.println();
//    delay(250);

    //MAIL BODY
    Message = MailPrefaceText;
#ifdef DEBUGON
    Serial.println(Message);
#endif
    client.println(Message);
//    delay(250);

    Message = MailMainText;
#ifdef DEBUGON
    Serial.println(Message);
#endif
    client.println(Message);
//    delay(250);

    Message = MailFooter;
#ifdef DEBUGON
    Serial.println(Message);
#endif
    client.println(Message);
//    delay(250);

    Message = MailSignature;
#ifdef DEBUGON
    Serial.println(Message);
#endif
    client.println(Message);
//    delay(250);

    Message = String(".");
#ifdef DEBUGON
    Serial.println(Message);
#endif
    client.println(Message);
//    delay(250);

    //Close comunication
    Message = String("QUIT");
#ifdef DEBUGON
    Serial.println(Message);
#endif
    client.println(Message);
//    delay(250);
  } 
  else {
#ifdef DEBUGON
    Serial.println("Connection failed!");
#endif
  }
}

//*********************************************************************************************


void loop()
{
  if (client.available()) {
    char c = client.read();
#ifdef DEBUGON
    Serial.print(c);
#endif
  }

  if (!client.connected()) {
#ifdef DEBUGON
    Serial.println();
    Serial.println("Disconnecting ...");
#endif
    client.stop();
    for(;;);
  }
}

Take two: better handshaking...

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

//serial line debugging is ON - else #undef DEBUGON for OFF
#define DEBUGON
//#undef DEBUGON

#undef TEXTLONG
#undef TEXTSHORT
#define TEXTCZECH

//User-defined texts
String MyID             = "some";
String MailFrom         = "arduino@somewhere";
String MailTo           = "someone@somewhere";

#ifdef TEXTLONG - not working!!!
String MailSubject      = "Garage alarm: door not closed at street/city!";
String MailPrefaceText  = "This is an automated message - please do not reply directly to this email!";
String MailMainText     = "Garage door at street/city stays accidentally left open.";
String MailFooter       = "Please take appropriate steps to remedy the situation.";
String MailSignature    = "My sincere thanks for your time and consideration, your Arduino";
#endif
#ifdef TEXTSHORT
String MailSubject      = "Garage alarm: door not closed!";
String MailPrefaceText  = "This is an automated message - please do not reply!";
String MailMainText     = "Garage door at street/city stays accidentally left open.";
String MailFooter       = "Please take appropriate steps to remedy the situation.";
String MailSignature    = "Regards, your Arduino";
#endif
#ifdef TEXTCZECH
String MailSubject      = "Poplach: otevrena garaz!";
String MailPrefaceText  = "Na tuto zpravu neodpovidejte!\n\r";
String MailMainText     = "Garazova vrata v street/city zustala nedopatrenim otevrena.";
String MailFooter       = "Ucinte prosim potrebne kroky k naprave.\n\r";
String MailSignature    = "S pozdravem, vase Arduino";
#endif

//Global variables
String Message = "";

//Global constants
byte mac[] = { 
  0x00, 0x00, 0x00, 0x00, 0xFE, 0x00 };
// Mail server address
byte mailserver[] = { 
  10, 0, 0, 1 };
int smtpport = 25;  
EthernetClient client;

void setup() {
#ifdef DEBUGON
  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for Leonardo only
  }
  Serial.println("Waiting for DHCP lease ...");
#endif

  // start the Ethernet connection using DHCP:
  if (Ethernet.begin(mac) == 0) {
#ifdef DEBUGON
    Serial.println("Failed to configure IPv4 for using Dynamic Host Configuration Protocol!");
#endif
    // no point in carrying on, so do nothing forevermore:
    for(;;)
      ;
  }
#ifdef DEBUGON
  Serial.println("Dynamic Host Configuration Protocol passed");
  Serial.print("Board IP address = ");
  Serial.println(Ethernet.localIP());
  Serial.print("Network subnet mask = ");
  Serial.println(Ethernet.subnetMask());
  Serial.print("Network gateway IP address = ");
  Serial.println(Ethernet.gatewayIP());
  Serial.print("DNS IP address = ");
  Serial.println(Ethernet.dnsServerIP());
  Serial.print("MAC = ");
  for (byte thisByte = 0; thisByte < 6; thisByte++) {
    // print the value of each byte of the MAC address:
    Serial.print(mac[thisByte], HEX);
    if (thisByte < 5) {
      Serial.print(":");
    };
  };
  Serial.println();
#endif

  delay(1000);

#ifdef DEBUGON
  Serial.print("Connecting to mail server ");
  for (byte thisByte = 0; thisByte < 4; thisByte++) {
    // print the value of each byte of the MAC address:
    Serial.print(mailserver[thisByte], DEC);
    if (thisByte < 3) {
      Serial.print(".");
    };
  };
  Serial.println(" ...");
#endif

  if (client.connect(mailserver, smtpport)) {
    ReadResponse();
    
    Message = String("EHLO ")+MyID;
#ifdef DEBUGON
    Serial.println("SMTP connection established. Start talking ...");
    Serial.println(Message);
#endif
    client.println(Message);
    ReadResponse();

    Message = String("MAIL FROM:<")+MailFrom+String(">");
#ifdef DEBUGON
    Serial.println(Message);
#endif
    client.println(Message);
    ReadResponse();

    Message = String("RCPT TO:<")+MailTo+String(">");
#ifdef DEBUGON
    Serial.println(Message);
#endif
    client.println(Message);
    ReadResponse();

    Message = String("DATA");
#ifdef DEBUGON
    Serial.println(Message);
#endif
    client.println(Message);
    ReadResponse();

    //MAIL HEADER
    Message = String("From:<")+MailFrom+String(">");
#ifdef DEBUGON
    Serial.println(Message);
#endif
    client.println(Message);
    ReadResponse();

    Message = String("To:<")+MailTo+String(">");
#ifdef DEBUGON
    Serial.println(Message);
#endif
    client.println(Message);
    ReadResponse();

    Message = String("Subject: ")+MailSubject;
#ifdef DEBUGON
    Serial.println(Message);
#endif
    client.println(Message);
    ReadResponse();

#ifdef DEBUGON
    Serial.println();
#endif
    client.println();
    ReadResponse();

    //MAIL BODY
    Message = MailPrefaceText;
#ifdef DEBUGON
    Serial.println(Message);
#endif
    client.println(Message);
    ReadResponse();

    Message = MailMainText;
#ifdef DEBUGON
    Serial.println(Message);
#endif
    client.println(Message);
    ReadResponse();

    Message = MailFooter;
#ifdef DEBUGON
    Serial.println(Message);
#endif
    client.println(Message);
    ReadResponse();

    Message = MailSignature;
#ifdef DEBUGON
    Serial.println(Message);
#endif
    client.println(Message);
    ReadResponse();

    Message = String(".");
#ifdef DEBUGON
    Serial.println(Message);
#endif
    client.println(Message);
    ReadResponse();

    //Close comunication
    Message = String("QUIT");
#ifdef DEBUGON
    Serial.println(Message);
#endif
    client.println(Message);
    ReadResponse();
  } 
  else {
#ifdef DEBUGON
    Serial.println("Connection failed!");
#endif
  }
}

//*********************************************************************************************


void ReadResponse()
{
  int counter = 0;
  while(counter != 256 ){
    if (client.available()) 
    {  
      char c = client.read();
#ifdef DEBUGON
      Serial.print(c);
#endif
      while (c != '\n' && c != '\r') {
        c = client.read();
#ifdef DEBUGON
        Serial.print(c);
#endif
      }  
    } 
    else {
      counter++;    }
  }  
}

//*********************************************************************************************


void loop()
{
  if (client.available()) {
    char c = client.read();
#ifdef DEBUGON
    Serial.print(c);
#endif
  }

  if (!client.connected()) {
#ifdef DEBUGON
    Serial.println();
    Serial.println("Disconnecting ...");
#endif
    client.stop();
    for(;;);
  }
}

You have an awful lot of text in your sketch and the uno has only 2K of RAM. Use of String objects will make your consumption of it worse. As a first pass at improving matters use the F macro on all your serial prints to move them to progmem. Like this:

  Serial.print(F("Connecting to mail server "));

wildbill:
You have an awful lot of text in your sketch and the uno has only 2K of RAM. Use of String objects will make your consumption of it worse. As a first pass at improving matters use the F macro on all your serial prints to move them to progmem. Like this:

  Serial.print(F("Connecting to mail server "));

I understand that there is a large consumption of resources, but as novice I do not know what F macro is and what is the difference between Serial.print(F("text")); and Serial.print("text");

Please give me a detailed explanation, thanks!

K5CZ:
...but as novice I do not know what F macro is...

Oh, I found this:

Version 1.0 of the Arduino IDE introduced the F() syntax for storing strings in flash memory rather than RAM. e.g.
Serial.println(F("This string will be stored in flash memory"));

Please help me! I do not know all about C++ , so I'm confused how to fix this line:

buffer = ((char*)pgm_read_word(&TextItemPointers[ItemIndex]));

Idea is, copy text stored in FLASH to buffer in SRAM and manage them.

#include <avr/pgmspace.h>

//do not exceed 80 characters per line!
static char buffer[80+1]; // must be big enough for longest string and the terminating null
char TextMailSubject[] PROGMEM = "Garage alarm: door not closed at Street/City!";
char TextMailBodyLn1[] PROGMEM = "This is an automated message - please do not reply directly to this email!\r\n";
char TextMailBodyLn2[] PROGMEM = "Hi there!";
char TextMailBodyLn3[] PROGMEM = "Garage door at Street/City stays accidentally left open.";
char TextMailBodyLn4[] PROGMEM = "Please take appropriate steps to remedy the situation.\r\n";
char TextMailBodyLn5[] PROGMEM = "My sincere thanks for your time and consideration, your Arduino\r\n";
char TextMailBodyLn6[] PROGMEM = "Date and time of incident:";
char* TextItemPointers[] PROGMEM = {
  TextMailSubject, TextMailBodyLn1, TextMailBodyLn2, TextMailBodyLn3, TextMailBodyLn4, TextMailBodyLn5, TextMailBodyLn6}; 

void setup(){
  Serial.begin(9600);
};

/* function to return one line - string */

char* GetTExtFromFlashMemory(int ItemIndex)
{
  buffer = ((char*)pgm_read_word(&TextItemPointers[ItemIndex]));
  return buffer;
}

void loop(){
  GetTExtFromFlashMemory(1);
  Message = buffer;
//  Message = Message + Someone;
  Serial.println(Message);
  //in future:
  //client.println(Message);
};

This here:

pgm_read_word(&TextItemPointers[ItemIndex]));

Returns a 16 bit value. Say you're trying to read from TextMailSubject, that 16 bit value will contain 'G' and 'a'. You then try turn 'G' and 'a' into a pointer. That's not doing what you think its doing. What you need is to read the first character:

int i = 0;
char c = pgm_read_byte(&TextItemPointers[ItemIndex] + i);

You can put that in your buffer, and use a while loop to keep reading until you reach a null ('\0'):

while (c != '\0')
{

}

Within the while loop, you need to increment i, read the next character, and put that in your buffer. Once you're out of the while loop, you'll just need to null terminate the array:

buffer[i] = '\0';

Arrch:
...

Thank for helping me, I do this and it works as requested!

#include <avr/pgmspace.h>

//do not exceed 80 characters per line!
static char buffer[80+1]; // must be big enough for longest string and the terminating null
char TextMailSubject[] PROGMEM = "Garage alarm: door not closed at Street/City!";
char TextMailBodyLn1[] PROGMEM = "This is an automated message - please do not reply directly to this email!\r\n";
char TextMailBodyLn2[] PROGMEM = "Hi there!";
char TextMailBodyLn3[] PROGMEM = "Garage door at Street/City stays accidentally left open.";
char TextMailBodyLn4[] PROGMEM = "Please take appropriate steps to remedy the situation.\r\n";
char TextMailBodyLn5[] PROGMEM = "My sincere thanks for your time and consideration, your Arduino\r\n";
char TextMailBodyLn6[] PROGMEM = "Date and time of incident:";
char* TextItemPointers[] PROGMEM = {
  TextMailSubject, TextMailBodyLn1, TextMailBodyLn2, TextMailBodyLn3, TextMailBodyLn4, TextMailBodyLn5, TextMailBodyLn6}; 
String Message = "";

void setup(){
  Serial.begin(9600);
};

int GetFreeRAM() {
  extern int __heap_start, *__brkval; 
  int v; 
  return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); 
}

/* function to return string by index */

String GetTextFromFlashMemory(int ItemIndex)
{
  int i = 0;
  char c;
  while (c != '\0')
  {
    c = pgm_read_byte(pgm_read_word(&TextItemPointers[ItemIndex]) + i);
    buffer[i] = c;
    i++;
  }
  buffer[i] = '\0';
  return String(buffer);
}

void loop(){
  Serial.print(F("Free SRAM: "));
  Serial.print(GetFreeRAM());
  Serial.println(F(" bytes")); 
  int thisItem;
  for (thisItem = 0; thisItem < 7; thisItem++) {
    Message = "Item #"+String(thisItem);
    Serial.println(Message);
    Message = GetTextFromFlashMemory(thisItem);
    Serial.println(Message);
  };
  Serial.print(F("Free SRAM: "));
  Serial.print(GetFreeRAM());
  Serial.println(F(" bytes")); 
  delay(5000);
};

Next attempt: attached program sends e-mail with timestamp (IP leased form DHCP, current time obtained from NTP)
memory (SRAM) consumption: about 1,5 KB
sketch size: about 20 KB

send_mail.txt (15.5 KB)

The figures below shows the scheme of electrical circuit as I currently use when debugging my program


click to enlarge


click to enlarge

It is working well, but only one I/O pin left unused. I have not tried SD card yet (so A0 and A1 are free too).

K5CZ:
It is working well, but only one I/O pin left unused. I have not tried SD card yet (so A0 and A1 are free too).

While connected to internet the hardware RTC is superfluous, you can drop the RTC and use software RTC with NTP sync every hour.

My first project is a bit closer to implementation, so this is way how I connected the RGB LED to Crib for Arduino. The LED can be disconnected or easy replaced.

A few days ago... putting into operation (description in czech language).