How to create a webpage with a given name using Ethernet Sheild 2

Hi,

I have a basic webserver configured on my Ethernet Shield 2 (W5500). The sever, implemented using Ethernet.h, serves an html page that shows a set of random values. That works perfectly.

What I would like to understand is how to “name” that page? For example I might like to call it values.html or suchlike.

Ultimately I need a route or routes so that the server knows which pages to return, but how is that done?

I have seen reference to server.on() but that only seems to be used with WiFi – Is that just a coincidence? If not is there any documentation?

Any advice much appreciated.

Please post your full sketch, using code tags when you do

Hi @UKHeliBob here's the sketch:

/*
  Web Server

 A simple web server that shows the value of the analog input pins.
 using an Arduino Wiznet Ethernet shield.

 Circuit:
 * Ethernet shield attached to pins 10, 11, 12, 13
 * Analog inputs attached to pins A0 through A5 (optional)

 created 18 Dec 2009
 by David A. Mellis
 modified 9 Apr 2012
 by Tom Igoe
 modified 02 Sept 2015
 by Arturo Guadalupi
 
 */

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

// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = {
  0xA8, 0x61, 0x0A, 0xAE, 0xBF, 0x00
};
IPAddress ip(192, 168, 1, 42);

EthernetServer server(80);

void setup() {

  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    ;  // wait for serial port to connect. Needed for native USB port only
  }
  Serial.println("Ethernet WebServer Example");

  // start the Ethernet connection and the server:
  Ethernet.begin(mac, ip);

  // Check for Ethernet hardware present
  if (Ethernet.hardwareStatus() == EthernetNoHardware) {
    Serial.println("Ethernet shield was not found.  Sorry, can't run without hardware. :(");
    while (true) {
      delay(1);  // do nothing, no point running without Ethernet hardware
    }
  }
  if (Ethernet.linkStatus() == LinkOFF) {
    Serial.println("Ethernet cable is not connected.");
  }

  // start the server
  server.begin();
  Serial.print("server is at ");
  Serial.println(Ethernet.localIP());
}


void loop() {
  // listen for incoming clients
  EthernetClient client = server.available();
  if (client) {
    Serial.println("new client");
    // an http request ends with a blank line
    boolean currentLineIsBlank = true;
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        Serial.write(c);
        // if you've got to the end of the line (received a newline
        // character) and the line is blank, the http request has ended,
        // so you can send a reply
        if (c == '\n' && currentLineIsBlank) {
          // send a standard http response header
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println("Connection: close");  // the connection will be closed after completion of the response
          client.println("Refresh: 5");         // refresh the page automatically every 5 sec
          client.println();
          client.println("<!DOCTYPE HTML>");
          client.println("<html>");
          // output the value of each analog input pin
          for (int analogChannel = 0; analogChannel < 6; analogChannel++) {
            int sensorReading = analogRead(analogChannel);
            client.print("analog input ");
            client.print(analogChannel);
            client.print(" is ");
            client.print(sensorReading);
            client.println("<br />");
          }
          client.println("</html>");
          break;
        }
        if (c == '\n') {
          // you're starting a new line
          currentLineIsBlank = true;
        } else if (c != '\r') {
          // you've got a character on the current line
          currentLineIsBlank = false;
        }
      }
    }
    // give the web browser time to receive the data
    delay(1);
    // close the connection:
    client.stop();
    Serial.println("client disconnected");
  }
}

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

// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = {
  0xA8, 0x61, 0x0A, 0xAE, 0xBF, 0x00
};
IPAddress ip(192, 168, 1, 42);

EthernetServer server(80);

void setup() {

  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    ;  // wait for serial port to connect. Needed for native USB port only
  }
  Serial.println("Ethernet WebServer Example");

  // start the Ethernet connection and the server:
  Ethernet.begin(mac, ip);

  // Check for Ethernet hardware present
  if (Ethernet.hardwareStatus() == EthernetNoHardware) {
    Serial.println("Ethernet shield was not found.  Sorry, can't run without hardware. :(");
    while (true) {
      delay(1);  // do nothing, no point running without Ethernet hardware
    }
  }
  if (Ethernet.linkStatus() == LinkOFF) {
    Serial.println("Ethernet cable is not connected.");
  }

  // start the server
  server.begin();
  Serial.print("server is at ");
  Serial.println(Ethernet.localIP());
}


void loop() {
  // listen for incoming clients
  EthernetClient client = server.available();
  if (client) {
    Serial.println("new client");
    // an http request ends with a blank line
    boolean currentLineIsBlank = true;
    string PageRequested = "";
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        Serial.write(c);
        //if not newline and return add char to PageRequested..
        if ((c != '\n') && (c != '\r')) {PageRequested = PageRequested + c;}
        // if you've got to the end of the line (received a newline
        // character) and the line is blank, the http request has ended,
        // so you can send a reply
        if (c == '\n' && currentLineIsBlank) {
          //debug show the request
          Serial.println();
          Serial.println("Page: "+PageRequested);
          // send a standard http response header
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println("Connection: close");  // the connection will be closed after completion of the response
          client.println("Refresh: 5");         // refresh the page automatically every 5 sec
          client.println();
          client.println("<!DOCTYPE HTML>");
          client.println("<html>");
          // output the value of each analog input pin
          for (int analogChannel = 0; analogChannel < 6; analogChannel++) {
            int sensorReading = analogRead(analogChannel);
            client.print("analog input ");
            client.print(analogChannel);
            client.print(" is ");
            client.print(sensorReading);
            client.println("<br />");
          }
          client.println("</html>");
          break;
        }
        if (c == '\n') {
          // you're starting a new line
          currentLineIsBlank = true;
          PageRequested = "";//get ready for the next
        } else if (c != '\r') {
          // you've got a character on the current line
          currentLineIsBlank = false;
        }
      }
    }
    // give the web browser time to receive the data
    delay(1);
    // close the connection:
    client.stop();
    Serial.println("client disconnected");
  }
}

What prints out for Page??

Hi,

It shows:

analog input 1 is 456
analog input 2 is 678

Etc.

on the Serial monitor, I added Page: to it.

Oh, sorry, i completely missed that ...

I'll check in the morning and let you know :slight_smile:

Cheers

You must save all the caracters of the first line, to have the request and the name of the HML page.
ex:
GET /test.html HTTP/1.1
or
GET /logo.jpg HTTP/1.1

In the example, the request is not used and the same HTML page is responsed. regardless the contained of the HTTP request.

That's ok, had a typo in there anyways. didn't capitalize string.
got tired of waiting, so threw my ethernet shield on my zero and played a bit.

try this..

#include <SPI.h>
#include <Ethernet2.h>

// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = {
  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED
};
IPAddress ip(192, 168, 0, 200);

// Initialize the Ethernet server library
// with the IP address and port you want to use
// (port 80 is default for HTTP):
EthernetServer server(80);



void setup() {
  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for Leonardo only
  }


  // start the Ethernet connection and the server:
  Ethernet.begin(mac, ip);
  server.begin();
  Serial.print("server is at ");
  Serial.println(Ethernet.localIP());
}

word GetPage(String FullRequest)
{
  int StartHere = FullRequest.indexOf("GET");
  int EndHere = FullRequest.indexOf("HTTP/");
  Serial.print("Start:");
  Serial.println(StartHere,DEC);
  Serial.print("End:");
  Serial.println(EndHere,DEC);
  word bRet = 404;
  if (StartHere>-1)
  {//have a get
   String tmpStr = FullRequest.substring(StartHere+3,EndHere);
   tmpStr.trim();
   Serial.println(tmpStr);
    if (tmpStr=="/" || tmpStr=="/index.html" || tmpStr=="/index.htm" || tmpStr=="/home.htm" || tmpStr=="/home.html"){bRet=0;} else
    if (tmpStr=="/page2.html" || tmpStr == "/page2.htm"){bRet=1;} else
    if (tmpStr=="/page3.html" || tmpStr == "/page3.htm"){bRet=2;}        
  }

  return bRet;
}

void loop() {
  // listen for incoming clients
  EthernetClient client = server.available();
  if (client) {
    Serial.println("new client");
    // an http request ends with a blank line
    boolean currentLineIsBlank = true;
    String PageRequested = "";    
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        Serial.write(c);
        // if you've gotten to the end of the line (received a newline
        // character) and the line is blank, the http request has ended,
        // so you can send a reply
        if ((c != '\n') && (c != '\r')) {PageRequested = PageRequested + c;}        
        if (c == '\n' && currentLineIsBlank) {
          // send a standard http response header
          word newpage = GetPage(PageRequested);
          Serial.println();
          Serial.println("Page: "+PageRequested);          
          Serial.println(newpage,DEC);    
            switch (newpage){
               case 0:SendRoot(client);break;
               case 1:SendPage2(client);break;
               case 2:SendPage3(client);break;
               case 404:Send404(client);break;          
            }
          break;
        }
        if (c == '\n') {
          // you're starting a new line
          currentLineIsBlank = true;
        }
        else if (c != '\r') {
          // you've gotten a character on the current line
          currentLineIsBlank = false;
        }
      }
    }
    // give the web browser time to receive the data
    delay(1);
    // close the connection:
    client.stop();
    Serial.println("client disconnected");
  }
}

