When exploring practical raspberry pi pico projects, moving from blinking LEDs to networked home automation is the biggest leap. The Raspberry Pi Pico W, featuring the RP2040 microcontroller paired with an Infineon CYW43439 Wi-Fi chip, is perfectly suited for low-power, always-on sensor nodes. This guide walks through building a Wi-Fi-enabled soil moisture monitor that reads analog data and publishes it to an MQTT broker for integration with Home Assistant or Node-RED.
Estimated Time: 45 minutes
Estimated Cost: $12 - $15 USD
Project Spec Sheet & Parts List
The most common mistake in beginner raspberry pi pico projects involving soil is using resistive moisture sensors. Resistive probes pass current directly through the soil, causing rapid electrolytic corrosion that destroys the probes within a week. We use a capacitive sensor instead, which measures the dielectric permittivity of the soil without exposing bare metal to the elements.
| Component | Exact Variant / Model | Approx. Cost | Technical Notes |
|---|---|---|---|
| Microcontroller | Raspberry Pi Pico W (with headers) | $6.00 | Must be the 'W' variant for CYW43439 Wi-Fi. RP2040 dual-core Cortex-M0+ @ 133MHz. |
| Moisture Sensor | Capacitive Soil Moisture Sensor v1.2 | $2.50 | Outputs analog voltage (0-3.3V). Do not buy the resistive fork-style probes. |
| Display (Optional) | 0.96 inch SSD1306 I2C OLED | $3.50 | Address 0x3C. Strictly 3.3V logic compatible. |
| Wiring | 22 AWG solid core jumper wires | $2.00 | Use distinct colors for VCC (Red), GND (Black), SDA/SCL (Blue/Yellow). |
Pin Mapping & Wiring Guide
Proper pin assignment is critical. The Pico W's ADC0 is tied to GPIO 26. The I2C0 bus defaults to GP4 (SDA) and GP5 (SCL), but we will explicitly map it to GP0 and GP1 to keep the breadboard layout clean. Note that the Pico W handles its onboard LED differently than the original Pico; it is routed through the Wi-Fi chip and requires the string 'LED' rather than an integer pin number.
| Pico W Pin | Function | Sensor / Module Pin |
|---|---|---|
| 3V3(OUT) (Pin 36) | Power (3.3V) | VCC (Sensor & OLED) |
| GND (Pin 38) | Ground | GND (Sensor & OLED) |
| GP26 / ADC0 (Pin 31) | Analog Input | AOUT (Soil Sensor) |
| GP0 (Pin 1) | I2C0 SDA | SDA (OLED) |
| GP1 (Pin 2) | I2C0 SCL | SCL (OLED) |
Wiring Steps:
- Place the Pico W across the center trench of your solderless breadboard.
- Connect the 3.3V and GND rails on both sides of the breadboard to the Pico's Pin 36 and Pin 38.
- Wire the capacitive sensor's AOUT pin to GP26. Ensure the sensor's VCC is tied to the 3.3V rail, not the 5V VBUS pin.
- Wire the OLED display SDA to GP0 and SCL to GP1.
- Double-check all connections with a multimeter in continuity mode before applying power.
Complete MicroPython Firmware
The following MicroPython script targets the Raspberry Pi Pico W specifically. It connects to a 2.4GHz Wi-Fi network, reads the analog moisture level, maps it to a percentage, and publishes the payload to an MQTT broker. Error handling is included to catch network drops and I2C faults.
Note: This code uses the standard MicroPython umqtt.simple library. Ensure you have copied umqtt/simple.py to your Pico's lib folder, or use Thonny's package manager to install micropython-umqtt.simple. For authoritative syntax references, consult the official MicroPython machine.I2C documentation.
import network
import time
import json
from machine import Pin, ADC, I2C
from umqtt.simple import MQTTClient
# --- PIN DEFINITIONS & CONFIGURATION ---
# Pico W onboard LED is controlled via the CYW43439 Wi-Fi chip
LED_PIN = 'LED'
ADC_PIN = 26
I2C_SDA = 0
I2C_SCL = 1
WIFI_SSID = 'Your_2.4GHz_Network'
WIFI_PASS = 'Your_Password'
MQTT_BROKER = '192.168.1.50'
MQTT_TOPIC = b'home/garden/plant1/moisture'
# Calibration values for Capacitive Sensor v1.2 (adjust based on your readings)
DRY_VALUE = 58000 # ADC reading when completely dry
WET_VALUE = 22000 # ADC reading when submerged in water
led = Pin(LED_PIN, Pin.OUT)
adc = ADC(Pin(ADC_PIN))
# Initialize I2C for optional OLED (Error handling included)
try:
i2c = I2C(0, sda=Pin(I2C_SDA), scl=Pin(I2C_SCL), freq=400000)
print(f'I2C devices found: {i2c.scan()}')
except Exception as e:
print(f'I2C Init Failed: {e}')
def connect_wifi():
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
if not wlan.isconnected():
print(f'Connecting to {WIFI_SSID}...')
wlan.connect(WIFI_SSID, WIFI_PASS)
timeout = 15
while not wlan.isconnected() and timeout > 0:
led.toggle()
time.sleep(0.5)
timeout -= 1
if wlan.isconnected():
print(f'Wi-Fi Connected: {wlan.ifconfig()}')
led.value(1)
return True
else:
print('Wi-Fi Connection Failed')
led.value(0)
return False
def read_moisture():
raw = adc.read_u16()
# Map raw ADC to percentage (0% = dry, 100% = wet)
percent = 100 - int(((raw - WET_VALUE) / (DRY_VALUE - WET_VALUE)) * 100)
percent = max(0, min(100, percent)) # Clamp between 0 and 100
return raw, percent
def main():
if not connect_wifi():
return
try:
client = MQTTClient('pico_plant_monitor', MQTT_BROKER, port=1883, keepalive=60)
client.connect()
print(f'Connected to MQTT Broker: {MQTT_BROKER}')
except OSError as e:
print(f'MQTT Connection Error: {e}')
return
while True:
try:
raw, percent = read_moisture()
payload = json.dumps({'raw': raw, 'moisture_pct': percent})
client.publish(MQTT_TOPIC, payload)
print(f'Published: {payload}')
# Blink LED to indicate successful transmission
led.value(1)
time.sleep(0.1)
led.value(0)
# Sleep for 15 minutes to save power and reduce broker spam
time.sleep(900)
except OSError as e:
print(f'Network/MQTT Error during loop: {e}. Reconnecting...')
connect_wifi()
try:
client.connect()
except:
pass
time.sleep(10)
if __name__ == '__main__':
main()
Debugging: First Three Things to Check
When your build fails to run, do not rewrite the code immediately. Hardware and network edge cases cause 90% of failures in raspberry pi pico projects. Run through this decision path first:
- Verify the 2.4GHz Wi-Fi Band: The CYW43439 chip on the Pico W does not support 5GHz Wi-Fi. If your router uses a unified SSID for both bands, the Pico may fail to associate. Create a dedicated 2.4GHz IoT SSID or force the router to broadcast on 2.4GHz.
- Check the LED Pin Syntax: If your code throws a
ValueError: bad pinon the linePin(LED_PIN, Pin.OUT), you are likely using code written for the original Pico (which uses integer25). The Pico W requires the string'LED'. - Ping the MQTT Broker: Ensure the device running your broker (e.g., Mosquitto on a Raspberry Pi 4) is reachable from your PC. If your PC can't ping the broker IP, the Pico W certainly cannot.
Common Error Strings and Ranked Causes
Error 1: OSError: [Errno 5] EIO
This is an I2C bus communication failure, usually occurring when initializing the OLED display.
- Cause A (Most Likely): Missing or insufficient I2C pull-up resistors. While the SSD1306 module usually has 4.7k pull-ups onboard, long breadboard traces can introduce capacitance. Add external 4.7k resistors between SDA/SCL and 3.3V.
- Cause B: The OLED is wired to the wrong I2C bus. Ensure SDA is on GP0 and SCL is on GP1, matching the
I2C(0...)declaration in the code.
Error 2: OSError: [Errno 113] EHOSTUNREACH
The Pico W cannot route packets to the MQTT broker IP address. For deeper MQTT protocol troubleshooting, refer to the HiveMQ Python MQTT Encyclopedia.
- Cause A (Most Likely): The MQTT broker service (e.g., Mosquitto) is stopped, or it is bound only to
localhost(127.0.0.1) instead of0.0.0.0. Edit yourmosquitto.confto includelistener 1883 0.0.0.0. - Cause B: The Pico W dropped its Wi-Fi connection and failed to renew its DHCP lease, leaving it with an invalid IP route. The
try/exceptblock in the provided code handles this by forcing a reconnection.
Extending and Simplifying the Build
Not every environment requires a full MQTT stack. Here is how to adapt this project based on your constraints:
How to Simplify:
If you lack a local MQTT broker and just want to log data for a science fair or personal analysis, strip out the umqtt imports and Wi-Fi connection. Replace the client.publish() line with print(f'{time.time()},{raw},{percent}'). You can then use Thonny's serial plotter or log the console output directly to a CSV file on your PC. This reduces the code footprint and eliminates network-related crashes entirely.
How to Extend:
To turn this monitor into an automated irrigation system, add a 5V submersible water pump. Do not power the pump directly from the Pico's GPIO. Instead, use an NPN transistor (like a 2N2222) or a logic-level MOSFET (like an IRLZ44N) to switch the pump's ground path. Drive the transistor's base/gate from GP15 via a 1kΩ current-limiting resistor. Always place a 1N4007 flyback diode in reverse parallel across the pump's motor terminals to protect the Pico from inductive voltage spikes when the motor shuts off.
Frequently Asked Questions
What are the best raspberry pi pico projects for beginners?
For absolute beginners, the best projects focus on the Pico's unique hardware features without introducing complex networking. A digital thermometer using the onboard RP2040 temperature sensor (accessible via ADC channel 4) is the ideal starting point. From there, building a hardware macro keyboard using the Pico's native USB HID capabilities, or a simple LED matrix clock using a MAX7219 driver, teaches foundational I2C/SPI protocols before tackling Wi-Fi and MQTT.
How do I power raspberry pi pico projects without a USB cable?
The Pico W accepts unregulated input voltage from 1.8V to 5.5V on the VSYS pin (Pin 39). For portable builds, a standard 3.7V LiPo battery connected directly to VSYS and GND is highly efficient, as the onboard RT6150 buck-boost converter will regulate it to a stable 3.3V for the RP2040. If using a 9V alkaline battery or a 12V solar setup, you must step the voltage down using a buck converter (like an LM2596 module) set to 5.0V before feeding it into VSYS, or you will fry the voltage regulator.
Why do my raspberry pi pico projects keep disconnecting from Wi-Fi?
Frequent Wi-Fi drops on the Pico W are usually tied to power delivery rather than software. The CYW43439 Wi-Fi chip draws current spikes of up to 150mA during transmission. If you are powering the Pico via a low-quality USB cable or a weak PC USB port, the voltage will sag below 3.3V, causing the Wi-Fi chip to brownout and reset. Solder a 100µF electrolytic capacitor and a 0.1µF ceramic capacitor across the 5V and GND pins on the Pico to provide local energy storage for these RF transmission spikes. For more hardware specifications, review the official Raspberry Pi Pico documentation.






