Go Down

Topic: Greenhouse Project v 0.5 Final rev5 IDE 1.0 (Read 15324 times) previous topic - next topic

DanielaES

Dec 03, 2011, 04:27 pm Last Edit: Mar 25, 2012, 04:15 pm by DanielaES Reason: 1
Edit:
Ho terminato il mio progetto per il controller della serra.
Il progetto si basa su due arduino ed una ethshield. Gli arduino comunicano tra loro via seriale, dividendosi i compiti.

Ecco le specifiche.
Arduino che si occupa dei Sensori: MasterSen.
Quote
/*
Greenhouse Project - MasterSen v 0.5 Final rev5 IDE 1.0
 
FREERAM: 952
Binary sketch size: 22526 bytes (of a 32256 byte maximum).

SPECIFICHE.
Monitoraggio temperatura ed umidità, interne ed esterne, con due sensori DHT22.
Monitoraggio intensità luminosa con sensore TSL235R su D5.
Monitoraggio temperatura riscaldatore e acqua di irrigazione con due sensori DS18S20.
Termostato settabile tramite menu ad LCD e via web.
Invio e ricezione dati from/to SlaveWeb tramite softeasytransfer.
Invio dati a SlaveWeb ogni 55secondi - 60 reali.*
Dati inviati a SlaveWeb:
UnixTime, Anno, Mese, Giorno, Ora, Minuti, Secondi, t_out DHT, rh_out DH, t_in DHT, rh_in DHT,
th20, thot, mediaHz, statusSSR, tSSRMin, tSSRMax, resetMasterSen, flagSyncNTP
Dati ricevuti da SlaveWeb:
secsSince1900, tminviaweb, tmaxviaweb

IMPLEMENTATO SEND SOFTEASYTRANSFER.
I pin di TXeRX andrebbero invertiti, in questo caso è stato invertito il codice.
E' quindi sufficiente collegare MasterSen e SlaveWeb rispettivamente:
PIN A3 con PIN A3
PIN A2 con PIN A2

TERMOSTATO.
Relé SSR su pin D8
Le temperature di SetPoint sono salvate in EEPROM.
Nel caso gli indirizzi EEPROM fossero vergini, i setpoits vengono inizializzati con le temperature di
default ( tmin 16C° e tmax 18C° ).
Controlli di sicurezza implementati. Cfr CONTROLLI DI SICUREZZA.

CONTROLLO TEMPERATURA TERMOSTATO VIA WEB PAGE.
Ricezione via seriale dei SetPoints per il termostato: tSSRMin e tSSRMax.
Display ad LCD dell'avvenuta ricezione: display Old Value e New Value.
Aggiornamento dei valori ricevuti, confronto ed eventuale salvataggio in EEPROM.

CONTROLLO TEMPERATURA TERMOSTATO CON BOTTONI.
Menù per il controllo indipedente della temperatura di accensione e di spegnimento del termostato.
Uscita dal menu con goto outmenu: pressione di entrambi i tasti contemporaneamente.
Uscita automatica dal menu dopo 60 secondi di inattività.
UpPin D9 - DownPin D10

SOFTWARE DEBOUNCE.
PIN D9 E D10

LCD 2 WIRES CON SHIFREGISTER 74LS164.
DATAPIN D6 - CLKPIN D7 - Libreria aggiornata IDE 1.0 compatibile.
Aggiunto carattere speciale per il grado centigrado °
Aggiunti caratteri per animazione orologio alla ricezione della sincronizzazione NTP.

SENDLOG.
Invio dei valori dei sensori e dello status generale a SlaveWeb ogni 60 secondi circa.
Contatore per il log basato sul numero di loops.
#define cicliSendLog 15    // cicli per il SendLog
Lag di trasferimento compensati al fine di avere su SlaveWeb una ricezione ogni 60secondi,
scarto < 10ms.

SINCRONIZZAZIONE NTP.
Ricezione da SlaveWeb di secsSince1900ES, via NTP server.
Se il micro è appena stato resettato o se sono passate 24 ore dall'ultimo sync,
funzione di sincronizzazione RTC hardware con server NTP INRIM.
Compensazione fuso orario italiano.
Compensazione ora legale e solare.
Compensazione lag di sincronizzazione in secondi.
Invio flag di avvenuta sincronizzazione NTP a SlaveWeb per SD log.
Se non sono passate 24 ore dall'ultima sincronizzazione display ad LCD in posizione 2,0 di animazione
orologio con lancette.

WATCHDOG.
Watchdog 8 secondi.
Reset del micro se sono passati DUE giorni, stabiliti con #define cicloresetwdt 2
Condizioni per il reset: ciclo di SendLog concluso ed orario tra mezzanotte e l'una di notte.
Aggiunto reset flag e disposto invio seriale a SlaveWeb per SD log e Pachube send.

CONTROLLI DI SICUREZZA.
Controllo di sicurezza sulla temperatura interna: se troppo alta spegnimento relé.
Impostazione con #define temperaturadisicurezza 28
Inserito spegnimento di sicurezza del relè in caso di fail del sensore.

OTTIMIZZAZIONI.
Codice per calcolare la media delle luminosità all'interno del periodo di log.
Inserita compensazione errore media frequenza luminosa: quando c'è un reset le prime due letture
spurie vengono ignorate nel calcolo della media da inviare a SlaveWeb.

NOTE*.
Lo script viene eseguito con un loop di circa 4 secondi, delay incluso.
Questa versione richiede bootloader UNO.

CREDITS.
ladyada, Rob Tillaart, Bernardo Giovanni, Martin Nawrath KHM LAB3, arduino forum.

*/


