Zum Inhalt springen

← - Lambda-Beispiele | Inhaltsverzeichnis | Weiter: - Lambda FAQ & Fehlerbehebung →


ESPHome-Integration — Lambda-Referenz

Vollständige Referenz für die Arbeit mit DimmerLink über ESPHome Lambda.

Info
**Dokument in Bearbeitung.** DimmerLink wird aktiv weiterentwickelt — neue Register und Funktionen werden dieser Referenz hinzugefügt.



Inhaltsverzeichnis




4.1 I2C-Grundlagen in ESPHome


I2C-Bus-Konfiguration

yaml
i2c:
  sda: GPIO21
  scl: GPIO22
  scan: true
  frequency: 100kHz
  id: bus_a
Parameter Beschreibung Empfehlung
sda Daten-Pin GPIO21 (ESP32-Standard)
scl Takt-Pin GPIO22 (ESP32-Standard)
scan Bus beim Start scannen true zum Debuggen
frequency Bus-Frequenz 100kHz (DimmerLink Standard Mode)
id Bus-Kennung Erforderlich für Lambda


Konstanten und Geräteadresse

yaml
substitutions:
  # DimmerLink I2C address (default)
  dimmerlink_addr: "0x50"

Zur Verwendung in Lambda:

cpp
// Device address
const uint8_t DIMMERLINK_ADDR = 0x50;


Grundlegende I2C-Operationen

In ein Register schreiben

cpp
// Template: write a single byte to a register
uint8_t reg = 0x10;       // Register address
uint8_t value = 50;       // Value to write
uint8_t data[2] = {reg, value};
id(bus_a).write(DIMMERLINK_ADDR, data, 2, true);

write() Parameters:
- address — I2C device address
- data — pointer to data
- length — number of bytes
- stop — send STOP condition (true usually)

Aus einem Register lesen

cpp
// Template: read a single byte from a register
uint8_t reg = 0x10;
uint8_t value = 0;

// 1. Send register address (without STOP)
auto err = id(bus_a).write(DIMMERLINK_ADDR, ®, 1, false);
if (err != i2c::ERROR_OK) {
    ESP_LOGW("dimmerlink", "Write error: %d", err);
    return {};  // or error handling
}

// 2. Read data
err = id(bus_a).read(DIMMERLINK_ADDR, &value, 1);
if (err != i2c::ERROR_OK) {
    ESP_LOGW("dimmerlink", "Read error: %d", err);
    return {};
}

// value now contains the read value

Mehrere Bytes lesen

cpp
// Reading 2 bytes (e.g., 16-bit value)
uint8_t reg = 0x21;
uint8_t buffer[2] = {0, 0};

id(bus_a).write(DIMMERLINK_ADDR, ®, 1, false);
id(bus_a).read(DIMMERLINK_ADDR, buffer, 2);

uint16_t value = (buffer[1] << 8) | buffer[0];  // Little-endian


Fehlerbehandlung

cpp
#include "esphome/components/i2c/i2c.h"

// ESPHome I2C error codes
// i2c::ERROR_OK          = 0  — success
// i2c::ERROR_TIMEOUT     = 1  — timeout
// i2c::ERROR_NOT_ACKNOWLEDGED = 2  — NACK
// i2c::ERROR_DATA_TOO_LARGE   = 3  — too much data
// i2c::ERROR_UNKNOWN     = 4  — unknown error

auto err = id(bus_a).write(DIMMERLINK_ADDR, data, 2, true);

if (err == i2c::ERROR_OK) {
    ESP_LOGD("dimmerlink", "Success");
} else if (err == i2c::ERROR_NOT_ACKNOWLEDGED) {
    ESP_LOGW("dimmerlink", "Device not responding (NACK)");
} else {
    ESP_LOGE("dimmerlink", "I2C error: %d", err);
}


Protokollierung

cpp
// ESPHome logging levels
ESP_LOGV("tag", "Verbose: %d", value);   // Very detailed
ESP_LOGD("tag", "Debug: %d", value);     // Debug
ESP_LOGI("tag", "Info: %d", value);      // Information
ESP_LOGW("tag", "Warning: %d", value);   // Warning
ESP_LOGE("tag", "Error: %d", value);     // Error


Hilfsfunktionen (Global)

Für mehr Komfort können Sie Hilfsfunktionen definieren:

yaml
esphome:
  includes:
    - dimmerlink_helpers.h

Datei dimmerlink_helpers.h (im Konfigurationsordner):

cpp
#pragma once

#include "esphome.h"

namespace dimmerlink {

const uint8_t ADDR = 0x50;

// Registers
namespace reg {
    const uint8_t STATUS      = 0x00;
    const uint8_t COMMAND     = 0x01;
    const uint8_t ERROR       = 0x02;
    const uint8_t VERSION     = 0x03;
    const uint8_t DIM0_LEVEL  = 0x10;
    const uint8_t DIM0_CURVE  = 0x11;
    const uint8_t AC_FREQ     = 0x20;
    const uint8_t AC_PERIOD_L = 0x21;
    const uint8_t AC_PERIOD_H = 0x22;
    const uint8_t CALIBRATION = 0x23;
    const uint8_t I2C_ADDRESS = 0x30;
}

// Commands
namespace cmd {
    const uint8_t NOP         = 0x00;
    const uint8_t RESET       = 0x01;
    const uint8_t RECALIBRATE = 0x02;
    const uint8_t SWITCH_UART = 0x03;
}

// Curves
namespace curve {
    const uint8_t LINEAR = 0;
    const uint8_t RMS    = 1;
    const uint8_t LOG    = 2;
}

// DimmerLink errors
namespace error {
    const uint8_t OK         = 0x00;
    const uint8_t SYNTAX     = 0xF9;
    const uint8_t NOT_READY  = 0xFC;
    const uint8_t INDEX      = 0xFD;
    const uint8_t PARAM      = 0xFE;
}

}  // namespace dimmerlink

Verwendung in Lambda:

cpp
uint8_t data[2] = {dimmerlink::reg::DIM0_LEVEL, 50};
id(bus_a).write(dimmerlink::ADDR, data, 2, true);
Tip
Die Verwendung der Hilfsdatei ist optional. Alle folgenden Beispiele funktionieren auch ohne sie.



4.2 Steuerungsregister (0x00-0x0F)

Gerätesteuerung und Statusregister.


STATUS (0x00) — Gerätestatus

Parameter Wert
Adresse 0x00
Zugriff Nur Lesen
Größe 1 Byte

Bitstruktur:

Bit Name Beschreibung
0 READY 1 = Gerät bereit (Kalibrierung abgeschlossen)
1 ERROR 1 = Letzte Operation mit Fehler beendet
2-7 Reserviert

Lambda — Status lesen:

cpp
// Read full status byte
uint8_t reg = 0x00;
uint8_t status = 0;

if (id(bus_a).write(0x50, ®, 1, false) == i2c::ERROR_OK) {
    if (id(bus_a).read(0x50, &status, 1) == i2c::ERROR_OK) {
        bool ready = status & 0x01;
        bool error = status & 0x02;

        ESP_LOGI("dimmerlink", "Status: ready=%d, error=%d", ready, error);
    }
}

ESPHome-Entität — Binary Sensor:

yaml
binary_sensor:
  # Device ready status
  - platform: template
    name: "DimmerLink Ready"
    id: dimmerlink_ready
    icon: "mdi:check-circle"
    entity_category: "diagnostic"
    lambda: |-
      uint8_t reg = 0x00;
      uint8_t status = 0;
      if (id(bus_a).write(0x50, ®, 1, false) == i2c::ERROR_OK) {
        if (id(bus_a).read(0x50, &status, 1) == i2c::ERROR_OK) {
          return (status & 0x01) != 0;
        }
      }
      return {};

  # Error flag
  - platform: template
    name: "DimmerLink Error Flag"
    id: dimmerlink_error_flag
    icon: "mdi:alert-circle"
    entity_category: "diagnostic"
    device_class: problem
    lambda: |-
      uint8_t reg = 0x00;
      uint8_t status = 0;
      if (id(bus_a).write(0x50, ®, 1, false) == i2c::ERROR_OK) {
        if (id(bus_a).read(0x50, &status, 1) == i2c::ERROR_OK) {
          return (status & 0x02) != 0;
        }
      }
      return {};


COMMAND (0x01) — Steuerbefehle

Parameter Wert
Adresse 0x01
Zugriff Nur Schreiben
Größe 1 Byte

Verfügbare Befehle:

