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.

Clean up ESP32 logging

Remove verbose debug output:
- HTTP request URLs and response codes
- JSON parse error details
- Session refresh messages
- Individual item counts during sync

Keep useful logs:
- Startup and connection status
- Button press actions and results
- Sync completion summaries
- Error conditions

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

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

+7 -72
+3 -18
firmware/esp32/GoalsGardenSync/GoalsGardenSync.ino
··· 333 333 334 334 if (event.action == JetstreamAction::Create) { 335 335 // For creates, check if it's for our goal 336 - Serial.printf("Jetstream create: goalUri='%s' year=%d month=%d day=%d\n", 337 - event.goalUri.c_str(), event.year, event.month, event.day); 338 - Serial.printf("Expected goalUri='%s'\n", goalUri.c_str()); 339 - 340 - if (event.goalUri != goalUri) { 341 - Serial.println(F("Goal URI mismatch - ignoring")); 342 - return; 343 - } 336 + if (event.goalUri != goalUri) return; 344 337 345 338 year = event.year; 346 339 month = event.month; ··· 357 350 } 358 351 359 352 // Only process if it's for current year 360 - if (year != currentYear) { 361 - Serial.printf("Year mismatch: %d != %d - ignoring\n", year, currentYear); 362 - return; 363 - } 353 + if (year != currentYear) return; 364 354 365 355 // Convert to calendar coordinates (0-indexed) 366 356 uint8_t calMonth = month - 1; // 0-11 367 357 uint8_t calDay = day - 1; // 0-30 368 358 369 - if (calMonth >= 12 || calDay >= 31) { 370 - Serial.printf("Invalid date: month=%d day=%d - ignoring\n", calMonth, calDay); 371 - return; 372 - } 359 + if (calMonth >= 12 || calDay >= 31) return; 373 360 374 361 // Update internal state (calendar will pick up on next poll) 375 362 if (event.action == JetstreamAction::Create) { 376 - Serial.printf("Setting LED: month=%d day=%d ON\n", calMonth, calDay); 377 363 calendarI2C.setState(calMonth, calDay, true); 378 364 } else if (event.action == JetstreamAction::Delete) { 379 - Serial.printf("Setting LED: month=%d day=%d OFF\n", calMonth, calDay); 380 365 calendarI2C.setState(calMonth, calDay, false); 381 366 } 382 367 }
+4 -46
firmware/esp32/GoalsGardenSync/atproto_client.cpp
··· 11 11 pdsUrl = pdsUrl.substring(0, pdsUrl.length() - 1); 12 12 } 13 13 14 - Serial.printf("Creating session at %s for %s\n", pdsUrl.c_str(), handle.c_str()); 15 - 16 14 HTTPClient http; 17 15 WiFiClientSecure client; 18 16 client.setInsecure(); // Skip cert validation ··· 40 38 did = respDoc["did"].as<String>(); 41 39 accessJwt = respDoc["accessJwt"].as<String>(); 42 40 refreshJwt = respDoc["refreshJwt"].as<String>(); 43 - 44 - Serial.println(F("Session created successfully")); 45 41 http.end(); 46 42 return true; 47 - } else { 48 - Serial.printf("JSON parse error: %s\n", error.c_str()); 49 43 } 50 - } else { 51 - Serial.printf("HTTP error: %d\n", httpCode); 52 - Serial.println(http.getString()); 53 44 } 54 45 55 46 http.end(); ··· 71 62 } 72 63 73 64 String ATProtoClient::httpGet(const String& endpoint) { 74 - if (!isAuthenticated()) { 75 - Serial.println(F("httpGet: not authenticated")); 76 - return ""; 77 - } 65 + if (!isAuthenticated()) return ""; 78 66 79 67 HTTPClient http; 80 68 WiFiClientSecure client; 81 69 client.setInsecure(); // Skip cert validation 82 70 83 71 String url = pdsUrl + endpoint; 84 - Serial.printf("GET %s\n", url.c_str()); 85 72 86 73 http.begin(client, url); 87 74 http.addHeader("Authorization", "Bearer " + accessJwt); 88 75 89 76 int httpCode = http.GET(); 90 - Serial.printf("Response: %d\n", httpCode); 91 77 92 78 String response = ""; 93 79 if (httpCode == 200) { ··· 98 84 http.end(); 99 85 return httpGet(endpoint); 100 86 } 101 - } else { 102 - Serial.printf("GET failed: %d\n", httpCode); 103 - if (httpCode > 0) { 104 - Serial.println(http.getString()); 105 - } 106 87 } 107 88 108 89 http.end(); ··· 110 91 } 111 92 112 93 String ATProtoClient::httpPost(const String& endpoint, const String& body) { 113 - if (!isAuthenticated()) { 114 - Serial.println(F("httpPost: not authenticated")); 115 - return ""; 116 - } 94 + if (!isAuthenticated()) return ""; 117 95 118 96 HTTPClient http; 119 97 WiFiClientSecure client; ··· 136 114 http.end(); 137 115 return httpPost(endpoint, body); 138 116 } 139 - } else { 140 - Serial.printf("POST %s failed: %d\n", endpoint.c_str(), httpCode); 141 - if (httpCode > 0) { 142 - Serial.println(http.getString()); 143 - } 144 117 } 145 118 146 119 http.end(); ··· 148 121 } 149 122 150 123 bool ATProtoClient::refreshSession() { 151 - Serial.println(F("Refreshing session...")); 152 124 153 125 HTTPClient http; 154 126 WiFiClientSecure client; ··· 169 141 if (!error) { 170 142 accessJwt = doc["accessJwt"].as<String>(); 171 143 refreshJwt = doc["refreshJwt"].as<String>(); 172 - Serial.println(F("Session refreshed")); 173 144 http.end(); 174 145 return true; 175 146 } 176 147 } 177 148 178 - Serial.println(F("Session refresh failed")); 179 149 http.end(); 180 150 return false; 181 151 } ··· 191 161 192 162 JsonDocument doc; 193 163 DeserializationError error = deserializeJson(doc, response); 194 - if (error) { 195 - Serial.printf("JSON parse error: %s\n", error.c_str()); 196 - return goals; 197 - } 164 + if (error) return goals; 198 165 199 166 JsonArray records = doc["records"].as<JsonArray>(); 200 167 for (JsonObject record : records) { ··· 213 180 goals.push_back(goal); 214 181 } 215 182 216 - Serial.printf("Found %d goals for year %d\n", goals.size(), year); 217 183 return goals; 218 184 } 219 185 ··· 238 204 url += "&cursor=" + cursor; 239 205 } 240 206 241 - Serial.printf("GET %s\n", url.c_str()); 242 - 243 207 HTTPClient http; 244 208 WiFiClientSecure client; 245 209 client.setInsecure(); 246 210 http.begin(client, url); 247 211 248 212 int httpCode = http.GET(); 249 - Serial.printf("Response: %d\n", httpCode); 250 213 251 214 if (httpCode != 200) { 252 - Serial.printf("Backlinks request failed: %d\n", httpCode); 253 215 http.end(); 254 216 break; 255 217 } ··· 259 221 260 222 JsonDocument doc; 261 223 DeserializationError error = deserializeJson(doc, response); 262 - if (error) { 263 - Serial.printf("JSON parse error: %s\n", error.c_str()); 264 - break; 265 - } 224 + if (error) break; 266 225 267 226 JsonArray records = doc["records"].as<JsonArray>(); 268 227 for (JsonObject record : records) { ··· 319 278 } 320 279 } 321 280 322 - Serial.printf("Found %d completions for year %d\n", completions.size(), year); 323 281 return completions; 324 282 } 325 283
-3
firmware/esp32/GoalsGardenSync/calendar_i2c.cpp
··· 53 53 54 54 // Update internal state immediately 55 55 setState(btn.month, btn.day, btn.state); 56 - 57 - Serial.printf("I2C: Button month=%d, day=%d, state=%d\n", 58 - btn.month, btn.day, btn.state); 59 56 } 60 57 break; 61 58 }
-5
firmware/esp32/GoalsGardenSync/jetstream_client.cpp
··· 22 22 webSocket.beginSSL(JETSTREAM_HOST, JETSTREAM_PORT, path.c_str()); 23 23 webSocket.onEvent(webSocketEvent); 24 24 webSocket.setReconnectInterval(5000); 25 - 26 - Serial.printf("Jetstream subscribing to %s\n", did.c_str()); 27 25 } 28 26 29 27 void JetstreamClient::update() { ··· 139 137 event.action = JetstreamAction::Unknown; 140 138 return; // Ignore updates for now 141 139 } 142 - 143 - Serial.printf("Jetstream event: %s %s/%s\n", 144 - operation.c_str(), collection.c_str(), rkey.c_str()); 145 140 146 141 eventQueue.push(event); 147 142 }