Voice-Controlled AI Home Assistant
Build an intelligent smart home assistant using Raspberry Pi Pico and MicroPython — with OLED display, DHT22 sensor, multi-room LED control, and buzzer feedback.
Key Features
A simplified AI assistant that listens, controls devices, reads sensor data, and displays responses on OLED.
Wake Word
Activates on "Hey Assistant" — like Alexa or Google Home
3-Zone Lighting
Control living room, bedroom, and kitchen lights independently
DHT22 Sensor
Real-time temperature and humidity readings on demand
OLED Display
SSD1306 128×64 shows commands and responses visually
Audio Feedback
Buzzer simulates text-to-speech with short, long, and alert tones
State Machine
Idle → Listening → Processing — real AI assistant architecture
Smart Routines
"Good Morning" turns all lights on; "Goodnight" shuts everything off
Wokwi Ready
Fully simulated in Wokwi — no hardware needed to start
Components Required
All available as virtual parts in Wokwi — or build on real hardware!
Pin Wiring Reference
All GPIO connections for Raspberry Pi Pico
| Component | Pico Pin | Notes |
|---|---|---|
| OLED SDA | GP0 | I2C data |
| OLED SCL | GP1 | I2C clock |
| OLED VCC | 3V3 | 3.3V power |
| DHT22 SDA | GP15 | Data signal |
| LED Living Room | GP10 | 220Ω series |
| LED Bedroom | GP11 | 220Ω series |
| LED Kitchen | GP12 | 220Ω series |
| 🔊 Buzzer (+) | GP13 | (−) to GND |
| 🟢 Wake Button | GP14 | PULL_UP, active LOW |
0x3C by default. The Pico uses I2C bus 0 with GP0 (SDA) and GP1 (SCL) at 400 kHz.
Pin.PULL_UP internally — no external resistor needed. Reads 0 when pressed, 1 when released.
diagram.json
Paste this into Wokwi to auto-load the full circuit in seconds
Open Wokwi
Go to wokwi.com → New Project → Raspberry Pi Pico. Log in with Google to save and share.
Paste diagram.json
Click the diagram.json tab → select all (Ctrl+A) → delete → paste the JSON below → Ctrl+S to save.
Paste main.py
Switch to the main.py tab → paste the full MicroPython code → click ▶ Play to start.
Test via Serial Monitor
Open the Serial Monitor → type Hey Assistant to wake it, then type a command like turn on living room.
{
"version": 1,
"author": "Voice Assistant Project",
"editor": "wokwi",
"parts": [
{ "type": "wokwi-pi-pico", "id": "pico", "top": 0, "left": 0, "attrs": {} },
{ "type": "wokwi-ssd1306", "id": "oled1", "top": -137.33, "left": 122.67, "attrs": { "i2cAddress": "0x3C" } },
{ "type": "wokwi-dht22", "id": "dht1", "top": -145.2, "left": -115.2, "attrs": {} },
{ "type": "wokwi-led", "id": "led_red", "top": 120, "left": -180, "attrs": { "color": "red", "label": "Living Room" } },
{ "type": "wokwi-led", "id": "led_green", "top": 120, "left": -100, "attrs": { "color": "green", "label": "Bedroom" } },
{ "type": "wokwi-led", "id": "led_blue", "top": 120, "left": -20, "attrs": { "color": "blue", "label": "Kitchen" } },
{ "type": "wokwi-resistor", "id": "r1", "top": 110, "left": -210, "attrs": { "value": "220" } },
{ "type": "wokwi-resistor", "id": "r2", "top": 110, "left": -130, "attrs": { "value": "220" } },
{ "type": "wokwi-resistor", "id": "r3", "top": 110, "left": -50, "attrs": { "value": "220" } },
{ "type": "wokwi-buzzer", "id": "buzzer1", "top": 90, "left": 100, "attrs": { "volume": "0.8" } },
{ "type": "wokwi-pushbutton", "id": "btn1", "top": -60, "left": -220, "attrs": { "color": "green", "label": "WAKE" } }
],
"connections": [
["pico:GP0", "oled1:SDA", "green", ["v0"]],
["pico:GP1", "oled1:SCL", "blue", ["v0"]],
["pico:3V3(OUT)", "oled1:VCC", "red", ["v0"]],
["pico:GND.8", "oled1:GND", "black", ["v0"]],
["pico:3V3(OUT)", "dht1:VCC", "red", ["v0"]],
["pico:GND.3", "dht1:GND", "black", ["v0"]],
["pico:GP15", "dht1:SDA", "orange", ["v0"]],
["pico:GP10", "r1:1", "red", ["v0"]],
["r1:2", "led_red:A", "red", ["v0"]],
["led_red:C", "pico:GND.4", "black", ["v0"]],
["pico:GP11", "r2:1", "green", ["v0"]],
["r2:2", "led_green:A", "green", ["v0"]],
["led_green:C", "pico:GND.5", "black", ["v0"]],
["pico:GP12", "r3:1", "blue", ["v0"]],
["r3:2", "led_blue:A", "blue", ["v0"]],
["led_blue:C", "pico:GND.6", "black", ["v0"]],
["pico:GP13", "buzzer1:1", "magenta", ["v0"]],
["buzzer1:2", "pico:GND.7", "black", ["v0"]],
["pico:GP14", "btn1:1.l", "yellow", ["v0"]],
["btn1:2.l", "pico:GND.2", "black", ["v0"]]
],
"dependencies": {}
}
Full Code
Paste into Wokwi's main.py editor, then click ▶ Play
① Imports & Pin Setup
from machine import Pin, I2C, ADC import time, framebuf, dht # I2C + OLED i2c = I2C(0, scl=Pin(1), sda=Pin(0), freq=400000) oled = SSD1306_I2C(128, 64, i2c) # DHT22 Sensor dht_sensor = dht.DHT22(Pin(15)) # Smart device LEDs led_living = Pin(10, Pin.OUT) led_bedroom = Pin(11, Pin.OUT) led_kitchen = Pin(12, Pin.OUT) # Buzzer + Wake button buzzer = Pin(13, Pin.OUT) wake_button = Pin(14, Pin.IN, Pin.PULL_UP) # Device state dictionary devices = { "living_room": False, "bedroom": False, "kitchen": False } temperature = 0.0 humidity = 0.0 listening = False
② speak() — Audio + OLED Output
def speak(message, tone_pattern="short"): """Display on OLED + buzzer audio feedback""" print(f"🔊 Assistant: {message}") oled.fill(0) oled.rect(0, 0, 128, 64, 1) oled.text("ASSISTANT", 30, 5) # Word-wrap message to 16-char lines words = message.split() lines, line = [], "" for word in words: if len(line + word) < 16: line += word + " " else: lines.append(line.strip()); line = word + " " if line: lines.append(line.strip()) y = 25 for l in lines[:4]: oled.text(l, 5, y); y += 10 oled.show() # Buzzer tones if tone_pattern == "short": buzzer.on(); time.sleep(0.1); buzzer.off() elif tone_pattern == "long": for _ in range(2): buzzer.on(); time.sleep(0.15) buzzer.off(); time.sleep(0.05) elif tone_pattern == "alert": for _ in range(3): buzzer.on(); time.sleep(0.05) buzzer.off(); time.sleep(0.05) time.sleep(2)
③ process_command() — Voice NLP Parser
def process_command(command): cmd = command.lower().strip() if "living" in cmd: if "on" in cmd: led_living.on(); devices["living_room"] = True speak("Living room on", "short") elif "off" in cmd: led_living.off(); devices["living_room"] = False speak("Living room off", "short") elif "bedroom" in cmd: if "on" in cmd: led_bedroom.on(); devices["bedroom"] = True speak("Bedroom on", "short") elif "off" in cmd: led_bedroom.off(); devices["bedroom"] = False speak("Bedroom off", "short") elif "kitchen" in cmd: if "on" in cmd: led_kitchen.on(); devices["kitchen"] = True speak("Kitchen on", "short") elif "off" in cmd: led_kitchen.off(); devices["kitchen"] = False speak("Kitchen off", "short") elif "all" in cmd: state = "on" in cmd led_living.value(state); led_bedroom.value(state); led_kitchen.value(state) for k in devices: devices[k] = state speak(f"All lights {'on' if state else 'off'}", "long") elif "temperature" in cmd or "weather" in cmd: dht_sensor.measure() temperature = dht_sensor.temperature() humidity = dht_sensor.humidity() speak(f"{temperature}C {humidity}%", "short") elif "time" in cmd: t = time.localtime() speak(f"{t[3]}:{t[4]:02d}", "short") elif "good morning" in cmd or "morning" in cmd: led_living.on(); led_bedroom.on(); led_kitchen.on() for k in devices: devices[k] = True speak("Good morning!", "long") elif "goodnight" in cmd or "good night" in cmd: led_living.off(); led_bedroom.off(); led_kitchen.off() for k in devices: devices[k] = False speak("Goodnight!", "long") elif "status" in cmd: count = sum(devices.values()) speak(f"{count} devices on", "short") elif "help" in cmd: speak("Say turn on/off device", "long") else: speak("Not understood", "alert")
④ Main Loop — State Machine
show_boot_screen() update_temperature() show_idle_screen() try: while True: # Physical wake button (active LOW) if wake_button.value() == 0: listening = True show_listening_screen() speak("Yes?", "short") while wake_button.value() == 0: time.sleep(0.1) # Serial input simulates voice (for Wokwi) user_input = input("🎤 You: ").strip() if listening else "" if user_input: if "hey" in user_input.lower() or "assistant" in user_input.lower(): listening = True show_listening_screen() speak("Yes?", "short") elif listening: process_command(user_input) listening = False show_idle_screen() else: time.sleep(0.1) except KeyboardInterrupt: led_living.off(); led_bedroom.off(); led_kitchen.off() buzzer.off() oled.fill(0); oled.text("GOODBYE!", 35, 28); oled.show()
Supported Voice Commands
Type these in the Wokwi Serial Monitor after saying "Hey Assistant"
Hey Assistant → press Enter → OLED shows "LISTENING..." → then type your command, e.g. turn on all lights → press Enter.
Key Concepts
Programming and electronics skills this project teaches
Keyword-Based Command Matching
Commands are parsed by checking whether keywords like "living", "on", or "temperature" appear in the lowercased input. This is how simple NLP worked before large language models — fast, lightweight, perfect for microcontrollers.
Idle → Listening → Processing
The listening boolean flag controls which branch of the main loop runs. A classic embedded state machine — the device behaves completely differently based on its current state. Real AI assistants like Alexa use a much more complex version of this same pattern.
OLED Display via I2C
The SSD1306 OLED communicates over I2C using just two wires (SDA + SCL). The driver writes display commands and pixel data via i2c.writeto(). Understanding I2C is essential for connecting sensors, displays, and modules in embedded systems.
DHT22 Temperature & Humidity
The DHT22 uses a single-wire protocol. Calling dht_sensor.measure() triggers a reading, then .temperature() and .humidity() return the values. Sensor errors are caught with try/except so the system keeps running even if a reading fails.
Synchronized Smart Home Control
All three LEDs share a devices dictionary that tracks on/off state. This lets the "Status" command count active devices, and lets routines like "Good Morning" update all lights and their states in a single block of code.
Comments
Post a Comment