Chicken Coop Door — ESP32 + IBT-2 + ESPHome#

codex resume 01a00aab-e96d-7aa3-8a96-579fe3727d04

Overview#

This note documents the final working configuration for controlling the chicken coop door using:

  • ESP32 development board
  • ESP32 screw-terminal breakout board
  • IBT-2 / BTS7960 H-bridge motor driver
  • 14 V DC linear actuator
  • 14 V DC power supply
  • ESPHome
  • Home Assistant

The ESP32 communicates with Home Assistant over Wi-Fi using ESPHome.

The IBT-2 controls the direction of the two-wire DC actuator by reversing the polarity applied to the actuator.

The final system provides three Home Assistant controls:

  • Coop Door Open
  • Coop Door Close
  • Coop Door Stop

The ESP32 is powered separately through USB. The actuator receives its power from the 14 V supply through the IBT-2.


Hardware#

ESP32#

ESP32 development board installed in a screw-terminal breakout board.

Relevant terminals used:

ESP32 Purpose
3V3 IBT-2 logic supply / R_EN
GND Common logic ground
D25 / GPIO25 IBT-2 RPWM
D26 / GPIO26 IBT-2 LPWM
D27 / GPIO27 IBT-2 L_EN

The breakout provides more than one GND connection. They are electrically common, so either may be used.


IBT-2 / BTS7960 Motor Driver#

The control header on this particular board is labeled:

VCC
GND
R_IS
L_IS
R_EN
L_EN
RPWM
LPWM

The four large green power/motor terminals were identified from the markings on the reverse side of the actual board as:

B-    B+    M+    M-

Where:

Terminal Function
B- 14 V supply negative
B+ 14 V supply positive
M+ Actuator lead
M- Actuator lead

Final Wiring#

ESP32 → IBT-2#

Final working control wiring:

IBT-2 ESP32 Purpose
VCC 3V3 IBT-2 logic power
GND GND Common logic ground
RPWM D25 / GPIO25 Motor direction control
LPWM D26 / GPIO26 Motor direction control
R_EN 3V3 Permanently enables one side of driver
L_EN D27 / GPIO27 Enables other side under ESPHome control
R_IS Not connected Optional current-sense output
L_IS Not connected Optional current-sense output

R_IS and L_IS are not required for basic actuator operation and are left disconnected.


Why R_EN and L_EN Are Different#

The final wiring uses:

R_EN → 3V3
L_EN → GPIO27

R_EN is permanently held HIGH.

L_EN is controlled by ESPHome using GPIO27 and is turned HIGH during boot.

This avoids needing another physical connection to the ESP32’s 3V3 terminal while still enabling both sides of the motor driver.


Actuator → IBT-2#

The actuator has two wires:

  • Pink
  • Black

Final connection:

Actuator IBT-2
Pink M+
Black M-

For a two-wire DC actuator, these wires are not permanently positive and negative.

The H-bridge reverses the polarity across M+ and M- to reverse the actuator direction.

Therefore:

one polarity → actuator extends
opposite polarity → actuator retracts

The physical pink/black assignment can therefore be reversed if necessary. In this installation, direction was corrected in ESPHome instead of rewiring the actuator.


14 V Power Supply → IBT-2#

The power supply also has:

  • Pink wire
  • Black wire

Unlike the actuator wires, polarity matters here.

Because the wires had no polarity markings, polarity was verified using a multimeter.

Measuring polarity#

Multimeter:

Mode: DC Voltage (V⎓)

Measurement:

Red probe   → Pink power-supply wire
Black probe → Black power-supply wire

Reading: +14.34 V

Because the reading was positive:

Pink  = positive
Black = negative

Final connection:

Power supply IBT-2
Pink (+14.34 V) B+
Black (−) B-

Never determine DC supply polarity solely from wire color. Measure it if the cable is not explicitly marked.


Complete Wiring Summary#

ESP32                    IBT-2
────────────────────────────────────

3V3  ──────────────────> VCC
GND  ──────────────────> GND

GPIO25 / D25 ──────────> RPWM
GPIO26 / D26 ──────────> LPWM

3V3  ──────────────────> R_EN
GPIO27 / D27 ──────────> L_EN

                          R_IS  [unused]
                          L_IS  [unused]


14 V POWER SUPPLY        IBT-2
────────────────────────────────────

Pink  +14.34 V ─────────> B+
Black negative ─────────> B-


LINEAR ACTUATOR           IBT-2
────────────────────────────────────

Pink  ──────────────────> M+
Black ──────────────────> M-

Power Architecture#

There are two separate power functions in the system.

ESP32 / logic power#

The ESP32 is powered through:

USB-C

The ESP32 then provides 3.3 V logic power to the IBT-2 control circuitry.

Motor power#

The actuator receives power from:

14 V DC power supply
       IBT-2
 linear actuator

The 14 V supply does not power the ESP32 directly.


ESPHome Installation#

The ESP32 was initially flashed using ESPHome.

After the initial USB installation and successful Wi-Fi connection, subsequent firmware updates can be performed OTA:

ESPHome
→ Install
→ On the network

The device was successfully assigned:

Hostname: coop-door
IP during setup: 10.1.3.70

The IP address may change unless a DHCP reservation/static assignment is configured.

Successful ESPHome logs included:

Successfully connected to coop-door
Successful handshake with coop-door
WiFi:
  Connected: YES

and finally:

Boot seems successful; resetting boot loop counter

Final ESPHome Configuration#

The first motor test revealed that the logical Open and Close directions were reversed.

Rather than changing the physical motor wires, GPIO25 and GPIO26 were logically swapped in ESPHome.

Final configuration:

esphome:
  name: coop-door
  friendly_name: Coop Door
  min_version: 2026.4.0
  name_add_mac_suffix: false

  on_boot:
    priority: -100
    then:
      # Make absolutely sure the actuator is stopped at startup
      - output.turn_off: motor_open
      - output.turn_off: motor_close

      # Enable the L side of the BTS7960
      - output.turn_on: motor_enable

esp32:
  variant: esp32
  framework:
    type: esp-idf

# Enable logging
logger:

# Enable Home Assistant API
api:

# Allow Over-The-Air updates
ota:
  - platform: esphome

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

# BTS7960 control outputs
output:
  # LPWM -> GPIO26
  # This is the physical direction that OPENS the door
  - platform: gpio
    pin: GPIO26
    id: motor_open

  # RPWM -> GPIO25
  # This is the physical direction that CLOSES the door
  - platform: gpio
    pin: GPIO25
    id: motor_close

  # L_EN -> GPIO27
  # R_EN is permanently enabled from 3V3
  - platform: gpio
    pin: GPIO27
    id: motor_enable

# Motor control scripts
script:
  - id: stop_motor
    mode: restart
    then:
      - output.turn_off: motor_open
      - output.turn_off: motor_close

  - id: open_door
    mode: restart
    then:
      # Stop before changing direction
      - script.execute: stop_motor
      - delay: 250ms

      # Drive actuator in OPEN direction
      - output.turn_on: motor_open

      # Absolute safety timeout
      - delay: 45s
      - output.turn_off: motor_open

  - id: close_door
    mode: restart
    then:
      # Stop before changing direction
      - script.execute: stop_motor
      - delay: 250ms

      # Drive actuator in CLOSE direction
      - output.turn_on: motor_close

      # Absolute safety timeout
      - delay: 45s
      - output.turn_off: motor_close

# Home Assistant controls
button:
  - platform: template
    name: "Coop Door Open"
    icon: mdi:arrow-up-bold
    on_press:
      - script.stop: close_door
      - script.execute: open_door

  - platform: template
    name: "Coop Door Close"
    icon: mdi:arrow-down-bold
    on_press:
      - script.stop: open_door
      - script.execute: close_door

  - platform: template
    name: "Coop Door Stop"
    icon: mdi:stop
    on_press:
      - script.stop: open_door
      - script.stop: close_door
      - script.execute: stop_motor

Motor Control Logic#

Open#

Home Assistant:

Coop Door Open

executes:

Stop motor
Wait 250 ms
GPIO26 ON
Actuator moves OPEN
Maximum 45 seconds
GPIO26 OFF

Close#

Home Assistant:

Coop Door Close

executes:

Stop motor
Wait 250 ms
GPIO25 ON
Actuator moves CLOSED
Maximum 45 seconds
GPIO25 OFF

Stop#

Home Assistant:

Coop Door Stop

immediately stops both motor-direction outputs:

GPIO25 OFF
GPIO26 OFF

Direction Change Protection#

The configuration deliberately prevents immediate direction reversal.

Before either direction starts:

- script.execute: stop_motor
- delay: 250ms

This means the driver is first commanded to stop and then waits 250 ms before energizing the opposite direction.

This reduces electrical and mechanical stress from instantly reversing a moving DC motor.


45-Second Safety Timeout#

Both movement scripts contain:

- delay: 45s
- output.turn_off: motor_open

or:

- delay: 45s
- output.turn_off: motor_close

This is an absolute runtime safety limit.

The motor cannot remain commanded indefinitely if Home Assistant loses communication or a command is accidentally issued.

The 45-second timer is currently a safety timeout, not position detection.

The system currently does not know whether the door is physically open or closed unless additional position sensors are added.


Home Assistant#

After ESPHome integration, Home Assistant exposes the device as:

Coop Door (ESP32)

Controls:

↓ Coop Door Close     Press
↑ Coop Door Open      Press
■ Coop Door Stop      Press

These appear under:

Settings
→ Devices & services
→ ESPHome
→ Coop Door (ESP32)

They can also be added to a Home Assistant dashboard.


Initial Power-Up Procedure#

The system was tested conservatively in stages.

1. ESP32 only#

Power the ESP32 using USB.

Leave the 14 V motor supply disconnected.

Confirm:

ESPHome online
Wi-Fi connected
API connected
Firmware boot successful

2. Apply motor power without commanding movement#

With the ESP32 already running:

Plug in 14 V supply

Do not press Open or Close.

Expected result:

Actuator does not move

This test passed successfully.


3. Short movement test#

Because the door was already physically open, the first command used was:

Coop Door Close

The motor successfully moved.

However, the physical movement was opposite to the original software definition.

This confirmed:

  • ESP32 control worked
  • IBT-2 worked
  • actuator worked
  • 14 V supply worked
  • Home Assistant command path worked

The direction was then corrected in software by swapping the GPIO assignments for motor_open and motor_close.


Important Lessons / Troubleshooting#

IBT-2 green terminals#

The four green terminals are not control terminals.

They carry motor current and supply power:

B-
B+
M+
M-

The small control header handles:

VCC
GND
R_IS
L_IS
R_EN
L_EN
RPWM
LPWM

Actuator wire colors do not define polarity#

For the two-wire actuator:

Pink
Black

do not represent fixed positive and negative connections during operation.

The H-bridge intentionally reverses their polarity.

If the actuator moves in the wrong direction, either:

  1. swap M+ and M-, or
  2. swap the logical Open/Close outputs in software.

This installation uses option 2.


Power-brick polarity DOES matter#

Unlike the motor wires:

B+ and B-

must receive the correct supply polarity.

The power supply was measured at:

14.34 V DC

with:

Pink  = +
Black = -

ESPHome firmware direction versus physical wiring#

Physical wiring remains:

RPWM → GPIO25
LPWM → GPIO26

But the final software defines:

motor_open  → GPIO26
motor_close → GPIO25

This is intentional because the initial movement test showed that the actuator’s physical direction was opposite the original assumption.


Current Limitations#

The current controller provides movement commands, not actual door-position feedback.

It currently does not independently know:

Door fully open
Door fully closed
Door partially open
Door obstructed

The 45-second timeout only prevents indefinite motor operation.

Potential future improvements include:

  • Open-position limit sensor
  • Closed-position limit sensor
  • Door-state entity in Home Assistant
  • Proper Home Assistant cover entity
  • Obstruction/current detection
  • Automatic sunrise opening
  • Automatic sunset closing
  • Notifications if the door fails to reach its expected position
  • Manual override
  • Watchdog/failsafe behavior

Final Verified State#

At the end of the initial hardware test:

  • ESP32 flashed successfully
  • ESP32 connected to Wi-Fi
  • ESPHome API connected
  • OTA updates working
  • GPIO25 configured
  • GPIO26 configured
  • GPIO27 configured
  • IBT-2 logic connected
  • 14 V supply polarity measured
  • 14 V supply connected to B+ / B-
  • Actuator connected to M+ / M-
  • Power-up produced no unintended motor movement
  • Home Assistant controls appeared
  • Motor responded to Home Assistant
  • Stop control available
  • Physical direction identified
  • Open/Close direction corrected in ESPHome configuration
  • 45-second safety timeout configured

Final Wiring Quick Reference#

                ┌─────────────────┐
                │      ESP32      │
                │                 │
         3V3 ───┼───────────────┐ │
         GND ───┼─────────────┐ │ │
      GPIO25 ───┼───────────┐ │ │ │
      GPIO26 ───┼─────────┐ │ │ │ │
      GPIO27 ───┼───────┐ │ │ │ │ │
                └───────┼─┼─┼─┼─┼─┘
                        │ │ │ │ │
                        │ │ │ │ └── VCC
                        │ │ │ └──── R_EN
                        │ │ └────── GND
                        │ └──────── RPWM
                        └────────── LPWM / L_EN*

More explicitly:

ESP32 3V3    → IBT-2 VCC
ESP32 GND    → IBT-2 GND
ESP32 D25    → IBT-2 RPWM
ESP32 D26    → IBT-2 LPWM
ESP32 3V3    → IBT-2 R_EN
ESP32 D27    → IBT-2 L_EN

IBT-2 R_IS   → unused
IBT-2 L_IS   → unused

14 V Pink    → IBT-2 B+
14 V Black   → IBT-2 B-

Actuator Pink  → IBT-2 M+
Actuator Black → IBT-2 M-

The ASCII diagram above is illustrative. The explicit connection list immediately below it is the authoritative wiring reference.


Next Phase#

The basic motor controller is operational.

The logical next phase is to add door-position sensing so Home Assistant knows whether the coop door is actually:

OPEN
CLOSED
MOVING
UNKNOWN

Once position sensing is available, the three temporary push buttons can potentially be replaced by a proper Home Assistant Cover entity with Open / Close / Stop controls and real state feedback.

That should be completed before relying on unattended scheduled operation.