MycilaJSY 13.0.0
Arduino / ESP32 library for the JSY1031, JSY-MK-163, JSY-MK-193, JSY-MK-194, JSY-MK-227, JSY-MK-229, JSY-MK-333 families single-phase and three-phase AC bidirectional meters from Shenzhen Jiansiyan Technologies Co, Ltd.
Loading...
Searching...
No Matches
MycilaDimmer

License: MIT Continuous Integration PlatformIO Registry

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
    • PlatformIO
    • Arduino IDE
  • 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
    • Build Flags
  • Examples
  • Build Configuration
    • PlatformIO Configuration
    • Dependencies
  • Troubleshooting
    • Common Issues
  • Contributing
    • Development Setup
  • 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

  1. Go to SketchInclude LibraryManage Libraries
  2. Search for "MycilaDimmer"
  3. Install the library by Mathieu Carbou

Quick Start

#include <MycilaDimmer.h>
// Create a PWM dimmer instance
void setup() {
Serial.begin(115200);
// Configure the dimmer
dimmer.setPin(GPIO_NUM_26);
dimmer.begin();
// Set 50% power
dimmer.setDutyCycle(0.5);
}
void loop() {
// Gradually increase power
for (float power = 0.0; power <= 1.0; power += 0.1) {
dimmer.setDutyCycle(power);
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() {
dimmer.setPin(GPIO_NUM_26);
dimmer.setSemiPeriod(10000); // 50Hz AC (10ms semi-period)
dimmer.begin();
// Register with external zero-cross detector
pulseAnalyzer.onZeroCross(Mycila::ThyristorDimmer::onZeroCross);
}
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() {
dimmer.setPin(GPIO_NUM_26);
dimmer.setFrequency(1000); // 1kHz PWM
dimmer.setResolution(12); // 12-bit resolution
dimmer.begin();
}
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.

ESP32 Voltage Regulator Heat Sink DFRobot DAC
#include <MycilaDimmer.h>
void setup() {
dimmer.setSKU(Mycila::DFRobotDimmer::SKU::DFR1071_GP8211S);
dimmer.setDeviceAddress(0x59);
dimmer.setOutput(Mycila::DFRobotDimmer::Output::RANGE_0_10V);
dimmer.begin();
}
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):

  1. Power Limiter: Limit dimmer (in example to 40% of nominal load)
  2. Reduced Load: Use lower wattage resistance (e.g., 1000W @ 53Ω instead of 3000W @ 18Ω)
  3. Proper Wiring: Minimize cable length, use appropriate wire gauge
  4. Strategic Placement: Position router close to grid entry/exit point
  5. Stepped Loads: Use multiple resistances with relays (e.g., 3x 800W elements)
  6. 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)

// Lifecycle
void begin(); // Initialize dimmer
void end(); // Cleanup and disable
const char* type() const; // Get dimmer type name
// Power Control
void on(); // Full power
void off(); // Turn off
bool setDutyCycle(float dutyCycle); // Set power (0.0-1.0)
// Status & State
bool isEnabled() const; // Is configured
bool isOnline() const; // Ready for operation (enabled + online)
void setOnline(bool online); // Set online status (grid connection)
bool isOn() const; // Currently active (online + duty > 0)
bool isOff() const; // Currently inactive
bool isOnAtFullPower() const; // Check if at max power
// Calibration & Remapping
void setDutyCycleMin(float min); // Remap 0% point (hardware calibration)
void setDutyCycleMax(float max); // Remap 100% point
void setDutyCycleLimit(float limit); // Clamp max allowed power
float getDutyCycle() const; // Current power setting
float getDutyCycleMapped() const; // Get mapped/calibrated duty cycle
float getDutyCycleLimit() const; // Get current limit
float getDutyCycleMin() const; // Get current min
float getDutyCycleMax() const; // Get current max
// Dimming Curve (Power LUT)
void enablePowerLUT(bool enable, uint16_t semiPeriod = 0); // Enable/disable perceptual LUT (default: false)
bool isPowerLUTEnabled() const; // Check if LUT is enabled
uint16_t getPowerLUTSemiPeriod() const; // Get LUT semi-period (us)
// Measurements
float getDutyCycleFire() const; // Actual firing ratio (0-1)
#ifdef MYCILA_JSON_SUPPORT
void toJson(const JsonObject& root) const; // Serialize to JSON
#endif

Thyristor Dimmer Specific

void setPin(gpio_num_t pin); // Set output GPIO pin
void setSemiPeriod(uint16_t semiPeriod); // Set grid semi-period (us)
static void onZeroCross(int16_t delayUntilZero, void* arg); // Zero-cross callback

PWM Dimmer Specific

void setPin(gpio_num_t pin); // Set output GPIO pin
void setFrequency(uint32_t frequency); // Set PWM frequency (default: 1000 Hz)
void setResolution(uint8_t resolution); // Set PWM resolution (default: 12-bit)

DFRobot DAC Dimmer Specific

void setWire(TwoWire& wire); // Set I2C bus (default: Wire)
void setSKU(SKU sku); // Set module SKU (DFR0971/1071/1073)
void setOutput(Output output); // Set voltage range (0-5V or 0-10V)
void setDeviceAddress(uint8_t addr); // Set I2C address (default: 0x58)
void setChannel(uint8_t channel); // Set DAC channel (0 or 1 for dual-channel)

Advanced Features

// Duty Cycle Remapping (Hardware Calibration)
dimmer.setDutyCycleMin(0.1); // 0% now maps to 10%
dimmer.setDutyCycleMax(0.9); // 100% now maps to 90%
// Safety Limiting
dimmer.setDutyCycleLimit(0.8); // Never exceed 80% power
// Power LUT - Selectable Dimming Curve
// Choose between LINEAR or POWER LUT dimming at runtime!
//
// LINEAR MODE (default, disabled):
// - Direct phase angle control
// - 50% duty cycle = 50% phase delay
// - Non-linear relationship between duty cycle and actual power output
// - Use when you need direct phase control or working with non-resistive loads
//
// POWER LUT MODE (enabled):
// - Non-linear curve that matches real power output of resistive loads
// - 50% duty cycle ≈ 50% actual power consumption
// - Also provides more natural dimming that matches human brightness perception
// - Best for resistive loads (heating elements, incandescent bulbs) where
// you want predictable power control
//
dimmer.enablePowerLUT(true, 10000); // Enable Power LUT mode (semi-period: 10000us for 50Hz, 8333us for 60Hz)
dimmer.enablePowerLUT(false); // Switch to linear phase angle mode
bool isUsing = dimmer.isPowerLUTEnabled(); // Check current mode
// Online Status Control
dimmer.setOnline(false); // Temporarily disable dimmer (e.g., when grid disconnected)
dimmer.setOnline(true); // Re-enable dimmer
// Telemetry (with MYCILA_JSON_SUPPORT)
#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

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. 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