void SendRoot(EthernetClient client)
{

          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println("Connection: close");  // the connection will be closed after completion of the response
          client.println("Refresh: 5");  // refresh the page automatically every 5 sec
          client.println();
          client.println("<!DOCTYPE HTML>");
          client.println("<html>");
          client.println("Page 1<br>");          
          // output the value of each analog input pin
          for (int analogChannel = 0; analogChannel < 6; analogChannel++) {
            int sensorReading = analogRead(analogChannel);
            client.print("analog input ");
            client.print(analogChannel);
            client.print(" is ");
            client.print(sensorReading);
            client.println("<br />");
          }
          client.println("</html>");



  
}

void SendPage2(EthernetClient client)
{

          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println("Connection: close");  // the connection will be closed after completion of the response
          client.println("Refresh: 5");  // refresh the page automatically every 5 sec
          client.println();
          client.println("<!DOCTYPE HTML>");
          client.println("<html>");
          client.println("Page 2<br>");          
          // output the value of each analog input pin
          for (int analogChannel = 0; analogChannel < 6; analogChannel++) {
            int sensorReading = analogRead(analogChannel);
            client.print("analog input ");
            client.print(analogChannel);
            client.print(" is ");
            client.print(sensorReading);
            client.println("<br />");
          }
          client.println("</html>");


  
}

void SendPage3(EthernetClient client)
{

          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println("Connection: close");  // the connection will be closed after completion of the response
          client.println("Refresh: 5");  // refresh the page automatically every 5 sec
          client.println();
          client.println("<!DOCTYPE HTML>");
          client.println("<html>");
          client.println("Page 3<br>");          
          // output the value of each analog input pin
          for (int analogChannel = 0; analogChannel < 6; analogChannel++) {
            int sensorReading = analogRead(analogChannel);
            client.print("analog input ");
            client.print(analogChannel);
            client.print(" is ");
            client.print(sensorReading);
            client.println("<br />");
          }
          client.println("</html>");


  
}

void Send404(EthernetClient client)
{

          client.println("HTTP/1.1 404 Not Found");
          client.println("Content-Type: text/html");
          client.println("Connection: close");  // the connection will be closed after completion of the response
          client.println();
          client.println("Not Found");
}



Should get you started anyways.. :slight_smile:
have fun!

@desp166

qubits' proposal is a nice start.

I have another proposal which doesn't uses Arduino Strings. It's based on the webserver example of the Arduino IDE and shows how to read the HTTP header fields and split them in parts so you can Identify which URL was called. Furthermore it shows how to read parameters from the HTTP Body (transmitted via POST).

Hey @qubits-us thanks so much for this! It works exactly as expected!!

One question, I see that you used the Ethernet2.h library, I understood that the library is now "Depreciated" was it just habit to use that library or was there a clear reason? I changed to the standard Ethernet.h library and it worked perfectly.

@noiasca I will investigate, thanks!

old lib, mistake, change it, no worries..
only does "gets" and yes using strings and maybe there's some issues with ards string type, new to ard myself, so still discovering all its quirks..
could take strings out use chr arrays, but then need replacements for substring, trim and indexOf.

pretty simple when we use string type as you see and you should be able to expand on this pretty easy. @desp166 proposal looks quite nice too but haven't played with it yet.

have fun!

@noiasca I've spent a considerable amount of time going through your code and I think I'm getting there :smiley:

What would be really helpful would be if you could point me to some further reading about the state-machine control that you use. I keep thinking that I understand it but then realise, that I'm just missing some detail ... Thanks

well, there is not so much to tell, as the states in this state machine are a simple walk through one by one.

Remember, the HTTP Requests consists of

HTTP Header Fields
(blank line)
HTTP Body

(see Hypertext Transfer Protocol - Wikipedia)

and the state machine keeps track about what to read (or what to await) next. Hence the states are named:
REQUEST, CONTENT_LENGTH, EMPTY_LINE, BODY

  • REQUEST ... read the method (GET or PRINT), the URI and the GET parameters
  • CONTENT_LENGTH ... read the request length
  • EMPTY_LINE ... await the empty line
  • BODY ... read data from the the HTTP-body

If you have specific question - ask :wink:

@noiasca Wow, super fast reply, thanks!

I was looking at these lines:

    enum class Status { REQUEST,
                        CONTENT_LENGTH,
                        EMPTY_LINE,
                        BODY };

    Status status = Status::REQUEST;

I was getting a bit lost in all the uses of the word Status and the ::

However, I now realise that you used
enum class
and so the enumerator had to be qualified by the enum type.

Am I reading that correctly?

Yes.

status is of type Status (from the enum class), and the initial value is REQUEST.

The nice thing is you can't assign "wrong" values to status. When you have a state control like switch/case you get a warning when you forget one state etc. And enum classes are scoped, so you can have several enumerations in parallel without messing up the values (hence the :: )

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.