Skip to content

feat: Add ESP32 climb preview display firmware for Waveshare LCD#645

Open
marcodejongh wants to merge 6 commits intomainfrom
claude/esp32-climb-preview-Exo4F
Open

feat: Add ESP32 climb preview display firmware for Waveshare LCD#645
marcodejongh wants to merge 6 commits intomainfrom
claude/esp32-climb-preview-Exo4F

Conversation

@marcodejongh
Copy link
Owner

Add firmware for the Waveshare ESP32-S3 Touch LCD 4.3" to display
climb previews from Boardsesh party sessions. Features:

  • LovyanGFX-based display driver for 800x480 RGB parallel LCD
  • Real-time climb preview via GraphQL subscription
  • Shows climb name, angle, difficulty, and hold visualization
  • WiFiManager for easy WiFi configuration
  • Web-based configuration portal for API key and session ID
  • Touch screen support (GT911 controller)
  • Double-buffered rendering with PSRAM sprites

The display uses the same controllerEvents subscription as the LED
controller, showing colored circles for lit-up holds matching the
web UI colors.

https://claude.ai/code/session_01KQdMgLnHiXmpn2TxKcS6Pd

@vercel
Copy link

vercel bot commented Feb 2, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
boardsesh Building Building Preview, Comment Feb 3, 2026 5:21am

Request Review

@claude
Copy link

claude bot commented Feb 2, 2026

Claude Review

Ready to merge - Minor issues noted below, but nothing blocking.

Issues

  1. Memory leak potential in climb_display.cpp:58-71: _boardSprite and _infoSprite are allocated with new but never deleted in a destructor. Acceptable for embedded singletons that live for the device lifetime, but consider adding a destructor for completeness.

  2. Hardcoded placeholder data in main.cpp:330-344 (populateHoldPositionCache): The function generates a fake grid of positions starting at ID 4117 which won't match actual board configurations. Real boards will show holds in incorrect positions. The README documents this needs manual configuration, but runtime behavior may be confusing for users.

  3. Potential precision issue in drawHold color extraction (climb_display.cpp:324-327): The RGB565 extraction uses << 3 and << 2 to expand to 8-bit, then multiplies by 0.7 for darkening. The order loses some precision compared to darkening first then expanding - minor visual impact only.

  4. LedCommand struct redefinition (graphql_ws_client.h:9-14): The struct is defined with a #ifndef LED_COMMAND_DEFINED guard, but if led_controller.h is included elsewhere with a different definition, ODR violations could occur. This is mitigated by the conditional include system but worth noting.

  5. Missing tests: No unit tests are included for the new display logic, hold position calculations, or GraphQL callback handling. Given the complex coordinate transformations in hold_positions.h, tests would help ensure correctness across board configurations.

Documentation

No documentation updates needed - this is a new standalone embedded project that doesn't affect documented systems in docs/.

Add firmware for the Waveshare ESP32-S3 Touch LCD 4.3" to display
climb previews from Boardsesh party sessions. Features:

- LovyanGFX-based display driver for 800x480 RGB parallel LCD
- Real-time climb preview via GraphQL subscription
- Shows climb name, angle, difficulty, and hold visualization
- WiFiManager for easy WiFi configuration
- Web-based configuration portal for API key and session ID
- Touch screen support (GT911 controller)
- Double-buffered rendering with PSRAM sprites

The display uses the same controllerEvents subscription as the LED
controller, showing colored circles for lit-up holds matching the
web UI colors.

https://claude.ai/code/session_01KQdMgLnHiXmpn2TxKcS6Pd
…port

- Add GraphQLLedUpdateCallback type for receiving parsed LED updates
- Add setLedUpdateCallback() method to GraphQL client
- Make LED controller and BLE dependencies optional using __has_include
- Update climb-preview-display to use new callback API
- Add proxy mode compatibility documentation

The GraphQL client now supports display-only devices that don't have
LED controllers. When ledUpdateCallback is set, LED updates are
forwarded to the callback instead of directly controlling LEDs.

This enables the climb-preview-display to work alongside the
board-controller in proxy mode.

https://claude.ai/code/session_01KQdMgLnHiXmpn2TxKcS6Pd
@marcodejongh marcodejongh force-pushed the claude/esp32-climb-preview-Exo4F branch from 1d42160 to aff915e Compare February 2, 2026 12:39
The display can now serve as a BLE proxy itself, connecting directly to
official Kilter/Tension boards and forwarding LED commands from Boardsesh.

Changes:
- Create aurora-ble-client library for BLE client functionality
- Add BLE connection status to display info panel
- Add memory leak fix with proper destructor for ClimbDisplay
- Update main.cpp with BLE proxy support and auto-reconnect
- Update documentation with new proxy mode architecture

https://claude.ai/code/session_01KQdMgLnHiXmpn2TxKcS6Pd
@claude
Copy link

claude bot commented Feb 2, 2026

Claude Review

Ready to merge - This is a well-structured ESP32 firmware addition. Minor issues noted below, but nothing blocking.

Issues

  1. embedded/libs/aurora-ble-client/src/aurora_ble_client.cpp:68 - Memory leak: pScanCallbacks = new ScanCallbacks(this) is never freed in destructor (class has no destructor defined)

  2. embedded/libs/aurora-ble-client/src/aurora_ble_client.h:508 - connectToDevice method declared but not implemented in .cpp file

  3. embedded/projects/climb-preview-display/src/main.cpp:2455-2468 - Placeholder hold position data is hardcoded for testing. This will not work correctly for production use with real Kilter boards. Consider documenting more clearly that users must generate actual hold data for their board configuration.

  4. embedded/libs/graphql-ws-client/src/graphql_ws_client.cpp:303 - climbName variable is shadowed - it's declared at line 303 then referenced from data again at line 364 (now just strlen(climbName) > 0), but the variable was already extracted at the top of the function.

