Orto idroponico verticale con Arduino – quinta parte

In questo articolo dedicato all’orto idroponico verticale con arduino ci dedicheremo alle funzioni richiamate.

Orto idroponico verticale

Come ho descritto nell’articolo orto idroponico verticale con arduino – quarta parte per semplificare la descrizione delle funzionalità e dello sketch ho divisol il progetto in parti in cui ciascuna descrive parte del progetto completo.

Le funzioni ti permettono di controllare in modo semplice alcune parti specifiche del progetto evitando di complicare in modo eccessivo lo sketch principale che contiene quindi le sole funzionalità di setup() e loop().

Le funzioni dell’orto idroponico verticale con arduino

Poichè le funzioni non hanno una relazione diretta le une nei confronti delle altre leggerai la descrizione di ciascuna funzione in modo indipendente.

Nel tuo sketch le funzioni puoi inserirle nel file principale nella posizione che preferisci o usare un file separato (.ino) inserito nella stessa dir del progetto principale; in questo modo arduino IDE si accorgerà del file ed in fase di compilazione utilizzerà entrambi i file .ino

Funzione getApiSmartcitizen()

la prima funzione che descrivo è la getApiSmartcitizen() il cui scopo è connettersi al server SmartCitizen e recuperare i dati rilevati dai sensori ambientali.

/***************************************************/

boolean getApiSmartCitizen() {
  if (client.connect(server_in, 80)) {
    #ifdef DEBUG
      Serial.print("SmartCitizen: ");
      Serial.println("connected");
    #endif
    
    client.println("GET /v0.0.1/*****************/lastpost.json HTTP/1.1");
    client.println("Host: api.smartcitizen.me");
    client.println("Connection: close");
    client.println();
  }
  index = 0;
  if (client.available())  {
     while (client.connected()) {
       char c = client.read();
       if( c == '{'  ){ if( startData==false){ startData=true; } }
       if(startData==true){ results[index] = c; index++; }
     } 
  }
  results[index]=0;
  
  if (!client.connected()) {
    #ifdef DEBUG
      Serial.print("SmartCitizen: ");
      Serial.println("disconnected");
    #endif
    
    client.stop();
    startData=false; index = 0;
    StaticJsonBuffer<550> jsonBuffer;
    JsonObject& root = jsonBuffer.parseObject(results);
    if (!root.success()) {
      Serial.println("parseObject: failed");
      return true;
    }
    //timestamp = root["devices"][0]["posts"]["timestamp"];
    temp  = root["devices"][0]["posts"]["temp"];
    hum   = root["devices"][0]["posts"]["hum"];
    co    = root["devices"][0]["posts"]["co"];
    no2   = root["devices"][0]["posts"]["no2"];
    noise = root["devices"][0]["posts"]["noise"];
    light = root["devices"][0]["posts"]["light"];
    batt  = root["devices"][0]["posts"]["bat"];
    return true;
  }
  return false;
}

/***************************************************/

linea 03: definisci la funzione di tipo boolean in quanto la funzione restituirà un valore booleano per dirti se è andata a buon fine o meno. Se ricordi nell’articolo in cui hai letto lo sketch principale al punto in cui la richiami usi il comando: while ( !getApiSmartCitizen() ) { ; } che genera un ciclo in cui continua a richiamare la funzione fino a quando non ritorna true che inidca la buona riuscita dell’operazione eseguita dalla getApiSmartCitizen();

linea 04: esegui una connessione al server denominato server_in ( vedi sketch principale );

linee 05-08: definisci delle righe di debug che scrivono sul monitor seriale solo in presenza della definizione della costante DEBUG, in questo modo puoi abilitare e disabilitare il DEBUG solo variando la definizione di questa costante;

linee 10-14: definisci la chiamata all’Api messa a disposizione dal progetto SmartCitizen e la cui documentazione puoi leggerla sul sito ufficiale al link: http://api.smartcitizen.me/ ovviamente ho sostituito la chiave di accesso con degli ***** dovrai inserire al posto giusto la tua key;

linea 17: quando il client riesce a connettersi il valore del metodo client.available() diventa true e inizi ad eseguire le operazioni scritte nell’IF;

linea 18: fino a quando esiste la connessione tra client e server esegui il contenuto delle linee successive;

