In this tutorial, I’m going to show how to develop a small website that gets data from Arduino (using your ethernet shield), stores it and displays it on a chart.
Logical schema
Your website will be made by two pages:
- the first, saveTemp.php, gets data from Arduino and stores it in text file;
- the second, displayTemp.php, reads the text file and displays the data.
In this example, Arduino gets room’s temperature using the SD18B20 sensor; I’ve already blogged about this sensor in this post.
For programming the web pages, I chose the PHP language, widely used on the web.
Sending data
I use the GET method of the HTTP protocol to send data to the webserver. That method sends the parameters in the clear within the URL, using the form parameter=value and dividing the different parameters with the & symbol:
To prevent other users from sending data, in addition to the temp parameter you must also send to the webpage a password using the pwd parameter.
My sketch reads the temperature from the sensor, converts it in a string value and “print” it in a Stash object:
sensors.requestTemperatures(); float float_temp = sensors.getTempCByIndex(0); char string_temp[7]; dtostrf(float_temp, 4, 2, string_temp); Stash stash; byte sd = stash.create(); stash.print(string_temp); stash.save(); |
Then it prepares the request in a different Stash object and sends it with the tcpSend() method:
Stash::prepare(PSTR("GET /demo/saveTemp.php?temp=$H&pwd=$F HTTP/1.0" "\r\n" "Host: $F" "\r\n" "\r\n"), sd, password, website); session_id = ether.tcpSend(); |
Thanks to the session identifier (session_id) you can get the response from the server and check if it contains an error message (“KO”):
const char* reply = ether.tcpReply(session_id); [...] if(strstr(reply, "KO - ") != 0) Serial.println(strstr(reply, "KO - ")); |
In PHP you can get the data using the associative array $_GET:
$temp = $_GET["temp"]; $pwd = $_GET["pwd"]; |
After having verified the password, the temperature value is stored in the file together with a timestamp:
define("LOG_FILE", "./temperatures.csv"); [...] $file_handler = fopen(LOG_FILE, "a+"); fwrite($file_handler, time() . "," . $temp . "\n"); |
In the next page, you’ll learn how to display the data on a chart…
I’ve just gone through your 14 tutorials and I’m happy to be using the $4.00 enc shields instead of the $20 wiznets. I think you can also get the enc in DIP too.
You are a great teacher, nice pace and movement from principles to greater complexity.
Next for me to figure out is a system using an apikey instead of putting the password in the URL
I’d also like to figure out how to push a notice from the avr to a browser/smartphone.
Con tcpReply() e tcpSend() sarebbe possibile dialogare con un server smtp per inviare email ?
ciao, teoricamente sì… sto preparando un piccolo tutorial perché è un poco più complesso rispetto ad una singola chiamata web
Ciao Luca. Ho provato questo esempio ma trovo degli errori. Mi spiego meglio:
1) ho caricato i file php e la cartella JpGraph nella root del mio sito;
2) nello skecth ho inserito il mio sito web e la password ftp;
il file csv lo crea da solo?
Questo è quello che mi spunta nel serial monitor:
WebTemperature demo
Ethernet controller initialized
DHCP configuration done
Website IP resolved
IP Address: 192.168.1.58
Netmask: 255.255.255.0
Gateway: 192.168.1.1
Website IP: 217.—————
Temperature -127.00U sent to website… OK
Temperature -127.00U sent to website… OK
Temperature -127.00U sent to website… OK
Temperature -127.00U sent to website… OK
Temperature -127.00U sent to website… OK
Temperature -127.00U sent to website… OK
dove sta l’errore?
ciao Matteo, il csv lo crea da solo… sembra che lo sketch non riesca a leggere la temperatura dal sensore: i collegamenti sono ok? Prova lo sketch demo della libreria e vedi se ti da qualche informazione in più.
Hello,
great tutorial. I have question about sending variable directly from arduino to web.
If i want use this:
analog = analogRead(A0);
bfill.emit_p(PSTR(analog));
i get:
In function ‘void loop()’:
error: initializer fails to determine size of ‘__c’
Hi Petr,
in the PSTR you have to enter a “placeholder” for the variables you add as parameters of emit_p, take a look at this example.
who to use this for socket programming please advice !!
Suresh, could you please explain better your question?
thanks
Ciao complimenti per i tutorial li ho seguiti tutti e sarei interessato a quello sulle e-mail. La serie di tutorial è finita o ne arriveranno altri? Grazie
ciao! sono stato un po’ impegnato sul lavoro ma sicuramente arriveranno altri tutorials 😉
grazie per i complimenti!
Do you know how I can send live data from the arduino/ENC28J60? I have a CANBus connection working alongside the ENC shield and I would like to forward CAN packets to a computer via the internet. I was thinking of using UDP but I can’t find any examples on UDP with the ENC shield. any tips?
Hi Peter,
did you read my example about sending actual temperature to a C# application?
Luca,
Great tutorials, thank you. I’m curious, when I try to access the webpage “xxx.com/displayTemp.php”, all it gives me is the code. Am I doing something wrong? Do I need to set something up first?
Hi David
your webserver must be able to “run” PHP code… so if you’re running your own server, install PHP following the guides on PHP website.
Hello Luca,
your ENC28J60 tutorial was very helpful to me in understanding the chip and its usage in real hardware. Moreover, the example listings are well documentated and can be easily adapted onto different tasks. Thank you for providing such valuable infos!
Best regards, Jürgen
Jürgen, thanks for your comment!
Thank you very much for this tutorial, I am finally able to send some data to the web 😀 Just as a comment, I think there is an error in “session_id = ether.tcpSend();”.. don’t you need to add the data type as in “byte session_id = ether.tcpSend();” ? Thanks!
Hi Armando,
if you analyze the full sketch on Github, you’ll notice that session_id is defined on the top:
static byte session_id;
because it must be visible also in the checkResponse() subrutine.
Luca,
Again great tutorials thank you. I’ve the PHP server running correctly (I forgot to install PHP) (DUH). I’m curious if you might be able to do a tutorial on how to bring a couple of your tutorials together like this one and the WebRelay? I was also wondering if PHP allows you to change set points or if I’d have to use HTML for that (still new to both of these languages).
Hi David
thanks! about set points, the JPGraph library is in PHP so with that language you have full control of the chart’s properties.
About your other request, are you thinking of a “dashboard” that displays data AND lets the user give commands (for example “close that relay”) to Arduino?
Luca,
Yes that basically what I was thinking. The dsahboard could have the graph at the top and buttons at the bottom or somethin like that.
Ciao Luca, ho cominciato a seguire da poco i tuoi tutorials e li trovo fantastici.
Mi chiedevo: in che modo si potrebbe ottenere lo stesso risultato con un POST Request? Il GET raggiunge il risultato, ma vorrei evitare di mostrare variabili e valori nell’url. Grazie.
Ciao Rob
sto per pubblicare un articolo che usa proprio il metodo POST…
ciao luca, naturalmente ottimo lavoro 😉
avrei un problema, io devo inviare i dati ad un server locale, al posto del sito web ho inserito l’indirizzo ip del server, ma arduino non riesce a risolvere l’ip. sbaglio metodo o c’è qualcosa che ho saltato?
Saluti, igor
Ciao Igor
se hai già l’indirizzo IP, non devi usare il metodo dnsLookup. Semplicemente definisci l’IP del server (es
static byte serverIp[] = {192,168,1,10};
) e copia tale indirizzo nella variabile hisip:ether.copyIp(serverIp, hisip);
Good Morning Friend
I’m tetando example web_client
but if I try to write my website in order to use a variable at run time I can not
website char [] PROGMEM = “www.google.com”;
works well, but
so
website char [] = “www.google.com”;
does not work, can you help me?
this is my code
#include
// ethernet interface mac address, must be unique on the LAN
static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 };
byte Ethernet::buffer[700];
static uint32_t timer;
//char website[] PROGMEM = “www.vallesolucoes.com”;
char website[] = “www.vallesolucoes.com”;
// called when the client request is complete
static void my_callback (byte status, word off, word len) {
Serial.println(“>>>”);
Ethernet::buffer[off+300] = 0;
Serial.print((const char*) Ethernet::buffer + off);
Serial.println(“…”);
}
void setup () {
Serial.begin(57600);
Serial.println(“\n[webClient]”);
if (ether.begin(sizeof Ethernet::buffer, mymac,14) == 0)
Serial.println( “Failed to access Ethernet controller”);
if (!ether.dhcpSetup())
Serial.println(“DHCP failed”);
ether.printIp(“IP: “, ether.myip);
ether.printIp(“GW: “, ether.gwip);
ether.printIp(“DNS: “, ether.dnsip);
if (!ether.dnsLookup(website))
Serial.println(“DNS failed”);
ether.printIp(“SRV: “, ether.hisip);
}
void loop () {
ether.packetLoop(ether.packetReceive());
if (millis() > timer) {
timer = millis() + 5000;
Serial.println();
Serial.print(“<<< REQ ");
ether.browseUrl(PSTR("/photos/envia/"), "envia.php", website, my_callback);
}
}
Hi
why do you need to store the URL in the RAM memory? The browseUrl function expects a website string stored in the PROGMEM… to change it you have to change the library.
Hello Luca. I have problem to connect with my WebSpace – Error Message: Unable to resolve Website IP
char website[] PROGMEM = “http://www.solarstation.lima-city.de”;
I try also with …
char website[] PROGMEM = “solarstation.lima-city.de”;
do you have any idea?
Thanks a lot for all this tutorials. Michael
Hi Michael,
try “www.solarstation.lima-city.de” it should work. Are you sure your Arduino gets the correct DNS server? Are you using a DHCP setup or a static one?
Hello Luca. I’m using DHCP and i think the Server IP Address is resolved correctly. Maybe the reason is the free Webspace of lima-city. That’s what the terminal says…
WebTemperature demo
Ethernet controller initialized
DHCP configuration done
Website IP resolved
IP Address: 192.168.2.139
Netmask: 255.255.255.0
Gateway: 192.___._._
Website IP: 212.83.45.137
Temperature 23.00 sent to website… OK
should i try it with a Static IP Address?
Hi Michael,
from the output it seems everything’s working now… doesn’t it?
Hello Luca. I have a project that looks similar with your tutorial here, but I’m using HC-SR04 distance sensor instead of the temperature sensor. I already programmed the sensor but I really have no idea how to send the data to the web just like your tutorial. Can you give me a more detailed step-by-step explanation? I will be very happy if you would like to see my sketch for the HC-SR04 and show me how to integrate it with the ethernet module so it can send the data to the web. Thank you very much
Prima di tutto un sincero ringraziamento per gli ottimi tutorial pubblicati, mi sono stati molto d’aiuto nella realizzazione di un piccolo sito web.
Stavolta ho difficoltà a gestire la variabile stash in particolare vorrei implementare 4 sonde termiche, ho modificato il programma ed ora ho tre variabili temp numerate da 1 a 4 che restituiscono il loro corretto valore, però non riesco a modificare l’oggetto stash in modo che la variabile “sd” contenga i valori di tutte e 4 le sonde, mi potresti aiutare?
ciao Antonio,
nella prepare() devi inserire per ogni valore un “segnalibro” con $H (qualcosa tipo saveTemp.php?temp1=$H&temp2=$H&temp3=$H…); quindi chiusa la stringa puoi inserire separate da virgola le varie variabili. Per riceverle e gestirle poi hai modificato di conseguenza lo script php?
Hello Luca!
I’m fiddling with something similar to your project.
I just have big problems with the GET function.
it is not quite the same as your but may be you can help me anyway.
Base: so I also collects data packs them into a string and then I send it to a server.
like this:
Serial.println(“connected”);
client.println(“GET /test_fil_1.php?name=string”);
client.println(“HOST:www.XXXXXXX.com”);
client.println();
in file test_fil_1.php is written
but it does not work.
in file test_fil_1.php is written
”
$temp = $_GET[“name”];
$filename = ‘temperatures.csv’;
define(“LOG_FILE”, “./temperatures.csv”);
$file_handler = fopen(LOG_FILE, “a+”);
fwrite($file_handler, time() . “,” . $temp . “\n”);
“
hey it does not matter. I’ve got it to work.
I do like this
” Serial.println(“connected”); // report successful connection
// Make a HTTP request:
client.println(“GET /test_fil.php?key=125 HTTP/1.1”);
client.println(“Host: http://www.moencamping.com“);
client.println(“Connection: close”);
client.println();
”
it is made for W5100 shield.
However, I would like to do something similar with ENC28J shield.
But I can not really get started in it.
I looked at several client examples to ENC28J, but it’s not really the same code.
I know it is a different chip and the setup is different but a GET request is probably a GET request. Right!
The only question is, where to put the GET rotine.
hope that you will help me
‘ve fixed it.
I use UIPEthernet library.
So it’s easy.
Luca,
ottimo lavoro!!!
Io sto provando a realizzare la stessa cosa (circa) però usando la libreria Ethernet.h (quella standard per capirci). Ora quello che non riesco a capire bene è la sintassi che devo usare nel comando con GET. Praticamente io eseguo una cosa del genere …
sprintf(buffer, “%s%s%s/%s/%d/%d/%d/%d/%d/%d/%d/%d/%d/%d/%d/%d/%d/%d/%d/%d %s”, “GET http://xxxx.org:84“/saveTemp.php?temp=15.2&pwd=password”, “HTTP/1.1”);
Serial.println(buffer);
client.println(buffer);
… ma senza risultato.
Cosa faccio come errore?
Ciao Massimo,
usi la sprintf() immagino per creare la URL da chiamare, con alcune parti “statiche” (http://xxx.org…) e alcune “dinamiche” (i valori dei sensori)… non capisco tutti quei %s%d…
Luca grazie innanzitutto!
E’ come avevo previsto a quanto scrivi. Ho provato a lanciare come dici tu ma senza risultato. Quei %s%d … sono riferiti alla formattazione della stringa. Ora ci lavoro e ti tengo aggiornato.
Grazie ancora
Extraordinary tutorials Luca! You are a great teacher and these are among the best tutorials I have ever read for microcontrollers! Thank you for sharing this…
Thanks Kafes 😉
hey if I need to send to a particular port, for example:
xxxxxxxx.yy: 8004
how do i do that
ciao, grazie per il blog davvero molto utile.
non riesco a far comunicare arduino (con ip fisso) con il server. Ambientmonitor, sempre con Arduino con ip fisso, funziona senza problem: saveTemp.php funziona se chiamato dal pc, mentre con Arduino continuo ad avere “No response”.
C’è modo di leggere l’url trasmesso da arduino?
Graxie
Ciao Marco,
puoi installare Wireshark sul tuo PC, con quello riesci a “sniffare” la chiamata di Arduino…
Ciao, grazie.
Praticamente Arduino non si collegava al router.
Ho risolto ricaricando l’ide, aggiornando le librerie e cambiando i MAC di un paio di Arduino.
Grazie ancora
Hello Luca, I want to get data from the Arduino and send it to a computer. But I need to create a .exe than be able to get the data and make alarms, graphics, etc. Do you know about some compiler to do this? I don’t want to program in PHP because isn’t necesary then I need to get the data from the IP address but without make a website or something like that.
Thanks for the tutorial.
Hi Pedro, I usually develop in C#, please see some examples on my blog.
Hello Luca,
great tutorials You have done here. I had a problem with DHCP, it was refusing to work. I have found solution that in the line:
static byte mymac[] = {0xDD,0xDD,0xDD,0x00,0x00,0x01}; i have changed with
static byte mymac[] = {0xDD, 0xDD, 0xDD, 0x00, 0x00, 0x01};
just by adding extra space after every comma sign.
I am new to Arduino, and willing to learn. Can you please help me to implement reading from more than one sensor and drawing in that jpgraph.
Thank you for sharing these great tutorial.
Ciao Luca, Im triyng implement my code to send the data (from 2 sensors) to send to web (localhost) via method GET, but im no lucking, so could you please help me to solve them?
on this link below are my code:
http://pastebin.com/tx54WcCC
Hello.
Is it possible to send readings from arduino to google spreadsheet using the enc28j60 ethernet shield ?
Ciao Luca, grazie per questi splendidi articoli mi sono stati molto utili per capire varie cose.
Ora però mi sono arenato in questo esempio e non riesco a cavarne piede…
Riesco a farmi passare i parametri dal dhcp. Pero al momento di risolvere l’indirizzo della pagina web mi da picche sempre il messaggio “unable to resolve website”.
[…]
Ciao Paolo… lo sketch sembra ok, sicuro che Arduino possa raggiungere il DNS server su Internet? Hai provato a cambiare sito web di destinazione? Non risolvi alcun indirizzo? E se provi direttamente mettendo l’IP?
Ciao.. dalle prove che ho fatto non riesco a risolvere nessun indirizzo, nella mia rete ci sono diverse mecchine, nas, smartphone e non ho mai avuto di questi problemi.
Ora che me lo dici provo a fare uno sketch per pingare da arduino verso interne e vediamo che succede…
Grazie per la risposta celere ti tengo aggiornato sugli sviluppi
rieccomi spulciando negli esempi a corredo della libreria c’e ne era uno per pingare un url sul web, ho compilato e il tutto ha funzionato… allora ho confrontato i due listati e l’unica differenza che ho trovato e questa
nel tuo codice.
if (!ether.dnsLookup(website)) {
Serial.print(“Unable to resolve Website IP”);
while(1);
} else Serial.println(“Website IP resolved”);
nell’ esempio:
#if 1
// use DNS to locate the IP address we want to ping
if (!ether.dnsLookup(PSTR(“google.it”)))
Serial.println(“DNS failed”);
#else
ether.parseIp(ether.hisip, “74.125.77.99”);
#endif
ether.printIp(“SRV: “, ether.hisip);
ho inserito con le dovute modifiche nel mio listato e ora sembra che l’indirizzo del sito venga risolto correttamente.
pero… il responso che ricevo e un bel Error 404.
ho ancora da lavorare… devo capire meglio come funge stash credo che li ci sia qualche cosa che non vada.
esiste il modo per inviarmi sulla seriale una copia della stringa che invia al server???
scusa per lo stress.
Grazie Luca per l’ottimo tutorial ! Al posto di Arduino+Ethernet shield, vorrei utilizzare l’ESP8266 sia per leggere il sensore di temperatura che per inviare i dati al server web. Potresti aiutarmi a modificare il codice dello sketch per adattarlo all’ESP8266 ?
Grazie !
ciao Gianluca, mi spiace ma non mi sono mai cimentato con l’ESP8266… penso ci siano ottimi tutorial in rete vista la sua diffusione!
Hey, excellent tutorial. I was wondering thoug if it is possible to remove the part with the password
Hi! Of course, if you don’t need a password, you can use one of my previous examples…
Ciao Luca, complimenti per le ottime guide e i progetti sempre molto interessanti, non mi è chiara una cosa che forse non è stata trattata, se volessi cancellare il file csv a mezzanotte per resettare il grafico, sarebbe meglio abbinare all’arduino un’rtc e inviare un dato aggiuntivo, oppure tramite uno script php che legge la data? grazie!
ciao Ivan, secondo me è più facile farlo lato PHP
Buongiorno Luca,
Ho scoperto solo la scorsa settimana il tuo sito e devo dire che è veramente una miniera di idee…
Sto cercando di modificare per le mie esigenze questo sketch ma non riesco a inviare più di una variabile sul sito, se invio gli stessi dati direttamente da browser il file generato da savetemp.php, nel mio caso log.csv si aggiorna correttamente.
la parte modificata è questa:
dtostrf(f_temp, 4, 2, data1);
dtostrf(iBat, 4, 2, data2);
dtostrf(iFp, 4, 2, data3);
dtostrf(vBat, 4, 2, data4);
dtostrf(vFp, 4, 2, data5);
dtostrf(pingAns, 4, 2, data6);
/* variabile “sd”
nella prepare() devi inserire per ogni valore un “segnalibro” con
$H (qualcosa tipo saveTemp.php?temp1=$H&temp2=$H&temp3=$H…);
quindi chiusa la stringa puoi inserire separate da virgola le varie variabili.
Per riceverle e gestirle poi hai modificato di conseguenza lo script php?
*/
Stash stash;
byte sd = stash.create();
stash.print(data1);
stash.print(data2);
// stash.print(data3);
// stash.print(data4);
// stash.print(data5);
stash.save();
// Stash::prepare(PSTR(“GET /StationMonitor/saveTemp.php?data1=$H&pwd=$F HTTP/1.0” “\r\n”
Stash::prepare(PSTR(“GET /StationMonitor/saveTemp.php?data1=$H&data2=$H&pwd=$F HTTP/1.0” “\r\n”
“Host: $F” “\r\n” “\r\n”),
sd, password, website);
session_id = ether.tcpSend();
Quello che vorrei riuscire a fare è inviare (adesso riesco a leggere i dati tramite la seriale di Arduino) sul sito un file txt con 6 valori (5 float e 1 byte) per monitorare in remoto batteria, tensione pannelli solari e con un ping il blocco delle webcam e raspberry connessi, una stazione meteo non presidiata e connessa in rete con una chiavetta.
In tutto questo sono un autodidatta e cercando in rete di solito ci cavo il classico ragno dal buco ma in questo caso ho trovato pochissimo, e quel poco utilizza il comando POST invece che GET.
Cosa sbaglio in quelle righe di codice? sono un paio di giorni che cerco la soluzione ma senza successo.
Grazie
Luca, I have the same problem as Igor in 2013, so i followed your advice and added in the declarations:
byte hisip[] = { 192,168,1,1 };
static byte website[] = {192,168,1,102};
in setup i added
ether.copyIp(website, hisip);
But sadly, same problem “no response”
Have I misunderstood your solution?
If i have the audacity to briefly use your ip domain, everything works and if i just manually URL/GET my server i get connection.
I know it is a very old totorial, but could you maybe give some more advice on how to resolve to a local IP?
with regard to my earlier question abt local ip…never mind, i think i solved it
sadly after my initial euforia thinking i solved my earlier problem I still have a problem with this project. I managed to connect to my local server and I get an OK response
However, my csv file does not get updated. It works without problem if i do a manual update.
I suspect that somehow i arrive at my local server, but at the wrong place: if i give a wrong pw, or even remove the entire saveTemp.php file, i still get an ‘OK’
My php file is located in /var/www/html and as said, manual update works.
I go to my local server with
static byte website[] = {192,168,1,102};
ether.copyIp(ether.hisip, website);
and ether.printIp(“hisip: “, ether.hisip); shows it is the right address, but sadly no update so somehow i arrive at the wrong place.
My stash is as follows:
Stash::prepare(PSTR(“GET /saveTemp.php?temp=$H&pwd=$F HTTP/1.0” “\r\n”
“Host: $F” “\r\n” “\r\n”),
sd, password, website);
session_id = ether.tcpSend();
Any idea what could be wrong