Wert Befehl Beschreibung Ausführungszeit
0x00 NOP Keine Operation
0x01 RESET Software-Reset ~3 Sek. (Neustart)
0x02 RECALIBRATE AC-Frequenz neu kalibrieren ~200 ms
0x03 SWITCH_UART In UART-Modus wechseln Sofort

Lambda — Befehl senden:

cpp
// General command sending template
void send_command(uint8_t cmd) {
    uint8_t data[2] = {0x01, cmd};
    id(bus_a).write(0x50, data, 2, true);
}
cpp
// RESET — software reset
uint8_t data[2] = {0x01, 0x01};
id(bus_a).write(0x50, data, 2, true);
ESP_LOGW("dimmerlink", "Reset command sent, device will reboot");
cpp
// RECALIBRATE — frequency recalibration
uint8_t data[2] = {0x01, 0x02};
id(bus_a).write(0x50, data, 2, true);
ESP_LOGI("dimmerlink", "Recalibration started");
cpp
// SWITCH_UART — switch to UART
// After this command I2C no longer works!
uint8_t data[2] = {0x01, 0x03};
id(bus_a).write(0x50, data, 2, true);
ESP_LOGW("dimmerlink", "Switched to UART mode, I2C disabled");
Warning
Nach dem Befehl `SWITCH_UART` antwortet das Gerät nicht mehr über I2C!

ESPHome-Entität — Button:

yaml
button:
  # Software reset
  - platform: template
    name: "DimmerLink Reset"
    id: dimmerlink_reset
    icon: "mdi:restart"
    entity_category: "config"
    on_press:
      - lambda: |-
          uint8_t data[2] = {0x01, 0x01};
          id(bus_a).write(0x50, data, 2, true);
          ESP_LOGW("dimmerlink", "Reset command sent");
      - delay: 3s
      - logger.log:
          level: INFO
          format: "DimmerLink should be back online"

  # Recalibration
  - platform: template
    name: "DimmerLink Recalibrate"
    id: dimmerlink_recalibrate
    icon: "mdi:refresh"
    entity_category: "config"
    on_press:
      - lambda: |-
          uint8_t data[2] = {0x01, 0x02};
          id(bus_a).write(0x50, data, 2, true);
          ESP_LOGI("dimmerlink", "Recalibration started");
      - delay: 500ms
      - component.update: ac_frequency


ERROR (0x02) — Letzter Fehlercode

Parameter Wert
Adresse 0x02
Zugriff Nur Lesen
Größe 1 Byte

Fehlercodes:

Code Name Beschreibung
0x00 OK Kein Fehler
0xF9 ERR_SYNTAX Ungültige Registeradresse
0xFC ERR_NOT_READY Gerät nicht bereit (nicht kalibriert oder FLASH-Fehler)
0xFD ERR_INDEX Ungültiger Dimmer-Index
0xFE ERR_PARAM Ungültiger Parameterwert

Lambda — Fehler lesen:

cpp
uint8_t reg = 0x02;
uint8_t error_code = 0;

if (id(bus_a).write(0x50, ®, 1, false) == i2c::ERROR_OK) {
    if (id(bus_a).read(0x50, &error_code, 1) == i2c::ERROR_OK) {
        switch (error_code) {
            case 0x00: ESP_LOGD("dimmerlink", "No error"); break;
            case 0xF9: ESP_LOGW("dimmerlink", "ERR_SYNTAX"); break;
            case 0xFC: ESP_LOGW("dimmerlink", "ERR_NOT_READY"); break;
            case 0xFD: ESP_LOGW("dimmerlink", "ERR_INDEX"); break;
            case 0xFE: ESP_LOGW("dimmerlink", "ERR_PARAM"); break;
            default:   ESP_LOGE("dimmerlink", "Unknown error: 0x%02X", error_code);
        }
    }
}

ESPHome-Entität — Text Sensor:

