Setting variable value from arduino web server

Hi! Can you please help me with my code? I just can’t seem to get it right.

The thing I need is to have a text box on a web server hosted by my arduino. When I type in a numeric value, the variable in the arduino code should be updated and set to the new value that I typed on the web server. I should probably mention that I’m using an SD Card with an “index.htm” file on it. You can see the arduino code and the HTML code bellow.

#include <SPI.h>
#include <Ethernet.h>
#include <SD.h>
// size of buffer used to capture HTTP requests
#define REQ_BUF_SZ   60

// MAC address from Ethernet shield sticker under board
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192, 168, 0, 122); // IP address, may need to change depending on network
IPAddress gateway(192, 168, 0, 1);
IPAddress subnet(255, 255, 255, 0);
EthernetServer server(80);  // create a server at port 80
File webFile;               // the web page file on the SD card
char HTTP_req[REQ_BUF_SZ] = {0}; // buffered HTTP request stored as null terminated string
char req_index = 0;              // index into HTTP_req buffer
boolean LED_state[2] = {0}; // stores the states of the LEDs

float temp;
int sensor = 0;
int startTemp = 30;
float onTemp = startTemp;
float offTemp = onTemp - 2;
int ledPin = 22;
static bool measuring = false;
const unsigned long interval = 1000;

void setup()
{
    pinMode(ledPin, OUTPUT);
    pinMode(sensor, INPUT);
  
    // disable Ethernet chip
    pinMode(10, OUTPUT);
    digitalWrite(10, HIGH);
    
    Serial.begin(9600);       // for debugging
    
    // initialize SD card
    Serial.println("Initializing SD card...");
    if (!SD.begin(4)) {
        Serial.println("ERROR - SD card initialization failed!");
        return;    // init failed
    }
    Serial.println("SUCCESS - SD card initialized.");
    // check for index.htm file
    if (!SD.exists("index.htm")) {
        Serial.println("ERROR - Can't find index.htm file!");
        return;  // can't find index file
    }
    Serial.println("SUCCESS - Found index.htm file.");
    
    Ethernet.begin(mac, ip);  // initialize Ethernet device
    server.begin();           // start to listen for clients
}

void loop()
{
    static unsigned long timer = millis();
  
    if (measuring == true && timer - millis() >= interval) 
    {
      measureTemperature();
      delay(1000);
    }
    else
    {
      digitalWrite(ledPin, LOW);
    }
  
    EthernetClient client = server.available();  // try to get client

    if (client) {  // got client?
        boolean currentLineIsBlank = true;
        while (client.connected()) {
            if (client.available()) {   // client data available to read
                char c = client.read(); // read 1 byte (character) from client
                // limit the size of the stored received HTTP request
                // buffer first part of HTTP request in HTTP_req array (string)
                // leave last element in array as 0 to null terminate string (REQ_BUF_SZ - 1)
                if (req_index < (REQ_BUF_SZ - 1)) {
                    HTTP_req[req_index] = c;          // save HTTP request character
                    req_index++;
                }
                // last line of client request is blank and ends with \n
                // respond to client only after last line received
                if (c == '\n' && currentLineIsBlank) {
                    // send a standard http response header
                    client.println("HTTP/1.1 200 OK");
                    // remainder of header follows below, depending on if
                    // web page or XML page is requested
                    // Ajax request - send XML file
                    if (StrContains(HTTP_req, "ajax_inputs")) {
                        // send rest of HTTP header
                        client.println("Content-Type: text/xml");
                        client.println("Connection: keep-alive");
                        client.println();
                        SetLEDs();
                        // send XML file containing input states
                        XML_response(client);
                    }
                    else {  // web page request
                        // send rest of HTTP header
                        client.println("Content-Type: text/html");
                        client.println("Connection: keep-alive");
                        client.println();
                        // send web page
                        webFile = SD.open("index.htm");        // open web page file
                        if (webFile) {
                            while(webFile.available()) {
                                client.write(webFile.read()); // send web page to client
                            }
                            webFile.close();
                        }
                    }
                    // reset buffer index and all buffer elements to 0
                    req_index = 0;
                    StrClear(HTTP_req, REQ_BUF_SZ);
                    break;
                }
                // every line of text received from the client ends with \r\n
                if (c == '\n') {
                    // last character on line of received text
                    // starting new line with next character read
                    currentLineIsBlank = true;
                } 
                else if (c != '\r') {
                    // a text character was received from client
                    currentLineIsBlank = false;
                }
            } // end if (client.available())
        } // end while (client.connected())
        delay(1);      // give the web browser time to receive the data
        client.stop(); // close the connection
    } // end if (client)
}