linee 19-21: leggi l’output proveninete dal client in modo seriale e quando trovi il valore ‘{‘ ( inizio del JSON ) poni a true il valore della variabile startData che indica alla linea 21 di iniziare a memorizzare la sequenza JSON nel results con indice index;

linea 24: imposta un carattere di fine riga oltre l’ultimo valore letto dal client ethernet per essere certo del termine della linea;

linea 26: quando il client non è più connesso puoi eseguire il contenuto delle linee successive in quanto sei certo che la trasmissione dei dati si è conclusa;

linee 27-30: definisci il debug;

linea 32: ferma il client e chiudi la connessione con il server;

linea 33: imposta nuovamente la variavile startData a false e l’ndice a 0;

linea 34: definisci un oggetto jsonBuffer di 550 caratteri;

linea 35: usando il metodo parseObject della classe Json inclusa nell’articolo precedente esegui la validazione del JSON presente nella variabile results e poni il rsultato, un array, nell’oggetto root;

linee 36-39: in caso di fallimento del parsing, ossia se l’oggetto JSON ricevuto non è corretto o conforme allo standard JSON atteso scrivi sul monitor seriale il testo di errore e restituisci true al ciclo while che ha richiamato questa funzione;

linee 41-47: estrai il valore di ciascuna variabile dall’oggetto root come se fosse un array. Punti al valore ricercato come ad una arry sulla struttura JSON;

linea 48: restituisci true in modo che la loop() sappia che la funzione è finita e che l’esito è positivo;

linea 50: fino a quando la funzione non termina e la comunicazione con il server API SmartCitizen non è conclusa continui a inviare il valore false al loop().

Funzione postData()

Anche per l’invio dei dati ad un server di log ho usato una funzione: postData() in quanto il server predisposto per la ricezione dei dati è stato predisposto per accettare dati di tipo JSON nella forma

{"sensorId":"[id sensore]","value":"[valore_letto_dal_sensore]"}

per cui ho creato la funzione generica di invio dati in formato JSON al server a cui passi id e valore perché lei a sua volta li invii al server di destinazione.

/***************************************************/

boolean postData( const char* idToSend, char* valueToSend) {
  
  if (client.connect(server_out, 80)) {
    String post = "{\"sensorId\":\""; 
           post += idToSend; 
           post += "\",\"value\":\""; 
           post += valueToSend; 
           post += "\"}";

    #ifdef DEBUG
      Serial.print("Id: "); Serial.print(idToSend);
      Serial.print(" Val: "); Serial.println(valueToSend);
    #endif
    
    idToSend = "";
    valueToSend ="";
    
    client.println("POST /iog/samples HTTP/1.1");
    client.println("Host: iot.enter.it");
    client.println("Accept: */" "*");
    client.println("User-Agent: Arduino/1.0.0");
    client.println("Content-Type: application/json");
    client.print("Content-Length: ");
    client.println(post.length());
    client.println("Connection: close");
    client.println();
    client.print(post);
    
    post = "";
  }

  index = 0;
  if (client.available())  {
    while (client.connected()) {
      char c = client.read();
    } 
  }
  results[index]=0;
  
  if (!client.connected()) {
    client.stop();
    startData=false;
    index = 0;
    return true;
  }
  
  return false;
}

/***************************************************/

linea 03: definisci la funzione postaData che accetti in ingresso l’ID da inviare ( idToSend ) ed il valore da inviare ( valueToSend ) e restituisca true quando la funzione ha eseguito il suo compito e false in tutti gli altri casi;

linea 05: definisci e controlla la connessione con il server definito come server_out ossia il server di uscita dei dati dallo sketch;

linee 06-10: componi la riga JSON da inviare come indicata sopra sostituendo al posto dell’ID il valore passato alla funzione così come per il valore da inviare per ciascun sensore;

linee 12-15: imposta delle linee di DEBUG per verificare i valori che arrivano alla funzione postData e che dovrebbero essere inviati al server JSON;

linee 17-18: elimina il contenuto delle variabili per evitare sovrapposizioni di dati;

linee 20-29: invia al client le stringhe di header ed il contenuto da inviare ai server in formato JSON mediante POST, poni l’attenzione sulla linea 26 in cui invii al server la lunghezza dei dati raggiunta dalla linea JSON, questo valore è richiesto nell’invio di dati con il metodo POST e puoi calcolarlo grazie al metodo length applicabile ad oggetti di tipo String;

linea 31: pulisci il valore della variabile post in modo che futuri invii non siano influenzati da questo;

linee 34-40: similmente a come hai letto per la funzione getApiSmartcitizen valuti anche in questa funzione i valori restituiti dal server, nota che in questo caso non esiste alcuna assegnazione alla variabile results in quanto abbiamo convenuto di non inviare risposte da parte del server almeno in questa prima fase e di lasciare questa implementazione in futuro.

linee 42-47: quando rilevi la fine della connessione da parte del server provvedi a chiudere anche il client con il metodo close() ed azzera tutte le variabili coinvolte, restituisci infine true alla loop() che ti ha richiamato;

linea 49: restituisci sempre false fino a quando la comunicazione è attiva.

Funzioni getTime(), getHour(), getMinute(), getSecond()

sono le funzioni dedicate alla sincronizzazione dell’ora con il server NTP e destinate all’assegnazione dei valori restituiti allo sketch perché possano essere utilizzati dallo sketch.

Riporto tutte le funzioni di seguito:

/***************************************************/

void getTime() {
  sendNTPpacket(timeServer); // send an NTP packet to a time server
  delay(1000);  
  if ( Udp.parsePacket() ) {  
    Udp.read(packetBuffer,NTP_PACKET_SIZE);  // read the packet
    unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
    unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);  
    unsigned long secsSince1900 = highWord << 16 | lowWord;  
    const unsigned long seventyYears = 2208988800UL;     
    unsigned long epoch = secsSince1900 - seventyYears;  
    
    #ifdef DEBUG    
      Serial.print("Seconds since Jan 1 1900 = " ); 
      Serial.println(secsSince1900);
    #endif
    
    getHour( epoch );                               
    getMinute( epoch );                               
    getSecond( epoch );

    #ifdef DEBUG
      Serial.print("Ora Corrente: "); Serial.print( currHour ); 
      Serial.print(":"); Serial.print( currMin ); 
      Serial.print(":"); Serial.println( currSec );
    #endif
  }
}

/***************************************************/

void getHour( unsigned long epoch ) { 
   currHour = (((epoch  % 86400L) / 3600) + timeZone); 
}   

/***************************************************/

void getMinute( unsigned long epoch ) { 
   currMin = ((epoch % 3600) / 60); 
}

/***************************************************/

void getSecond( unsigned long epoch ) {
   currSec = (epoch % 60); 
}

/***************************************************/

//unsigned long sendNTPpacket(IPAddress& address)
unsigned long sendNTPpacket(char* address)
{
  memset(packetBuffer, 0, NTP_PACKET_SIZE); 
  packetBuffer[0] = 0b11100011;   // LI, Version, Mode
  packetBuffer[1] = 0;     // Stratum, or type of clock
  packetBuffer[2] = 6;     // Polling Interval
  packetBuffer[3] = 0xEC;  // Peer Clock Precision
  packetBuffer[12]  = 49; 
  packetBuffer[13]  = 0x4E;
  packetBuffer[14]  = 49;
  packetBuffer[15]  = 52;

  Udp.beginPacket(address, 123); //NTP requests are to port 123
  Udp.write(packetBuffer,NTP_PACKET_SIZE);
  Udp.endPacket(); 
}

/***************************************************/

tuttavia le funzioni getTime() e sendNTPpacket() avrai già notato che sono del tutto identiche a quelle descritte nell’articolo Tutorial ntp arduino per cui ti rimando alla lettura di quell’articolo per comprenderne il funzionamento.

le funzioni getHour(), getMinute() e getSecond() sono simili nel loro funzionamento in quanto nessuna di questa restituisce un valore in modo diretto ma si limitano ad assegnare un valore alle rispettive variabili calcolandolo sulla base dei secondi trascorsi dal 01 gennaio del 1970:

linea 34: esegui il % ( modulo ) della divisione tra il valore epoch, valore in seocndi trascorsi dal 01 gennaio 1970, e il valore in secondi 86400 di un giorno ( 60 sec * 60 min + 24 ore ) il risultato ti da il numero di giorni restanti, in pratica qualsiasi sia il numero di giorni trascorsi questa operazione ti restituisce la differenza di ore oltre l’ultimo giorno intero trascorso; dividendo questo valore per i secondi di cui è composta un ora ( 3600 ) ti restituisce l’ora corrente a cui devi solo sommare il timezone italiano;

linea 40: esegui la medesima operazione per i minuti dividendo epoch per 3600 e dividendo il risultato per 60 ( secondi in un minuto );

linea 46: il calcolo è più semplice in quanto il valore di epoch è già in secondi.

Funzione getPH()

Per recuperare il valore di Ph dell’acqua ho usato il PhMetro della DfRobot che ho descritto nell’articolo che ti invito a leggere: Orto idroponico verticale con Arduino – terza parte

Riporto le funzioni di seguito ma ti invito a leggere l’articolo per approfondirne il funzionamento:

/***************************************************/

double avergearray(int* arr, int number){
  int i;
  int max,min;
  double avg;
  long amount=0;
  if(number<=0){
    Serial.println("Error number for the array to avraging!/n");
    return 0;
  }
  if(number<5){   //less than 5, calculated directly statistics
    for(i=0;i<number;i++){
      amount+=arr[i];
    }
    avg = amount/number;
    return avg;
  }else{
    if(arr[0]<arr[1]){
      min = arr[0];max=arr[1];
    }
    else{
      min=arr[1];max=arr[0];
    }
    for(i=2;i<number;i++){
      if(arr[i]<min){
        amount+=min;        //arr<min
        min=arr[i];
      }else {
        if(arr[i]>max){
          amount+=max;    //arr>max
          max=arr[i];
        }else{
          amount+=arr[i]; //min<=arr<=max
        }
      }//if
    }//for
    avg = (double)amount/(number-2);
  }//if
  return avg;
}

/***************************************************/

void getPh() {
  static float voltage;
  int pHArray[ArrayLenth];   //Store the average value
  byte pHArrayIndex=0;  
  for (byte i = 0; i < ArrayLenth; i++ ) {
      pHArray[pHArrayIndex++]=analogRead(PhMeterPin);
      if(pHArrayIndex==ArrayLenth)pHArrayIndex=0;
      voltage = avergearray(pHArray, ArrayLenth)*5.0/1024;
      pHValue = 3.5*voltage+Offset;
  }
  
  #ifdef DEBUG
    Serial.print("Volt: "); Serial.println(voltage); 
    Serial.print("Ph:   "); Serial.println(pHValue); 
  #endif
}

/***************************************************/

Funzione readEC()

La lettura dei sensori EC permette il controllo della conducibilità elettrica dell’acqua e la concentrazione dei fertilizzanti, per funzionare Paolo ha realizzato due sensori che ho descritto nel dettaglio nell’articolo:

Orto idroponico verticale con Arduino – seconda parte

Riporto anche in questo caso lo sketch che ti invito ad approfondire nell’articolo dedicato ai sensori EC:

/***************************************************/

float readEC( byte isens ) {
  
  float RS1 = 0.;
  float RS2 = 0.;
  float VCC = 5000.;
  float Vconv = VCC/1024.;
  float V1 = 0.;
  float V2 = 0.;
  float VSG = 0.;
  
  float runningAvg1 = 0.;
  float runningAvg2 = 0.;
  float runningAvg3 = 0.;
  
  for(byte i = 0; i < n; i++) {
    digitalWrite(pinEC1[isens],HIGH);
    digitalWrite(pinEC3[isens],LOW);
    runningAvg1 = runningAvg1 + Vconv*analogRead(pinEC2[isens]);         
    digitalWrite(pinEC1[isens],LOW);
    runningAvg2 = runningAvg2 + Vconv*analogRead(pinEC2[isens]);         
    digitalWrite(pinEC3[isens],HIGH);
    runningAvg3 = runningAvg3 + Vconv*analogRead(pinEC2[isens]);         
  }
  VSG = runningAvg2/n;
  V1  = runningAvg1/n;      
  V2  = runningAvg3/n;      
  //  compute RH and VS
  if(V1 < 2.){
    RS[isens] = 60000.;
    CS[isens] = 0.;
  } else {
    //  correggo con la galvanica
    V1 = V1-VSG;
    V2 = V2-VSG;
    //  primo calcolo di RS
    RS1 = R1*(VCC-V1)/V1; 
    //  secondo calcolo di RS e media tra i due (RS in kohm)
    RS2 = R1*V2/(VCC-V2);
    RS[isens] = (RS1 + RS2)/2000.;
    //  calcolo CS secondo i parametri di taratura
    if( RS[isens] < 0.5) { CS[isens] = 1300; } 
    else{ CS[isens] = A[isens]*pow(RS[isens],B[isens]); }          
  }
  
  #ifdef DEBUG
    Serial.print( "EC: " ); Serial.println( CS[isens] ); 
  #endif
  
  return CS[isens];
}

