It’s been a while since I did anything productive with my Raspberry Pi 2, but my recent purchase of a Yucca made me think about how I could use it for something intelligent, like Making a soil moisture sensor with the Raspberry Pi 2. This post is really aimed at saving you a lot of time hunting around for all the information you need. I had to browse a tonne of sites to find all the bits and pieces, but eventually I got it all to work as I expected.

First of all, the hardware. I had some bits and pieces lying around already; mainly some connecting wires and a spare breadboard. The only two components I had to buy were:

  • The sensor itself, available from Amazon.
  • An MCP3008 analogue to digital converter, also available from Amazon.

Goals for a Soil Moisture Sensor

I had a few key things this soil moisture sensor project should deliver:

  1. It had to read the moisture level in a pot of soil.
  2. It should record the moisture level and time stamp in some useful format, like CSV.
  3. It should tell me, somehow, the readings as it makes them. Like a Tweet, etc.
  4. It should be simple enough for me to make!

Since I had to wait for the additional hardware to arrive, I set about building the Python script that was going to make this all happen. I knew I needed to find out how to manipulate CSV files, work with the date and timeinteract with Twitter, use the SPI interface of the Raspberry Pi, work with analogue sensors, and share files with other computers running Windows.


This is the Python script I came up with. I should point out that the articles linked previously in this post played a huge part in helping me to write this. Some bits I borrowed directly, and other bits modified or built upon. This script won’t work if you just copy and run it. You’ll need to follow the various guides to install and configure certain things, enable SPI, etc. but once you have, this should run.

#!/usr/bin/env python
import sys
import os
import datetime
import csv
import spidev
import time

#Open SPI bus
spi = spidev.SpiDev(),0)

# Function to read SPI data from MCP3008 chip
# Channel must be an integer 0-7
def ReadChannel(channel):
adc = spi.xfer2([1,(8+channel)<<4,0])
data = ((adc[1]&3) << 8) + adc[2]
return data

#Function to convert data into a standard range
def ConvertMoisture(data):
moist_reading = (data * 100) / float(1023)
moist_reading = round(moist_reading,1)
return moist_reading

#Set up CSV file for writing to
csv_out = open('readings.csv','a')
mywriter = csv.writer(csv_out, delimiter=',')

#Twitter details
from twython import Twython


i =

#Get the time and date
timestamp = i.strftime('%H:%M:%S')
date = i.strftime('%Y/%m/%d %H:%M:%S')

#Get the sensor data
moisture = ReadChannel(0) #Reads CH0 from the MCP3008 chip
moisture_level = ConvertMoisture(moisture) #Normalises the reading from 0-1023 to 0-100
moisture_level = str(moisture_level) #Converts from int to str for tweet.

#Optional testing loop to see realtime readings from sensor
#while True:
# moisture = ReadChannel(0)
# moisture_level = ConvertMoisture(moisture)
# print moisture_level
# time.sleep(0.5)

#Send tweet
api.update_status(status='@jamesbmarshall it is '+timestamp+', and my current moisture level is '+moisture_level+'.')

#Write-out new reading to CSV
data = [(date,moisture_level),]

for item in data:



Wiring Up

When it comes to wiring up the hardware, I found myself getting confused. One negative of the wonderful Pi community is that it’s not always clear when there’s different versions of the Pi being referenced. Most of what I found to work with was not specifically for the RPi 2, so I found these two images particularly helpful; one to compare the GPIO pins between the different Pi versions, and the other more detailed pinout for the GPIO on the RPi 2.

Next Steps

Now that the basic soil moisture sensor proof of concept works, it’s time to move to phase two. My next set of goals are:

  1. Convert the breadboard to veroboard as a more permanent solution.
  2. Build up some sample data for calibration of the sensor.
  3. Implement some thresholds in the code: overwatered, too dry, etc. so that the Tweets can say something more interesting like "It's time to water me!".
  4. Expose / inject the readouts into some kind of database (SQL Azure perhaps) so that I can use some machine learning to predict when the soil will dry out.
  5. Add more sensors for light and temperature to get a better picture of what's happening to the plant.