Upgraded firmware for Simone Giertz's Every Day Calendar that links an ATProto-powered ESP32, for sync with goals.garden 🌱
3
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add CLAUDE.md with project-specific gotchas

Document hard-won debugging lessons:
- Timer2 ISR blocking causes LED flicker
- I2C bitmap protocol to minimize transactions
- ATmega328P 32-byte Wire buffer limit
- Jetstream-triggered sync instead of periodic

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

+76 -22
+5
.vscode/extensions.json
··· 1 1 { 2 + // See http://go.microsoft.com/fwlink/?LinkId=827846 3 + // for the documentation about the extensions.json format 2 4 "recommendations": [ 3 5 "platformio.platformio-ide" 6 + ], 7 + "unwantedRecommendations": [ 8 + "ms-vscode.cpptools-extension-pack" 4 9 ] 5 10 }
+67
CLAUDE.md
··· 1 + # CLAUDE.md 2 + 3 + ## CLAUDE.md Maintenance 4 + 5 + **Keep this file lean.** Only include: 6 + 7 + - Project-specific setup that isn't obvious from package.json/config files 8 + - API patterns unique to this codebase 9 + - Hard-won lessons from debugging (gotchas that caused real bugs) 10 + - User preferences for how Claude should work 11 + 12 + **Don't include:** General language/framework knowledge, standard patterns, things discoverable from file structure. 13 + 14 + **Update this file** when you discover: 15 + 16 + - A non-obvious bug or gotcha that took debugging to figure out 17 + - A project-specific pattern that would save research time 18 + - New user preferences expressed during the conversation 19 + 20 + --- 21 + 22 + ## Project Overview 23 + 24 + Simone Giertz's Every Day Calendar with WiFi sync to goals.garden (ATProto/Bluesky). 25 + 26 + **Hardware:** 27 + - ATmega328P: Main calendar controller, runs LED multiplexing via Timer2 ISR 28 + - ESP32-S3 (QT Py): WiFi/sync module, I2C slave at address 0x42 29 + 30 + ## Critical Gotchas 31 + 32 + ### Timer2 ISR blocks everything 33 + The LED matrix is multiplexed at ~3900Hz via Timer2 ISR. **Any blocking operation causes visible LED flicker.** This is why: 34 + - Serial communication failed (UART blocking caused flicker) 35 + - I2C transactions must be minimal and fast 36 + - The calendar polls the ESP32, not vice versa 37 + 38 + ### I2C protocol must minimize transactions 39 + Individual SET_LED commands (~367 transactions for full state) caused visible LED flashing every poll cycle. **Solution:** Bitmap protocol sends full state in 2 transactions (24 bytes each for months 0-5 and 6-11). 40 + 41 + ### ATmega328P Wire buffer is 32 bytes 42 + Can't send more than 32 bytes per I2C transaction. Bitmap protocol uses 25 bytes (1 type + 24 data) per part to stay within limit. 43 + 44 + ### Sync on Jetstream connect, not periodically 45 + Periodic syncs cause unnecessary traffic and complexity. Sync only when Jetstream WebSocket (re)connects - this catches startup and any missed events from disconnections. 46 + 47 + ### Don't sync before Jetstream connects 48 + Initial `performFullSync()` in `connectATProto()` caused double-sync because Jetstream connects asynchronously and triggers another sync. Let the Jetstream connection detection handle all syncs. 49 + 50 + ## Build Commands 51 + 52 + ```bash 53 + # Calendar firmware (ATmega328P) 54 + pio run -e calendar 55 + pio run -e calendar -t upload 56 + 57 + # ESP32 firmware 58 + pio run -e esp32sync 59 + pio run -e esp32sync -t upload 60 + ``` 61 + 62 + ## ESP32 Configuration 63 + 64 + Copy `firmware/esp32/GoalsGardenSync/config.local.h.example` to `config.local.h` and fill in: 65 + - WiFi credentials 66 + - Bluesky identifier and app password 67 + - Goal URI from goals.garden
+4 -22
README.md
··· 6 6 7 7 **New in this fork:** 8 8 9 - - WiFi sync with goals.garden (ATProto) via ESP32-S3 co-processor 9 + - WiFi sync with goals.garden (ATProto) via a [QT Py ESP32-S3](https://www.adafruit.com/product/5426) co-processor 10 10 - Real-time updates via Jetstream WebSocket 11 - - Simplified brightness buttons (single tap for on/off) 12 - - Light wave animation when enabling a day 13 - - Starburst animation around touched lights 11 + - Simplified brightness buttons just full brightness or off. 12 + - Light wave/fireworks animation when enabling a day 14 13 15 14 ## Quick Start (PlatformIO) 16 15 ··· 19 18 ### Building the Calendar Firmware 20 19 21 20 ```bash 22 - pio run -e calendar 23 21 pio run -e calendar -t upload 24 22 ``` 25 23 ··· 32 30 firmware/esp32/GoalsGardenSync/config.local.h 33 31 ``` 34 32 35 - 2. Edit `config.local.h` with your WiFi and Bluesky credentials: 33 + 2. Edit `config.local.h` with your WiFi and ATProto/Bluesky credentials (you'll need to make an [app-password](https://bsky.app/settings/app-passwords), this project doesn't support OAuth): 36 34 37 35 ```cpp 38 36 #define WIFI_SSID "your-wifi-ssid" ··· 45 43 3. Build and upload: 46 44 47 45 ```bash 48 - pio run -e esp32sync 49 46 pio run -e esp32sync -t upload 50 47 ``` 51 - 52 - ### Hardware Setup for WiFi Sync 53 - 54 - Connect an ESP32-S3 (e.g., Adafruit QT Py) to the calendar's "Unused I/O" header: 55 - 56 - - Calendar A2 (RX) <- ESP32 TX 57 - - Calendar A3 (TX) -> ESP32 RX 58 - - GND -> GND 59 - - 3.3V or 5V -> ESP32 power (see note below) 60 - 61 - **Power note:** You can use 3.3V from J1/J2 headers to the ESP32's 3V pin, or 5V from the barrel jack to the ESP32's 5V pin. Don't connect USB while externally powered. 62 - 63 - The ESP32 will be available at `everydaycalendar.local` on your network. 64 - 65 - --- 66 48 67 49 ## The Every Day Calendar (Original) 68 50