Arduino and Internet - home automation

Hi all,

I recently finished an Arduino project that I was very proud of and learnt a lot about the Arduino platform (I made an alarm clock with music playing capabilities and a lamp dimmer). I have now come up with a new project. I was thinking of setting up some home automation. I looked into buying systems that would do this for you straight out of the box, but then I thought that it could be fun to do this yourself from scratch. This would be cheaper, more versatile and a great project to undertake. Getting different Arduinos to communicate with each other over a WiFi should not be too much hassle, but I wanted to do something extra special. I have seen a few people talking about communicating with the Arduino over the internet using a web browser, which seems cool in itself. However, I would love to have an app running on my iPhone that would tell my home automation system (run by Arduino) automatically to turn on the heating, for example, when I am 5 miles from the house. Now would anyone know how to get an iPhone app to do this?

Thanks for replies.

Have a look at www.2wg.co.nz - there are quite a few web pages and SD card files that you can access.

www.2wg.co.nz is an Arduino web server application. Via the password protected login function (and with the assistance of session cookies) I can access any application functionality and control any device using any web browser anywhere in the world including Safari on my iPhone.

I guess it would be nice to have an IOS App that could tell my system I was on the way home based on GPS information. However at this time I can still have a collection of desktop icons on my home screen that with a single finger touch could control individual device functionality at home via unique password embedded URL requests.

Does anyone know of any existing IOS App that can automatically issue http URL requests based on GPS co-ordinate information?

Cheers

Catweazle NZ

Baileys24, CatweazleNZ provides an excellent example of where we can go with Home Monitoring but at this stage has provided no source code for us to learn from.

I’m at a similar level of development to yourself and now have a rough Web Server running successfully, the code for which is provided below as it may be of assistance to others.
This code has a lot of comments purposely retained for memory prompts & is based upon what had been previously published by Jimboza late last month & Example sketches. SurferTim had some excellent recommendations I still need to consider / implement.

Hardware I’m using is as follows:

  • UNO
  • Ethernet Shield
  • RTC
  • Dallas Temp Sensor

The UNO is close to running out of memory so I have a MEGA on order from ebay.

Watch your use on SRAM - refer to comments in listing.

I have this running well remotely using Port Forwarding on a TP-Link Modem Router and using DUCKDNS to provide a static IP address.

Next development will be to provide some graphical I/O boxes and get browser inputted data to control the UNO output points.

Elsewhere in another sketch I’ve been able to get twitter notifications running OK so intend merging all of this code into this sketch, within memory restraints.

Obviously there are alternatives to Arduino based Remote Monitoring like ThinkSpeak, MegunoLink or Freedomotic to be considered.

Code follows, it’s obviously a bit messy but anyone is welcome to comment. Due to attachment size restrictions code is broken up as follows:

Initial Part 1 of code follows:

// FileName: 89AHomer_WebSite_RFB09A
// Original Source - refer to http://jimboza.gotdns.com:8085/
// and forum post http://forum.arduino.cc/index.php?topic=280724.new#new

/*
SRAM PROBLEMS
With a lot of code like downloaded to a UNO you soon run out of the limited 2K of Static RAM which is 
where the sketch creates and manipulates variables when it runs.
To overcome this I've using 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"));
Note F() will not work with Serial.print to function calls
Excellent reference is at :  https://learn.adafruit.com/memories-of-an-arduino/optimizing-sram
*/
/*
THANKS & POSTS 
refer to my original calls for help here & assistance from others http://forum.arduino.cc/index.php?topic=280724.0

IDE EXAMPLES used in this project
Will add a list here ....

*/

#include <SPI.h>
#include <Ethernet.h>
#include <Time.h>
#include <Wire.h>
#include <DS1307RTC.h>
#include <OneWire.h>
#include <DallasTemperature.h>

// declare timestrings
String boottime, time_now, h_stg, m_stg, s_stg, d_stg, mth_stg, yr_stg;

//// following is config for I/O  ////////////////

