HomeTutorials › Raspberry Pi Irrigation Control – Part 2

Raspberry Pi Irrigation Control – Part 2

In the first part of this tutorial we looked at each of the connections available on the board (and if using the bare bones version, soldered everything in place). Now that we have everything ready for power we can work on the software / coding side of the project. In part two of this tutorial we will boot up the Raspberry Pi, do some initial configuration of the Raspbian operating system, install Python libraries for a few of the sensors, and write some basic Python code to trigger each solenoid and read and display the data from each of the sensors. The Python code will be quite long, but we have broken it down into smaller steps. As always, if you have any questions, feel free to post at the bottom of the page.

Operating System:
Before we get started, you should have a microSD card pre-installed with Raspbian. We are using the installation image dated June 27, 2018. Using a different version than this *could* require additional steps during the installation process – so for this reason we recommend using the exact version we are. At the time of writing this tutorial, this is the most current version available from the Raspberry Pi Foundation and it can be found here.

The Parts Needed:

parts

This tutorial requires several items:

  • A completed assembly from Part 1 of this tutorial set
  • 1 x microSD card (with Raspbian 2018-06-27)
  • 1 x Pi 3 / 3+ capable power supply
  • A USB Keyboard & Mouse
  • A HDMI compatible monitor
  • Internet access

Step 1 – Boot Up

We are going to start by inserting the microSD card with our operating system pre-installed into the Pi. Your keyboard, mouse and monitor should also be connected at this time. Depending on which power option you went with in your project, plug in your power supply(s).

Once the Pi has done its initial boot of the operating system you should arrive at a desktop. A dialogue should appear for initial configuration – we will take care of this in the next step.

Step 2 – OS Configuration

As of this version of Raspbian, most initial setup can be done by following the dialogue that pops up on first boot up. However, we do need to set up a few additional things once this is initial configuration is completed. Follow through the initial setup, if prompted to reboot – go ahead and do that as well.

Once all of that has been completed, we can go ahead and configure a few more things. Click the Raspberry Logo in the top left corner, scroll down to Preferences, and select “Raspberry Pi Configuration”.

On the first tab you can change your overscan settings. If you are using a computer monitor, you may want to disable the overscan setting to remove the black bars on the sides of the screen.

On the second tab we are going to want to enable the I2C and 1-Wire interfaces. These are the two interfaces our sensors are using in this project.

If prompted to reboot, click yes. Once the Pi boots back up we can proceed.

Step 3 – Internet Connectivity

Step3

Before we can install any of the libraries or make any of the sensors work we need internet connectivity. If you are using WiFi, this was probably already set up during the initial configuration. If it isn’t working, or you skipped that step, it can be accessed by clicking the connectivity logo (located beside the Volume control in the top right corner of the screen).

Ethernet is as simple as plugging it into the Pi – if you are planning to use ethernet, go ahead and plug this in if you haven’t already.

Step 4 – Terminal

Step4

Now that all of the basic configuration is done, we can get on with installing the software libraries needed to read each of the sensors. These libraries of code are going to take a lot of the hard work out of reading the sensors. We are going to install these using the “Terminal” , in the bar at the top of the screen, click the black square logo, and this window should pop up:

Step 5 – Adafruit Python GPIO Library

Step5

The first items to install are the Adafruit Python GPIO Library and the Adafruit Blinka Library. To install these we will type a series of commands into the terminal window we just opened up.

Run each of these commands (in order!) by typing them in and hitting enter:

sudo apt-get update

sudo pip3 install --upgrade setuptools

pip3 install RPI.GPIO

pip3 install adafruit-blinka

Step 6 – ADS1x15 Library

Next, we are going to set up the ADS1015 Analog to Digital chip. Adafruit has built an easy to use library for this series of Analog to Digital converters. We will use this to read the any analog sensors connected. To install the library, type the following command into the Terminal:


sudo pip3 install adafruit-circuitpython-ads1x15

Step 7 – DS18B20

step10

Now it is time to set up the DS18B20 temperature sensor. The setup for this sensor is a bit different; the past two sensors both used the I2C bus, the DS18B20 uses 1-Wire. Enter the following commands in the terminal:

cd

sudo modprobe w1-gpio

sudo modprobe w1-therm

cd /sys/bus/w1/devices

ls

Since the temperature sensor will be listed in the devices folder, we will want to see everything in that folder. The last command “ls” will display the contents of the folder in the window. Our DS18B20 shows up with an address of 28-0316853d8fff – but each sensor has a unique ID so your number will not match the image!

Step 8 – Test Your DS18B20

set11

