Ethernet shield comunicazione con pagina web

Ciao a tutti
ho iniziato da un pò ad utilizzare arduino (mega 2560) e con i primi esperimenti tutto bene, ho utilizzato anche processing per comunicare con arduino...

ora vorrei complicare un pò le cose e vorrei poter usare la scheda eth...

vorrei costruire una pagina web per poter accendere o spegnere un led collegato ad arduino (la cosa più semplice giusto per iniziare a capire il meccanismo)

vorrei imparare a caricare una pagina in un sd ed inserirla nella scheda ethernet di arduino..

Qualcuno conosce un tutorial in italiano?
C'è qualcuno che ha già provato qualcosa di simile e sarebbe così bravo da esporre l'operazione in un paio di punti passo passo?

Naturalmente ho già visto un pò di documentazione (in inglese ) però ho molta confusione in testa!!

Grazie mille in anticipo per l'aiuto!!!!

il mio consiglio è di fare un programma che faccia da "ponte" tra ethernet e pc via seriale. In pratica tutto ciò che arriva via ethernet lo rispedisci via seriale, e tutto ciò che arriva via seriale all'arduino lo rispedisci via ethernet.
a questo punto trovi l'ip del tuo arduino, apri il brower e nella barra dell'indirizzo scrivi ipArduino:porta (porta è la porta in cui hai messo in ascolto arduino).
vedrai che il browser invia dei dati ad arduino (che ti arriveranno via seriale).
a questo punto dovrai rispondere alla richiesta: per sapere come fare prendi la richiesta che ti è arrivata, apri telnet (se non sai cosè cerca con google), collegati ad un server e inviagli la richiesta. osserva la risposta.
cambia i dati che ti servono a tuo piacimento :slight_smile:
altre info: Hypertext Transfer Protocol - Wikipedia

se invece non sai cos'è un'ip, una porta ecc..: http://it.wikipedia.org/wiki/Transmission_Control_Protocol

Ciao, ti illustro un esempio pratico e semplice :

OBBIETTIVO: Accendere e spegnere 3 leds con arduino da browser internet
IN QUESTO CASO: Il codice che vedrai sul browser è già dentro arduino
INDIRIZZO INTERNET: il mio router dice che c'è qualcosa attaccato ad una porta ethernet che ha come indirizzo IP "192.168.0.151" e capisco che è il mio arduino quindi sul browser scriverò http://192.168.0.151
(nel tuo caso probabilmente nella pagina di gestione del router vedrai più di un indirizzo IP , magari 192.168.1.2 oppure 192.168.1.3 e così via, sta a te capire quel'è quello dell'arduino e di conseguenza cambi quello che c'è scritto nello sketch)
Altro metodo per intercettare l'IP ADDRESS dell'Ethernet shield (proposto ad un utente Fastweb ma sempre valido)

BrainBooster:
se sei su windows , esegui cmd
e scrivi:
Ipconfig /all
guarda dove dice "connessione alla rete locale LAN"
e così vedi indirizzo ip della scheda ethernet del pc e del gateway (indirizzi da evitate).
Poi, se per esempio l'indirizzo del gateway è 10.0.0.1 e la scheda ethernet del pc è 10.0.0.2 allora dovrai configurare l'ethernet shield in modo che sia sulla stessa sottorete ma che non collida con indirizzi già assegnati dal server dhcp, quindi potrai usare gli indirizzi che vanno da 10.0.0.3 in poi (10.0.0.4 , 10.0.0.5 ecc...)
Se solo per provare, tutto il resto (subnet ecc...) puoi lasciarlo così com'è (chiaramente se nello sketch è impostato anche un gateway, quello deve coincidere con quello che è impostato sulla scheda ethernet del pc, quindi sarà 10.0.0.1).

Inserisco un sketch di prova con idirizzo 192.168.0.151:

#include <SPI.h>
#include <Ethernet.h>
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
byte ip[] = { 192,168,0,151 };
Server server(80);
String query;

void setup()
{
  query = String("");
  Ethernet.begin(mac, ip);
  server.begin();
  pinMode(8,OUTPUT);
  pinMode(7,OUTPUT);
  pinMode(6,OUTPUT);
}
void loop()
{

  Client client = server.available();
  if (client) {
    while (client.connected()) {
	if (client.available()) {
	  char c = client.read();
	  query.concat(c);
	  if (c == '\n') {
	    client.println("HTTP/1.1 200 OK");
	    client.println("Content-Type: text/html");
	    client.println();
	    if (query.indexOf("accendi8") > 0) {
		digitalWrite(8,HIGH);
		client.print("Accendo
");
	    }
	    if (query.indexOf("spegni8") > 0) {
		digitalWrite(8,LOW);
		client.print("Spengo
");
	    }

           if (query.indexOf("accendi7") > 0) {
		digitalWrite(7,HIGH);
		client.print("Accendo
");
	    }
	    if (query.indexOf("spegni7") > 0) {
		digitalWrite(7,LOW);
		client.print("Spengo
");
	    }
           if (query.indexOf("accendi6") > 0) {
		digitalWrite(6,HIGH);
		client.print("Accendo
");
	    }
	    if (query.indexOf("spegni6") > 0) {
		digitalWrite(6,LOW);
		client.print("Spengo
");
	    }
	    client.print("<a href='/accendi8'>Accendi LED 8</a>
<a href='/spegni8'>Spegni LED 8</a>
");
            client.print("<a href='/accendi7'>Accendi LED 7</a>
<a href='/spegni7'>Spegni LED 7</a>
");
            client.print("<a href='/accendi6'>Accendi LED 6</a>
<a href='/spegni6'>Spegni LED 6</a>
");
	    client.print("<pre>");//DEBUG
	    client.print(query);// DEBUG
	    client.print("</pre>");//DEBUG
	    break;//fermo il ciclo
	  }
	}
    }
    delay(1);
    client.stop();
    query = String("");
  }
}

Ho collegato 3 led ad arduino, uno sul pin 6 uno sul pin 7 e l'ultimo sul pin 8

Se vado alla pagina http://192.168.0.151 vedrò le scritte

Accendi LED 8
Spegni LED 8
Accendi LED 7
Spegni LED 7
Accendi LED 6
Spegni LED 6

E cliccandoci sopra si accenderanno o spegneranno i led corrispondenti

Otterrai lo stesso risultato scrivendo nel browser: http://192.168.0.151?accendi6 o http://192.168.0.151?spegni6

(sono tutte cose che puoi leggere nello sketch)

Poi puoi sempre imparare a creare una pagina internet e inserire dei bottoni adeguati ecc...
e in quel caso il link dei bottoni saranno qualcosa tipo:
ACCENDI LED 6
SPEGNI LED 6

IN CONCLUSIONE:
Scopri l'indirizzo IP di Arduino collegato al router, carichi lo sketch in arduino, colleghi i led, apri internet e ti colleghi all'indirizzo IP di arduino

P.S
Ho il blog temporaneamente chiuso per ristrutturazione sennò ti linkavo il tutorial.

Ottima guida!!!
Ma per capire, se creassi delle pagine web con qualsiasi editor html tipo frontpage, tutto il contenuto devo salvarlo nella SD?

spillo84topp:
Ottima guida!!!
Ma per capire, se creassi delle pagine web con qualsiasi editor html tipo frontpage, tutto il contenuto devo salvarlo nella SD?

Anche si e anche no...
cioè se salvi su SD stai quindi usando Arduino come Server Web...
ma con tutte le imitazioni del caso (in termini di prestazioni)
oppure ti crei un serverino dedicato in casa collegato alla lan interna, o crei un server WAMP o LAMP sul computer che utlizzi o anche un hosting web (ma non mi pare il caso).

mi potete aiutare nel capire dove sbaglio ?

ho modificato il listato ... per un solo led.
ma quando lo spengo subito si riaccende.
Perche ? .

poi ho dovuto modificare gli IF da spegni e accendi ho dovuto mettere l'intera QUERY.

Why ?

Grazie.

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

int Led = 13;
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
byte ip[] = { 192,168,3,151 };
Server server(80);
String query;

void setup()
{
  query = String("");
  Ethernet.begin(mac, ip);
  server.begin();
  pinMode(Led,OUTPUT);
}

void loop()
{

  Client client = server.available();
  if (client) {
    while (client.connected()) {
	if (client.available()) {
	  char c = client.read();
	  query.concat(c);
	  if (c == '\n') {
	    client.println("HTTP/1.1 200 OK");
	    client.println("Content-Type: text/html");
	    client.println();
	    if (query.indexOf("GET /accendi HTTP/1.1") > 0) { // Modifica se no non si accendeva
		digitalWrite(Led,HIGH);
		client.print("Accendo
");
	    }
	    if (query.indexOf("GET /spegni HTTP/1.1") > 0) { // Modifica se no non si spegneva
		digitalWrite(Led,LOW);
		client.print("Spengo
");
	    }
	    client.print("<a href='/accendi'>Accendi LED</a>
<a href='/spegni'>Spegni LED</a>
");
            client.print("<pre>");//DEBUG
	    client.print(query);// DEBUG
	    client.print("</pre>");//DEBUG
	    break;//fermo il ciclo
	  }
	}
    }
    delay(1);
    client.stop();
    query = String("");
  }
}

Grazie mille per i suggerimenti e scusate se non ho potuto rispondere prima....cmq ho provato e sembra che la strada sia quella giusta...

magari KrashNet quando il tuo blog sarà accessibile mi piacerebbe vederlo.....
pubblica il link quando puoi..

Ciao a tutti

Naturalmente il topic rimane aperto a tutti quelli che vogliono aggiungere esempi......magari con l'utilizzo di un sd...

Buon divertimento

Mauro_Titan:
mi potete aiutare nel capire dove sbaglio ?

ho modificato il listato ... per un solo led.
ma quando lo spengo subito si riaccende.
Perche ? .

perchè tra un loop e l'alto NON azzeri query... :smiley:

Paolc:
magari KrashNet quando il tuo blog sarà accessibile mi piacerebbe vederlo.....
pubblica il link quando puoi..

Spero di trovare il tempo e pubblicae in settimana!

lesto:
perchè tra un loop e l'alto NON azzeri query... :smiley:

Errato .. viene azzerata a fine programma.
e cmq. ho ricontollato e ricontrollato e l'unica differena e'nella scelta del pin
e cosi' ho impostato il PIN 8 e funziona :slight_smile:
penso che il problema sia che i pin 10-11-12 vengano utilizzati per dialogare con Arduino.
ipotizzo .. ma devo cercare.

Ciao-

Anche io un paio di settimane fa smanettavo con queste cose..
Il codice scritto sopra va bene...
Ma sarebbe interessante anche fare in modo di conoscere lo stato del led (acceso o spento) anche quando si è a regime..

Questo codice potrebbe essere utile.

Avevo cercato di aggiungere altri comandi.. Funzionano, ma ho incontrato un po di problemi con la formattazione e non riuscivo a fare funzionare due led contemporaneamente... Riuscivo a fare accendere a turno uno alla volta..
Accendendo uno si spegneva automaticamente l'altro...
Io per ora non ho molto tempo
Se volete provare e riuscite a modificare l'interfaccia per fare funzionare tutto, non sarebbe male...

Buon divertimento :grin:

@Mauro_Titan
metti una serial.println all'interno degli if per le digitalWrite, giusto per capire se le accensioni/spegnimenti derivano dal loop o qualcosa di esterno.
sul'arduino con atmega 168/328p i pin digitali 9-10-11 sono PWM, quindi se usi analogWrite.. o magari sono usati dallo shield ethernet....

Ragazzi, ho moificato un po di codici seguendo il link che ho postato su e prendendo come spunto anche qualche dritta dei post precedenti..

Quello che ho ottenuto è qesto:

#include <String.h>
#include <SPI.h>
#include <Ethernet.h>
 
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; //physical mac address
byte ip[] = { 192, 168, 1, 10 }; // ip in lan
byte subnet[] = { 255, 255, 255, 0 }; //subnet mask
Server server(80); //server port

String readString; //string
boolean LED1ON = false; //LED1 status flag
boolean LED2ON = false; //LED2 status flag
boolean LED3ON = false; //LED3 status flag
 
void setup(){
Ethernet.begin(mac, ip, gateway, subnet);
pinMode(6, OUTPUT);
pinMode(7, OUTPUT);
pinMode(8, OUTPUT);
Serial.begin(9600);
}
 
void loop(){
Client client = server.available();
if (client) {
  boolean currentLineIsBlank = true;
  while (client.connected()) {
    if (client.available()) {
      char c = client.read();
        readString.concat(c);
      if (c == '\n' && currentLineIsBlank) {
         Serial.print(readString);
        if(readString.indexOf("L=1") > 0) {
          digitalWrite(6, HIGH); // set the LED on
          LED1ON = true;
          }else{
          //led has to be turned OFF
          digitalWrite(6, LOW); // set the LED OFF
          LED1ON = false;
        }
        if(readString.indexOf("L=2") > 0) {//lets check if LED should be lighted
          //led has to be turned ON
          digitalWrite(7, HIGH); // set the LED on
          LED2ON = true;
          }else{
          //led has to be turned OFF
          digitalWrite(7, LOW); // set the LED OFF
          LED2ON = false;
        }
        if(readString.indexOf("L=3") > 0) {//lets check if LED should be lighted
          //led has to be turned ON
          digitalWrite(8, HIGH); // set the LED on
          LED3ON = true;
          }else{
          //led has to be turned OFF
          digitalWrite(8, LOW); // set the LED OFF
          LED3ON = false;
        }
        // INIZIO DICHIARAZIONE PAGINA HTML
        client.println("HTTP/1.1 200 OK");
        client.println("Content-Type: text/html");
        client.println();
        client.print("<html><head><title>ARDUINO Controllo Led via WEB</title><meta http-equiv='Content-Type' content='text/html; charset=iso-8859-1' ></head><body>");
        //Primo led
        client.println("<hr />");
        client.println("<h1>LED1</h1>");
        client.println("
");
        //printing LED status
        client.print("<span>STATO LED: </span>");
 
          if (LED1ON) {
              client.println("<span style='color:green'>ON</span>");
            }
            else
            {
              client.println("<span style='color:grey'>OFF</span>");
          }
        client.print("<h2><a href='/?L=1'>ON</a> | <a href='/?L=01'>OFF</a></h2>");
        
        client.println("<hr />");
        
        //Secondo led
        client.println("<h1>LED2</h1>");
        client.println("
");
        //printing LED status
        client.print("<span>STATO LED: </span>");
 
          if (LED2ON) {
              client.println("<span style='color:green'>ON</span>");
            }
            else
            {
              client.println("<span style='color:grey'>OFF</span>");
          }
        client.print("<h2><a href='/?L=2'>ON</a> | <a href='/?L=02'>OFF</a></h2>");
        client.println("<hr />");
        
        //terzo led
         client.println("<h1>LED3</h1>");
        client.println("
");
        //printing LED status
        client.print("<span>STATO LED: </span>");
 
          if (LED3ON) {
              client.println("<span style='color:green'>ON</span>");
            }
            else
            {
              client.println("<span style='color:grey'>OFF</span>");
          }
        client.print("<h2><a href='/?L=3'>ON</a> | <a href='/?L=03'>OFF</a></h2>");
 
        client.println("</body></html>");
 
        //clearing string for next read
        readString="";
        //stopping client
        client.stop();
 
        } 
    } 
  } 
} 
}

L'interfaccia andrebbe anche bene.. Si riesce ad avere anche lo status di ogni led se ON oppure OFF...
L'unico problema che non riesco a risolvere in nessun modo è che non si possono accendere due led contemporaneamente.
L'accensione di uno implica lo spegnimento dell'altro.
Non riesco a risolvere.

Penso che sia un problema di qualche variabile condivisa o del booleano, ma non riesco ad inquadrarlo bene.

Avete qualchee suggerimento?

@dr4gone

L'unico problema che non riesco a risolvere in nessun modo è che non si possono accendere due led contemporaneamente.
L'accensione di uno implica lo spegnimento dell'altro.
Non riesco a risolvere.

Penso che sia un problema di qualche variabile condivisa o del booleano, ma non riesco ad inquadrarlo bene.

non c'entrano variabili condivise.
Sempicemente, tu verifichi che nella GET ci sia L=N (1, 2 o 3).

In tutti questi casi, se trovi una corrispondenza (L=1) accendi il led, altrimenti lo spegni.

if(readString.indexOf("L=1") > 0) {
          digitalWrite(6, HIGH); // set the LED on
          LED1ON = true;
}else{
          //led has to be turned OFF
          digitalWrite(6, LOW); // set the LED OFF
          LED1ON = false;
}

..mentre nel codice html che vai a generare scrivi:

client.print("

ON | OFF

");

cioè, prevedi (perlomeno, chi ha scritto il codice) che per spegnere il led si debba usare L=01

Quindi devi modificare il tuo codice in questo modo:

if(readString.indexOf("L=1") > 0) {
digitalWrite(6, HIGH); // set the LED on
LED1ON = true;
}
if(readString.indexOf("L=01") > 0) {
//led has to be turned OFF
digitalWrite(6, LOW); // set the LED OFF
LED1ON = false;
}

perchè possa funzionare nell'insieme.
Ricapitolando:
L=1 accende il led
L=01 spegne il led

Grazie. Sei un grande. Funziona tutto perfettamente. Karma +1 :grin:

Ma per fare qualcosa di più accattivante graficamente come si può fare? si deve sempre inglobare il codice della pagina (html, php o quello che è) e farlo stampare ad Arduino dallo sketch, o si può fare in modo di fare una grafica di base, in modo tale che lo sketch modifichi solo i dati essenziali,input/outpout e lo stato ?

Ciao

Ma per fare qualcosa di più accattivante graficamente come si può fare?

puoi:

  1. lavorare sull'attributo style dei tag html
  2. inserire nell'head una sezione dedicata al css (CSS Tutorial)
  3. inserire nell'head un riferimento ad un foglio di style, residente in un altro server;
  4. gestire tutte le chiamate ad Arduino da una pagina php / asp / pl etc etc, che risiede fisicamente su pc/server/altro, ma su cui pui lavorare con più margini.

La soluzione 1 è la meno elegante, ma la più veloce da implementare; ma non si ottengono miracoli.
La soluzione 2 non è male, ma se ti fai prendere la mano rischi di occupare tutto lo spazio disponibile nell'atmega solo per una questione estetica.
La soluzione 3 è interessante, anche perchè puoi cambiare l'interfaccia web senza toccare Arduino, ma lavorando sul file css esterno ad Arduino stesso.
La soluzione 4 a mio avviso è la più completa e scalabile, ma per progettini di questo livello, le 3 soluzioni sopra son più che sufficienti.

Grazie mille
Questo week end mi studio un po delle cose che hai proposto e vedo cosa riesco a tirarne fuori. :slight_smile:

Grazie dei suggerimenti!!!
Ho usato il metodo 3 che hai detto.. Cioè usare un server esterno per mettere gli stili css e le cose pesanti e far eseguire il codice html ad arduino... E' diventato tutto molto più utilizzabile.

Ora manca solo una cosa da capire. Come si può fare in modo di mettere un'autenticazione quando si cerca di accedere ad arduino.
Avevo visto che era stato fatto un codice adattato a un webduino, ma non riesco a trovare le librerie giuste e implementarle. Mi danno errore...

Avete qualche link dove repirire info? o qualche suggerimento?

io farei così: all'inizio arduino manda una pagina di autenticazione.
Se ha avito successo l'autenticazione si "inventa" un codice( quì torna utile la funzione rand() ), che viene inserito in un hidden input in ogni pagina (e quindi viene incluso nei parametri del GET).
Quindi arduino ogni richiesta controlla se è presente il codice e se è valido: se non lo è rimanda alla pagina di login, altrimenti esegue i comandi richiesti, e ovviamente alla pagina di risposta inserisce l'hidden input del codice.

[paranoia on]
Per una maggiore sicurezza puoi fare che arduino controlla non solo il codice, ma anche l'ip legato ad esso, e un time-out se il codice non viene usato per qualche tempo.
Per una sicurezza estrema puoi fare che la pagina di login abbia al suo interno uno script che faccia lo sha1 di pass+un numero random, e invii lo sha1 e il numero ad arduino. Anche arduino farà lo sha1 della pass in memoria+numero random: se i 2 sha1 corrispondono allora l'utente è autenticato.
Usa lo sha1 perchè ormai l'md5 è craccabile in pochi secondi.
[paranoia off]