Arduino Webserver with Temperature Monitor / Control

Hey Guys,

I spent the last few days coding up a Webserver for the Arduino with the Aim of using several of them for different purposes
throughout my house. So I made the code as generic as possible. I plan on using one to control a HLT (Hot Liquor Tank) on a Brewery,
One for Fermentation Control and one to simply switch on my Coffee Machine remotely but I can think of a multitude of uses if
I can knock up my own boards/enclosures cheap enough.

I grabbed the cheapest parts I could find on eBay so I'm using an Arduino Nano Clone, Enc28J60 Ethernet, Dallas Ds18b20 Temperature Sensor & an LED (to replicate a Solid State Relay - SSR)
You could easily get this sketch working with any Arduino & also a Wiznet w5100 with only a few lines of code change.

Parts - Ethernet Board on the left, Arduino on the Right.

Browser Output (Auto Mode)

Browser Output (Manual Mode)

Source Code ==> Google

Thanks for Looking, Hope others find the code useful

Cheers Rob.

Hey Guys,

My Arduino is still running strong with the above sketch, and I had some time at lunch so I knocked up a Shield and sent it of to get fabbed.
It will allow me to keep everything together and a small footprint (51cmx51cm)
It has screw down Terminals for 4 x SSR's and as many Temperature sensors as I want, a pin header for Ethernet as well which supports both
ENC28J60 & Wiznet Chips & 2 pin headers for each pin on the Arduino.

Cheers Rob.

I end up re-writing my code using a better Ethernet Library (EtherCard)
I'm really happy with how it is running, most of my bits have arrived from china just waiting on the Custom PCB to arrive.

Cheers Rob.

Nice work! :slight_smile: Thanks for sharing source code.

I'm currently working on a similar solution, but I'm using a web server running Django to control my arduinos. I needed a good example to show how I could use the EtherCard Library.

I want know whether Arduino Nano Clone is a USB Microcontroller or not? .Because I found a product in website named http://iteadstudio.com and the product name is Arduino Nano USB Microcontroller v3 (Clone version) .As you mentioned in your description the these words "Arduino" ,"Nano" and "Clone" words are containing in the product name Arduino Nano USB Microcontroller v3 (Clone version). If you mentioned the same product can you please tell me the prize you bought that part and from where you bought it. So I can compare it with the prizes in markets and buy the cheapest one

Dashquid
fatlossprofessional.co.uk
fatlossprofessional
mobilehelper
securetrip
whichpetcover
google
abc
facebook
craigslist

Great job!

warunasanjaya11,

Yes the Nano is USB. The one on the website you listed is the same as the one I got.

I just grabbed the Nano ($15 inc post) and Ethernet Controller ($5 inc post) from dealextreme, but ebay had similar prices.

Amazing how cheap all this stuff has gotten over the last couple of years.

Cheers Rob.

Hi

I really like your project, it has finally got me to understanding some of the programming involved in completing this.

You have changed your sketch from version one, do you have any plans to post the new sketch?

I'd like to compare the two new vs old.

Thanks you have been a great help.

Rich

Hey Rich,

Thanks much appreciated.

When I changed the sketch to the Ethercard library I updated it on the link too. So that is latest version.

Still waiting on the Custom PCB to arrive to finish the project.....

Cheers Rob.

Hi looks good - I have a question on the PCB?

Did you order just one? or a few?

What was the cost? including shippping?

And who did it?

I want to get some board made but still not sure of where to get it done. I am in New Zealand.

Also what did you use for the board design?

Cheers

Chris

Hi looks good - I have a question on the PCB?

Hello Chris

Did you order just one? or a few?

I ordered 3 (the minimal)

What was the cost? including shippping?

$5 per square inch for three copies of your design and postage was $5, so If you can fit it on a square inch works out to be ~$3.30 a board

Pricing is here OSH Park Docs ~ Services ~ Fabrication Services

And who did it?

These guys http://oshpark.com/
Great site and very easy to use and deal with.

