Web server with Ajax malfunctioning....

Hi everybody,

Im trying to build a webserver with data from temperature sensors. For the web server I used code from this page

As it is it works fine on my arduino with ethernet shield. Then I start to add my code for reading sensors (works perfectly on its own when information are send only to serial monitor).

Here is my code:

#include <SPI.h>
#include <Ethernet.h>

// MAC address from Ethernet shield sticker under board
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192, 168, 1, 5); // IP address, may need to change depending on network
EthernetServer server(80);  // create a server at port 80

String HTTP_req;            // stores the HTTP request


#include <dht11.h>   //library for DHT11
#define DHT11PIN 2         //digital pin to read DHT11   ( # way of defining constants takes no memory)
dht11 DHT11;               //define variable DHT11 of type dht11  


#define LMPin  A0   // analog pin to read LM35
#define numReadings  50    //number of readings for LM35
float lm35tmp = 100;

float mintemp[8], maxtemp[8];   //arrays to keep extremas

long meastimer;        //timer
int measint = 2000;



void setup()
{
    Ethernet.begin(mac, ip);  // initialize Ethernet device
    server.begin();           // start to listen for clients
    Serial.begin(9600);       // for diagnostics
    
    
    analogReference(INTERNAL); //changes Aref to 1.1V for better accuracy on LM35
    

 //   for (int i = 0; i < 8; i++) { mintemp[i] = 100; maxtemp[i] = 0;} 
     
   
  meastimer =millis();
    
  delay(measint); // give the sensor and Ethernet shield time to set up  
  
     
}


void DHT11temperature() {     // function to obtain temperature and humidity from DHT11 sensor

int chk = DHT11.read(DHT11PIN);

 // Serial.print("Read sensor: ");
  switch (chk)
  {
    case DHTLIB_OK:
                Serial.print("DHT11...");
                 break;
    case DHTLIB_ERROR_CHECKSUM:
                Serial.println("DHT11 Checksum error...");
                break;
    case DHTLIB_ERROR_TIMEOUT:
                Serial.println("DHT11 Time out error...");
                break;
    default:
                Serial.println("DHT11 Unknown error...");
                break;
  }


}



 //function that returns temperature of LM35 in degrees C - takes 50ms
float   LM35temperature() 

{ float LMtotal =0; 
  
  for (int index =0; index < numReadings; index++) 
   {
         LMtotal= LMtotal + analogRead(LMPin);  
         delay(1);
    }
 
   // calculate the average:
float LMaverage = LMtotal / numReadings; 
 
   //compute average voltage on LM35
float LMtemp = (LMaverage /1024.0)*111 ;

Serial.print("LM35...");
return LMtemp;  
}





void loop()
{
 
    // check for a reading no more than once a second.
  if (millis() - meastimer > measint){
   
    
     Serial.print("Reading temperatures...");
//     DHT11temperature();
//     lm35tmp = LM35temperature();

     Serial.println("done");
       meastimer = millis();
    }
    
    
    
    // listen for incoming Ethernet connections:
  listenForEthernetClients();
}



void listenForEthernetClients() {
  
    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
                HTTP_req += c;  // save the HTTP request 1 char at a time
                // last line of client request is blank and ends with \n
                // respond to client only after last line received
                if (c == '\n' && currentLineIsBlank) {
                    Serial.println(HTTP_req);
                    Serial.println(HTTP_req.indexOf("ajax_switch"));
                    // send a standard http response header
                    client.println("HTTP/1.1 200 OK");
                    client.println("Content-Type: text/html");
                    client.println("Connection: keep-alive");
                    client.println();
                    // AJAX request for switch state
                    if (HTTP_req.indexOf("ajax_switch") > -1) {
                        // read switch state and send appropriate paragraph text
                        Serial.println("ajax_switch contained");
                        GetSwitchState(client);
                    }
                    else {  // HTTP request for web page
                        Serial.println("ajax_switch NOT contained");
                        // send web page - contains JavaScript with AJAX calls
                        client.println("<!DOCTYPE html>");
                        client.println("<html>");
                        client.println("<head>");
                        client.println("<title>Arduino Web Page</title>");
                        client.println("<script>");
                        client.println("function GetSwitchState() {");
                        client.println("nocache = \"&nocache=\"\
                                                         + Math.random() * 1000000;");
                        client.println("var request = new XMLHttpRequest();");
                        client.println("request.onreadystatechange = function() {");
                        client.println("if (this.readyState == 4) {");
                        client.println("if (this.status == 200) {");
                        client.println("if (this.responseText != null) {");
                        client.println("document.getElementById(\"switch_txt\")\
.innerHTML = this.responseText;");
                        client.println("}}}}");
                        client.println(
                        "request.open(\"GET\", \"ajax_switch\" + nocache, true);");
                      //client.println("request.open(\"GET\", \"ajax_switch\", true);");
                        client.println("request.send(null);");
                        client.println("}");
                        client.println("</script>");
                        client.println("</head>");
                        client.println("<body>");
                        client.println("<h1>Arduino AJAX Switch Status</h1>");
                        client.println(
                        "<p id=\"switch_txt\">Switch state: Not requested...</p>");
                        client.println("<button type=\"button\"\
                            onclick=\"GetSwitchState()\">Get Switch State</button>");
                        client.println("</body>");
                        client.println("</html>");
                    }
                    // display received HTTP request on serial port
                    //Serial.print(HTTP_req);
                    HTTP_req = "";            // finished with request, empty string
                    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)
}

// send the state of the switch to the web browser
void GetSwitchState(EthernetClient cl)
{
    
        cl.println(millis());

        
    
}

Basic description of the code: Main loop measures temperatures every 2s. If there is an http request, we store it in String HTTP_req and using function HTTP_req.indexOf we are looking if the HTTP_req contains fraze ajax_switch. Based on that we either send only data or we send whole web page without data. Simple. But, you may noticed the for loop which is commented out, as well the functions who read the sensors are commented out. When I run the code like this, I get in Serial monitor

Reading temperatures...done

every two seconds. When I open browser and send http request for the page, this request (not containg ajax_switch) writes in serial monitor with -1 (value of indexOf when string not found). When I click on the button on webpage, it send http request containing ajax_switch and in serial monitor this request and 5 appear (5 is the position of ajax_switch). This is how it should be. Now try to uncomment one of those functions for reading sensors or just the for loop in setup. Then first http request without ajax works no problem, but once you call ajax request, the Http request doesnt contain ajax (and it should!!!) but whats worse function indexOf gives 0 instead of -1. I see no reason why the indexOf function should give 0. And then all subsequent http requests get 0 no matter if they contain ajax or not and that of course ruins the webpage. Can somebody please explain where is the problem?

Thank you so much

1 Like

A usual suspect is that you are running out of memory due to all the static html text in the code. Use the F() macro to conserve the arduino dynamic memory. The below shows the F() macro in use.

          client.print(F("HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n"));

          //generate data page
          if(readString.indexOf("data") >0) {  //checks for "data" page
            x=x+1; //page upload counter
            client.print(F("<HTML><HEAD>"));
            //meta-refresh page every 1 seconds if "datastart" page
            if(readString.indexOf("datastart") >0) client.print(F("<meta http-equiv='refresh' content='1'>")); 
            //meta-refresh 0 for fast data
            if(readString.indexOf("datafast") >0) client.print(F("<meta http-equiv='refresh' content='0'>")); 
            client.print(F("<title>Zoomkat's meta-refresh test</title></head><BODY>
"));
            client.print(F("page refresh number: "));
            client.print(x); //current refresh count
            client.print(F("

"));
            
              //output the value of each analog input pin
            client.print(F("analog input0 is: "));
            client.print(analogRead(analogInPin0));
            
            client.print(F("
analog input1 is: "));
            client.print(analogRead(analogInPin1));
                        
            client.print(F("
analog input2 is: "));
            client.print(analogRead(analogInPin2));
            
            client.print(F("
analog input3 is: "));
            client.print(analogRead(analogInPin3));
                                    
            client.print(F("
analog input4 is: "));
            client.print(analogRead(analogInPin4));
            
            client.print(F("
analog input5 is: "));
            client.print(analogRead(analogInPin5));
            client.print(F("
</BODY></HTML>"));
           }
          //generate main page with iframe
          else
          {
            client.print(F("<HTML><HEAD><TITLE>Zoomkat's frame refresh test</TITLE></HEAD>"
            "Zoomkat's Arduino frame meta refresh test 8/17/13"
            "

Arduino analog input data frame:
"
            "&nbsp;&nbsp;<a href='/datastart' target='DataBox' title=''yy''>META-REFRESH</a>"
            "&nbsp;&nbsp;&nbsp;&nbsp;<a href='/data' target='DataBox' title=''xx''>SINGLE-STOP</a>"
            "&nbsp;&nbsp;&nbsp;&nbsp;<a href='/datafast' target='DataBox' title=''zz''>FAST-DATA</a>
"
            "<iframe src='/data' width='350' height='250' name='DataBox'>"
            "</iframe>
</HTML>"));
          }

Thanks, I will look into it. But what do you mean running out of memory? The sketch is 21KB so still lots of space in it no?

AVR have one memory for code and one for data they are not interchangeable. The Uno has 2k of data space in total.

Mark

Is there a way to monitor this memory, while programing, so I know if I use too much of it?

You can use a library called "MemoryFree" to monitor RAM usage on arduino : Arduino Playground - AvailableMemory .

Great, thanks, Ill try that.

I used the F() makro and it seems to work. But my next step was to use an SD card, where the webpage is stored on
and I use code

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

To copy it to web. So in this case there is minimum strings in the code that could be put in F() makro. In this case I have the
same malfunction, so not enough memory. What can I do about that? (the rest of the code is basically the same as before)

kingbean:
the rest of the code is basically the same as before

If you want help with a problem with your code, please post your actual code (compete). If it needs any data files to demonstrate the problem, it would be best to attach those too. Also explain what you need to do (e.g. in terms of browser page requests) to demonstrate the problem, and attach serial logs.

So in this case there is minimum strings in the code that could be put in F() makro. In this case I have the
same malfunction, so not enough memory. What can I do about that?

The SD class reads from, and writes to, the SD card in 512 bytes chunks. It will, therefore, use over 1/4 of the memory on a 328-based Arduino.

The ONLY solution is to use an Arduino that is not based on the 328 chip, such as the Mega and the DUE.