Arduino che si occupa del web server, web client e dell'SD log: SlaveWeb.
Quote
/*
Greenhouse Project - SlaveWeb v 0.5 Final rev5 IDE 1.0
 
FREERAM AVVIO: 360
FREERAM LOOP : 316
Binary sketch size: 31452 bytes (of a 32256 byte maximum)
 
IMPLEMENTATO SEND SOFTEASYTRANSFER.
I pin di TXeRX andrebbero invertiti, in questo caso è stato invertito il codice.
E' quindi sufficiente collegare MasterSen e SlaveWeb rispettivamente:
PIN A3 con PIN A3
PIN A2 con PIN A2

SD.LOGGING.
SD log cartella root formato mensile: DBannomese.CSV
SD card at SPI_FULL_SPEED
Log su SD ogni 6 recezioni dati - 6 minuti. Scarto tra due cicli SD LOG < 50ms.
Creazione del file di log ed aggiunta dell'header se file non presente.
Media lumimosa all'interno del periodo di log.
Log dello status della connessione internet, se connessione assente viene loggato "NC".
Se la connessione è presente viene loggata la stringa di risposta di Pachube.
Log dei setpoints termostato, ricevuti via seriale da MasterSen.
Log dei reset effettuati da MasterSen e SlaveWeb con somma dei flags reset MasterSen nel ciclo di log e azzeramento dopo SD log.
Log dell'avvenuta sincronizzazione NTP di MasterSen, flag ricevuto via seriale.
Dati loggati:
millis, date, t_out, rh_out, t_in, rh_in, t_h2o, t_heat, hz, ssr, tSSRMin, tSSRMax, rstMS, rstSW, SyncNTPMS, pachubeRsp

WEBSERVER.
Implementato webserver su porta 84.
Indirizzo: 192.168.0.9:84
Display a web dei valori dei sensori ricevuti via seriale da MasterSen.
Display a web status riscaldatore ON/OFF
Display a web dei setpoints del riscaldatore.
Display a web dello status connessione del webclient.
Display a web della stringa di risposta di pachube, solo se la connessione del webclient è andata buon fine.
Display a web data ed orario e dei minuti since last reset.
Invio dei SetPoints per il termostato tramite GET.
Trasferimento via seriale dei SetPoints a MasterSen per l'aggiornamento dei parametri.
Conferma dell'invio dei SetPoints con diplay all'interno della pagina principale via <iframe>.
Autorefresh page ogni 60 secondi.
Autoformattazione pagina per visualizzazione su iPhone.
Stringhe html in PROGMEM con F() per risparmiare RAM.
Organizzazione pagina html con <br> e <hr>

WEBCLIENT.
Invio dei dati dei sensori ed altre variabili a Pachube.
Implementate funzioni per il calcolo del content-lenght della parte variabile.
Implementato upload datastreams ad api.pachube.com
Signola PUT ogni ricezione dati seriale ( ogni minuto ).
Implementata risoluzione DNS con open dns: 208.67.222.222
Feed: xxxxxxxxxxxxxxxx.csv
ApiKey: xxxxxxxxxxxxxxxx
Datastreams:  t_out, rh_out, t_in, rh_in, t_h2o, t_heat, hz, ssr, rstMS, tSSRMin, tSSRMax,

NTP CLIENT.
Aggiunto NTP client con avvio nel setup.
Server NTP italiano: ntp1.inrim.it (193.204.114.232) con risoluzione DNS. http://www.inrim.it/ntp/index_i.shtml
Invio dei secondi since 1900 a MasterSen per la sincronizzazione RTC.
Ricezione da MasterSen della notifica di sincronizzazione (sync ogni 24 ore o dopo ogni reset).
Log della notifica di sincronizzazione NTP su SD.

WATCHDOG.
Funzione esterna di inizializzazione della EtherneShield, richiamata dove serve.
La Ethernet Shield viene reinizializzata ogni ciclo di log ( 6 cicli di ricezione dati ).
Il micro viene riavviato ogni 60 minuti.
Spostato reset del micro a fine loop, fuori dalla funzione di ricezione dati seriali.
Per non intralciare il ciclo log, il reset del micro si verifica se sono passati 60min
ed il ciclo di log è terminato.
 
NOTE.
Questa versione richiede bootloader UNO.

CREDITS.
ladyada, Rob Tillaart, Bernardo Giovanni, Martin Nawrath KHM LAB3, arduino forum.

*/


