The Sketch
The sketch contains 3 .PDE files. This is the main program.
Download the Thermostat sketch
/* Thermostat with arduino
created 2011
by Boris Landoni
This example code is in the public domain.
http://www.open-electronics.org
http://www.futurashop.it
*/
#include <SPI.h>
#include <Ethernet.h>
#include <avr/pgmspace.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <EEPROM.h>
#define SHARE_FEED_ID 5102 // this is your Pachube feed ID that you want to share to
#define REMOTE_FEED_ID 256 // this is the ID of the remote Pachube feed that you want to connect to
#define REMOTE_FEED_DATASTREAMS 4 // make sure that remoteSensor array is big enough to fit all the remote data streams
#define UPDATE_INTERVAL 20000 // if the connection is good wait 10 seconds before updating again - should not be less than 5
#define RESET_INTERVAL 10000 // if connection fails/resets wait 10 seconds before trying again - should not be less than 5
#define PACHUBE_API_KEY "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" // fill in your API key
#define ONE_WIRE_BUS 4
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
DeviceAddress insideThermometer;
int puls1 = 5; // pulsante per il cambio di modalità di funzionamento
int puls2 = 2; // pulsante per il cambio di modalità di funzionamento
int in = 3; // ingresso del termostato
prog_char string_0[] PROGMEM = "<html><head><title>Boris's Project</title><META HTTP-EQUIV=\"Refresh\" CONTENT=\"3600\"></head>";
prog_char string_1[] PROGMEM = "<body><center><br><form> <input type=button value=\"Refresh \" onClick=\"window.location.reload()\"> </form><br><br><h2>Remote Control Thermostat ";
prog_char string_2[] PROGMEM = " C</h2><form method=GET><font size= 5>Boiler ";
prog_char string_3[] PROGMEM = "</font><br><font size= 3>Input Thermostat ";
prog_char string_4[] PROGMEM = "</font><br><table><td><input type=\"radio\" name=\"statourl\" value=\"1\" onClick=\"this.form.submit()\" ";
prog_char string_5[] PROGMEM = "></td><td>Sensor</td><td><input type=\"radio\" name=\"statourl\" value=\"2\" onClick=\"this.form.submit()\" ";
prog_char string_6[] PROGMEM = "></td><td>Manual</td><td><input type=\"radio\" name=\"statourl\" value=\"3\" onClick=\"this.form.submit()\" ";
prog_char string_7[] PROGMEM = "></td><td>Thermostat</td><br></table> </form><form method=GET>";
prog_char string_8[] PROGMEM = "<table><tr><td><input type=submit name=b11 value=\"Boiler ON\"></td><td><input type=submit name=b10 value=\"Boiler OFF\"></td><td>";
prog_char string_9[] PROGMEM = "</td></tr></table></form><form method=GET>Temperature: <input type=\"text\" size=\"2\" name=temp value=#* MAXLENGTH=2>";
prog_char string_10[] PROGMEM = "<input type=\"submit\" value=\"Set temperature\"><br></form>";
prog_char string_11[] PROGMEM = "<br><OBJECT classid=\"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\"";
prog_char string_12[] PROGMEM = "codebase=\"http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab";
prog_char string_13[] PROGMEM = "#version=6,0,0,0\" WIDTH=\"200\" HEIGHT=\"100\" id=\"gauge\"><PARAM NAME=\"movie\"";
prog_char string_14[] PROGMEM = "VALUE=\"http://apps.pachube.com/scaredycat/gauge.swf?xml_source=";
prog_char string_15[] PROGMEM = "http%3A//apps.pachube.com/scaredycat/getData.php";
prog_char string_16[] PROGMEM = "%3Fm%3D0%26f%3D5102%26s%3D0%26u%3D30%26l%3D0%26n%3D5%26t%3D";
prog_char string_17[] PROGMEM = "Temperatura%26w%3Dfalse%26c1%3D33FF33%26c2%3DEFE415%26c3%3DEF8B15%26c4%3DFF3333%26";
prog_char string_18[] PROGMEM = "in%3Dtrue\" /><PARAM NAME=\"quality\" VALUE=\"high\" /><param name=\"wmode\" value=\"transparent\">";
prog_char string_19[] PROGMEM = "<param name=\"allowScriptAccess\" value=\"sameDomain\" /><EMBED src=\"";
prog_char string_20[] PROGMEM = "http://apps.pachube.com/scaredycat/gauge.swf?xml_source=";
prog_char string_21[] PROGMEM = "http%3A//apps.pachube.com/scaredycat/getData.php";
prog_char string_22[] PROGMEM = "%3Fm%3D0%26f%3D5102%26s%3D0%26u%3D30%26l%3D0%26n%3D5%26t%3D";
prog_char string_23[] PROGMEM = "Temperatura%26w%3Dtrue%26c1%3D33FF33%26c2%3DEFE415%26c3%3DEF8B15%26c4%3DFF3333%26in%3Dtrue\"";
prog_char string_24[] PROGMEM = "quality=\"high\" wmode=\"transparent\" WIDTH=\"200\" HEIGHT=\"100\"";
prog_char string_25[] PROGMEM = "NAME=\"gauge\" allowScriptAccess=\"sameDomain\" swLiveConnect=\"true\"";
prog_char string_26[] PROGMEM = "TYPE=\"application/x-shockwave-flash\" PLUGINSPAGE=\"";
prog_char string_27[] PROGMEM = "http://www.macromedia.com/go/getflashplayer\"></EMBED></OBJECT>";
prog_char string_28[] PROGMEM = "<br><br><script type=\"text/javascript\" src=\"http://www.google.com/jsapi\">";
prog_char string_29[] PROGMEM = "</script><script language=\"JavaScript\" src=\"http://apps.pachube.com/google_viz/viz_multi.js\">";
prog_char string_30[] PROGMEM = "</script><script language=\"JavaScript\">createViz([5102,5102],[0,1],800,400,[\"ff0000\",\"0000ff\"],0,40);</script>";
prog_char string_31[] PROGMEM = "";
prog_char string_32[] PROGMEM = "";
prog_char string_33[] PROGMEM = "<font size= 2>Powered by Open-Electronics.org - Boris Landoni</font>"; //please don't remove :-)
prog_char string_34[] PROGMEM = "";
prog_char string_35[] PROGMEM = "";
prog_char string_36[] PROGMEM = "";
prog_char string_37[] PROGMEM = "";
prog_char string_38[] PROGMEM = "";
prog_char string_39[] PROGMEM = "";
prog_char string_40[] PROGMEM = "<br></center></body></html>";
prog_char string_41[] PROGMEM = "<font color=\"red\">ON</font>";
prog_char string_42[] PROGMEM = "OFF";
prog_char string_43[] PROGMEM = "checked";
prog_char string_44[] PROGMEM = "on";
prog_char string_45[] PROGMEM = "off";
PROGMEM const char *string_table[] = // change "string_table" name to suit
{
string_0,
string_1,
string_2,
string_3,
string_4,
string_5,
string_6,
string_7,
string_8,
string_9,
string_10,
string_11,
string_12,
string_13,
string_14,
string_15,
string_16,
string_17,
string_18,
string_19,
string_20,
string_21,
string_22,
string_23,
string_24,
string_25,
string_26,
string_27,
string_28,
string_29,
string_30,
string_31,
string_32,
string_33,
string_34,
string_35,
string_36,
string_37,
string_38,
string_39,
string_40,
string_41,
string_42,
string_43,
string_44,
string_45
};
char buffer[150]; // make sure this is large enough for the largest string it must hold
byte mac[] = { 0xDE, 0xAD, 0xBA, 0xAF, 0xFA, 0xAD };
byte ip[] = { 192, 168, 0, 172 };
byte gateway[] = { 192, 168, 0, 1 };
byte subnet[] = { 255, 255, 255, 0 };
byte remoteServer[] = { 173,203,98,29 }; // pachube.com
float remoteSensor[REMOTE_FEED_DATASTREAMS]; // we know that feed 256 has floats - this might need changing for feeds without floats
String inString = String(35);
Server server(80);
const int led = 6;
const int rele = 7;
String temp="";
String statourl="";
int tam=0;
int st1=42,st2=42,st3=42,st4=42,st5=43,st6=44;
//float tempCold;
unsigned long pubblica;
unsigned long lampeggio;
int stato=1; // se 0 controllo con sensore temperatura integrato, se 1 controllo manuale, se 2 controllo con termostato esterno
float tempC=0;
void setup()
{
pinMode(puls1, INPUT);
pinMode(puls2, INPUT);
pinMode(in, INPUT);
pinMode(led, OUTPUT);
pinMode(rele, OUTPUT);
Serial.begin(9600);
Ethernet.begin(mac, ip,gateway,subnet);
server.begin();
Serial.println("Serial READY");
Serial.println("Ethernet READY");
Serial.println("Server READY");
sensors.begin();
Serial.print("Found ");
Serial.print(sensors.getDeviceCount(), DEC);
Serial.println(" devices.");
Serial.print("Parasite power is: ");
if (sensors.isParasitePowerMode()) Serial.println("ON");
else Serial.println("OFF");
if (!sensors.getAddress(insideThermometer, 0)) Serial.println("Unable to find address for Device 0");
Serial.print("Device 0 Address: ");
printAddress(insideThermometer);
Serial.println();
// set the resolution to 9 bit (Each Dallas/Maxim device is capable of several different resolutions)
sensors.setResolution(insideThermometer, 9);
Serial.print("Device 0 Resolution: ");
Serial.print(sensors.getResolution(insideThermometer), DEC);
Serial.println();
}
// function to print a device address
void printAddress(DeviceAddress deviceAddress)
{
for (uint8_t i = 0; i < 8; i++)
{
if (deviceAddress[i] < 16) Serial.print("0");
Serial.print(deviceAddress[i], HEX);
}
}
void printWebPage(Client *client)
{
int tmp=0;
int temperatura=0;
// send a standard http response header
client->println("HTTP/1.1 200 OK");
client->println("Content-Type: text/html");
client->println();
strcpy_P(buffer, (char*)pgm_read_word(&(string_table[0]))); // Necessary casts and dereferencing, just copy.
client->println( buffer );
//Serial.println( buffer );
for (int i = 1; i < 41; i++)
{
if (i==9)
{
strcpy_P(buffer, (char*)pgm_read_word(&(string_table[i]))); //butto tutto nell'array buffer
for (tmp=0 ; tmp < sizeof(buffer); tmp++)
{
if (buffer[tmp]=='#')
{
//Serial.println( "trovato ##### " );
temperatura = EEPROM.read(0);
Serial.print("dato in mem : ");
Serial.println(temperatura);
buffer[tmp] = char ((temperatura/10)+48);
tmp++;
buffer[tmp] = char ((temperatura % 10)+48);
}
}
}
else
{
strcpy_P(buffer, (char*)pgm_read_word(&(string_table[i]))); // Necessary casts and dereferencing, just copy.
}
client->println( buffer );
switch(i){
case 1:
itoa (tempC, buffer, 10); client->print( buffer ); Serial.print( buffer ); client->print( "," ); Serial.print( "," ); itoa ((int(tempC * 100) % 100), buffer, 10); client->print( buffer ); Serial.print( buffer ); break;
case 2:
if(digitalRead(rele)) st4=41;
else st4=42;
strcpy_P(buffer, (char*)pgm_read_word(&(string_table[st4]))); client->println( buffer ); Serial.println( buffer ); break;
case 3:
strcpy_P(buffer, (char*)pgm_read_word(&(string_table[st6]))); client->println( buffer ); Serial.println( buffer ); break;
case 4:
if (stato==1){
strcpy_P(buffer, (char*)pgm_read_word(&(string_table[st5]))); client->println( buffer ); Serial.println( buffer ); break;
}
case 5:
if (stato==2){
strcpy_P(buffer, (char*)pgm_read_word(&(string_table[st5]))); client->println( buffer ); Serial.println( buffer ); break;
}
case 6:
if (stato==3){
strcpy_P(buffer, (char*)pgm_read_word(&(string_table[st5]))); client->println( buffer ); Serial.println( buffer ); break;
}
}
delay(30);
}
}
void verificaingressi()
{
int temperatura = EEPROM.read(0);
if (!digitalRead(puls1))
{
stato=stato+1;
if (stato>3)
{
stato=1;
}
EEPROM.write(1, stato);
digitalWrite(led,HIGH);
delay(1000);
digitalWrite(led,LOW);
delay(1000);
lampeggio=4000; //così lampeggia poi subito
}
if (stato==1)
{
if (tempC<temperatura )
{
digitalWrite(rele,HIGH);
//st4=41;
}
else
{
if (tempC>(temperatura+1))
{
digitalWrite(rele,LOW);
//st4=42;
}
}
}
if (!digitalRead(in))
{
if (stato==3) digitalWrite(rele,HIGH);
st6=44;
}
else
{
if (stato==3) digitalWrite(rele,LOW);
st6=45;
}
}
void loop()
{
stato = EEPROM.read(1);
verificaingressi();
sensors.requestTemperatures(); // Send the command to get temperatures
tempC = sensors.getTempC(insideThermometer);
if (millis() < pubblica) pubblica = millis();
if ((millis() - pubblica) > UPDATE_INTERVAL){
pubblica = millis();
Serial.println("Pubblico");
Serial.print("Temp C : ");
Serial.println(tempC);
if (tempC<50 && tempC>-20)
{
pachube_in_out(tempC);
}
}
if (millis() < lampeggio) lampeggio = millis();
if ((millis() - lampeggio) > 5000){ //ogni 5 sec faccio lampeggiare il led giallo
lampeggio = millis();
for (int i = 0; i < stato; i++)
{
//Serial.println("lamp");
digitalWrite(led,HIGH);
delay(250);
digitalWrite(led,LOW);
delay(250);
}
}
Client client = server.available();
int led=0;
int tmp=0;
if (client) {
// an http request ends with a blank line
boolean current_line_is_blank = true;
while (client.connected()) {
if (client.available()) {
char c = client.read();
if (inString.length() < 35) {
inString.concat(c);
}
if (c == '\n' && current_line_is_blank) {
if(inString.indexOf("b10")>=0){
digitalWrite(led,LOW);
stato=2;
}
if(inString.indexOf("b11")>=0){
digitalWrite(led,HIGH);
stato=2;
}
if(inString.indexOf("b40")>=0){
digitalWrite(led,LOW);
}
if(inString.indexOf("b41")>=0){
digitalWrite(led,HIGH);
}
if(digitalRead(rele)) st4=41;
else st4=42;
if (inString.indexOf("temp")>=0){
char tempArr[20];
temp=inString.substring(inString.indexOf('p')+2, inString.indexOf(" H"));
temp.toCharArray(tempArr, 5);
EEPROM.write(0, atoi(tempArr));
tmp = EEPROM.read(0);
stato=1;
}
if(inString.indexOf("statourl")>=0){
char statoArr[20];
statourl=inString.substring(inString.indexOf('l')+2, inString.indexOf(" H"));
statourl.toCharArray(statoArr, 5);
stato=(atoi(statoArr));
}
EEPROM.write(1, stato);
verificaingressi();
printWebPage( &client);
break;
}
if (c == '\n') {
// we're starting a new line
current_line_is_blank = true;
} else if (c != '\r') {
// we've gotten a character on the current line
current_line_is_blank = false;
}
}
}
// give the web browser time to receive the data
delay(1);
inString = "";
client.stop();
}
}
Great job- very impressive!
What kind of tool did you use to create the HTML code?
That is one place where I lack experience, and I am working on a similar project.
Also, how can one make the site secure to avoid tampering by unauthorized users?
Many thanks!
Thank you,
I use simple Notepad++ and test the page on the various browser.
The page is very simple.
You can add a login page on Arduino
Take a look http://www.arduino.cc/playground/Code/WebServer
[…] (http://www.open-electronics.org/web-thermostat-with-arduino/)Alarm systems (http://www.abbotsfordsecurityalarms.ca/blog/?p=12)Appliance controllers […]
Hi Boris. Very good job. Thanks for the information.
I have one question: in order to get/set current data in the board from Pachube, do you connect directly arduino RJ45 cable to your home router?
Thanks in advance!
Hi Alex, in the sketch there are all network config.
To send data to pachube and set temperature you have to connect the board to ethernet
[…] Visto en Open Electronics + Pachube + Descargar esquema, PCB, firmware y […]
[…] Web thermostat with Arduino […]
[…] Web thermostat with Arduino […]