Time to get a reading from the DS18B20 sensor! Enter the following command with your sensor ID in place of *sensor ID*

cd *sensor ID*

Now we can pull a temperature from it by entering the following command:

cat w1_slave

Not as easy to read as the ADC, but the information should be there. The temperature is located in the second line, take the number given and divide by 1000 to get the temperature in degrees Celsius.

Step 9 – DS18B20 Library

Since the DS18B20 isn’t the easiest sensor to read directly in Python, we will be installing one last library to make it a little more straight forward. In the terminal type the following commands:

cd

sudo apt-get install python3-w1thermsensor

This will make things quite a bit easier once we start writing some code.

Step 10 – Python

step10

Now we are getting somewhere! All of the complex sensors are sending back data so lets write some basic python code to poll each of the sensors and report back every 5 seconds. We aren’t going for award winning code here, just something easy to understand for those relatively new to Python.

We want to program in Python 3 so type the following command in the terminal and hit enter:

idle3

Alternatively, Python 3 can be found by clicking the Raspberry Button in the top left. Under programming you will find a shortcut. Either way, A new window should have opened for the Python 3 Shell. We are now done with the terminal window so it can be minimized or moved out of the way (but don’t close it!).

Step 12 – Getting Ready

In the Python Shell window we just opened, click “File” and “New File” to start a new Python file. This will open another window that we will write all of our code in.

Programing a Raspberry Pi to read sensors and control outputs can be done any number of ways. We are going to try and keep this as easy as possible using plain Python code and a simplistic program that runs all the time. But before we get into that, lets write some basic code to test read the sensors and try out our solenoid drivers.

Step 13 – Starting The Code

Before we can read any of the sensors, we will need to create the basic framework of the program. This means we need to import the time library, create our loop, and set the interval we want to pause the code each time the loop has completed. For those unfamiliar with Python, note that the white spaces (tabs and spaces) are very important in this language so be sure to format exactly as shown in the example.


import time

interval = 5  #How long we want to wait between loops (seconds)


while True:

    time.sleep(interval)

Libraries are added to the project using the import command. On the first line we are importing the time library. On line 3 we define a variable to store the length of time in seconds that we want to sleep the program during each loop of the code. Next, we want to create the loop itself – in Python this can be done in a variety of ways; “While true:” works well. Note that when you press “Enter” the next line becomes indented. Finally, on line 8 we “sleep” or pause our program using the variable we set above.

Note: Because we are going to be adding a lot of code over the next few steps, each new line we add will be highlighted in the example code and the line number will correspond to notes below the code.

Step 14 – Read The Temperature

During the set up we installed a bunch of libraries to make this program a lot easier to write. We are going to use one of these libraries right now to read the DS18B20 temperature sensor. In these next bits of codewWe are going to import the DS18B20 library, set up the sensor, read the sensor, and print the result.


import time
from w1thermsensor import W1ThermSensor

ds18b20 = W1ThermSensor()

interval = 5  #How long we want to wait between loops (seconds)

while True:

    time.sleep(interval)

    #Pull Temperature from DS18B20
    temperature = ds18b20.get_temperature()

    #Print the results
    print( 'Temperature: ' , temperature)

  • (2) Similar to the time library, we import the w1Thermsensor library
  • (4) Next we create our temperature sensor object and give it a name
  • (13) Down in the loop we get the temperature from the sensor and store it in a variable named “temperature”
  • (16) And finally print the result using the print command

Let’s try it out – press “F5” and it should prompt you to save it. After saving it should run, and in the Python Shell window you should see the temperature appear after a 15 second wait. It will continue to post an updated temperature every 15 seconds. This can be stopped by pressing “Ctrl + C”.

Step 15 – Read The ADC (Soil Moisture)

If you are using one of the SparkFun Soil Moisture Sensors (or any other analog sensor) reading the ADC will be the next step. Again, we are going to import the library, set up the sensor, and read the results. Unlike all of the past sensors, the ADC does not simply spit out exactly what we want to know. Instead, it gives us a number relative to the sensor reading that we can then interpret. For the soil moisture sensor, the higher the number we receive, the greater the moisture content. With many analog sensors, it will be up to the end user to determine how that relates to what they are measuring. This may require tweaking, and we will address this later when writing the control code. For now, we will just spit out the data and see what it says!


import time
from w1thermsensor import W1ThermSensor

import board
import busio
i2c = busio.I2C(board.SCL, board.SDA)

import adafruit_ads1x15.ads1015 as ADS
from adafruit_ads1x15.analog_in import AnalogIn

ds18b20 = W1ThermSensor()