I want to get some board made but still not sure of where to get it done. I am in New Zealand.

I am in Australia so not to far :slight_smile:

Also what did you use for the board design?

I used Eagle free version

http://www.cadsoftusa.com/eagle-pcb-design-software/?language=en

easy enough to use and there is heaps of guides on youtube, instructables etc.

Rob.

Thanks Rob

Appreciate the quick response

chris

Im having trouble with this ethernet module. What pinout did you use with the jeelabs library.
thanks Michael

Looks great! Well done!

michaelelcano:
Im having trouble with this ethernet module. What pinout did you use with the jeelabs library.
thanks Michael

Hey Michael,

I used :

Arduino ==> Ethernet Controller

2 ==> INT
10 ==> CS
11 ==> SI
12 ==> SO
13 ==> SCK
Reset ==> RST

and +3.3v, Ground

also make sure that you are calling pin 10 at the start of the sketch like os

if (ether.begin(sizeof Ethernet::buffer, mymac, 10) == 0)

Lemme know if you get stuck...

I got the PCB's on friday, soldered it up, put it inside an enclosure and gave it a good run in on the weekend and it works perfectly, very happy, bit of a tight fit inside the enclosure tho!

Cheers Rob.

Thanks Rob for sharing this app. I'm in your tracks (but way behind) on a DINo, with Cosm publishing.

If that helps, I reformatted your sketch (mainly strings and comments) so that it prints correctly. Attached.
Apparently Arduino doesn't word wrap, and fails to print if you lower the margins.

I checked it still compiles, but can't check if it still works OK :wink:

TempControllerWebServer.ino (11.7 KB)

@Rob,

I tried to integrate part of your sketch in mine, and it failed to compile because I didn't include BufferFiller. Strange, as my sketch already included some web page(s?) using the Stash, and I don't see you using it. Any idea on the inner working that could help me understand ?

Thanks for the source code.

I'm new to arduino and html code as well and for my first big project I want to make a web controlled thermostat. I have both an uno and a mega and I am also using a wiznet 5100 ethernet shield. Plan is to wire a set of contacts from my relay module parallel with the thermostat on the wall. In the end I'd like to have a temperature schedule set up on the web page where I can set a different temperature every 3 hours for all 7 days. But for now I'd just like to be able to set the target temperature through the web page.

I was happy when I saw your code cause I needed an example to go off of. Problem is I am using the wiznet 5100 ethernet chip.

Anyways do you know what needs to be changed to get your code to work with the wiznet chip?

I am also using an analog temperature sensor so I edited out all the code for the dallas sensor and added in code for the analog sensor.

Thanks

can someone please explain how the current temperature and the target temperature get displayed on the web page.

I don't understand this
"Temperature: "
"
"
"<font size=""7"">"
"$D.$D °C
"
and this
"Target Temperature: "
"$D.0 °C
"

what is SD.SD and SD.0 are those somehow bound to currenttemp and targettemp?

I'd like to edit the original code to display a couple other values besides the current and target temperatures.

Thanks,

Finally realized how the ethercard code works and was able to edit your original code. Added 3 more text input boxes to the web page. My code has day and night temperature set points as well as day and night start times. I added a real time clock so it will automatically change the target temp based on the times i set on the web page. Thanks again for the source code, I didn't know what I was getting into when I got the Enc28J60 module.

#include <EtherCard.h>
#include <EEPROM.h>
#include <Wire.h>
#include "RTClib.h"

RTC_DS1307 RTC;

char DayTempTextbox[4];               // Data in text box
char NightTempTextbox[4];             // Data in text box
char DayTimeTextbox[4];               // Data in text box
char NightTimeTextbox[4];             // Data in text box

// ethernet interface mac address, must be unique on the LAN
static byte mymac[] = { 0xAA,0xAA,0xAA,0xAA,0xAA,0xAA };
static byte myip[] = { 192,168,1,102 }; //used for static IP

