Digital Mood Lamp with Capacitive Touch Control using Raspberry Pi Pico
Digital Mood Lamp - Raspberry Pi Pico

Digital Mood Lamp with Raspberry Pi Pico

01 Overview

This project features a customizable digital mood lamp built with the Raspberry Pi Pico. It allows users to interact with lighting patterns using a capacitive touch sensor and adjust brightness using a potentiometer.

Powered by 16 individually controlled RGB LEDs on a NeoPixel ring, the lamp offers various modes such as rainbow, breathing effect, solid colors, and blinking.

Programming is done in MicroPython via the Thonny IDE, making it beginner-friendly and ideal for learning about embedded electronics and interactive lighting.

 

02 Hardware and Software Components

Gather everything below before you start.

Hardware Components

Component Description
Raspberry Pi Pico Microcontroller board that runs the MicroPython code and drives the lamp
NeoPixel Ring - 16 x 5050 RGB LED Addressable RGB LED ring with integrated drivers
Potentiometer Analog input used to adjust LED brightness
Digital Touch Sensor Capacitive touch input used to cycle through lighting modes
Breadboard Used for prototyping and connecting components
Dupont Jumper Wires Used to connect the components to the Pico

 

Software Tools

Software Details
MicroPython Firmware and programming language used on the Raspberry Pi Pico
Thonny IDE Used to write, upload, run, and debug the code

 

03 Application Discussion

  • RASPBERRY PI PICO

RASPBERRY PI PICO WH RASPBERRY-PI, SBC, Raspberry Pi Pico WH, RP2040, ARM  Cortex-M0+, 264KB RAM, 2MB Flash, WiFi, With Header | element14 Philippines

A low-cost microcontroller board based on the RP2040 chip. It runs the MicroPython code and acts as the brain of the lamp. It processes inputs from the touch sensor and potentiometer and drives the NeoPixel ring.

  • NEOPIXEL RING - 16 X 5050 RGB LED WITH INTEGRATED DRIVERS

Hand holding NeoPixel Ring with 16 x 5050 RGB LED, lit up rainbow

Provides colorful LED lighting effects. Each LED can be individually controlled for dynamic animations like rainbow or breathing effects. It’s controlled through a single data pin using MicroPython’s timing and math libraries.

  • POTENTIOMETER

An analog input that allows users to change the brightness of the LEDs. Connected to one of the Pico’s ADC (analog-to-digital converter) pins, it provides a value between 0 and 65,535 which is then scaled to adjust the LED intensity.

  • DIGITAL TOUCH SENSOR

Acts like a touch-sensitive button. Every tap cycles the lamp through six different modes. It provides a digital HIGH signal when touched, making it easy to detect input through code.

  • BREADBOARD AND JUMPER WIRES

Used for non-permanent prototyping. All connections between components and the Raspberry Pi Pico are made here, allowing for easy debugging and adjustments.

 

OTHERS

  • MICROPYTHON

File:Micropython-logo.svg - Wikimedia Commons

MicroPython is a lean version of Python designed for microcontrollers. It lets you program the Raspberry Pi Pico in a language that’s simple and easy to understand, making it perfect for students. In this project, it’s used to control the LED patterns, read analog and digital inputs, and handle brightness scaling.

  • THONNY IDE

Thonny - Wikipedia

Thonny is a beginner-friendly Python IDE that supports MicroPython directly. It’s used to write, upload, and run the code on the Raspberry Pi Pico. It also allows Serial printing for debugging. Thonny makes coding on hardware easier by offering real-time output and error messages.

 

04 Hardware Setup

Wire the components to the Raspberry Pi Pico as shown in the schematic below.

Wiring schematic for the Digital Mood Lamp

Pico to NeoPixel Ring

Pico Pin Connects To
GP15 NeoPixel Ring Data In (DIN)
5V external supply NeoPixel Ring VCC
GND NeoPixel Ring GND

Pico to Potentiometer and Touch Sensor

Component Pin Pico Pin Description
Potentiometer wiper GP26 (ADC0) Analog brightness input
Potentiometer VCC / GND 3V3 / GND Powers the potentiometer
Touch sensor signal GP14 Digital HIGH signal on touch
Touch sensor VCC / GND 3V3 / GND Powers the touch sensor

