Solar powering an Attiny or Arduino with a capacitor, or just use AA? Part 1

If you have a processor in a remote location that you cannot or will not bring a psu cable to, you have several options of supplying it with energy.
Batteries come to mind and these could be rechargeable or not, or one can use a capacitor. After all, those store energy as well. To make a capacitor a viable option, obviously it needs to be a big one (in capacity, not especially in size), and one has the option of adding a solar cell to it.
As I wanted to feed an attiny that is somewhere in my garden and that is asleep most of the time and as I had some idle solar panels  (9 Volts, 2 Volts) those seemed  suitable to use, but as they do not provide much energy during the night, I needed to store that energy as well. As storage Nicads or even a LiPo came to mind. A Lipo I discarded as it takes some extra circuitry to do any decent charging. A nicad obviously needs some consideration in charging and discharging  as well, but they are more tolerant albeit that a deep discharge is usually not appreciated by them, nor is a constant charge.
Therefore I also considered using a “supercapacitor” I have a capacitor of 10.000uF but one can hardly call that a supercapacitor, but nowadays supercapacitors are readily available at modest prices. They would be easy to use in a charging circuit (basically a resistor would be enough) and they don’t mind frequent  charge and discharge. As their charge is  limited, obviously I would need a solar-cell, so the only thing I needed to see is if they would carry my application ‘through the night’

The Charge of a capacitor is expressed in Coulomb (symbol C).
this can be expressed as:

C=F * V  (where of course ‘F’ stands for the capacity in Farad)
Energy in Joule is expressed as:
J=C*V
Which is:
F*V*V  of F.V²
However, at a given voltage and capacity only half of the energy is available to charge the capacitor hence the energy in the capacitor will be:
J=½ * F *V²
and Joules can also be expressed as ‘Wattseconds’:
J=W *s

So if we calculate the number of Joules in the capacitor at 5.1 Volt:
J=0.5 * 1.5 * 5.1² = 19.5 J
Now obviously we will not all use those as the attiny kinda stops working at 1.8 Volt. If we calculate the number of Joules still left then we come to
J=0.5 * 1.5 * 1.8² = 2.43 J
So the amount of usable energy comes to 19.5-2.43= 17J (rounded down)

From an earlier project on  an attiny13 that was put to sleep only to awake every so many seconds, I found out that the current consumption was 5.5 uA at 5 Volt. Now obviously it will consume a bit less when the voltage drops, so lets assume 4uA at an average of 3.45 Volt (The average voltage being (5.1+1.8)/2=3.45 Volt).
We can calculate the average power consumption as V*I:
3.45 * 4*10⁻⁶ = 13.8 uWatt
as we have 17 Joules available and 17 joules being 17 Ws (Wattseconds) we can calculate the time:
J=W*s
s=J/W
s=17/(13.8 *10⁻⁶)
s=17/13.8  *10⁶
s=1.23 *10⁶
s=1230 000 sec (1,23 million seconds)
that is:
20.531 min, is
342 hrs is
14 days
Now this is just an approximation as there might be some current leakage. The processor will need to do something when awake, like flash a  led or send something, so it will probably not make the full 14 days, but that is not important as it is obviously enough to carry us through the night and probably an overcast day as well.

So how would this be if I used normal AA batteries or NiCad batteries?
As example for regular alkaline batteries  I will take the ubiquitous Philips  LR6. Fortunately someone else already calculated the energie stored in these batteries  at  1986 mAh at a discharge of 100mA. As the performance of these batteries is increasing when the discharge decreases, I will use 2000mAh for my calculations.
If one uses 3 of those to get to 4.5 Volts that will be a total of 9000mWh or 9 Wh.
Again, we will not be able to use this all as we have 1.8 Volt as lower limit, so we will be stuck with 3.6 Wh that we cant use, leaving  5.4 Watthour usable energy.
The average Voltage on the  processor will be:
(4.5+1.8)/2=3.15 Volts.
the average power consumption thus is:
3.15* 4*10⁻⁶ = 12.6uW
as we have 5.4 Wh available we can again calculate the time:
h=5.4/12.6 * 10⁶
h=0.428571 *10⁶
h=428571 hr
=17857 days
=592 months
=50 years
Wow. Why would anybody want to use anything else but LR6 batteries ?
Well for several reasons: 3 of those batteries take more space and eventhough they tend to perform well at low temperatures and low discharge rate, we all have experienced that Alkaline batteries left in a hardly used device tend to leak, even destroying that device by its corrosive leaking. Advantages and disadvantages of alkaline batteries are discussed here.
Nevertheless using alkaline batteries can be a good choice, but don’t forget to change them.

