A cute, AI-powered bathroom companion for the M5Stack Core 2. It greets you every morning with an animated kawaii face, a personalized weather-based briefing, and spoken advice β all running on a tiny ESP32 device.
- Animated Kawaii Face β Expressive eyes with realistic blinking, emotions (happy, excited, surprised, sleepy, thinking), and rosy cheeks
- AI Morning Briefing β Tap the screen or just make noise β get a personalized German morning briefing powered by any LLM via OpenRouter
- Text-to-Speech β Briefings are spoken aloud using OpenAI TTS (voice: nova)
- Live Weather β Real-time temperature, humidity, and conditions via Open-Meteo (free, no API key)
- Smart Wake/Sleep β Falls asleep after 2 minutes of inactivity; wakes on vibration (tap the shelf!) or sound (say "Guten Morgen!")
- Auto Brightness β Adjusts display brightness based on time of day (bright during day, dim at night)
- Status Bar β Clock, date, WiFi indicator, battery level with charging state
- Sleep Mode β Dark theme with floating Z animation and dim clock
Mount it in your bathroom (a small shelf or suction cup mount works great). Every morning:
- Walk in β vibration or sound wakes it up
- It fetches weather + generates a briefing via AI
- Shows and speaks: "Guten Morgen! Heute wird es 4 Grad bei Nieselregen β nimm den Regenschirm mit und zieh dich warm an. Du schaffst das!"
- After 30 seconds (or a touch), it goes back to showing the kawaii face with weather
| Component | Details |
|---|---|
| Device | M5Stack Core 2 (ESP32, 320Γ240 IPS touch, speaker, IMU, microphone) |
| Power | USB-C (or battery β built-in 390mAh LiPo) |
| Mounting | Any small shelf, suction cup mount, or 3D-printed stand |
Note: This runs on the device itself (MicroPython) β no external server or Raspberry Pi needed. Just WiFi and power.
- M5Stack Core 2 with MicroPython/UIFlow2 firmware
- Python 3.x on your computer (for deployment)
- mpremote (
pip install mpremote) or pyserial
cp config_example.json config.jsonEdit config.json:
{
"wifi_ssid": "YourWiFi",
"wifi_password": "YourPassword",
"openrouter_api_key": "sk-or-v1-...",
"openrouter_model": "anthropic/claude-3.5-haiku",
"lat": 53.87,
"lon": 10.69,
"language": "de",
"timezone_offset": 1,
"openai_api_key": "sk-...",
"tts_voice": "nova"
}| Key | Required | Description |
|---|---|---|
wifi_ssid |
β | Your WiFi network name |
wifi_password |
β | WiFi password |
openrouter_api_key |
β | OpenRouter API key for AI briefing |
openrouter_model |
β | LLM model (default: anthropic/claude-3.5-haiku) |
lat / lon |
β | Your location for weather (default: LΓΌbeck, Germany) |
timezone_offset |
β | Hours offset from UTC (default: 1 = CET) |
openai_api_key |
β | OpenAI key for TTS (optional β works without, just no voice) |
tts_voice |
β | OpenAI TTS voice: nova, alloy, shimmer, echo, fable, onyx |
Option A: mpremote (recommended)
./upload.sh /dev/ttyUSB0 # Linux
./upload.sh /dev/cu.usbserial-* # macOSOption B: deploy.py (with serial console output)
python deploy.py
β οΈ Edit thePORTandPROJECT_DIRvariables indeploy.pyto match your setup.
The device will:
- Connect to WiFi
- Sync time via NTP
- Show the kawaii face with weather
- Wait for interaction (touch, vibration, or sound)
boot.py β WiFi + NTP setup
main.py β Async event loop orchestrator
βββ face.py β Kawaii face rendering + blink animation
βββ ui.py β Screen states (IDLE/LOADING/BRIEFING/SLEEPING)
βββ weather.pyβ Open-Meteo weather fetcher
βββ briefing.py β OpenRouter LLM briefing generator
βββ sense.py β IMU vibration + microphone wake detection
βββ tts.py β OpenAI text-to-speech playback
The system runs 8 concurrent async loops:
| Loop | Frequency | Purpose |
|---|---|---|
face_loop |
10 FPS | Animate kawaii face (blink, emotions) |
ui_loop |
10 FPS | UI animations (loading dots, sleep Zs, progress bar) |
clock_loop |
1/sec | Update clock + battery |
weather_loop |
1/30min | Fetch weather from Open-Meteo |
wifi_loop |
1/30sec | Monitor WiFi connectivity |
sensor_loop |
~3/sec | IMU + microphone wake detection |
touch_loop |
10/sec | Touch event handling |
brightness_loop |
1/5min | Auto-adjust display brightness |
| State | Description |
|---|---|
| IDLE | Kawaii face + weather flanks + "Touch fΓΌr Morning Briefing" |
| LOADING | Thinking face + animated dots |
| BRIEFING | Mini face + word-wrapped text + progress bar + TTS playback |
| SLEEPING | Dark theme + sleepy face + floating Zs + dim clock |
Weather descriptions are in German, powered by Open-Meteo's free API (no key needed). Supports all WMO weather codes from clear sky to thunderstorms.
The assistant wakes from sleep on:
- Vibration β Tap the shelf or surface (IMU accelerometer, threshold: 0.35g deviation)
- Sound β Clap, speak, or make noise (microphone, threshold: amplitude > 20000)
- Touch β Tap the screen directly
Cooldown: 5 seconds between triggers to avoid false positives.
- No TTS? Works fine without an OpenAI key β you just won't get spoken briefings
- Different LLM? Change
openrouter_modelin config β any OpenRouter model works - Adjust sensitivity: Edit
VIBRATION_THRESHOLDandSOUND_THRESHOLDinsense.py - Sleep timeout: Default 2 minutes β change
sleep_timeoutinmain.py(milliseconds) - DST: Manually update
timezone_offset(1 for CET, 2 for CEST) β no auto-DST on ESP32
MIT β do whatever you want with it.
- M5Stack for the excellent Core 2 hardware
- Open-Meteo for free weather data
- OpenRouter for unified LLM access
- OpenAI for TTS
Built with π©· and MicroPython