Documentation

No documentation updates needed - this is new embedded firmware with comprehensive README.

- Add destructor to AuroraBLEClient to fix memory leak (pScanCallbacks)
- Remove unused connectToDevice() declaration from header
- Add comprehensive documentation for placeholder hold data, making it
  clear that users must replace it with real board data for production

https://claude.ai/code/session_01KQdMgLnHiXmpn2TxKcS6Pd
@claude
Copy link

claude bot commented Feb 2, 2026

Claude Review

Ready to merge - Minor issues noted below, but nothing blocking. This is a well-structured addition of ESP32 firmware for a climb preview display with BLE proxy capability.

Issues

  1. Memory leak potential in error path - embedded/libs/climb-display/src/climb_display.cpp:601-609: If _boardSprite creation succeeds but _infoSprite creation fails, _boardSprite is not cleaned up before returning false.

  2. Race condition in BLE scanning - embedded/projects/climb-preview-display/src/main.cpp:155-159: The lastBleScanTime is updated before startScan() is called, but if startScan() fails or throws, the timestamp is still updated, potentially delaying retry.

  3. Unbounded vector growth - embedded/projects/climb-preview-display/src/main.cpp:2309-2311: currentLedCommands vector is cleared and repopulated each update but never has a size limit. On memory-constrained ESP32, this could cause issues with malformed backend data.

  4. Placeholder data warning - embedded/projects/climb-preview-display/src/main.cpp:2445-2491: populateHoldPositionCache() contains placeholder data that won't work with real boards. While documented, it's easy to miss. Consider adding a more prominent runtime warning or requiring configuration.

  5. Missing null check - embedded/libs/graphql-ws-client/src/graphql_ws_client.cpp:299-300: climbName is used in the later log statement without checking if it's null first (only length is checked).

Documentation

No documentation updates needed - this is a new embedded component and includes its own comprehensive README at embedded/projects/climb-preview-display/README.md.

Tests

No tests included, but this is ESP32 firmware where automated testing is non-trivial. The README includes manual testing instructions.

claude and others added 2 commits February 2, 2026 20:26
- climb_display.cpp: Fix memory leak in error path - clean up _boardSprite
  if _infoSprite creation fails
- main.cpp: Fix race condition - only update lastBleScanTime if scan started
- main.cpp: Add MAX_LED_COMMANDS limit (500) to prevent unbounded growth
- main.cpp: Add prominent runtime warning for placeholder hold data with
  visual display message and serial log banners
- graphql_ws_client.cpp: Use explicit null checks for climbUuid/climbName
  to ensure they're never null pointers

https://claude.ai/code/session_01KQdMgLnHiXmpn2TxKcS6Pd
Add new firmware project for LilyGo T-Display S3 (170x320) to display
climb queue information with QR codes for quick access to climbs.

Changes:
- Create lilygo-display shared library with ST7789 driver and UI rendering
- Add climb-queue-display project with WiFi AP mode for first-time setup
- Add ws:// and wss:// protocol prefix support to graphql-ws-client
- Add AP mode support to wifi-utils library for captive portal setup

Features:
- Shows current climb name, grade (with color), and angle
- Generates QR codes linking to climb in Kilter/Tension app
- Displays climb history (last 3 climbs)
- Status bar showing WiFi, backend, and BLE connection status
- Web config portal for WiFi, API key, and session setup

Note: BLE proxy mode is disabled pending NimBLE 1.4.x API compatibility fixes.

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

claude bot commented Feb 3, 2026

Claude Review

Ready to merge - This is a new embedded firmware project for ESP32 displays. No blocking issues found, minor suggestions noted below.

Issues

  1. Missing WiFiManager include in climb-queue-display - embedded/projects/climb-queue-display/platformio.ini doesn't include tzapu/WiFiManager@^2.0.17 in lib_deps, but the wifi-utils library may rely on it. The climb-preview-display project includes it.

  2. Callback signature mismatch - embedded/projects/climb-preview-display/src/main.cpp:3034 declares onLedUpdate with 5 parameters but GraphQLLedUpdateCallback in graphql_ws_client.h:40 now has 7 parameters (added grade and gradeColor). The callback won't compile correctly.

  3. Incomplete AP_MODE handling - embedded/libs/wifi-utils/src/wifi_utils.cpp:128 adds AP_MODE to the enum but wifi_utils.h still declares state checks without handling this new state in the state callback.

  4. Potential memory leak in climb_display.cpp:600-622 - If _boardSprite->createSprite() fails, the code properly cleans up, but if _infoSprite->createSprite() fails and _boardSprite was successfully created, the cleanup deletes _boardSprite but then immediately tries to delete the uninitialized/null _infoSprite pointer (line 619 deletes _infoSprite which was never created).

  5. Variable shadowing - embedded/libs/graphql-ws-client/src/graphql_ws_client.cpp:45 declares local bool useSSL = true which shadows the class member this->useSSL declared at line 188. The local variable is used for assignment but never propagates correctly to the member until line 66.

Notes

  • No tests included, but this is typical for embedded firmware in this repo
  • Documentation is comprehensive with good README files

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants