
A comprehensive ESP32/Arduino library for controlling AC power devices including TRIACs, SSRs, and voltage regulators through multiple dimming methods.

Table of Contents
- Overview
- Features
- Hardware Support
- Supported Platforms
- Supported Hardware
- Installation
- Quick Start
- Dimmer Types
- Thyristor Dimmer
- PWM Dimmer
- DFRobot DAC Dimmer
- Understanding AC Dimming Methods
- Dimming Method Comparison
- Phase Control
- Cycle Stealing on Full Period
- Cycle Stealing on Semi-Period
- Stochastic Cycle Stealing (Coming Soon)
- Recommendations for Harmonic Mitigation (Phase Control)
- Current MycilaDimmer Support
- Choosing the Right Method
- References and Further Reading
- API Reference
- Common API (All Dimmer Types)
- Thyristor Dimmer Specific
- PWM Dimmer Specific
- DFRobot DAC Dimmer Specific
- Advanced Features
- Configuration
- Examples
- Build Configuration
- PlatformIO Configuration
- Dependencies
- Troubleshooting
- Contributing
- License
- Disclaimer
Overview
MycilaDimmer provides a unified interface for controlling AC power devices through different hardware implementations. The library uses a polymorphic architecture that allows you to switch between different dimming methods without changing your application code.
Key Benefits:
- Unified API - Same interface for all dimmer types
- IRAM Safe - Interrupt handlers work during flash operations
- Hardware Agnostic - Supports multiple hardware approaches
- Production Ready - Used in YaSolR Solar Router
Features
- ✨ Flicker-Free Dimming: Progressive dimming without flickering using precise DAC control or zero-cross detection with quality ZCD circuits
- 🎛️ Multiple Control Methods: Zero-cross detection, PWM, and I2C DAC
- ⚡ High Performance: IRAM-safe interrupt handlers with lookup table optimization
- 💡 Selectable Dimming Curves: Choose between linear dimming or Power LUT for perceptual brightness matching - switch at runtime based on your needs
- � Flexible Configuration: Duty cycle remapping, calibration, and user-selectable dimming modes
- 📊 Rich Telemetry: Duty cycle measurements, firing ratios, and online status
- 🛡️ Safety Features: Duty cycle limits and grid connection detection
- 📱 JSON Integration: Optional ArduinoJson support for telemetry
- 🔄 Real-time Control: Microsecond-precision timing control
Hardware Support
Supported Platforms
- ESP32 (all variants: ESP32, ESP32-S2, ESP32-S3, ESP32-C3, ESP32-C6, ESP32-H2)
- Arduino Framework via PlatformIO or Arduino IDE
Supported Hardware
- TRIACs with zero-cross detection circuits
- Random Solid State Relays (SSRs)
- Voltage Regulators with 0-10V control (LSA, LCTC, etc)
- DFRobot DAC Modules (GP8211S, GP8413, GP8403)
Installation
PlatformIO
[env:myproject]
lib_deps =
mathieucarbou/MycilaDimmer
Arduino IDE
- Go to Sketch → Include Library → Manage Libraries
- Search for "MycilaDimmer"
- Install the library by Mathieu Carbou
Quick Start
#include <MycilaDimmer.h>
void setup() {
}
void loop() {
for (float power = 0.0; power <= 1.0; power += 0.1) {
delay(1000);
}
}
bool setDutyCycle(float dutyCycle)
Set the power duty.
PWM based dimmer implementation for voltage regulators controlled by a PWM signal to 0-10V analog con...
void setPin(gpio_num_t pin)
Set the GPIO pin to use for the dimmer.
void begin() override
Enable a dimmer on a specific GPIO pin.
Dimmer Types
Thyristor Dimmer
Perfect for TRIAC and Random SSR control with flicker-free progressive dimming. Achieves smooth, continuous power control through precise phase angle control when paired with quality zero-cross detection circuits.
| ESP32 | Random Solid State Relay | Heat Sink | Zero-Cross Detection Module |
| | | |
#include <MycilaDimmer.h>
void setup() {
}
Thyristor (TRIAC) based dimmer implementation for TRIAC and Random SSR dimmers.
static void onZeroCross(int16_t delayUntilZero, void *args)
void begin() override
Enable a dimmer on a specific GPIO pin.
void setPin(gpio_num_t pin)
Set the GPIO pin to use for the dimmer.
void setSemiPeriod(uint16_t semiPeriod)
Set the semi-period of the grid frequency in us. It cannot be zero and it is required for proper dimm...
Features:
- Flicker-free dimming: Smooth progressive control without visible flickering
- Microsecond-precision phase angle control
- Lookup table with linear interpolation for seamless transitions
- IRAM-safe interrupt handlers
- Supports several zero-cross detection circuits:
The Zero-Cross Detector mounted on DIN Rail mount from Daniel is is very good and reliable. I sometimes buy it in bulk from PCBWay. If you want one, you can have a look at the YaSolR Pro page for the stock status.
PWM Dimmer
Standard PWM output for PWM to analog converters to control voltage regulators
| ESP32 | Voltage Regulator | Heat Sink | PWM to Analog Converter |
| | | |
#include <MycilaDimmer.h>
void setup() {
}
void setResolution(uint8_t resolution)
Set the PWM resolution in bits.
void setFrequency(uint32_t frequency)
Set the PWM frequency in Hz.
Features:
- Configurable frequency (default: 1kHz)
- Configurable resolution (default: 12-bit)
- Automatic PWM channel management
For example, this dimmer can be used with a 3.3V to 0-5V/0-10V signal converter
DFRobot DAC Dimmer
Flicker-free progressive dimming using precision I2C DAC modules. Perfect for voltage regulator controlled devices (LSA, LCTC, etc) with 0-10V input, providing ultra-smooth dimming without any visible flickering thanks to high-resolution DAC output.
#include <MycilaDimmer.h>
void setup() {
dimmer.setSKU(Mycila::DFRobotDimmer::SKU::DFR1071_GP8211S);
dimmer.
setOutput(Mycila::DFRobotDimmer::Output::RANGE_0_10V);
}
DFRobot DFR1071/DFR1073/DFR0971 I2C controlled 0-10V/0-5V dimmer implementation for voltage regulator...
void setDeviceAddress(uint8_t deviceAddress)
I2C address of the device.
void begin() override
Enable a dimmer on a specific GPIO pin.
void setOutput(Output output)
Set output mode of the device: 0-5V or 0-10V.
Supported Models:
- DFR0971 (GP8403): 12-bit, dual channel, 0-5V/10V
- DFR1071 (GP8211S): 15-bit, single channel, 0-5V/10V
- DFR1073 (GP8413): 15-bit, dual channel, 0-5V/10V
Here is a comparison table of the different DFRobot DAC modules.
Understanding AC Dimming Methods
When controlling AC power devices like TRIACs, SSRs, and voltage regulators, there are several dimming approaches available. Each method has specific characteristics, advantages, and limitations that affect precision, grid compatibility, and regulatory compliance.
Dimming Method Comparison
Phase Control
How it works: Controls power by delaying the firing angle within each AC semi-period (twice per cycle). The TRIAC/SSR activates at a specific point in the sine wave, "chopping" the waveform to deliver partial power.

Advantages:
- ✅ High Precision: Can adjust power at each semi-period (every 10ms for 50Hz), enabling watt-level control
- ✅ Fast Response: Instant power adjustment with no delay
- ✅ Accurate Power Control: With Power LUT, achieves predictable power output matching the desired level
- ✅ Regulatory Compliant: Keeps grid balanced (no DC component) when properly implemented under harmonic regulations
- ✅ Widely Used: Standard method in commercial dimmers and variable speed drives
Limitations:
- ⚠️ Harmonics: Generates harmonic distortion, especially at 50% power (90° phase angle)
- Harmonics are regulated by CEI 61000-3-2 (Class A devices)
- H3 (3rd harmonic) is the most significant, exceeds limits at 50% dimming with ~1700W nominal load
- H15 (15th harmonic) first to exceed limits at ~760W nominal load (but less significant than H3)
- Maximum compliant load: ~800W without mitigation
- Maximum significant load: ~1700W
- ⚠️ Mitigation may be required: May need RC snubbers, proper wiring, load management, or limiter settings
MycilaDimmer Implementation:
- All three implementations (ThyristorDimmer, PWMDimmer, DFRobotDimmer) use phase control
- ThyristorDimmer: Direct TRIAC/Random SSR control with zero-cross detection
- PWMDimmer: Generates PWM signal for converter for voltage regulators (LSA, LCTC) which perform internal phase control
- DFRobotDimmer: Outputs 0-10V analog signal to voltage regulators (LSA, LCTC) which perform internal phase control
Cycle Stealing on Full Period
How it works: Rapidly switches complete AC cycles on/off (20ms periods for 50Hz). For example, to achieve 50% power, alternates full power for 20ms, then turns off for 20ms, and so on.

Advantages:
- ✅ No Harmonics: Preserves complete sine waves, generates minimal harmonic distortion
- ✅ Simple Implementation: Basic on/off switching logic
- ✅ Compatible with many common SSRs (Zero-Cross / Sync ones): Can use simpler, cheaper SSRs
Limitations:
- ❌ Flickering: Visible light can flicker and voltage fluctuations can affect nearby devices
- Caused by sudden high current draw creating voltage drops
- Can impact micro-inverters and other sensitive electronics
- ❌ Slow Response: Limited precision due to coarse time slots
- Example: 50 slots in 1-second window for 50Hz = 60W resolution for 3000W load
- ❌ Heat Dissipation: Rapid switching generates more heat in SSR
- ❌ Poor Accuracy: Cannot achieve watt-level control precision
- ❌ Delayed Corrections: By the time adjustment is applied, conditions may have changed
Cycle Stealing on Semi-Period
How it works: Switches at semi-period level (every 10ms for 50Hz) to double the control slots and improve response time. For example, to achieve 50% power, alternates full power and no power for 20ms, and 10ms, to avoid creating DC components.

Advantages:
- ✅ Better Resolution: Twice as many control slots compared to full-period cycle stealing
- ✅ Faster Response: 2x quicker than full-period cycle stealing
Limitations:
- ❌ All Full-Period Limitations: Still suffers from flickering, heat, and inaccuracy but to a lesser extent
- ❌ DC Component: Critical regulatory violation in some countries
- Can create dangerous DC components on AC grid (current asymmetry drawn only one side of the waveform for a short time)
- Can unbalance grid network by drawing current asymmetrically if not properly balanced
- Can violate electrical regulation - this method cannot be used in some countries where regulations forbid DC components on AC grids
Stochastic Cycle Stealing (Coming Soon)
How it works: Probabilistic switching at each zero-cross. At each AC cycle, generates a random number (0-100) and compares it to the desired power level percentage. If the random number is lower, the full wave is allowed through; otherwise, it's blocked.
Advantages:
- ✅ No DC Component: Always switches at zero-cross on full waves, maintains grid balance
- ✅ Eliminates Periodic Flickering: Random distribution prevents visible periodic patterns
- ✅ Minimal EMF Interference: Zero-cross switching reduces electromagnetic interference
- ✅ Multi-Channel Safe: Random switching prevents simultaneous current spikes across channels
- ✅ Even Distribution: Over time, produces statistically accurate power output
- ✅ No Harmonics: Preserves complete sine waves like traditional cycle stealing
Limitations:
- ⚠️ Less Precise: Statistical accuracy over time, not instant watt-level precision
- ⚠️ Requires More Cycles: Needs multiple AC cycles to reach target power level
- ⚠️ Not for Fast-Response Systems: Better suited for thermal/heating applications with slower dynamics
Use Cases:
- Multi-channel heating systems
- Temperature control with PID regulation
- Applications where eliminating flicker is more important than instant precision
- Systems sensitive to EMF interference
Recommendations for Harmonic Mitigation (Phase Control)
When using phase control, harmonics can be reduced or partially mitigated through several approaches. Examples (but not limited to):
- Power Limiter: Limit dimmer (in example to 40% of nominal load)
- Reduced Load: Use lower wattage resistance (e.g., 1000W @ 53Ω instead of 3000W @ 18Ω)
- Proper Wiring: Minimize cable length, use appropriate wire gauge
- Strategic Placement: Position router close to grid entry/exit point
- Stepped Loads: Use multiple resistances with relays (e.g., 3x 800W elements)
- RC Snubbers: 100Ω 100nF snubbers can help with sensitive equipment
Current MycilaDimmer Support
Currently Supported (Phase Control):
- ✅ ThyristorDimmer - TRIAC/Random SSR with zero-cross detection
- ✅ PWMDimmer - PWM output for voltage regulators (LSA, LCTC)
- ✅ DFRobotDimmer - I2C DAC for voltage regulators (LSA, LCTC)
Coming Soon:
- ✅ CycleStealingDimmer - Stochastic cycle stealing for common SSR (Zero-Cross / Sync ones) and TRIAC / Random SSR with zero-cross detection
Choosing the Right Method
For Solar Routers & High-Precision Applications:
- Use Phase Control with appropriate harmonic mitigation
- Provides best accuracy and response time
For Simple On/Off Control:
- Consider normal SSR (Zero-Cross / Sync ones) with simple relay control
- Suitable when precise dimming is not required
- No harmonics, but no variable power control
References and Further Reading
Harmonics
TRIAC and Thyristors
Technical docs and algorithms
Solar Router using this library:
API Reference
Doxygen documentation is available here.
Common API (All Dimmer Types)
void begin();
void end();
const char* type() const;
void on();
void off();
bool setDutyCycle(float dutyCycle);
bool isEnabled() const;
bool isOnline() const;
void setOnline(bool online);
bool isOn() const;
bool isOff() const;
bool isOnAtFullPower() const;
void setDutyCycleMin(float min);
void setDutyCycleMax(float max);
void setDutyCycleLimit(float limit);
float getDutyCycle() const;
float getDutyCycleMapped() const;
float getDutyCycleLimit() const;
float getDutyCycleMin() const;
float getDutyCycleMax() const;
void enablePowerLUT(bool enable, uint16_t semiPeriod = 0);
bool isPowerLUTEnabled() const;
uint16_t getPowerLUTSemiPeriod() const;
float getDutyCycleFire() const;
#ifdef MYCILA_JSON_SUPPORT
void toJson(const JsonObject& root) const;
#endif
Thyristor Dimmer Specific
void setPin(gpio_num_t pin);
void setSemiPeriod(uint16_t semiPeriod);
static void onZeroCross(int16_t delayUntilZero, void* arg);
PWM Dimmer Specific
void setPin(gpio_num_t pin);
void setFrequency(uint32_t frequency);
void setResolution(uint8_t resolution);
DFRobot DAC Dimmer Specific
void setWire(TwoWire& wire);
void setSKU(SKU sku);
void setOutput(Output output);
void setDeviceAddress(uint8_t addr);
void setChannel(uint8_t channel);
Advanced Features
#ifdef MYCILA_JSON_SUPPORT
JsonDocument doc;
dimmer.toJson(doc.to<JsonObject>());
serializeJson(doc, Serial);
#endif
void setDutyCycleMin(float min)
Duty remapping (equivalent to Shelly Dimmer remapping feature). Useful to calibrate the dimmer when u...
void setOnline(bool online)
Set the online status of the dimmer.
bool isPowerLUTEnabled() const
Check if the power LUT is enabled.
void enablePowerLUT(bool enable, uint16_t semiPeriod=0)
Enable or disable the use of power LUT for dimmer curve The power LUT provides a non-linear dimming c...
void setDutyCycleMax(float max)
Duty remapping (equivalent to Shelly Dimmer remapping feature). Useful to calibrate the dimmer when u...
void setDutyCycleLimit(float limit)
Set the power duty cycle limit of the dimmer. The duty cycle will be clamped to this limit.
Configuration
Build Flags
For Thyristor Dimmer (IRAM safety):
build_flags =
-D CONFIG_ARDUINO_ISR_IRAM=1
lib_deps =
mathieucarbou/MycilaPulseAnalyzer
For JSON Support:
build_flags =
-D MYCILA_JSON_SUPPORT
lib_deps =
bblanchon/ArduinoJson
Examples
The library includes comprehensive examples:
Build Configuration
PlatformIO Configuration
[platformio]
lib_dir = .
src_dir = examples/Thyristor ; or DAC, PWM, etc.
[env]
framework = arduino
board = esp32dev
build_flags =
-D CONFIG_ARDUHAL_LOG_COLORS
-D CORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG
-Wall -Wextra
; ThyristorDimmer specific flags
-D CONFIG_ARDUINO_ISR_IRAM=1
lib_deps =
bblanchon/ArduinoJson
mathieucarbou/MycilaPulseAnalyzer
Dependencies
Troubleshooting
Common Issues
Thyristor Dimmer Not Working
- Ensure IRAM build flags are set
- Check semi-period is configured (setSemiPeriod())
- Verify zero-cross signal is connected and working
PWM Output Not Visible
- Check GPIO pin configuration
- Verify PWM frequency and resolution settings
- Use oscilloscope or LED to test output
DFRobot Module Not Responding
- Verify I2C wiring (SDA, SCL, power, ground)
- Check device address with I2C scanner
- Ensure correct SKU is configured
Contributing
- Fork the repository
- Create a feature branch (git checkout -b feature/amazing-feature)
- Commit your changes (git commit -m 'Add amazing feature')
- Push to the branch (git push origin feature/amazing-feature)
- Open a Pull Request
Development Setup
git clone https://github.com/mathieucarbou/MycilaDimmer.git
cd MycilaDimmer
pio run
License
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
Disclaimer
This website is provided for informational purposes only. By accessing this site and using the information contained herein, you accept the terms set forth in this disclaimer.
- Accuracy of Information: We strive to provide accurate and up-to-date information on this site, but we cannot guarantee the completeness or accuracy of this information. The information provided is subject to change without notice.
- Use of Information: Use of the information provided on this site is at your own risk. *We decline all responsibility for the consequences arising from the use of this information. It is recommended that you consult a competent professional for advice specific to your situation.
- External Links: This site may contain links to external websites which are provided for your reference and convenience. We have no control over the content of these external sites and we accept no responsibility for their content and their use.
- Limitation of Liability: To the fullest extent permitted by applicable law, we disclaim all liability for any direct, indirect, incidental, consequential or special damages arising out of the use of, or inability to use, this website, even if we have been advised of the possibility of such damage.
By using this site, you agree to hold harmless the owners, administrators and authors of this site from any claims arising from your use of this website. If you do not agree to these terms, please do not use this site.
Author: Mathieu Carbou
Used in: YaSolR Solar Router