ATtiny for your garden

This post is largely theoretical: Finished project here

Since I have a habit of being not home but still need my water gardened I was trying to find a way to do that. Of pourse there are the watering clocks like the Gardena or others that can be programmed to water the garden for a certain time ach day or each week and I have used thoes but the have two drawbacks:

They will water even if it is not necessary + I always feel a bit anxious to use those if I am away for a long time, just in case something goes wrong and the mains waterline will start spraying for days on end.

Therefore I decided to turn to a microcontroller. Ofcourse ‘Arduino’ pops to mind but that seemed a bit like overkill for a simple task, but it seemed like a good idea to develop a system on the Arduino an then transfer it to an ATtiny45.

The idea was to let the Arduino measure moisture in my plantbed and then depending on a preset value for moisture or dryness, switch on a pump.

As the ATtiny has several pins that could be used as an output or input, I was thinking to find a use for the other pins a swell and I found the perfect solution. As the watering function will probably only be used in the summertime, after planting, I could use the device earlier alrady for heating up a propagator. yes I know there are heated propagators but I just could not find one in my local gardenshops.

First a bit of theory:

spanningsdelerIn this figure, the voltage Va is a function of the Voltage Vcc and the two resistors R1 and R2. The Current I flowing through R2 and R1 is Vcc/(R1+R2) and therefore the voltage over R1 and thus the voltage Va=I x R1.

If we subsitute I then the formula will be (Vcc/(R1+R2))xR1= Vcc*R1/(R1+R2)=Va.

With a Vcc of 5 V and both resistors being 10 k, the voltage Va therefore will be 2.5 V.

If R2 would be replaced by a variable resistor such as an NTC or a humidity sensor, the voltage over Va will vary dpending on the value of the temperature or the humidity and that voltage Va will subsequently be read by an analog port on the Attiny.

The temperature sensor

NTCThe temperature sensor is quite easy. a 10 k NTC will do the trick. It will come in the place of R2 so with a rising temperature the voltage on Va will rise as well.

The value of an NTC (e.g. 10k)  is usually given at an ambient temperature of 25 degrees Celsius. Therefore, at 25C the voltage on Va should be 1/2 Vcc.
Initially I had the intention to calculate the temperature with the Steinhart-Hart formula but as I only needed two temperatures, one to switch on the heating and one to switch off the heating in the propagator, it made more sense to just measure the Va at these specific temperature as this also takes into account a variation in the Vcc, in the resistor R1 and in the resistance of the leads to the NTC.
I wanted to keep the temperature between 21 and 26 degrees and you will find my values for that in the program. The values that you will need might be different. Mind that the Analogue ports will give you a reading between 0 and 1023. The Arduino can map this with the map command, but it is just as useful to divide by 4. The function that does this is the function ‘sample’. It will take the average of 5 readings and then divide that (‘map it’) by four.

The humidity sensor

Build-Your-Moisture-SensorThe humidity sensor is basically not more than 2 spikes driven into the ground. The citcuit is similar to that of the temperature reader, with the spikes taking the place of the NTC. In my experience, soil that is just sufficiently humid gives a resitence (with my humidity resistor) of  about 10 k. Also here if the soil dries out, the resistence of the sensor will increase and the voltage on the analogue port will rise. A specific dryness or wetness of the soil therefore corresponds with a certain value on the analogue port.


The construction of a humidity sensor is quite simple although there seem to be various ‘schools’ of thought. Some people will embed their ‘spikes’ in plaster of paris to give a more even reading of moisture. Most people however will just take two metal spikes that are inserted in the earth. There are however two things to remember: the spikes need to be attached to eachother, otherwise putting them in another position may cause the distance between the two spiks to chanage and therefore also the resistance; the spikes need to be made of galvanized material will they stand any chance of surviving being in the soil. Galvanized nails are a popular material, but they ar ehard to solder. Th best way is to file or sand the place where one wants to solder the wire. Wrap the wire around the spike and solder and then to top it off, pit some shrink wrap around it to ensure a good contact between the wire and the spike.

Metal spikes in the soil. especially if they have a DC current going through them, may corrode very quickly. In practice that has not bothered me that much, but there are some things that one could do to prevent corrosion: only put tension to the pins when the device is actually read. In that case the humidity sensor should not be connected to +Vcc but to digital pin 0 that can be switched on right before the reading and switched off  right after it. Another thing one can do –but in our example we are a pin short- is not to connect the pin and its pull down resistor to + V and earth, but to two digital output pinds that then will feed it with an AC current bij alternating the polarity of the two digital pins and only to read it when the proper pin is high.

Also, avoid using copper. Copper seems to be pretty good in actually picking up voltages from the earth whcih may cause some weird effects when you are trying to read the resistance. You may get complte different readings if you reverse the connection to those copper spikes.

The program

The program is fairly simple. First it starts with some descriptions and gives the lay-out for the Attiny. It then defines the pins and sets the variables.
It then reads the humidity sensor with the ‘sample’ function and stores the result in the variable ‘moist’. It compares the value for ‘moist’ with the value that is set for ‘irrigation’. If it is lower or equal to that value, it switches on the pump by setting the ‘pumpPin’ high.
If it is a level of 5 above that value, iyt switches the pump off.
This is done to avoid the pump switching on and off repeatedly and to make the soil wet enough. Depending on the flow of water in your particular set up, you may want to alter that value of ‘5’.
It then reads the temperature, again with the ‘sample’ function and stores the result in the variable ‘ntc’. It then sees if this value is less than ‘142’ (which is 21 degrees in my case)  and if so, it switches on the heating in my propagator. It then compares the value with ‘155’(which is 26 degrees in my case) and if so, switches off the heating.
As a heater I have used a 40 W lamp that is switched via a solidstate relais.

So just to summarize: I use this device in summer outside to water my plantbeds and in  early spring I use it inside to heat a propagator. The device therefore is never controlling both temperature and irrigation at the same time, but if you would use it in a greenhouse, ofcourse it could.
Although the irrigation could be done by switching an electric valve in the main waterline, I have opted to use an immersible pump in a large bucket with water. As immersible pumps should not run dry, I have used a reed switch with a magnet on a floating device to cut the power to the pump if the water level is too low.



