Arduino for greenhouse or growbox

greenhouse2Let me start with saying it is not really an ‘Arduino’ but an Atmega 328 with Arduino bootloader.
After doing several ‘garduino’ projects, i wanted to build something that I could use to either run a greenhouse outside, or a growbox inside the house, for veggies and stuff during the winter.

The circuit contains various elements, that I will discuss:
Most will probably recognize the ‘barebones arduino’ basically the atmega 328, a crystal, 2 capacitors and a reset circuit.
K1: is a header that will feed into 4 relays that have the following functions:
Switch on the irrigation, switch on a lamp, switch on a heater, switch on a fan
K2: is an FTDI header for uploading programs to the Atmega.
K3: is a header to connect a DHT11 moisture and temperature sensor. Those only need 3 connectors, but I had 2 with different pin lay-outs, hence the 4 prong  connector. R11 is a pull up resistor
K4: is the IIC header  that connects to an LCD
K5: is a connector  to connect an RTC module. The Led and resistors are optional… just in case you would want a led flashing every second.
CN 1 and 2 are to connect a soil moisture sensor. In order to save the sensor being broken down by electrolysis quickly, The transistor is there to switch off current through the sensor.
The Zenerdiodes  are there to protect the Atmega against high voltages that may build up on a long wire.
There are 2 switches tat can be used  freely. Currently I use the pushbutton to select a different reading on the LCD and the throw switch is still unused.
The level Switch  is a switch that closes when the waterlevel in the reservoir is too low. It is a simple float switch
The LDR can determine if it is day or night if no RTC is used. ofcourse for inside use it is not that usefull


/* meet de vochtigheid
 als minder dan ingestelde waarde, pomp aan
 meet temperatuur
 als lager dan ingestelde waarde, verwarming aan
 meet humidity
 als hoger dan ingestelde waarde zet ventilator aan
 ventilator ook aan snachts
 LCD commands:
/*-----( Import needed libraries )-----*/
#include  //Malpertida
#include "RTClib.h"   //Adafruit
//DHT11 instellingen
dht DHT;
/*-----( Declare objects )-----*/
// set the LCD address to 0x27 for a 20 chars 4 line display
// Set the pins on the I2C chip used for LCD connections:
//                    addr, en,rw,rs,d4,d5,d6,d7,bl,blpol
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address
/*-----(Declare RTC objects )------*/
RTC_DS1307 RTC; //declare onject

/*-----( Declare pins )------*/
byte moisturePin=0; //read soil mositure
byte levelPin= 1; //analogue Pin1  set level for  irrigation
byte humidPin=2;  //Physical pin4  Humidity sensor
byte lightPin=5; //Switches on light
byte fanPin=6; //Switches fan
byte pumpPin =7;  //Switches pump
byte hotPin= 8; // Switches heater
byte buzPin=9;  // Switches buzzer
byte emptyPin=10;  //digital  Pin10  guards waterlevel
byte spikePin=12;  //Digital  Pin12  -> Extra for intermittent switching of spike
byte LDRPin=3;// analog pin for LDR
byte PushButton=4;   // PushButton
byte SwitchButton=3;// Make Switch
byte push=0;
byte sButton=0;
#define DHT11_PIN humidPin
/* Variable setting   */
unsigned int moist=0;    //will contain the soil moisture level
unsigned int irrigate=0;   //sets level for irrigation in case no potmeter
byte level=0;
int c;// contains the temperature reading
// these constants won't change:
const int sensorMin = 40;      // LDR minimum, discovered through experiment
const int sensorMax = 1012;    // LDR maximum, discovered through experiment
byte light;  // value for LDR reading
// Create a set of new characters

const uint8_t charBitmap[][8] = {

    0xc, 0x12, 0x12, 0xc, 0, 0, 0, 0     }

    0x6, 0x9, 0x9, 0x6, 0, 0, 0, 0     }

    0x0, 0x6, 0x9, 0x9, 0x6, 0, 0, 0x0     }

    0x0, 0xc, 0x12, 0x12, 0xc, 0, 0, 0x0     }

    0x0, 0x0, 0xc, 0x12, 0x12, 0xc, 0, 0x0     }

    0x0, 0x0, 0x6, 0x9, 0x9, 0x6, 0, 0x0     }

    0x0, 0x4, 0xE, 0x15, 0x4, 0x4, 0x4, 0x0     }

    0x4,0x4,0x4, 0x4, 0x15, 0xE,0x4,0x0     }
