Web-controlled Window Air Conditioner Using an Arduino

It’s done. It works. The internet of things has come to my little apartment in New York City. After about a week of tinkering, soldering, and piecing together bits of code from here and there, I can now load a web page from any browser, see the current temperature in my apartment (and a graph of the last 12 hours), and turn the AC unit on or off with the click of a button. This was accomplished with an Arduino, the open-source prototyping platform and the community of artists, techies and hackers behind it. I’ll show you what it looks like, then I’ll show you how I put it all together (my code is at the bottom if you want to try it yourself!

The End Results:

The screenshots below are from the web server that is running on the arduino.  It simply presents the temperature reading, the ON/OFF state of the Air Conditioner, and a graph from cosm.com of the last 24 hours of temperature readings.  The readings are pushed up to cosm.com every 10 seconds.  (The screenshots have some wild temperature fluctuations because I was hacking a bit, but the steady temperature you see for most of the day is accurate.  The AC was off all day, but it was cool and rainy here in New York City today)

This setup does require a dynamic dns name, and port forwarding on my router, which is not the sexiest way to do a remote control connection.  It works, and I’ll leave the websockets and pusher.com connections for a later date.

 

 

How it Works:

To start with, I purchased the Sparkfun Inventor’s Kit, a great out-of-the-box kit for anyone who wants to start tinkering with an arduino.  It includes an arduino UNO R3, a breadboard, and a plastic mounting panel that holds both the breadboard and the arduino in place.  The kit has resistors, LEDs, and jumper wires, lots of sensors, potentiometers, a motor, pushbuttons, a servo, and plenty more.  Best of all, it has a VERY easy to follow booklet of experiments to build, downloadable sketch code, and even circuit templates that show you exactly where to put each pin on the breadboard.  I knew right away that I wanted to remote control my AC window unit, so I started out playing  with temperature sensing.

Temperature Sensing

The Sparkfun kit comes with a TMP36 temperature sensor, which looks exactly like a transistor.  Give it a voltage and ground (anywhere from 2.7 to 5.5 volts), and it will spit out voltage on its third pin.  Regardless of the input voltage (as long as it is in range), the output voltage is converted into a Celcius temperature reading by subtracting 500mV and multiplying by 100.  (Room temperature of 25° C will have a reading of 750mV.

This seems like a simple enough calculation to do, however the arduino’s analog pin don’t read voltage directly, they compare the voltage on the pin to a reference voltage (5v by default).  When we do an analogRead() in a sketch, the arduino converts the analog voltage into a digital value from 0 to 1023.  To get a temperature in degrees, we need to convert the digital reading back into volts or millivolts.

For example:

if analogRead(A0) = 153 ->

153/1024= .149 or 14.9% of the reference voltage ->

5 volts *.149 = .745 volts

To convert the voltage to temperature, we use the formula above:

.745 volts – .5 *100 = 24.5° C

The Sparkfun temperature sketch can be downloaded here, which spits out constant temperature readings via the arduino’s serial monitor.

I purchased the Arduino Ethernet Shield at this point to have my device start talking to the internet!

Cosm.com, formerly pachube

View the cosm feed for this project, showing real-time temperature data from the Arduino.

Once I knew how to read the temperature sensor and had my ethernet sheild in place, I started looking at Cosm.com to log the data and make fancy graphs on the fly.  Cosm.com has a great arduino tutorial ready to go.  All you need to do is sign up for an account, copy their code, paste in an API key and feed ID, and tell the arduino what data you’d like to send.

Cosm has a great API that will let you integrate your data into other apps, but for my purposes, the built-in graph builder worked just fine.

Remote Control

The next step was to figure out remote control.  I originally wanted to find a solution that could use websockets and a remote server so that I wouldn’t have to open a port on my firewall, but I found these to be beyond my capabilities, at least right now.  Cosm had a tutorial for internet control, but it was not real time (the arduino would log into a control feed at regular intervals and download a string of numbers that held values for pin settings.

I ended up finding some simple webserver code that switched an LED on and off using the arduino’s digital outputs and an HTML form.  The example had radio buttons, one for on, and one for off, and a submit button.  It simply added ?status=0 or ?status=1 to the URL, then read the results and turned the output pin on or off.

I tweaked this web form a bit to pulse a pin on for 500 milliseconds, and got rid of the radio buttons and replaced them with a hidden form field that would pass “status=1″ and reload the page.

I tested this out with an LED, and it worked without a charm.  The next step was to hack my way into the Air Conditioner.

Hacking the AC

All that is necessary to turn the AC on and off is to mimic the action of the power switch, which closes a circuit for a moment and tells the processer in the AC unit that it should turn on (or off).  We need to accomplish this using a digital output pin on the arduino.  A transistor or a reed relay would fit the bill for this task, and I decided to go with the option that had no moving parts.  An NPN transistor with its base connected to my arduino output pin, and it’s collector and emitter connected directly to the power switch on the AC will mimic the pushing of the button when the output goes high.



When the transistor method didn’t work, I did some googling and learned that unless I had an optocoupler in the circuit, I would need to connect the grounds of the arduino and the AC circuit board together. I found a good ground spot with a huge solder pad, and my web-enabled switch was live!Finishing TouchesThe last step was to figure out when the unit was on or off, so it could be displayed.  On advice from my little brother the robotics engineer, I used the power LED.  For whatever reason, it had a voltage in both the  ON and OFF states, but they were different enough to tell the two states apart.  I connected one side of the LED directly to an analog input on the arduino, and set the threshold at 900 (remember, that’s a digital representation of the actual voltage).  If the pin reads above 900, the AC is off.  If it reads below, the unit is on… update HTML accordingly.Tying it all together, I had to combine my functioning webserver code with the cosm.com uploader code, embed a graph from cosm.com (it’s simply a dynamically generated image, so you can easily paste an <img> tag.), and add a refresh button so I could get new temperature readings and a new graph without turning the unit on and off again.Now, before I get on the subway to head home, I can pull out my iPhone and turn on the AC… the apartment will be nice and cool when I arrive.  I hope this helps anyone else who wants to do home automation with Arduinos!Here’s my Code:/*
Web AC Remote
by Chris Whong
Scrapped together using “Webserver” by David A. Mellis (modified by Tom Igoe), and “Cosm Sensor Client” and a tutorial on homebrew-tech.comThis program creates a simple web server that displays the current temperature, the ON/OFF status of an Air Conditioner.
The web page also has a power button that can turn the Air Conditioner on and off, a Refresh button to refresh the page,
and a cosm.com embedded temperature graph.*/#include <SPI.h>

	
	
#include <Ethernet.h>//the next three lines are used by cosm
#define APIKEY "INSERT API KEY HERE" // your cosm api key
#define FEEDID INSERT FEEDID HERE // your feed ID
#define USERAGENT "Cosm Arduino Example" // user agent is the project name//sets pin 7 to output, we flash an LED on pin 7 whenever the program uploads data
int ledPin = 7;//mac and ip address for the ethernet shield to use
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192,168,8, 20);

// Initialize the Ethernet server library
// with the IP address and port you want to use
// (port 80 is default for HTTP):
EthernetServer server(80);

//Initialize an ethernet client for the cosm uploader
EthernetClient cosm;

IPAddress server2(216,52,233,121); // numeric IP for api.cosm.com

unsigned long lastConnectionTime = 0; // last time you connected to the server, in milliseconds
boolean lastConnected = false; // state of the connection last time through the main loop
const unsigned long postingInterval = 10*1000; //delay between updates to Cosm.com
//sets reference voltage to 3.3 volts instead of the default 5. The Ethernet sheild was drawig too much power, and was messing up the readings
void setup()
{
Serial.begin(9600); // open up serial port connection to PC
pinMode(8, OUTPUT); // Set digital pin 8 as output

// start the Ethernet connection and the server:
Ethernet.begin(mac, ip);
server.begin();

analogReference(EXTERNAL);
}

void loop()
{
// listen for incoming clients
EthernetClient client = server.available();
if (client) {
// an http request ends with a blank line
boolean currentLineIsBlank = true;
String buffer = ""; // Declare the buffer variable

while (client.connected()) {
if (client.available()) {
char c = client.read();
Serial.print(c); // Send every character read to serial port
buffer+=c; // Assign to the buffer

// 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();

// read the analog sensor:
float voltage = getVoltage(A0); //getting the voltage reading from the temperature sensor

//convert the voltage we just read into degrees farenheit
int temperature = tempCalc(voltage);

//these lines create the text of the web page
client.print("The indoor temperature is ");
client.print(temperature);
client.print(" degrees farenheit. ");
client.println("<br />");

//read analog pin 1, connected to the power LED on the Air Conditioner circuit board. Reading when off is always greater than 900, reading when on is always greater than 900.
int aread = analogRead(A1);
if (aread>900) {
client.print(" The AC is OFF");
}else{
client.print(" The AC is ON");
}
client.println("<br />");
client.print("Air Conditioner Remote Control by Chris");

client.println("<br />");

//Creates an HTML form with hidden input, and submit button that reloads the page with "?status=1" in the URL
client.print("<FORM action=\"http://YOUR EXTERNAL URL/\" >");
client.print("<P> <INPUT type=\"hidden\" name=\"status\" value=\"1\">");
client.print("<P> <INPUT type=\"submit\" value=\"Power\"> </FORM>");

//Creates an HTML form with a refresh button that reloads the page without any variables
client.print("<FORM action=\"http://YOUR EXTERNAL URL/\" >");
client.print("<P> <INPUT type=\"submit\" value=\"Refresh\"> </FORM>");
client.print("<img src = 'https://api.cosm.com/v2/feeds/61098/datastreams/sensor1.png?width=500&height=250&colour=%230000cc&duration=1day&legend=Degrees%20Farenheit&title=Apartment%20Temperature&show_axis_labels=true&detailed_grid=true&scale=auto&timezone=UTC'>");

break;
}
if (c == '\n') {
// you're starting a new line
currentLineIsBlank = true;
buffer=""; // Clear the buffer at end of line
} else if (c == '\r') {
//if "?status=1" is found at the end of the URL, pulse pin 8 for 500ms, which will power the unit on or off
if(buffer.indexOf("GET /?status=1")>=0){
digitalWrite(8,HIGH); // Catch ON status and set LED
delay(500);
digitalWrite(8,LOW);

}

}
else {
// 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();
}// End AC Control Section

 

//following code sends the temperature readings to a cosm.com feed every 10 seconds

float voltage = getVoltage(A0); //getting the voltage reading from the temperature sensor
//convert the reading into degrees farenheit
int temperature = tempCalc(voltage);

// if there's incoming data from the net connection.
// send it out the serial port. This is for debugging
// purposes only:
if (cosm.available()) {
char c = cosm.read();
Serial.print(c);
}

if (!cosm.connected() && lastConnected) {
Serial.println();
Serial.println("disconnecting.");
Serial.println(temperature);
float Aread = analogRead(A0);
Serial.print("Analog Reading from 0-1023: "); Serial.println(Aread);
float voltageCalc = Aread * 0.0032541666666667;
Serial.print("Millivolt Calculation: "); Serial.println(voltageCalc);
cosm.stop();
}

// if you're not connected, and ten seconds have passed since
// your last connection, then connect again and send data:
if(!cosm.connected() && (millis() - lastConnectionTime > postingInterval)) {
sendData(temperature);
}
// store the state of the connection for next time through
// the loop:
lastConnected = cosm.connected();

} //End Loop
// this method makes a HTTP connection to the server:
void sendData(int thisData) {
// if there's a successful connection:
if (cosm.connect(server2, 80)) {
Serial.println("connecting...");
// send the HTTP PUT request:
cosm.print("PUT /v2/feeds/");
cosm.print(FEEDID);
cosm.println(".csv HTTP/1.1");
cosm.println("Host: api.cosm.com");
cosm.print("X-ApiKey: ");
cosm.println(APIKEY);
cosm.print("User-Agent: ");
cosm.println(USERAGENT);
cosm.print("Content-Length: ");

// calculate the length of the sensor reading in bytes:
// 8 bytes for "sensor1," + number of digits of the data:
int thisLength = 8 + getLength(thisData);
cosm.println(thisLength);

// last pieces of the HTTP PUT request:
cosm.println("Content-Type: text/csv");
cosm.println("Connection: close");
cosm.println();

// here's the actual content of the PUT request:
cosm.print("sensor1,");
cosm.println(thisData);

//flash the LED for 1 second!
digitalWrite(ledPin, HIGH);
delay(1000);
digitalWrite(ledPin, LOW);

}
else {
// if you couldn't make a connection:
Serial.println("connection failed");
Serial.println();
Serial.println("disconnecting.");
cosm.stop();
}
// note the time that the connection was made or attempted:
lastConnectionTime = millis();
}

/*
* getVoltage() - returns the voltage on the analog input defined by
* pin... using an odd calculation based on trial and error, comparing calculated temperatures to an external digital thermometer.
It should be 3.3v/1024/1000, but this is what gets us accurate readings. You may need to tweak this.
*/
float getVoltage(int pin){
return (analogRead(pin) * 0.0032541666666667
); //converting from a 0 to 1023 digital range
}

int getLength(int someValue) {
// there's at least one byte:
int digits = 1;
// continually divide the value by ten,
// adding one to the digit count for each
// time you divide, until you're at 0:
int dividend = someValue /10;
while (dividend > 0) {
dividend = dividend /10;
digits++;
}
// return the number of digits:
return digits;
}

//function to convert analog reading into degrees farenheit
int tempCalc(float reading) {
//convert analog reading to degrees celcius
float temp = (reading - .5) * 100;
//convert degrees celsius to farenheit
temp = ((temp * 9) / 5) + 32;

return temp;
}

4 Responses to “Web-controlled Window Air Conditioner Using an Arduino”

  1. Haris Hashim August 18, 2012 at 5:48 am #

    Great write up and thanks for the link back to my article.

    Best Regards,
    Haris | homebrew-tech.com

  2. Vin February 13, 2013 at 7:09 pm #

    I noticed that once you click the button, if you refresh the page with F5 it will always trigger the 500ms output. This is because ?status=1 is at the end of the URL. I assume that is why you have your refresh button there as well.

    I’ve tried modifying your code to make it automatically refresh and get rid of the ?status=1 after a period of time but have been unsuccessful. Have you by chance figured out a workaround?

Trackbacks/Pingbacks

  1. Arduino & Pusher-Powered Remote Control Hexbug | Charm City Networks | IT Services & Computer Repair in Baltimore Maryland - July 20, 2012

    [...] success with the Arduino Air Conditioner Remote Control, and getting Pusher authentication and client events working from an Arduino, I was in search of [...]

  2. Sending Pusher Client Events from an Arduino | Charm City Networks | IT Services & Computer Repair in Baltimore Maryland - August 3, 2012

    [...] few weeks ago, I got my first arduino and set out to make my window air conditioner web-remote-controllable. Following some examples online, I created an Ethernet Server that displayed a simple web page with [...]

Leave a Reply

css.php