I am not going to point out that if you are switching a pump or a lamp that you have to be careful with the mains voltage that can kill you. If you have no knowledge of these things you should not attempt to fiddle with it. But there is something else I need to point out: If the lines of the of your sensors to your ATtiny are long, they may pick up spikes that could be too high for the ports on your microcontroller and you may want to consider a bit of protection. This can be obtained by adding a 1 k resistor and a 5v1 zener as is shown in the picture. Obviously if you use that you need to recalibrate the values that are read from the sensor.

 /*February 2012 

-NTC  aan analoog  pin1
-Humidity spike aan analoog pin2
* Schematic:
*   [Ground] -- [10k-pad-resistor] -- | -- [NTC] --[Vcc]

*                                     |
*                                Analog Pin 3
*    Rntc=((Vcc * pad / Vpin1) - pad);
*   =((1024 * pad / RawADC) - pad);

* Schematic:
*   [Ground] -- [10k-pad-resistor] -- | -- [Spikes] --[Vcc]
*                                     |
*                                Analog Pin 2
If the humidity sensor gets too dry, the resistance goes up and the voltage on the analog pin goes down. As a result the pump relais is activated. The sensor measures ca 10 kOhm if the soil is moist enough. The reading therefore should be at 512 (with a pull down resistor of 10k).
* If the temperature goes down the resistance of the NTC goes up and therefore the voltage on the analogue port goes down and a relay can be switched (for heating or for ventilation). In my case the resistance should be between 12.5 and 10k Ohm (21-23 degrees Centigrade) the reading on the analogue port thus must be kept between 512 and 455.

ATTiny pins
Physical  Analoog  Digital
1           0          5   Reset, PinChange Interrupt
2           3          3   INT0,3
3           2          4   INT0,4
4           Ground
5                      0   INT0,0
6                      1   INT0,1
7           1          2   INT0,2
8           Vcc
//Pin definitions
int ntcPin= 3; //analogue Pin3  ->Physical pin2
NTC int humidPin=2;//analogue Pin2  ->Physical pin3  Humidity spike
int pumpPin =2;//digital  Pin2  ->Physical pin7  Bevloeiingspomp
int warmPin=1;//digital  Pin1  ->Physical Pin6  Verwarming
int signalPin=0;//Digital  Pin0  ->Physical Pin5  Extra

// Variabelen setting
int moist=0; // maybe float is not necessary
int ntc=0;   // maybe float is not necessary
int ldr=0;   // maybe float is not necessary
int irrigate=512; // level for irrigation ca 126 after mapping

//The following function, "setup", must always be present
void setup() {//Serial.begin(9600);// for debugging only, remove for Attiny
pinMode(ntcPin,INPUT);// meet temperatuur
pinMode(humidPin,INPUT);// meet vochtigheid
pinMode(signalPin,OUTPUT);//Signaallamp oid
pinMode(warmPin,OUTPUT);//Output for heating element
pinMode(pumpPin,OUTPUT);//Output for Relais/waterpump
digitalWrite(pumpPin, LOW);
digitalWrite(warmPin, LOW);}

void loop() //This function must always be present
/* First we read the Humidity sensor. If the sensor is >10 k this is considered dry As the sensor is in a voltage divider of 10k the value read then will be 1/2 Vcc In analogue value this will be about 1/2 *1024=512 and after mapping it will be 127

So if the value read ('moist') is smaller than what is considered dry ('irrigate'), the pump should be switched on for a specific time. This is done by indicating a higher treshhold for switching the pump off


moist=sample(humidPin);  //read humiditySensor
//This function samples 5 times and averages
// Serial.print("Value Read: ");
// Serial.println(moist);
if (moist <= irrigate) digitalWrite(pumpPin, HIGH);
if (moist >= irrigate+5) digitalWrite(pumpPin, LOW);

/* Now read the temperature sensor. If  the sensor is 10 k this is considered 26 degrees, the analogue reading will be 512 and 128 after mapping at a higher value the heating should be switched off
If the sensor is 12k5 this is considered 21 degrees, the analogue reading will be 455 and 113 after mapping this is the lower treshhold and the heating should be switched on
In real life however the values 142 and 155 corresponded better with those temperatures (apparently theory and practice do not always match)

ntc=sample(ntcPin); // Serial.println(ntc);
if (ntc <= 142) digitalWrite(warmPin, HIGH);
if (ntc >= 155) digitalWrite(warmPin, LOW);} //end loop

// Sample Function
int sample(int z)
/* This function will read the Pin 'z' 5 times and take an average.Afterwards it will be mapped by dividing by 4 */

int 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 = 255 - sval;  // invert output
return sval;

Getting the code in the ATtiny

Now this may all be very well, but how to get the program in the ATtiny, as it has no bootloader? Well, there are several ways. One can use the Arduino IDE to generate the hexfile and then program that with either a parallelport programmer or a USBtiny programmer, or if one has an Arduino, the Arduino can be used as a programmer. Several websites have described this and I will refer to the procedure as explained by John Boxalin his blog.

In principle the method is as follows.

  • Connect the 6 pins between the Arduino and the ATtiny that make up the official in line programming header.
  • Add a specific ATtiny board file to yr IDE.
  • Load the Arduino with the ‘ArduinoISP’ sketch.
  • Then choose ‘ATtiny 85 (w/ Arduino as ISP)’ as your board.
  • Load the ‘Garden’ sketch and upload as usual.

Do I really need a microcontroller for this

Some people may wonder if perhaps even using an ATtiny for this is overkill? Well, ofcourse it is because what you are basically doing here is comparing two values. The value for a measured temperature (or humidity) with a set value and there are devices that have been used for doing exactly that for years already: Opamps, like the trusty 741:

opamp Obviously with this design it is harder to set a low and a high level (one can use two opamps for that) but that means it will keep the temperature (or humidity)  at a narrower level. For other possible op amp solutions see here and here

Using a microcontroller however has advantages over an op amp because it is easier to add functions (e.g. time) or look at things like ‘is the reservoir still full, won’t my pump run dry?’. With an op amp that means ‘extra parts’ (actually, that is not always necessary: Check here)