Using NiCad batteries gives a somewhat similar calculation. Suppose we use 3 cells of 1.2 Volt 2000mAh (or 2Ah).
Total energy will be 3.6*2= 7.2 Wh
useable energy will be (3.6-1.8)* 2=3.6 Wh
the average voltage we set at (3.6+1.8)/2=2.70 Volt
The average power consumption will be:
2.7* 4*10⁻⁶ = 10.8uW  (V*I)
The time will thus be:
h=(3.6/10.8) * 10⁶
=333333 hr
=38 yrs
Now if that only was true. My experience with  for instance solar garden lights (that often only have an 800mAh cell)  is that they usually dont last through the winter… and mind you, those are being recharged (which could contribute to their demise).
Nevertheless they may be a good choice.

In a following article I will discuss some practical examples

 

Advertisements

A capacitive soil humidity sensor: Part 2

In a previous article I presented a simple way to read a capacitive moisture sensor with a simple RC generator.
In this post I will present a sensor with some added functionality that can be read through I2C. The circuit (figure) doesnt need much explanation: the RC generator we saw in the previous article and the two variable resistors in a voltage divide read by analogue inputs. The Attiny 45  is the heart, or rather the brains of the sensor. As the Attiny  functions as an I2C slave we will need the TinyWireS library. The library comes with some examples and one example was quite easy to rework to what I needed. The code is as follows.

#define I2C_SLAVE_ADDRES 0x4
#include <TinyWireS.h>//https://github.com/rambo/TinyWire
#ifndef TWI_RX_BUFFER_SIZE
#define TWI_RX_BUFFER_SIZE ( 16 )
#endif

volatile uint8_t i2c_regs[] =
{
	0x00,
	0x00,
	0x00,
	0x00,
};
// Tracks the current register pointer position
volatile byte reg_position;
const byte reg_size = sizeof(i2c_regs);

byte LDRvalue;
byte NTCvalue;
int MoistPulse;

/**
 * This is called for each read request we receive, never put more than one byte of data (with TinyWireS.send) to the
 * send-buffer when using this callback
 */
void requestEvent()
{
	TinyWireS.send(i2c_regs[reg_position]);
	// Increment the reg position on each read, and loop back to zero
	reg_position++;
	if (reg_position >= reg_size)
	{
		reg_position = 0;
	}
}

/**
 * The I2C data received -handler
 *
 * This needs to complete before the next incoming transaction (start, data, restart/stop) on the bus does
 * so be quick, set flags for long running tasks to be called from the mainloop instead of running them directly,
 */
void receiveEvent(uint8_t howMany)
{
	if (howMany < 1) { // Sanity-check return; } if (howMany > TWI_RX_BUFFER_SIZE)
	{
		// Also insane number
		return;
	}

	reg_position = TinyWireS.receive();
	howMany--;
	if (!howMany)
	{
		// This write was only to set the buffer for next read
		return;
	}
	while(howMany--)
	{
		i2c_regs[reg_position] = TinyWireS.receive();
		reg_position++;
		if (reg_position >= reg_size)
		{
			reg_position = 0;
		}
	}
}


void setup()
{
	pinMode(1, INPUT);
	TinyWireS.begin(I2C_SLAVE_ADDRESS);
	TinyWireS.onReceive(receiveEvent);
	TinyWireS.onRequest(requestEvent);
}

void loop()
{
	readSensors();
	/**
	 * This is the only way we can detect stop condition (http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&p=984716&sid=82e9dc7299a8243b86cf7969dd41b5b5#984716)
	 * it needs to be called in a very tight loop in order not to miss any (REMINDER: Do *not* use delay() anywhere, use tws_delay() instead).
	 * It will call the function registered via TinyWireS.onReceive(); if there is data in the buffer on stop.
	 */
	TinyWireS_stop_check();
}

void readSensors()
{
	LDRvalue = (analogRead(A2)) >>2; // max value is 1023/4=255 is 1 byte (FF) physical pin3=PB4=A2
        i2c_regs[0] = LDRvalue;
	NTCvalue = (analogRead(A3)) >>2; // max value is 1023/4=255 is 1 byte (FF) pin2=PB3=A3
	i2c_regs[1] = NTCvalue;
	//pulsepin= pin6=PB1
	MoistPulse = pulseIn(1, HIGH);
	i2c_regs[2] = highByte(MoistPulse); // or use = MoistPulse >> 8;
	i2c_regs[3] = lowByte(MoistPulse); // or use = MoistPulse & 0xFF;
}

I have called the pulseIn function with an integer rather than with a long. This means that you will have to choose a value for R3 that gives a reasonable range for the type of soil that you use. A range of say 0-200 uS is very reasonable. Once you have done that you can also add a timeout to the pulseIn function. This should be abt 2 times the pulselength you expect (but depends on the duty cycle). With regard to the two variable resistors, they are in pull up so their value is Rntc = Rseries/((1023/ADC) – 1));  For the NTC this could be substituted in a Steinhart Hart approximation

