Arduino Home Remote Control

I once again, again, again and again started a new project. This time it is about controlling an Arduino from a website, and at the still time have a nice and mobile friendly GUI.

The project can be followed here http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1278347111, but I decided to try and make my own version of it. One of the big differences is that I use a MySQL database to store the status from the arduino.

The database is only synchronized every 15th second, or when any of the lights are actually changed. With that change it can easily handle multiple clients at the same time, and even with a faster rate. The original design had a 2000ms refresh delay, and asked the Arduino for each of its pins, this version only asks once. My version runs at 500ms, here is why. One request for status will give something like 1,0 and that is for the first being on, and the second off. The PHP then stores that in the database, along with the time, and then just feeds the other clients that information when they request it. When the information is over 15 seconds old, the Arduino will be asked once again about the status, and it will again be updated in the database. If and of the lights are changed, it will however change right away and due to the only 500ms refresh delay I set it down to, it is close to realtime for all clients, with a maximum 500ms delay from the button is pressed, until everyone see the change.

The GUI it-self is put together by tehjrow and can be downloaded here: http://code.google.com/p/arduino-web-control/downloads/list

To control my Arduino, I use this little program. All it can do right now, is to toggle pin 7 between HIGH and LOW, but good enough for testing.

#include <WiServer.h>
#define WIRELESS_MODE_INFRA	1
#define WIRELESS_MODE_ADHOC	2

#include <WString.h>                // include the String library

boolean debug = true;

// Wireless configuration parameters ----------------------------------------
unsigned char local_ip[] = {10,0,0,15};	// IP address of WiShield
unsigned char gateway_ip[] = {10,0,0,1};	// router or gateway IP address
unsigned char subnet_mask[] = {255,0,0,0};	// subnet mask for the local network
const prog_char ssid[] PROGMEM = {"dd-wrt"};		// max 32 bytes

unsigned char security_type = 3;	// 0 - open; 1 - WEP; 2 - WPA; 3 - WPA2

// WPA/WPA2 passphrase
const prog_char security_passphrase[] PROGMEM = {"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"};	// max 64 characters

// WEP 128-bit keys
// sample HEX keys
prog_uchar wep_keys[] PROGMEM = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,	// Key 0
				  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	// Key 1
				  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	// Key 2
				  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00	// Key 3
				};

// setup the wireless mode
// infrastructure - connect to AP
// adhoc - connect to another WiFi device
unsigned char wireless_mode = WIRELESS_MODE_INFRA;

unsigned char ssid_len;
unsigned char security_passphrase_len;
// End of wireless configuration parameters ----------------------------------------

int motorPin =  7;    // Pin the motor trigger is connected to
int closePin = 3; //When port is closed
int openPin = 4; //When port is open

int    fanon = 0;

int    led7 = 1;
int    led8 = 1;

// This is our page serving function that generates web pages
boolean sendMyPage(char* URL)
{
  if (strcmp(URL, "/toggle7") == 0)
  {
    led7 = 1 - led7;
    if (led7 == 1)
    {
      digitalWrite(motorPin, HIGH);
    }
    else
    {
      digitalWrite(motorPin, LOW);
    }
  }
  if (strcmp(URL, "/toggle8") == 0)
  {
    led8 = 1 - led8;
    if (led8 == 1)
    {
      digitalWrite(motorPin, HIGH);
    }
    else
    {
      digitalWrite(motorPin, LOW);
    }
  }

  WiServer.print(led7); WiServer.print(","); WiServer.print(led8);
  return true;
}

void setup()
{
  pinMode(motorPin, OUTPUT); //Set to output to be able to drive the relay
  pinMode(closePin, INPUT); //Input from switch telling the motor to stop when port is closed
  digitalWrite(closePin, HIGH); //Activate internal pull-up
  pinMode(openPin, INPUT); //Input from switch telling the motor to stop when port is open
  digitalWrite(openPin, HIGH); //Activate internal pull-up

  digitalWrite(motorPin, HIGH); //Set to HIGH when it starts so the TIP102 won't pull the relay.

  // Initialize WiServer and have it use the sendMyPage function to serve pages
  WiServer.init(sendMyPage);
}

void loop()
{
  // Run WiServer
  WiServer.server_task();
}

PHP

Next part of my version is the modifications to middle.php

The table used in the MySQL database is just id|status|time. (might make that automated later)

<?php
$arduinoip = "http://10.0.0.15/";
$interval = 15;

echo $date1;

function request($func, $val)
{
	global $interval;
	global $arduinoip;

	$username="user";
	$password="pass";
	$database="arduino";

	$unixNow = time();

	mysql_connect(localhost,$username,$password);
	@mysql_select_db($database) or die( "Unable to select database");

	if (strtoupper($func) == "F")
	{
		$curl_handle=curl_init();
		curl_setopt($curl_handle,CURLOPT_URL, $arduinoip . $val);
		curl_setopt($curl_handle,CURLOPT_CONNECTTIMEOUT,2);
		curl_setopt($curl_handle,CURLOPT_RETURNTRANSFER,1);
		$buffer = curl_exec($curl_handle);
		curl_close($curl_handle);

		if (!empty($buffer))
		{
			$query="UPDATE status SET time='$unixNow', status='$buffer' WHERE id='1'";
			mysql_query($query);
		}
	}
	else
	{
		$query = "SELECT * FROM status";
		$result = mysql_query($query);

		$unixLast = mysql_result($result, 0, "time");

		if ($unixNow - $unixLast >= $interval)
		{
			$curl_handle=curl_init();
			curl_setopt($curl_handle,CURLOPT_URL, $arduinoip . "/status");
			curl_setopt($curl_handle,CURLOPT_CONNECTTIMEOUT,2);
			curl_setopt($curl_handle,CURLOPT_RETURNTRANSFER,1);
			$buffer = curl_exec($curl_handle);
			curl_close($curl_handle);

			if (!empty($buffer))
			{
				$query="UPDATE status SET time='$unixNow', status='$buffer' WHERE id='1'";
				mysql_query($query);
			}
		}

		$query = "SELECT * FROM status";
		$result = mysql_query($query);
		$status = mysql_result($result, 0, "status");

		$lights = explode(",", $status);

		if ($val == "get7")
		{
			$status = $lights[0];
			if ($status == 0)
			{
				$status = "off";
			}
		}

		if ($val == "get8")
		{
			$status = $lights[1];
			if ($status == 0)
			{
				$status = "off";
			}
		}

		//echo "DEBUG: Updated";
	}
	mysql_close();

	if (empty($status))
	{
		return "<img src='images/ajax-loader.gif'>";
	}
	else
	{
		if ($status == "1")
		{
			return "<img src='images/lighton.png'>";
		}
		else
		{
			return "<img src='images/lightoff.png'>";
		}
	}
}

if (isset($_GET["l"]))
{
	if($_GET["l"] == "toggle8")
	{
		echo request("F", "toggle8");
	}
	else if($_GET["l"] == "toggle7")
	{
		echo request("F", "toggle7");
	}
	else
	{
		echo "Unknown request";
	}
}
else if (isset($_GET["a"]))
{
	if($_GET["a"] == "get8")
	{
		echo request("S", "get8");
	}
	else if($_GET["a"] == "get7")
	{
		echo request("S", "get7");
	}
	else
	{
		echo "Unknown request";
	}
}
else
{
	echo "Unknown request";
}
?>

And lastly, here is the live test of it: http://bld-live.dk/arduino/control/

Leave a Reply