yaml
text_sensor:
  - platform: template
    name: "DimmerLink Last Error"
    id: dimmerlink_last_error
    icon: "mdi:alert"
    entity_category: "diagnostic"
    update_interval: 10s
    lambda: |-
      uint8_t reg = 0x02;
      uint8_t error_code = 0;

      if (id(bus_a).write(0x50, ®, 1, false) != i2c::ERROR_OK) {
        return {"I2C Error"};
      }
      if (id(bus_a).read(0x50, &error_code, 1) != i2c::ERROR_OK) {
        return {"Read Error"};
      }

      switch (error_code) {
        case 0x00: return {"OK"};
        case 0xF9: return {"ERR_SYNTAX"};
        case 0xFC: return {"ERR_NOT_READY"};
        case 0xFD: return {"ERR_INDEX"};
        case 0xFE: return {"ERR_PARAM"};
        default:   return {"UNKNOWN (0x" + format_hex_pretty(&error_code, 1) + ")"};
      }

ESPHome-Entität — Sensor (numerischer Code):

yaml
sensor:
  - platform: template
    name: "DimmerLink Error Code"
    id: dimmerlink_error_code
    icon: "mdi:alert-octagon"
    entity_category: "diagnostic"
    accuracy_decimals: 0
    update_interval: 10s
    lambda: |-
      uint8_t reg = 0x02;
      uint8_t error_code = 0;
      if (id(bus_a).write(0x50, ®, 1, false) == i2c::ERROR_OK) {
        if (id(bus_a).read(0x50, &error_code, 1) == i2c::ERROR_OK) {
          return (float)error_code;
        }
      }
      return {};


VERSION (0x03) — Firmware-Version

Parameter Wert
Adresse 0x03
Zugriff Nur Lesen
Größe 1 Byte

Version Format:
- 0x01 = v1.0
- 0x02 = v2.0
- 0x10 = v1.0 (alternative format, if major.minor)

Lambda — Version lesen:

cpp
uint8_t reg = 0x03;
uint8_t version = 0;

if (id(bus_a).write(0x50, ®, 1, false) == i2c::ERROR_OK) {
    if (id(bus_a).read(0x50, &version, 1) == i2c::ERROR_OK) {
        ESP_LOGI("dimmerlink", "Firmware version: %d", version);
    }
}

ESPHome-Entität — Sensor:

yaml
sensor:
  - platform: template
    name: "DimmerLink Firmware Version"
    id: dimmerlink_version
    icon: "mdi:chip"
    entity_category: "diagnostic"
    accuracy_decimals: 0
    update_interval: never  # Read once on startup
    lambda: |-
      uint8_t reg = 0x03;
      uint8_t version = 0;
      if (id(bus_a).write(0x50, ®, 1, false) == i2c::ERROR_OK) {
        if (id(bus_a).read(0x50, &version, 1) == i2c::ERROR_OK) {
          return (float)version;
        }
      }
      return {};

# Read on startup
esphome:
  on_boot:
    priority: -100
    then:
      - component.update: dimmerlink_version



4.3 Dimmer-Register (0x10-0x1F)

Register zur Steuerung der Dimmer-Kanäle.

Info
**Aktuelle Version:** 1 Kanal (DIM0) wird unterstützt. Die Register DIM1-DIM3 sind für zukünftige Versionen reserviert.


DIM0_LEVEL (0x10) — Helligkeitsstufe

Parameter Wert
Adresse 0x10
Zugriff Lesen/Schreiben
Größe 1 Byte
Bereich 0-100 (%)

Values:
- 0 — off (TRIAC does not open)
- 1-99 — dimming (phase-cut)
- 100 — full brightness (minimum delay)

Warning
Das Schreiben eines Wertes > 100 gibt den Fehler `ERR_PARAM (0xFE)` zurück.

Lambda — Stufe schreiben:

cpp
// Set brightness 0-100%
uint8_t level = 50;  // 50%

if (level > 100) level = 100;  // Overflow protection

uint8_t data[2] = {0x10, level};
auto err = id(bus_a).write(0x50, data, 2, true);

if (err == i2c::ERROR_OK) {
    ESP_LOGD("dimmerlink", "Level set to %d%%", level);
} else {
    ESP_LOGW("dimmerlink", "Failed to set level: %d", err);
}

Lambda — Stufe lesen:

cpp
uint8_t reg = 0x10;
uint8_t level = 0;

if (id(bus_a).write(0x50, ®, 1, false) == i2c::ERROR_OK) {
    if (id(bus_a).read(0x50, &level, 1) == i2c::ERROR_OK) {
        ESP_LOGD("dimmerlink", "Current level: %d%%", level);
        return (float)level;
    }
}
return {};  // Error

ESPHome-Entität — Output (Basis für Light):

