Pi Pico Soil Moisture Indicator

Pi Pico soil moisture sensor setup

Overview

A guide for creating a soil moisture indicator using Raspberry Pi Pico and CircuitPython to monitor indoor plant hydration levels with automatic sensor calibration.

What You'll Need

  • Raspberry Pi Pico
  • Sparkfun Soil Moisture Sensor
  • WS2812B (Neopixel) ring or strip
  • Solid core wire
  • Micro USB cable

Note: Alternative boards supporting CircuitPython (like Adafruit QTPy) work similarly.

Putting It Together

Wiring diagram

Circuit Connections

Raspberry Pi Pico pin assignments:

  • Pin 2: Neopixel data signal
  • Pin 7: Moisture sensor power
  • Pin 27: Moisture sensor analog signal
  • Pin 23: Moisture sensor ground
  • Pin 40: Neopixel power (USB direct)
  • Pin 38: Neopixel ground

Setup Instructions

  1. Solder components per circuit diagram
  2. Install CircuitPython on Raspberry Pi Pico
  3. Download CircuitPython library bundle
  4. Copy neopixel.mpy to lib folder
  5. Paste provided code into code.py

The Code

Completed moisture sensor in a plant pot

import time
import board
import neopixel
from analogio import AnalogIn
from digitalio import DigitalInOut, Direction, Pull

# how frequently to take readings
DELAY = 600

# Update this to match the number of NeoPixel LEDs connected to your board.
num_pixels = 16

# setup the moisture sensor power pin and turn it off by default
sensor_power = DigitalInOut(board.GP7)
sensor_power.direction = Direction.OUTPUT
sensor_power.value = False

# set the analog read pin for the moisture sensor
sensor_signal = AnalogIn(board.GP27)

# set up the noepixels
pixels = neopixel.NeoPixel(board.GP2, num_pixels, auto_write=False)
pixels.brightness = 0.2

# some variables for internal use, you shouldn't have to worry about them
calibrate_count = 0
auto_calibrate = True
SENSOR_MAX = 0
SENSOR_MIN = 9999

# set the neopixels to blue
for i in range(num_pixels):
    pixels[i] = (0,0,255)
pixels.show()

print("=============")
print("calibrating sensor")
print("=============\n\n")

while True:

    if auto_calibrate == True:

        sensor_power.value = True
        value = round(sensor_signal.value / 100)
        sensor_power.value = False

        print("reading:", value)

        if value > SENSOR_MAX:
            SENSOR_MAX = value
        if value < SENSOR_MIN:
            SENSOR_MIN = value

        calibrate_count += 1

        if(calibrate_count > 100):
            print("\n-------------------")
            print("MIN:", SENSOR_MIN)
            print("MAX:", SENSOR_MAX)
            print("-------------------\n")
            time.sleep(5)

            for i in range(num_pixels):
                pixels[i] = (0,0,0)
            pixels.show()

            auto_calibrate = False

        time.sleep(0.2)

    else:

        value = round(sensor_signal.value / 100)
        print("reading:", value)

        sensor_power.value = True

        percent = round(((value - SENSOR_MIN) / (SENSOR_MAX - SENSOR_MIN)) * 100)
        print("Percent:", percent)

        show_leds = round(100 / (100 / num_pixels) * percent / 100)
        print("leds to show:", show_leds)

        print((value, percent, show_leds))

        if(show_leds < 8):
            color = (255,0,0)
        else:
            color = (0,255,0)

        if(show_leds > num_pixels):
            show_leds = num_pixels

        if(show_leds <= 3):
            show_leds = num_pixels

        for i in range(num_pixels):
            pixels[i] = (0,0,0)

        for i in range(show_leds):
            pixels[i] = color

        pixels.show()

        time.sleep(DELAY)

        print("\n-------------------\n")

How to Use It

Upon powering up, the NeoPixel ring displays blue during calibration mode.

Calibration Process

The sensor requires calibration due to variations in water purity and soil mineral content. The device automates this:

  1. Ensure sensor gold fingers are completely dry
  2. Water plant to desired moisture level
  3. Plug Pico into power
  4. Insert sensor forks into soil after 5 seconds
  5. Ring fills with green at maximum moisture

Operation

  • Green lights: Adequate moisture
  • Red lights: Moisture dropping, approaching dry
  • All red: Critical dryness warning

Credits

Thanks to Adafruit for CircuitPython guidance, SparkFun for sensor documentation, and Raspberry Pi Foundation for the Pico microcontroller.