In questo terzo articolo vedremo come collegarci e ottenere informazioni da un sito web.
Dopo aver imparato come collegare Arduino alla rete (con indirizzi statici oppure sfruttando un server DHCP) vediamo ora come inviare/ricevere informazioni attraverso un sito web.
Per rendere l’esempio un po’ più interessante, ho preparato una semplice pagina web in PHP che restituisce, in maniera randomica, un aforisma ogni volta che viene chiamata (gli aforismi provengono da Aphorisms Galore):
Proveremo a recuperare tali aforismi con Arduino e a visualizzarli via seriale.
DNS
Il collegamento ad un sito web avviene normalmente digitando il suo nome: il computer, attraverso il server DNS, è in grado di risolvere tale nome nel relativo indirizzo IP per effettuare poi la connessione.
Molto importante è quindi configurare in Arduino l’indirizzo IP del server DNS della nostra rete:
- se la configurazione avviene tramite DHCP, normalmente Arduino prenderà in automatico anche il server DNS;
- se la configurazione avviene manualmente, è necessario inserire l’indirizzo IP del DNS chiamando il metodo staticSetup():
#include <EtherCard.h> static byte mymac[] = {0xDD,0xDD,0xDD,0x00,0x00,0x01}; static byte myip[] = {192,168,1,10}; static byte gatewayip[] = {192,168,1,1}; static byte dnsip[] = {151,99,125,2}; ... ether.staticSetup(myip, gatewayip, dnsip); |
Possiamo verificare se la risoluzione DNS funziona utilizzando il metodo dnsLookup():
char website[] PROGMEM = "www.lucadentella.it"; ... if (!ether.dnsLookup(website)) Serial.println("DNS failed"); else Serial.println("DNS resolution done"); ether.printIp("SRV IP:\t", ether.hisip); |
Collegamento
La libreria EtherCard mette a disposizione un metodo per collegarsi ad un sito web: browseUrl(). Questo metodo prepara la connessione; la quale avviene in vari passi successivi, gestiti all’interno del loop dalla coppia di istruzioni che ormai conosciamo:
ether.packetLoop(ether.packetReceive()); |
E’ quindi importante mantenere queste istruzioni perché tutto funzioni.
Il metodo browseUrl() richiede alcuni parametri:
- prog_char *urlbuf, la parte costante dell’indirizzo;
- const char *urlbuf_varpart, la parte variabile dell’indirizzo;
- prog_char *hoststr, il nome del sito web;
- void (*callback)(byte,word,word)), il nome di una funzione di callback ovvero la funzione che verrà eseguita al termine della chiamata al sito web.
L’indirizzo è stato diviso in due parti per questioni di occupazione di memoria: la parte statica viene memorizzata nella memoria programma (con il comando PSTR()), senza quindi sprecare memoria RAM.
Nella prossima pagina vedremo il programma completo…
Ciao,
Ho provato tutti i tuoi esempi, e sono veramente interessanti.Ora, ho la necessità di accedere alla mia WebPage Arduino, dall’esterno. Mi sono iscritto al server NO-IP, che funziona abbastanza bene, ma devo necessariamente avere il PC acceso, che provvede ad effettuare la richiesa di autorizzazione, ogni volta che cambia l’indirizzo IP. E’ possibile far effettuare la richiesta direttamente da ARDUINO, senza dover necessariamente tenere il PC acceso ?
Oppure conosci un altro sistema per risolvere il problema dell’IP dinamico ?
Grazie in anticipo dell’aiuto.
Ciao Domenico,
molti router ADSL hanno incorporata la funzione di aggiornamento per i più famosi servizi di Dynamic IP, prova a vedere se anche il tuo ti offre questa possibilità.
Non ho mai pensato ad un modo per farlo fare ad Arduino, mi sembra un ottimo spunto per un futuro articolo 😉
Ciao Luca,
in realtà, il mio modem ha la possibilità di inserire il DDNS, ma solo con il server dyndns.org, che purtroppo è diventato a pagamento.
Io, sono riuscito ad ottenere l’IP tramite Arduino, utilizzando il tuo esempio con browseUrl() al sito http://www.indirizzo-ip.com/ip.php?.txt.
Questo sito, restituisce il solo indirizzo IP senza testi aggiuntivi e senza tag html.
Ora, se riuscissimo a farci inviare tale IP tramite un sms gratis, ad esempio, Google calendar, avremmo risolto il problema senza iscriverci a nessun server.
Non a caso ho nominato Google calendar, perchè ho letto che è possibile farsi inviare tali sms a ogni richiesta, la partre oscura, per me, sono dei file .php che onestamente non so come possono interagire e soprattutto dove metterli.
Ricordo che ho la necessità di accedere a PC spento.
Scusa se sono stato un po lungo, ma per me risolvere la questione è molto importate.
Saluti
Ciao Domenico,
ho guardato le API che no-ip mette a disposizione… sembra abbastanza semplice far fare l’aggiornamento ad Arduino: una cosa tipo:
– ogni tot minuti controllo il mio IP
– se l’IP è diverso da quello precedente, aggiorno no-ip e me lo memorizzo
Per aggiornare no-ip serve fare una GET:
http://www.no-ip.com/integrate/request
faccio qualche prova e posto uno sketch di esempio nei prossimi giorni 😉
Ciao, Luca
Sei, riuscito a fare qualche prova per il no-ip ?
Saluti
Ciao Domenico,
sì, ho quasi pronto uno sketch… mi manca l’interpretazione dei possibili codici di errore ma l’aggiornamento avviene.
Dovrei pubblicarlo entro fine settimana, stay tuned 😉
Ciao Luca,
Spero che non ti sia dimenticato di me !
Ciao Luca,
se ai già la solizione del get con no-ip, potresti postare il progetto; per gli errori penso di cavarmela da solo.
Scusami per l’insistenza.
Saluti
Ciao Domenico,
ce l’ho fatta finalmente a completare il post 😉
http://www.lucadentella.it/2012/04/28/enc28j60-e-arduino-6/
Ciao Luca, grazie mille dei tuoi tutorial, chiarissimi e funzionanti!!! 🙂
Ho provato però a fare una variante a questo tuo sketch, ossia ho provato a leggere un’altro file su un sito diverso e tutto funziona bene, però non riesco a far alternare all’interno dello stesso sketch la chiamata a due siti differenti! Cioè ho creato una piccola sequenza in cui in un primo passo ripeto completamente tutto quello che è la parte di chiama e risposta alla tua pagina e poi faccio lo stesso con una mia pagina, però non funziona nulla!!!! :-(((( Se le chiamo individualmente in due sketch distinti, tutto lavora, così sono sicuro che anche l’altra pagina è accessibile, poi se li metto insieme, non leggo ne l’una ne l’altra!!! Dove sbaglio??????? :-((((
Ciao Massimiliano,
riesci a mandarmi il tuo sketch che ci guardo? Ogni volta che cambi sito ricordati di chiamare la funzione
ether.dnsLookup(nuovoSito)
in modo che la libreria risolva l’IP del sito e lo memorizzi.
Ciao Luca,
In realtà pensando che fosse proprio un problema di inizializzazione avevo richiamato tutto, pure la richiesta DHCP, ma ora controllando la parte ether.dnslookup ho visto che avevo col copia e incolla, lasciato il primo sito!!!!!!!
Sono un pirla!
Nel leggere quello che mi hai scritto sono andato subito a vedere e l’ho trovato!!!!
Ora funziona!!!!
Grazie mille per il tempo e per l’illuminazione!!!!!! :-))))))))
Luca, approfitto ancora un attimo del tuo tempo e della tua pazienza 🙂
Il puntatore che è presente nella:
static void response_callback (byte status, word off, word len) {
Serial.print((const char*) Ethernet::buffer + off + 207);
}
Lo posso portare fuori in modo da poterlo manipolare anche nel Loop() ?
E se si, come posso trasformare un puntatore di char in una String?
Grazie :-)))))
Ciao Massimiliano,
vorresti “leggere” nel loop il contenuto del buffer di risposta?
se usi la tcpReply() puoi ottenere già un puntatore a char della risposta, guarda il mio esempio su DynDNS:
http://www.lucadentella.it/2012/04/28/enc28j60-e-arduino-6/
Proverò a fare come suggerisci!
Un’altra domanda, ho provato a cambiare il valore all’interno della “byte Ethernet::buffer[700];”, provando con valori come 750 o 800 non funziona più nulla!!! Immaginavo che fosse la profondità del buffer, ma forse non ho capito qualcosa!!!!
Ho bisogno di fare questo perchè io ho più dati da ricevere ed ho notato che inoltre su una chiamata, quando arrivo a leggere 550 byte, mi fermo nonostante ce ne siano altri da leggere (ho fatto un conteggio della lunghezza dei byte all’interno della response_callback che vengono passati alla Serial.println per la stampa su seriale, comprensiva di header).
Ciao Massimiliano,
quello è il buffer dove lo shield va a memorizzare l’intero pacchetto… se si blocca Arduino significa che aumentando la sua dimensione stai saturando tutta la (poca) memoria RAM che Arduino ha a disposizione.
Il buffer contiene tutto il pacchetto, compresi gli header dello stack protocollare TCP/IP… per questo dei 700 bytes totali, quelli utili per il payload sono sicuramente meno! Se la lettura si ferma significa che hai raggiunto in memoria il terminatore di stringa (‘\0’) e quindi la fine del paypload.
Luca ciao, son sempre io e son sempre più disperato!!!!
Allora seguendo i tuoi consigli, son riuscito a connettermi a diverse pagine su diversi server, ho prelevato i “pochi” dati concessi e ho fatto quello che dovevo fare con loro.
Ora se ripeto tutta la mia sequenza una sola volta, fila tutto liscio, le varie parti di programma fanno quello che desidero e tutto gira liscio.
Ora, nel momento in cui voglio ripetere in continuo questa sequenza, il primo passo viene rieseguito ma poi si riavvia il micro!!!!! Non capisco cosa cavolo sia!!!!!
Ti posso passare lo sketch per un’occhiata??? :-))))
Ciao Massimiliano
sì, mandamelo che ci do un’occhiata!
Grazie mio salvatore!!!!!! :-)))
Dove trovo nel sito una tua mail alla quale spedirlo????
ciao
ti ho scritto una mail… 😉
Ciao, ti ho spedito lo Sketch sulla mail, peró non so se ti è arrivata oppure no. Non vorrei fosse finita nella Spam :-))))
Hello Luca,
Could I connect with 2 websites?
Should I run the dnslookup for both sites?
I tried this but I could establish connection with only the second website I ran the dnslookup.
Could that be possible?
Thank you,
John
Ciao Luca,
Thanks for this great tutorial, I learned a lot and was already able to realize some servers.
My question for you regarding the client is whether you have a solution if only the IP address of the server is known? In my case I’d like to connect to a server in my local network i.e. server address 192.168.1.1.
Would be great if you could give me a hint.
Thanks in advance,
Axel
Hi Axel,
it’s easy: you have only to manually asign the IP address to the variable ether.hisip, without calling ether.dnsLookup:
static byte hisip[] = { 192,168,1,1 }; // remote webserver
[…]
ether.copyIp(ether.hisip, hisip);
let me know if it works!
Thank you Luca,
Yes, it’s a simple as this.
Best regards,
Axel
Could you please show me you code? I’m a beginner…Thank you so much…
Ciao luca,
i tried your code of this tutorial.am getting DNS failed message.What will be the reason? Am pasting the data i got on arduino serial window.
Client Demo
Setting up DHCP
My IP: 192.168.1.102
Netmask: 255.255.255.0
GW IP: 192.168.1.1
DNS IP: 208.67.222.222
DNS failed
SRV IP: 0.0.0.0
Ciao Luca,
sto facendo alcune prove per interfacciare un Arduino via Ethernet ad un WebService. Ho seguito le indicazioni che ho trovato nell’esempio WebClient di EtherCard e le ho confrontate con il tuo articolo. Tutto funziona, ma nella risposta che ricevo dal WebService sembra perdersi circa un terzo della risposta. Ho provato ad aumentare la dimensione del buffer fino a 1300 byte, ma il risultato non cambia.
Ho anche provato a stampare il buffer carattere per carattere per vedere bene il contenuto, ma la parte terminale è tutta a zero.
E’ come se si perdesse un pacchetto di risposta (e anche in questo caso la colpa potrebbe essere proprio del buffer troppo piccolo…).
Hai qualche suggerimento?
Grazie per il tuo tempo.
Ciao Riccardo,
purtroppo anche in fase di ricezione il buffer ha un limite vicino ai 700 bytes: se la risposta è superiore il pacchetto viene troncato. Prova a chiamare il webservice da un browser o usando un client (tipo SoapUI) e vedi quanto è grande la risposta…
My English is not good. .I want to access a server on the LAN (IP 192.168.1.104).But does not know how to use BrowseUrl this function to access.And I also want to POST some data to this IP address.Can you please give me some advice it?Very, very grateful.Thank you..
Hi Leroy,
first, set the ether.hisip to the IP of your server (192.168.1.104), so methods like tcpSend() and browseUrl() connects to that IP.
Then, for POSTing data you need to create a Stash (using :prepare) that contains your POST data (including HTTP headers) and send it to the server using tcpSend(). Take a look to this example, where I’m POSTing data to Skebby’s webservice.
Thank you so much…I’m sorry for my english..If I have offended, please forgive me….I tried the following code..
static byte hisip[] = { 192,168,1,104 };
And in setup function:
ether.copyIp(ether.hisip, hisip);
In loop function:
ether.browseUrl(PSTR(“/demo/”), “abc.html”, “192.168.1.104”, response_callback);
But does not seem to work…
Hi Leroy
I assume you’re webserver has a page to the following address: http://192.168.1.104/demo/abc.html right? Can you display it using a browser?
Hi Luca,
I am a bit new in arduino but I really like all the tutorials you made here. Great to learn many things.
I would like to ask you if you can help me with sketch which should get/post data from web but using password. I was thinking to have a file which would be in folder protected by .htaccess . Then I would need to get the data by basic authorization http request. Is that possible to be done with ethercard.h library? If so can you help me with it please?
Thanks.
Hi Martin,
yes, you can implement basic authentication… I’ll write a post about it!
Hi Luca,
great, thanks for it. I will wait the post.
Hi Luca,
This tutorial worked perfectly. Now I’m trying to make it work with another server, but I only have the IP address. I saw the comments above, so I tried this:
static byte hisip[] = ip adress
and instead to use dnsLookUp:
ether.copyIp(ether.hisip, hisip);
Now I don’t know how to set the parameters of browseUrl function, since I don’t have the parameter “website” and I have the variable “hisip”. I tried to do this in different ways, without sucess. Do you have any sugestion?
Thanks! (and sorry about my english)
Hi Emanoeli, define the variable “website” with the IP address of your webserver, for example:
char website[] PROGMEM = "10.0..1";
MY C Demo
Ethernet controller initialized
DHCP configuration done
IP Address: 192.168.5.102
Netmask: 255.255.255.0
Gateway: 192.168.5.1
dnsip: 192.168.5.1
DNS failed
SRV IP: 0.0.0.0
ether.browseUrl(PSTR(“/examples/servlets/servlet/”), “HelloWorldExample”, “192.168.5.108:8080”, response_callback);
Hi Polly,
which is your problem? No response? The callback is never executed?
My English is poor, do not know how to describe the problem,
why can’t println ‘response_callback’ Content?
see this —
http://www.520665.com/problem.html
cia luca…
nn capisco xk quando vado a compilare mi da errore sulla stringa ether.printIp(“Netmask:\t”, ether.mymask): ‘classethercard’ has no member named ‘mymask’
ps mi e successo ank sul 2° progetto… xo mi pinga lo stesso… aiutami… 🙁
…e mi dice ank “dns failed”
I print the text which come from the website to a LCD, but it is too long. And the text is autoscrolling on the LCD. There is a problem. Text is scrolling in the first line but some last characters are printing to the second line. I need to all of them in the first line.
My English is bad. Hopefully, you have understood my problem. 🙂
Hi, the problem seems in the way you’re printing the text… are you using LiquidCrystal library? Probably the text you’re printing includes a “new line” and therefore the library goes to the second line automatically.
Hi, you have nice tutorials, just to say at the begining. But I have problem retrieving info from site other than one in your example? What do you use to produce that random phrase? PHP or?
When i try to retrive Hello world even from simple txt file on server, I can’t connect to it.
Hi Mate,
yes, I wrote a simple php page to generate aphorisms… but the code should work with every site/page that returns a text message: which URL are you trying to fetch? Can you get it using a web browser?
HI Luca, sorry for delay, I was on business trip. Well, I made a simple hello world text/html web page and tried to access it but in vain, so I wasn’t sure if you were using something other than just simple echo command in PHP for phrase generation (since PHP code is invisible from client side so i can’t check it).
But even better for me would be solution to access .txt file on server (which I can from the browser). Is tha also possible?
Btw this is what i get in serial:
>>> REQ
<<< reply 383 ms
HTTP/1.1 301 Moved Permanently
Content-Type: text/html; charset=UTF-8
Location: http://btcgoodies.com/hello.html
Server: Microsoft-IIS/8.0
X-Powered-By: ASP.NET
X-Powered-By-Plesk: PleskWin
Date: Sat, 23 Aug 2014 14:04:35 GMT
Connection: close
Content-Length: 155
Document Moved
Object MovedThis document may be found here
Hm, it seems your server is powered by Apache and mine by Windows IIS (crap), so that might be it. Or maybe Godaddy hosting is causing problem (again) as they are using redirects in their system as typical procedure. But thing is I can open it with any browser normally, only Arudino has trouble reaching it.
Hi Mate,
well you are right: it seems your ISP (godaddy) is always using redirects when accessing to the hosted pages… web browsers can seamlessly follow the redirects but Arduino can’t. I don’t know the reason of that behaviour, but it’s clear from the log you sent me (HTTP 301)
It seems that was the issue. This thing don’t work either on windows based servers or just Godaddy windows based servers.
I bought another linux based (apache) server also on Godaddy and it works great now! Be notified that Godaddy doesn’t offer switching from Windows to Linux after you already bought initial package.
Did you find a way for working on windows based servers ?
Hi, I cannot see any difference as far as they support HTTP protocol (IIS, apache httpd, nginx… all can run on Windows servers)
Hi luca!
I noticed that some people have the same problem as me. It’s about a problem with the DNS. I noticed that the majority report this problem this year. Maybe it has to do with the library EtherCard? Can you put your version of the library? Alternatively, if you could check the operation of your design on a new version of the library?
Anyway – great job with your tutorial!
Hello. Thanks a lot for this tutorial, I’ve got it working.
My question is about the timer in the loop().
if (millis() > timer) {
timer = millis() + 5000;
…
}
Can you elaborate on the use of these lines please.
Also I’ve been figuring out how to store the response into a string or sd card instead of serial.print it but with no success. Can you help me out please.
Thanks.
Hi! It’s just a way to “wait” 5 seconds without blocking the execution… give a look to the blinkNoDelay tutorial. For your question about storing data in a file located on an SD card, there are many tutorials on the playground.
Buonasera Luca, innanzitutto voglio ringraziarti per il lavoro che hai fatto per il ENC28j60, è illuminante visto che sono alle prime esperienze.Sulla ricezione delle stringhe e decodifica nel buffer, non ho problemi, mentre ne ho sull’invio delle richieste HTTP. Vorrei che Arduino inviasse il seguente comando”http://192.168.1.188:81/cam/Cam11/trigger”. Potresti cortesemente inviarmi uno sketch che realizza tale funzione? Ti ringrazio .Andrea
Buonasera Luca
Sorry for my bad English
There is the possibility of programming the
char website [] PROGMEM = “www.lucadentella.it”;
in another way to be able to change it dynamically without having to record the micro again, I receive the data by serial port.
Tante grazie
Hi Italo, not at the moment… there’s an open issue in Github for this problem but it hasn’t been solved yet. You can have a dynamic website but not use it with the browseUrl() method.