byte Ethernet::buffer[1000];
BufferFiller bfill;

byte TargetTemp = 65;                     
byte DayTempSP = 70;
byte NightTempSP = 68;
byte DayStartTime = 7;
byte NightStartTime = 20;
byte value;

byte TempSensor = A3;
byte HeatONRelay1 = 3;
byte HeatONRelay2 = 4;

const int numReadings = 15;
byte TempReading[numReadings];
byte TempIndex = 0;
int TempTotal = 0;

byte RoomTemperature = 0;
byte TempDBMax = 71;
byte TempDBMin = 69;
byte TempDeadBandSP = 1;

byte Hour = 12;
byte Minute = 24;
byte Second = 36;
byte Month = 11;
byte Day = 23;
int Year = 2012;

//====================================================================================================
void setup () {
//====================================================================================================
  if (ether.begin(sizeof Ethernet::buffer, mymac, 10) == 0);
  ether.staticSetup(myip);
  Wire.begin();
  RTC.begin();
  pinMode(HeatONRelay1, OUTPUT);          // sets the digital pin as input
  pinMode(HeatONRelay2, OUTPUT);          // sets the digital pin as input
  
  analogReference(INTERNAL);  
  
  DayTempSP = EEPROM.read(0);
  NightTempSP = EEPROM.read(1);
  DayStartTime = EEPROM.read(2);
  NightStartTime = EEPROM.read(3);
   
}

//====================================================================================================

const char http_OK[] PROGMEM =
    "HTTP/1.0 200 OK\r\n"
    "Content-Type: text/html\r\n"
    "Pragma: no-cache\r\n\r\n";

const char http_Found[] PROGMEM =
    "HTTP/1.0 302 Found\r\n"
    "Location: /\r\n\r\n";

const char http_Unauthorized[] PROGMEM =
    "HTTP/1.0 401 Unauthorized\r\n"
    "Content-Type: text/html\r\n\r\n"
    "<h1>401 Unauthorized</h1>";

