Last tested: MicroPython v1.23 | April 11, 2026 | Raspberry Pi Pico W with Raspberry Pi 4 as MQTT broker
Raspberry Pi companion boards let you offload specific tasks from your main Pi to a dedicated microcontroller. I use a Pico W to handle sensor reading without touching the resources on my Pi 4. The Pico W reads a DHT11, publishes the data over MQTT to a Mosquitto broker running on the Pi, and the Pi logs or visualizes it. The Pico W sits on a breadboard powered by a USB bank. No reboots, no drama, and the Pi stays free for everything else.
This guide covers what companion boards are, how to wire common sensors to the Pico W, how MQTT connects everything together, and how to build a working sensor-to-dashboard setup from scratch.
Key Takeaways
- The Pico W is a microcontroller, not a computer. It runs MicroPython firmware and handles one job reliably without an OS.
- MQTT separates sensor nodes from processing nodes. The Pico W publishes, the Raspberry Pi subscribes and logs.
- The Pico W only supports 2.4GHz Wi-Fi. If your router is 5GHz only, it will not connect.
- The onboard LED on Pico W is controlled via the CYW43 chip, not GPIO pin 25. Use
machine.Pin("LED", machine.Pin.OUT). - Multiple Pico W boards can report to one Pi broker using distinct MQTT client IDs and structured topic paths.