ads = ADS.ADS1015(i2c)
ads.gain = 1

interval = 5  #How long we want to wait between loops (seconds)

while True:

    time.sleep(interval)

    #Pull Temperature from DS18B20
    temperature = ds18b20.get_temperature()

    #Measure Analog Input 0 
    chan = AnalogIn(ads, ADS.P0) #ADS.P1 , P2, P3 for channels 1, 2, 3
    val = chan.value #Pull the raw ADC data from Channel 0

  

    #Print the results
    print( 'Temperature: ' , temperature)
    print( 'Soil Moisture: ' , val)
    print( ' ')


  • (4-9) we import the Adafruit_ADS1x15 library – this one is a little different as it is using I2C so we have to set that up as well
  • (13) Next we create our ADC object and give it a name
  • (14) Set the gain on the ADC
  • (26) Get the data from ADC channel 0 and store it in the “chan” variable
  • (27) Pull the raw ADC reading and store it in a new variable, “val”
  • (33) Print the results
  • (34) Print an extra blank line to keep things separated

Step 16 – Flow Sensor

This sensor is a simple digital input on the Pi, this doesn’t have a fancy chip to read or anything of the sort. The flow sensor is effectively a magnet and a small magnetic switch. As the sensor spins the magnet moves past a switch, causing it to close. Each revolution represents approximately 2.25mL of fluid so we just need to count how many times this switch it is opening and closing over a period of time to figure out how much water has flowed through.

The Pi has an easy way of monitoring this sort of thing. Even though we have paused the entire program for a period of 5 seconds, we can create a background process that will still watch for changes in this pin and keep count while the main code is paused.

So lets get started: First we need to import the Raspberry Pi GPIO library, set up the pin we are using, and create the background process that monitors the pin. We will then calculate the windspeed and, finally, print the result.


import time
from w1thermsensor import W1ThermSensor

import board
import busio
i2c = busio.I2C(board.SCL, board.SDA)

import adafruit_ads1x15.ads1015 as ADS
from adafruit_ads1x15.analog_in import AnalogIn

import RPi.GPIO as GPIO

ds18b20 = W1ThermSensor()

ads = ADS.ADS1015(i2c)
ads.gain = 1

interval = 5  #How long we want to wait between loops (seconds)
waterTick = 0   #Used to count the number of times the flow input is triggered

#Set GPIO pins to use BCM pin numbers
GPIO.setmode(GPIO.BCM)

#Set digital pin 24 to an input
GPIO.setup(24, GPIO.IN) 

#Event to detect flow (1 tick per revolution)
GPIO.add_event_detect(24, GPIO.FALLING) 
def flowtrig(self):
    global waterTick
    waterTick += 1

GPIO.add_event_callback(24, flowtrig)

while True:

    time.sleep(interval)

    #Pull Temperature from DS18B20
    temperature = ds18b20.get_temperature()

    #Measure Analog Input 0 
    chan = AnalogIn(ads, ADS.P0) #ADS.P1 , P2, P3 for channels 1, 2, 3
    val = chan.value #Pull the raw ADC data from Channel 0

    waterFlow = waterTick * 2.25
    waterTick = 0

    #Print the results
    print( 'Temperature: ' , temperature)
    print( 'Soil Moisture: ' , val)
    print( 'Flow Rate: ' , waterFlow)
    print( ' ')




  • (11) Just like the other libraries, we import the GPIO library.
  • (19) Create a variable to store the number of times the flow sensor pin is triggered
  • (22) Set the GPIO pins to use Broadcom’s pin numbering
  • (25) Set pin 24 to be an input
  • (28-33) Create a background process to keep track of how many times pin 24 transitions from HIGH to LOW and, each time it does, add 1 to the count
  • (46) Convert number of revolutions to mL of flow (based on 1 revolution = 2.25mL)
  • (47) Reset our counter
  • (52) Print the result

Once again, feel free to test the code again with the “F5” key. Blowing into the liquid flow sensor will make it spin and should give you a reading!

Step 17 – Controlling The Solenoids

Each of the solenoids are controlled by a MOSFET , which is in turn, controlled by a GPIO pin from the Raspberry Pi. Turning on these solenoids is as easy as turning on a digital output. We have 6 driver circuits here so, for now, we will just turn each one on for a half second to make sure everything is working.


import time
from w1thermsensor import W1ThermSensor

import board
import busio
i2c = busio.I2C(board.SCL, board.SDA)

import adafruit_ads1x15.ads1015 as ADS
from adafruit_ads1x15.analog_in import AnalogIn

import RPi.GPIO as GPIO

ds18b20 = W1ThermSensor()

ads = ADS.ADS1015(i2c)
ads.gain = 1

interval = 5  #How long we want to wait between loops (seconds)
waterTick = 0   #Used to count the number of times the flow input is triggered

#Assign channels to variables to keep track of them easier (these BCM pin numbers were listed in part 1 of the tutorial)
s1 = 13
s2 = 16
s3 = 19
s4 = 20
s5 = 26
s6 = 21

#Set GPIO pins to use BCM pin numbers
GPIO.setmode(GPIO.BCM)

#Set digital pin 24 to an input
GPIO.setup(24, GPIO.IN) 

#Set solenoid driver pins to outputs:
GPIO.setup(s1, GPIO.OUT) #set Solenoid 1 output 
GPIO.setup(s2, GPIO.OUT) #set Solenoid 2 output
GPIO.setup(s3, GPIO.OUT) #set Solenoid 3 output 
GPIO.setup(s4, GPIO.OUT) #set Solenoid 4 output
GPIO.setup(s5, GPIO.OUT) #set Solenoid 5 output 
GPIO.setup(s6, GPIO.OUT) #set Solenoid 6 output


#Event to detect flow (1 tick per revolution)
GPIO.add_event_detect(24, GPIO.FALLING) 
def flowtrig(self):
    global waterTick
    waterTick += 1

GPIO.add_event_callback(24, flowtrig)

while True:

    time.sleep(interval)

    #Pull Temperature from DS18B20
    temperature = ds18b20.get_temperature()

    #Measure Analog Input 0 
    chan = AnalogIn(ads, ADS.P0) #ADS.P1 , P2, P3 for channels 1, 2, 3
    val = chan.value #Pull the raw ADC data from Channel 0

    waterFlow = waterTick * 2.25
    waterTick = 0

    #Test Solenoids by turning each on for a half second
    GPIO.output(s1, GPIO.HIGH) #turn solenoid 1 on
    time.sleep(0.5) #Wait for a half second
    GPIO.output(s1, GPIO.LOW) #turn solenoid 1 off
    time.sleep(0.5)

    GPIO.output(s2, GPIO.HIGH) #turn solenoid 2 on
    time.sleep(0.5) #Wait for a half second
    GPIO.output(s2, GPIO.LOW) #turn solenoid 2 off
    time.sleep(0.5)

    GPIO.output(s3, GPIO.HIGH) #turn solenoid 3 on
    time.sleep(0.5) #Wait for a half second
    GPIO.output(s3, GPIO.LOW) #turn solenoid 3 off
    time.sleep(0.5)

    GPIO.output(s4, GPIO.HIGH) #turn solenoid 4 on
    time.sleep(0.5) #Wait for a half second
    GPIO.output(s4, GPIO.LOW) #turn solenoid 4 off
    time.sleep(0.5)

    GPIO.output(s5, GPIO.HIGH) #turn solenoid 5 on
    time.sleep(0.5) #Wait for a half second
    GPIO.output(s5, GPIO.LOW) #turn solenoid 5 off
    time.sleep(0.5)

    GPIO.output(s6, GPIO.HIGH) #turn solenoid 6 on
    time.sleep(0.5) #Wait for a half second
    GPIO.output(s6, GPIO.LOW) #turn solenoid 6 off
    time.sleep(0.5)

    #Print the results
    print( 'Temperature: ' , temperature)
    print( 'Soil Moisture: ' , val)
    print( 'Flow Rate: ' , waterFlow)
    print( ' ')




  • (21-27) Set a variable for each solenoid channel to give them a more relevant name. These BCM pin numbers were listed in part 1 of the tutorial
  • (35-41) Set each of the solenoid control pins to outputs
  • (66-95) Test each solenoid by triggering it on, hold for a half second, shut it off, hold for half second… and then on to the next on

Once again, feel free to test the code again with the “F5” key. If you have your 12V solenoid power source connected to the 12V power terminal on the board, as each solenoid triggers a red LED will light up!

Step 18 – All Done!

Alright, now we have confirmed everything is working and we have written enough code to control / read each of the different functions available from the board. In Part 3 of this tutorial series we will be making this much more useful. We will take what we learned and turning it into a program that will trigger the solenoids at pre-defined times for pre-defined durations based on a schedule. We will also send an email notification when it has started, and once again when it has completed. Stay Tuned!

Have A Question?
If you have any questions, or need further clarification please post in the comments section below; this way future users of this tutorial can see the questions and answers!

Parts Used In This Tutorial:

Leave a Reply