Zum Inhalt springen

AC Dimmer Doesn't Turn Off: Residual Glow at 0%

Why a lamp keeps glowing faintly when the dimmer is set to 0%, and how to eliminate it with software commands, an RC snubber, or a relay.

TL;DR: Setting the dimmer to 0% does not guarantee the lamp turns off. TRIAC holding current keeps the switch conducting at low loads. Fix: call dimmer.setState(OFF) or setMode(OFF_MODE) instead of setPower(0) — or add a relay for full galvanic disconnection. DimmerLink stops all gate pulses at level 0, eliminating the issue in software.




What the Problem Looks Like

You call setPower(0) or set brightness: 0 in your automation. The load should be off. Instead:

  • an incandescent or halogen lamp continues to glow dimly;
  • the lamp may flicker slowly (1–4 Hz) at "zero" level;
  • the behavior is worse with low-wattage lamps (25–40 W) and disappears with 100 W+.

This is not a code error. It is a fundamental property of TRIAC circuits interacting with small resistive loads.




Root Causes


Cause 1 — TRIAC Holding Current

A TRIAC (Triode for Alternating Current) conducts in both AC half-cycles once triggered. To stop conducting it must naturally reach zero current crossing — and the current through the load at the moment of crossing must fall below the holding current (I_H) of the device.

Typical holding current for a BTA16 or BT138 TRIAC: 25–80 mA.

With a 25 W lamp at 230 V:

text
I_load = 25 W / 230 V ≈ 109 mA  (peak during conduction)

At a very small phase-cut angle (near 0%, i.e., near the zero-crossing) the current pulse is so brief that it collapses below I_H before the TRIAC has time to latch. Result: some half-cycles the TRIAC opens, some it doesn't — producing slow, irregular flicker or a constant dim glow.


Cause 2 — Optocoupler Leakage Current

The TRIAC driver optocoupler (MOC3041, MOC3021, or equivalent) passes a small leakage current (1–5 mA typical) even when the LED inside is off. For a 100 W lamp this is invisible. For a 10 W LED lamp or a 25 W incandescent the leakage alone may be enough to sustain a glow.


Cause 3 — Library Minimum Pulse at 0%

Both RBDdimmer and rbdimmerESP32 enforce a minimum non-zero firing angle to avoid hardware instability near the crossings. Calling setPower(0) may still generate a very short gate pulse each half-cycle. The load therefore receives a tiny power burst — not enough to light a 100 W bulb, but visible on a 25 W lamp.

The solution is to switch the library mode to OFF, not just set power to 0.




Diagnosing the Problem

  1. Check the wattage — replace the 25–40 W lamp with a 100 W incandescent. If the glow disappears, holding current is the cause.
  2. Disconnect the MCU — unplug all control signals (DIM, ZC, VCC, GND on the MCU side). If the lamp still glows, leakage current is the cause; if it goes out, the library is sending residual pulses.
  3. Check the API call — search your code for setPower(0). Confirm you are not missing a setState(OFF) call.



Solutions


🟢 For Beginners — Use DimmerLink or a Relay

DimmerLink manages gate firing in its own firmware (Cortex-M0+). At level 0 it generates zero gate pulses — the TRIAC is not triggered regardless of leakage. Write 0 to register 0x10 (DIM0_LEVEL) and the lamp turns off completely.

cpp
// Arduino / ESP32 — DimmerLink I2C
Wire.beginTransmission(0x50);
Wire.write(0x10);   // DIM0_LEVEL register
Wire.write(0);      // 0% — no gate pulses
Wire.endTransmission();

Add a relay if the load must be fully de-energised (galvanic isolation). Connect a normally-open relay (or SSR) in series with the dimmer's AC-IN. Open the relay when the load should be off; close it to enable dimming:

cpp
// Arduino example
const int RELAY_PIN = 7;
void setLoad(bool on, uint8_t level) {
    if (!on) {
        dimmer.setState(OFF);
        digitalWrite(RELAY_PIN, LOW);   // relay open — fully off
    } else {
        digitalWrite(RELAY_PIN, HIGH);  // relay closed — enable AC path
        delay(5);                       // let contacts settle
        dimmer.setState(ON);
        dimmer.setPower(level);
    }
}


🔵 For Advanced Users — Software and Hardware Fixes


Option A — Use the Correct OFF Mode (Software)

setPower(0) sets the firing angle to near-zero but may still generate a pulse. The correct way to turn the load completely off is to change the operating mode:

rbdimmerESP32 / RBDdimmer:

cpp
#include <rbdimmerESP32.h>  // or RBDdimmer.h for AVR/ESP8266
rbdimmer::Dimmer dimmer(DIM_PIN, ZC_PIN);
void setup() {
    dimmer.begin(NORMAL_MODE, ON);
    dimmer.setPower(50);
}
void turnOff() {
    // Correct: switch mode to OFF — no gate pulses at all
    dimmer.setState(OFF);
    // Wrong: dimmer.setPower(0) — may still fire
}
void turnOn(uint8_t level) {
    dimmer.setState(ON);
    dimmer.setPower(level);
}

If your library version uses setMode():

cpp
dimmer.setMode(OFF_MODE);    // turns off
dimmer.setMode(NORMAL_MODE); // resumes dimming

ESPHome ac_dimmer component:

ESPHome's ac_dimmer component sets output: false to fully inhibit gate pulses:

yaml
output:
  - platform: ac_dimmer
    id: triac_output
    gate_pin: GPIO4
    zero_cross_pin: GPIO5
light:
  - platform: monochromatic
    output: triac_output
    name: "Lamp"
    # When HA sends "turn off", the component stops gate pulses.

When Home Assistant sends a turn-off command, ESPHome stops gate pulses entirely — the TRIAC is not triggered and the lamp goes out.


Option B — RC Snubber (Hardware)

An RC snubber connected in parallel with the TRIAC reduces the rate of voltage rise (dV/dt) across the device after a zero crossing. This helps the TRIAC self-commutate reliably at small conduction angles.

text
TRIAC anode/cathode
┌──────────┐
│  TRIAC   │
└──────────┘
     │     ← in parallel:  100 Ω (0.5 W) + 100 nF class-X2
     └── R ── C ── ┘

Standard snubber values: R = 100 Ω (0.5 W) and C = 100 nF, class X2 (rated for mains voltage).

Most rbdimmer modules already include a built-in snubber. Check your module's schematic before adding an external one.

An RC snubber does not eliminate the problem completely — it makes TRIAC turn-off more reliable, but optocoupler leakage persists.


Option C — Series Relay for Full Disconnection

If the load must be completely de-energised (safety requirement, or inductive load), add a relay in series:

Scenario Relay type Note
Normal loads SPST NO relay Open = no AC path
Inductive (motors) SPST NO relay Arc suppression recommended
Mains isolation required SSR (solid state relay) No moving parts

Use the dimmer for power control and the relay for on/off:

cpp
void loop() {
    if (targetLevel == 0) {
        dimmer.setState(OFF);
        digitalWrite(RELAY_PIN, LOW);
    } else {
        digitalWrite(RELAY_PIN, HIGH);
        delay(5);
        dimmer.setState(ON);
        dimmer.setPower(targetLevel);
    }
}



Load Compatibility Matrix

Load Symptom at 0% Root cause Fix
Incandescent 100 W+ No glow Enough load setState(OFF) sufficient
Incandescent 25–40 W Faint glow Holding current setState(OFF) or relay
Halogen 50 W Glow or slow flicker Holding current RC snubber + setState(OFF)
Halogen 12 V (transformer) Glow Reactive current Relay for full disconnection
Heating element No glow Resistive load setState(OFF) sufficient



Common Mistakes

Mistake Effect Fix
Calling setPower(0) instead of setState(OFF) Residual pulse at each half-cycle Use setState(OFF)
Assuming 0% = off for low-wattage lamps Glow or flicker Use OFF mode
Adding an undersized snubber (< 0.5 W resistor) Snubber overheats Use 0.5 W or 1 W resistor
Using a relay without arc protection on inductive loads Contact welding Add snubber across relay contacts



Quick Checklist

Before replacing hardware, check these in order:

  • ☐ Code uses `setState(OFF)` / `setMode(OFF_MODE)`, not just `setPower(0)`
  • ☐ Lamp wattage is > 60 W (below this, holding current is often the cause)
  • ☐ Library version supports a separate OFF mode
  • ☐ Built-in snubber on the module is present (check PCB)
  • ☐ If DimmerLink: level register 0x10 is set to 0 via I2C



  • Related Articles



    Still have questions?

    Ask on forum.rbdimmer.com or open a GitHub Issue.

    Diesen Beitrag teilen
    Anmelden , um einen Kommentar zu hinterlassen