In allegato trovate:

  • Gli sketch per MasterSen e SlaveWeb.

  • Due grafici del funzionamento del controller, con un log di prova dei sensori ed il log degli eventi di status.

  • Uno zip contenente gli eagle (brd e sch) per la shield dei sensori e il button pad. Inoltre ho allegato due librerie. Considerato che le nuove versioni di queste librerie stanno aumentando in dimensioni, aggiornare con le versioni recenti potrebbe non compilare per mancanza di spazio.



Un ringraziamento enorme a tutto il forum :)

leo72

Premetto che di Ethernet shield non ne so nulla (mai usata), ti dico solo che per il filename dovrebbe andar bene il secondo approccio, ossia integrare la path nell'array del nome perché "log/filename" non va bene come nome, indica ad Arduino di fare una divisione  ;)

Riguardo al formato, il CVS è universalmente caricabile da qualunque foglio elettronico tipo Impress di Open/Libre-Office.

Ricordati che il filesystem FAT ha un limite sul numero di file gestibili. Forse ti converrebbe quindi creare file il cui nome riprenda il mese/anno e poi riversarci dentro le letture.
Ad esempio il file 201112 conterrà le letture di dicembre 2011 mentre il file 201201 le letture di gennaio 2012 ecc...

uwefed

Il FAT limita il numero dei file della direttori principale perché riserva solo un certo numero di blocchi per la direttory. Quel numero dipende dalla grandezza del volume. Nelle sottocartelle il numero di file é limitato solo dal spazio della memoria del volume perché vengono aggiunte a necessitá altri blocchi per usarli come FAT.
Daniela, io non vedo la foto; o meglio dire vedo una foto nera.
Ciao Uwe

DanielaES

#3
Dec 03, 2011, 05:05 pm Last Edit: Dec 03, 2011, 05:08 pm by DanielaES Reason: 1

Daniela, io non vedo la foto; o meglio dire vedo una foto nera.


Strano :\ è su tinypic, provo imagehost ed aggiorno, al di la di tutto è bello avere una visione concreta dei progetti che crescono :)
edit: sono andata di allegato, tanto posto solo quella, almeno rimane a prescindere :)

MauroTec

Io non posso darti aiuto, per mancanza di conoscenza la http. Però posso dirti che quella foto mi piace tanto, mi da la senzazione di ordine e pulizia.
Json lo incontrato in javascript, gli ho dato uno sguardo, non mi tornava utile e non ho approfondito.

