4-months-programmed data logger

2022-01-28T22:50:00Z

Hello

Do you think that the next code and circuit ought to be improved to guarantee data capture over 4 months?

/* 
   Weather data logger integrated to an automated drip irrigation system
   Author: Juan José Guáqueta Restrepo 09012022
   Note: The maximum identifiable capacity of micro SD module is 16GB.
*/


// Libraries:

#include "RTClib.h"
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <DHT.h>

// Constants:
 
#define DHTPIN 2                           
#define DHTTYPE DHT22                                           
#define LDR 3                              
#define SERIALSPEED 9600
DHT dht(DHTPIN, DHTTYPE);
File myFile;                               
RTC_DS3231 rtc;                            
char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
const int PumpPin =  8;                    // Pin to turn water pump's relay on.
unsigned long interval1 = 86400000;        // 86400000 ms (24 h) interval at which water pump will be turn on.
unsigned long interval2 = 600000;          // Interval at which weather data will be recorded (10 min).
unsigned long irrigationTime = 10000;      // Time while water pump is working (10 s).

// Variables:

int PumpPinState = HIGH;                   // Variable to store PumpPinState.
int readed;                                // Variable to store LDR lectures.
int chk;
unsigned long previousMillis1 = 0;         // Variable to measure initial time to water pump.
unsigned long previousMillis2 = 0;         // Variable to measure initial time to weatherstation.
unsigned long currentMillis = 0;           // Variable to store current time.
float hum;
float temp;




void setup () 
{
  
  Serial.begin(SERIALSPEED);               
  
  delay(3000);                             
  
  dht.begin();                             
  
  if (!rtc.begin())                        
  { 
    Serial.println("Couldn't find RTC");
    while (1);                             
  }

  Serial.print("Initializing SD card...");

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

  Serial.println("initialization done.");

  if (rtc.lostPower())                     
  {                  
    Serial.println("RTC lost power, lets set the time!");
                                    
    DateTime(F(__DATE__), F(__TIME__));    
  }

  pinMode(PumpPin, OUTPUT);                
  
  digitalWrite(PumpPin, HIGH);                             

  pinMode(LDR, OUTPUT);                    

  myFile = SD.open("dos.txt", FILE_WRITE);

  myFile.print("Date-RTC-DS3231-M, ");

  myFile.print("Time-RTC-DS3231-M, ");

  myFile.print("Temperature-RTC-DS3231-M (a.u), ");

  myFile.print("HumidityDHT22 (%), ");

  myFile.print("TemperatureDHT22 (°c), ");

  myFile.println("LuxLDR (%)");
  
  myFile.close();
  
}




void loop () 
{
  
  currentMillis = millis();                
  
  save_data();
  
  pump_state();
  
  pump_on();
  
}




void pump_state() 
{

  if (PumpPinState == HIGH) {             
    if (currentMillis - previousMillis1 >= interval1) {
       PumpPinState = LOW;
       previousMillis1 += currentMillis;  
    }
  }
  else {
    if (currentMillis - previousMillis1 >= irrigationTime) {
       PumpPinState = HIGH;
       previousMillis1 += irrigationTime;
    }
  }    
}




void pump_on()
{
  digitalWrite(PumpPin, PumpPinState);
}




void save_data() 
{

if(currentMillis - previousMillis2 >= interval2)
{
  
  previousMillis2 = currentMillis;
               
  readed = analogRead(LDR);               
  readed = map(readed, 0, 1023, 0, 100);  
  hum = dht.readHumidity();               
  temp = dht.readTemperature();           
  DateTime now = rtc.now();
  myFile = SD.open("dos.txt", FILE_WRITE);
  myFile.print(now.year(), DEC);
  myFile.print('/');
  myFile.print(now.month(), DEC);
  myFile.print('/');
  myFile.print(now.day(), DEC);
  myFile.print(" (");
  myFile.print(daysOfTheWeek[now.dayOfTheWeek()]); 
  myFile.print("), ");
  myFile.print(now.hour(), DEC);
  myFile.print(':');
  myFile.print(now.minute(), DEC);
  myFile.print(':');
  myFile.print(now.second(), DEC);
  myFile.print(',');
  myFile.print(" ");
  myFile.print(rtc.getTemperature());
  myFile.print(',');
  myFile.print(' ');
  myFile.print(hum);
  myFile.print(',');
  myFile.print(' ');
  myFile.print(temp);
  myFile.print(',');
  myFile.print(' ');
  myFile.println(readed);                 
  myFile.close();                         

}

}

Code.ino (4.4 KB)

I wish people would simply post code.

/* 
   Weather data logger integrated to an automated drip irrigation system
   Author: Juan José Guáqueta Restrepo 09012022
   Note: The maximum identifiable capacity of micro SD module is 16GB.
*/


// Libraries:

#include "RTClib.h"
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <DHT.h>

// Constants:
 
#define DHTPIN 2                           
#define DHTTYPE DHT22                                           
#define LDR 3                              
#define SERIALSPEED 9600
DHT dht(DHTPIN, DHTTYPE);
File myFile;                               
RTC_DS3231 rtc;                            
char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
const int PumpPin =  8;                    // Pin to turn water pump's relay on.
unsigned long interval1 = 86400000;        // 86400000 ms (24 h) interval at which water pump will be turn on.
unsigned long interval2 = 600000;          // Interval at which weather data will be recorded (10 min).
unsigned long irrigationTime = 10000;      // Time while water pump is working (10 s).

// Variables:

int PumpPinState = HIGH;                   // Variable to store PumpPinState.
int readed;                                // Variable to store LDR lectures.
int chk;
unsigned long previousMillis1 = 0;         // Variable to measure initial time to water pump.
unsigned long previousMillis2 = 0;         // Variable to measure initial time to weatherstation.
unsigned long currentMillis = 0;           // Variable to store current time.
float hum;
float temp;




void setup () 
{
  
  Serial.begin(SERIALSPEED);               
  
  delay(3000);                             
  
  dht.begin();                             
  
  if (!rtc.begin())                        
  { 
    Serial.println("Couldn't find RTC");
    while (1);                             
  }

  Serial.print("Initializing SD card...");

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

  Serial.println("initialization done.");

  if (rtc.lostPower())                     
  {                  
    Serial.println("RTC lost power, lets set the time!");
                                    
    DateTime(F(__DATE__), F(__TIME__));    
  }

  pinMode(PumpPin, OUTPUT);                
  
  digitalWrite(PumpPin, HIGH);             

  //pinMode(RED, OUTPUT);                  

  pinMode(LDR, OUTPUT);                    

  myFile = SD.open("dos.txt", FILE_WRITE);

  myFile.print("Date-RTC-DS3231-M, ");

  myFile.print("Time-RTC-DS3231-M, ");

  myFile.print("Temperature-RTC-DS3231-M (a.u), ");

  myFile.print("HumidityDHT22 (%), ");

  myFile.print("TemperatureDHT22 (°c), ");

  myFile.println("LuxLDR (%)");
  
  myFile.close();
  
}




void loop () 
{
  
  currentMillis = millis();                
  
  save_data();
  
  pump_state();
  
  pump_on();
  
}




void pump_state() 
{

  if (PumpPinState == HIGH) {             
    if (currentMillis - previousMillis1 >= interval1) {
       PumpPinState = LOW;
       previousMillis1 += currentMillis;  
    }
  }
  else {
    if (currentMillis - previousMillis1 >= irrigationTime) {
       PumpPinState = HIGH;
       previousMillis1 += irrigationTime;
    }
  }    
}




void pump_on()
{
  digitalWrite(PumpPin, PumpPinState);
}




void save_data() 
{

if(currentMillis - previousMillis2 >= interval2)
{
  
  previousMillis2 = currentMillis;
               
  readed = analogRead(LDR);               
  readed = map(readed, 0, 1023, 0, 100);  
  hum = dht.readHumidity();               
  temp = dht.readTemperature();           
  DateTime now = rtc.now();
  myFile = SD.open("dos.txt", FILE_WRITE);
  myFile.print(now.year(), DEC);
  myFile.print('/');
  myFile.print(now.month(), DEC);
  myFile.print('/');
  myFile.print(now.day(), DEC);
  myFile.print(" (");
  myFile.print(daysOfTheWeek[now.dayOfTheWeek()]); 
  myFile.print("), ");
  myFile.print(now.hour(), DEC);
  myFile.print(':');
  myFile.print(now.minute(), DEC);
  myFile.print(':');
  myFile.print(now.second(), DEC);
  myFile.print(',');
  myFile.print(" ");
  myFile.print(rtc.getTemperature());
  myFile.print(',');
  myFile.print(' ');
  myFile.print(hum);
  myFile.print(',');
  myFile.print(' ');
  myFile.print(temp);
  myFile.print(',');
  myFile.print(' ');
  myFile.println(readed);                 
  myFile.close();                         

}

}
#define SERIALSPEED 9600

The 1970s called - they want their line speed back

1 Like

Please post a clearly labeled schematic diagram (photo of hand drawn is fine). Fritzing diagrams despised on this forum, as they are usually wrong, always poorly labeled, and extremely difficult to interpret. Are we supposed to know what the blue rectangles represent?

Your code makes the classic mistake of opening the file, writing a tiny bit of data, and closing it again. This dramatically increases the SD card error rate and the time to write data.

Open the file ONCE in setup and close it when you are all done collecting data. Issue a flush() command once an hour or day or so, to make sure that the file info is kept up to date.

1 Like

A 9 volt battery will NOT last 4 months.

