Skip to content

About

ESP32 + Raspberry Pi Pico projects: from first blink to Pixel the DJ, a Wi-Fi desk robot with a servo head, Telegram bot, music, weather and games

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

ESP32 Maker Projects

My electronics projects, from a first blinking LED to Pixel the DJ, a Wi-Fi desk robot that dances to my music, shows album art, turns its head with a servo and talks to me on Telegram.

Built on an ESP32 DevKit (Arduino framework) and a Raspberry Pi Pico (MicroPython), with parts from two starter kits.


⭐ Pixel the DJ (pixel_dj/)

A desk companion with a personality that reacts to the room, to me, and to whatever I'm listening to.

On the desk

  • Animated eyes on an OLED that blink, look around and change mood (happy, tired, bored, grumpy)
  • A head that turns (SG90 servo): it sways on every beat, does a double-take when I arrive, shakes "no" when grumpy and relaxes the motor when idle
  • Music mode: when a song starts on my phone, the OLED shows the album art (downloaded, decoded and dithered to 1-bit), the LCD scrolls title and artist, and the LED strip pulses to the beat in the cover's main colour
  • Comments on my music: "First song of the day!", "This one again?!", "Song #3 from Tame Impala!"
  • Late night mode: music in a dark room gives dim purple light and sleepy dancing instead of sleeping
  • Touch pad: tap, double-tap (saves the current song), or hold to pet it
  • Reacts to presence (PIR), light (LDR) and temperature/humidity (DHT11), and gets bored if ignored

From anywhere, through a Telegram bot

Command What it does
/np Current song with album art, artist, album and BPM
/pet Pixel purrs and nuzzles on the desk
/say <text> Shows a message on Pixel's LCD
/room Temperature, humidity, lights on or off, whether someone is there, mood
/today Today's song count and top artists
/saved Songs I saved by double-tapping
/party Rainbow LEDs, a little tune and wild head swaying
/guard on|notify|off Desk alarm: 10-second countdown to disarm (secret IR hold), then siren + phone alert
/remind 20m drink water, /reminders, /cancel Reminders on the desk (chime, LCD, flashing strip) and on the phone
/focus 25 Focus timer: quiet mode, LED progress bar, break reminder. Also by holding a hand over the IR sensor.
/alarm 07:00 Daily alarm with sunrise lights; wave to snooze, touch to stop
/breaks 50, /water on Stand-up nudge after sitting too long (tracked with the PIR), hourly water reminder
/weather, /location Weather (Open-Meteo); location shared from the phone with one tap
/history 24-hour chart of temperature, humidity, light and desk time (QuickChart)
/game, /rlgl Reaction game (wave when the eyes flash) and Red Light, Green Light with the turning head
/head <55-125>, /trim, /dance on|off Turn the head, fine-tune its centre, switch head dancing
/status, /log Uptime, Wi-Fi signal, memory, last error, recent log lines (also at http://<Pixel IP>/)
Automatic Morning weather briefing on first arrival, rain warnings, nightly recap at 23:00

The bot only answers its owner's chat ID.

How it works

Phone (YT Music) ──► Pano Scrobbler ──► Last.fm API ─┐
                                                      │  Wi-Fi
MusicBrainz + AcousticBrainz (tempo) ─────────────────┤
Telegram Bot API (commands, alerts) ◄────────────────►│
                                                      ▼
┌─────────────────────────── ESP32 ───────────────────────────┐
│ Core 0: netTask                    Core 1: loop() (the pet)  │
│  - polls Last.fm every 8 s          - eyes, LCD, LED strip   │
│  - downloads + dithers album art    - servo head gestures    │
│  - looks up the song's BPM          - touch, PIR, LDR, DHT11 │
│  - Telegram long-lived TLS link     - non-blocking buzzer    │
│        └──── FreeRTOS queues + mutex ────┘                   │
└──────────────────────────────────────────────────────────────┘

All slow network work runs on its own core, so the eyes and the dancing never freeze while a download is in progress.

Problems I solved along the way

  • 5 V LCD on a 3.3 V board: the LCD's I2C backpack pulls its data lines up to 5 V. Two 3.3 kΩ resistors in series to GND on each line bring them down to ~2.9 V, so the LCD and OLED can share one I2C bus safely.
  • Out of memory: the PNG decoder needs ~40 KB in one block. Allocating it at boot, before Wi-Fi and TLS fragment the heap, fixed a crash I traced with the ESP32 backtrace decoder.
  • Only one TLS connection fits: the Telegram connection is closed briefly while album art and tempo are downloaded, then reopens.
  • HTTPS failing with 80 KB free: the TLS library reported BIGNUM - Memory allocation failed. Free memory was fragmented, so I removed 19 KB of static buffers (the album-art work area now reuses the download buffer). Weather and location use plain HTTP to save TLS memory.
  • Too close to the router: a −4 dBm signal overloaded the radio, so bigger transfers failed. The /status command now warns about it.
  • No USB cable, still debuggable: logs go to a RAM ring buffer, readable with /log or a small status web page, and updates install over Wi-Fi (OTA).
  • A "memory leak" that wasn't: heap dropped ~300 bytes per Last.fm request, then levelled off after 2 minutes. Closed TCP sockets stay in TIME_WAIT for a while.
  • Buzzer vs servo: both use the ESP32's PWM hardware. Putting them on channels with different hardware timers stops the buzzer's pitch changes from disturbing the servo's 50 Hz signal.
  • Progressive JPEG covers: asking Last.fm for .png instead gives an image the microcontroller can decode.

All projects

Listed in the order I built them.

Getting started (ESP32 starter kit)

Sketch What it does
esp32_blink First program: blink the onboard LED
step1_oled Find the OLED on the I2C bus and draw on it
step2_dht11 Temperature and humidity on the OLED
step3_pin_check, step3_rgb_test Diagnose the RGB LED's wiring pin by pin
step3_temp_color RGB LED colour follows the temperature
step4_buzzer, buzzer_test Temperature alarm with a passive buzzer
step5_wifi Live sensor dashboard as a web page over Wi-Fi (http://esp32.local/)
step6_motion Adds a PIR motion sensor to the dashboard

Games and displays

Sketch What it does
red_light_green_light Statue game: the PIR catches you moving on red. High score saved in flash.
lcd_oled_test Two displays on one I2C bus (5 V LCD + 3.3 V OLED)
now_playing What's playing on my phone, with dithered album art and an LED strip in the cover's colour
now_playing_dual Same, on two screens, with a beat-synced equaliser from the song's BPM

The desk pet

Sketch What it does
desk_pet_sensor_check Shows every sensor's live reading, to check the wiring
desk_pet Pixel, stage 1: eyes, moods, speech bubble, petting, sleep
servo_test Learn how a servo works (pulse length → angle) before it became Pixel's head
pixel_dj Pixel the DJ: everything above + music, Telegram, a moving head, daily helpers, desk health, weather and games. Split into tabs: 01_pet … 13_games.

Raspberry Pi Pico (MicroPython)

Project What it does
pico/lcd_dimmer Turn a knob to fade an LED; the LCD shows the brightness and a bar graph. Includes my own small LCD1602 driver.

Hardware

Part Used for
ESP32 DevKit (ESP32-D0WD-V3) Main board
0.96" SSD1306 OLED (I2C) Eyes, album art
LCD1602 with I2C backpack Speech bubble, song title
WS2812 8-LED strip Mood and beat lighting
SG90 micro servo Pixel's head
HC-SR501 PIR, LDR, DHT11, touch pad (GPIO32) Presence, light, climate, petting
IR obstacle module Wave and hold gestures, reaction game
Passive buzzer Sounds and melodies
Raspberry Pi Pico MicroPython projects

Pixel's pins: OLED + LCD on SDA 22 / SCL 23 · strip 5 · servo 18 · IR 19 · PIR 33 · buzzer 13 · LDR 34 · touch 32 · DHT11 4

Build it yourself

  1. Install the ESP32 board package (Espressif, v3.x) in the Arduino IDE or arduino-cli.
  2. Install the libraries: Adafruit SSD1306, Adafruit GFX, Adafruit NeoPixel, DHT sensor library, LiquidCrystal I2C, ArduinoJson (v7), PNGdec, FluxGarage RoboEyes.
  3. For sketches that use Wi-Fi, copy secrets.example.h to secrets.h in the same folder and fill in your Wi-Fi, Last.fm API key and Telegram bot token (from @BotFather). secrets.h is git-ignored.
  4. Build and upload, e.g.
    arduino-cli compile --fqbn esp32:esp32:esp32:PartitionScheme=min_spiffs pixel_dj
    arduino-cli upload -p COM9 --fqbn esp32:esp32:esp32:PartitionScheme=min_spiffs pixel_dj
    

Pixel uses the Minimal SPIFFS partition scheme (1.9 MB app, with OTA). After the first USB upload it can be updated over Wi-Fi with espota (password in secrets.h).

For music features, your phone needs to scrobble to Last.fm (I use YT Music + the Pano Scrobbler app).

Next up

  • Pixel's body turns toward you: a DC motor on a homemade turntable, with the Pico as a motor controller talking to the ESP32
  • Wave gestures with two IR sensors, and a smart lamp with the relay
  • Robot car

License

MIT

About

ESP32 + Raspberry Pi Pico projects: from first blink to Pixel the DJ, a Wi-Fi desk robot with a servo head, Telegram bot, music, weather and games

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages