creating multiple text boxes on a arduino web page

My first (I'm new to arduino and to C/C++ and while I'm at it HTML) big project is an arduino thermostat with a simple web page hosted by the arduino. I started with a basic web page that displayed the current temperature, target temperature, temperature at which the heat turns on and off and if the arduino was controlling the temperature or not. Just simple no frills text. Through an example that was posted on this forum I was able to figure out how to set the target temperature through the web page using a text input box. Now I would like to add a second (and maybe even more) text input box to the web page. Problem is I just don't understand how the code works for the one box I have now which is makes it difficult to add another one. If someone can explain how the code works and maybe how to add another box it would be appriciated. I'm not looking for someone to do the code for me, or else how would I learn, but if someone does, please explain to me what you did.

Here is my entire code.

#include <SPI.h>
#include <Ethernet.h>
#define maxLength 25

byte mac[] = { 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA };
byte ip[] = { 192, 168, 1, 102 };

EthernetServer server(80);

char TargetTemp[4];
int val;
String inString = String(maxLength);

// Define I/O pins
const int TempSensor = A4;        // pin that the temp sensor is attached to
const int HeatONMain = 8;         // pin that activates heat on relay
const int HeatONFailSafe = 9;     // pin that activates heat on relay 2

// Other constant stuff
const int RelayON = LOW;
const int RelayOFF = HIGH;

char* HeatStatusStg[]={"OFF", "ON"};
char* CntrlStatusStg[]={"NO", "YES"};

// Define the number of readings to take.  The higher the number,
// the more the readings will be smoothed, but the slower the output will
// respond to the input.  Using a constant rather than a normal variable lets
// us use this value to determine the size of the readings array.
const int numReadings = 15;

int TempReadings[numReadings];      // the readings from the analog input
int TempIndex = 0;                  // the index of the current reading
int TempTotal = 0;                  // the running total

int RoomTemperature = 0;          // result after converting analog value to degf
int AvgTemperature = 0;           // averaged current room temperature
int TempSetpoint = 70;	          // room temperature setpoint as set from the web page
int RoomTemperatureSPmin = 69;	  // room temperature minimum setpoint (SP - temperature deadband)
int RoomTemperatureSPmax = 71;	  // room temperature maximum setpoint (SP + temperature deadband)
int TemperatureDB = 1;		  // deadband

int HeatStatus = 0;
int CntrlStatus = 0;

long HeatCntrlDelayTime = 120000;  // wait for 2 minutes after bootup before trying to control temp

//==================================================================================================================
void setup()
//==================================================================================================================
{
  // Initialize pins so relays are inactive at startup/reset
  digitalWrite(HeatONMain, RelayOFF);
  digitalWrite(HeatONFailSafe, RelayOFF);
  // Set pins that are wired to relay board as outputs
  pinMode(HeatONMain, OUTPUT);
  pinMode(HeatONFailSafe, OUTPUT);
  delay (2000);
  // start the serial connection
  Serial.begin(9600);
  // start the Ethernet connection and the server:
  Ethernet.begin(mac, ip);
  server.begin();
}
//==================================================================================================================
void loop()
//==================================================================================================================
{
  // Convert analog reading from temperature sensor to degrees fahrenheit:
  RoomTemperature = ((5.0 * analogRead(TempSensor) * 100.0)/1024.0);      //convert the analog data to temperature
  // subtract the last reading:
  TempTotal= TempTotal - A0Readings[TempIndex];         
  // read from the sensor:  
  TempReadings[TempIndex] = RoomTemperature; 
  // add the reading to the total:
  TempTotal= TempTotal + TempReadings[TempIndex];       
  // advance to the next position in the array:  
  TempIndex = TempIndex + 1;                    

  // if we're at the end of the array...
  if (TempIndex >= numReadings) {             
    // ...wrap around to the beginning: 
    TempIndex = 0;  
    }                         

  // calculate the average:
  AvgTemperature = TempTotal / numReadings;   

  // set the min and temperature setpoint relative to the temperature entered in through the web page
  RoomTemperatureSPmin = (TempSetpoint - TemperatureDB);
  RoomTemperatureSPmax = (TempSetpoint + TemperatureDB);

  if (millis() < HeatCntrlDelayTime) {
    CntrlStatus = 0;
    digitalWrite(HeatONMain, LOW);
    digitalWrite(HeatONFailSafe, LOW);
    HeatStatus = 0;
  }

  if (millis() > HeatCntrlDelayTime) {
    CntrlStatus = 1;
    // monitor Room Temperature and turn on heat when temperature drops below setpoint
    if ((AvgTemperature) < (RoomTemperatureSPmin)) {
      digitalWrite(HeatONMain, HIGH);
      digitalWrite(HeatONFailSafe, HIGH);
      HeatStatus = 1;}
    if ((AvgTemperature) > (RoomTemperatureSPmax)) {
      digitalWrite(HeatONMain, LOW);
      digitalWrite(HeatONFailSafe, LOW);
      HeatStatus = 0;}
  }

  int bufLength;
  EthernetClient client = server.available();
  if (client) {
    boolean current_line_is_blank = true;
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        if (inString.length() < maxLength) {
          inString += c;
        }        
        if (c == '\n' && current_line_is_blank) {
          if (inString.indexOf("?") > -1) {
            int Pos_L = inString.indexOf("L");
            int End = inString.indexOf("H", Pos_L);
            if(End < 0){
              End =  inString.length() + 1;
            }
            bufLength = ((Pos_L) - (Pos_L+2));
            if(bufLength > 4){  //dont overflow the buffer
              bufLength = 4;
            }    
            inString.substring((Pos_L+2), (End-1)).toCharArray(TargetTemp, bufLength);  //transfer substring to buffer
            val = atoi(TargetTemp);
            Serial.print("TargetTemp = ");
            Serial.println( val );
            TempSetpoint = val;
          }
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println();
          client.println("<html><head></head><body>");
          client.println("<h1>WEB ENABLED ARDUINO THERMOSTAT</h1>");
          client.println("
");
	  client.println("<hr />");
          // add a meta refresh tag, so the browser pulls again every 20 seconds:
          client.println("<meta http-equiv=\"refresh\" content=\"20\">");
          client.print("Room Temperature:");
          client.print(" ");
          client.print(AvgTemperature);
          client.print(" ");
          client.print("DEGF");
          client.println();  // send a cr/lf
          client.println("
");   
          client.print("Heat turns on below:");
          client.print(" ");
          client.print(RoomTemperatureSPmin);
          client.print(" ");
          client.print("DEGF");
          client.println();  // send a cr/lf
          client.println("
");       
          client.print("Heat turns off above:");
          client.print(" ");
          client.print(RoomTemperatureSPmax);
          client.print(" ");
          client.print("DEGF");
          client.println();  // send a cr/lf
          client.println("
");       
          client.print("Temperature is being controlled?");
          client.print(" ");
          client.print(CntrlStatusStg[CntrlStatus]);
          client.println();  // send a cr/lf
          client.println("
");       
          client.print("Heat is:");
          client.print(" ");
          client.print(HeatStatusStg[HeatStatus]);
          client.println();  // send a cr/lf
          client.println("<Hr />");
          client.print("<form method=get>CHANGE TEMPERATURE SETPOINT:<input type=text size=3 name=L value=");
          client.print(val);
          client.print(">&nbsp;<input name=H type=submit value=submit></form>");
          client.println("<Hr />");
          client.println("</body></html>");
          break;
        }
        if (c == '\n') {
          current_line_is_blank = true;
        }
        else if (c != '\r') {
          current_line_is_blank = false;
        }
      }
    }
    delay(1);
    inString = "";
    client.stop();
  }
}

Moderator edit:
</mark> <mark>[code]</mark> <mark>

</mark> <mark>[/code]</mark> <mark>
tags added.

Forgot to list hardware

  • Uno
  • Wiznet 5100 ethernet shield

wrapping your code in CODE tags will help you get better responses.. :slight_smile:

There are three parts to the problem.

Firstly, your sketch supplies an HTML page which includes a form. Look at the page source in your web browser to understand what is in this page. Currently it has one input field named "L". You will want to extend this form so that it has an extra field with some other name.

Secondly, when your browser submits the form it sends an HTTP request to the Arduino which includes the values that were in the form. Your sketch has some logic to extract these values from the HTTP request:

if (inString.indexOf("?") > -1) {
            int Pos_L = inString.indexOf("L");
            int End = inString.indexOf("H", Pos_L);
            if(End < 0){
              End =  inString.length() + 1;
            }
            bufLength = ((Pos_L) - (Pos_L+2));
            if(bufLength > 4){  //dont overflow the buffer
              bufLength = 4;
            }   
            inString.substring((Pos_L+2), (End-1)).toCharArray(TargetTemp, bufLength);  //transfer substring to buffer
            val = atoi(TargetTemp);
            Serial.print("TargetTemp = ");
            Serial.println( val );
            TempSetpoint = val;
          }

Some of that looks a bit dodgy (I'm not sure what "((Pos_L) - (Pos_L+2))" is supposed to give you) but you will need to modify this code to parse two field values from the incoming request instead of just one. I suggest that the easiest way to understand what this is doing is to print out the whole input line when you reach this bit of code. You will see that the code looks for the position in the string where it expects to find the field value, extracts that value from the string and parses it to get a number. You would need to add similar code for the second field.

Once you've got the values from the form you need to save/apply them somehow within your sketch.

The third part is that you might want to have the current values displayed in the form rather than leave those fields blank. In that case you would need to change the code that prints out the HTML source for the form to include the value within the HTML.

Hi,
If you think your project may grow in terms of wanting to capture real world sensor data, doing statistical munching and then producing nice web pages, can I suggest you take a look at this thread here http://arduino.cc/forum/index.php/topic,129122.0.html.

It demonstrates what I think is a better way of doing this task.

Firstly, your web page is more coded up to relieve the Arduino from having to continuously send complete web pages when you only want to have updated data values.
This is done by useing a RESTful web service, where your web page request small packets of data from the Arduino, typically 'jason' formatted.

You can elect to serve up a web page from either a dedicated web server or from your Arduino.
To get a little more fancy, you'll be wanting to serve up some styled HTML, so there will be CCS files, maybe some js (javascript) files, such as libraries or specific to your project.

Also, think about modularising your code.
For example having all your real world sensing in a routine of its own, the web stuff also in a routine of its own.
Then use the main loop to go through the routines you need at specific timings.

Also, look into smoothing your analogues with something like a moving average filter.
I use an array that gets a new value every 100mSec and the oldest in the array kicked out and then re-average the array.
It makes a difference, firstly for accuracy with presenting present values data or stats. Also especially if you are wanting to do things like produce alarm trip point settings.

You'll be amazed what you can do using this concept I am mentioning, I am playing around with nice analogue meters on my web page and also historical trends displays from the SD card.
The bonus is, you'll learn a lot more about all these programing models and be able to create a truly effective, efficient and eye catching application.

Paul

A google search like below should provide info and examples of html forms.

https://www.google.com/search?hl=en&as_q=form+html+tutorial&as_epq=&as_oq=&as_eq=&as_nlo=&as_nhi=&lr=&cr=&as_qdr=all&as_sitesearch=&as_occt=any&safe=images&tbs=&as_filetype=&as_rights=

Thanks for the replies and suggestions!

I renamed some variables and tried adding the second text box (nightenter, nightsubmit). Now when I enter in a value for either text box and hit enter the website times out.

Code was too long so I had to attach it.

Arduino_web_thermostat_night_heat.ino (11.6 KB)

Please tell me if you solved the problem and how. I have the same problem.

You can add a data logger shield (includes an SD card reader and RTC), load all your individual web pages on the SD card and then just read in the appropriate one in line by line and out put each line via ::print(...) or ::write(...), what ever the library you are using calls it.

You can also insert text markers in your html file on the SD card and replace, via the string functions, those text markers with names or what ever such that you web page appears dynamic.

When you read in the external htpp request it will look something like this:

GET index.html HTTP/1.0

So you need to extract the file name and send the client the appropriate html file from your SD card.

If you submit a form then you will see something like this at the arduino end:

GET index.html?editfield1=xxxxxx,editfield2=yyyyyy,submit=submit

Where 'editfield1' is the name you gave to the edit field in your html file and xxxxxx is the value the user entered for that field. So again you need to use the string functions to extract the field names and their contents entered by the user.

The WiFiEsp library that I am using can't seem to deal with POST data that appears after the html header - it seems to just ignore it and it never gets through to my code. So you might want to check if the library youn are using has a similar restriction.