Però posso dirti che quella foto mi piace tanto, mi da la senzazione di ordine e pulizia.
+1

PS: questo è uno dei casi in cui una sezione "progetti e idee" potrebbe tornare utile. Almeno so dove cercare il post di Daniela quando mi servirà o solo per vedere come procede.

Ciao.
AvrDudeQui front end per avrdude https://gitorious.org/avrdudequi/pages/Home

DanielaES

#5
Dec 04, 2011, 02:48 pm Last Edit: Dec 04, 2011, 03:56 pm by DanielaES Reason: 1
Ok.
Ho un bel problema con il datalogging, vediamo se potete aiutarmi.
Obiettivo: creare il file di log, nella sottocartella Log che si trova già nel root della SD

Setup:
Code: [Select]
void setup() {
 Serial.begin(115200);
 Serial.println("Greenhouse test! v 0.3");
 lcd.begin(20, 4); // set up the LCD's number of columns and rows:
 Wire.begin();
 RTC.begin();
 dht_in.begin();
 dht_out.begin();

 if (! RTC.isrunning()) {
   Serial.println("RTC is NOT running!");
 }

 Serial.print("Initializing SD card...");
 // On the Ethernet Shield, CS is pin 4. It's set as an output by default.
 // Note that even if it's not used as the CS pin, the hardware SS pin
 // (10 on most Arduino boards, 53 on the Mega) must be left as an output
 // or the SD library functions will not work.
 pinMode(10, OUTPUT);

 if (!SD.begin(4)) {
   Serial.println("initialization failed!");
   return;
 }
 Serial.println("initialization done.");

}


fx per la creazione del file
Code: [Select]
// funzione creazione timestamp file di log
void getFilename(char *filename) {
 DateTime now = RTC.now();
 int year = now.year();
 int month = now.month();
 int day = now.day();
 filename[0] = 'L';
 filename[1] = 'o';
 filename[2] = 'g';
 filename[3] = '/';
 filename[4] = '2';
 filename[5] = '0';
 filename[6] = year%10 + '0';
 filename[7] = year%10 + '0';
 filename[8] = month/10 + '0';
 filename[9] = month%10 + '0';
 filename[10] = day/10 + '0';
 filename[11] = day%10 + '0';
 filename[12] = '.';
 filename[13] = 'c';
 filename[14] = 's';
 filename[15] = 'v';
 return;
}



loop (controlla se il file esiste, se non c'è lo crea, se c'è già va avanti tranquillamente e mostra i dati dei sensori sullo schermo)

