Arduino ed Internet
Ci sono applicazioni per cui è comodo avere Arduino collegato ad internet, ad esempio per un sistema di domotica per gestire le luci di casa online, oppure per monitorare dei sensori ambientali dal cellulare.
Per questi piccoli progetti è adatta la Ethernet Shield, una scheda già pronta per essere "incastrata" su un Arduino e che mette a disposizione una porta Ethernet coordinata da un chip dedicato, ed uno slot per microSD, utile per esempio in progetti di monitoraggio per salvare le informazioni catturate. Esiste anche una wireless shield, molto simile, che però usa la rete senza fili.
Ma attenzione, questa scheda dipende molto dalla potenza del microprocessore di Arduino, poiché è lui che deve occuparsi, come vedremo, di tutti i protocolli di rete. Scordatevi quindi di poter tirare su in questo modo un server web con tante pagine, database, eccetera. In questo caso bisognerà optare per schede come [Raspberry Pi http://www.glgprograms.it/?p=tricks/raspberrypi-1] o BeagleBone, anziché Arduino.
Concetti di base
TCP/IP e protocolli
Tutti i dispositivi collegati in rete devono rispettare un certo protocollo, ovvero seguire regole per poter identificarsi fra loro senza creare conflitti.
Ogni dispositivo è in particolare identificato da un nome sulla
rete, detto indirizzo IP. Ad esempio, nella mia rete di casa
il computer che uso ha come indirizzo 192.168.142
, e il cellulare
192.168.1.119
.
Tutti gli indirizzi IP sono composti da una quartina di numeri compresi fra 0 e 255, separati da un punto. Solitamente, nelle reti di casa, la prima coppia è fissa a 192 e 168, mentre il terzo è solitamente 1. Quello a cui siamo interessati è quindi l'ultimo numero, che varia da dispositivo a dispositivo.
Fa eccezione 192.168.1.255
, che è un indirizzo speciale detto
broadcast che equivale a parlare contemporaneamente con tutti i
dispositivi connessi alla rete di casa.
Chi è che dà gli indirizzi nella rete casalinga?
Teoricamente ogni dispositivo può autoassegnarsi un indirizzo,
ma questo non viene fatto su oggetti "quotidiani" (cellulari,
computer, etc..) perché verrebbero a crearsi altrimenti conflitti
quando due o più si assegnano lo stesso indirizzo.
È quindi il router che ha l'autorità di dare ad ognuno il suo
indirizzo evitando i conflitti; si dice che il router "è il DHCP
(Dynamic Host Configuration Protocol)".
Il router sbriga tutta questa burocrazia, e cerca anche di associare ad uno stesso dispositivo lo stesso IP. Riesce a far ciò perché c'è una seconda informazione necessaria per "presentarsi sulla rete", il MAC address. Questo è un secondo codice, univoco, che viene assegnato in fabbrica ad ogni dispositivo.
Può sorgere la domanda "perché allora non si usa il MAC address per presentarsi in rete?". Senza perdersi in cose complicate, rispondo dicendo che sono due indirizzi che hanno un significato completamente diverso: l'indirizzo IP può variare a seconda delle reti, e inserisce il dispositivo in un "gruppo" di altri dispositivi connessi insieme (ricordi la parte fissa 192.168? Dice che tutti quelli che hanno questo indirizzo appartengono alla stessa rete casalinga). Il MAC è invece statico, tipico del dispositivo.
Per fare un paragone che renda chiaro il tutto, l'indirizzo IP è come fosse il soprannome di una persona, mentre il MAC address è il codice fiscale del dispositivo, che permette di "beccarlo" in qualsiasi gruppo.
Bene, detto questo, sappiamo che anche il nostro Arduino on the internet
dovrà avere una coppia di indirizzi IP e un MAC.
Il MAC è solitamente scritto su un adesivo sotto l'ethernet shield.
Per quanto riguarda l'IP, bisogna aggiungere qualcos'altro:
per i dispositivi che si collegano ad internet non ci interessa
che abbiano un IP particolare, e quindi lo possono anche chiedere
al router col meccanismo del DHCP: si dice che hanno un IP
dinamico.
I dispositivi a cui invece ci dobbiamo collegare dovrebbero avere sempre lo stesso IP, noto e indipendente dalle volontà del router: si dice che hanno un IP statico.
Anche il nostro Arduino dovrà avere un IP statico, che gli assegneremo nel programma. Prima però dovremo assicurarci di due cose:
- quale "serie" di IP è in uso nella propria rete casalinga;
- se l'IP scelto è disponibile, ovvero se il router non l'ha già assegnato a qualcuno;
Per il primo punto basta controllare a quale IP risponde il router: solitamente infatti ha ip 192.168.1.1 oppure 192.168.0.1. Basta quindi aprire un browser e digitare il primo e poi il secondo indirizzo. A noi interessa sapere se il terzo numero è 1 oppure 0.
Noto questo, basta tirare un numero a caso da aggiungere in coda
a 192.168.1.
per avere un IP, e verificare tramite un terminale
(o il prompt di DOS su windows) se è disponibile:
digita ping 192.168.1.245
e se nessuno risponde
il comando dovrebbe dare come output un errore come
Destination Unreachable
.
Appuntati quindi questo IP.
Servizi e Servitori
Quando ti colleghi ad un sito internet, chi ti dà la pagina non è una magica entità immateriale, bensì uno (o più) computer. Il questo caso il computer con cui ti colleghi al sito è un cliente (client), mentre il computer che risponde inviando la pagina è un server, ovvero offre un servizio.
Di servizi offribili sulla rete ve ne sono molti: oltre alla classica pagina web (gentilmente offerta dai server web), si possono avere servizi di trasferimento files (ftp oppure sftp), servizi di e-mail (POP3, IMAP, SMTP), e tanti altri. Uno stesso computer può offrire più servizi contemporaneamente, e per poter discriminare a chi mandare cosa, il protocollo TCP/IP prevede una struttura a porte.
Quando con un browser si richiede, ad esempio, una pagina web ad un computer, si
"bussa" alla porta numero 80 del suo indirizzo IP, e tramite quella
porta fluisce la compunicazione.
Ogni servizio ha una porta dedicata, in particolare il servizio
di trasferimento pagine web (HTTP) ha il numero 80.
Lo stesso dovrà succedere con il nostro Arduino: lo metteremo in grado di poter "rispondere" alle richieste fatte sulla porta 80.
HTTP & HTML
Ed eccoci quasi arrivati al termine. Dopo che il browser ha inviato la richiesta di connessione al server, incomincia uno scambio di informazioni fra i due, seguendo un protocollo molto rigoroso: l'HTTP (HyperText Transfer Protocol).
Il browser invia la richiesta della pagina web, seguita da una linea bianca per indicare il termine, e il server gli deve rispondere con un codice di approvazione o di errore (a seconda se la pagina è disponibile o no), specificare il formato della pagina (HTML nel nostro caso) e accodare finalmente il contenuto.
Vedremo queste cose direttamente nel codice Arduino, in particolare lo scambio di dati: attivando la trasmissione USB si vede in diretta tutta la comunicazione HTTP fra lui e il browser.
Il codice Arduino
Il codice altro non è che l'esempio EthernetServer di Arduino, leggermente modificato e commentato in italiano. In linea di massima questo programma resta in attesa di una richiesta HTTP, dopodiché legge il valore analogico del pin Analog0 e lo trasmette al client connesso. Per avere letture sensate bisognerà collegare un sensore analogico, che in questo esempio è stato simulato da un semplice potenziometro.
#include <SPI.h> #include <Ethernet.h> // Pin del sensore da monitorare via Ethernet const byte PIN_SENSORE = A0; // Qui va il MAC address della tua shield byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; // E qui l'indirizzo IP che dovrà essere associato IPAddress ip(192, 168, 1, 177); // Inizializza il "server" EthernetServer con la porta 80 (HTTP) EthernetServer server(80); void setup() { // Apre la comunicazione seriale: è utile per monitorare via USB // cosa sta succedendo Serial.begin(9600); // Avvia la connessione ethernet ed il server Ethernet.begin(mac, ip); server.begin(); // Messaggi di controllo inviati via USB Serial.print("Il server Arduino risponde all'indirizzo "); Serial.println(Ethernet.localIP()); } void loop() { // "ascolta" sulla porta 80 in attesa di un client EthernetClient client = server.available(); // se un client si è connesso... if (client) { Serial.println("Un nuovo client!"); // una richiesta HTTP termina con una linea bianca (un doppio a-capo) // serve quindi una variabile per ricordare se si è già ricevuto un a-capo boolean lineaCorrenteBianca = true; // Finché il client è connesso avviene lo scambio dei dati while (client.connected()) { if (client.available()) { // Leggo un byte trasmesso char c = client.read(); Serial.write(c); // se avevo già ricevuto un a-capo (lineaCorrenteBianca == true) // e ricevo un nuovo a-capo ('\n') è finita la richiesta del client // e posso inviare la pagina web if (c == '\n' && lineaCorrenteBianca) { // invio la risposta HTTP standard client.println("HTTP/1.1 200 OK"); client.println("Content-Type: text/html"); // Chiudo la connessione al termine della tramsissione client.println("Connection: close"); // Aggiorna la pagina ogni 5 secondi client.println("Refresh: 5"); client.println(); /* ****** Qui comincia la pagina HTML vera e propria ****** */ client.println("<!DOCTYPE HTML>"); client.println("<html>"); int lettura_sensore = analogRead(PIN_SENSORE); client.print("Il valore della lettura del pin "); client.print(PIN_SENSORE); client.print(" è "); client.print(lettura_sensore); client.println("</html>"); /* ****** Termine della pagina HTML ****** */ // break esce dal ciclo while, perché lo scambio dati è terminato break; } // Se ricevo un a-capo devo ricordare che ho iniziato una nuova riga if (c == '\n') { lineaCorrenteBianca = true; } // Se invece ricevo tutti gli altri caratteri, fatta eccezione per // '\r', significa che la richiesta del client non è ancora terminata else if (c != '\r') { lineaCorrenteBianca = false; } } } // piccola pausa per la trasmissione, dopodiché si chiude la connessione delay(1); client.stop(); Serial.println("client disconnesso!"); } }
Prossimamente vedremo come interagire via Ethernet con i componenti collegati alla scheda.
[Category::Howto]