All skills
nodnarbnitram avatar

/esphome-box3-builder

@1ac816c

This skill should be used when the user asks to "configure esp32-s3-box-3", "set up box-3", "create box-3 voice assistant", "display lambda on box-3", "configure ili9xxx display", "set up gt911 touch", "configure i2s audio", "es7210 microphone", "es8311 speaker", "box-3 audio pipeline", or mentions error messages like "I2S DMA buffer error", "Touch not responding", "Display flicker", "Audio popping", "PSRAM not detected". Provides complete ESP32-S3-BOX-3 hardware templates, display lambda cookbook, touch patterns, and voice assistant configurations.

Use this Skill: https://skilld.dev/gh/nodnarbnitram/claude-code-extensions/esphome-box3-builder

This session only. Nothing lands on disk.

referencestouch-patterns.md

≈2.2k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Touch Interaction Patterns for ESP32-S3-BOX-3 GT911

Complete guide to touchscreen binary sensors, gesture detection, and page navigation patterns.

Touch Binary Sensors

Button Zone Pattern

binary_sensor:
  - platform: touchscreen
    name: "Button Name"
    x_min: 10
    x_max: 150
    y_min: 200
    y_max: 240
    on_press:
      - logger.log: "Button pressed"
    on_release:
      - logger.log: "Button released"

Common Button Sizes

Material Design minimum touch target: 48x48 pixels

  • Small button: 60x40px
  • Medium button: 100x48px
  • Large button: 140x60px
  • Full-width button: 300x48px

Button Grid Layout

3 buttons (bottom row):

binary_sensor:
  # Left button
  - platform: touchscreen
    name: "Button 1"
    x_min: 10
    x_max: 100
    y_min: 200
    y_max: 240

  # Center button
  - platform: touchscreen
    name: "Button 2"
    x_min: 110
    x_max: 210
    y_min: 200
    y_max: 240

  # Right button
  - platform: touchscreen
    name: "Button 3"
    x_min: 220
    x_max: 310
    y_min: 200
    y_max: 240

Gesture Detection

Swipe Left/Right

binary_sensor:
  # Swipe right zone
  - platform: touchscreen
    name: "Swipe Right"
    x_min: 220
    x_max: 320
    y_min: 80
    y_max: 160
    on_press:
      - lambda: |-
          id(current_page) = (id(current_page) + 1) % 3;

  # Swipe left zone
  - platform: touchscreen
    name: "Swipe Left"
    x_min: 0
    x_max: 100
    y_min: 80
    y_max: 160
    on_press:
      - lambda: |-
          id(current_page) = (id(current_page) - 1 + 3) % 3;

Long Press

binary_sensor:
  - platform: touchscreen
    name: "Long Press Button"
    x_min: 10
    x_max: 310
    y_min: 100
    y_max: 140
    on_press:
      - delay: 1s  # Long press = 1 second
      - if:
          condition:
            # Still pressed after delay
            lambda: return id(long_press_button).state;
          then:
            - logger.log: "Long press detected"

Page Navigation

Multi-Page System

Globals:

globals:
  - id: current_page
    type: int
    initial_value: '0'

Navigation Zones:

binary_sensor:
  # Previous page (left edge)
  - platform: touchscreen
    name: "Page Previous"
    x_min: 0
    x_max: 60
    y_min: 0
    y_max: 240
    on_press:
      - lambda: |-
          id(current_page) = (id(current_page) - 1 + 3) % 3;

  # Next page (right edge)
  - platform: touchscreen
    name: "Page Next"
    x_min: 260
    x_max: 320
    y_min: 0
    y_max: 240
    on_press:
      - lambda: |-
          id(current_page) = (id(current_page) + 1) % 3;

  # Direct page selection (footer buttons)
  - platform: touchscreen
    name: "Go to Page 0"
    x_min: 80
    x_max: 140
    y_min: 210
    y_max: 240
    on_press:
      - lambda: id(current_page) = 0;

  - platform: touchscreen
    name: "Go to Page 1"
    x_min: 140
    x_max: 180
    y_min: 210
    y_max: 240
    on_press:
      - lambda: id(current_page) = 1;

  - platform: touchscreen
    name: "Go to Page 2"
    x_min: 180
    x_max: 240
    y_min: 210
    y_max: 240
    on_press:
      - lambda: id(current_page) = 2;

Value Control Patterns

Increment/Decrement Buttons

binary_sensor:
  # Increase value
  - platform: touchscreen
    name: "Increase"
    x_min: 200
    x_max: 310
    y_min: 100
    y_max: 150
    on_press:
      - lambda: |-
          id(target_value) = id(target_value) + 1;
          if (id(target_value) > 30) id(target_value) = 30;  // max

  # Decrease value
  - platform: touchscreen
    name: "Decrease"
    x_min: 10
    x_max: 120
    y_min: 100
    y_max: 150
    on_press:
      - lambda: |-
          id(target_value) = id(target_value) - 1;
          if (id(target_value) < 10) id(target_value) = 10;  // min

Slider Zone (Continuous Value)

binary_sensor:
  - platform: touchscreen
    name: "Volume Slider"
    x_min: 20
    x_max: 300
    y_min: 180
    y_max: 200
    on_press:
      - lambda: |-
          // Get touch X coordinate (0-319)
          auto touch = id(box3_touch).get_touches()[0];
          int x = touch.x;

          // Map to volume (0-100%)
          int volume = (x - 20) * 100 / 280;
          volume = max(0, min(100, volume));

          id(current_volume) = volume;
          ESP_LOGI("touch", "Volume: %d%%", volume);

Toggle Patterns

On/Off Toggle

binary_sensor:
  - platform: touchscreen
    name: "Power Toggle"
    x_min: 100
    x_max: 220
    y_min: 150
    y_max: 200
    on_press:
      - lambda: |-
          id(power_state) = !id(power_state);
          if (id(power_state)) {
            ESP_LOGI("touch", "Turned ON");
          } else {
            ESP_LOGI("touch", "Turned OFF");
          }

Mode Cycling

binary_sensor:
  - platform: touchscreen
    name: "Mode Button"
    x_min: 10
    x_max: 310
    y_min: 120
    y_max: 170
    on_press:
      - lambda: |-
          id(mode) = (id(mode) + 1) % 3;  // Cycle through 3 modes
          if (id(mode) == 0) id(mode_text) = "Heat";
          else if (id(mode) == 1) id(mode_text) = "Cool";
          else if (id(mode) == 2) id(mode_text) = "Auto";

Media Player Controls

binary_sensor:
  # Play/Pause
  - platform: touchscreen
    name: "Play/Pause"
    x_min: 140
    x_max: 180
    y_min: 250
    y_max: 290
    on_press:
      - media_player.toggle: box_player

  # Previous track
  - platform: touchscreen
    name: "Previous"
    x_min: 60
    x_max: 120
    y_min: 250
    y_max: 290
    on_press:
      - media_player.play_media: !lambda return id(previous_track);

  # Next track
  - platform: touchscreen
    name: "Next"
    x_min: 200
    x_max: 260
    y_min: 250
    y_max: 290
    on_press:
      - media_player.play_media: !lambda return id(next_track);

  # Volume up
  - platform: touchscreen
    name: "Volume Up"
    x_min: 270
    x_max: 310
    y_min: 200
    y_max: 240
    on_press:
      - media_player.volume_up: box_player

  # Volume down
  - platform: touchscreen
    name: "Volume Down"
    x_min: 10
    x_max: 50
    y_min: 200
    y_max: 240
    on_press:
      - media_player.volume_down: box_player

Visual Feedback

Button Press Indicator

Display lambda:

lambda: |-
  // Draw button
  if (id(button_pressed).state) {
    it.filled_rectangle(100, 150, 120, 50, Color(33, 150, 243));  // Pressed (blue)
  } else {
    it.filled_rectangle(100, 150, 120, 50, Color(66, 66, 66));    // Normal (gray)
  }
  it.printf(160, 175, id(roboto_16), TextAlign::CENTER, "Press Me");

Touch Ripple Effect

Using globals:

globals:
  - id: ripple_x
    type: int
    initial_value: '0'
  - id: ripple_y
    type: int
    initial_value: '0'
  - id: ripple_radius
    type: int
    initial_value: '0'

On touch:

on_press:
  - lambda: |-
      auto touch = id(box3_touch).get_touches()[0];
      id(ripple_x) = touch.x;
      id(ripple_y) = touch.y;
      id(ripple_radius) = 1;
  - while:
      condition:
        lambda: return id(ripple_radius) < 50;
      then:
        - lambda: id(ripple_radius) += 5;
        - delay: 50ms
  - lambda: id(ripple_radius) = 0;

Display lambda:

if (id(ripple_radius) > 0) {
  it.circle(id(ripple_x), id(ripple_y), id(ripple_radius), Color(33, 150, 243));
}

Coordinate Reference

Display: 320x240 pixels

  • Top-left: (0, 0)
  • Top-right: (319, 0)
  • Bottom-left: (0, 239)
  • Bottom-right: (319, 239)
  • Center: (160, 120)

Safe touch zones:

  • Top bar: y 0-40
  • Content area: y 40-200
  • Bottom buttons: y 200-240

Edge margins:

  • Left/right: 10px minimum
  • Top/bottom: 10px minimum

Multi-Touch Support

GT911 supports up to 5 simultaneous touch points.

Accessing multiple touches:

auto touches = id(box3_touch).get_touches();
for (auto touch : touches) {
  ESP_LOGI("touch", "Touch at (%d, %d)", touch.x, touch.y);
}

Best Practices

  1. Minimum touch target: 48x48 pixels (Material Design)
  2. Leave 10px margins around screen edges
  3. Provide visual feedback on touch (color change, ripple)
  4. Use debouncing for sensitive actions (delay 100-200ms)
  5. Test touch zones thoroughly (adjust boundaries as needed)
  6. Group related buttons (left/center/right, top/bottom)
  7. Consistent placement (navigation always at bottom, etc.)

Summary

Buttons: x_min, x_max, y_min, y_max define touch zone Actions: on_press, on_release for interaction Gestures: Use zones for swipe left/right Pages: Use global variable + conditional rendering Feedback: Change colors, show ripple, log events Minimum size: 48x48px for touch targets

For display rendering, see display-lambdas.md For Material Design guidelines, see material-design.md

Source: SKILL.md on GitHub

2 warnings7d4 checks · Risk SAFE
  • Gen Agent Trust Hub7d

    The esphome-box3-builder skill is a legitimate tool for configuring ESP32-S3-BOX-3 hardware using ESPHome. It provides well-documented templates, UI components, and a flashing utility. All external resources are sourced from trusted providers, and the skill correctly implements credential management via ESPHome secrets.

  • Socket7d

    No alerts

  • Snyk7d

    Risk: MEDIUM · 1 issue

  • Runlayer7mo

    9/9 files flagged

Signed by skilld at 1ac816c. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 2 months ago.

Steadyupdated 6 months ago
What it can do
Reads files Edits files Network Runs commands
version
0.1.0
All 7 allowed tools
ReadWriteEditGrepGlobWebFetchBash

README badge

README badge for nodnarbnitram/claude-code-extensions/esphome-box3-builder