TL;DR: Two ESPHome integration methods exist. The standard
ac_dimmerplatform works out-of-the-box but has ISR/WiFi conflicts on ESP32. The DimmerLink external component uses a hardware controller for reliable, flicker-free dimming on any board.
Method Comparison
| Feature | Standard ac_dimmer | DimmerLink component |
|---|---|---|
| ESP8266 | ✅ Stable | ✅ Stable |
| ESP32 (dual-core) | ⚠️ May flicker | ✅ Stable |
| ESP32-S2/C3/H2/C6 | ❌ Not supported | ✅ Supported |
| Raspberry Pi | ❌ Not supported | ✅ Supported |
| Additional hardware | None | DimmerLink module |
| YAML lines (minimal) | ~10 | ~30 |
| Built-in sensors | No | Frequency, brightness |
| Dimming curve select | No | LINEAR / RMS / LOG |
Method 1: Standard ESPHome ac_dimmer Platform
This is the built-in ESPHome platform. No external components needed.
Minimal config (ESP8266)
esphome:
name: dimmer-esp8266
platform: ESP8266
board: nodemcuv2
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
api:
encryption:
key: !secret api_key
ota:
password: !secret ota_password
output:
- platform: ac_dimmer
id: dimmer_out
gate_pin: GPIO4 # DIM pin
zero_cross_pin:
number: GPIO5 # ZC pin
mode: INPUT
inverted: yes
method: leading_pulse # TRIAC default
light:
- platform: monochromatic
output: dimmer_out
name: "Dimmer"Full config — with gamma and min power
output:
- platform: ac_dimmer
id: dimmer_out
gate_pin: GPIO4
zero_cross_pin:
number: GPIO5
mode: INPUT
inverted: yes
method: leading_pulse
min_power: 0.01 # minimum duty (1%) — avoids flicker at 0
light:
- platform: monochromatic
output: dimmer_out
name: "Dimmer"
gamma_correct: 0 # 0 = linear; 2.8 = human perception curve
default_transition_length: 500msDimming method options
method: leading_pulse # Brief gate pulse — standard TRIAC (default)
method: leading # Gate held until ZC — alternative TRIAC
method: trailing # Gate pulled low at end — MOSFET onlyESP32 warning
⚠️ The standard
ac_dimmerplatform has two distinct problems on ESP32 hardware:
- ESP32, ESP32-S3 — may flicker; ISR timing disrupted by WiFi
- ESP32-S2, ESP32-C3, ESP32-H2, ESP32-C6 — not supported at all
Fix: Use Method 2 (DimmerLink) for any ESP32-based setup.
Method 2: DimmerLink External Component
DimmerLink offloads zero-cross detection and TRIAC timing to a
dedicated Cortex-M0+ controller. ESPHome sends brightness via I2C
(register 0x10). No ISR runs on the MCU.
Docs: rbdimmer.com/docs/dimmerlink-esphome
Component source: github.com/robotdyn-dimmer/DimmerLink/tree/main/components
Wiring
DimmerLink → ESP32 (or any MCU)
──────────────────────────────────
VCC → 3.3V
GND → GND
SDA → GPIO21
SCL → GPIO22Minimal config (~30 lines)
esphome:
name: dimmerlink
platform: ESP32
board: esp32dev
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
api:
encryption:
key: !secret api_key
ota:
password: !secret ota_password
external_components:
- source:
type: git
url: https://github.com/robotdyn-dimmer/DimmerLink
ref: main
components: [dimmerlink]
i2c:
sda: GPIO21
scl: GPIO22
frequency: 100kHz
light:
- platform: dimmerlink
name: "Dimmer"
address: 0x50Standard config — with sensors and curve selector
# (external_components + i2c block as above)
light:
- platform: dimmerlink
name: "Dimmer"
address: 0x50
sensor:
- platform: dimmerlink
address: 0x50
frequency:
name: "AC Frequency"
unit_of_measurement: "Hz"
brightness:
name: "Dimmer Level"
unit_of_measurement: "%"
select:
- platform: dimmerlink
address: 0x50
dimming_curve:
name: "Dimming Curve"
# Options shown in HA dropdown: LINEAR, RMS, LOGARITHMIC
binary_sensor:
- platform: dimmerlink
address: 0x50
status:
name: "Dimmer Online"
button:
- platform: dimmerlink
address: 0x50
reset:
name: "Dimmer Reset"
recalibrate:
name: "Dimmer Recalibrate"Extended config — all entities
# Full DimmerLink integration with diagnostics
sensor:
- platform: dimmerlink
address: 0x50
frequency:
name: "AC Frequency"
brightness:
name: "Dimmer Level"
text_sensor:
- platform: dimmerlink
address: 0x50
firmware_version:
name: "DimmerLink Firmware"
number:
- platform: dimmerlink
address: 0x50
min_brightness:
name: "Min Brightness"
min_value: 0
max_value: 20
select:
- platform: dimmerlink
address: 0x50
dimming_curve:
name: "Dimming Curve"
binary_sensor:
- platform: dimmerlink
address: 0x50
status:
name: "Dimmer OK"
calibration_mode:
name: "Calibration Active"
button:
- platform: dimmerlink
address: 0x50
reset:
name: "Reset"
recalibrate:
name: "Recalibrate"Multi-device config
Multiple DimmerLink modules on one I2C bus (different addresses):
light:
- platform: dimmerlink
name: "Kitchen"
address: 0x50
- platform: dimmerlink
name: "Bedroom"
address: 0x51Lambda Integration (Advanced)
For custom logic — for example, setting brightness from a physical button or a sensor reading — use ESPHome lambda functions with direct I2C register access.
Docs: rbdimmer.com/docs/dimmerlink-esphome/lambda-integration
DimmerLink I2C register map (key registers)
| Register | Address | Description |
|---|---|---|
| STATUS | 0x00 |
Status flags (read-only) |
| DIM0_LEVEL | 0x10 |
Channel 0 brightness, 0–100 |
| DIM0_CURVE | 0x11 |
Curve: 0=LINEAR, 1=RMS, 2=LOG |
| AC_FREQ | 0x20 |
Measured AC frequency (Hz) |
Lambda example — set brightness directly
# Template output using lambda for custom brightness control
output:
- platform: template
id: dimmer_out
type: float
write_action:
- lambda: |-
uint8_t level = (uint8_t)(state * 100.0f);
// requires i2c: block in your ESPHome config
Wire.beginTransmission(0x50);
Wire.write(0x10); // DIM0_LEVEL register
Wire.write(level);
Wire.endTransmission();
light:
- platform: monochromatic
output: dimmer_out
name: "Dimmer (lambda)"Lambda example — button triggers preset
binary_sensor:
- platform: gpio
pin: GPIO0
name: "Dim Button"
on_press:
- lambda: |-
// Toggle between 30% and 80%
static bool high = false;
uint8_t level = high ? 30 : 80;
high = !high;
Wire.beginTransmission(0x50);
Wire.write(0x10);
Wire.write(level);
Wire.endTransmission();Dimming Curves
| Curve | Register value | ESPHome dimming_curve |
Best for |
|---|---|---|---|
| Linear | 0 | LINEAR |
Heaters, resistive |
| RMS | 1 | RMS |
Incandescent, halogen |
| Logarithmic | 2 | LOGARITHMIC |
Dimmable LED bulbs |
RMS and logarithmic curves compensate for the non-linear relationship between phase angle and perceived brightness.
Common Issues
| Symptom | Cause | Fix |
|---|---|---|
| Flickering with ESP32 | ISR/WiFi conflict | Use DimmerLink method |
| Dimmer offline after OTA | ISR preempted during flash | Use DimmerLink |
| Brightness stuck at 0% | min_power too low or ZC wiring |
Check ZC pin |
| HA light entity missing | ESPHome not adopted in HA | Re-adopt device |
| Component not found | Wrong ref: in external_components |
Use ref: main |
Related Articles
- Home Assistant full guide →
home-automation/home-assistant-ac-dimmer.md - ESP32 WiFi ISR problem → IRAM_ATTR Causes and Fix
- Single-core ESP32 → ESP32-S2/C3/H2 Doesn't Work
- MQTT alternative →
home-automation/mqtt-esp32-ac-dimmer.md
Still have questions?
Ask on forum.rbdimmer.com or open a GitHub Issue.