# API Reference

The full **C++ API reference** is available in the [C++ API](cppapi/annotated.md) 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)

```cpp
// 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)

```cpp
// 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

```cpp
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

```cpp
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
```

!!! warning "Semi-period required"
`CycleStealingDimmer` requires `setSemiPeriod()` to be called before `begin()`.

!!! note "No Power LUT"
`CycleStealingDimmer` does NOT support `enablePowerLUT()`. It uses whole-cycle on/off control, not phase angle.

---

## PWM Dimmer

```cpp
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

```cpp
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
```

!!! warning "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):

```cpp
dimmer.setDutyCycleMin(0.1); // 0% now maps to 10%
dimmer.setDutyCycleMax(0.9); // 100% now maps to 90%
```

### Safety Limiting

```cpp
dimmer.setDutyCycleLimit(0.8); // Never exceed 80% power
```

### 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.

```cpp
Mycila::Dimmer::setSemiPeriod(10000); // 10000us for 50Hz, 8333us for 60Hz
dimmer.enablePowerLUT(true);
bool isUsing = dimmer.isPowerLUTEnabled();
```

### Harmonics & Metrics Calculation

```cpp
// 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

```cpp
dimmer.setOnline(false); // Temporarily disable (e.g., when grid disconnected)
dimmer.setOnline(true);  // Re-enable
```

### JSON Telemetry

```cpp
#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
```