I had one in a smoke alarm last over a year.

1 Like

A couple of things.

You are fairly low on dynamic memory, 575 bytes free, and the SD library will need 512 bytes of that for a buffer. Do a bit of research on the F() macro for printing text literals. You have also committed the common error with the daysOfTheWeek array of using 12 characters to store the name of each day, when the longest (Wednesday) only needs 10 characters (9 characters plus the terminating NULL).

Implement a watchdog timer so that you have some hope of recovery if the code locks up.

< edit >
You also have what appears to be an error in your code:


  if (PumpPinState == HIGH) {             
    if (currentMillis - previousMillis1 >= interval1) {
       PumpPinState = LOW;
       previousMillis1 += currentMillis; //<<<<<<<<<<<<
    }
  }
1 Like

If the relay module pictured is a true representation of the one you have, with the JD-VCC / VCC / GND jumper block, then you have the preferred option of powering the relay coils from a separate power supply from the arduino.

You are opening and closing the file each trip around the loop. This will eventually be fatal - very likely before the four months is up. Other than that, you do not appear to be clogging things up with Strings so, if your code does what it is supposed to do for a while, it will do so for ever.

But I don't think it does do what it is supposed to do, because I don't see any time control of the loop whatsoever, just a meaningless allusion to millis. I recognise you do have some time-related lines elsewhere, but I don't understand them. I submit having a common time control in the loop makes more sense, and leaves nobody in any doubt about your intentions. You may then find a sensible comment about SD capacity will be on offer. As things are, 16Gb is an awful lot, but there may a be a surprise there.

I see you already realise the futility of using a 9v PP3 but you don't say how you are powering Uno, and using a 12v PSU will be very uncomfortable for it. If you need 12v for the pump, a dedicated 5v regulator for Arduino would make sense.

All those

  myFile.print(' ');

make no sense to Arduino and, if you are serious about what you are doing, the data will probably land up in a spreadsheet, and they make no sense there either.

I don't know anything about your peripherals, but you appear to be printing the temperature twice. And I really wonder why you need to save the days of the week.

1 Like

Hello dear david_2018. Would you please explain to me in detail what could be an error in this part of the code?:

if (PumpPinState == HIGH) {             
    if (currentMillis - previousMillis1 >= interval1) {
       PumpPinState = LOW;
       previousMillis1 += currentMillis; //<<<<<<<<<<<<
    }
  }

You are adding currentMillis to the current value of previousMillis1, instead of the common technique of setting previousMillis1 = currentMillis, or adding interval1 to previousMillis1.

1 Like

Dear community, I have changed the code. What do you think?

/* 
   Weather data logger integrated to an automated drip irrigation system
   Author: Juan José Guáqueta Restrepo 09012022
   Note: The maximum identifiable capacity of micro SD module is 16GB.
*/


// Libraries:

#include "RTClib.h"
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <DHT.h>

// Constants:

#define DHTPIN 2                           // The DHT22 sensor uses the Arduino UNO's Pin 2 to collect data.
#define DHTTYPE DHT22                      // The DHT22 instead of the DHT11 since the first one is more precise.
#define LDR 3                              // Pin at which LDR sensor is connected.
#define SERIALSPEED 9600                   // Bits per second rate.
DHT dht(DHTPIN, DHTTYPE);
File myFile;                               // It defines a file named 'myFile' in which data will be saved.
RTC_DS3231 rtc;                            // Declaration of a RTC_DS3231 type object called rtc. rtc = real time clock.
const int PumpPin =  8;                    // Pin to turn an electro valve on by a relay. Const int: The definition of an integer type constant.
unsigned long interval1 = 86400000;        // The interval at which the electro valve is turned on (24 h). Unsigned long: Is a positive extended size variable.
unsigned long interval2 = 600000;          // The interval at which weather data is recorded (10 min).
unsigned long irrigationTime = 10000;      // The electro valve is on for 10 s.

// Variables:

int PumpPinState = HIGH;                   // A variable to store PumpPinState.
int readed;                                // A variable to store LDR (light diode resistor) values.
unsigned long previousMillis1 = 0;         // Electro valve's reference time.
unsigned long previousMillis2 = 0;         // Weatherstation's reference time.
unsigned long currentMillis = 0;           // A variable to store current time.
unsigned long experimentPeriod = 172800000;// 604800000 = One week.
float hum;                                 // A variable to store humidity values from the DHT22. float: Is a variable with decimal points. 
float temp;                                // A variable to store temperature values from the DHT22.




void setup ()
 
