setPower(100) does not give full brightness. Lamp is noticeably dimmer than when connected directly to mains without the module.
Setup:
- rbdimmer 1CH 8A module (new one after T011 upgrade)
- Arduino Mega
- 200W incandescent bulb, 230V
Test: I measured brightness with a lux meter at 30cm distance.
- Lamp directly in mains socket: 1850 lux
- Lamp through dimmer at setPower(100): 1720 lux
That is about 7% less. Is this normal or is the module limiting output? I need full brightness for a specific application.
This is expected behavior for any phase-cut dimmer — not a defect in the module.
I measured the ZC signal with my oscilloscope on the same rbdimmer module. The zero-cross detection pulse has a finite width — typically 200-400µs depending on the optocoupler response time. After the ZC pulse, the library needs a minimum delay before firing the TRIAC gate.
At setPower(100), the firing angle is approximately 5-8° after each zero-cross — not 0°. This means the first 3-5% of each half-cycle is always cut off. You cannot fire the TRIAC at the exact zero-cross point because the ZC detection has propagation delay, the MCU needs time to process the interrupt, and firing too close to ZC risks misfiring in the wrong half-cycle.
The result: setPower(100) delivers approximately 95-97% of true uncontrolled AC power. Your 7% measurement aligns with this — some additional loss comes from the TRIAC’s on-state voltage drop (~1.2V for a BTA16).
This is a fundamental limitation of all phase-cut dimmers, not specific to rbdimmer.
Workaround for true 100%: Add a relay or SSR in parallel with the dimmer module. At full brightness, energize the relay to bypass the TRIAC entirely — zero loss. For dimming, de-energize the relay and use the TRIAC as normal. I use this approach in my workshop lighting.
Ola’s explanation is spot on. This is expected behavior and applies to all TRIAC/phase-cut dimmers on the market.
Quick clarification on the numbers:
setPower(100) = maximum firing angle the library can achieve safely = ~95-97% of true AC power
- The
max_power parameter in the library does not change this — it sets the upper software limit but cannot override the hardware timing constraint
- The remaining 3-5% loss is due to ZC detection delay + minimum safe firing time
For applications requiring true 100% output, the relay bypass approach Ola described is the recommended solution. A simple 5V relay module controlled by a spare GPIO works well:
#define RELAY_PIN 7
#define DIMMER_PIN 5
#define ZC_PIN 2
dimmerLamp dimmer(DIMMER_PIN, ZC_PIN);
void setLight(int power) {
if (power >= 100) {
dimmer.setState(OFF); // stop TRIAC firing
digitalWrite(RELAY_PIN, HIGH); // bypass via relay
} else {
digitalWrite(RELAY_PIN, LOW); // relay off
dimmer.setState(ON); // resume dimming
dimmer.setPower(power);
}
}
Important: always turn off the TRIAC (setState(OFF)) before energizing the relay, and de-energize the relay before resuming TRIAC dimming. Running both simultaneously can cause current conflicts.
More details on wiring and relay bypass in our documentation:
— rbdimmer support team
Understood. Not a bug — hardware limitation of phase-cut dimming.
The relay bypass is a good solution. For my application I will add an SSR (solid-state relay) in parallel — faster switching and no mechanical wear. I already have a Fotek SSR-40 DA in stock.
Logic will be: setPower < 100 → use TRIAC dimmer, setPower == 100 → switch to SSR bypass.
Thank you Ola for the oscilloscope data and detailed explanation. And rbdimmer team for the code example — the setState(OFF) before relay activation is an important detail I would have missed.