Nella quinta parte di questo tutorial, inizieremo ad utilizzare il nostro ethernet shield per trasformare Arduino in un server web.
World Wide Web
Tra i servizi di rete, quello sicuramente più utilizzato è il servizio web: ogni volta che “navigate” su un sito, il programma che utilizzate (chiamato browser) contatta il server web che ospita tale sito utilizzando il protocollo HTTP e ottiene i contenuti (pagine, immagini, animazioni…) da visualizzare.
Le pagine web sono scritte utilizzando un linguaggio di marcatura chiamato HTML; tale linguaggio utilizza dei tag per descrivere il contenuto della pagina.
I principali vantaggi di utilizzare HTTP anche per comunicare via rete con Arduino sono:
[checklist]
- non è necessario sviluppare un client dedicato, è possibile utilizzare un comune browser (Internet Explorer, Firefox…);
- il protocollo HTTP è testuale, facilmente interpretabile da Arduino con le funzioni di string compare…
- anche il linguaggio HTML è testuale, rendendo comodo generare pagine -anche dinamiche- da Arduino.
[/checklist]
Programma
Scriveremo un semplice programma che stamperà su seriale le richieste del nostro browser e risponderà con una semplice pagina HTML. Il programma sarà utile sia per vedere come gestire la comunicazione HTTP, sia per capire quali informazioni il browser ci manda (informazioni che saranno utilizzate in un prossimo tutorial).
Lo sketch completo è disponibile sul repository di GitHub, di seguito commentiamo le righe di codice più significative:
word len = ether.packetReceive(); word pos = ether.packetLoop(len); |
All’interno del loop salviamo in una variabile il valore di ritorno del metodo packetLoop(): questo valore indica la posizione, all’interno dei buffer di ricezione, in cui inizia la richiesta del browser.
if(pos) { Serial.println("---------- NEW PACKET ----------"); Serial.println((char *)Ethernet::buffer + pos); Serial.println("--------------------------------"); Serial.println(); |
Se pos è maggiore di zero, significa che abbiamo effettivamente ricevuto una richiesta e possiamo stamparla su seriale (buffer + pos indica proprio la posizione da cui partire ad estrarre i dati dal buffer di ricezione).
BufferFiller bfill = ether.tcpOffset(); |
Per memorizzare la risposta da inviare al browser, utilizziamo un oggetto BufferFiller. Questo oggetto deriva dalla classe Print e viene costruito passando l’indirizzo (tcpOffset) del buffer ethernet da cui partire per memorizzare la risposta.
bfill.emit_p(PSTR("HTTP/1.0 200 OK\r\n" "Content-Type: text/html\r\nPragma: no-cache\r\n\r\n" "<html><body><h1>BasicServer Demo</h1></body></html>")); |
Il metodo emit_p() ci consente di inserire dati nel buffer: in questo caso creiamo una semplice pagina HTML che visualizza la scritta BasicServer Demo. Per risparmiare spazio in memoria RAM, utilizziamo la macro PSTR() che memorizza le stringhe in PROGRAM.
ether.httpServerReply(bfill.position()); |
Infine utilizzando il metodo httpServerReply() possiamo inviare al browser la risposta. Il metodo richiede, come parametro, il numero di caratteri da inviare; numero di caratteri che possiamo ottenere dal BufferFiller con il suo metodo position().
Caricato lo sketch, possiamo provarne il funzionamento inserendo nel browser l’indirizzo IP di Arduino… il risultato dovrebbe essere:
E sul monitor seriale:
Vi starete domandando come mai il browser ha fatto due richieste, una per la pagina “/” (ovvero la homepage del sito) e una per l’immagine favicon.ico. Questa è l’immagine che alcuni siti visualizzano accanto al loro indirizzo; ecco ad es. l’icona di DangerousPrototypes:
sono assolutamente digiuno di informatica ed elettronica, ma ho molto apprezzato i tutorial per arduino che mi hanno aiutato a capire come connetterlo ad una rete. Vorrei ancora avere indicazioni per trasmettere dati a google spreadsheet (magari usando i moduli) e anche come impostare una porta diversa dalla 80 sulla quale ho già un altro webservver. grazie per il lavoro già fatto che ha condiviso.
Hai provato questa nuova libreria per ENC28j60 ??
https://github.com/turicas/Ethernet_ENC28J60
Ciao Mario,
no, non l’ho ancora provata… ad un primo sguardo sembra condividere molto codice di base con la EtherCard, anche se qualche parte sembra scritta in maniera più “pulita”…
Hello,
I found your tutorials very interesting. I have a question if you can help me.
I am trying to create a temperature sensor on a web page. I use ENC28j60 and the ethercard library.
How can i write down on the webpage the temperature that my sensor is sensing and another variable from my arduino program?
Another question is how to make buttons on the webpage act on a variable in my program.
Regards.
Hi Ciprian,
I’m working on a new tutorial with a more complex webserver… stay tuned 😉
ciao luca,
complimenti per il tutorial.
Sono riuscito a eseguirlo e ad integrarlo in una mia applicazione che legge degli impulsi da un contalitri e al momento li spedisce sulla seriale.
Tramite un timer, eseguo il codice relativo alla parte ethernet e riesco correttamente a collegarmi al server e visualizzare sul browser la pagina demo che hai proposto. In questa pagina, vorrei inserire il valore dei miei impulsi che è salvato in una variabile di tipo int. Ho provato a creare una stringa contenente la risposta HTTP ma quando faccio bfill.emit_p(PSTR(miastringa)); il compilatore mi da questo errore:
initializer fails to determine size of ‘__c’
Sono abbastanza nuovo di Arduino per cui non conosco ancora bene la sintassi e le best practices….hai un consiglio da darmi ?
Grazie!
Ciao Ettore!
“miastringa” è una stringa statica oppure una tua variabile?
Luca, thanks for your great tutorial, I have a question: I’d like to connect 3-4 EthernetArduinos via Ethernet and allow them to share files stored on their respective SD cards.
I’ve found examples for making the Arduino a web-server, but it needs a DHCP server being provided by e.g. a PC.
And it doesnt really allow one arduino to access the files on the other arduino’s SD card.
I was wondering if you think this would be possible and maybe give me a few pointers how to best go about it. Thank you in advance!
Peter
Hi Peter
you don’t need a DHCP server, you can configure ethernet shield with a static IP address using staticSetup().
I wasn’t able to find an example using SD card with enc28j60 shield… I’m working on it! 😉
Ciao Luca,
During the last days I learned a lot from you about the EtherCard library and collaboration with Arduino – Thanks!
However, I still got one for you: With “smaller” Arduinos I run into buffer size limitations. Do you know whether there is a way to split the response to the server in smaller chunks allowing to keep the message within the buffer size limits?
Thanks a lot in advance!
Axel
Hi Axel!
Unfortunately at the moment the EtherCard library doesn’t support TCP fragmentation and you’re required to buffer the entire packet in Arduino’s memory… The developers are working on a rewritten version of the library so keep an eye on its Github repository!
Hi!
how I can send a string to indicate the state of a digital input?
Thanks
Hi Pedro,
are you trying to display the state of a digital pin on a webpage? Or send it to a script/program?
Do the tutorials for the enc28j60 also work with ethernet shield & W5100?
no, the two ICs are very different… for W5100 you can refer to the official Arduino documentation.
Hi Luca!
Do you have any news about TCP fragmentation? I am working on this behavior and it getting me crazy!
Do you have contact with EtherCard developers? Do you think they would interest in my work?
Take a look at: https://github.com/renatoaloi
Please, if you can send me some feedback it will be very nice for my work. Thanks!
Renato
Hi Renato,
no, at the moment my workaround is the use of Yun, where the ethernet connection is managed by a Linux distribution. I contacted the authors of EtherCard via Github, I think they may be interested as I know they are rewriting the library to support such functionalities!
Hi, congratulations for tutorial!
Please help me..
In my serial monitor:
BasicServer Demo
Ethernet controller initialized
Failed to get configuration from DHCP
IP Address: 0.0.0.0
Netmask: 0.0.0.0
Gateway: 0.0.0.0
What wrong¿?
Hi Maryori,
it’s hard to find out what’s wrong… it seems that Arduino doesn’t receive a valid address: is a DHCP server active in your network? Try changing the Mac address in the sketch, it may help.
Ciao Luca,
vorrei usare il tuo code e ho provato a modificarlo solo che mi da sempre un errore il code sarebbe:
String temp = “hello”;
BufferFiller bfill = ether.tcpOffset();
bfill.emit_p(PSTR(“HTTP/1.0 200 OK\r\n”
“Content-Type: text/html\r\nPragma: no-cache\r\n\r\n”
“” + temp + “”));
ether.httpServerReply(bfill.position());
l’errore é:
bfill.emit_p(PSTR(temp));
error: array must be initialized with a brace-enclosed initializer
exit status 1
initializer fails to determine size of ‘__c’
hai qualche idea?
grazie mille!