Breadboard prototype: WeAct Studio ESP32-S3-N16R8, 128×128 SSD1327 (GND / VCC / SCL / SDA), two discrete LEDs, GPIO 4 touch wake pad, and DS18B20 on GPIO 10. Sensor fail on the OLED is T:--Error--.
Status: shipped breadboard firmware · v0.5.1 · green CI compile · PCB / desk case still planned.
I find this working well and have not found any bugs. Unless I find something to add to its function, or a bug, this is now shipped code.
After Wi-Fi connects, MiniMe serves a LAN web dashboard at http://<board-ip>/ (Display, SysInfo, LOG, Serial). Theme matches k9dtv.com (light/dark). IC chips: theme (sun/moon) and Display / Log layout.
LAN web UI (v0.5.1): light/dark + Display/Log layout chips; Sig / Heap / Srv bars share one left edge and stop at the Display panel edge. SysInfo shows live CPU MHz. Screenshot follows the site theme toggle.
This is my first big modern MCU / Discord bot project on ESP32. AI helped with firmware edits, multi-file layout, and GitHub updates. I owned the architecture, wiring, Discord Gateway/OLED design, commands, power/idle trade-offs, and what shipped on the board.
Ongoing project
Firmware on the GitHub repo is shipped. Hardware and optional extras still on the list:
- Wireless firmware updates - update the ESP32 over the network without USB each time (Wi-Fi OTA is in firmware; keep polishing)
- Mention / DM indicators on set1 / set2 - DM to the bot flashes set1 at 10 Hz; @mention of
OWNER_ID_STRflashes set2 at 10 Hz. Owner!clearturns both off - PCB and desk case - move off the breadboard onto a custom board and enclosure
What this bot can do
Same list Discord shows for !help.
Public commands
DMs, TARGET_CHANNEL_ID, or TARGET_CHANNEL_ID1:
!apod- NASA Astronomy Picture of the Day!ask <question>- DeepSeek text reply in chat!display <text>- payload on OLED rows 15-16 (not the word!display)!help- command list!iss- International Space Station position!news- space / high-tech headlines!physics- latest arXiv physics papers!sys- uptime (d h m s), heap (SRAM + PSRAM), Wi-Fi RSSI, gateway, USB VBUS!temp- indoor DS18B20 temperature!time- bot local time (US Pacific, DST aware)!weather <zip>- US ZIP weather (OpenWeatherMap)
Owner-only
OWNER_ID_STR:
!led on/off/!led <r> <g> <b>- RGB NeoPixel (GPIO 48)!servo <0-90>- servo angle (updates theSrv:bar)!set1 on/!set1 off- digital output pin 1!set2 on/!set2 off- digital output pin 2!clear- stop set1/set2 flash and force both off!ota- Wi-Fi firmware update info (IP / hostname)
Automatic posts
Sent once to TARGET_CHANNEL_ID after Gateway connects (boot only):
!sysdiagnostics!helpcommand list
No repeating 4-hour sys posts or daily temperature summaries. Commands still work in TARGET_CHANNEL_ID, TARGET_CHANNEL_ID1, and DMs.
Bot Discord presence
- Starts Online when the Gateway identifies
- Goes Idle after 5 minutes with no activity
- Returns to Online on commands and the boot channel announce (touch does not set Online)
How it works
Everything runs on one ESP32-S3. Discord stays in the cloud; MiniMe talks to it over Gateway (websocket) and REST (HTTPS), paints the OLED, serves a LAN web dashboard, and wakes the panel from a touch pad.
Cloud
WeAct ESP32-S3
- Gateway - live link for chat commands, presence, Online/Idle, heartbeats
- REST - bot posts replies, loads member names, pulls weather/science/AI APIs
- OLED - always the status board; sleep blanks the panel only (Wi-Fi and Gateway stay up)
- LAN web UI - same board status in a browser at
http://<board-ip>/; light/dark theme and Display/Log layout chips; refreshes about once a second; does not replace OLED. The LOG panel is capped at 20 KB; if the next line would go over, LOG is cleared (avoids unbounded growth). Serial stays a fixed 12-line ring - Touch - wakes the OLED only; does not change Discord status or fire GPIO commands
OLED dashboard
128×128 SSD1327 status board (U8g2). Font is 5×7 with 1px padding (8px per row).
| Row | Baseline y | What it shows |
|---|---|---|
| 0 | 7 | MiniMe, GW:Good / GW:Bad, time |
| 2 | 15 | Bot Online/Idle; date (right) |
| 3 | 23 | Uptime + temp; fail: T:--Error-- |
| 4 | 31 | Sig: Wi-Fi RSSI bar |
| 5 | 39 | Heap: memory bar (SRAM + PSRAM) |
| 6 | 47 | Srv: servo bar 0-90° |
| 7-14 | 55...111 | Eight user rows: name, presence, command count (24h) |
| 15-16 | 119 / 127 | Command text or !display payload (blank when idle) |
After 1 minute idle the panel dims, then turns off (setPowerSave). Touch on GPIO 4, commands, and the boot channel announce wake it. When the OLED is off and Discord is Idle, CPU is 80 MHz; otherwise 240 MHz.
Secrets and IDs
Copy MiniMe_Discord_Bot/secrets.example.h to secrets.h and fill in:
#define WIFI_SSID "ssid"
#define WIFI_PASSWORD "password"
#define BOT_TOKEN "bot token"
#define WEATHER_API_KEY "WEATHER_API_KEY"
#define NASA_API_KEY "NASA_API_KEY"
#define DEEPSEEK_API_KEY "DEEPSEEK_API_KEY"
#define BOT_GUILD_ID "GUILD_ID"
#define OWNER_ID_STR "OWNER_ID_STR"
#define TARGET_CHANNEL_ID "TARGET_CHANNEL_ID"
#define TARGET_CHANNEL_ID1 "TARGET_CHANNEL_ID1"
Use #define (not const char*) so every .cpp can include secrets.h without linker errors. IDs are digits only as C strings. OTA password (if used) also lives in secrets.h.
How to get a Discord bot token
- Open the Discord Developer Portal.
- New Application → name it → Create.
- Bot → Add Bot if needed → copy token into
BOT_TOKEN. - Enable Message Content, Server Members, and Presence intents.
- OAuth2 → URL Generator: scope
bot, permissions View Channels, Send Messages, Read Message History → invite to your server.
Owner, channel, and guild IDs
Enable Discord Developer Mode, then:
- Owner ID: right-click your avatar → Copy User ID →
OWNER_ID_STR - Channel ID: right-click text channel → Copy Channel ID
- Guild ID: right-click server icon → Copy Server ID →
BOT_GUILD_ID
Hardware (default pins)
WeAct Studio ESP32-S3-N16R8 (16MB flash, 8MB PSRAM). Display: SSD1327 128×128 I2C.
| Device | GPIO |
|---|---|
RGB NeoPixel (!led) | 48 |
| Servo | 47 |
Digital out 1 (!set1) | 6 |
Digital out 2 (!set2) | 7 |
| DS18B20 data | 10 |
| OLED SDA / SCL | 8 / 9 |
| Touch wake pad | 4 |
| USB VBUS ADC | 1 |
OLED labels: GND, VCC, SCL, SDA. Change pins in minime_config.h if your wiring differs.
Touch wake pad (GPIO 4)
Capacitive pad on GPIO 4 wakes the OLED after dim/off. Connect copper tape or a short wire to GPIO 4; no external pull-up needed. USB VBUS on GPIO 1 (10 kΩ divider) compensates touch thresholds when port voltage sags.
Touch only wakes the OLED - it does not send Discord messages, change Online/Idle, or move GPIO outputs.
Arduino IDE setup
- Install Arduino IDE and the Espressif esp32 board package.
- Open only
MiniMe_Discord_Bot/MiniMe_Discord_Bot.ino(plus the sketch.cpp/.hfiles andpartitions.csv). - Board: ESP32S3 Dev Module; enable USB CDC On Boot, OPI PSRAM, 16MB flash; use the sketch
partitions.csv(dual OTA apps, no filesystem). - Libraries: WebSockets, ArduinoJson, U8g2, OneWire, DallasTemperature, Adafruit NeoPixel, NTPClient.
- Copy
secrets.example.htosecrets.hand fill in. - Upload. Confirm with Discord
!help, the OLED, andhttp://<board-ip>/.
GitHub Actions compiles the sketch on every push to master (compile check only; does not upload to the board).
Safety
Never commit live bot tokens, API keys, passwords, or Discord snowflake IDs. Reset leaked tokens in the Developer Portal immediately.
Original MiniMe source and docs in the repo are under the MIT License. See LICENSE on GitHub.