Webserver and led

Hello,

First of all, I need to be sorry about my english, I’m not good at other languages hahah

I’m having a problem with toggling a led over the internet. I have a Mega with Ethernet Shield connected to my router.
My code use the indexOf function to find de GET request with the HTML file to be opened, if it’s “led1.htm”, the Arduino toggles the LED and open that file at SD card and send to the browser, pretty simple in theory.

The problem is: when the browser(tested on Chrome, IE and Android Chrome) sends the HTML GET, there is not only one GET request, but a lot of them, making dificult to “analyze” the String and find the “led1.htm”, for example, because there’s a lot of “GET’s” requesting all the pages linked at the HTML file.

Here’s my code:

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

byte mac[]={0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
IPAddress ip(192,168,0,100);

EthernetServer server(80);

File webFile;

String req;

int LED1=36;
int LED2=40;
int cont1=0;
int cont2=0;

void setup()
{
  pinMode(LED1, OUTPUT);
  pinMode(LED2, OUTPUT);
  digitalWrite(LED1, LOW);
  digitalWrite(LED2, LOW);
  
  Ethernet.begin(mac, ip);
  server.begin();
  Serial.begin(9600);
  if(!SD.begin(4))
  {
    Serial.println("ERRO - SD NAO INICIALIZADO");
    return;
  }
  
  Serial.println("SD INICIADO COM SUCESSO");
  
  if(!SD.exists("index.htm"))
  {
    Serial.println("ERRO - index.html não encontrado");
    return;
  }
  Serial.println("index.html encontrado");
}

void loop()
{
  EthernetClient client=server.available();
  
  if(client)
  {
    Serial.println("Cliente");
    boolean currentLineIsBlank=true;
    while(client.connected())
    {
      if(client.available())
      {
        char c=client.read();
        req+=c;
        if(c=='\n' && currentLineIsBlank)
        {
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println("Connection: close");
          client.println();
          
          Serial.println(req);
          if(req.indexOf("led1.htm")>-1)
          {
            Serial.println("LED1 aberto");
            led1Switch();
          }
          else if(req.indexOf("led2.htm")>-1)
          {
            Serial.println("LED2 aberto");
            led2Switch();
          }
          else
            webFile=SD.open("index.htm");  
            
          if(webFile)
          {
            Serial.println("Aberto");
            while(webFile.available())
              client.write(webFile.read());
            webFile.close();
          }
          break;
        }
        
        if(c=='\n')
          currentLineIsBlank=true;
        
        else if(c!='\r')
          currentLineIsBlank=false;
      }
    }
    delay(10);
    client.stop();
  }
}

void led1Switch()
{
  Serial.println("LED1 TOGGLED");
  digitalToggle(LED1);
  webFile=SD.open("led1.htm");
}
  
void led2Switch()
{
  Serial.println("LED 2 TOGGLED ");
  digitalToggle(LED2);
  webFile=SD.open("led2.htm");
}

There’s a easier way to analyze the string or making it simpler?

PS: sorry again about my English, ask me if it’s difficult to understand something hahah

but a lot of them, making dificult to “analyze” the String and find the “led1.htm”, for example, because there’s a lot of “GET’s” requesting all the pages linked at the HTML file.

We can’t see your index.htm file or your led1.htm or led2.htm files. We can’t see the GET requests being made. So, we can’t help you, other than to suggest “Don’t do that”. Whatever that is that you are doing.

Here’s the HTML code, it’s the same for index, led1 and led2:

<html>
	<head>
		<center><img src="http://i242.photobucket.com/albums/ff45/yeoman108/Eureka/domotica.jpg" width="400px" height="300px"/></center>
		<title>Residência Iribarrem</title>
	</head>
	
	<body>
		

		<center><a href="led1.html" target="_self">LED 1</a></center>
		

		<center><a href="led2.html" target="_self">LED 2</a></center>
	</body>
</html>

The GET request is normal, but when I type 192.168.0.100 at Chrome, there’s not only “GET /”, it sends “GET /led1.htm” and “GET /led2.htm” as well, making difficult to determine on Arduino what page is being requested.

Sorry man, I’m new to forum and I didn’t think that this was necessary hahah

gustavori:
The GET request is normal, but when I type 192.168.0.100 at Chrome, there's not only "GET /", it sends "GET /led1.htm" and "GET /led2.htm" as well, making difficult to determine on Arduino what page is being requested.

Modern times.

HighSpeed-Internet and "intelligent" web browsers.

But you can change settings.

With Chrome go to "Settings" and activate "Show advanced settings."
Then deactivate "Predict network actions to improve page load performance."

This "next possible action prediction" of your browser will load the next linked pages, before you even decide to click the link. So if you should click the link, the browser already has loaded the page and can show it at once.

To prevent such prediction actions, you better not link your next "action pages" with "a href" linking, but you better create a "HTML form" with buttons to send the form and switch your LEDs.

Thank you man!

So using a form button it will not “predict” the links?

I’m not good at HTML, so correct me if I’m wrong, but a button with the same function will have this code?

<form method="get" action="/led1">
    <button type="button">LED 1</button>
</form>

Will I need two tags with two differents “action” attributes?
Of course I will need to change the code at Arduino to look for “led1” and not “led1.htm”, but will this work?

gustavori:
So using a form button it will not “predict” the links?

I don’t know for sure, as I have not tested that by myself.

But I suppose so: Forms are intended to be filled out by the user with some information and send them to the server. Even forms with “GET” method are intended for that. So it just would not make any sense to preload the form “action” address.

gustavori:
I’m not good at HTML, so correct me if I’m wrong, but a button with the same function will have this code?

<form method="get" action="/led1">

LED 1

> ``` > > > > Will I need two tags with two differents "action" attributes? > Of course I will need to change the code at Arduino to look for "led1" and not "led1.htm", but will this work?

Perhaps this may work:

<table>
  <tr>
    <th>
<form method="GET" action="/led1.htm">
    <input type="submit" value="LED 1"/>
</form>
    </th>

    <th>
<form method="GET" action="/led2.htm">
    <input type="submit" value="LED 2"/>
</form>
    </th>
  </tr>
</table>

But most likely you will receive a request for “/led1.htm?” and “/led2.htm?” and therefore must remove the question mark.

The other method would be sending form as method=“post”, but perhaps you must change your webserver to accept also POST requests in addition to GET requests.

jurs:
But I suppose so: Forms are intended to be filled out by the user with some information and send them to the server. Even forms with "GET" method are intended for that. So it just would not make any sense to preload the form "action" address.

I did some tests here and unfortunely even the form "action" is predicted by Chrome, I'm running out of optins here kkk
Is there another possible solution for this? I don't know more than the basics of HTML, so I don't know how to work with POST method, and make it work with Arduino is tricky, isn't?

Edit: writing the HTML code at the sketch or loading it from SD, there's difference?

gustavori:
Is there another possible solution for this? I don’t know more than the basics of HTML, so I don’t know how to work with POST method, and make it work with Arduino is tricky, isn’t?

For the HTML part it is easy, just replace
form method=“GET”
with
form method=“POST”
in the form.

In your code I cannot find any processing of “GET” requests, I just see you looking for search strings in the whole header. Very strange. Seems a very dirty and incomplete handling of client requests.

gustavori:
Edit: writing the HTML code at the sketch or loading it from SD, there’s difference?

What you send is what you send, the origin does not matter.

What do you want to create?
A webserver that runs from SD card, but that also can switch LEDs on certain pins across the Internet?

jurs:
In your code I cannot find any processing of "GET" requests, I just see you looking for search strings in the whole header. Very strange. Seems a very dirty and incomplete handling of client requests.

Make a String with the GET request was the way I founded to search for a certain part of the header and switch the LED that was requested, is there a better way?

jurs:
What do you want to create?
A webserver that runs from SD card, but that also can switch LEDs on certain pins across the Internet?

I just thought that storing the HTML files in SD card would made the sketch simpler, clearier. I don't have problems with using or not the SD, just thought it would be simpler.

gustavori:
I just thought that storing the HTML files in SD card would made the sketch simpler, clearier. I don't have problems with using or not the SD, just thought it would be simpler.

There should be sketches out there on the Internet which work correctly.

If I find some time tomorrow, I'll make a Google search and post a link or a sketch.

Testing different sketches with different HTML is much simpler if you keep the HTML in the sketch. Then you can change programming logic and HTML all in the same place. And need not change the programming logic in the sketch and the HTML in the SD card.

Thank you man, you’re helping me a lot.

The only thing about handling of GET requests in Arduino I found was how to parse them, what is pretty much what I’m doing, I think.

Here’s my lastest code:

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

byte mac[]={0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
IPAddress ip(192,168,0,100);

EthernetServer server(80);

File webFile;

String req;

int LED1=36;
int LED2=40;
int cont1=0;
int cont2=0;

void setup()
{
  pinMode(LED1, OUTPUT);
  pinMode(LED2, OUTPUT);
  digitalWrite(LED1, LOW);
  digitalWrite(LED2, LOW);
  
  Ethernet.begin(mac, ip);
  server.begin();
  Serial.begin(9600);
  if(!SD.begin(4))
  {
    Serial.println("ERRO - SD NAO INICIALIZADO");
    return;
  }
  
  Serial.println("SD INICIADO COM SUCESSO");
  
  if(!SD.exists("index.htm"))
  {
    Serial.println("ERRO - index.html não encontrado");
    return;
  }
  Serial.println("index.html encontrado");
}

void loop()
{
  EthernetClient client=server.available();
  
  if(client)
  {
    Serial.println("Cliente");
    boolean currentLineIsBlank=true;
    while(client.connected())
    {
      if(client.available())
      {
        char c=client.read();
        req+=c;
        if(c=='\n' && currentLineIsBlank)
        {
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println("Connection: close");
          client.println();
          
          webFile=SD.open("index.htm");  
          
          Serial.println(req);
          if(req.indexOf("led1=")>-1)
          {
              Serial.println("LED1 TOGGLED");
              digitalToggle(LED1);
          }
          else if(req.indexOf("led2=")>-1)
          {
            Serial.println("LED 2 TOGGLED ");
            digitalToggle(LED2);
          }
            
          if(webFile)
          {
            Serial.println("Aberto");
            while(webFile.available())
              client.write(webFile.read());
            webFile.close();
          }
          break;
        }
        
        if(c=='\n')
          currentLineIsBlank=true;
        
        else if(c!='\r')
          currentLineIsBlank=false;
      }
    }
    delay(10);
    client.stop();
  }
}

gustavori:
Here’s my lastest code:

And here is a code I just copied from the Internet.
I had to adapt it a little bit, the code was heavily broken by strange HTML formatting on its page.

Runs with UNO and Ethernet-Shield, just change the IP-Adresse for the server.

Be sure to take the SD card out from the shield, before loading the sketch, all files are sent from the sketch. I think the “write protect” and “SD card present” switches might be used as outputs in this sketch, I don’t know for sure. Edit/Correction: D4 is used for the SD card and can only be used for general I/O if the SD slot is not occupied.

Because of size, I append a file attachment and cannot send the code inline.

The programming logic is like that:

  • The HTML page reloads every 10 seconds with the current state
  • pushing a button you can switch the output(s) and reloads the page

EthernetSwitch.ino (14.5 KB)

Now days browsers make a second request for a favorite icon which sometimes can cause issues.

This is exactly what I need, thank you jurs!

Just one problem I'm trying to fix hahah
Arduino couldn't connect to the router, I think. The IP address at serial monitor is always 0.0.0.0 :S

Edit: I got it, I had an SD card in the shield hahah

gustavori:
Just one problem I’m trying to fix hahah
Arduino couldn’t connect to the router, I think. The IP address at serial monitor is always 0.0.0.0 :S

Edit: I got it, I had an SD card in the shield hahah

Congratulations, you found out what I wrote in my last message when I posted the sketch:
Be sure to take the SD card out from the shield, before loading the sketch

That’s because I wrote the sketch for an UNO and wanted to maximize the number of output pins, so the SD card on pin-4 is blocked with the code I posted.

If you want to use pin-4 for the SD card, you cannot use pin-4 for a switching output and on an UNO only pin-5 to pin-9 would be left for switching outputs.

But for a MEGA board, you could use many more pin numbers that are unused by the Ethernet shield.

Perhaps some extensions would be nice: I.e. if you want to switch the output over the Internet and make your Arduino webserver visible from outside your LAN, some kind of “basic authentication” with Username/Password would be useful. Just to prevent, that anybody on the Internet can switch your Arduino outputs.