/***************************************************/

Funzioni apriGocciolatore(), chiudiGocciolatore()

La gestione del fertilizzante avviene attraverso un gocciolatore autocostruito dai membri WeMake.

In pratica abbiamo utilizzato una elettro-valvola di qualche anno fa di quelle costruite con un ingresso e due uscite singole ciascuna controllata da un motore che ruotando apre e chiude il flusso d’acqua.

Per ciascun motore è presente un finecorsa il cui stato determina se la valvola è aperta o chiusa.

Abbiamo collegato una tanica all’ingresso con della colla a caldo e realizzato un semplice driver con mosfet per il controllo del motore in quanto è necessario che giri sempre nella medesima direzione e quindi un ponte-H era eccessivo.

Controllando la chiusura del microswitch ( finecorsa ) ho determinato se la valvola si trovi in posizione di apertura o chiusura e di conseguenza il passaggio o meno del flusso idrico, usato in questo caso per il fertilizzante da aggiungere al bidone di irrigazione.

Lo sketch che controlla tutto questo:

/***************************************************/

void apriGocciolatore() {
   Serial.println( "apri" );
   while ( digitalRead(pinValF1) == 1 ) {
     analogWrite(pinFert1,100);
   }
   analogWrite(pinFert1,0);
}

/***************************************************/

void chiudiGocciolatore() {
   Serial.println( "chiudi" );
   while ( digitalRead(pinValF1) == 0 ) {
     analogWrite(pinFert1,100);
   }
   delay( 100 );
   analogWrite(pinFert1,0);
}

/***************************************************/

linea 03: definisci la funzione apriGocciolatore() il cui scopo è apreire l’elettrovalvola al momento di agiungere fertilizzante;

linea 05: fino a quando il valore letto in modo digitale sul pin a cui è connesso il finecorsa corrispondente al motore 1 esegui la line a successiva;

linea 06: invia il PWM 100 al motore in modo che girando apra la valvola del gocciolatore;

linea 08: ferma il motore appena uscito dal while;

linee 15-17: esegui la stessa operazione vista per l’apertura del gocciolatore controllando il valore 0 del pin digitale connesso al finecorsa;

linea 18: attendi 100 millisecondi ulteriori, al termine del while, per essere certo che il gocciolatore si sia chiuso;

linea 19: invia al motore il PWM 0 perché si fermi;

Funzione LegalTime()

L’ultima funzione dello sketch è la funzione che si occupa di calcolare l’ora legale partendo dalla data e l’ora corrente.

/***************************************************/

byte LegalTime(DateTime now) {
          byte cFlag = 0;
    const byte iDayW = now.dayOfWeek();
    const byte iDay  = now.day();
    const byte iMonth= now.month();
    const byte iHour = now.hour();
    
    if (iMonth == 10) {
      if (iDayW == 0) {
          if (((iDay + 7) > 31) && (iHour >= 3)) { cFlag = 0; }
      } else {
        if ((iDay + (7 - iDayW))> 31) { cFlag = 0; }
        else { cFlag = 1; }
      }
    }
    
    if (iMonth == 3) {
      if (iDayW == 0) {
        if (((iDay + 7) > 31) && (iHour >= 2)) { cFlag = 1; }
      } else {
        if((iDay + (7 - iDayW))> 31) { cFlag = 1; } else { cFlag = 0; }
      }
    }
    
    if(iMonth >= 4 && iMonth <= 9) { cFlag = 1; }
    if((iMonth >= 1 && iMonth <= 2) || (iMonth >= 11 && iMonth <= 12)) { cFlag = 0; }
    
    return cFlag;
}

/***************************************************/

linea 03: definisci la funzione LegalTime( DateTime now ) che accetta in ingresso l’oggetto now di tipo DateTime e restituisce 0 in caso di ora solare nel periodo corrente o 1 se è presente l’impostazione di ora legale. In questo modo se usi il valore della funzione sommato all’orario corrente vedrai sempre l’ora esatta;

linea 04: definisci una variabile di tipo byte in cui memorizzerai il valore da restituire alla funzione che richiama questa, nel nostro caso la loop();

linee 05-08: definisci le costanti di tipo byte in cui memorizzi il valore del giorno corrente rispetto alla settimana ed i valori di giorno, mese ed ora;

linea 10: se il mese corrente è ottobre esegui le linee seguenti;