// checks if received HTTP request is switching on/off LEDs
// also saves the state of the LEDs
void SetLEDs(void)
{
    // LED 2 (pin 7)
    if (StrContains(HTTP_req, "LED2=1")) {
        LED_state[1] = 1;  // save LED state
        digitalWrite(7, HIGH);
        measuring = true;
    }
    else if (StrContains(HTTP_req, "LED2=0")) {
        LED_state[1] = 0;  // save LED state
        digitalWrite(7, LOW);
        measuring = false;
    }
}

// send the XML file with analog values, switch status
//  and LED status
void XML_response(EthernetClient cl)
{
    float analog_val;            // stores value read from analog inputs
    int count;                 // used by 'for' loops
    
    cl.print("<?xml version = \"1.0\" ?>");
    cl.print("<inputs>");
    // checkbox LED states
    // LED1
    cl.print("<LED>");
    if (LED_state[0]) {
        cl.print("checked");
    }
    else {
        cl.print("unchecked");
    }
    cl.println("</LED>");
    // button LED states
    // LED3
    cl.print("<LED>");
    if (LED_state[1]) {
        cl.print("on");
    }
    else {
        cl.print("off");
    }
    cl.println("</LED>");
    
    analog_val = analogRead(0) * 0.48828125;
    cl.print("<analog>");
    cl.print(analog_val);
    cl.print("</analog>");
    cl.print("</inputs>");
}

// sets every element of str to 0 (clears array)
void StrClear(char *str, char length)
{
    for (int i = 0; i < length; i++) {
        str[i] = 0;
    }
}

// searches for the string sfind in the string str
// returns 1 if string found
// returns 0 if string not found
char StrContains(char *str, char *sfind)
{
    char found = 0;
    char index = 0;
    char len;

    len = strlen(str);
    
    if (strlen(sfind) > len) {
        return 0;
    }
    while (index < len) {
        if (str[index] == sfind[found]) {
            found++;
            if (strlen(sfind) == found) {
                return 1;
            }
        }
        else {
            found = 0;
        }
        index++;
    }

    return 0;
}

void measureTemperature()
{
  temp = analogRead(sensor) * 0.48828125;

  static unsigned long timer = millis();

  Serial.print(temp);
  Serial.print("°C\n");

  if (timer - millis() >= interval)
  {
    if (temp < onTemp)
    {
      onTemp = startTemp;
      digitalWrite(ledPin, HIGH);
    }

    else if (temp >= onTemp)
    {
      onTemp = offTemp;
      digitalWrite(ledPin, LOW);
    }
  }
}

I need the variable called “startTemp” to change when I input a new value on the web server.

Most of this code is copied from the internet but there are some things that I wrote on my own. There might be some mistakes or maybe the code isn’t “optimised” but it works for me and that’s what counts.

I will post the HTML code in the comments, because this post exceeds the maximum character length.

Anyways, If you can help, I would really appreciate it.

Thanks in advance.
Stefan.

The HTML code:

<!DOCTYPE html>
<html>
    <head>
        <script>
		strLED1 = "";
		strLED2 = "";
		var LED2_state = 0;
		var data_val = 0;
                //THERE IS ANOTHER LINE HERE, but it was waaaaay too long and I couldn't post the code.
		function GetArduinoIO()
		{
			nocache = "&nocache=" + Math.random() * 1000000;
			var request = new XMLHttpRequest();
			request.onreadystatechange = function()
			{
				if (this.readyState == 4) {
					if (this.status == 200) {
						if (this.responseXML != null) {
							document.getElementById("input3").innerHTML =
								this.responseXML.getElementsByTagName('analog')[0].childNodes[0].nodeValue;
								data_val = this.responseXML.getElementsByTagName('analog')[0].childNodes[0].nodeValue;
							// XML file received - contains analog values, switch values and LED states
							var count;
							// LED 2
							if (this.responseXML.getElementsByTagName('LED')[1].childNodes[0].nodeValue === "on") {
								document.getElementById("LED2").innerHTML = "ON";
								document.getElementById("LED2").style.color = "green";
								LED2_state = 1;
							}
							else {
								document.getElementById("LED2").innerHTML = "OFF";
								document.getElementById("LED2").style.color = "red";
								LED2_state = 0;
							}
						}
					}
				}
			}
			// send HTTP GET request with LEDs to switch on/off if any
			request.open("GET", "ajax_inputs" + strLED1 + strLED2 + nocache, true);
			request.send(null);
			setTimeout('GetArduinoIO()', 1000);
			strLED1 = "";
			strLED2 = "";
		}
		function GetButton1()
		{
			if (LED2_state === 1) {
				LED2_state = 0;
				strLED2 = "&LED2=0";
			}
			else {
				LED2_state = 1;
				strLED2 = "&LED2=1";
			}
		}
	</script>
	<style>
		.IO_box {
			float: left;
			margin: 0 20px 20px 0;
			border: 1px solid black;
			padding: 0 5px 0 5px;
			width: 150px;
			height: 150px;
			text-align: center;
		}
		h1 {
			font-family: Ariel;
			font-size: 120%;
			color: blue;
			margin: 0 0 10px 0;
			text-align: center;
		}
		h2 {
			font-family: Ariel;
			font-size: 85%;
			color: black;
			margin: 5px 0 5px 0;
			text-align: center;
		}
		p, form, button {
			font-family: Ariel;
			font-size: 80%;
			color: #252525;
			width: 75px;
			text-align: center;
		}
		.small_text {
			font-family: Ariel;
			font-size: 70%;
			color: #737373;
			text-align: center;
		}
	</style>
    </head>
    <body onload="GetArduinoIO()">
		<div class="IO_box">
			<h2>Room One</h2>
			<p>Temp is: <span id="input3">...</span></p>
			<button type="button" id="LED2" onclick="GetButton1()" color="red">OFF</button>


		</div>
    </body>