yaml
output:
  - platform: template
    id: dimmerlink_output
    type: float
    write_action:
      - lambda: |-
          // state: 0.0 - 1.0, convert to 0-100
          uint8_t level = (uint8_t)(state * 100.0f);
          if (level > 100) level = 100;

          uint8_t data[2] = {0x10, level};
          auto err = id(bus_a).write(0x50, data, 2, true);

          if (err == i2c::ERROR_OK) {
              ESP_LOGD("dimmerlink", "Set level: %d%%", level);
          } else {
              ESP_LOGW("dimmerlink", "Write error: %d", err);
          }

ESPHome-Entität — Light:

yaml
light:
  - platform: monochromatic
    name: "Dimmer"
    id: dimmer_light
    output: dimmerlink_output
    default_transition_length: 1s
    gamma_correct: 1.0  # DimmerLink has its own curves

ESPHome-Entität — Number (direkte Steuerung):

yaml
number:
  - platform: template
    name: "Dimmer Level"
    id: dimmer_level_number
    icon: "mdi:brightness-percent"
    unit_of_measurement: "%"
    min_value: 0
    max_value: 100
    step: 1
    optimistic: true
    set_action:
      - lambda: |-
          uint8_t level = (uint8_t)x;
          uint8_t data[2] = {0x10, level};
          id(bus_a).write(0x50, data, 2, true);
          ESP_LOGI("dimmerlink", "Level set to %d%%", level);

ESPHome-Entität — Sensor (Rücklesen):

yaml
sensor:
  - platform: template
    name: "Dimmer Level Readback"
    id: dimmer_level_sensor
    icon: "mdi:brightness-percent"
    unit_of_measurement: "%"
    accuracy_decimals: 0
    update_interval: 5s
    lambda: |-
      uint8_t reg = 0x10;
      uint8_t level = 0;
      if (id(bus_a).write(0x50, ®, 1, false) == i2c::ERROR_OK) {
        if (id(bus_a).read(0x50, &level, 1) == i2c::ERROR_OK) {
          return (float)level;
        }
      }
      return {};


DIM0_CURVE (0x11) — Dimmkurve

Parameter Wert
Adresse 0x11
Zugriff Lesen/Schreiben
Größe 1 Byte
Bereich 0-2

Kurventypen:

Wert Name Beschreibung Anwendung
0 LINEAR Lineare Abhängigkeit Universell
1 RMS Quadratisch (RMS) Glühlampen, Halogen
2 LOG Logarithmisch LED (entspricht der Augenwahrnehmung)
Info
Eine Änderung der Kurve wirkt sich sofort auf die Helligkeit bei der aktuellen Stufe aus.

Lambda — Kurve setzen:

cpp
// Set curve
// 0 = LINEAR, 1 = RMS, 2 = LOG
uint8_t curve = 1;  // RMS

if (curve > 2) {
    ESP_LOGW("dimmerlink", "Invalid curve: %d", curve);
    return;
}

uint8_t data[2] = {0x11, curve};
id(bus_a).write(0x50, data, 2, true);
ESP_LOGI("dimmerlink", "Curve set to %d", curve);

Lambda — Kurve lesen:

cpp
uint8_t reg = 0x11;
uint8_t curve = 0;

if (id(bus_a).write(0x50, ®, 1, false) == i2c::ERROR_OK) {
    if (id(bus_a).read(0x50, &curve, 1) == i2c::ERROR_OK) {
        const char* names[] = {"LINEAR", "RMS", "LOG"};
        if (curve <= 2) {
            ESP_LOGI("dimmerlink", "Current curve: %s", names[curve]);
        }
        return (float)curve;
    }
}
return {};

ESPHome-Entität — Select:

yaml
select:
  - platform: template
    name: "Dimming Curve"
    id: dimming_curve
    icon: "mdi:chart-bell-curve"
    options:
      - "LINEAR"
      - "RMS"
      - "LOG"
    initial_option: "LINEAR"
    optimistic: true
    set_action:
      - lambda: |-
          uint8_t curve = 0;
          if (x == "RMS") curve = 1;
          else if (x == "LOG") curve = 2;

          uint8_t data[2] = {0x11, curve};
          id(bus_a).write(0x50, data, 2, true);
          ESP_LOGI("dimmerlink", "Curve set to: %s (%d)", x.c_str(), curve);