{
  
  Serial.begin(SERIALSPEED);               // It sets communication at a rate of 9600 bits/s.
  
  delay(3000);                             // Wait while the console is opened.
  
  dht.begin();                             // It initializes the DHT22 sensor.
  
  if (!rtc.begin())                        // begin() function ensures that the rtc module is connected. !: logical not.
  
  { 
    Serial.println(F("Couldn't find RTC"));// F() macro. F() is to free dynamic memory.
    while (1);                             // while(1): Do not do anything more -Infinite loop.
  }

  Serial.print(F("Initializing SD card..."));

  if (!SD.begin())                         // It guarantees that the micro SD card is connected.
                         
  {
    Serial.println(F("initialization failed!"));
    return;                                // return: Go out of the SetUp.
  }

  Serial.println(F("initialization done."));

                                           // lostPower() function reads the DS3231’s internal I2C registers to check if the chip has lost track of time. If the function returns true, we can then set the date & time.

  if (rtc.lostPower())                     // It runs if the rtc lost power and it is necessary to adjust date and time.
  
  {                  
    Serial.println(F("RTC lost power, lets set the time!"));                               
    DateTime(F(__DATE__), F(__TIME__));    // This line sets the rtc module to the date & time this sketch was compiled.
  }

  pinMode(PumpPin, OUTPUT);                // It defines the PumpPin as an output.
  
  digitalWrite(PumpPin, HIGH);             // It turns the PumpPin off since the previous line turns the electro valve on by the relay.

  pinMode(LDR, OUTPUT);                    // It defines the LDR pin as an output.

  myFile = SD.open("tres.txt", FILE_WRITE);// It creates a .txt file called 'three' and opens it to write into it.
    
}




void loop ()

{
  
  currentMillis = millis();                // Returns the number of milliseconds passed since the Arduino board began running the current program and stores them into currentMillis variable.
  
  save_data();                             // This invokes a function whose aim is to stores date, time, and weather data each 10 minutes.
  
  pump_state();                            // This invokes a function whose aim is to set PumpPinState HIGH or LOW according to interval1 and irrigationTime.
  
  pump_on();                               // This invokes a function whose aim is to turn an electro valve on by the relay.
  
}




void pump_state()
 
{

  if (PumpPinState == HIGH) {              // == means equals to.
    if (currentMillis - previousMillis1 >= interval1) {
       PumpPinState = LOW;
       previousMillis1 += currentMillis;  // +=: previousMillis1 = previousMillis1 + currentMillis.
    }                                     // '+=' has been working good. Then, I tried to put just '=' instead of '+=' but that let the relay on all the time. Hence, I decided to use '+='.
  }
  else {
    if (currentMillis - previousMillis1 >= irrigationTime) {
       PumpPinState = HIGH;
       previousMillis1 += irrigationTime;
    }
  }    
}




void pump_on()

{
  digitalWrite(PumpPin, PumpPinState);
}




void save_data()

{

if(currentMillis - previousMillis2 >= interval2)

{
  
  previousMillis2 = currentMillis;

  readed = analogRead(LDR);               // It reads LDR sensor and stores data into 'readed'.
  readed = map(readed, 0, 1023, 0, 100);  // It maps analog-digital-conversor states (2^(10) = 1024 (0 included)) into values between 0 and 100.
  hum = dht.readHumidity();               // It reads humidity from the DHT22 and stores it into 'hum'.
  temp = dht.readTemperature();           // It reads temperature from the DHT22 and stores it into 'temp'.
  DateTime now = rtc.now();
  myFile.print(now.year(), DEC);          // It prints the current year into the 'three' file previously opened.
  myFile.print('/');                      // It prints a '/' after the above into the 'three' file.
  myFile.print(now.month(), DEC);         // It prints the current month into the 'three' file.
  myFile.print('/');
  myFile.print(now.day(), DEC);           // It prints the current day.
  myFile.print(',');
  myFile.print(now.hour(), DEC);          // It prints the current hour.
  myFile.print(':');
  myFile.print(now.minute(), DEC);
  myFile.print(':');
  myFile.print(now.second(), DEC);
  myFile.print(',');
  myFile.print(hum);                      // It prints humidity from the DHT22.
  myFile.print(',');
  myFile.print(temp);                     // It prints temperature from the DHT22.
  myFile.print(',');
  myFile.println(readed);                 // 'ln' before '(' is necessary since each 10 minute-set of data must be in a row instead of all 10 minute-set data in one row.
  
}
  
  if(currentMillis == experimentPeriod)   // Once experimentPeriod has reached then the file 'three' is closed and the code do nothing more.
  
{
  
  myFile.close();                         // Close the file is necessary since otherwise no data is recorded.
  while(1);

}

}

Much improved, but you need to execute myFile.flush() every once in a while (hourly, daily, etc.).

In case of a power failure you will lose only the data written since the last time it was executed.

Change this
if(currentMillis == experimentPeriod)
to this:
if(currentMillis >= experimentPeriod)

1 Like

Dear community, I've programmed it to work for seven days. Besides, I interrupted it on the sixth day. Finally, it works ok -A beautiful set of data was taken.

Thank you

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.