Code: [Select]
void loop () {

 // Verifica presenza file di log formattato in TimeStamp:
 char filename[] = "Log/00000000.csv";
 getFilename(filename);
 if (SD.exists(filename)) {
   Serial.print(filename);
   Serial.println(" esiste.");
 }
 else {
   Serial.println("File di Log non presente.");
   lcd.clear ();
   lcd.setCursor(0, 0);
   lcd.print("FileLog Missing.");
   // Se il file di log non esiste viene creato:
   Serial.println("Creazione File di Log...");
   lcd.setCursor(0, 1);
   lcd.print("Building FileLog...");
   myFile = SD.open(filename, FILE_WRITE);
   // Scrittura dell'Header del file di Log e successiva chiusura:
   myFile.println("millis, date, t_out, rh_out, t_in, rh_in, t_h20, t_heat, hz, heat");
   myFile.close();
   delay(1000);
   lcd.clear ();
 }


Ora, il problema è questo.
Se nella cartella Log non c'è nulla, il file viene correttamente creato. Ma poi il loop sembra bloccarsi, perché non compaiono i valori dei sensori ecc.
Se il file nella cartella è già presente... non succede assolutamente nulla, lo schermo rimane vuoto e da seriale appaiono solo i messaggi di debug del setup!
"Initializing SD card..."
"initialization done."

La cosa strana è che se riporto il codice alla ver precedente (creazione file in root):
Code: [Select]
// funzione creazione timestamp file di log
void getFilename(char *filename) {
 DateTime now = RTC.now();
 int year = now.year();
 int month = now.month();
 int day = now.day();
 filename[0] = '2';
 filename[1] = '0';
 filename[2] = year%10 + '0';
 filename[3] = year%10 + '0';
 filename[4] = month/10 + '0';
 filename[5] = month%10 + '0';
 filename[6] = day/10 + '0';
 filename[7] = day%10 + '0';
 filename[8] = '.';
 filename[9] = 'c';
 filename[10] = 's';
 filename[11] = 'v';
 return;
}

void loop () {

 // Verifica presenza file di log formattato in TimeStamp:
 char filename[] = "00000000.csv";
 getFilename(filename);
 if (SD.exists(filename)) {
   Serial.print(filename);
   Serial.println(" esiste.");
 }
 else {
   Serial.println("File di Log non presente.");
   lcd.clear ();
   lcd.setCursor(0, 0);
   lcd.print("FileLog Missing.");
   // Se il file di log non esiste viene creato:
   Serial.println("Creazione File di Log...");
   lcd.setCursor(0, 1);
   lcd.print("Building FileLog...");
   myFile = SD.open(filename, FILE_WRITE);
   // Scrittura dell'Header del file di Log e successiva chiusura:
   myFile.println("millis, date, t_out, rh_out, t_in, rh_in, t_h20, t_heat, hz, heat");
   myFile.close();
   delay(1000);
   lcd.clear ();
 }

tutto funziona alla perfezione!
ci deve essere qualcosa che mi sfugge!
Perché lo crea correttamente ma poi (e da li in avanti) sembra impallarsi?

leo72

Intanto la logica è errata:

Code: [Select]
if (! SD.exists(filename)) { // il "!" dice NOT
    Serial.print(filename);
    Serial.println(" esiste.");
  }
  else {
    Serial.println("File di Log non presente.");


L'if è diverso rispetto a prima, difatti nella versione ultima non metti "!".
Tu dici:
Code: [Select]
se (NON esiste (filename) {
Serial.print("esiste")
}

Non può funzionare.

DanielaES

#7
Dec 04, 2011, 03:54 pm Last Edit: Dec 04, 2011, 04:05 pm by DanielaES Reason: 1
Errore mio, nel senso di refuso da una prova che avevo fatto :)
Il codice, che ancora non funziona, è:
Code: [Select]

// Verifica presenza file di log formattato in TimeStamp:
 char filename[] = "LOG/00000000.csv";
 getFilename(filename);
 if (SD.exists(filename)) {
   Serial.print(filename);
   Serial.println(" esiste.");
 }


edit: vado a correggerlo nel post prima
BTW

Mentre aspetto gli esperti, faccio prove ed ottengo risultati strani...
con
Code: [Select]
  char filename[] = "/LOG/00000000.csv";
ovvero la / anche davanti a log ottengo che:
il file viene creato ed i dati vengono loggati fino alla fine del primo loop. Ed addirittura compaiono i valori sul display.
Il loop ricomincia, il file ad sd.exist da falso... quindi viene ricreato (in realtà riaperto) e viene aggiunta di nuovo la riga dell'header.
E così via.
Sorprendentemente da seriale non appare nulla, anche se crea il file, rimaniamo cmq fermi a "inizialization done"

E' come se:
Code: [Select]
if (SD.exists(filename)) {
    Serial.print(filename);
    Serial.println(" esiste.");
  }


restituisse valori alla cavolo.

Questo il file di log creato nella sottdir log
Quote
1323011872, 2011/12/4 15:17:52, 24.70, 49.90, 24.10, 51.20, 24.62, 24.37, 0, 0
millis, date, t_out, rh_out, t_in, rh_in, t_h20, t_heat, hz, heat
1323011880, 2011/12/4 15:18:0, 24.60, 49.70, 24.10, 51.30, 24.56, 24.31, 65609, 0
millis, date, t_out, rh_out, t_in, rh_in, t_h20, t_heat, hz, heat
1323011888, 2011/12/4 15:18:8, 24.60, 49.80, 24.20, 51.30, 24.56, 24.31, 74, 0
millis, date, t_out, rh_out, t_in, rh_in, t_h20, t_heat, hz, heat

leo72

E riducendo il nome ad un max di 8.3 caratteri?
LOG/0000.TXT


DanielaES

#9
Dec 04, 2011, 04:17 pm Last Edit: Dec 04, 2011, 04:47 pm by DanielaES Reason: 1

E riducendo il nome ad un max di 8.3 caratteri?
LOG/0000.TXT


era esattamente quello che mi accingevo a provare :)
Pero cavoletti, cosi non posso fare timestamp... cmq provo e riporto :)

leo72

Li puoi fare, come già ti avevo suggerito:

Forse ti converrebbe quindi creare file il cui nome riprenda il mese/anno e poi riversarci dentro le letture.
Ad esempio il file 201112 conterrà le letture di dicembre 2011 mentre il file 201201 le letture di gennaio 2012 ecc...

Quindi crei dei file mensili e dentro tutte le letture di quel mese.

DanielaES

#11
Dec 04, 2011, 04:38 pm Last Edit: Dec 04, 2011, 04:41 pm by DanielaES Reason: 1

Ad esempio il file 201112 conterrà le letture di dicembre 2011 mentre il file 201201 le letture di gennaio 2012 ecc...
Quindi crei dei file mensili e dentro tutte le letture di quel mese.


Funzionasse lo farei, anzi avevo già intenzione di farlo per il logging a lungo termine.
Cmq ci sarebbero problemi in ogni caso log/201201.csv sono 10.3
Certo si potrebbe cmq trovare qualche formato tipo aamm, però cmq non funziona a monte :)
Domanda:
ma è normale che quando apro il serial monitor, l'arduino fa reboot? è la prima volta che lo noto...

