Controllers - ESPHome Configuration Guide

Comprehensive guide to understanding and customizing ESPHome configurations for Wala Works controllers.

Overview

Both MotorWala and RelayWala use ESPHome firmware, providing:

  • Native Home Assistant integration via API
  • MQTT support for platform independence
  • Built-in web server for standalone operation
  • Over-the-Air (OTA) updates for easy maintenance
  • Open-source and fully customizable

Configuration Files

Complete YAML configurations are available in the /configs/esphome/ directory:

  • motorwala.yaml - Motor controller configuration
  • relaywala.yaml - 4-channel relay configuration
  • secrets.yaml.example - Template for your credentials

MotorWala Configuration Dissection

Basic Device Setup

esphome:
  name: motorwala
  comment: Wala Works Motor Controller
  platform: ESP32
  board: esp32dev

Explanation:

  • name: Unique identifier for your device (used in Home Assistant)
  • platform: ESP32 microcontroller (240MHz dual-core)
  • board: Development board type (esp32dev for ESP32-WROOM-32)

WiFi Configuration

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  ap:
    ssid: "MotorWala-Setup"
    password: !secret ap_password

Explanation:

  • Uses !secret to keep credentials secure (stored in secrets.yaml)
  • ap: Fallback Access Point mode for initial setup
  • If WiFi fails, device creates "MotorWala-Setup" network for configuration

Why this matters: Local-only WiFi ensures no internet dependency. Your motor data never leaves your network.

Home Assistant API

api:
  encryption:
    key: !secret api_encryption_key

  services:
    - service: calibrate_motor
      then:
        - logger.log: "Starting motor calibration..."
        - script.execute: calibration_script

Explanation:

  • encryption: Secures communication with Home Assistant
  • services: Custom services you can call from Home Assistant
  • calibrate_motor: One-click calibration to find motor limits

Usage in Home Assistant:

# Call from automations or scripts
service: esphome.motorwala_calibrate_motor

OTA Updates

ota:
  password: !secret ota_password

Explanation:

  • Allows firmware updates over WiFi (no USB cable needed)
  • Password protects against unauthorized updates
  • Update from ESPHome dashboard or Home Assistant

Web Server (Standalone Control)

web_server:
  port: 80
  auth:
    username: !secret web_username
    password: !secret web_password

Explanation:

  • Access device at http://[DEVICE-IP] in any browser
  • No Home Assistant required for basic control
  • Password protected for security

Accessing:

  1. Find device IP: Check your router or ESPHome logs
  2. Open browser: http://192.168.1.150 (example)
  3. Login with your username/password

MQTT Integration

mqtt:
  broker: !secret mqtt_broker
  username: !secret mqtt_username
  password: !secret mqtt_password
  discovery: true
  discovery_prefix: homeassistant
  topic_prefix: walaworks/motorwala

Explanation:

  • broker: Your MQTT server address (e.g., Mosquitto)
  • discovery: Auto-registers with Home Assistant
  • topic_prefix: MQTT topics namespace

MQTT Topics:

walaworks/motorwala/cover/motor_cover/state
walaworks/motorwala/cover/motor_cover/command
walaworks/motorwala/sensor/motor_current/state

Motor Control - The Heart of MotorWala

PWM Outputs

output:
  - platform: ledc
    pin: GPIO25
    id: motor_a_forward
    frequency: 1000 Hz

  - platform: ledc
    pin: GPIO26
    id: motor_a_reverse
    frequency: 1000 Hz

Explanation:

  • ledc: ESP32's LED Controller (used for PWM)
  • GPIO25/26: Pins connected to L298N motor driver
  • 1000 Hz: PWM frequency for smooth motor operation
  • forward/reverse: H-bridge control for bi-directional movement

Hardware Connection:

ESP32 GPIO25 → L298N IN1 (Motor A Forward)
ESP32 GPIO26 → L298N IN2 (Motor A Reverse)
L298N OUT1/OUT2 → DC Motor terminals

Limit Switches

binary_sensor:
  - platform: gpio
    pin:
      number: GPIO32
      mode: INPUT_PULLUP
      inverted: true
    name: "Motor Fully Open"
    id: limit_open
    on_press:
      then:
        - cover.stop: motor_cover
        - logger.log: "Reached fully open position"

Explanation:

  • INPUT_PULLUP: Uses internal pull-up resistor (no external resistor needed)
  • inverted: true: Switch connects to ground when pressed
  • on_press: Automatically stops motor at limits

Wiring:

Limit Switch (Normally Open) → GPIO32 → Motor stops when switch closes
Common → Ground

Safety: Motor automatically stops when limit is reached, preventing damage.

Overcurrent Protection

sensor:
  - platform: adc
    pin: GPIO34
    name: "Motor Current"
    id: motor_current
    update_interval: 0.5s
    filters:
      - multiply: 3.3
      - sliding_window_moving_average:
          window_size: 10
    on_value_range:
      - above: 2.5
        then:
          - cover.stop: motor_cover
          - logger.log: "ALERT: Overcurrent detected!"

Explanation:

  • adc: Analog-to-Digital Converter reads current sensor
  • GPIO34: One of ESP32's ADC pins (ADC1_CH6)
  • multiply: 3.3: Converts ADC reading to actual current
  • sliding_window_moving_average: Smooths readings to prevent false triggers
  • above: 2.5: Triggers at 2.5A (safety threshold)

How it works:

  1. Current sensor (like ACS712) outputs voltage proportional to current
  2. ESP32 ADC reads this voltage
  3. If current exceeds 2.5A, motor stops immediately
  4. Prevents motor burnout from obstructions

Cover Entity (User Interface)

cover:
  - platform: time_based
    name: "Motor Cover"
    id: motor_cover
    device_class: curtain

    open_action:
      - switch.turn_on: motor_enable
      - output.turn_on: motor_a_forward
      - output.set_level:
          id: motor_a_forward
          level: 80%
      - output.turn_off: motor_a_reverse

    close_action:
      - switch.turn_on: motor_enable
      - output.turn_off: motor_a_forward
      - output.turn_on: motor_a_reverse
      - output.set_level:
          id: motor_a_reverse
          level: 80%

    stop_action:
      - output.turn_off: motor_a_forward
      - output.turn_off: motor_a_reverse
      - switch.turn_off: motor_enable

    open_duration: 30s
    close_duration: 30s

Explanation:

  • time_based: Tracks position based on time (vs encoder/sensor)
  • device_class: curtain: Shows curtain icon in Home Assistant
  • open_action: Sequence when opening
    1. Enable motor driver
    2. Turn on forward output
    3. Set speed to 80% (adjustable)
    4. Ensure reverse is off
  • level: 80%: PWM duty cycle controls speed (0-100%)
  • open_duration: How long to fully open (calibrate this!)

Customization:

# Slower motor (60% speed)
level: 60%

# Longer travel time (45 seconds)
open_duration: 45s

Calibration Script

script:
  - id: calibration_script
    then:
      - logger.log: "Calibrating motor positions..."
      - cover.open: motor_cover
      - wait_until:
          condition:
            binary_sensor.is_on: limit_open
          timeout: 35s
      - delay: 1s
      - cover.close: motor_cover
      - wait_until:
          condition:
            binary_sensor.is_on: limit_closed
          timeout: 35s
      - logger.log: "Calibration complete!"

Explanation:

  • Opens motor until limit_open switch triggers
  • Waits 1 second
  • Closes until limit_closed switch triggers
  • Measures time for accurate position tracking

When to calibrate:

  • First installation
  • After adjusting limit switches
  • If position becomes inaccurate

RelayWala Configuration Dissection

Device Setup - ESP8266

esphome:
  name: relaywala
  platform: ESP8266
  board: nodemcuv2

Explanation:

  • ESP8266: More affordable than ESP32, perfect for relay control
  • nodemcuv2: NodeMCU v2 development board (common and well-supported)
  • 80MHz processor is plenty for relay switching

Static IP (Recommended)

wifi:
  manual_ip:
    static_ip: !secret static_ip
    gateway: !secret gateway
    subnet: 255.255.255.0
    dns1: !secret dns1

Explanation:

  • static_ip: Device always has same IP address
  • Crucial for reliability (avoid DHCP issues)
  • Easier to remember: http://192.168.1.150

Setting static IP: In secrets.yaml:

static_ip: "192.168.1.150"
gateway: "192.168.1.1"      # Your router's IP
dns1: "8.8.8.8"              # Google DNS

Best Practice: Reserve this IP in your router's DHCP settings.

Captive Portal

captive_portal:

Explanation:

  • On first boot, if WiFi fails, device creates setup hotspot
  • Connect phone/laptop to "RelayWala-Setup"
  • Captive portal opens automatically
  • Enter WiFi credentials like connecting to public WiFi
  • Device reboots and connects

Setup Steps:

  1. Power on RelayWala (no WiFi configured)
  2. Look for "RelayWala-Setup" WiFi network
  3. Connect (password in secrets.yaml)
  4. Portal opens → enter your WiFi SSID/password
  5. Done! Device connects to your network

Advanced Services

api:
  services:
    - service: pulse_relay
      variables:
        relay_id: int
        duration: int
      then:
        - if:
            condition:
              lambda: 'return relay_id == 1;'
            then:
              - switch.turn_on: relay_1
              - delay: !lambda 'return duration;'
              - switch.turn_off: relay_1

Explanation:

  • pulse_relay: Turns relay on for specific duration, then off
  • Perfect for garage doors, gates, doorbells
  • lambda: C++ code for dynamic values

Usage from Home Assistant:

# Trigger garage door (pulse for 500ms)
service: esphome.relaywala_pulse_relay
data:
  relay_id: 1
  duration: 500
    - service: all_off
      then:
        - switch.turn_off: relay_1
        - switch.turn_off: relay_2
        - switch.turn_off: relay_3
        - switch.turn_off: relay_4

Explanation:

  • Emergency "kill switch" - turns everything off
  • Useful for automations and panic button

Relay Configuration

switch:
  - platform: gpio
    pin: GPIO16
    name: "Relay 1"
    id: relay_1
    icon: "mdi:lightbulb"
    restore_mode: RESTORE_DEFAULT_OFF
    on_turn_on:
      - output.turn_on: led_1
    on_turn_off:
      - output.turn_off: led_1

Explanation:

  • GPIO16: Pin connected to relay module (adjust per your board)
  • icon: Material Design Icon shown in UI
  • restore_mode: RESTORE_DEFAULT_OFF: After power loss, relay stays OFF (safety!)
  • on_turn_on/off: Controls LED indicator

Restore Modes:

  • RESTORE_DEFAULT_OFF: Always start OFF (safest)
  • RESTORE_DEFAULT_ON: Always start ON
  • RESTORE_INVERTED_DEFAULT_OFF: Opposite of last state, default OFF
  • RESTORE_RESTORE: Remember last state (use carefully!)

Safety Note: For water pumps, heaters, or dangerous appliances, use RESTORE_DEFAULT_OFF.

GPIO Pin Mapping (NodeMCU)

# NodeMCU Pin Labels → GPIO Numbers
GPIO16 = D0   # Relay 1
GPIO14 = D5   # Relay 2
GPIO12 = D6   # Relay 3
GPIO13 = D7   # Relay 4
GPIO0  = D3   # LED 1
GPIO15 = D8   # LED 2
GPIO4  = D2   # I2C SDA
GPIO5  = D1   # I2C SCL

Important: Use GPIO numbers in YAML, not D numbers!

Manual Control Buttons

binary_sensor:
  - platform: gpio
    pin:
      number: GPIO10
      mode: INPUT_PULLUP
      inverted: true
    name: "Button 1"
    on_press:
      - switch.toggle: relay_1

Explanation:

  • Physical button toggles relay (works without WiFi!)
  • INPUT_PULLUP: No external resistor needed
  • toggle: Press once ON, press again OFF

Wiring:

Button (Normally Open)
├─ One side → GPIO10
└─ Other side → Ground

Emergency Stop

  - platform: gpio
    pin:
      number: GPIO2
      mode: INPUT_PULLUP
      inverted: true
    name: "Emergency Stop"
    on_press:
      then:
        - switch.turn_off: relay_1
        - switch.turn_off: relay_2
        - switch.turn_off: relay_3
        - switch.turn_off: relay_4
        - logger.log: "EMERGENCY STOP activated!"

Explanation:

  • Single button turns OFF all relays
  • Critical safety feature
  • Works even if WiFi is down

Use Case: Mount emergency button near exit for safety.

Auto-Off Timers

switch:
  - platform: template
    name: "Relay 1 Auto Off"
    turn_on_action:
      - switch.turn_on: relay_1
      - delay: 3600s  # 1 hour
      - switch.turn_off: relay_1

Explanation:

  • Automatically turns off after time limit
  • 3600s = 1 hour (adjust as needed)
  • Prevents forgetting to turn off appliances

Safety Examples:

  • Water heater: 30 minutes
  • Bathroom exhaust fan: 20 minutes
  • Outdoor lights: 4 hours

Optional Current Monitoring

sensor:
  - platform: adc
    pin: A0
    name: "Total Current"
    filters:
      - multiply: 3.3
      - calibrate_linear:
          - 0.0 -> 0.0
          - 1.0 -> 10.0

Explanation:

  • Requires external current sensor (CT clamp or hall-effect)
  • A0: ESP8266's analog input pin
  • calibrate_linear: Maps sensor output to actual amperage
  • Track total power consumption

Hardware Needed:

  • SCT-013 Current Transformer (CT clamp), or
  • ACS712 Hall Effect Current Sensor

MQTT Birth/Will Messages

mqtt:
  birth_message:
    topic: walaworks/relaywala/status
    payload: online
  will_message:
    topic: walaworks/relaywala/status
    payload: offline

Explanation:

  • birth_message: Published when device connects
  • will_message: Published when device disconnects unexpectedly
  • Home Assistant uses this to show device status

Monitoring:

# Home Assistant automation
trigger:
  platform: mqtt
  topic: walaworks/relaywala/status
  payload: offline
action:
  service: notify.mobile_app
  data:
    message: "Warning: RelayWala went offline!"

Template Sensor for Status

text_sensor:
  - platform: template
    name: "RelayWala Status"
    lambda: |-
      int active_relays = 0;
      if (id(relay_1).state) active_relays++;
      if (id(relay_2).state) active_relays++;
      if (id(relay_3).state) active_relays++;
      if (id(relay_4).state) active_relays++;

      if (active_relays == 0) return {"All relays OFF"};
      return {std::to_string(active_relays) + " relay(s) active"};

Explanation:

  • lambda: Custom C++ code
  • Counts how many relays are ON
  • Returns status string
  • Shows in Home Assistant dashboard

Result: "2 relay(s) active" or "All relays OFF"


Secrets File Setup

Create secrets.yaml in your ESPHome directory:

# WiFi
wifi_ssid: "YourNetworkName"
wifi_password: "YourWiFiPassword"

# Access Point (fallback)
ap_password: "setup12345"

# API Encryption (generate with: esphome random-key)
api_encryption_key: "base64-encoded-key-here="

# OTA Password
ota_password: "securePassword123"

# Web Server
web_username: "admin"
web_password: "webPassword456"

# MQTT
mqtt_broker: "192.168.1.100"
mqtt_port: "1883"
mqtt_username: "mqttuser"
mqtt_password: "mqttpass"

# Static IPs
static_ip: "192.168.1.150"
gateway: "192.168.1.1"
dns1: "8.8.8.8"

Generating API Key:

esphome random-key

Customization Examples

Change Motor Speed

# In motor cover configuration
open_action:
  - output.set_level:
      id: motor_a_forward
      level: 60%  # Slower (was 80%)

Add More Relays

# Add 5th relay
switch:
  - platform: gpio
    pin: GPIO3  # Choose available pin
    name: "Relay 5"
    id: relay_5

Change Relay Icons

# Relay 1 → Ceiling Fan
icon: "mdi:ceiling-fan"

# Relay 2 → Water Heater
icon: "mdi:water-boiler"

# Relay 3 → Garden Lights
icon: "mdi:outdoor-lamp"

Browse all icons


Troubleshooting

Device Won't Connect to WiFi

  1. Check secrets.yaml for typos in SSID/password
  2. Ensure 2.4GHz WiFi (not 5GHz - ESP8266/32 don't support it)
  3. Connect to fallback AP: "MotorWala-Setup" or "RelayWala-Setup"
  4. Use captive portal to reconfigure

Motor Runs Wrong Direction

# Swap forward/reverse pins
open_action:
  - output.turn_on: motor_a_reverse  # was motor_a_forward

Relay Doesn't Switch

  1. Check GPIO pin number (NodeMCU labels vs GPIO numbers)
  2. Test with multimeter: Relay should click when toggled
  3. Verify relay module voltage (usually 5V)

OTA Update Fails

  1. Device must be on same network as computer
  2. Check firewall isn't blocking port 3232
  3. Verify OTA password matches secrets.yaml

Next Steps


Support

Questions about the configuration?

Previous

Next