← - Ejemplos Lambda | Contenido | Siguiente: - FAQ y Solución de problemas Lambda →
Integración ESPHome — Referencia Lambda
Referencia completa para trabajar con DimmerLink a través de funciones lambda en ESPHome.
Contenido
- 4.1 Fundamentos de I2C en ESPHome
- 4.2 Registros de control (0x00-0x0F)
- 4.3 Registros del dimmer (0x10-0x1F)
- 4.4 Registros del sistema (0x20-0x2F)
- 4.5 Registros de configuración (0x30-0x3F)
- 4.6 Tablas de referencia
4.1 Fundamentos de I2C en ESPHome
Configuración del bus I2C
i2c:
sda: GPIO21
scl: GPIO22
scan: true
frequency: 100kHz
id: bus_a
| Parámetro | Descripción | Recomendación |
|---|---|---|
sda |
Pin de datos | GPIO21 (por defecto en ESP32) |
scl |
Pin de reloj | GPIO22 (por defecto en ESP32) |
scan |
Escanear bus al inicio | true para depuración |
frequency |
Frecuencia del bus | 100kHz (DimmerLink Standard Mode) |
id |
Identificador del bus | Requerido para lambda |
Constantes y dirección del dispositivo
substitutions:
# DimmerLink I2C address (default)
dimmerlink_addr: "0x50"
Uso en lambda:
// Device address
const uint8_t DIMMERLINK_ADDR = 0x50;
Operaciones I2C básicas
Escritura en un registro
// 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)
Lectura de un registro
// 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
Lectura de múltiples bytes
// 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
Manejo de errores
#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);
}
Registro de eventos
// 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
Funciones auxiliares (globales)
Para mayor comodidad, puede definir funciones auxiliares:
esphome:
includes:
- dimmerlink_helpers.h
Archivo dimmerlink_helpers.h (en la carpeta de configuración):
#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
Uso en lambda:
uint8_t data[2] = {dimmerlink::reg::DIM0_LEVEL, 50};
id(bus_a).write(dimmerlink::ADDR, data, 2, true);
4.2 Registros de control (0x00-0x0F)
Registros de control y estado del dispositivo.
STATUS (0x00) — Estado del dispositivo
| Parámetro | Valor |
|---|---|
| Dirección | 0x00 |
| Acceso | Solo lectura |
| Tamaño | 1 byte |
Estructura de bits:
| Bit | Nombre | Descripción |
|---|---|---|
| 0 | READY | 1 = Dispositivo listo (calibración completada) |
| 1 | ERROR | 1 = Última operación finalizó con error |
| 2-7 | — | Reservado |
Lambda — lectura del estado:
// 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);
}
}
Entidad ESPHome — Binary Sensor:
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) — Comandos de control
| Parámetro | Valor |
|---|---|
| Dirección | 0x01 |
| Acceso | Solo escritura |
| Tamaño | 1 byte |
Comandos disponibles:
| Valor | Comando | Descripción | Tiempo de ejecución |
|---|---|---|---|
0x00 |
NOP | Sin operación | — |
0x01 |
RESET | Reinicio por software | ~3 seg (reboot) |
0x02 |
RECALIBRATE | Recalibración de frecuencia AC | ~200 ms |
0x03 |
SWITCH_UART | Cambio a modo UART | Inmediato |
Lambda — envío de comando:
// General command sending template
void send_command(uint8_t cmd) {
uint8_t data[2] = {0x01, cmd};
id(bus_a).write(0x50, data, 2, true);
}
// 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");
// RECALIBRATE — frequency recalibration
uint8_t data[2] = {0x01, 0x02};
id(bus_a).write(0x50, data, 2, true);
ESP_LOGI("dimmerlink", "Recalibration started");
// 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");
Entidad ESPHome — Button:
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) — Último código de error
| Parámetro | Valor |
|---|---|
| Dirección | 0x02 |
| Acceso | Solo lectura |
| Tamaño | 1 byte |
Códigos de error:
| Código | Nombre | Descripción |
|---|---|---|
0x00 |
OK | Sin error |
0xF9 |
ERR_SYNTAX | Dirección de registro inválida |
0xFC |
ERR_NOT_READY | Dispositivo no listo (sin calibrar o error FLASH) |
0xFD |
ERR_INDEX | Índice de dimmer inválido |
0xFE |
ERR_PARAM | Valor de parámetro inválido |
Lambda — lectura del error:
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);
}
}
}
Entidad ESPHome — Text Sensor:
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) + ")"};
}
Entidad ESPHome — Sensor (código numérico):
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) — Versión del firmware
| Parámetro | Valor |
|---|---|
| Dirección | 0x03 |
| Acceso | Solo lectura |
| Tamaño | 1 byte |
Version Format:
- 0x01 = v1.0
- 0x02 = v2.0
- 0x10 = v1.0 (alternative format, if major.minor)
Lambda — lectura de la versión:
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);
}
}
Entidad ESPHome — Sensor:
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 Registros del dimmer (0x10-0x1F)
Registros de control de canales del dimmer.
DIM0_LEVEL (0x10) — Nivel de brillo
| Parámetro | Valor |
|---|---|
| Dirección | 0x10 |
| Acceso | Lectura/Escritura |
| Tamaño | 1 byte |
| Rango | 0-100 (%) |
Values:
- 0 — off (TRIAC does not open)
- 1-99 — dimming (phase-cut)
- 100 — full brightness (minimum delay)
Lambda — escritura del nivel:
// 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 — lectura del nivel:
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
Entidad ESPHome — Output (base para Light):
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);
}
Entidad ESPHome — Light:
light:
- platform: monochromatic
name: "Dimmer"
id: dimmer_light
output: dimmerlink_output
default_transition_length: 1s
gamma_correct: 1.0 # DimmerLink has its own curves
Entidad ESPHome — Number (control directo):
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);
Entidad ESPHome — Sensor (relectura):
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) — Curva de atenuación
| Parámetro | Valor |
|---|---|
| Dirección | 0x11 |
| Acceso | Lectura/Escritura |
| Tamaño | 1 byte |
| Rango | 0-2 |
Tipos de curvas:
| Valor | Nombre | Descripción | Aplicación |
|---|---|---|---|
0 |
LINEAR | Dependencia lineal | Universal |
1 |
RMS | Cuadrática (RMS) | Lámparas incandescentes, halógenas |
2 |
LOG | Logarítmica | LED (se ajusta a la percepción visual) |
Lambda — configuración de la curva:
// 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 — lectura de la curva:
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 {};
Entidad ESPHome — Select:
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();
}
}
Entidad ESPHome — Sensor (valor numérico):
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 {};
Registros reservados (0x12-0x1F)
| Dirección | Nombre | Descripción |
|---|---|---|
0x12 |
DIM1_LEVEL | Canal 1 — reservado |
0x13 |
DIM1_CURVE | Canal 1 — reservado |
0x14 |
DIM2_LEVEL | Canal 2 — reservado |
0x15 |
DIM2_CURVE | Canal 2 — reservado |
0x16 |
DIM3_LEVEL | Canal 3 — reservado |
0x17 |
DIM3_CURVE | Canal 3 — reservado |
0x18-0x1F |
— | Reservado |
4.4 Registros del sistema (0x20-0x2F)
Información del sistema y parámetros de calibración.
AC_FREQ (0x20) — Frecuencia AC
| Parámetro | Valor |
|---|---|
| Dirección | 0x20 |
| Acceso | Solo lectura |
| Tamaño | 1 byte |
| Valores | 50 o 60 (Hz) |
Lambda — lectura de la frecuencia:
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 {};
Entidad ESPHome — Sensor:
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) — Período de media onda
| Parámetro | Valor |
|---|---|
| Dirección | 0x21 (L), 0x22 (H) |
| Acceso | Solo lectura |
| Tamaño | 2 bytes (16 bits) |
| Unidades | microsegundos (us) |
Expected Values:
- 50 Hz: ~10000 us (9000-11000)
- 60 Hz: ~8333 us (7500-9000)
Lambda — lectura del período:
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 {};
Entidad ESPHome — Sensor:
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) — Estado de calibración
| Parámetro | Valor |
|---|---|
| Dirección | 0x23 |
| Acceso | Solo lectura |
| Tamaño | 1 byte |
Values:
- 0 — Calibration in progress
- 1 — Calibration complete
Lambda — verificación de calibración:
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 {};
Entidad ESPHome — Binary Sensor:
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 Registros de configuración (0x30-0x3F)
Registros de configuración del dispositivo.
I2C_ADDRESS (0x30) — Dirección I2C del dispositivo
| Parámetro | Valor |
|---|---|
| Dirección | 0x30 |
| Acceso | Lectura/Escritura |
| Tamaño | 1 byte |
| Rango | 0x08-0x77 |
| Por defecto | 0x50 |
Prohibited Addresses:
- 0x00-0x07 — reserved by I2C
- 0x78-0x7F — reserved by I2C
Lambda — lectura de la dirección actual:
// 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 — cambio de dirección:
// 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);
}
Entidad ESPHome — Number (para cambiar la dirección):
# 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 — Soporte para múltiples dispositivos:
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 Tablas de referencia
Mapa completo de registros
| Dirección | Nombre | R/W | Tamaño | Rango | Descripción |
|---|---|---|---|---|---|
0x00 |
STATUS | R | 1 | bitmap | Estado del dispositivo |
0x01 |
COMMAND | W | 1 | 0-3 | Comandos de control |
0x02 |
ERROR | R | 1 | enum | Último código de error |
0x03 |
VERSION | R | 1 | — | Versión del firmware |
0x04-0x0F |
— | — | — | — | Reservado |
0x10 |
DIM0_LEVEL | R/W | 1 | 0-100 | Brillo canal 0 (%) |
0x11 |
DIM0_CURVE | R/W | 1 | 0-2 | Curva canal 0 |
0x12-0x1F |
DIMx | — | — | — | Reservado (canales 1-3) |
0x20 |
AC_FREQ | R | 1 | 50/60 | Frecuencia AC (Hz) |
0x21 |
AC_PERIOD_L | R | 1 | — | Período, byte bajo (us) |
0x22 |
AC_PERIOD_H | R | 1 | — | Período, byte alto |
0x23 |
CALIBRATION | R | 1 | 0-1 | Estado de calibración |
0x24-0x2F |
— | — | — | — | Reservado |
0x30 |
I2C_ADDRESS | R/W | 1 | 0x08-0x77 | Dirección I2C del dispositivo |
0x31-0x3F |
— | — | — | — | Reservado |
Códigos de comando (registro 0x01)
| Código | Comando | Descripción |
|---|---|---|
0x00 |
NOP | Sin operación |
0x01 |
RESET | Reinicio por software (~3 seg) |
0x02 |
RECALIBRATE | Recalibración de frecuencia (~200 ms) |
0x03 |
SWITCH_UART | Cambio a modo UART |
Códigos de error (registro 0x02)
| Código | Nombre | Descripción |
|---|---|---|
0x00 |
OK | Sin error |
0xF9 |
ERR_SYNTAX | Dirección de registro inválida |
0xFC |
ERR_NOT_READY | Dispositivo no listo (sin calibrar o error FLASH) |
0xFD |
ERR_INDEX | Índice de canal inválido |
0xFE |
ERR_PARAM | Valor de parámetro inválido |
Tipos de curvas (registro 0x11)
| Código | Nombre | Fórmula | Aplicación |
|---|---|---|---|
0 |
LINEAR | out = in | Universal |
1 |
RMS | out = in^2 | Lámparas incandescentes |
2 |
LOG | out = log(in) | Lámparas LED |
Historial de cambios
| Versión | Fecha | Cambios |
|---|---|---|
| 1.0 | 2026-02 | Versión inicial |
← - Ejemplos Lambda | Contenido | Siguiente: - FAQ y Solución de problemas Lambda →