NOTA BENE:
byte remoteServer[] = { 209,40,205,190 }; // IP del server pachube.com
non è più così ma:
byte remoteServer[] = { 173,203,98,29 }; // IP del server pachube.com
(grazie Weiss)
L'idea è quella di inviare la temperatura locale, misurata con il nostro sensore LM35, al server Pachube (http://www.pachube.com). Ciò avviene a intervalli regolari di tempo (1 min.) sfruttando come bridge di accesso alla rete il modulo Ethernet di Arduino, collegandolo al router ADSL domestico; questa soluzione evita, dunque, la necessità di avere un personal computer sempre acceso.
L'implementazione si basa sfruttando del codice prodotto da 'usman' (www.haque.co.uk), che ha reso disponibile gratuitamente degli sketch che consentono ad Arduino di dialogare con Pachube. Il lavoro di usman è di fatto riconosciuto da Pachube come l'insieme di API ufficiali per Arduino ( http://community.pachube.com/node/112 )
Gli sketch di usman sono due:
PACHUBE_FUNCTIONS.PDE
Contiene tutte le funzioni di accesso a Pachube, sia in get (lettura da Pachube di sensori remoti) che in put (scrittura su Pachube di sensori locali) . Sono state apportate alcune modifiche: la funzione pachube_in_out() accetta ora un parametro formale (tipo array di caratteri) che rappresenta il dato da inviare al server Pachube; cioè consente di migliorarne la modularità, in quanto tutto il lavoro di preparazione del dato da inviare viene fatto nello sketch chiamante, principale, non modificando dunque questo file di libreria. Inoltre, dalla versione 18 di Arduino, essendo disponibile anche la stampa dei numeri in virgola mobile è stata prevista questa possibilità nell'istruzione di lettura dei sensori remoti.
ETHERNET_FUNCTIONS.PDE
Contiene le funzioni necessaria per l'inizializzazione dello shield Ethernet di Arduino (versione ufficiale). A questo sketch, come il precedente, non va apportata alcuna modifica.
Il terzo sketch è quello principale, il main: PACHUBE_LM35.PDE
In quest'ultimo si rivede la funzione per la lettura della temperatura con un LM35, già usata nel precedente lavoro. Il dato letto dalla nostra funzione viene però scomposto nella parte intera e nella parte decimale e poi riunito (con il punto decimale di separazione) dalla funzione sprintf() in un'unica stringa; questo si rende necessario perché passando direttamente il valore, su Pachube questo non viene formattato correttamente. La stringa così generata viene passata a pachube_in_out().
Tutti e tre gli sketch devono trovarsi nella stessa directory.
La configurazione dei parametri relativi a Pachube viene affidata a etichette simboliche:
#define SHARE_FEED_ID 8276 #define REMOTE_FEED_ID 0 #define REMOTE_FEED_DATASTREAMS 0 #define PACHUBE_API_KEY "INSERIRE_QUI_LA_PROPRIA_API_KEY" #define UPDATE_INTERVAL 60000
L'etichetta SHARE_FEED_ID rappresenta l'ID che Pachube ha assegnato all'atto della creazione del nostro feed manuale. Nel caso in esame, lo sketch funziona solo in modalità di "sharing" (invia dati, non legge sensori remoti), quindi REMOTE_FEED_ID e REMOTE_FEED_DATASTREAMS vanno posti a 0.
Nell'etichetta PACHUBE_API_KEY va inserire la chiave API che troviamo nell'area utente.
Va inserita fra le doppie virgolette.
In ultimo, l'intervallo di aggiornamento: UPDATE_INTERVAL che si è impostato a 1min (60.000 ms).
Una seconda parte, riguarda i parametri per la connessione di rete del modulo Ethernet,
che sono invece memorizzati in delle variabili:
byte mac[] = { 0xCC, 0xAC, 0xBE, 0xEF, 0xFE, 0x91 }; byte ip[] = { 192, 168, 0, 10 }; byte gateway[] = { 192, 168, 0, 1 }; byte subnet[] = { 255, 255, 255, 0 }; byte remoteServer[] = { 173,203,98,29 };
mac[] e remoteServer[] non vanno modificati...il resto, dipende dalla configurazione del proprio router...
/* * Nome sketch: PACHUBE_LM35.PDE * (ETHERNET_FUNCTIONS.PDE, PACHUBE_FUNCTIONS.PDE) * Motivazione: Acquisisce una temperatura mediante un sensore LM35 collegato ad Arduino e, * tramite il modulo Ethernet dello stesso collegato a un router ADSL, * la invia su un server Pachube a intervalli regolari. * Data: 30-giu-2010 * Rev.: 1.1 * Autore: Francesco Parisi, fparisi [at] gmail [dot] com , fparisi [at] tiscali [dot] it * Ver. Arduino: 18 (o superiore) * * Note: Il presente sketch utilizza (e si basa) su sketch sviluppati da usman (www.haque.co.uk), maggio 2009 * copy, distribute, whatever, as you like: * http://community.pachube.com/node/112 * */ #include <Ethernet.h> #include <string.h> #include <stdio.h> // per la funzione sprintf //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* Configurazione connessione al server Pachube */ #define SHARE_FEED_ID 8276 // ID del feed locale Pachube (quello assegnato da Pachube) #define REMOTE_FEED_ID 0 // ID del feed remoto Pachube (impostare a 0 se non si usa nessun feed remoto) #define REMOTE_FEED_DATASTREAMS 0 // Numero di sensori remoti associati al feed remoto (impostare a 0 se non si usa nessun feed remoto) #define PACHUBE_API_KEY "INSERIRE_QUI_LA_PROPRIA_API_KEY" #define UPDATE_INTERVAL 60000 // Se la connessione è valida aspetta 10s prima di un nuovo aggiornamento - dovrebbe essere non inferiore a 5s #define RESET_INTERVAL 10000 // Se la connessione fallisce/si resetta aspetta 10s prima di riprovare - dovrebbe essere non inferiore a 5s float remoteSensor[REMOTE_FEED_DATASTREAMS]; // Se i dati sono diversi (es. interi) cambiare il tipo di ritorno //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* Configurazione hardware di Arduino */ #define LM35PIN 5 // Numero dell'ingresso analogico al quale e' collegato il sensore LM35 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* Configurazione di rete del modulo Ethernet */ byte mac[] = { 0xCC, 0xAC, 0xBE, 0xEF, 0xFE, 0x91 }; // assicurarsi che il MAC address sia unico sulla propria rete byte ip[] = { 192, 168, 0, 10 }; // dipende dalla configurazione del ns. router byte gateway[] = { 192, 168, 0, 1 }; // dipende dalla configurazione del ns. router byte subnet[] = { 255, 255, 255, 0 }; // dipende dalla configurazione del ns. router byte remoteServer[] = { 173, 203, 98, 29 }; // IP del server pachube.com //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* Funzione per leggere la temperatura rilevata dall'LM35 */ double readLM35Temp() { double temp = 0.0; // valore convertito in temperatura (°C) int val = 0; // valore quantizzato dall'ADC [0..1023] int nread = 20; // numero di letture double somma = 0.0; // somma delle singole letture for (int i=0; i<nread; i++) { val = analogRead( LM35PIN ); // legge il dato convertito della tensione sul pin LM35PIN temp = ( 100.0 * 1.1 * val ) / 1024.0; // Vref=1,1V (riferimento interno) somma += temp; // lo aggiunge alla somma delle temperature lette delay( 50 ); // aspetta 50ms } return ( somma / nread ); // restituisce la temperatura media } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void setup() { Serial.begin(57600); setupEthernet(); analogReference( INTERNAL ); // per l'ADC usiamo il Vref interno da 1,1V (migliore precisione) analogRead( LM35PIN ); // Prima lettura "a vuoto" (cfr. pag. 47 datashett ATmega168) } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void loop() { char data[20]; // Stringa dati da inviare a Pachube // Leggiamo la temperatura e assegnamone il risultato a 'temp' double temp = readLM35Temp(); // Estraiamo la parte intera della temperatura unsigned int int_part = (unsigned int)temp; // quindi estraiamo la parte decimale (con una cifra dopo la virgola) unsigned int frac_part = 10.0 * ( temp - (double)int_part ); // Creiamo la stringa concatenando le due parti sprintf( data, "%d.%d", int_part, frac_part ); // Chiamiamo la funzione di put/get verso/da Pachube pachube_in_out ( data ); } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Di seguito, i due sketch di usman:
PACHUBE_FUNCTIONS.PDE
/* * Nome sketch: PACHUBE_FUNCTIONS.PDE * Motivazione: Gestisce il put/get dei dati verso/da il server Pachube * attraverso un'unica funzione di put/get. I dati letti dai sensori * remoti vengono stampati su seriale. * Data: 30-giu-2010 * Rev.: 1.1 * Autore: usman (www.haque.co.uk), maggio 2009 * http://community.pachube.com/node/112 * Modificato da: Francesco Parisi (fparisi * gmail . com, giugno 2010) * + La funzione pachube_in_out() ha un parametro di ingresso * + La stampa dei dati dei sensori remoti avviene con due cifre dopo la virgola * Ver. Arduino: 18 (o superiore) * */ boolean found_status_200 = false; boolean found_session_id = false; boolean found_CSV = false; char *found; unsigned int successes = 0; unsigned int failures = 0; boolean ready_to_update = true; boolean reading_pachube = false; boolean request_pause = false; boolean found_content = false; int content_length; unsigned long last_connect; void pachube_in_out( char data[] ){ content_length = strlen( data ); if (millis() < last_connect) last_connect = millis(); if (request_pause){ if ((millis() - last_connect) > interval){ ready_to_update = true; reading_pachube = false; request_pause = false; found_status_200 = false; found_session_id = false; found_CSV = false; //Serial.print("Ready to connect: "); //Serial.println(millis()); } } if (ready_to_update){ Serial.println("Connecting..."); if (localClient.connect()) { Serial.println("GET request to retrieve"); localClient.print("GET /api/"); localClient.print(REMOTE_FEED_ID); localClient.print(".csv HTTP/1.1\nHost: pachube.com\nX-PachubeApiKey: "); localClient.print(PACHUBE_API_KEY); localClient.print("\nUser-Agent: Arduino (Pachube In Out v1.1)"); localClient.println("\n"); Serial.println("finished GET now PUT, to update"); localClient.print("PUT /api/"); localClient.print(SHARE_FEED_ID); localClient.print(".csv HTTP/1.1\nHost: pachube.com\nX-PachubeApiKey: "); localClient.print(PACHUBE_API_KEY); localClient.print("\nUser-Agent: Arduino (Pachube In Out v1.1)"); localClient.print("\nContent-Type: text/csv\nContent-Length: "); localClient.print(content_length); localClient.print("\nConnection: close\n\n"); localClient.print(data); localClient.print("\n"); Serial.println("\n--- updated: "); Serial.println(data); ready_to_update = false; reading_pachube = true; request_pause = false; interval = UPDATE_INTERVAL; // Serial.print("finished PUT: "); // Serial.println(millis()); } else { Serial.print("connection failed!"); Serial.print(++failures); found_status_200 = false; found_session_id = false; found_CSV = false; ready_to_update = false; reading_pachube = false; request_pause = true; last_connect = millis(); interval = RESET_INTERVAL; setupEthernet(); } } while (reading_pachube){ while (localClient.available()) { checkForResponse(); } if (!localClient.connected()) { disconnect_pachube(); } } } void disconnect_pachube(){ Serial.println("disconnecting.\n=====\n\n"); localClient.stop(); ready_to_update = false; reading_pachube = false; request_pause = true; last_connect = millis(); found_content = false; resetEthernetShield(); } void checkForResponse(){ char c = localClient.read(); //Serial.print(c); buff[pointer] = c; if (pointer < 64) pointer++; if (c == '\n') { found = strstr(buff, "200 OK"); if (found != 0){ found_status_200 = true; //Serial.println("Status 200"); } buff[pointer]=0; found_content = true; clean_buffer(); } if ((found_session_id) && (!found_CSV)){ found = strstr(buff, "HTTP/1.1"); if (found != 0){ char csvLine[strlen(buff)-9]; strncpy (csvLine,buff,strlen(buff)-9); //Serial.println("This is the retrieved CSV:"); //Serial.println("---"); //Serial.println(csvLine); //Serial.println("---"); // Serial.println("\n--- updated: "); // Serial.println(pachube_data); Serial.println("\n--- retrieved: "); char delims[] = ","; char *result = NULL; char * ptr; result = strtok_r( buff, delims, &ptr ); int counter = 0; while( result != NULL ) { remoteSensor[counter++] = atof(result); result = strtok_r( NULL, delims, &ptr ); } for (int i = 0; i < REMOTE_FEED_DATASTREAMS; i++){ Serial.print( remoteSensor[i], 2); // due cifre dopo la virgola Serial.print("\t"); } found_CSV = true; Serial.print("\nsuccessful updates="); Serial.println(++successes); } } if (found_status_200){ found = strstr(buff, "_id="); if (found != 0){ clean_buffer(); found_session_id = true; } } }
ETHERNET_FUNCTIONS.PDE
/* * Nome sketch: ETHERNET_FUNCTIONS.PDE * Motivazione: Gestisce la configurazione * e l'inizializzazione del dispositivo Ethernet * Data: 30-giu-2010 * Rev.: 1.1 * Autore: usman (www.haque.co.uk), maggio 2009 * http://community.pachube.com/node/112 * Ver. Arduino: 18 (o superiore) * */ Client localClient(remoteServer, 80); unsigned int interval; char buff[64]; int pointer = 0; void setupEthernet(){ resetEthernetShield(); Client remoteClient(255); delay(500); interval = UPDATE_INTERVAL; Serial.println("setup complete"); } void clean_buffer() { pointer = 0; memset(buff,0,sizeof(buff)); } void resetEthernetShield(){ Serial.println("reset ethernet"); Ethernet.begin(mac, ip); }
Grazie per l'esempio sicuramente d'aiuto per molte persone! L'unica cosa è cambiato l'IP del server di Pachube!!!!!
RispondiEliminabyte remoteServer[] = { 209,40,205,190 }; // IP del server pachube.com
non è più così ma:
byte remoteServer[] = { 173,203,98,29 }; // IP del server pachube.com
Un saluto ragazzi!!!!!!! :-)
grazie WEISS.
RispondiEliminaHo provato l' esempio ma non mi funziona mi segnala: connection failed!1reset ethernet
RispondiEliminaDurante la compilazione mi chiede di importare la libreria SPI.Uso l' ultima versione la 22.
Grazie.
Ho risolto il problema: alimentavo la scheda arduino con un alimentatore da 5V ora l' ho sostituito con uno da 9V e finalmente funziona.
RispondiEliminail regolatore usato su Arduino, il 78L05, ha un drop-out di 2V, quindi bisogna alimentare Arduino con almeno 7V; per andare sul sicuro, la tensione di alimentazione deve dunque essere di almeno 8..9V
RispondiElimina