Assembly Instructions

  1. Place the Raspberry Pi Pico on the breadboard.
  2. Connect the NeoPixel data pin to GP15 and power it from an external 5V source.
  3. Connect the potentiometer wiper to GP26 and its outer pins to 3V3 and GND.
  4. Connect the touch sensor signal to GP14 and its power pins to 3V3 and GND.
  5. Confirm that all ground connections are shared.
Safety Note: Do not power the NeoPixel ring directly from the Pico's 3.3V pin. Use an external 5V supply with a shared ground.

05 Software Setup

Follow these steps in order. Do not skip any step.

Board Settings

Setting Value
Interpreter MicroPython (Raspberry Pi Pico)
Port Auto-detect or select the Pico's USB port

Upload the Code

  1. Open the code in Thonny IDE.
  2. Save it to the Raspberry Pi Pico as main.py.
  3. Click Run to start the program.

06 Code

MicroPython
import machine
import time
import neopixel
import math

# === Pin Definitions ===
PIN_TOUCH = 14       # Digital touch sensor
PIN_NEOPIXEL = 15    # NeoPixel data pin
PIN_POT = 26         # Potentiometer analog pin

# === LED Settings ===
NUM_LEDS = 16
ALL_LEDS = list(range(NUM_LEDS))  # Use all 16 LEDs
np = neopixel.NeoPixel(machine.Pin(PIN_NEOPIXEL), NUM_LEDS)

# === Touch Sensor Setup ===
touch = machine.Pin(PIN_TOUCH, machine.Pin.IN)
last_touch_state = 0
touch_count = 0
mode = 0

# === Potentiometer (ADC) Setup ===
pot = machine.ADC(PIN_POT)

# === Breathing Effect Setup ===
breathing_phase = 0

# === Rainbow Effect ===
def wheel(pos):
	if pos < 0 or pos > 255:
		return (0, 0, 0)
	if pos < 85:
		return (int(pos * 3), int(255 - pos * 3), 0)
	if pos < 170:
		pos -= 85
		return (int(255 - pos * 3), 0, int(pos * 3))
	pos -= 170
	return (0, int(pos * 3), int(255 - pos * 3))

def show_rainbow(offset, brightness):
	for i in ALL_LEDS:
		color = wheel((int(i * 256 / len(ALL_LEDS)) + offset) % 256)
		scaled = tuple(int(c * brightness) for c in color)
		np[i] = scaled
	np.write()

# === Helper for printing mode names ===
def print_mode(touch_count):
	mode_names = {
		1: "Solid White",
		2: "Breathing Yellow",
		3: "Red",
		4: "Rainbow",
		5: "Blinking Blue Stars",
		6: "Off"
	}
	print(f"Touch count: {touch_count} -> Mode: {mode_names.get(touch_count, 'Unknown')}")

# === Main Loop ===
rainbow_offset = 0
blink_state = True

while True:
	brightness = pot.read_u16() / 65535
	brightness = max(0.05, brightness)

	# Touch detection (rising edge)
	current_touch_state = touch.value()
	if current_touch_state == 1 and last_touch_state == 0:
		touch_count += 1
		if touch_count > 6:
			touch_count = 1
		print_mode(touch_count)
	last_touch_state = current_touch_state

	# Set mode based on touch count
	if touch_count == 1:
		mode = 1
	elif touch_count == 2:
		mode = 2
	elif touch_count == 3:
		mode = 3
	elif touch_count == 4:
		mode = 4
	elif touch_count == 5:
		mode = 5
	elif touch_count == 6:
		mode = 6

	# Mode behaviors
	if mode == 1:
		for i in ALL_LEDS:
			np[i] = (int(255 * brightness), int(255 * brightness), int(255 * brightness))
		np.write()
	elif mode == 2:
		breath = (math.sin(breathing_phase) + 1) / 2
		scaled = int(breath * 255 * brightness)
		for i in ALL_LEDS:
			np[i] = (scaled, scaled, 0)
		np.write()
		breathing_phase += 0.1
		if breathing_phase > 2 * math.pi:
			breathing_phase = 0
		time.sleep(0.05)
	elif mode == 3:
		for i in ALL_LEDS:
			np[i] = (int(255 * brightness), 0, 0)
		np.write()
	elif mode == 4:
		show_rainbow(rainbow_offset, brightness)
		rainbow_offset = (rainbow_offset + 1) % 256
		time.sleep(0.05)
	elif mode == 5:
		color = (0, 0, int(255 * brightness)) if blink_state else (0, 0, 0)
		for i in ALL_LEDS:
			np[i] = color
		np.write()
		blink_state = not blink_state
		time.sleep(0.1)
	elif mode == 6:
		for i in ALL_LEDS:
			np[i] = (0, 0, 0)
		np.write()

	time.sleep(0.05)

 