int sensorPin0 = A0;    // select the input pin for sensing
int sensorPin1 = A1;    // select the input pin for sensing
int sensorPin2 = A2;    // select the input pin for sensing
int sensorPin3 = A3;    // select the input pin for sensing
int sensorValue0 = 0;  // initialise variable to store the value coming from the sensor
int sensorValue1 = 0;  // initialise variable to store the value coming from the sensor
int sensorValue2 = 0;  // initialise variable to store the value coming from the sensor
int sensorValue3 = 0;  // initialise variable to store the value coming from the sensor
int ledPin = 13;      // select the pin for the LED


///// following for Dallas OneWire Sensor  ///////////////////////
/////////  following is code for temp sensor a onewire device  as per example file simple.ico ////////////////////////
// Data wire is plugged into port 3 on the Arduino
#define ONE_WIRE_BUS 3
#define TEMPERATURE_PRECISION 12

// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_BUS);

// Pass our oneWire reference to Dallas Temperature. 
DallasTemperature sensors(&oneWire);

// arrays to hold device addresses
DeviceAddress insideThermometer, outsideThermometer;

////////// end of Onewire requirements  /////////////////////////////////////////////

// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = { 
  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192,168,1,177);

EthernetServer server(8085); //server port

String readString; // stores incoming strings from ethernet
const int chipSelect = 4;

Part 2 of code (Setup) follows:

// *************************************** SETUP  **************************************************
void setup(){
  Serial.begin(9600);
  
///////////////// sort out RTC requirements ///////////////////////
  while (!Serial) ; // wait until Arduino Serial Monitor opens
  setSyncProvider(RTC.get);   // the function to get the time from the RTC
  if(timeStatus()!= timeSet) 
     Serial.println(F("Unable to sync with the RTC"));
  else
     Serial.println(F("RTC has set the system time"));      

boot_time_string();  // build the string to be used later in loop

//Serial.println(F("end of RTC stuff"));
/////////////////// end of RTC setups //////////////////////////////
 
/////////// Start up the temp sensor library   /////////////////////
sensors.begin();
  
// locate devices on the bus - look at example Multiple
Serial.print(F("Locating devices..."));  
Serial.print(F("Found "));
Serial.print(sensors.getDeviceCount(), DEC);
Serial.println(F(" devices.")); 

// report parasite power requirements
Serial.print(F("Parasite power is: ")); 
  if (sensors.isParasitePowerMode()) Serial.println("ON");
  else Serial.println("OFF");

  // assign address manually.  The addresses below will need to be changed to valid device addresses on your bus.
  // Device address can be retrieved by using either oneWire.search(deviceAddress) or individually via
  // sensors.getAddress(deviceAddress, index)
  // insideThermometer = { 0x28, 0xBC, 0xDA, 0x95, 0x05, 0x0, 0x0, 0xD2 };
  // outsideThermometer   = { 0x28, 0x3F, 0x1C, 0x31, 0x2, 0x0, 0x0, 0x2 };

  // Search for devices on the bus and assign based on an index.  ideally, you would do this to initially
  // discover addresses on the bus and then use those addresses and manually assign them (see above) once you know 
  // the devices on your bus (and assuming they don't change).
  // 
  // method 1: by index
  if (!sensors.getAddress(insideThermometer, 0)) Serial.println("Unable to find address for Device 0"); 
  if (!sensors.getAddress(outsideThermometer, 1)) Serial.println("Unable to find address for Device 1"); 

  // method 2: search()
  // search() looks for the next device. Returns 1 if a new address has been returned. 
  // A zero might mean that the bus is shorted, there are no devices or you have already retrieved all of them.
  // It might be a good idea to check the CRC to make sure you didn't get garbage. 
  // The order is deterministic. You will always get the same devices in the same order
  //
  // Must be called before search()
  // oneWire.reset_search();
  // assigns the first address found to insideThermometer
  // if (!oneWire.search(insideThermometer)) Serial.println("Unable to find address for insideThermometer");
  // assigns the seconds address found to outsideThermometer
  // if (!oneWire.search(outsideThermometer)) Serial.println("Unable to find address for outsideThermometer");

  // show the addresses we found on the bus
  Serial.print(F("Device 0 Address: "));
  printAddress(insideThermometer);
  Serial.println();

  Serial.print(F("Device 1 Address: "));
  printAddress(outsideThermometer);
  Serial.println();

  // set the resolution to 9 or 12 bit
  sensors.setResolution(insideThermometer, 12);
  sensors.setResolution(outsideThermometer, 12);

  Serial.print(F("Device 0 Resolution: "));
  Serial.print(sensors.getResolution(insideThermometer), DEC); 
  Serial.println();

  Serial.print(F("Device 1 Resolution: "));
  Serial.print(sensors.getResolution(outsideThermometer), DEC); 
  Serial.println();
   
  setSyncProvider (RTC.get); // load time varibles from RTC

  // to be safe, disabling SD card explicitly
  pinMode(4, OUTPUT);
  digitalWrite(4, HIGH);

//////////////////  Start Ethernet   ///////////////////////////////
//  Ethernet.begin(mac, ip, gateway, gateway, subnet);  // from original code
  Ethernet.begin(mac, ip);
  server.begin();
  Serial.print(F("server is at Local Lan IP "));       // for debugging
  Serial.println(Ethernet.localIP());  // for debugging

Serial.println(F("***** Setup finished *****"));

}  ////////////////// END OF SETUP //////////////////////////

