Plant Watering Machine with a Raspberry Pi
Building a useful machine doesn’t have to require complicated code or expensive equipment. With a Raspberry Pi and some basic hardware, you can keep your plants healthy and happy from anywhere in the world!
Follow this tutorial to learn how to set up an automatic plant watering system:
- Complete the physical assembly and wiring.
- Create and connect to the machine, and configure your machine’s components.
- Configure the ADC as a module from the registry.
- Write code utilizing the Viam Python SDK to control the plant watering robot.
You can also follow a simplified version of this tutorial in this video: it eliminates the need for the ADC and the breadboard, instead using the digital pin of the moisture sensor to get “high” and “low” readings and to turn a relay on and off. You can start with this simple version and then add the ADC to make your machine more accurate!
The tutorial uses the following hardware, but you can adjust it as needed:
- A Raspberry Pi 3 or later or Raspberry Pi 2 W, including an SD card and power supply
- A resistive soil moisture sensor
- A 5V mini water pump with clear vinyl tube
- A MCP3008 ADC
- A one channel relay switch
- A breadboard
- Assorted jumper wires, including two splicing connectors
- A planter box or flower pot
- A water container
- A screwdriver
Before starting this tutorial, follow the Raspberry Pi Setup Guide to prepare your machine to run viam-server
.
Your Pi must run a Viam-compatible operating system, and you must have SSH access.
Set up your plant watering robot
Before programming the machine, you need to physically set up the plant watering robot by wiring the different components together. You will set up the robot to receive signals from the resistive soil moisture sensor and signal to the peristaltic pump when it is time to pump water from the water container to the plant container.
Full wiring diagram
Refer back to this diagram as you complete the steps to wire your hardware. Disconnect your Pi from power while you wire.

Wire your ADC
The analog-to-digital converter (ADC) converts the resistive soil moisture sensor’s analog readings to digital signals that can be processed by your machine through GPIO pins.
Start by wiring your ADC to your machine.
Reference the following pinout diagram for your MCP3008 analog-to-digital converter:

Tip
The half circle shown in the pinout diagram above should be physically present on your ADC. Use this to orient the ADC to determine the location to insert your wires.
Insert the MCP3008 into your breadboard so that it bridges both sides of the center divider. Now you can use the breadboard points next to the MCP3008 to connect pins on the MCP3008 to your Raspberry Pi and other peripherals using jumper wires. Begin by connecting MCP3008 pins to the following physical pins on the Raspberry Pi:
MCP3008 ADC Pin | Raspberry Pi Physical Pin | GPIO | Function |
---|---|---|---|
DIN | 19 | 10 | MOSI |
DOUT | 21 | 9 | MISO |
CLK | 23 | 11 | SCLK |
CS/SHDN | 24 | 8 | SPI0 |
Tip
Raspberry Pis use two distinct pin numbering systems:
- Physical pin numbers correspond to physical positions on the header. Count from left to right, starting at the top-left corner when the Raspberry Pi is positioned with its Ethernet port facing downward.
- GPIO numbers refer to GPIO channel designations used in programming. For GPIO pin assignments, see the Raspberry Pi pinout diagram at pinout.xyz.
Next, connect the following MCP3008 pins to any point on the indicated rails on the breadboard:
MCP3008 ADC Pin | Breadboard rail |
---|---|
VDD | 5V power rail (red +) |
VREF | 5V power rail (red +) |
AGND | ground (blue -) |
DGND | ground (blue -) |
Finally, connect your breadboard rails to 5V power and ground on the Raspberry Pi:
Breadboard rail | Raspberry Pi Physical Pin | Function |
---|---|---|
Any point on 5V power rail (red +) | 4 | 5V power |
Any point on GND rail (blue -) | 34 | ground |
Wire your resistive soil moisture sensor
Next, wire your resistive soil moisture sensor to your Pi and ADC.
Reference this diagram of the blue module part of the sensor:
Start by connecting the female jumper wires at the end of the sensor prongs to the blue module where the diagram shown above is labeled “Connect with Probe.” You can connect either wire to either pin on the blue module.
Then, wire the rest of the pins on the module to any point on the indicated row or rails of the breadboard:
Moisture Sensor Pin | Breadboard points |
---|---|
A0 (Analog Signal Output) | row adjacent to CH0 |
VCC | 5V power rail (red +) |
GND | ground rail (blue -) |
Put the soil moisture sensor inside of the container holding your plant.
Wire your pump
Now, wire and power your pump and relay module to complete your hardware setup.
Tip
To connect jumper wires to the relay module:
- Use a screwdriver to loosen the screws on top of the pin gates on the relay module.
- Insert a jumper wire pin into the pin gate.
- Tighten the screws on top of the pin gates to fasten the jumper wires.
Connect the pump wires to the following physical pins on the relay and Raspberry Pi:
Pump Wire | Pin |
---|---|
positive | Relay module NO |
negative | Raspberry Pi pin 39 (ground) |
NO stands for normally open, which will keep the circuit open unless the pin is triggered.
Connect the relay module pins to the following physical pins on the Raspberry Pi:
Relay Pin | Raspberry Pi Physical Pin | Function |
---|---|---|
COM | 2 | 5V power |
DC+ | 1 | 3.3V power |
DC- | 14 | GND |
IN | 8 | GPIO 14 |
Program your plant watering machine
Now that your machine is fully wired, it’s time to configure the logic with Viam.
Enable SPI on your machine
Before you begin, ensure that the Serial Peripheral Interface (SPI) is enabled on your machine. This protocol allows your machine to communicate with the moisture sensor peripheral.
Connect your Raspberry Pi to power. SSH into your machine and run the following command:
sudo raspi-config
Once the raspi-config
interface is open, navigate to Interface Options:
Then, select SPI:
Now, select Yes to enable SPI:
Finally, select Finish.
Run the following command to reboot your machine and load your changes:
sudo reboot
Configure the components of your robot in the Viam app
Add a new machine in the Viam app.
On the machine’s page, follow the setup instructions to install viam-server
on the computer you’re using for your project.
Wait until your machine has successfully connected to the Viam app.
Then, navigate to the CONFIGURE tab of your new machine’s page in the app.
First, add your machine as a board component:
Click the + icon next to your machine part in the left-hand menu and select Component or service.
Select the board
type, then select the appropriate viam:raspberry-pi:pi
model (for example, viam:raspberry-pi:pi4
for Raspberry Pi 4).
Enter a name for your board and click Create.
This tutorial uses the name local
.
{
"components": [
{
"name": "local",
"model": "pi",
"api": "rdk:component:board",
"attributes": {},
"depends_on": []
}
]
}
Configure the ADC as a module from the registry
Resources refer to the different components and services Viam provides for robots to use.
Components refer to types of hardware, and each component’s built-in models
support the most common models of this hardware.
For example, the sensor component has an ultrasonic
model built in for the ubiquitous ultrasonic sensor.
However, there are many different types of sensors used for sensing different things across the Internet of Things. Although the resistive soil moisture sensor is not currently one of Viam’s built-in models, you can add an analog-to-digital-converter (ADC) as a module and use it to get readings from the moisture sensor.
A module provides one or more modular resources, which add resource types (components and services) or models that are not built into Viam. A module can be added to your machine from the Viam Registry.
The Viam Registry allows hardware and software engineers to collaborate on their projects by writing and sharing custom modules with each other. You can add a module from the Viam Registry directly from your machine’s CONFIGURE tab in the Viam app, using the + (Create) button.
To add the mcp300x-adc-sensor module to your machine, follow these steps:
Go to your machine’s CONFIGURE tab. Click the + icon next to your machine part in the left-hand menu and select Component or service.
Search for
mcp300x
and selectsensor / mcp300x
. Click Add module.Give your module a name of your choice. We used the name
sensor
.Click Create to add this module to your machine.
Find your module’s card on the CONFIGURE page. Copy the following JSON object into the configuration field.
{ "channel_map": { "moisture": 0 }, "sensor_pin": 8 }
sensor_pin
is the GPIO pin number of the machine’s pin you connected to the MCP300x chip: in this case, GPIO8
.
Save your config by clicking Save in the top right corner of the page.
On the sensor configuration panel, click on the TEST area to confirm you can get readings from your sensor.
This module allows you to get multiple readings at the same time from different channels of the ADC sensor.
Now that you have set up your machine, place your pump in the water cup, and the output tube in your plant pot!
Install the Python SDK
Make sure any packages on your Pi are up to date, while connected to your Pi with SSH run:
sudo apt update
sudo apt upgrade
Then run the following command to create and activate the virtual environment: If you want to read more on virtual environments, check out the documentation.
python3 -m venv .venv
source .venv/bin/activate
Make sure you have pip
installed for Python 3:
pip --version
If not, run the following command:
sudo apt install python3-pip
Run the following command to install the SDK:
pip3 install viam-sdk
Add Python control code
Follow these instructions to start working on your Python control code:
Navigate to your machine’s page in the Viam app, and click on the CONNECT tab and the Code sample page.
Select Python as the language.
Follow the instructions shown under step 1 on that page to install the SDK.
Then, under step 2 on that page, click the copy icon to copy the generated code sample, which establishes a connection with your robot when run.
To show your machine’s API key in the sample code, toggle Include API key.
Caution: Keep your API key and machine address safe
We strongly recommend that you add your API key and machine address as an environment variable. Anyone with these secrets can access your machine, and the computer running your machine.
Paste this code sample into a new file on your machine.
Name the file
plant-watering-robot.py , and save it.
Run the following commands on your machine to create and open the file:
source .venv/bin/activate
touch plant-watering-robot.py
nano plant-watering-robot.py
Now, add code into
To start, add your system logic code into the main()
function of the program.
Use the Viam board and sensor API methods to read from the moisture sensor and control the pump’s voltage from a GPIO pin.
To access components from the machine, use the following code snippet:
# Note that this name, `sensor`, is defined when you add the mcp300x module
sensor = Sensor.from_robot(robot=robot, name='sensor')
# Note that this name, `local`, is defined when you add the board
local = Board.from_robot(machine, "local")
Then, add a control loop that runs continuously, similar to the following example:
# this level depends on your specific setup, replace after testing
DRY = 600
# amount of time to pump water to plant, in seconds; depends on planter size
WATERING_TIME = 15
# time between moisture checks, in seconds
MOISTURE_CHECK_INTERVAL = 60
# delay after watering before we check moisture level again, in seconds
SOAK_TIME = 600
# GPIO number of pin that toggles the relay
MOTOR_CONTROL_GPIO = "8"
while True:
# Get the moisture sensor's readings
readings = await sensor.get_readings()
soil_moisture = readings.get("moisture")
# If the moisture reading indicates moisture, pump water
if (soil_moisture > DRY):
print("plant is thirsty! watering")
# Get the GPIO pin connected to the IN pin on the relay
motor_control_pin = await local.gpio_pin_by_name(
name=MOTOR_CONTROL_GPIO)
# Run the pump
# Set pin to high to close the relay, connects power to the pump
await motor_control_pin.set(high=True)
# Wait for water to pump
print("it's watering time")
time.sleep(WATERING_TIME)
# Stop the pump
# Set pin to low to open the relay, removes power from the pump
await motor_control_pin.set(high=False)
# Wait an hour to let the soil soak
print("waiting a little bit for the water to soak in")
time.sleep(SOAK_TIME)
# wait 60 seconds between checks
print("waiting a little bit for the water to soak in")
time.sleep(MOISTURE_CHECK_INTERVAL)
Tip
You must import time
at the top of sleep()
!
Test motor
On your machine’s CONTROL page in the Viam app, expand the TEST panel for your board component. You should see a panel that allows you to control individual GPIO pins:

In the Pin field, enter 8
to write to physical pin 8.
To activate the motor and begin pumping water, use the State control to select High, then click Set.
You should hear your motor activate and it should begin pumping water if immersed.
To turn off the motor and stop pumping water, use the State control to select Low, then click Set.
Test moisture sensor
On your machine’s CONTROL page in the Viam app, expand the TEST card for your mcp300x
sensor module to see a live observed value from your moisture sensor.
Test your sensor by putting it in air, water, and soils containing different amounts of moisture.
Use these values to determine an appropriate value for the DRY
variable in your setup.
Save control code
Save
sudo python3 plant-watering-robot.py
Next steps
Now that you have created your automatic plant watering system with a resistive soil moisture sensor, you can easily use Viam to automate other aspects of your garden. For example, you could add a light sensor or a temperature sensor, and get readings from other channels of the MCP3008!
You could set up data capture and graph your sensor data, or create your own custom Typescript dashboard to display your sensor data.
If you build something based on this please share it in our Community Discord - we’d love to see it.
Was this page helpful?
Glad to hear it! If you have any other feedback please let us know:
We're sorry about that. To help us improve, please tell us what we can do better:
Thank you!