# Read current curve on startup
esphome:
  on_boot:
    priority: -100
    then:
      - lambda: |-
          uint8_t reg = 0x11;
          uint8_t curve = 0;
          if (id(bus_a).write(0x50, ®, 1, false) == i2c::ERROR_OK) {
            if (id(bus_a).read(0x50, &curve, 1) == i2c::ERROR_OK) {
              auto call = id(dimming_curve).make_call();
              switch (curve) {
                case 0: call.set_option("LINEAR"); break;
                case 1: call.set_option("RMS"); break;
                case 2: call.set_option("LOG"); break;
              }
              call.perform();
            }
          }

ESPHome-Entität — Sensor (numerischer Wert):

yaml
sensor:
  - platform: template
    name: "Dimming Curve Value"
    id: dimming_curve_value
    icon: "mdi:chart-bell-curve"
    entity_category: "diagnostic"
    accuracy_decimals: 0
    update_interval: 60s
    lambda: |-
      uint8_t reg = 0x11;
      uint8_t curve = 0;
      if (id(bus_a).write(0x50, ®, 1, false) == i2c::ERROR_OK) {
        if (id(bus_a).read(0x50, &curve, 1) == i2c::ERROR_OK) {
          return (float)curve;
        }
      }
      return {};


Reservierte Register (0x12-0x1F)

Adresse Name Beschreibung
0x12 DIM1_LEVEL Kanal 1 — reserviert
0x13 DIM1_CURVE Kanal 1 — reserviert
0x14 DIM2_LEVEL Kanal 2 — reserviert
0x15 DIM2_CURVE Kanal 2 — reserviert
0x16 DIM3_LEVEL Kanal 3 — reserviert
0x17 DIM3_CURVE Kanal 3 — reserviert
0x18-0x1F Reserviert
Info
Zukünftige Versionen von DimmerLink können bis zu 4 Dimmer-Kanäle unterstützen.



4.4 Systemregister (0x20-0x2F)

Systeminformationen und Kalibrierungsparameter.


AC_FREQ (0x20) — AC-Frequenz

Parameter Wert
Adresse 0x20
Zugriff Nur Lesen
Größe 1 Byte
Werte 50 oder 60 (Hz)

Lambda — Frequenz lesen:

cpp
uint8_t reg = 0x20;
uint8_t freq = 0;

if (id(bus_a).write(0x50, ®, 1, false) == i2c::ERROR_OK) {
    if (id(bus_a).read(0x50, &freq, 1) == i2c::ERROR_OK) {
        if (freq == 50 || freq == 60) {
            ESP_LOGI("dimmerlink", "AC Frequency: %d Hz", freq);
            return (float)freq;
        } else {
            ESP_LOGW("dimmerlink", "Invalid frequency: %d", freq);
        }
    }
}
return {};

ESPHome-Entität — Sensor:

yaml
sensor:
  - platform: template
    name: "AC Frequency"
    id: ac_frequency
    icon: "mdi:sine-wave"
    unit_of_measurement: "Hz"
    accuracy_decimals: 0
    device_class: frequency
    state_class: measurement
    update_interval: 60s
    lambda: |-
      uint8_t reg = 0x20;
      uint8_t freq = 0;
      if (id(bus_a).write(0x50, ®, 1, false) == i2c::ERROR_OK) {
        if (id(bus_a).read(0x50, &freq, 1) == i2c::ERROR_OK) {
          if (freq == 50 || freq == 60) {
            return (float)freq;
          }
        }
      }
      return {};


AC_PERIOD_L / AC_PERIOD_H (0x21-0x22) — Halbwellenperiode

Parameter Wert
Adresse 0x21 (L), 0x22 (H)
Zugriff Nur Lesen
Größe 2 Bytes (16 Bit)
Einheiten Mikrosekunden (µs)

Expected Values:
- 50 Hz: ~10000 us (9000-11000)
- 60 Hz: ~8333 us (7500-9000)

Lambda — Periode lesen:

cpp
uint8_t reg = 0x21;
uint8_t buffer[2] = {0, 0};

if (id(bus_a).write(0x50, ®, 1, false) == i2c::ERROR_OK) {
    if (id(bus_a).read(0x50, buffer, 2) == i2c::ERROR_OK) {
        uint16_t period_us = (buffer[1] << 8) | buffer[0];  // Little-endian
        ESP_LOGI("dimmerlink", "AC Half-period: %d us", period_us);
        return (float)period_us;
    }
}
return {};

ESPHome-Entität — Sensor:

yaml
sensor:
  - platform: template
    name: "AC Half-Period"
    id: ac_period
    icon: "mdi:timer-outline"
    unit_of_measurement: "us"
    accuracy_decimals: 0
    entity_category: "diagnostic"
    update_interval: 60s
    lambda: |-
      uint8_t reg = 0x21;
      uint8_t buffer[2] = {0, 0};
      if (id(bus_a).write(0x50, ®, 1, false) == i2c::ERROR_OK) {
        if (id(bus_a).read(0x50, buffer, 2) == i2c::ERROR_OK) {
          uint16_t period = (buffer[1] << 8) | buffer[0];
          return (float)period;
        }
      }
      return {};


CALIBRATION (0x23) — Kalibrierungsstatus

Parameter Wert
Adresse 0x23
Zugriff Nur Lesen
Größe 1 Byte

Values:
- 0 — Calibration in progress
- 1 — Calibration complete

Lambda — Kalibrierung prüfen:

cpp
uint8_t reg = 0x23;
uint8_t cal_status = 0;

if (id(bus_a).write(0x50, ®, 1, false) == i2c::ERROR_OK) {
    if (id(bus_a).read(0x50, &cal_status, 1) == i2c::ERROR_OK) {
        bool calibrated = (cal_status == 1);
        ESP_LOGI("dimmerlink", "Calibration: %s", calibrated ? "done" : "in progress");
        return calibrated;
    }
}
return {};

ESPHome-Entität — Binary Sensor:

yaml
binary_sensor:
  - platform: template
    name: "DimmerLink Calibrated"
    id: dimmerlink_calibrated
    icon: "mdi:tune"
    entity_category: "diagnostic"
    lambda: |-
      uint8_t reg = 0x23;
      uint8_t status = 0;
      if (id(bus_a).write(0x50, ®, 1, false) == i2c::ERROR_OK) {
        if (id(bus_a).read(0x50, &status, 1) == i2c::ERROR_OK) {
          return status == 1;
        }
      }
      return {};



4.5 Konfigurationsregister (0x30-0x3F)

Gerätekonfigurationsregister.


I2C_ADDRESS (0x30) — I2C-Geräteadresse

Parameter Wert
Adresse 0x30
Zugriff Lesen/Schreiben
Größe 1 Byte
Bereich 0x08-0x77
Standard 0x50
Important
Nach dem Schreiben einer neuen Adresse antwortet das Gerät **sofort** unter der neuen Adresse. Die alte Adresse funktioniert nicht mehr. Die Änderung wird im EEPROM gespeichert.

Prohibited Addresses:
- 0x00-0x07 — reserved by I2C
- 0x78-0x7F — reserved by I2C

Lambda — aktuelle Adresse lesen:

cpp
// Assuming the address is known (default 0x50)
uint8_t current_addr = 0x50;
uint8_t reg = 0x30;
uint8_t addr = 0;

if (id(bus_a).write(current_addr, ®, 1, false) == i2c::ERROR_OK) {
    if (id(bus_a).read(current_addr, &addr, 1) == i2c::ERROR_OK) {
        ESP_LOGI("dimmerlink", "Current I2C address: 0x%02X", addr);
    }
}

Lambda — Adresse ändern:

cpp
// After this operation the device will only respond at the new address!
uint8_t old_addr = 0x50;
uint8_t new_addr = 0x51;

// Range check
if (new_addr < 0x08 || new_addr > 0x77) {
    ESP_LOGE("dimmerlink", "Invalid address: 0x%02X (must be 0x08-0x77)", new_addr);
    return;
}

uint8_t data[2] = {0x30, new_addr};
auto err = id(bus_a).write(old_addr, data, 2, true);

if (err == i2c::ERROR_OK) {
    ESP_LOGW("dimmerlink", "Address changed from 0x%02X to 0x%02X", old_addr, new_addr);
    ESP_LOGW("dimmerlink", "Device now responds ONLY at new address!");
} else {
    ESP_LOGE("dimmerlink", "Failed to change address: %d", err);
}
Warning
Nach der Adressänderung müssen Sie Ihre ESPHome-Konfiguration aktualisieren!

