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 online status tracking for burst animation feedback

Only show burst animation when ESP32 is connected to internet,
providing visual feedback that button presses will sync.

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

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

+41 -2
+9
firmware/esp32/GoalsGardenSync/GoalsGardenSync.ino
··· 65 65 bool wifiConnected = false; 66 66 bool atprotoConnected = false; 67 67 bool wasJetstreamConnected = false; 68 + bool wasOnline = false; // Track online status for calendar animation feedback 68 69 69 70 // Timing for background refresh 70 71 unsigned long lastGoalsRefresh = 0; ··· 186 187 JetstreamEvent event = jetstream.getEvent(); 187 188 handleJetstreamEvent(event); 188 189 } 190 + } 191 + 192 + // Update online status for calendar animation feedback 193 + bool isOnline = atprotoConnected && goalUri.length() > 0; 194 + if (isOnline != wasOnline) { 195 + calendarI2C.setOnlineStatus(isOnline); 196 + wasOnline = isOnline; 197 + Serial.printf("Online status changed: %s\n", isOnline ? "online" : "offline"); 189 198 } 190 199 191 200 delay(100);
+8
firmware/esp32/GoalsGardenSync/calendar_i2c.cpp
··· 212 212 _calStatePart1Received = false; 213 213 _calStatePart2Received = false; 214 214 } 215 + 216 + void CalendarI2C::setOnlineStatus(bool online) { 217 + PendingCmd cmd; 218 + cmd.data[0] = RSP_SET_ONLINE; 219 + cmd.data[1] = online ? 1 : 0; 220 + cmd.len = 2; 221 + pendingCmds.push(cmd); 222 + }
+4
firmware/esp32/GoalsGardenSync/calendar_i2c.h
··· 22 22 #define RSP_STATE_PART1 0x84 // State bitmap months 0-5 (24 bytes) 23 23 #define RSP_STATE_PART2 0x85 // State bitmap months 6-11 (24 bytes) 24 24 #define RSP_REQUEST_CAL_STATE 0x86 // ESP32 requests calendar's current state 25 + #define RSP_SET_ONLINE 0x87 // Online status: 1 byte (0=offline, 1=online) 25 26 #define RSP_NONE 0x00 // No pending response 26 27 27 28 struct CalendarButton { ··· 56 57 bool hasCalendarState(); 57 58 void getCalendarState(uint32_t* monthStates); 58 59 void clearCalendarStateRequest(); 60 + 61 + // Send online status to calendar (for animation feedback) 62 + void setOnlineStatus(bool online); 59 63 60 64 // Static callbacks for Wire library 61 65 static void onReceiveStatic(int numBytes);
+13
firmware/libraries/EverydayCalendar/EverydayCalendar_i2c_sync.cpp
··· 10 10 _lastPollTime = 0; 11 11 _lastResponseTime = 0; 12 12 _connected = false; 13 + _online = false; 13 14 } 14 15 15 16 void EverydayCalendar_i2c_sync::begin() { ··· 160 161 break; 161 162 } 162 163 164 + case RSP_SET_ONLINE: { 165 + // ESP32 is telling us its online status 166 + if (len >= 2) { 167 + _online = data[1] != 0; 168 + } 169 + break; 170 + } 171 + 163 172 default: 164 173 break; 165 174 } ··· 205 214 206 215 bool EverydayCalendar_i2c_sync::isConnected() { 207 216 return _connected; 217 + } 218 + 219 + bool EverydayCalendar_i2c_sync::isOnline() { 220 + return _online; 208 221 } 209 222 210 223 void EverydayCalendar_i2c_sync::sendCalendarState() {
+5
firmware/libraries/EverydayCalendar/EverydayCalendar_i2c_sync.h
··· 22 22 #define RSP_STATE_PART1 0x84 // State bitmap months 0-5 (24 bytes) 23 23 #define RSP_STATE_PART2 0x85 // State bitmap months 6-11 (24 bytes) 24 24 #define RSP_REQUEST_CAL_STATE 0x86 // ESP32 requests calendar's current state 25 + #define RSP_SET_ONLINE 0x87 // Online status: 1 byte (0=offline, 1=online) 25 26 #define RSP_NONE 0x00 // No pending response 26 27 27 28 class EverydayCalendar_i2c_sync { ··· 39 40 // Check if sync is connected 40 41 bool isConnected(); 41 42 43 + // Check if ESP32 is online (can sync button presses) 44 + bool isOnline(); 45 + 42 46 private: 43 47 EverydayCalendar_lights* _lights; 44 48 unsigned long _lastPollTime; 45 49 unsigned long _lastResponseTime; 46 50 bool _connected; 51 + bool _online; // ESP32 is online and can sync button presses 47 52 48 53 // Request and process state from ESP32 49 54 void requestState();
+2 -2
firmware/sketches/EverydayCalendar/EverydayCalendar.ino
··· 189 189 // Notify ESP32 of the button press 190 190 cal_sync.sendButtonPress((uint8_t)cal_touch.x, (uint8_t)cal_touch.y, on); 191 191 192 - // Burst if toggled on 193 - if (on) { 192 + // Burst if toggled on and online (so sync will happen) 193 + if (on && cal_sync.isOnline()) { 194 194 doBurst({cal_touch.x, cal_touch.y}); 195 195 } 196 196 }