linea 11: verifica che il valore del giorno corrente sia 0, vuol dire che è domanica;

linea 12: se la data del giorno + 7 supera il 31, vuol dire che sei all’ultima domsnica del mese di ottobre ) e contemporaneamente ho superato le 3 del mattino allora l’ora legale è da togliere ed il valore restituito è 0;

linea 14: calcola il numero di giorni mancanti alla fine della settimana e somma il valore alla data corrente confrontando che il risultato sia oltre il 31 del mese di ottobre in tal caso sei nell’ultima settimana di ottobre e di certo l’ora legale deve essere tolta;

linea 15: per tutti gli altri giorni del mese di ottobre l’ora legale è attiva per cui il valore di cFlag = 1;

linea 19: se il mese è marzo esegui le linee successive;

linea 20: se il valore di iDayW == 0 ossia se è domenica allora dovrai verificare in quale domenica del mese di marzo sei;

linea 21: controlla che la somma della data odierna + 7 superi il 31 del mese per cui sei di certo all’ultima domenica del mese per cui se l’orario è superiore alle 2 del mattino devi aggiungere un ora all’ora corrente;

linea 23: se il giorno corrente cade nell’ultima settimana del mese di marzo devi impostare l’ora legale mentre per tutti gli altri giorni del mese il cFlag 0;

linea 27: per tutti i mesi da aprile a settembre l’ora legale è fissa a +1;

linea 29: per i mesi novembre, dicembre, gennaio e febbraio il valore da sommare all’orario solare è 0;

linea 31: restituisci il valore cFlag impostato dai calcoli precedenti.

La funzione LegalTime() è richiamata dalla loop() alla linea 170 in cui in fase di visualizzazione sommi all’ora corrente solare il valore di ora legale calcolato da questa funzione per mostrare sul monitor seriale l’ora corretta.

Buon orto !!!!

Cortesemente, prima di inserire i commenti leggi il regolamento

Permanent link to this article: http://www.mauroalfieri.it/elettronica/orto-idroponico-verticale-con-arduino-quinta-parte.html

16 comments

Skip to comment form

    • nino on 26 ottobre 2015 at 23:02
    • Reply

    ciao ho la mia arduino mega 2560 e l’rtc…ma ora che sto iniziando credo che manchi uno schema dei vari pin utilizzati, dei vari pompe sensori et……cmq ho un problema quando vado a caricare tutto su arduino mege:
    “OrtoWeMake.ino: In function ‘void loop()’:
    OrtoWeMake:72: error: ‘class DateTime’ has no member named ‘dayOfWeek’
    function.ino: In function ‘byte LegalTime(DateTime)’:
    function:295: error: ‘class DateTime’ has no member named ‘dayOfWeek’
    ‘class DateTime’ has no member named ‘dayOfWeek’

    1. Ciao Nino,
      l’errore è dovuto alla mancanza del metodo “dayOfWeek” nella libreria RTC che stai utilizzando.
      Controlla di possedere la medesima libreria che io ho inserito nel gitHub o scarica quella.

        • nino on 29 ottobre 2015 at 09:53
        • Reply

        Grazie!avevo pasticciato io con il codice,ora sono riuscito aa caricarlo.Ora ho un po di perplessità…..:appena riesco faccio un grafico di tutti i collegamenti con Fritz nel frattempo ho due dubbi :qual e il sensore del livello acqua e dove lo collego?quale l eletteovalvola del fertilizzante e possibile avere una foto o un link per l acquistò?

        1. Ciao Nino,
          lo schema è molto semplice in quanto i sensori sono dichiarati nel file di configurazione.
          L’elettrovalvola per il fertilizzante è stata ottenuta al WeMake riciclando del materiale obsoleto e mal funzionante che qualche membro aveva abbandonato.

    • nino on 29 novembre 2015 at 00:51
    • Reply

    Ciao ho un problema con la trasmissione dei dati sul server smartctizen:mi spiego creato nel mio profilo il sensore con mac address, il sito non riceve nulla da Arduino sebbene sulla porta seriale vengono scritti i vari sensori con i valori .Allora come indicato ho caricato solo il codice per il test di connessione a Smartctizen e sulla porta seriale mi crea un loop connesso disconnesso …puoi aiutarmi?

    1. Ciao Nino,
      ti consiglio di rivolgerti al loro supporto.
      Io ho solo visto la parte di connessione via API per questo progetto.

    • nino on 27 dicembre 2015 at 09:43
    • Reply

    Ciao Mauro allora ti aggiorno…:
    il mio Arduino scrive su db MySQL i dati dei sensori, ho creato un file PHP che estrae un file json,

    Credo che il modo piu potente di manipolare questi dati sia quello di usarli con un foglio di calcolo di google drive allora:

    nel foglio di calcolo ho creato un app che converte il json e scrive nelle celle, e con una formattazione condizionata e qualche funzione so lo stato di tutti i sensori con i rispettivi nomi (sonda ph …ec.. luci …pompa)

    ho creato dei trimmer che aggiornano i dati ogni 5 minuti e cancellano le righe dal db una volta a settimana. prossimo passo è abbinare un grafico ai numeri.

    Ma ho riscontrato un problema…

    ( currHour );( currMin );( currSec ); non mantengono l’ ora effettiva e alle 2 di notte circa o reinizia segnando 00:00 oppure a volte dopo le 23:59 continua 24:00 ….25:00….26:00 etc… sto monitorando le anomalie.
    Hai idea di come si po risolvere questa anomalia?
    Alla fine se vuoi posso fornire progetto completo per tutti.
    Ciao

    1. Ciao Nino,
      molto interessante il progetto che stai realizzando.
      Mi lascia dubbioso non tanto il primo caso ( reinizia segnando 00:00 ) potrebbe dipendere da un errore di comunicazione ntp o della funzione ntp; il secondo caso è strano, il componente RTC dopo le 23.59 deve continuare con 00:00 è programmato per farlo e non da noi, sembra quasi che il tuo sia danneggiato o che non ci sia vera comunicazione tra l’RTC e l’arduino.

    • nino on 9 gennaio 2016 at 08:47
    • Reply

    Ciao Mauro ti aggiorno:
    1. ho testato rtc con uno sketch che lo fa lavorare da solo e l’ orologio non perde un colpo
    2. sto testando con uno sketch REAL TIME CLOCK FROM NTC SERVER di arduino e ad oggi tiene ancora l’ ora.

    Ora il mio dubbio è:
    la funzione ntp perchè non corregge l’ora quando si accorge dell’ anomalia?

    Posso inviarti il codice che ho modificato per testarlo anche tu?
    Può essere magari che l’anomalia possa dipendere dalle modifiche da me apportate?
    Grazie

    1. Ciao Nino,
      purtroppo non ho il tempo di testare codici modificati da altri causa i numerosi impegni con il blog ed i progetti su commissione.
      Se hai fatto delle modifiche, che pensi scompensino il corretto funzionamento, eliminale e verifica cosa accade.

    • nino on 15 gennaio 2016 at 05:13
    • Reply

    Ciao Mauro ho testato il tuo codice senza apportare modifiche… e ritorna a 00.00 di un DayOfWeek precedente rispetto a quello che doveva essere.Credo che dopo i vari test che ho fatto il tuo codice dia questo errore.

    1. Ciao Nino,
      non ho compreso a cosa ti riferisci.

    • nino on 15 gennaio 2016 at 10:58
    • Reply

    ho raccolto un po di output della seriale
    qui puoi vedere
    https://docs.google.com/spreadsheets/d/1mh1X51ez6Zo5BSQhwadGgaO19OWl36R4ERcK1e7Q7CQ/edit?usp=sharing
    sono filtrati per il solo valore
    Ora:
    Ti ripeto questo è il tuo codice intatto, possibile che nessuno abbia avuto questo problema?

    1. Ciao Nino,
      da quello che vedo nei log il passaggio da DayOfWeek 4 a 5 è corretto, poi alle 3.59 del giorno 5 sembra si resetti tutto e riparta da 00.00 del giorno 4 .. sei certo che non sia un problema di reset dovuto a qualche collegamento errato o assorbimento non corretto?
      Questa versione era molto sensibile alla tensione di alimentazione per questo l’ho sostituita con una fatta su Yùn che pubblicherò questa primavera probabilmente.

    • nino on 15 gennaio 2016 at 15:45
    • Reply

    Premettendo pure quello che dici , ma a me sembra che tutto è ok , ma la funzione ntp non corregge mai l orario ora errato?

    1. Ciao Nino,
      se si resetta prima che questa intervenga o durante il suo intervento automaticamente non riuscirà ad aggiornare nulla.

Lascia un commento

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.