ESPHome-Entität — Number (zur Adressänderung):

yaml
# Dangerous operation! After changing you need to reconfigure everything.
number:
  - platform: template
    name: "DimmerLink I2C Address"
    id: dimmerlink_i2c_address
    icon: "mdi:identifier"
    entity_category: "config"
    min_value: 8      # 0x08
    max_value: 119    # 0x77
    step: 1
    mode: box
    optimistic: true
    set_action:
      - lambda: |-
          uint8_t new_addr = (uint8_t)x;

          if (new_addr < 0x08 || new_addr > 0x77) {
              ESP_LOGE("dimmerlink", "Invalid address: 0x%02X", new_addr);
              return;
          }

          uint8_t data[2] = {0x30, new_addr};
          // Use current address (default 0x50)
          id(bus_a).write(0x50, data, 2, true);

          ESP_LOGW("dimmerlink", "Address changed to 0x%02X", new_addr);
          ESP_LOGW("dimmerlink", "UPDATE YOUR CONFIG AND REBOOT!");

ESPHome — Unterstützung mehrerer Geräte:

yaml
substitutions:
  dimmer1_addr: "0x50"
  dimmer2_addr: "0x51"

output:
  - platform: template
    id: dimmer1_output
    type: float
    write_action:
      - lambda: |-
          uint8_t level = (uint8_t)(state * 100.0f);
          uint8_t data[2] = {0x10, level};
          id(bus_a).write(${dimmer1_addr}, data, 2, true);

  - platform: template
    id: dimmer2_output
    type: float
    write_action:
      - lambda: |-
          uint8_t level = (uint8_t)(state * 100.0f);
          uint8_t data[2] = {0x10, level};
          id(bus_a).write(${dimmer2_addr}, data, 2, true);

light:
  - platform: monochromatic
    name: "Dimmer 1"
    output: dimmer1_output

  - platform: monochromatic
    name: "Dimmer 2"
    output: dimmer2_output



4.6 Referenztabellen


Vollständige Registerkarte

Adresse Name L/S Größe Bereich Beschreibung
0x00 STATUS L 1 Bitmap Gerätestatus
0x01 COMMAND S 1 0-3 Steuerbefehle
0x02 ERROR L 1 Enum Letzter Fehlercode
0x03 VERSION L 1 Firmware-Version
0x04-0x0F Reserviert
0x10 DIM0_LEVEL L/S 1 0-100 Helligkeit Kanal 0 (%)
0x11 DIM0_CURVE L/S 1 0-2 Kurve Kanal 0
0x12-0x1F DIMx Reserviert (Kanäle 1-3)
0x20 AC_FREQ L 1 50/60 AC-Frequenz (Hz)
0x21 AC_PERIOD_L L 1 Periode, Low-Byte (µs)
0x22 AC_PERIOD_H L 1 Periode, High-Byte
0x23 CALIBRATION L 1 0-1 Kalibrierungsstatus
0x24-0x2F Reserviert
0x30 I2C_ADDRESS L/S 1 0x08-0x77 I2C-Geräteadresse
0x31-0x3F Reserviert


Befehlscodes (Register 0x01)

Code Befehl Beschreibung
0x00 NOP Keine Operation
0x01 RESET Software-Reset (~3 Sek.)
0x02 RECALIBRATE Frequenz-Neukalibrierung (~200 ms)
0x03 SWITCH_UART In UART-Modus wechseln


Fehlercodes (Register 0x02)

Code Name Beschreibung
0x00 OK Kein Fehler
0xF9 ERR_SYNTAX Ungültige Registeradresse
0xFC ERR_NOT_READY Gerät nicht bereit (nicht kalibriert oder FLASH-Fehler)
0xFD ERR_INDEX Ungültiger Kanal-Index
0xFE ERR_PARAM Ungültiger Parameterwert


Kurventypen (Register 0x11)

Code Name Formel Anwendung
0 LINEAR out = in Universell
1 RMS out = in^2 Glühlampen
2 LOG out = log(in) LED-Lampen



Änderungsprotokoll

Version Datum Änderungen
1.0 2026-02 Erstversion

← - Lambda-Beispiele | Inhaltsverzeichnis | Weiter: - Lambda FAQ & Fehlerbehebung →