What Is a Raspberry Pi Companion Board?
A companion board is a microcontroller that runs alongside a main Raspberry Pi, handling a specific task so the Pi does not have to. The Pico W is the most common example in the Pi ecosystem. It runs MicroPython scripts, communicates with sensors over GPIO, I2C, or SPI, and sends data wirelessly via MQTT. The Pi acts as the central hub: receiving, storing, and displaying the data the companion board collects.
This separation has practical benefits. The Pico W consumes very little power and can run continuously from a USB bank. It handles real-time sensor polling without the latency of a full Linux OS. If the Pi reboots or restarts a service, the Pico W keeps reading and publishing without interruption. For home automation, environmental monitoring, and IoT sensor networks, this division of labor keeps each device doing what it does best.
Getting Started with the Raspberry Pi Pico W
What the Pico W is
The Pico W uses the RP2040 dual-core processor and adds Wi-Fi through the Infineon CYW43439 chip. It runs MicroPython and is programmed through Thonny IDE, which connects over USB and doubles as a code editor and live terminal. It supports I2C, SPI, UART, and analog input through its GPIO header. It does not run a full OS. Scripts run directly on the hardware with no scheduler or background processes competing for resources.
Flash MicroPython firmware
- Hold the BOOTSEL button on the Pico W and connect it via USB to your computer
- It appears as a mass storage device called RPI-RP2
- Download the Pico W MicroPython UF2 from micropython.org
- Drag the UF2 file onto the RPI-RP2 drive. The board reboots automatically.
- Open Thonny, select MicroPython (Raspberry Pi Pico) as the interpreter, and confirm the REPL connects
Connect to Wi-Fi in MicroPython
import network
import time
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect("YOUR_SSID", "YOUR_PASSWORD")
while not wlan.isconnected():
time.sleep(0.5)
print("Connected:", wlan.ifconfig())
The Pico W only supports 2.4GHz Wi-Fi. If your router broadcasts only 5GHz or uses a combined SSID that hands out 5GHz to new devices, the Pico W will fail to connect without any helpful error message. Confirm a 2.4GHz SSID is available before debugging the script.
Connecting Sensors to the Pico W
The Pico W operates at 3.3V logic. All sensors must match this voltage or use a logic level shifter. For I2C devices, GP0 and GP1 are the default SDA and SCL pins. Analog sensors connect to GP26, GP27, or GP28, which are the ADC-capable pins.
| Sensor | Protocol | Pico W pins | Power |
|---|---|---|---|
| DHT11 / DHT22 | Digital | Any GPIO (e.g. GP15) | 3.3V |
| BME280 | I2C | GP0 (SDA), GP1 (SCL) | 3.3V |
| HC-SR04 | Digital | GP16 (TRIG), GP17 (ECHO) | 5V with resistor divider on ECHO |
| LDR (light sensor) | Analog | GP26 (ADC0) | 3.3V |
| SSD1306 OLED | I2C | GP0 (SDA), GP1 (SCL) | 3.3V |
Use a breadboard and jumper wires for initial testing. The Pico W fits on a half-size breadboard with room on each side for wiring. Power sensors from the 3V3 pin and share a common GND. Keep signal wires short to reduce noise, particularly on I2C buses running multiple devices.
MQTT: How the Pico W Talks to the Pi
MQTT is a lightweight publish-subscribe messaging protocol designed for constrained devices. The Pico W publishes sensor readings to a topic. A broker (Mosquitto running on the Pi) receives and holds the message. The Pi subscribes to the topic and receives the data. Neither device needs to be directly aware of the other. They only need to agree on a broker address and a topic name.
| Device | Role | Action |
|---|---|---|
| Pico W | Publisher | Sends sensor data to broker topic |
| Mosquitto on Pi | Broker | Receives, stores, and forwards messages |
| Raspberry Pi | Subscriber | Receives data for logging or automation |
Install Mosquitto on the Raspberry Pi
sudo apt update
sudo apt install mosquitto mosquitto-clients -y
sudo systemctl enable mosquitto
sudo systemctl start mosquitto
Test that the broker is working by subscribing in one terminal and publishing from another:
# Terminal 1 -- subscribe
mosquitto_sub -h localhost -t "test/topic"
# Terminal 2 -- publish
mosquitto_pub -h localhost -t "test/topic" -m "hello"
Build a Working Sensor Project
This project reads temperature and humidity from a DHT22 sensor on the Pico W, displays values on an SSD1306 OLED, and publishes them over MQTT to a Mosquitto broker on the Pi. Node-RED on the Pi subscribes and visualizes the data.
Parts needed
- Raspberry Pi Pico W
- DHT22 temperature and humidity sensor
- SSD1306 OLED display (I2C)
- Raspberry Pi (any model) with Mosquitto and Node-RED installed
- Breadboard and jumper wires
- USB power supply for the Pico W
Pin wiring
| Peripheral | Pico W pin | Notes |
|---|---|---|
| DHT22 VCC | 3V3 | Power |
| DHT22 GND | GND | Ground |
| DHT22 DATA | GP15 | Digital signal |
| OLED SDA | GP0 | I2C data |
| OLED SCL | GP1 | I2C clock |
| OLED VCC | 3V3 | Power |
| OLED GND | GND | Ground |
MicroPython script
import network
import time
import dht
import machine
from umqtt.simple import MQTTClient
import ssd1306
# Wi-Fi credentials
SSID = "YOUR_SSID"
PASSWORD = "YOUR_PASSWORD"
# MQTT broker address (your Pi's IP)
BROKER = "192.168.1.50"
TOPIC = b"home/livingroom/env"
CLIENT_ID = b"picow-livingroom"
# Hardware setup
sensor = dht.DHT22(machine.Pin(15))
i2c = machine.I2C(0, sda=machine.Pin(0), scl=machine.Pin(1), freq=400000)
oled = ssd1306.SSD1306_I2C(128, 64, i2c)
# Onboard LED -- note: use "LED" not Pin(25) on Pico W
led = machine.Pin("LED", machine.Pin.OUT)
# Connect to Wi-Fi
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(SSID, PASSWORD)
while not wlan.isconnected():
time.sleep(0.5)
# Connect to MQTT broker
client = MQTTClient(CLIENT_ID, BROKER)
client.connect()
while True:
sensor.measure()
temp = sensor.temperature()
hum = sensor.humidity()
payload = '{{"temp": {}, "humidity": {}}}'.format(temp, hum)
client.publish(TOPIC, payload)
oled.fill(0)
oled.text("Temp: {}C".format(temp), 0, 0)
oled.text("Hum: {}%".format(hum), 0, 16)
oled.show()
led.toggle()
time.sleep(30)
Save this as main.py on the Pico W so it runs automatically after every reset or power-on. The 30-second interval throttles DHT22 reads, which is important since reading DHT22 too frequently causes errors. Reduce the interval only if your application genuinely needs faster updates.
Receive and visualize on the Pi
Confirm messages are arriving on the Pi:
mosquitto_sub -h localhost -t "home/livingroom/env"
For a dashboard, install Node-RED and add an MQTT input node pointed at home/livingroom/env. Wire it to a JSON parse node and then to gauge or chart nodes. Node-RED’s dashboard module renders a live browser UI that updates as each MQTT message arrives. For home automation integration, the same MQTT topic can feed directly into Home Assistant using its MQTT integration.
Visual Feedback with Displays and LEDs
Local feedback on the Pico W confirms the script is running without needing a laptop connected. The SSD1306 OLED shows live sensor values. The onboard LED blinks on each successful MQTT publish. Together they tell you at a glance whether the sensor is reading, the Wi-Fi is connected, and data is flowing.
| System event | Visual feedback |
|---|---|
| Wi-Fi connected | LED steady on |
| MQTT message published | LED short blink |
| Sensor read successful | New value on OLED |
| Broker unreachable | OLED shows error text |
Managing Multiple Pico W Devices
When adding more than one Pico W to a project, two rules prevent most problems. First, every device needs a unique MQTT client ID. If two clients use the same ID, the broker will disconnect one of them when the other connects. Second, topic names should follow a consistent structure that encodes location and function, such as house/kitchen/temp or house/basement/humidity. This makes automation rules in Node-RED or Home Assistant straightforward to write.
| Node | Client ID | Topic |
|---|---|---|
| Living room temp | picow-livingroom | house/livingroom/env |
| Kitchen humidity | picow-kitchen | house/kitchen/humidity |
| Basement sensor | picow-basement | house/basement/temp |
| Fan controller | picow-fan | house/fan/cmd (subscriber) |
For I2C sensors, avoid address conflicts by using components with configurable addresses or separating them onto distinct I2C buses. The Pico W has two I2C buses (I2C0 and I2C1) that can run simultaneously. If you need multiple devices with the same fixed I2C address, use a TCA9548A multiplexer to assign each to its own channel.
The retain flag in MQTT tells the broker to store the last message on a topic so new subscribers receive the most recent value immediately on connection. Add retain=True to client.publish() calls for sensor readings that need to survive broker restarts or Pi reboots.
Troubleshooting
Pico W will not connect to Wi-Fi
The most common cause is a 5GHz-only SSID. Confirm a 2.4GHz network is available and that the SSID and password in the script match exactly, including case. Use print(wlan.status()) to get a numeric status code if wlan.isconnected() stays False. A status of 3 means connected, anything else indicates the failure mode.
MQTT messages not arriving on the Pi
| Symptom | Likely cause | Fix |
|---|---|---|
| No messages on subscriber | Topic name mismatch | Match topic strings exactly on publisher and subscriber |
| Connection refused error | Broker IP wrong or Mosquitto not running | Ping broker from Pi, check systemctl status mosquitto |
| Client keeps disconnecting | Duplicate client ID | Assign a unique client_id to each Pico W |
| Works once then stops | No reconnect logic in script | Add try/except around publish and reconnect on failure |
Sensor returns errors or bad values
DHT sensors need at least 2 seconds between reads. Reading faster than this causes OSError exceptions. Wrap the sensor.measure() call in a try/except block and log the error rather than crashing the loop. For I2C devices, confirm the address with:
import machine
i2c = machine.I2C(0, sda=machine.Pin(0), scl=machine.Pin(1))
print(i2c.scan()) # should show a list containing the device address
Onboard LED not working
On the Pico W, the onboard LED is routed through the CYW43439 Wi-Fi chip rather than directly to GPIO pin 25. Using machine.Pin(25, machine.Pin.OUT) will not work reliably. Use machine.Pin("LED", machine.Pin.OUT) instead. This is a common point of confusion for anyone following tutorials written for the original Pico rather than the Pico W.
Useful Tools
Development tools
Thonny IDE is the standard tool for writing and uploading MicroPython to the Pico W. It shows the REPL output live, which is the fastest way to debug sensor readings and Wi-Fi connection issues. For command-line workflows, mpremote (the official MicroPython remote tool) handles file transfers and REPL access without a GUI.
MQTT tools
MQTT Explorer is a desktop application that connects to your broker and shows all active topics, their payloads, and message history. It is the fastest way to confirm that the Pico W is actually publishing and that topic names are correct. On the Pi itself, mosquitto_sub -h localhost -t "#" -v shows all messages on all topics in real time.
Dashboard and automation
Node-RED runs on the Raspberry Pi and connects MQTT inputs to dashboard outputs through a visual flow editor. It handles JSON parsing, conditional logic, and data storage without writing server-side code. Home Assistant’s MQTT integration can consume the same topics directly, turning sensor readings into entities for dashboards and automations.
FAQ
What is the difference between the Pico W and a Raspberry Pi?
The Pico W is a microcontroller. It runs a single MicroPython script directly on hardware with no OS, no file system beyond a small flash storage, and no background processes. A Raspberry Pi is a single-board computer running a full Linux operating system. The Pico W handles real-time sensor tasks efficiently. The Pi handles storage, networking services, dashboards, and anything that needs a proper OS.
Can I use 5V sensors with the Pico W?
Not directly. The Pico W operates at 3.3V logic and its GPIO pins are not 5V tolerant. Connecting a 5V signal directly will damage the chip. Use a logic level shifter between a 5V sensor output and a Pico W GPIO input. The HC-SR04 ultrasonic sensor is the most common example of this. Its ECHO pin outputs 5V and needs a voltage divider or level shifter before connecting to GP17.
What MQTT broker should beginners use?
Mosquitto running on a Raspberry Pi is the standard choice. It is lightweight, well-documented, and keeps everything on the local network. Adafruit IO is a cloud-based alternative that provides a hosted broker and built-in dashboard, which is useful if you want to skip self-hosting. For anything beyond a small home network, consider adding basic Mosquitto authentication via a password file.
What happens if Wi-Fi drops during publishing?
The MQTT publish call will throw an exception. Without error handling, the script crashes and the Pico W stops sending data. Add a try/except block around both the Wi-Fi connection and the MQTT publish calls, with reconnect logic in the except clause. A watchdog timer (machine.WDT) can also reset the board automatically if the main loop stops progressing.
Why is my OLED display not working?
Confirm GP0 is SDA and GP1 is SCL with correct wiring. Run i2c.scan() to check the display is detected. It should return [60] which is 0x3C in decimal. If the scan returns an empty list, check the wiring and confirm the display is powered. Also confirm the ssd1306.py driver file is uploaded to the Pico W’s filesystem alongside your main script.
References
- https://datasheets.raspberrypi.com/picow/pico-w-datasheet.pdf
- https://micropython.org/download/rp2-pico-w/
- https://mosquitto.org/
- https://nodered.org/docs/getting-started/raspberrypi
About the Author
Chuck Wilson has been programming and building with computers since the Tandy 1000 era. His professional background includes CAD drafting, manufacturing line programming, and custom computer design. He runs PidiyLab in retirement, documenting Raspberry Pi and homelab projects that he actually deploys and maintains on real hardware. Every article on this site reflects hands-on testing on specific hardware and OS versions, not theoretical walkthroughs.
Last tested hardware: Raspberry Pi Pico W with Raspberry Pi 4 as MQTT broker. Last tested firmware: MicroPython v1.23.