leo72

Non ho capito se hai già provato con path/nome max ad 8 caratteri.
Comunque puoi risolvere con Log/1112.txt per 2011/dicembre, Log/1201.txt per 2012/gennaio.

E' normale, ogni volta che apri la seriale il PC invia un segnale di DTR che fa resettare l'Arduino perché è progettato per fare così. Serve a mettere l'Arduino in modalità di programmazione per flashare sull'Atmega328 eventuali sketch in arrivo dal computer.

DanielaES


Non ho capito se hai già provato con path/nome max ad 8 caratteri.


Mea culpa, ho utilizzato l'edit del forum al posto di fare un nuovo post, non volevo la discussione si allungasse troppo ma vedo che crea solo confusione.
Quindi:
Si ho provato, No non funziona.

Con il codice che segue, ne a schermo ne a seriale appare nulla.
Dentro la SD nella cartella log, nessun file.

Code: [Select]
// funzione creazione timestamp file di log
void getFilename(char *filename) {
  DateTime now = RTC.now();
  int month = now.month();
  int day = now.day();
  filename[0] = 'L';
  filename[1] = 'O';
  filename[2] = 'G';
  filename[3] = '/';
  filename[4] = month/10 + '0';
  filename[5] = month%10 + '0';
  filename[6] = day/10 + '0';
  filename[7] = day%10 + '0';
  filename[8] = '.';
  filename[9] = 'c';
  filename[10] = 's';
  filename[11] = 'v';
  return;
}

void loop () {

  // Verifica presenza file di log formattato in TimeStamp:
  char filename[] = "LOG/0000.csv";
  getFilename(filename);
  if (SD.exists(filename)) {
    Serial.print(filename);
    Serial.println(" esiste.");
  }
  else {
    Serial.println("File di Log non presente.");
    lcd.clear ();
    lcd.setCursor(0, 0);
    lcd.print("FileLog Missing.");
    // Se il file di log non esiste viene creato:
    Serial.println("Creazione File di Log...");
    lcd.setCursor(0, 1);
    lcd.print("Building FileLog...");
    myFile = SD.open(filename, FILE_WRITE);
    // Scrittura dell'Header del file di Log e successiva chiusura:
    myFile.println("millis, date, t_out, rh_out, t_in, rh_in, t_h20, t_heat, hz, heat");
    myFile.close();
    delay(1000);
    lcd.clear ();
  }


Rimettendo il codice precedente, con log file in root funziona normalmente.
Non ho idee, voi?

leo72

L'ultimo suggerimento è quello di mettere la cartella radice all'inizio del path, cioè "/log/1112.txt"

Go Up