Let 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
Software:
/* 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 http://www.quickgrow.com/gardening_articles/fans_air_movement.html LCD commands: lcd.setBacklight(LED_OFF); lcd.noBacklight(); lcd.clear(); lcd.home(); */ /*-----( Import needed libraries )-----*/ #include #include //Malpertida #include "RTClib.h" //Adafruit //DHT11 instellingen #include 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() { Serial.begin(115200); //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] ); } lcd.backlight(); // Print a message to the LCD. lcd.setCursor(0, 0); lcd.print("Greenhouse"); // ------- Quick 2 blinks of backlight ------------- flash(2); // ------- Quick buzz-------------------------------- // buzz(1); Wire.begin(); //needed for RTC, not for LCD RTC.begin(); /* 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 = RTC.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(now.day(), 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); Serial.print(level); if (level==0) { digitalWrite(buzPin, HIGH); delay (50); digitalWrite(buzPin, LOW); delay(500); } //------------2. Read the soil moisture content/switch pump---------------- /* First read the level set with P1 on the levelPin and store that in 'irrigate' */ irrigate=sample(levelPin); /* 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 // READ DATA // Serial.print("DHT11, \t"); int chk = DHT.read11(DHT11_PIN); switch (chk) { case DHTLIB_OK: // Serial.print("OK,\t"); break; case DHTLIB_ERROR_CHECKSUM: Serial.print("Checksum error,\t"); break; case DHTLIB_ERROR_TIMEOUT: Serial.print("Time out error,\t"); break; default: Serial.print("Unknown error,\t"); break; } //-------------4. Read LDR ---------------------------------------- light=Map(LDRPin); /* ------------------Actions -------------------*/ //-------------5. DISPLAY DATA ------------------------------------ // Serial.print(DHT.humidity,1); // Serial.print(",\t \t"); //Serial.println(DHT.temperature,0); /* Display data on LCD */ push=digitalRead(PushButton); //Serial.print("Push. : "); // Serial.println(push); if (push==1) // pushbutton not pressed { lcd.clear(); 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("C"); lcd.print(" "); lcd.print (char(7-level)); Serial.print(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("%"); lcd.print(" "); // Serial.print("Humidity (%): "); //Serial.println((float)DHT.humidity, 2); delay(1000); // wait for one second and then print the soilmoisture lcd.setCursor(0,1); lcd.print ("Irr. Level: "); lcd.print(irrigate); lcd.setCursor(0,0); lcd.print("Moisture: "); lcd.print(moist); lcd.print(" "); } if (push==0) // pushbutton pressed { lcd.clear(); lcd.setCursor(0,0); lcd.print("licht: "); lcd.print(light); lcd.print(" "); lcd.setCursor(0,1); lcd.print("licht niv.: "); lcd.print(analogRead(LDRPin)); //buzz(1); } // ---------------5. Action on temperature ------ c=(DHT.temperature); if (c<=20) //Serial.println(c); { // switch on heating digitalWrite(hotPin,HIGH); } else { digitalWrite(hotPin,LOW); } //--------------6. Action on Humidity ----------- if (DHT.humidity >=50) { // switch on fan digitalWrite(fanPin, HIGH); } else { digitalWrite(fanPin,LOW); } delay(1000); //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(); delay(250); lcd.noBacklight(); delay(250); } lcd.backlight(); // finish with backlight on return; } // This function will sound the buzzer "u" times void buzz(byte u) { byte k; for (k=0; k<u;k++) { digitalWrite(buzPin, HIGH); delay(200); digitalWrite(buzPin, LOW); delay(200); } return; } // 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); delay(lengthms); } } // 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"); lcd.backlight(); break; case 1: // // Serial.println("dim"); lcd.backlight(); break; case 2: // // Serial.println("medium"); lcd.noBacklight(); break; case 3: // // Serial.println("bright"); lcd.noBacklight(); break; } return range; }
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.
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