</html>

By the way, I know I am not using LED1, but I will be using it in the future. That’s why it’s in the code.

      delay(1000);

Why? There is NO excuse for making clients wait while you stupidly twiddle your thumbs. Read, understand, and embrace the blink with delay example, and NEVER use delay in web server sketches.

                        if (webFile) {
                            while(webFile.available()) {
                                client.write(webFile.read()); // send web page to client
                            }
                            webFile.close();
                        }

Sending packets that contain 1 character is horribly inefficient.

                //THERE IS ANOTHER LINE HERE, but it was waaaaay too long and I couldn't post the code.

Then, I can't post the answer.

We MUST be able to see what you are serving up.

Read the stickies at the top of the forum, to learn how to post code that is more than 9000 characters.

In the end, you MUST pay attention to what the client request looks like. Right now, you are ONLY concerned with whether the request contains the text "ajax_inputs" or not. You'll need to care about more than that if you want to use the data in the GET request.

Paul, thank you for answering.

The thing is, I'm not that good with coding and I just put the "delay" in there because the code was reading the temperature faster than I would like to.

Next about the "Sending packets that contain 1 character is horribly inefficient". Well I don't know exactly how that code works, I just copied it from the internet and it seems to work so I just stuck with it. If you can suggest anything that will make it run better, please tell me.

And finally, I uploaded the full HTML code to github. You can see it in the link below.

https://gist.github.com/LanternMG/956f329c40f0c02b6416ac8e782ff3a2

Thank you once again.

The thing is, I'm not that good with coding and I just put the "delay" in there because the code was reading the temperature faster than I would like to.

The code should read the temperature as frequently as possible. Doing something with the current value may, or may not, be necessary. That decision can be based on the blink without delay philosophy.

If you can suggest anything that will make it run better, please tell me.

Both the read() and write() methods are overloaded to use arrays. Read more than 1 character, storing in an array. Write the characters read, from the array.

It would be useful to print the GET request.

Sorry I was unable to reply earlier.

PaulS:
The code should read the temperature as frequently as possible. Doing something with the current value may, or may not, be necessary. That decision can be based on the blink without delay philosophy.

I don't need the code to read the temperature as frequently as possible. I need to read it once a minute, but in the code I set it to 1 second just for debugging and just to see if everything works.

PaulS:
Both the read() and write() methods are overloaded to use arrays. Read more than 1 character, storing in an array. Write the characters read, from the array.

It would be useful to print the GET request.

And can you please explain this to me. I don't quite understand it.

Thanks,
Stefan.

Not related to your problem, but in this code

void loop()
{
  static unsigned long timer = millis();
  if (measuring == true && timer - millis() >= interval)

will timer - millis() ever be greater than interval, which has a value of 1000 ?

UKHeliBob:
Not related to your problem, but in this code

void loop()

{
  static unsigned long timer = millis();
  if (measuring == true && timer - millis() >= interval)



will timer - millis() ever be greater than interval, which has a value of 1000 ?

I don't know...I found it like that on the internet, I used it in my code and it worked. I don't know how "millis()" functions, but it worked so I stuck with it.