07 Code Breakdown

MicroPython - Libraries
import machine
import time
import neopixel
import math

Discussion:
These are the essential libraries used in MicroPython:

  • machine: lets us control the Raspberry Pi Pico’s hardware pins.

  • time: used for adding delays (e.g., blinking or breathing effects).

  • neopixel: controls the RGB LEDs in the NeoPixel ring.

  • math: helps create smooth animation effects like breathing using sine waves.


Pin Assignments

MicroPython - Pin Assignments
PIN_TOUCH = 14
PIN_NEOPIXEL = 15
PIN_POT = 26

Discussion:

  • PIN_TOUCH: Pin connected to the digital touch sensor.

  • PIN_NEOPIXEL: Data pin for controlling the NeoPixel ring.

  • PIN_POT: Pin connected to the potentiometer (analog input).


LED Setup

MicroPython - LED Setup
NUM_LEDS = 16
ALL_LEDS = list(range(NUM_LEDS))
np = neopixel.NeoPixel(machine.Pin(PIN_NEOPIXEL), NUM_LEDS)

Discussion:

  • NUM_LEDS: Total number of LEDs in the NeoPixel ring.

  • ALL_LEDS: List of LED indices (0 to 15).

  • np: Initializes NeoPixel control on the specified pin.


Touch Sensor Setup

MicroPython - Touch Sensor Setup
touch = machine.Pin(PIN_TOUCH, machine.Pin.IN)
last_touch_state = 0
touch_count = 0
mode = 0

Discussion:

  • Configures the touch pin as an input.

  • last_touch_state: Remembers the last touch to detect rising edges.

  • touch_count: Counts the number of taps to switch between light modes.

  • mode: Stores the current mode selected by the user.


Potentiometer Setup

MicroPython - Potentiometer Setup
pot = machine.ADC(PIN_POT)

Discussion:
Sets up analog input from the potentiometer, which is used to control brightness (from 0 to full).

 


Breathing Effect Tracking

MicroPython - Breathing Effect
breathing_phase = 0

Discussion:
Used to store the current position in the sine wave for smooth breathing animation.

 


Rainbow Helper Functions

MicroPython - Rainbow Helpers
def wheel(pos):
	# Generate an RGB color from a position.
	.....

def show_rainbow(offset, brightness):
	# Display the flowing rainbow effect.
	.....

Discussion:

  • wheel(pos): Generates RGB values for rainbow colors based on a position (0-255).

  • show_rainbow(offset, brightness): Displays a flowing rainbow effect by adjusting each LED’s color and brightness.


Mode Print Function

MicroPython - Mode Print
def print_mode(touch_count):
	.....

Discussion:
Prints the name of the current lighting mode each time you touch the sensor. Useful for debugging or viewing in the Thonny terminal.

 


Main Loop Logic

MicroPython - Main Loop
rainbow_offset = 0
blink_state = True

while True:
	brightness = pot.read_u16() / 65535
	brightness = max(0.05, brightness)

Discussion:

  • Reads the potentiometer value and scales it between 0 and 1.

  • Sets a minimum brightness of 5% to avoid turning LEDs fully off.

 


Touch Detection

MicroPython - Touch Detection
current_touch_state = touch.value()
if current_touch_state == 1 and last_touch_state == 0:
	touch_count += 1
	if touch_count > 6:
		touch_count = 1
	print_mode(touch_count)
last_touch_state = current_touch_state

Discussion:

  • Detects a new touch (rising edge).

  • Cycles through 6 different modes with each tap.

  • Resets to 1 after reaching mode 6.


Mode Selection