//====================================================================================================
static word homePage() {
//====================================================================================================

//$D = word data type
//$L = long data type
//$S = c string
//$F = progmem string
//$E = byte from the eeprom. 

  char* Heatstat;
  if ( digitalRead(HeatONRelay1) == HIGH ) {
    Heatstat = "On" ; }
  else {
    Heatstat = "Off"; }
    
  bfill.emit_p(PSTR(
  "HTTP/1.0 200 OK\r\n"
  "Content-Type: text/html\r\n"
  "Pragma: no-cache\r\n"
  "\r\n"
  "<!DOCTYPE html>"
  "<html><head>"
  "<meta http-equiv='refresh' content='10'/>"
  "<title>ArduStat</title>"
  "<body bgcolor=""#99CCFF"">"
  "<center>"
  "<hr />"
  "Temperature: <b>"
  "
"
  "<font size=""5"">"
  "$D &deg;F</font></b>"   
  "
"
  "Current Target Temperature: <b>"
  "$D &deg;F</b>"
  "
"
  "Heat is <b>$S</b> "
  "<hr />"
  "Current Temperature Setpoint: <b><font size=""4"">$D &deg;F</font></b>" 
  "<form><input type=text name=daytemp size=4> <input type=submit value=Ok> </form>" 
  "Current Start Time: <b><font size=""4"">$D</font></b>"     
  "<form><input type=text name=daytime size=4> <input type=submit value=Ok> </form>" 
  "Current Temperature Setpoint: <b><font size=""4"">$D &deg;F</font></b>" 
  "<form><input type=text name=nighttemp size=4> <input type=submit value=Ok> </form>"  
  "Current Start Time: <b><font size=""4"">$D</font></b>" 
  "<form><input type=text name=nighttime size=4> <input type=submit value=Ok> </form>"
  "<hr />"
  "Date: $D/$D/$D Time: $D:$D:$D "     
  "</center></body></html>"),
  RoomTemperature, TargetTemp, Heatstat, DayTempSP, DayStartTime, NightTempSP, NightStartTime, Month, Day, Year, Hour, Minute, Second );
  return bfill.position();
         
}
//====================================================================================================
void loop () {
//====================================================================================================

  DateTime now = RTC.now();
  Month = now.month();
  Day = now.day();
  Year = now.year();
  Hour = now.hour();
  Minute = now.minute();
  Second = now.second();
  
  TempTotal = TempTotal - TempReading[TempIndex];
  TempReading[TempIndex] = ((analogRead(TempSensor)/9.31)-3);
  TempTotal = TempTotal + TempReading[TempIndex];
  TempIndex = TempIndex + 1;
  if (TempIndex >= numReadings) {
    TempIndex = 0; }
  RoomTemperature = TempTotal / numReadings;
  
  if ((Hour >= DayStartTime) & (Hour < NightStartTime)) {
    TargetTemp = DayTempSP; }
      
  if ((Hour >= NightStartTime) | (Hour < DayStartTime)) {
    TargetTemp = NightTempSP; }
  
  TempDBMin = (TargetTemp - TempDeadBandSP);
  TempDBMax = (TargetTemp + TempDeadBandSP);  
  
  if (RoomTemperature < TempDBMin) {
    digitalWrite(HeatONRelay1, HIGH);
    digitalWrite(HeatONRelay2, HIGH); }
  if (RoomTemperature > TempDBMax) {
    digitalWrite(HeatONRelay1, LOW);
    digitalWrite(HeatONRelay2, LOW); }
  
  word len = ether.packetReceive();
  word pos = ether.packetLoop(len);
  
  if (pos) {
    delay(1);   // necessary for my system //TODO
    bfill = ether.tcpOffset();
    char *data = (char *) Ethernet::buffer + pos;
    if (strncmp("GET /", data, 5) != 0) {
      bfill.emit_p(http_Unauthorized); }
    else {
      data += 5;
      if (data[0] == ' ') {
        homePage(); }
      else if (strncmp( "?daytemp=" , data , 8 ) == 0) {
        if (ether.findKeyVal(data + 1, DayTempTextbox , sizeof DayTempTextbox , "daytemp") > 0) { 
          value = atoi(DayTempTextbox);   // command to convert a string to number
          if ((value >= 55) & (value <= 80)) {
            DayTempSP = value;
            EEPROM.write(0, value); }
        }
        bfill.emit_p(http_Found);
      }
      else if (strncmp( "?daytime=" , data , 8 ) == 0) {
        if (ether.findKeyVal(data + 1, DayTimeTextbox , sizeof DayTimeTextbox , "daytime") > 0) { 
          value = atoi(DayTimeTextbox);   // command to convert a string to number
          if ((value > 0) & (value <= 24)) {
            DayStartTime = value;
            EEPROM.write(2, value); }
        }
        bfill.emit_p(http_Found);
      }
      else if (strncmp( "?nighttemp=" , data , 10 ) == 0) {
        if (ether.findKeyVal(data + 1, NightTempTextbox , sizeof NightTempTextbox , "nighttemp") > 0) { 
          value = atoi(NightTempTextbox);   // command to convert a string to number
          if ((value >= 55) & (value <= 80)) {
             NightTempSP = value;
            EEPROM.write(1, value); }
        }
        bfill.emit_p(http_Found);
      }  
      else if (strncmp( "?nighttime=" , data , 10 ) == 0) {
        if (ether.findKeyVal(data + 1, NightTimeTextbox , sizeof NightTimeTextbox , "nighttime") > 0) { 
          value = atoi(NightTimeTextbox);   // command to convert a string to number
          if ((value > 0) & (value <= 24)) {
            NightStartTime = value;
            EEPROM.write(3, value); }
        }
        bfill.emit_p(http_Found);
      }
      ether.httpServerReply(bfill.position()); 
    }
  }
}

webpage:

Arduino Thermostat 2.png