Skip to main content
Detailed explanation of the ESPHome configuration for the ED1 board.

File structure

ed1-hoas
ed1-message.sample.yaml
ed1-mqtt.sample.yaml
ed1-status.sample.yaml
secrets.yaml
secrets.sample.yaml
packages
core.yaml
hardware.yaml
display.yaml
fonts.yaml
buzzer.yaml
buttons.yaml
sensors.yaml
bluetooth.yaml
ir-receiver.yaml
led-matrix.yaml
mqtt.yaml
stepper.yaml

Modular package system

This project uses ESPHome’s package system for modularity. Each sample config uses !include to import reusable components from the packages/ directory.

Basic structure

substitutions:
  device_name: ed1-mydevice
  friendly_name: ED1 My Device
  ap_ssid: ED1-MyDevice-Rescue

packages:
  core: !include packages/core.yaml
  hardware: !include packages/hardware.yaml
  display: !include packages/display.yaml
  fonts: !include packages/fonts.yaml
  buzzer: !include packages/buzzer.yaml
  buttons: !include packages/buttons.yaml
  sensors: !include packages/sensors.yaml
  bluetooth: !include packages/bluetooth.yaml

Extending package components

Use !extend to override or add to components defined in packages:
# Override display lambda
display:
  - id: !extend internal_display
    lambda: |-
      // Custom display code here

# Add custom button behavior
binary_sensor:
  - id: !extend btn_ok
    on_press:
      - logger.log: "Custom OK action"
      - rtttl.play: 'success:d=8,o=5,b=160:c,e,g'

Creating a new configuration

  1. Copy an existing sample (e.g., ed1-message.sample.yaml)
  2. Update the substitutions section with your device name
  3. Add or remove packages as needed
  4. Override display lambda and button behaviors for your use case

Secrets setup

  1. Copy the sample file:
    cp secrets.sample.yaml secrets.yaml
    
  2. Edit secrets.yaml with your values:
    wifi_ssid: "YourNetworkName"
    wifi_password: "YourWiFiPassword"
    api_encryption_key: "base64-encoded-key"
    ota_password: "secure-ota-password"
    fallback_ap_password: "fallback-password"
    
  3. Generate an API key:
    openssl rand -base64 32
    

Package reference

The following sections describe what each package contains. These are automatically included when you use !include packages/<name>.yaml.

Core configuration (packages/core.yaml)

esphome:
  name: ed1-rev23-a
  friendly_name: ED1 Rev 2.3 A

esp32:
  board: esp32dev
  framework:
    type: arduino
  • name: Device hostname (lowercase, hyphens only)
  • friendly_name: Display name in Home Assistant
  • board: Generic ESP32 dev board
  • framework: Arduino for best compatibility

Connectivity (packages/core.yaml)

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  ap:
    ssid: "ED1-Rev23-Rescue"
    password: !secret fallback_ap_password

captive_portal:
  • ap: Fallback access point if WiFi fails
  • captive_portal: Web config when in AP mode

Hardware buses (packages/hardware.yaml)

spi:
  clk_pin: GPIO18
  mosi_pin: GPIO23
  miso_pin: GPIO19

i2c:
  sda: GPIO21
  scl: GPIO22
  scan: true
  id: bus_i2c
  • scan: true: Logs detected I2C devices on boot

Fonts (packages/fonts.yaml)

font:
  - file: "fonts/pixelmix/pixelmix.ttf"
    id: pixel_font
    size: 8
  - file: "fonts/pixelmix/pixelmix.ttf"
    id: large_font
    size: 16
The font file is included in the fonts/ directory.

TFT display (packages/display.yaml)

display:
  - platform: st7735
    id: internal_display
    cs_pin: GPIO5
    dc_pin: GPIO9
    reset_pin: GPIO10
    rotation: 0
    model: "INITR_GREENTAB"
    col_start: 2
    row_start: 3
    device_width: 128
    device_height: 128
    update_interval: 1s
    lambda: |-
      // Drawing code here
Display layout:
LineContentColor
1”ED1 FULL”Green
2IP addressWhite
3CPU temperatureWhite
4Matrix textYellow
Model Options:
  • INITR_GREENTAB: Use with row_start: 3 for 1.44” 128x128 displays (equivalent to Adafruit’s INITR_144GREENTAB)
  • INITR_BLACKTAB: Alternative initialization
  • INITR_18REDTAB: For 1.8” displays

LED matrix display (packages/led-matrix.yaml)

display:
  - platform: addressable_light
    id: led_matrix_display
    addressable_light_id: led_matrix_light
    width: 32
    height: 8
    pixel_mapper: |-
      if (x % 2 == 0) return (x * 8) + y;
      return (x * 8) + (7 - y);
    update_interval: 50ms
    lambda: |-
      // Text rendering
pixel_mapper: Handles the serpentine wiring pattern where odd columns are reversed.

LED matrix light (packages/led-matrix.yaml)

light:
  - platform: esp32_rmt_led_strip
    rgb_order: GRB
    chipset: WS2812
    pin: GPIO12
    num_leds: 256
    name: "ED1 LED Matrix"
    id: led_matrix_light
    default_transition_length: 0s
    color_correct: [40%, 40%, 40%]
  • platform: esp32_rmt_led_strip: ESPHome native driver using ESP-IDF 5.x RMT
  • rgb_order: GRB: Color order (Green-Red-Blue)
  • chipset: WS2812: LED chipset type
  • color_correct: Reduces brightness to 40% (power savings)
Note: We use esp32_rmt_led_strip instead of neopixelbus for compatibility with the IR receiver. Both use the RMT peripheral but the native driver uses the newer ESP-IDF 5.x API.

Bluetooth proxy (packages/bluetooth.yaml)

esp32_ble_tracker:
  scan_parameters:
    interval: 1100ms
    window: 1100ms

bluetooth_proxy:
  active: true
Extends Home Assistant’s Bluetooth range. The ED1 acts as a BLE relay.

MQTT (packages/mqtt.yaml)

Optional package for MQTT broker connectivity. Can be used alongside or instead of the native API.
mqtt:
  broker: !secret mqtt_broker
  username: !secret mqtt_user
  password: !secret mqtt_password
  topic_prefix: ed1/${device_name}
Topics:
  • ed1/<device_name>/message - Subscribe to receive messages
  • ed1/<device_name>/status - Publishes online/offline
Usage:
  1. Add MQTT credentials to secrets.yaml
  2. Include the package: mqtt: !include packages/mqtt.yaml
  3. Send messages via CLI: mosquitto_pub -t ed1/ed1-message/message -m "Hello!"
Choosing API vs MQTT:
  • Use native API for Home Assistant integration (auto-discovery, encryption)
  • Use MQTT for multi-system integration (Node-RED, scripts, other devices)
  • Both can be used simultaneously

Stepper motors (packages/stepper.yaml)

Controls two 28BYJ-48 stepper motors via the MCP23009 I2C GPIO expander and ULN2004A Darlington drivers.
packages:
  stepper: !include packages/stepper.yaml
Technical Details:
  • Uses direct I2C register writes (not ESPHome’s mcp23008 component)
  • Full-step mode: 512 steps = 1 complete revolution
  • Non-blocking interval-based stepping (2ms per step)
  • Compatible with MicroBlocks “ED1 Stepper Motor” library
Exposed Entities:
EntityTypeDescription
number.motor1_stepsNumberM1 steps (-4096 to +4096)
number.motor2_stepsNumberM2 steps (-4096 to +4096)
button.motor1_cwButtonM1 clockwise (512 steps)
button.motor1_ccwButtonM1 counter-clockwise
button.motor2_cwButtonM2 clockwise (512 steps)
button.motor2_ccwButtonM2 counter-clockwise
button.motors_stopButtonStop all motors, power down
button.motor_diagnosticButtonLog MCP23009 registers
Usage Example:
# In your main config, extend button behavior
binary_sensor:
  - id: !extend btn_up
    on_press:
      - script.execute:
          id: motor1_run
          steps: 128  # 1/4 turn forward
Step Counts:
  • 128 steps = 1/4 turn (90°)
  • 256 steps = 1/2 turn (180°)
  • 512 steps = 1 full turn (360°)

Buzzer (packages/buzzer.yaml)

output:
  - platform: ledc
    pin: GPIO26
    id: buzzer_output

switch:
  - platform: output
    name: "ED1 Buzzer"
    id: buzzer_switch
    output: buzzer_output
The buzzer uses PWM via the LEDC (LED Control) peripheral. Turning the switch on activates the buzzer with a continuous tone.

IR receiver (packages/ir-receiver.yaml)

remote_receiver:
  pin:
    number: GPIO35
    inverted: true
  dump: all
  on_nec:
    then:
      - lambda: |-
          ESP_LOGI("IR", "NEC: address=0x%04X, command=0x%04X", x.address, x.command);
  on_samsung:
    then:
      - lambda: |-
          ESP_LOGI("IR", "Samsung: data=0x%08X", x.data);
  • dump: all: Logs all received IR codes (useful for debugging)
  • on_nec/on_samsung: Protocol-specific handlers
  • IR codes appear in ESPHome logs, not as Home Assistant entities
  • Use to trigger automations based on remote control buttons

Touch buttons (packages/buttons.yaml)

esp32_touch:
  setup_mode: false

binary_sensor:
  - platform: esp32_touch
    id: btn_up
    name: "ED1 Button Up"
    pin: GPIO4
    threshold: 500
    on_press:
      - logger.log: "Button Up PRESSED"
Threshold Tuning:
  • Default: 500
  • If too sensitive: Increase threshold
  • If not responding: Decrease threshold
  • Enable setup_mode: true temporarily to see raw values

Sensors (packages/sensors.yaml)

# Safe RSSI value for display use (handles NaN before first reading)
globals:
  - id: wifi_rssi
    type: int
    initial_value: '-100'

sensor:
  - platform: wifi_signal
    name: "ED1 WiFi Signal"
    id: wifi_signal_sensor
    update_interval: 10s
    on_value:
      - lambda: 'id(wifi_rssi) = (int)x;'

  - platform: internal_temperature
    name: "ED1 CPU Temperature"
    id: cpu_temp

  - platform: adc
    pin: GPIO34
    name: "ED1 Light Level"
    attenuation: 12db
    unit_of_measurement: "%"
    filters:
      - multiply: 30.3  # Scale to 0-100%
Note: The wifi_rssi global provides a safe integer value for display code. Before the first WiFi signal reading (~10 seconds after boot), the sensor returns NaN which can cause display issues when cast to int. The global defaults to -100 dBm and updates on each reading.

Text input (packages/led-matrix.yaml)

text:
  - platform: template
    name: "ED1 Matrix Text"
    id: matrix_text_input
    optimistic: true
    min_length: 0
    max_length: 20
    mode: text
Allows Home Assistant to send text to display on the LED matrix.

Customization

Change display content

Modify the lambda in the display section:
lambda: |-
  it.fill(Color(0, 0, 0));
  it.print(0, 0, id(pixel_font), Color(255, 0, 0), "Custom Text");

Add button actions

binary_sensor:
  - platform: esp32_touch
    id: btn_ok
    name: "ED1 Button OK"
    pin: GPIO15
    threshold: 500
    on_press:
      - light.toggle: led_matrix_light

Adjust matrix brightness

Change color_correct values (0-100%):
color_correct: [20%, 20%, 20%]  # Dimmer
color_correct: [100%, 100%, 100%]  # Full brightness

Troubleshooting

Device not detected via USB

The ED1 uses a CP2102N USB-to-UART chip. Install the driver:
  • Download from Silicon Labs CP210x Drivers
  • Install for your OS (Windows, macOS, Linux)
  • Reconnect the USB cable
  • The device should appear as /dev/ttyUSB0 (Linux), /dev/cu.SLAB_USBtoUART (macOS), or COM3 (Windows)

Display shows garbage

  • Check model setting matches your display
  • Try adjusting col_start and row_start offsets
  • Verify SPI pins are correct

Touch buttons not working

  • Enable setup_mode: true in esp32_touch
  • Check logs for raw touch values
  • Adjust threshold based on idle vs touched values

LED matrix wrong colors

  • Change rgb_order from GRB to RGB or BRG
  • Some strips use different color orders

WiFi connection issues

  • Check signal strength sensor
  • Reduce update_interval on sensors to reduce traffic
  • Try static IP configuration

Device not discovered

  • Ensure API encryption key matches
  • Check Home Assistant logs for connection attempts
  • Verify device is on same network subnet