MicroPython - Mode Selection
if touch_count == 1:
	mode = 1
	.....
elif touch_count == 6:
	mode = 6

Discussion:
Selects which lighting mode should run based on touch count.

 


Mode Actions

Mode 1 – Solid White

MicroPython - Mode 1
for i in ALL_LEDS:
	np[i] = (int(255 * brightness), int(255 * brightness), int(255 * brightness))
np.write()

Discussion:
All LEDs turn solid white, scaled by potentiometer brightness.

 


Mode 2 – Breathing Yellow

MicroPython - Mode 2
breath = (math.sin(breathing_phase) + 1) / 2
scaled = int(breath * 255 * brightness)
for i in ALL_LEDS:
	np[i] = (scaled, scaled, 0)
np.write()
breathing_phase += 0.1
if breathing_phase > 2 * math.pi:
	breathing_phase = 0
time.sleep(0.05)

Discussion:
Creates a smooth fade in/out yellow effect using a sine wave. Yellow = red + green.

 


Mode 3 – Solid Red

MicroPython - Mode 3
for i in ALL_LEDS:
	np[i] = (int(255 * brightness), 0, 0)
np.write()

Discussion:
Displays red color on all LEDs.

 


Mode 4 – Rainbow Animation

MicroPython - Mode 4
show_rainbow(rainbow_offset, brightness)
rainbow_offset = (rainbow_offset + 1) % 256
time.sleep(0.05)

Discussion:
Creates a dynamic, moving rainbow effect across the LED ring.

 


Mode 5 – Blinking Blue (Stars)

MicroPython - Mode 5
color = (0, 0, int(255 * brightness)) if blink_state else (0, 0, 0)
for i in ALL_LEDS:
	np[i] = color
np.write()
blink_state = not blink_state
time.sleep(0.1)

Discussion:
LEDs blink blue on/off rapidly like twinkling stars.

 


Mode 6 – Off

MicroPython - Mode 6
for i in ALL_LEDS:
	np[i] = (0, 0, 0)
np.write()

Discussion:
Turns all LEDs off.

 


 

08 Testing and Calibration

Testing and Calibration:

  1. Power Testing:
     Initially, we powered the LEDs through the Pico's 3.3V pin, which caused flickering. Using an external 5V power source solved the issue.

  2. Touch Sensor Response:
     We verified each touch properly increased the mode count (1 to 6), and added debouncing using a small delay to avoid accidental double triggers.

  3. Brightness Range:
    The potentiometer was tested using print() statements in Thonny to view raw ADC values. We then scaled these to LED brightness between 5% (to remain visible) and 100%.

  4. Animation Timing:
    Animation delays were tweaked (e.g., time.sleep(0.05)) to make transitions smooth and visually pleasing.

Final Adjustments:

  • Secured all jumper wires on the breadboard to prevent connection drops.
  • Optimized brightness scaling to avoid overly dim or overly bright states.
  • Repositioned the touch sensor to avoid unintentional activation due to environmental interference.
  • Cleaned up the Serial output in Thonny for debugging.
  • Ensured each lighting mode runs efficiently without crashing the Pico.

09 System Demonstration

10 Conclusion

This interactive Digital Mood Lamp is a fun and functional way to explore microcontrollers, sensors, and LED control. With multiple lighting modes, touch interaction, and brightness adjustment, it teaches real-world embedded programming concepts using MicroPython on the Raspberry Pi Pico. The use of Thonny IDE ensures a beginner-friendly experience, while the end result is a visually stunning lamp that responds to human touch.

11 References

  • Raspberry Pi Pico Official Docs
  • NeoPixel Uberguide by Adafruit
  • MicroPython Reference for Pico
  • Thonny IDE Setup
  • Random Nerd Tutorials – MicroPython & Sensors
  • Raspberry Pi Pico + MicroPython NeoPixel Projects

12 Project Authors

  • Lenie Joy Badil
  • Naphtali Montayre
Quality Checked by:
  • John Ronan M. Limbadan
  • Alexander B. Maiso
Digital Mood Lamp with Raspberry Pi Pico - CreateLabz
NeopixelNeopixel ringPotentiometerRaspberry piRaspberry pi picoRgbRpiRpi pico

Leave a comment

All comments are moderated before being published