Using moisture sensor HW-103 with Raspberry Pi and MCP3008

Instead of connecting the sensor VCC to Raspberry Pi 5V or 3,3V, use a GPIO pin as DigitalOutput to switch on the sensor logics just during measurement. This saves one leg on the curcuit board from massive oxidation. Because it's dug into the soil, your are effectively causing unintentional electrolysis when the circuit is powered on.

What you need

Moisture Sensor (mine is labeled HW-103)
MCP3008 to be able to read analog values
Raspberry Pi with 40 pin GPIO with hardware SPI enabled
Python 3
Gpiozero library for Python 3

Wire it up

First of all, enable Hardware SPI in raspi-config. Then hook up the Raspberry Pi, sensor and MCP3008 like this (I like drawing circuits and connections a little more in the comic sans way):

You can also read more about how to connect it and read values here:

Write some Python3 code

This is a sample test code. I've gotten various analog readings from the probe, maybe it's not the most stable, or the MCP3008 is not the best. I don't know. But it seems like we need some pause (200ms) before reading the values, after power on. Also note the shebang line, this is written in Linux, the file needs to be executable.

Or, just download the code here:

#!/usr/bin/python3 from gpiozero import DigitalOutputDevice, MCP3008 from datetime import datetime from time import sleep def setup_connected_sensors(): sensors = { 'HW-103-0': { 'Description': 'Moisture Sensor', 'Power': DigitalOutputDevice(18), 'Analog': MCP3008(channel=0) }} return sensors # Setup probe_interval = 15 # List of all sensors sensor_list = setup_connected_sensors() # Loop and measure while True: for sensor in sensor_list: if (sensor_list[sensor]['Power'] != None): sensor_list[sensor]['Power'].on() sleep(0.2) print("%s %s (%s): Analog.value:%s, Analog.raw_value:%s, Percent:%s, Percent(inv):%s" %(, sensor, sensor_list[sensor]['Description'], (sensor_list[sensor]['Analog'].value if sensor_list[sensor]['Analog'] != None else None), (sensor_list[sensor]['Analog'].raw_value if sensor_list[sensor]['Analog'] != None else None), int(sensor_list[sensor]['Analog'].value*100) if sensor_list[sensor]['Analog'] != None else None, int(100-(sensor_list[sensor]['Analog'].value*100)) if sensor_list[sensor]['Analog'] != None else None)) if (sensor_list[sensor]['Power'] and sensor_list[sensor]['Power'].value == 1): sensor_list[sensor]['Power'].off() sleep(probe_interval)

So, what we do is we hook up the sensor VCC (3,3V) to a digital output pin on the Raspberry Pi GPIO instead. When this pin is HIGH, it outputs 3,3V. So using a pin as a DigitalOutputDevice we can just set this to HIGH using .on() and .off().

Then we read the analog value from MCP3008(channel=0) (be sure the AO on the HW-103 is connected to pin 1 on the MCP3008) and present it in different ways.

After reading, we then power off the pin and sensor and sleep some time before starting again.

A better way to probe

Another way of measuring the soil moisture (or any moisture) is using a capacitive probe instead, like this one:

With this you have no metal parts that come into contact with the soil thus the sensor will not corrode or oxidize.

Read more in this thread on Stackexchange:

An (almost) new probe:

An oxidized probe:

My breadboard mess around the MCP3008:

(c) 2020 Rolf Johansson