Here is remander of code

Part 3 of code (Loop) follows:

//////////////////// START OF LOOP  ////////////////////////////
void loop(){

  ///////////////  SET TIME FROM RTC  //////////////////////////////

 if (timeStatus() == timeSet) {
    Serial.print("Current time @ start of loop is: "); 
    digitalClockDisplay();
  } else {
    Serial.println("The time has not been set.  Please run the Time");
    Serial.println("TimeRTCSet example, or DS1307RTC SetTime example.");
    Serial.println();
    delay(1000);
  }
/////////////////////// END of RTC ////////////////////

///////////////////// NOW TEMPERATURE SENSORS  ///////////////////
  // call sensors.requestTemperatures() to issue a global temperature 
  // request to all devices on the bus
Serial.print(F("Requesting temperatures..."));
sensors.requestTemperatures();
Serial.println(F("DONE"));

  // print the device information
  printData(insideThermometer);    // this prints out the actual temperatures in C & F 
  printData(outsideThermometer);

  // call sensors.requestTemperatures() to issue a global temperature 
  // request to all devices on the bus
Serial.print(F("Requesting temperatures..."));
sensors.requestTemperatures(); // Send the command to get temperatures
Serial.println(F("DONE"));
Serial.print(F("Temperature for the device 1 (index 0) is: "));
Serial.println(sensors.getTempCByIndex(0));   
 
/////////  END OF TEMPERATURE SENSORS ////////////////////////  

///////////  CONNECT TO ETHERNET & SEND PAGE  ////////////////
 // Create a client connection to ethernet
  EthernetClient client = server.available();
  if (client) {
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();

        //read char by char HTTP request
        if (readString.length() < 100) {

          //store characters to string 
          readString += c; 
          Serial.print(c);
        } 

        //if HTTP request has ended
        if (c == '\n') {

          Serial.println(readString); //print to serial monitor for debuging 
          
          client.println("HTTP/1.1 200 OK"); //send new page
          client.println("Content-Type: text/html");
          client.println("Connection: close");  // the connection will be closed after completion of the response
          client.println("Refresh: 30");  // refresh the page automatically every 30 sec
          client.println();

          client.println("<HTML>");
          client.println("<HEAD>");
          client.print("<title>");
          client.print("89AHOMER");  // name of browser tab
          client.println("</title>");
          //client.println("<link href=\"jimza.ico\" rel=\"icon\" type=\"image/x-icon\" />");
          client.println("</HEAD>");
          client.println("<BODY>");

          client.println("<H1>This is Homer Street TEST SITE for ARDUINO</H1>");
          // The h1 element is used to indicate the most important (or highest-level) heading on the page. 
          // In total, we have six heading levels to choose
          
 
          client.print(F("Web Server was booted at DATE: "));
          client.print(d_stg);
          client.print(F(":"));
          client.print(mth_stg);
          client.print(F(":"));
          client.print(yr_stg);
          client.print(F("    TIME: "));
          client.print(h_stg);
          client.print(F(":"));
          client.print(m_stg);
          client.print(F(":"));
          client.print(s_stg);
          client.println("
"); // br: creates a single line break in a block of text 
 
 
          client.print(F("Arduino UNO current System Time is: "));
          client.print(F("       Date = "));
          client.print(day());
          client.print(F("/"));
          client.print(month());
          client.print(F("/"));
          client.print(year()); 
          client.print(F(" Time =  "));
          client.print(hour());
          client.print(F(":"));
          client.print(minute());  
          client.print(F(":"));
          client.print(second());  
          //client.println(" ");
          client.println("
"); // br: creates a single line break in a block of text
          client.println("
"); // br: creates a single line break in a block of text
          client.print(F("Enter F5 to refresh"));

          client.println("
"); // br: creates a single line break in a block of text
          client.println("
"); // br: creates a single line break in a block of text
 
 
          // following is sending some input values to web - i.e. read the value from the sensor:
          sensorValue0 = analogRead(0);  
          client.print(F("A0's Value = "));
          Serial.print("ana val ="); 
          Serial.print(sensorValue0);
          client.print(sensorValue0);        // where sensorValue is a int        
          client.println("
");

          // following is sending some input values to web - i.e. read the value from the sensor:
          sensorValue1 = analogRead(1);  
                    Serial.print("ana val ="); 
                    Serial.print(sensorValue1);
          client.print(F("A1's Value = "));
          client.print(sensorValue1);        // where sensorValue is a int        
          client.println("
");
 
          // following is sending some input values to web - i.e. read the value from the sensor:
          sensorValue2 = analogRead(2);
                    Serial.print("ana val ="); 
                  Serial.print(sensorValue2);  
          client.print(F("A2's Value = "));
          client.print(sensorValue2);        // where sensorValue is a int        
          client.println("
");

          // following is sending some input values to web - i.e. read the value from the sensor:
          sensorValue3 = analogRead(3);
                    Serial.print("ana val ="); 
                  Serial.print(sensorValue3);  
          client.print(F("A3's Value = "));
          client.print(sensorValue3);        // where sensorValue is a int        
          client.println("
");

//  client.print(insideThermometer);    // this prints out the actual temperatures in C & F 
client.println(F("DONE"));
client.print(F("Temperature for the device 1 (index 0) is: "));
client.println(sensors.getTempCByIndex(0));  
          client.println("
");
          client.println("
");
                    
client.print(F("Temperature for sensor 2 index 1) is: "));
client.println(sensors.getTempCByIndex(1));  
          client.println("
");
          client.println("
");

    delay(2000);
  
//          client.print(millis());
//          client.println(" mS since UNO reset or power up = ");
//          client.print((millis())/1000);
//          client.print(" Seconds");
          client.println("
"); 
          // delay(1000);        // INTRODUCE A delay
//          client.print("Temperature ");
//          client.print(analogRead(5)/2);
//          client.print("C");
          client.println("
"); 
         
  //        client.println("<H4>Hardware:</H4>");
          //client.println("
");  
          //client.print("<a href=\"http://arduino.cc/en/Main/ArduinoBoardUnoArduino\">Arduino UNO</a>");
  //        client.println("Arduino UNO");
  //        client.println("
");
  //        client.println("Ethernet shield (includes SD card slot)"); 
  //        client.println("
");
  //        client.println("but LM35 temperature sensor not connected "); 

          client.println("</BODY>");
          client.println("</HTML>");
 
         //stopping client
          client.stop();  // that's all folks to ethernet

        }
      }
    }
  }
  Serial.println(F("."));  // send a linefeed at end of loop
}     ////////////////////////////////////// end of loop  /////////////////////////

Here is remainder of code

Part 4 of code (Functions) follows:

//////////////////  START OF FUNCTIONS  /////////////////////////////////////////

void digitalClockDisplay(){  // digital clock display of the current time
  Serial.print(hour());
  printDigits(minute());
  printDigits(second());
  Serial.print(F(" "));
  Serial.print(day());
  Serial.print(F("/"));
  Serial.print(month());
  Serial.print(F("/"));
  Serial.print(year()); 
  Serial.println(); 
delay(5000);  // loop delay  
}

void printDigits(int digits){
  // utility function for digital clock display: prints preceding colon and leading 0
  Serial.print(F(":"));
  if(digits < 10)
    Serial.print('0');
  Serial.print(digits);
}

void boot_time_string() {  // build boot time string
h_stg = String(hour()); 
m_stg = String(minute());
s_stg = String(second());
d_stg = String(day());
mth_stg = String(month());
yr_stg = String(year());
Serial.print(F("This web server commenced running @ TIME: "));
String boottime = h_stg + ":" + m_stg + ":" + s_stg + " and DATE: " + d_stg + "/" + mth_stg + "/" + yr_stg ;
Serial.println(boottime);
Serial.println(F("  "));
}
 
  // function to print a device address
void printAddress(DeviceAddress deviceAddress)
{
  for (uint8_t i = 0; i < 8; i++)
  {
    // zero pad the address if necessary
    if (deviceAddress[i] < 16) Serial.print("0");
    Serial.print(deviceAddress[i], HEX);
  }
}

// function to print the temperature for a device
void printTemperature(DeviceAddress deviceAddress)
{
  float tempC = sensors.getTempC(deviceAddress);
  Serial.print(F("Temp C: "));
  Serial.print(tempC);
  Serial.print(F(" Temp F: "));
  Serial.print(DallasTemperature::toFahrenheit(tempC));
}

// function to print a device's resolution
void printResolution(DeviceAddress deviceAddress)
{
  Serial.print(F("Resolution: "));
  Serial.print(sensors.getResolution(deviceAddress));
  Serial.println();    
}

// main function to print information about a device
void printData(DeviceAddress deviceAddress)
{
  Serial.print(F("Device Address: "));
  printAddress(deviceAddress);
  Serial.print(F(" "));
  printTemperature(deviceAddress);
  Serial.println();
  
}

Hi all,

sorry I have not resounded quickly to your comments, but I forgot to put email notifications on for this post, so I only checked in today to see if anyone had replied. Thanks rbright and CatweazleNZ for your comments. I have come across the iPhone app IFTTT ("if this then that"). It has an interesting function. You can tell it to email an account (any you wish really) when you are leaving or entering a set area. Hence, I have been trying it out, to email myself when I leave or enter a area of a circumference of 5 miles around my home. I have seen other people use an arduino to check emails (every 10 sec if you like), and then use what is written in the email title to carry out a function. Sounds great in theory. However, just running the IFTTT app (which uses geofencing to track your location, which seems to use less battery than the full GPS service) in the background, it seems to have a bit of a delay in sending the email when you enter or leave the area - anywhere from 3 minutes to 30 minutes. Now this might be OK for some purposes, but I would really have liked something that acted in around 1 minute. This lag might be ok for other people and their projects, I will leave this for them to decide. Maybe there is another iPhone app that works faster, I will research this.

In the mean time I am very interested in the Arduino Yún. It has some very powerful functions via the AR9331 linux component which would allow some extra functionality, but I think it is still hampered by the same problems as the Uno when it comes to an iPhone controlling it by your iPhones coordinates. I have not yet come across an iPhone app that seems to give good control of an arduino, over the internet, that can also run silently in the background. I hopefully will get an Yún for my birthday :slight_smile: :slight_smile:

Anyway, as always, I would love to hear other people's opinions on the issue.

Does anyone know if there is any thing on Temboo that can help out?

Cheers

Bailey24 :wink: