Equipped with Ethernet interface, Arduino controls a boiler to maintain the set temperature and publish environmental data via Internet on Pachube, and the web interface allows setting the temperature remotely via Internet.
The Circuit
The Ethernet module is a WIZNET network adapter that can be interfaced via the SPI bus (Serial Peripheral Interface) 4-wire.
The module is a WIZ811MJ ethernet (IEEE 802.3/802.3) and W5100-based chip with full magnetic filters ethernet connector and 2 LEDs for status signaling. The module communicates with the microcontroller by SPI. It works with 3.3 Vcc and the 3V3 are provided by Arduino.
The connector J3 is that counts the largest number of connections: it comes from the control signal of the transistor T1, the controller of the relay RL1 (in parallel with the coil there is the LED LD2, signaling, the excitement of the relay). Through J3 the Arduino reads status of buttons P1 and P2 and the input IN, all with pull-up resistor. The yellow LED LD1 is used to give the state mode or assist the setting of operation modes made with the P1 button. This allows you to choose between modes of operation of the system: sensor, manual or thermostat. Pressing once set the system in the sensor mode (automatic) and that this operation is indicated by a flashing dell’LD1, two pressures set the sistem in manual mode (command from web page), which is indicated by two flashes Led. Finally, three pressures set the system in thermostat mode (slave input IN), and this is communicated by three consecutive flashes dell’LD1. Pressing the button P1 returns the sistem in the first mode.
As for P2, currently not used and is reserved for future developments.
R1: 4,7 kohm R2: 10 kohm R3: 470 ohm R4: 4,7 kohm R5: 4,7 kohm R6: 4,7 kohm R7: 4,7 kohm R8: 4,7 kohm U1: WIZNET U2: DS18B20 P1: Microswitch P2: Microswitch LD1: led 3 mm yellow LD2: led 3 mm red T1: BC547 RL1: Relé 5V D1: 1N4007 - Screw connector 2 via - Screw connector 3 via - Strip male 6 via(2 pz.) - Strip male 8 via (2 pz.) - Strip female 10 via (4 pz.) - PCB |
How to use
Opening in the browser the thermostat IP address (defined by the Arduino firmware) you can access the page and set the temperature of the system, the functions or active manually the boiler.
In the web page in memory dell’Arduino is also inserted a reference to the graphs of the gadget sites, in the graph bottom of the page where you can choose which display period (from 1 minute to 1 year).
The web page contains the top, some buttons and boxes for the settings. There is a refresh button and below there are an indication of the status of the boiler (OFF or ON): the system can be used for both heating systems both cooling and air conditioning: it depends on how connected the relay. In fact, with the exchange between C and NO it controls the boiler, while that between C and NC controls the air conditioner, this is because until the temperature is less than the threshold, the relay is energized and closes NO to NC, so it can turn on a boiler or other heating system, while when the temperature exceeds the set threshold, the relay returns to rest and NC close to C, going to control the cooling system.
We continue with the analysis of web page talking about the radio buttons under the present condition of the boiler, which are three and let you set how our system should work: clicking on the relay sensor is controlled based on temperature detected by the Dallas sensor, while opting for manual you can make the relay turn on and off using the On-screen buttons Boiler (relay activated), and Off Boiler (relay deactivated). Finally, opting for thermostat, the relay will be controlled according to the condition of our input IN interface card, this mode allows you to enslave the functioning of our system to an existing thermostat is substantially repeated in the environment and to relay the condition of the thermostat itself.
Below the radio buttons that define how, is the section of the temperature setting: Click in the box, you can set at will (within limits) the temperature at which the system should take, the setting made applies here by clicking the Set temperature.
We conclude the description of the web page with the chart, which summarizes the time courses of temperature measured by the sensor and the display may relate to a period of time to choose between 1 minute and 1 year.
As mentioned, the public system at that site www.pachube.com the value of the measured temperature, in a personal page reserved for each registered user, this site provides a service for storage and display of data from various sources, ranging from information gathered from sensors in environmental data, various measures, then everything is shared, or made accessible to registered users of the community.In order to publish data on www.pachube.com you must first register and create an account, then take your chosen username and validated by the site and write in the special section of the firmware on the feed, without informing the user name of firmware, our system will not be able to access the site and publish the data.
Delivery of data for the upgrade can be done with a frequency set by firmware, bearing in mind the limits allowed by the site (about 50 accesses per hour) for obvious reasons, because if any application tries to access in real time site for uploading the data, at some point the bandwidth of the connection used by it and would soon be saturated with its server would have some problem to run.
Well, having said that we can conclude by pointing out that clicking on the word pachube that is below the temperature graph, you enter the page on www.pachube.com mail account used by the system to publish data on the page shown address of the corresponding link, containing the account name.
The Sketch
The sketch contains 3 .PDE files. This is the main program.
Download the Thermostat sketch
Source Code:
/* Thermostat with arduino
created 2011
by Boris Landoni
This example code is in the public domain.
http://www.s2ptech.blogspot.com
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 <img src="http://www.open-electronics.org/wp-includes/images/smilies/icon_smile.gif" alt=":-)" class="wp-smiley">
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();
}
}
Hi,
ReplyDeleteNice project.
Can i get the eagle schematics & pcb files .
Regards
Franky