/// -------- end creation--------------
//The following function, "setup", must always be present
void setup()
  //upload defined characters to LCD

  //---------------end upload----------------
  pinMode(levelPin,INPUT);  // set level
  pinMode(humidPin,INPUT);  // measures humidity
  pinMode(emptyPin,INPUT);  // measures reservoir
  //digitalWrite(emptyPin, HIGH);       // turn on pullup resistors
  pinMode(SwitchButton, INPUT);   // make Switch
  pinMode(PushButton, INPUT);     // PushButton
  pinMode(spikePin,OUTPUT); // for alternative supply to spikes
  pinMode(pumpPin,OUTPUT);  // Output for Relay
  pinMode(fanPin, OUTPUT);  // Output for fan
  pinMode(hotPin, OUTPUT);  // Output for heater
  pinMode(lightPin, OUTPUT);// Output for light
  pinMode(buzPin, OUTPUT);  // Output for buzzer
  digitalWrite(pumpPin, LOW);// Pump off
  digitalWrite(spikePin, LOW);// moisture sensor off
  digitalWrite(fanPin,LOW);  // fan Off
  digitalWrite(hotPin,LOW);   // heater off
  digitalWrite(lightPin, LOW); // light Off
  digitalWrite(buzPin, LOW); // buzzer off
  /* Now LCD */
  lcd.begin(16,2);         // initialize the lcd for 20 chars 4 lines, turn on backlight
  int charBitmapSize = (sizeof(charBitmap ) / sizeof (charBitmap[0]));
  for ( int i = 0; i < charBitmapSize; i++ )
    lcd.createChar ( i, (uint8_t *)charBitmap[i] );
  // Print a message to the LCD.
  lcd.setCursor(0, 0);
  // ------- Quick 2 blinks of backlight  -------------
  // ------- Quick buzz--------------------------------
 // buzz(1);
  Wire.begin(); //needed for RTC, not for LCD
  /* Set the date / time to the time this program was compiled.
   Comment this OUT, AND upload, to let the clock just run.  */
  //  RTC.adjust(DateTime(__DATE__, __TIME__));

/*----------------------------(end setup )---------------------*/

void loop() 
  DateTime now =;  //Get the current data
 // Serial.print("The year is ");
 // Serial.print(now.year(), DEC);
 // Serial.print(" Month = ");
 // Serial.print(now.month(), DEC);
 // Serial.print(" Day = ");
 // Serial.print(, DEC);
 // Serial.print(" Time = ");
 // Serial.print(now.hour(), DEC);
 // Serial.print(':');
 // Serial.print(now.minute(), DEC);
 // Serial.print(':');
 // Serial.print(now.second(), DEC);
 // Serial.println();
  //------------end of RTC
  // ---------- 1. Check if there is enough water -------------  
  // check if there is water  
  level=  digitalRead(emptyPin);
  if (level==0) {
    digitalWrite(buzPin, HIGH);
    delay (50);
    digitalWrite(buzPin, LOW);
  //------------2. Read the soil moisture content/switch pump----------------
First read the level set with P1 on the levelPin and store that in 'irrigate'

   Then we read the soil humidity sensor.
   We'll first have to set the spikePin to HIGH, in case that is used to feed the sensor. 
   After the reading we set it back) 
   If the value read ('moist') is smaller than what is considered dry ('irrigate') 
   then the pump should be switched on for a specific time. 
   This is done by indicating a higher treshhold for switching the pump off
  digitalWrite(spikePin, HIGH);// put voltage on the  humidity sensor
  delay(100); //wait a short while
  moist=sample(moisturePin);  //read soil humiditySensor
  digitalWrite(spikePin, LOW);
  // level=  digitalRead(emptyPin);// just read again to make sure
  if (moist <= irrigate) digitalWrite(pumpPin, level);
   if (moist >= irrigate+5) digitalWrite(pumpPin, LOW); // prevents  Jitter

  //-------------3. Read the DHT11 humidity/temp sensor-----------------

  // now we measure temperature and air humidity
  // Serial.print("DHT11, \t");
  int chk = DHT.read11(DHT11_PIN);
  switch (chk)
  case DHTLIB_OK:  
    //	Serial.print("OK,\t"); 
    Serial.print("Checksum error,\t"); 
    Serial.print("Time out error,\t"); 
    Serial.print("Unknown error,\t"); 

  //-------------4. Read  LDR ----------------------------------------
   /* ------------------Actions -------------------*/

  //-------------5.  DISPLAY DATA ------------------------------------
  // Serial.print(DHT.humidity,1);
  // Serial.print(",\t \t");
  /*   Display data on LCD  */
  //Serial.print("Push.   : ");
  // Serial.println(push);
  if (push==1) // pushbutton not pressed
    lcd.setCursor(0, 0);  //set cursor on first line (line 0)
    lcd.print("Temp.   : ");
    lcd.print((float)DHT.temperature, 0);
    lcd.print (char(1));  // prints degree sign
    lcd.print(" ");
    lcd.print (char(7-level));
    //  Serial.print("Temp. (oC): ");
    //  Serial.println((float)DHT.temperature,2);
    lcd.setCursor(0,1);  //set cursor on 2nd line
    lcd.print("Humidity: ");
    lcd.print((float)DHT.humidity, 0);
    lcd.print("  ");
    // Serial.print("Humidity (%): ");
    //Serial.println((float)DHT.humidity, 2);  
    delay(1000);  // wait for one second and then print the  soilmoisture
    lcd.print ("Irr. Level: ");
    lcd.print("Moisture: ");
    lcd.print("   ");

  if (push==0)   // pushbutton pressed
    lcd.print("licht: ");
    lcd.print("          ");
    lcd.print("licht niv.: ");


  // ---------------5. Action on temperature ------
  if (c<=20)     //Serial.println(c);
// switch on heating     
}   else   {
 //--------------6. Action on Humidity -----------  
 if (DHT.humidity >=50)
    // switch on fan
    digitalWrite(fanPin, HIGH);
  //end dht
  //end loop
//-------  End of Main program-----------
//-------- Start of functions------------
int sample(int z)
/* This function will read the Pin 'z' 5 times and take an average.
 Afterwards it will be mapped to 8 bits by dividing by 4
 Could ofcourse immediately divided by 20 
  byte i;
  int sval = 0;
  for (i = 0; i < 5; i++){    
    sval = sval + analogRead(z);// sensor on analog pin 'z'
  //sval = sval / 5;    // average
  //sval = sval / 4;    // scale to 8 bits (0 - 255)
  sval=sval / 20;
  return sval;
//------------- Flash the backlight a number of times--------
void flash(byte y)
  byte j;
  for (j=0; j<y;j++)
  lcd.backlight(); // finish with backlight on  
// This function will sound the buzzer "u" times
void buzz(byte u)
  byte k;
  for (k=0; k<u;k++)
    digitalWrite(buzPin, HIGH);
    digitalWrite(buzPin, LOW);
// This function will blink an LED a number of times for a specific duration
void ledblink(int times, int lengthms, int pinnum){
  for (int x=0; x<times;x++){
     digitalWrite(pinnum, HIGH);
     delay (lengthms);
     digitalWrite(pinnum, LOW);
 // This function maps the LDR reading into nrs 0-3
 int Map(byte sens) {
  // read the sensor:
   int sensorReading = analogRead(sens);
   // map the sensor range to a range of four options:
   int range = map(sensorReading, sensorMin, sensorMax, 0, 3);
  // do something different depending on the
  // range value:
  switch (range) {
  case 0:    // 
  //  Serial.println("dark");
  case 1:    // 
   // Serial.println("dim");
  case 2:    // 
  //  Serial.println("medium");
  case 3:    // 
  //  Serial.println("bright");
  return range;


2 thoughts on “Arduino for greenhouse or growbox”

  1. Try to use capacitive soil sensors.
    They are much better, then your solution!
    Try to google the “Giesomat” Sensor.
    I use it since two years, without any problem.

    1. Thank you for your comment. I have wide experience with capacitive soil sensors and should you browse through my pages you can see i even built a few. “Much better” i would not say. They have their pro’s and cons.
      I mainly use graphite rods nowadays

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

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

%d bloggers like this: