enc28J60 e Arduino (6)

by luca
49 comments

Sketch

Lo sketch completo è disponibile nel repository GitHub di questo tutorial… nei paragrafi seguenti vi spiegherò le sue parti principali.

Workflow

Ho riassunto il funzionamento dello sketch in un diagramma di flusso:

Lo sketch è stato scritto come una semplice macchina a stati finiti (FSM) in cui sono definiti 4 stati:

  • all’avvio, il programma si trova nello stato di IDLE: trascorso un intervallo prefissato di secondi (costante CHECK_IP_INTERVAL) viene controllato l’IP pubblico attuale;
  • inviata la richiesta per ottenere l’IP pubblico, il programma attende la risposta nello stato di WAITING_FOR_PUBLIC_IP. Se la risposta non arriva entro un timeout (costante REQUEST_TIMEOUT) viene incrementato il contatore dei tentativi fatti e, se questo supera il massimo (costante MAX_ATTEMPTS), torna nello stato di IDLE;
  • se il programma ottiene risposta, confronta l’IP pubblico attuale con quello dell’alias DNS: se differiscono passa allo stato di NOIP_NEEDS_UPDATE, altrimenti torna allo stato di IDLE;
  • se è necessario aggiornare l’host su No-IP, il programma invia l’aggiornamento e attende la risposta nello stato di WAITING_FOR_NO_IP. Come per la richiesta di IP pubblico, se la richiesta di aggiornamento non viene esaudita entro un timeout il programma prova a reinviarla fino ad un massimo di tentativi oltre i quali torna nello stato di IDLE. Se invece ottiene risposta da No-IP, visualizza l’esito dell’aggiornamento e torna in IDLE.

IP Pubblico

Per ottenere l’IP pubblico, ho preparato una semplice pagina PHP sul mio sito:

Lo sketch ottiene tale pagina ed estrae l’indirizzo IP.

Alias DNS e confronto

Lo sketch utilizza il metodo dnsLookup() per ottenere l’IP attuale dell’alias DNS; converte poi il risultato in un oggetto String per usare il metodo compareTo() e confrontare i due indirizzi IP:

if(!ether.dnsLookup(noIP_host)) {
[...]
} else {
  for(int i = 0; i < 4; i++) {
    dnsIp = dnsIp + String(ether.hisip[i]);
    if(i < 3) dnsIp = dnsIp + ".";
  }
  if(actualIp.compareTo(dnsIp) == 0) {
    Serial.println("No update needed :)");
    [...]
  } else {
    Serial.println("Update needed :(");
    actual_status = STATUS_NOIP_NEEDS_UPDATE;

Autenticazione

Per poter aggiornare un host su No-IP, è necessario autenticarsi.

Nello sketch è definita una costante:

A tale costante dobbiamo assegnare come valore la codifica base64 della stringa username:password.

Possiamo usare un convertitore online:

Test

Per verificare il funzionamento dello sketch modifico l’alias DNS inserendo un IP errato:

quindi eseguo lo sketch:

Arduino ha correttamente rilevato la differenza tra i due IP ed ha aggiornato No-IP. Alla successiva esecuzione del controllo gli IP erano uguali e di conseguenza nessun aggiornamento è stato fatto.

Infine verifico che l’aggiornamento sia avvenuto:

Inserendo una autenticazione errata, lo sketch visualizza l’errore:

Related Posts

49 comments

Domenico 29 aprile 2012 - 13:35

Ciao Luca,

Durante la compilazione dello sketch, ho il seguente errore:
In function ‘void checkNoIPResponse()’:
_6_NoIPClient:187: error: ‘class EtherCard’ has no member named ‘tcpReply’.

Forse, ai aggiornato la libreria EtherCard ?

Saluti

Reply
luca 29 aprile 2012 - 13:44

Ciao Domenico,

ho utilizzato le nuove funzionalità introdotte nella libreria Ethercard circa un mese fa:
https://github.com/jcw/ethercard/commit/4cb278558a90f86bc2a1d17d301ee7f9d29d849e

scarica la nuova versione da Github, vedrai che la compilazione andrà a buon fine!

Reply
luca 29 aprile 2012 - 13:46

Hello!

Please update your Ethercard library: my sketch uses some new features they added in the last month: as usual you can follow the instructions I wrote in a previous post:
http://www.lucadentella.it/2012/02/12/enc28j60-e-arduino-1/

Reply
Domenico 29 aprile 2012 - 16:22

Ciao Luca,

Ora funziona.
Ma ho già un nuovo problema; quando inserisco la mia webpage, richiamandolo dal loop come subrutine, dopo i controlli effettuati da switch, semba che funzioni tutto ma dalla seriale, vedo che non riesce più a ricevere correttamente l’IP dopo aver fatto richiesta al tuo sito, vedo dei numeri strani (es. 3,75) e non effettuando la comparazione giusta, fa richiesta a no-op non andando a buon fine.
Il tutto torna normale, quando elimino dal loop il richiamo alla mia web page.

Sai darmi una dritta, ti ringrazio in anticipo.

Reply
luca 29 aprile 2012 - 22:29

Ciao Domenico,
purtroppo la libreria Ethercard non gestisce nativamente più connessioni… è quindi possibile che le due chiamate (quella per ottenere l’IP pubblico e quella per la tua webpage) in qualche modo si “sovrappongano”. Prova ad inserire il tuo codice (quello che immagino “risponde” ad una richiesta Web) nel metodo checkPublicIP() mettendo un else… in questo modo il tuo codice dovrebbe essere chiamato solo nello stato di IDLE. Mandami cmq il tuo codice via mail che ci do una occhiata!

Reply
Domenico 30 aprile 2012 - 17:14

Non riesco a trovare il tuo indirizzo e-mail.
Se vuoi, puoi inviarmelo al mio .

Saluti

Reply
Domenico 30 aprile 2012 - 17:45

Ciao Luca,

Anche con l’else in checkPublicIP(), fa la stessa cosa.
Secondo me è necessario aggiornare la pagina web solo quando ha finito il confronto con esito positivo.

Saluti

Reply
Domenico 3 maggio 2012 - 18:52

Ciao Luca,

Ora Funziona tutto.
Ti chiedo un’ultima gentilezza, ho provato ad impostare un ip statico, con scarsi risultati, i valori del gateway e del net mask, restano a 0,0,0,0 bloccandosi apparentemente il flusso del programma.

Saluti

Reply
luca 3 maggio 2012 - 20:11

Ciao Domenico! ottimo quindi le modifiche al tuo sketch erano veramente minimali, era già scritto bene!

Per impostare la netmask c’è un “trucco” visto che per ora non esiste un metodo nativo… vedi se quello che indico nel commento al primo articolo:
http://www.lucadentella.it/2012/02/12/enc28j60-e-arduino-1/
ti funziona…

Reply
Domenico 4 maggio 2012 - 19:25

Ciao Luca,

Sono riuscito ad impostare l’IP statico, è stato sufficente posticipare if (!ether.staticSetup(myip)) , dopo la il setup del DHCP.
Grazie a te, sono a buon punto, ma ti devo comunicare che avvolte, sempre alla prima accensione, la subnet mask e i gateway sono a zero bloccando il flusso del programma e quando il modem si riavvia ripetutamente, causa rete operatore, il programma sembra che si blocchi senza effettuare richieste per parecchio tempo (necessario reset hardware per ripartire), probabilmente dipende dai tempi di risposta del modem.
Secondo te se metto un goto nel setup che ripete il setup DHCP fino a che non va abuon fine, può essere una soluzione ?

Grazie di tutto.

Saluti

Reply
luca 4 maggio 2012 - 19:50

Ciao Domenico,

il setup via DHCP ha un timeout di 30 secondi, oltre il quale effettivamente rinuncia.

Se però utilizzi un setup statico, perché chiami anche il setup via DHCP? I due setup sono in alternativa: nel tuo caso semplicemente imposta tutto statico: l’IP e il gateway con staticSetup() e la subnet come ti dicevo nell’altro commento.

Reply
Domenico 7 maggio 2012 - 14:07

Ciao LUCA,

Ora funziona tutto, ho impostato tutto manualmente(IP, Mask e Gateway); terro il dispositivo collegato per un pò di tempo, per verificare l’affidabilità.

Grazie di tutto.
Saluti

Reply
Cesare 6 giugno 2012 - 09:00

Ciao Luca, vorrei sapere se ti è possibile fare una guida che spiega come collegarsi ad un feed rss e poi stamparlo su seriale.
Grazie
Cesare

Reply
luca 6 giugno 2012 - 11:34

Ciao Cesare,

è un ottimo spunto, vedo di approfondire e di dedicargli un prossimo articolo!

Reply
Cesare 7 giugno 2012 - 08:42

Grazie mille, non so se ti ricordi, sono quello dell’ rfid sul forum di arduino!
Comunque io sarei molto interessato al fatto dell’ rss perchè vorrei fare in modo che asrduino mi stampi i feed su una stampante termica del gameboy!

Reply
Cesare 17 giugno 2012 - 09:49

scusa se ti disturbo ancora, ma riusciresti a darmi lo schema della tua schedina, visto che in casa avrei già die enc28j60?

Reply
luca 18 giugno 2012 - 08:21

Ciao Cesare,

il produttore del mio shield non ha rilasciato lo schema, comunque fai riferimento a questo, è analogo:
http://www.nuelectronics.com/estore/index.php?main_page=project_eth

Reply
Domenico 11 luglio 2012 - 18:16

Ciao Luca,

Non ci si sente da un pò.
Volevo riferirti la mie esperienze con il tuo codice per la richiesta NO_IP.
Premetto che ho modificato il tuo codice iserendo come getIP_web “www.indirizzo-ip.com” modificando opportunamente la seguente linea di codice:
for(int i = 0; i < strlen(reply) – 182; i++) actualIp = actualIp + reply[181 + i] per filtrare solo la stringa dell'IP; ho eliminato la parete del web page, questo vuol dire che arduino si limita a verificare e a fare richiesta a no_ip, inoltre ho lasciato il DHCP automatico.
Funziona tutto alla grande con una Telecamera IP collegata al router. Avvolte nell'arco della giornata, (nel caso di oggi intoro alle 18,00 circa) non sono riuscito più a collegarmi dall'esterno. Visto che ero fuori ho pensato che il modem avesse uno dei soliti periodi che si disconnette, e per parecchio tempo non stabilisce la connessione. Invece rientrato in casa ho notato che il modem era regolarmente connesso, allora ho disalimentato arduino (senza disalimentare il modem) per qualche secondo e poi ha ripreso a funzionare regolarmete.
Secondo te è possibile che ci sia un baco software nel codice oppure perde il settaggio automatico del DHCP ?
Potrebbe essere una buona idea far riavviare arduino automaticamente quando si verificano questi eventi inprevisti ?

Grazie in anticipo.

Reply
luca 13 luglio 2012 - 19:25

Ciao Domenico! grazie per il feedback…
La configurazione via DHCP avviene solo nel setup(): finché lo sketch è in esecuzione, utilizza sempre l’IP assegnato.
Hai provato a vedere cosa Arduino stava inviando sulla seriale? Potrebbe esserci una condizione che lo manda in blocco (es. si aspetta una risposta che mai arriverà perché nel frattempo è caduta la connessione)… fammi sapere!

Reply
Antonio 26 luglio 2012 - 11:20

Ciao Luca, innanzitutto complimenti per la linearità utilizzata nello scrivere i tutorial che anche per uno come me, che è un “novello” con arduino, risultano comprensibilissimi.
Vorrei poter comandare gli ingressi/uscite della board tramite pagina web, ma non ho idea su come partire per fare il tutto.
Ho provato librerie alternative a questa, che non conoscevo (santo google), ma ottengo che o non parte proprio il webserver (rimane in clessidra il browser) come se fosse troppo il carico di info passate via web, utilizzo client.print() oppure se riesco a bilanciare la pagina sopo un po si blocca. Tralaltro se attivo la seriale è finita: non parte proprio il web server.. non è che mi puoi indirizzare (a livello di codice) come inizializzare l’accensione/spegnimento di una uscita? Poi proverei io a estendere a più ingressi/uscite. Ancora complimenti e grazie per quello che potrai fare.

Reply
luca 2 agosto 2012 - 08:47

Ciao Antonio e grazie per i complimenti!

Settimana prossima sarò in ferie e pubblicherò finalmente un tutorial su quanto chiedi (pagina web per attivare/disattivare uscite e leggere lo stato degli ingressi) quindi continua a seguire il blog 😉

Reply
carlo 6 agosto 2012 - 08:27

ciao Luca, complimenti per il sito e le guide (ottime).
ho un modulo eth con chipset enc28j60 (che conosci gia bene) non riesco a farlo andare assolutamente.
Vorrei innanzi tutto capire se il modulo funziona o è guasto.
L’unico script che mi da qualche speranza è “backSoon” perche il router lo rileva.
Poi sia come client, sia come server non ce modo di farlo andare assolutamente. Ho provato tutte le configurazioni possibili e inimmaginabili compresa quella del produttore. Ma niente.
Io lo uso in accoppiata con un Freeduino 1.16/atmega328pu

Reply
luca 10 agosto 2012 - 17:00

Ciao Carlo

se usi il mio primo sketch, che cosa ti appare sul serial monitor?

Reply
Francesco 10 ottobre 2012 - 12:28

Ciao, io volevo sapere se utilizzanto lil modulo ethernet con il Wiznet W5100 come chipset ci sono dei problemi, o funziona tutta allos tesso modo??
Grazie.

Reply
luca 10 ottobre 2012 - 12:52

Ciao Francesco,

no, il modulo Wiznet ha un funzionamento diverso. Visto che è il modulo scelto per l’ethernet shield “ufficiale” di Arduino, puoi usare le librerie messe a disposizione: http://www.arduino.cc/en/Reference/Ethernet

Reply
Francesco 10 ottobre 2012 - 16:39

Quindi a parte il cambio di librerie il codice resta uguale o mi tocca modificarlo??
Grazie.

Reply
luca 10 ottobre 2012 - 19:02

Ciao

mi dispiace ma devi completamente rifare il codice: il mio tutorial è specifico per lo shield con il chip enc28j60

Reply
dan 20 ottobre 2012 - 21:19

Hi Luca,

I studied your code and I really liked it a lot so I am using bits of it in my own sketch but now I’m stuck and I know no one who can help me so I thought maybe u can. I have a problem in a webclient after ether.tcpSend() Using your code I can get the response but … here comes the tricky part …if(strstr(reply, “rec=OK”) != 0)
{ Serial.println(“rec=OK”); } works but what i really want to do is something like this
if(strstr(reply,”svr_dig=”+3) == 0)
{
int rate = atoi(reply+9); //get the value for the dig pin
Serial.print(“svr_dig1=”);
Serial.println(rate);
} and now I’m stuck.

Please help with an ideea or guidance.

Thank you in advance.

Reply
luca 21 ottobre 2012 - 03:05

Hi Dan,

could you please explain what are you trying to implement? A webserver which gets queries from a browser about Arduino’s PINs and answers with pins’ statuses?
thanks

Reply
dan 21 ottobre 2012 - 10:47

Thank for fast response Luca,

I have a client which sends in a GET request pin status to a webserver (apache with php) and then apache responds with a page. The content of the response page is something like this {rec=OK&pck=123&svr_dig1=1&svr_dig2=1&svr_dig3=1&svr_dig4=1} . I need to parse this response and get the values of pck, svr_dig1, etc and implement the changes in arduino. I’m not really a programer so I find it difficult to understand where and how should I interpret this. Now with your code I can determine that the rec=OK is there but this is only a comparasion and with PWM this would not work really well since the code would be very large. Point me to the right direction please.

Grazie.

Reply
luca 26 ottobre 2012 - 08:22

Hi Dan

You can use the indexOf() method of the String object (http://arduino.cc/en/Reference/StringIndexOf) to find, in the received string, the position of ‘pck=’ string… then you can use the same method to find the next occurrence of ‘&’: your data (‘123’) is located between those two indices.
Here’s a tutorial explaining this method: http://arduino.cc/en/Tutorial/StringIndexOf

Let me know!

Reply
Yee Ho 8 novembre 2012 - 19:30

Thank you for the lesson, but i can’t update the no-ip, below is the output
Thank you

NoIP Client 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

Unable to resolve IP for http://www.lucadentella.itUnable to resolve IP for dynupdate.no-ip.com

Reply
luca 8 novembre 2012 - 20:12

Hi!

Are you using a DHCP server in your network? It seems Arduino can’t obtain an IP address… try with a static setup (like the first example in the tutorial)

Reply
sam 18 marzo 2013 - 19:56

check on the MAC address and also check on the CS pin u r using,,,,default CS pin of ethercard library is 8 but for some enc28j60 its 10.

Reply
ali 30 marzo 2013 - 16:47

Hi Luca;

we are able to control dc motor on local network with arduino but we would like to make it accessible on internet from everywhere.
we got no-ip host but we don’t know what to do as next step.
Could you please help us?
thanks

Reply
luca 1 aprile 2013 - 14:55

Hi Ali

you only need to configure your router to forward incoming connection on port 80 (I assume you’re implementing a web server on Arduino) to the internal IP of your Arduino…

Reply
Maurizio 3 aprile 2013 - 23:32

Ciao Luca,
ho scoperto il tuo tutorial e implementato (copiato pari pari) il tuo codice con le mie credenziali per aggiornare il mio account no-ip.
Tutto sembra funzionare a meraviglia però dopo circa 6 o 7 tentativi di aggiornamento andati a buon fine, lo sketch mi informa sul monitor seriale che non è possibile risolvere il mio ip esterno e tutto si blocca… Ho provato anche a sostituire il router ma succede la stessa cosa.
Non sono molto pratico di programmazione ma non credo voglia dire nulla il fatto che tu definisca lo sketch come ‘NoIp Client Demo’ vero?!
La variabile Max_Attempts centra qualcosa?
Grazie

Reply
luca 8 aprile 2013 - 20:03

Ciao Maurizio,

è strano… anche se si chiama “demo”, lo sketch non ha limiti o blocchi. Prova ad aumentare le due variabili:
REQUEST_TIMEOUT -> tempo di attesa per una risposta
MAX_ATTEMPTS -> numero massimo di tentativi prima di rinunciare

e fammi sapere come va…

Reply
Tonino 6 maggio 2013 - 12:08

Buongiorno, sarei interessato alla realizzazione fisica di questo progetto, in quanto avrei necessità di sopperire ad una mancanza del router presente in questa azienda.
Mi domandavo quanto costassero i vari componenti per realizzarlo, il solo shield ethernet l’ho trovato su ebay a 8 Euro ma il resto?
Grazie in anticipo e scusate la domanda da completo niubbo 😀

Reply
luca 7 maggio 2013 - 08:21

Buongiorno, se hai la necessità di qualcosa che gestisca un DynDNS, secondo me ti conviene o utilizzare un programma software installato su un vostro server, oppure acquistare un piccolo router tipo questo che tra le varie funzionalità ha anche quella che vi serve ad un costo molto limitato (20 euro).

Reply
Tonino 16 maggio 2013 - 17:44

Grazie per la risposta, ma purtroppo non posso sostituire il router in quanto quello della Telecom con voip e particolare.
La necessità di utilizzare l’arduino per fare questo lavoro è dettata dalla volontà di avere il pc spento ed accenderlo tramite wakeonlan tramite internet… ((magari un progetto che lo faccia dall’arduino?)).
Cmq per non divagare ho trovato su ebay come dicevo lo shield a 8 euro – ENC28J60 .
Inoltre penso che mi serva questo : Arduino Compatible Uno Rev 3.0 development board
sempre su Ebay.
Oltre ad un alimentatore, mi serve altro per programmarlo?

Reply
luca 19 maggio 2013 - 20:08

Ciao Tonino, il mio suggerimento non era di sostituire il router ma di utilizzare il TPLink come semplice dispositivo, connesso al tuo router o ad uno switch, per aggiornare il record DYNDNS. Comunque ti serve un Arduino e un alimentatore, la programmazione si fa via USB senza necessità di altro hardware dedicato.

Reply
Pawel 24 novembre 2013 - 22:21

Hi Luca! First – thank you for your great tutorials! Second – have you considered millis() overflow? After ~50 days millis start over from zero… So noip client won’t work correctly after 50 days. Do you have any solution to this?

Reply
luca 27 novembre 2013 - 14:30

Hi Pawel

you’re right… I’ve never considered that, not thinking my sketch could run without interruptions for 50+ days 😉
A simple solution is to check also if the current millis() is less than the previous one (this happens only in the overflow event) and, if so, consider the interval has passed.

Reply
drazen 5 ottobre 2014 - 21:18

Does your php script still working?
I m getting “Unable to resove IP for http://www.lucadantella.it” message.

Reply
luca 6 ottobre 2014 - 07:49

Hi! Sure it works but the site is lucadEntella.it, not lucadAntella.it 😉

Reply
Bob 26 agosto 2016 - 17:03

Hi Luca, great project, If i change ” http://www.lucadantella.it” to “https://api.ipify.org/”
What else i have to change ??/
Thanks in advance.
one more thing if i just want to get external ip ,what is smallest program i can make out of this ??
Thanks again

Reply
luca 14 settembre 2016 - 08:25

Hi Bob, you need a site that tells you your external ip address.. you can develop a php page by your own (like I did in the article) or use a public website

Reply
Bob 16 settembre 2016 - 16:40

Thanks for reply
Here is my project video
https://www.youtube.com/watch?v=2FPUSZuRJPU
I want to add External IP in it.
When i tried your code gives me error, missing 1st digit of IP like shows 92 instead of 192. Any clue??
Thanks

Reply

Leave a Comment

venti − undici =