The code to call the values (and that is loaded onto the master arduino) is even simpler:

#include <Wire.h>
void setup() {
  Wire.begin();        // join i2c bus (address optional for master)
  Serial.begin(9600);  // start serial for output
}

void loop() {
  for (byte i=0;i<4;++i){
  Serial.print("0x");
  Serial.println(readRegister(i),HEX); // print the character
}
Serial.println(" ");
    delay(1000);
  }

uint8_t readRegister(uint8_t regaddress)
{
	Wire.beginTransmission(4);
	Wire.write((byte)regaddress);
	Wire.endTransmission();
	Wire.requestFrom(4, 1);
	return Wire.read();


 delay(500);
}

This code only prints out the values, you still need to combine the LSB and MSB from the cycle time and e.g. switch a pump based on the value. You could do that with this function:

int combine (byte lsbv, byte msbv)
{
	int value = msbv << 8;
	value = value | lsbv;
	//value= msbv<<8 | lsvb;//if you want to do it in one go
	return value;
}

Don’ t forget that the I2C lines need pull-up resistors of 4.7-10k.

In a next article I will present the construction of the probe itself.

A capacitive soil humidity sensor: Part 1

An automated plant/garden watering system is a popular application for  the Arduino and other microcontrollers. The humidity sensor that is often used is  often a resistance meter: 2 probes in the soil form a resistor and as part of a voltage divider that gives info on the amount of water in the soil.
The major shortcoming of these sensors is that since there is a current flowing, the probe is sensitive to electrolytic corrosion. Another shortcoming is that it doesnt really give information on the soil humidity, but more on the  ion concentration in the soil. Remember: pure water is a bad conductor, It are the ions in the water that make it a conductor.

To get around the corrosion, people have started to feed the probe with AC rather than DC current, but at best the circuits for this supply a pulsating DC current. Another  possibility to minimize corrosion is to  switch off  the current to the probe and only switch it on when a measurement is taken, say every 5  minutes.

All these measures help but even then, just due to the contact with moist soil, the metal on the probe will corrode and weather.
Another method is to encase the probes in plaster. Some people swear by it but I  think it is bothersome. Also the plaster encased probe has a lag as it will retain water  for some time after the  soil is already dry and it will still be dry for some time after the soil is already moist.

Capacitive measuring is a way to avoid these problems. With capacitive measurement the ‘plates’ of the capacitor can be electrically isolated from the soil and the soil in fact forms the dielectrum of the capacitor. Water makes a good dielectrum, whereas ions dont. Capacitive measuring therefore will have a better correlation with the actual amount of water in the soil than resistive measuring and, as said, ideally there will not be any corrosion.

Although the Arduino can measure capacity, it needs 3 pins for that. Also, it isnt really practical to have a long wire as part of your soil probe capacitor go to your Arduino as the wire and whether it is  straight or curly or in a loop, will act as a parasitic capacity and affect the measurement.
Putting your Arduino right onto your plantbed might also not be the best solution.

capacitive74hc14
RC Oscillator With 74HCT14

A better way to do this is to introduce an RC oscillator in which the soil functions as a capacitor and the Arduino measures the frequency that comes out of the oscillator. More water  will increase the value of the ‘capacitor’ which usually will lower the frequency (or increase the cycle time) and that can be measured with the arduino.

An easy RC oscillator can be seen in the figure to the right. A 74HC14 or 74HCT14 Inverter Schmitt-trigger is all you need. For the HC version the Frequency is:
f=1/T=1/(0.8*R*C)
for the HCT version it is:
f=1/T=1/(0.67*R*C)

But in fact the frequency isn’t really that important because we are not making a frequency meter. We are only interested in changes of the frequency that relate to  dry, moist or wet soil. The workings of this type of Oscillator are explained here. and here. The theory behind the frequency calculation is explained here.

leydenjarI tested my set-up initially with a sort of Leyden Jar as a capacitor. Simply put I taped two pieces of alufoil on the outside of a glass jar, attached wires to it and tried if I could measure a change between an empty and a full jar. I started out using a 100k resistor, but only got a decent range after using a 2M2 resistor: an empty jar gave me 1uSec (maybe less, but I guess that was my lower limit) a half full jar around 50uS and a full jar about 100uS (measured with PulseIn). From using a known capacitor I knew I had to use the formula f=1/T=1/(0.67*R*C), but as said, neither the frequency or the actual capacitor value are of much importance as we are just looking for  changes.

Nevertheless the capacity of this jar (when full) could be calculated from
100*10⁻⁶=0.67*2.2*10⁶*C
C=(100*10⁻⁶)/(1.47*10⁶)
C=68*10⁻¹²
C=68pF
Now ofcourse this isn’t entirely correct as with PulseIn We only measured half a cycle, so in fact the Capacity is more likely to be 136pF, provided the dutycycle is 50% (some sources say it is 50% others say it is 33% with the space  2*mark).

byte pin = 8;
unsigned long duration;

void setup()
{
  pinMode(pin, INPUT);
  Serial.begin(115200);
}

void loop()
{
  duration = pulseIn(pin, HIGH);
  Serial.print("Time ");
  Serial.print(duration);
  Serial.print(" usec ");
  Serial.print(500/duration);
  Serial.print(" kHz ");
  Serial.print(500000/duration);
  Serial.println(" Hz");
  delay(500);
}

Then it was time to do some garden field tests. There are several ways to construct a probe: two pieces of PCB at a distance from eachother, One piece of PCB with two plates etched onto it, or a piece of double sided PCB. With regerd to the latter, we tend to think of a capacitor as two plates with a dielectrum in between, but in fact it can also be two  plates with a dielectrum around it.

capacitive probe-textMy garden field test, using two insulated plates of PCB (picture) kinda gave similar results as with the Leyden Jar so I knew I had a decent design.

Yet, two plates is not really very handy: you have a loose wire connecting the plates and as that forms part of the capacitor it introduces stray capacitance, so I decided to go for either a double sided PCB, or a single sided PCB with two plates etched onto it and then place the oscillator on that PCB as well. Frankly, that idea isnt new as many of the (semi)DIY (e.g. the ‘Chirp’) or commercial capacitive probes follow that design as well.

Now it is always good  that before you make a PCB to think through what you want. As I was using only 1/6th of the 74HCT14, I was thinking maybe I could use the other gates as RC oscillators as well  for e.g. an LDR or NTC. Now ofcourse I immediately dismissed that again as I could just as well use an analog read of those and I would have to run extra cables that would all carry a frequency signal, no doubt those would interfere, but it got me thinking. The ‘Chirp’ has a big brother that has an I2C interface, if I would add that, I could add some other sensors (light, temperature)  to my probe. With just the capacitive sensor I would have to run 3 wires (+Vcc, signal, ground). With I2C 4 wires (+Vcc, SDA, SCL, Ground) would be enough for a number of sensors on my probe. Also, as I have various plantbeds, having a number of I2C probes wouldnt require  more inputs on my Arduino.

Obviously, adding I2C meant adding a microcontroller, preferably a cheap one, which easily brings one to the attiny25/45/85 series. If you have good eye sight and a steady hand, you could consider the soic version that is available from 30-70 cts. If you go for a DIP version, that is around 0.9-1 euro. Considering one can get an entire Pro Mini for about 1.20, obviously that is a narrow gap and I (or you) could consider giving each plantbed a totally dedicated  Pro Mini microprocessor that could take care of the irrigation as well.
Having said that, in the past, I have made a self contained system for plantbeds, just using 1 Opamp, so maybe I should just consider this I2C excercise a ‘learning excercise’

capacitive74HC14_attinyI came up with the following circuit. It is easy to recognise the RC oscillator. The cycle signal is fed to PB1 whereas the analog inputs on PB3 and PB4
A3= PB3=physical pin2;A2=PB4=physical pin3.
Pin PB2 is used as SCL signal and PB0 as SDA signal for the I2C interface.

If for any reason you do not have a 74HCx14 in your toolbox, there are other ways of constructing an RC generator. E.g. a 555 or a 74HC00. Even a single transistor could be used. With this type of oscillator the dutycycle approaches 50%
rc-osc

555-oscillator-probe

In a next article I will discuss how to implement the I2C software.

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

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;
}


Opamp for your garden

opamp-probe

(You may want to have look at the improved version right away)

I admit that this has little to do with Arduino’s, but when working on my previous articles on moisture probes and garden irrigation with an Attiny, I mentioned using op-amp comparators instead of microcontrollers, so I thought I’d publish one like that as well.
The concept of an op-amp comparator is simple, if the ‘+’ gate is higher than the ‘-‘ gate, the output goes high, otherwise it goes low.
So with a humidity sensor attached in dry soil, the resistance of that sensor is high and therefore the voltage on the ‘-‘ gate is low and presumably lower than the voltage on the ‘+’ pin and therefore thge output of the opamp will go high.

This will switch on the Solidstate relay and the pump will start pumping. The water that flows into the plantbed will decrease the resistance between the humidity spikes, th evoltage on the ‘-‘ pin wil rise until it is above the level set with P1, the output will go low and the pump will be switched off.

Instead of a Solidstate relay you can also choose for a regular relay, hence the circuit around T1.

Capacitor C2 is in fact a bit optional. after the output of the op-amp goes low, C2 will still have a bit of charge that will keep the pump turn a little bit longer after the humidity is ‘enough’. It also gives a bit of delay in switching the pump on. This avoids jittering of the pump.

The value of R1 largely depends on the type of soil probe you decide to make. Some people have two spikes close together and that would call for a lower value of R1, some people choose to have the spikes at opposite sides of a plantbed, obviously that calls for a higher value of R1.

It is not really necessary to adapt R1, but if R1 and the resistance of the probe  in ‘almost to dry’ condition are far off, the gain of P1 will be limited.

As this is an Arduino dedicated site, I will pull the arduino in here as well. You could choose not to let the Arduino do the measuring of the soil through its analog gates, but you could hook up th eoutput of the above opamp to a digital port of the Arduino and only let it check high or low.
You could build, say 4 of these circuits, each (use a quad opamp then) and have your arduino just do the measuring of the outputs and take appropriate action.
741pcb

this is a design that is for toner transfer. So you are looking at it from the pertinax side.  PDF design here. (NOTE There is  new design in which a flaw was eliminated)
Below the component placing on the PCB. Unfortunately (I use a different program for the circuit and the PCB as I dislike Fritzing’s circuit design), the numbering of the components is different, but it does not take a rocket scientist to figure it out.
741-opbouw

U3 is the connector for the power. J1 is the connector for the probesu6 is there for a different spacing of the capacitor. U2, U4 and U5 are for a relay. U5 and U2 should be drilled according to the size of the relay you happen to use.
J2 is the switching output of the SSR. The entire PCB is about 4×5 cm.

Mounting components on the PCB

Power supply is 5-10 Volt. Depending on what type 741 you are using it could be up to 18 or 22 volts. If you feed with more than 10 Volts you need to recalculate and adapt the value of R2 in the circuit (unfortunately this has come out as R4 on the PCB design) . The forward voltage on the 39MF22 is 1.2 Volts, for a regular LED that is nominal 2 Volts. So if you would feed with say 15V and say 10 mA, you would need a resistor of  12.8/10=1.28k (say 1.4 k). With the current resistor you would have a current of12.8/0.330=39mA. That is too much for the 39MF22 (max 20 mA). The max supply voltage with the current 330 ohm resistor is in fact 10 Volts (and that is alreday pushing it with 20.6mA).

The current 330 Ohm resistor gives a value of 5.5 mA, which is just above the trigger current of the 39MF22.
Because of variations in resistor values and forward voltages of the LED, 330 might in some instances be just a bit too much if you are feeding the circuit with just 5 volts.  Try 220 or a 180 Ohm resistor then.

You should stick to the following minimal and maximal values of your resistor (in Ohm)

Voltage Min value Max value
5 90 360
6 140 560
7 190 760
8 240 960
9 290 1160
10 340 1360
11 390 1560
12 440 1760
13 490 1960
14 540 2160
15 590 2360
16 640 2560
17 690 2760
18 740 2960

As you may have noticed, there is a small mistake in the PCB design as that the LED and the resistor to the 39MF22 have been switched. This should not make any difference for the SSR version, but it may cause the Relay not to shut off. So if you are making the relay version, just switch the LED and the 330 Ohm (or adapted value) in position: The circuit is right, the PCB is wrong