API Reference¶
The full C++ API reference is available in the C++ API section (generated by Doxygen via mkdoxy).
Class Hierarchy¶
Dimmer (base)
├── PhaseControlDimmer
│ ├── ThyristorDimmer
│ ├── PWMDimmer
│ └── DFRobotDimmer
└── CycleStealingDimmer
Note
enablePowerLUT() is only available on PhaseControlDimmer subclasses (Thyristor, PWM, DFRobot). CycleStealingDimmer does not support Power LUT.
Common API (All Dimmer Types)¶
// Lifecycle
bool begin(); // Initialize dimmer (returns true on success)
void end(); // Cleanup and disable
const char* type() const; // Get dimmer type name: "thyristor", "pwm", "dfrobot", "cycle-stealing"
// Power Control
void on(); // Full power
void off(); // Turn off
bool setDutyCycle(float dutyCycle); // Set power (0.0 to 1.0), returns true if applied
// Status & State
bool isEnabled() const; // Is configured and initialized
bool isOnline() const; // Ready for operation (enabled + online)
void setOnline(bool online); // Set online status (e.g., grid connection)
bool isOn() const; // Currently active (online + duty > 0)
bool isOff() const; // Currently inactive
bool isOnAtFullPower() const; // Check if at max power (duty >= dutyCycleMax)
// 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 (user value, 0.0-1.0)
float getDutyCycleMapped() const; // Duty cycle after min/max remapping
float getDutyCycleFire() const; // Actual firing ratio applied to hardware (0.0-1.0)
float getDutyCycleLimit() const; // Current limit
float getDutyCycleMin() const; // Current min remap
float getDutyCycleMax() const; // Current max remap
// Grid Semi-Period (static, shared across all dimmers)
static void setSemiPeriod(uint16_t semiPeriod); // Set grid semi-period in microseconds
static uint16_t getSemiPeriod(); // Get semi-period (us)
// Power metrics
float getPowerRatio() const; // Actual power ratio (0.0-1.0), accounts for phase angle non-linearity
// Harmonics (phase-control dimmers only; cycle-stealing returns false)
bool calculateHarmonics(float* array, size_t n) const;
// Fills array with harmonic levels as % of fundamental: [H1, H3, H5, H7, ...]
// array[0]=H1 (100%), array[1]=H3, array[2]=H5, ...
// Returns false if dimmer is inactive or harmonics cannot be computed
// Metrics calculation for resistive loads
struct Metrics {
float voltage; // RMS output voltage (V)
float current; // RMS current (A)
float power; // Active power (W)
float apparentPower; // Apparent power (VA)
float powerFactor; // Power factor (0.0-1.0)
float thdi; // Total harmonic distortion of current (%)
};
bool calculateMetrics(Metrics& metrics, float gridVoltage, float loadResistance) const;
// Returns false if dimmer is disabled or inputs are invalid
#ifdef MYCILA_JSON_SUPPORT
void toJson(const JsonObject& root) const;
// Outputs: type, enabled, online, state, semi_period, duty_cycle,
// duty_cycle_mapped, duty_cycle_fire, duty_cycle_limit,
// duty_cycle_min, duty_cycle_max, harmonics{H1..H21}
#endif
PhaseControlDimmer (Thyristor, PWM, DFRobot)¶
// Dimming Curve (Power LUT)
void enablePowerLUT(bool enable); // Enable/disable perceptual Power LUT
bool isPowerLUTEnabled() const; // Check if LUT is enabled
// isOnline() for PhaseControlDimmer:
// Returns true only if: enabled AND online AND (powerLUT disabled OR semi-period > 0)
bool isOnline() const override;
Thyristor Dimmer¶
void setPin(gpio_num_t pin); // Set output GPIO pin
gpio_num_t getPin() const; // Get output GPIO pin
uint16_t getFiringDelay() const; // Firing delay in us [0, semi-period]
// 0 = 100% power, semi-period = 0% power
float getPhaseAngle() const; // Phase angle in degrees [0°, 180°]
// 0° = 100% power, 180° = 0% power
static void onZeroCross(int16_t delayUntilZero, void* args); // Zero-cross callback
// JSON also outputs: pin, firing_delay, firing_angle
Cycle Stealing Dimmer¶
void setPin(gpio_num_t pin); // Set output GPIO pin
gpio_num_t getPin() const; // Get output GPIO pin
// ZCD callback (only required when using Random SSR/TRIAC)
static void onZeroCross(int16_t delayUntilZero, void* args);
// JSON also outputs: pin
Semi-period required
CycleStealingDimmer requires setSemiPeriod() to be called before begin().
No Power LUT
CycleStealingDimmer does NOT support enablePowerLUT(). It uses whole-cycle on/off control, not phase angle.
PWM Dimmer¶
void setPin(gpio_num_t pin); // Set output GPIO pin
gpio_num_t getPin() const; // Get output GPIO pin
void setFrequency(uint32_t frequency); // Set PWM frequency (default: 1000 Hz)
uint32_t getFrequency() const; // Get PWM frequency
void setResolution(uint8_t resolution); // Set PWM resolution in bits (default: 12)
uint8_t getResolution() const; // Get PWM resolution
// JSON also outputs: pin, frequency, resolution, power_lut
DFRobot DAC Dimmer¶
void setWire(TwoWire& wire); // Set I2C bus (default: Wire)
TwoWire& getWire() const; // Get I2C bus
void setSKU(SKU sku); // Set module SKU
SKU getSKU() const; // Get module SKU
void setOutput(Output output); // Set voltage range
Output getOutput() const; // Get voltage range
void setDeviceAddress(uint8_t addr); // Set I2C address (default: 0x58)
uint8_t getDeviceAddress() const; // Get I2C address
void setChannel(uint8_t channel); // Set DAC channel (0 or 1; 2 = both)
uint8_t getChannel() const; // Get DAC channel
uint8_t getResolution() const; // DAC resolution: 15-bit (GP8211S/GP8413), 12-bit (GP8403)
// JSON also outputs: sku, output, i2c_address, channel, resolution, power_lut
I2C setup
Call Wire.begin(SDA, SCL) before calling dimmer.begin().
Advanced Usage¶
Duty Cycle Remapping (Hardware Calibration)¶
Useful when your hardware only operates in a sub-range (e.g., a voltage regulator that starts at 1V and saturates at 9V on a 0-10V input):
dimmer.setDutyCycleMin(0.1); // 0% now maps to 10%
dimmer.setDutyCycleMax(0.9); // 100% now maps to 90%
Safety Limiting¶
Power LUT — Selectable Dimming Curve¶
Available on ThyristorDimmer, PWMDimmer, and DFRobotDimmer only.
Linear mode (default, enablePowerLUT(false)):
- Direct phase angle control
getDutyCycleFire()equals the remapped duty cycle- Non-linear relationship between duty cycle and actual power delivered
Power LUT mode (enablePowerLUT(true)):
- Compensates for the non-linear power transfer of phase control
- 50% duty cycle ≈ 50% actual power delivered to a resistive load
- More natural dimming matching human brightness perception
Warning
PhaseControlDimmer::isOnline() requires the semi-period to be set (setSemiPeriod() > 0) when Power LUT is enabled. Without a valid semi-period the dimmer will be offline.
Mycila::Dimmer::setSemiPeriod(10000); // 10000us for 50Hz, 8333us for 60Hz
dimmer.enablePowerLUT(true);
bool isUsing = dimmer.isPowerLUTEnabled();
Harmonics & Metrics Calculation¶
// Harmonics (H1..H21) for phase-control dimmers
float harmonics[11]; // H1, H3, H5, H7, H9, H11, H13, H15, H17, H19, H21
if (dimmer.calculateHarmonics(harmonics, 11)) {
Serial.printf("H1=%.1f%% H3=%.1f%% H5=%.1f%%\n", harmonics[0], harmonics[1], harmonics[2]);
}
// Electrical metrics for a resistive load
Mycila::Dimmer::Metrics metrics;
if (dimmer.calculateMetrics(metrics, 230.0f, 53.0f)) { // 230V grid, 53Ω load (~1kW)
Serial.printf("Power=%.1fW PF=%.2f THDi=%.1f%%\n", metrics.power, metrics.powerFactor, metrics.thdi);
}
Online Status Control¶
dimmer.setOnline(false); // Temporarily disable (e.g., when grid disconnected)
dimmer.setOnline(true); // Re-enable
JSON Telemetry¶
#ifdef MYCILA_JSON_SUPPORT
JsonDocument doc;
dimmer.toJson(doc.to<JsonObject>());
serializeJson(doc, Serial);
// Outputs: type, enabled, online, state, semi_period, duty_cycle,
// duty_cycle_mapped, duty_cycle_fire, duty_cycle_limit,
// duty_cycle_min, duty_cycle_max, harmonics{H1..H21},
// + dimmer-specific fields (pin, firing_delay, etc.)
#endif