Installing the Project Code

Download a zip of the project by clicking Download Project Bundle below.

After unzipping the file, copy to the CIRCUITPY drive which appears when the Feather is connected to your computer via a USB cable.

# SPDX-FileCopyrightText: 2021 Eva Herrada for Adafruit Industries
# SPDX-License-Identifier: MIT

import time

import board
from digitalio import DigitalInOut
import adafruit_connection_manager
from adafruit_esp32spi import adafruit_esp32spi
from adafruit_esp32spi import adafruit_esp32spi_wifimanager
import neopixel
import adafruit_minimqtt.adafruit_minimqtt as MQTT
from adafruit_io.adafruit_io import IO_MQTT
from adafruit_seesaw.seesaw import Seesaw
import busio

# Used to make sure that the Adafruit IO Trigger is only run once when the moisture value is below
# the desired threshold, set in MIN
LOW = False
# The minimum moisture value. If the value is below this number, it will activate the Adafruit IO
# trigger. This number should match the number you set in your Adafruit IO trigger. Feel free
# to mess around and try out different moisture values as how wet this actually is can vary a lot
# depending on where the sensor is and the soil in the pot.
MIN = 500

# Set up moisture sensor with seesaw
i2c = board.I2C()  # uses board.SCL and board.SDA
# i2c = board.STEMMA_I2C()  # For using the built-in STEMMA QT connector on a microcontroller
seesaw = Seesaw(i2c, addr=0x36)

# Get wifi details and more from a file
    from secrets import secrets
except ImportError:
    print("WiFi secrets are kept in, please add them there!")

# Set up WiFi
esp32_cs = DigitalInOut(board.D13)
esp32_ready = DigitalInOut(board.D11)
esp32_reset = DigitalInOut(board.D12)

spi = busio.SPI(board.SCK, board.MOSI, board.MISO)
esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset)
status_light = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness=0.2)
wifi = adafruit_esp32spi_wifimanager.ESPSPI_WiFiManager(esp, secrets, status_light)

# Define callback functions which will be called when certain events happen.
# pylint: disable=unused-argument
def connected(client):
    # This method is called when the client connects to Adafruit IO

def subscribe(client, userdata, topic, granted_qos):
    # This method is called when the client subscribes to a new feed.
    print("Subscribed to {0} with QOS level {1}".format(topic, granted_qos))

def message(client, feed_id, payload):
    # This method is called when a feed receives a new message
    print("Feed {0} received new value: {1}".format(feed_id, payload))

# Connect to WiFi
print("Connecting to WiFi...")

pool = adafruit_connection_manager.get_radio_socketpool(esp)
ssl_context = adafruit_connection_manager.get_radio_ssl_context(esp)

# Initialize a new MQTT Client object
mqtt_client = MQTT.MQTT(

# Initialize an Adafruit IO MQTT Client
io = IO_MQTT(mqtt_client)

# Connect the callback methods defined above to Adafruit IO
io.on_connect = connected
io.on_subscribe = subscribe
io.on_message = message

# Connect to Adafruit IO
print("Connecting to Adafruit IO...")
plant_feed = "plant"


while True:
    # read moisture level through capacitive touch pad
    touch = seesaw.moisture_read()

    # read temperature from the temperature sensor
    temp = seesaw.get_temp()

    if touch < MIN:
        if not LOW:
            io.publish(plant_feed, touch)
        LOW = True

    elif touch >= MIN and time.time() - START > 10:
        io.publish(plant_feed, touch)
        print("published to Adafruit IO")
        START = time.time()
        LOW = False

    print("temp: " + str(temp) + "  moisture: " + str(touch))

There are also a few libraries you'll need to copy over to the Feather:

  • adafruit_esp32spi/
  • adafruit_requests/
  • adafruit_minimqtt/
  • adafruit_io/
  • adafruit_seesaw/
  • adafruit_requests.mpy
  • neopixel.mpy

Your file should at the very least have values for the fields ssidpasswordtimezoneaio_username, and aio_key. Make sure to copy it over to CIRCUITPY as well.

After you've done all that, this is what your CIRCUITPY drive should look like.


Luckily there isn't really any wiring for this project. Put the Feather RP2040 and AirLift FeatherWing on the FeatherWing Doubler, then plug the STEMMA to STEMMA QT cable into both the Feather RP2040 and the moisture sensor.


Now that you've put the code on the Feather, plug the STEMMA cable in and put the sensor in your plant. I've found it works better if you put one side of the sensor against the edge of the pot.

Code Usage

This project is rather easy to use. After you've set it up, put the sensor into the pot against the side, and plugged it in, it will send you a message if the moisture level is under 500, or whatever value you selected. If it is under that value, it won't send any more messages to Adafruit IO so that you don't get pinged every second until you water your plant.

Then, if the moisture value is above your value, it will send a message to Adafruit IO with the moisture value which shouldn't make the action send a webhook, and if the number dips below 500 again it will send another message that will make the action go off.

This guide was first published on Jun 02, 2021. It was last updated on Jul 24, 2024.

This page (Code the Smart Plant) was last updated on Jul 24, 2024.

Text editor powered by tinymce.