← - Esempi Lambda | Indice | Avanti: - FAQ e Risoluzione dei problemi Lambda →
Integrazione ESPHome — Riferimento Lambda
Riferimento completo per lavorare con DimmerLink tramite le funzioni lambda di ESPHome.
Indice
- 4.1 Fondamenti I2C in ESPHome
- 4.2 Registri di controllo (0x00-0x0F)
- 4.3 Registri del dimmer (0x10-0x1F)
- 4.4 Registri di sistema (0x20-0x2F)
- 4.5 Registri di configurazione (0x30-0x3F)
- 4.6 Tabelle di riferimento
4.1 Fondamenti I2C in ESPHome
Configurazione del bus I2C
i2c:
sda: GPIO21
scl: GPIO22
scan: true
frequency: 100kHz
id: bus_a
| Parametro | Descrizione | Raccomandazione |
|---|---|---|
sda |
Pin dati | GPIO21 (predefinito ESP32) |
scl |
Pin clock | GPIO22 (predefinito ESP32) |
scan |
Scansione bus all'avvio | true per il debug |
frequency |
Frequenza del bus | 100kHz (DimmerLink Standard Mode) |
id |
Identificatore del bus | Necessario per lambda |
Costanti e indirizzo del dispositivo
substitutions:
# DimmerLink I2C address (default)
dimmerlink_addr: "0x50"
Utilizzo in lambda:
// Device address
const uint8_t DIMMERLINK_ADDR = 0x50;
Operazioni I2C di base
Scrittura in 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)
Lettura da 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
Lettura di più byte
// 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
Gestione degli errori
#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);
}
Registrazione dei log
// 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
Funzioni ausiliarie (globali)
Per comodità, è possibile definire funzioni ausiliarie:
esphome:
includes:
- dimmerlink_helpers.h
File dimmerlink_helpers.h (nella cartella di configurazione):
#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
Utilizzo in lambda:
uint8_t data[2] = {dimmerlink::reg::DIM0_LEVEL, 50};
id(bus_a).write(dimmerlink::ADDR, data, 2, true);
4.2 Registri di controllo (0x00-0x0F)
Registri di controllo e stato del dispositivo.
STATUS (0x00) — Stato del dispositivo
| Parametro | Valore |
|---|---|
| Indirizzo | 0x00 |
| Accesso | Sola lettura |
| Dimensione | 1 byte |
Struttura dei bit:
| Bit | Nome | Descrizione |
|---|---|---|
| 0 | READY | 1 = Dispositivo pronto (calibrazione completata) |
| 1 | ERROR | 1 = Ultima operazione terminata con errore |
| 2-7 | — | Riservato |
Lambda — lettura dello stato:
// 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);
}
}
Entità 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) — Comandi di controllo
| Parametro | Valore |
|---|---|
| Indirizzo | 0x01 |
| Accesso | Sola scrittura |
| Dimensione | 1 byte |
Comandi disponibili:
| Valore | Comando | Descrizione | Tempo di esecuzione |
|---|---|---|---|
0x00 |
NOP | Nessuna operazione | — |
0x01 |
RESET | Riavvio software | ~3 sec (reboot) |
0x02 |
RECALIBRATE | Ricalibrazione della frequenza AC | ~200 ms |
0x03 |
SWITCH_UART | Passaggio alla modalità UART | Immediato |
Lambda — invio 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");
Entità 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) — Ultimo codice di errore
| Parametro | Valore |
|---|---|
| Indirizzo | 0x02 |
| Accesso | Sola lettura |
| Dimensione | 1 byte |
Codici di errore:
| Codice | Nome | Descrizione |
|---|---|---|
0x00 |
OK | Nessun errore |
0xF9 |
ERR_SYNTAX | Indirizzo di registro non valido |
0xFC |
ERR_NOT_READY | Dispositivo non pronto (non calibrato o errore FLASH) |
0xFD |
ERR_INDEX | Indice dimmer non valido |
0xFE |
ERR_PARAM | Valore del parametro non valido |
Lambda — lettura dell'errore:
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);
}
}
}
Entità 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) + ")"};
}
Entità ESPHome — Sensor (codice numerico):
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) — Versione del firmware
| Parametro | Valore |
|---|---|
| Indirizzo | 0x03 |
| Accesso | Sola lettura |
| Dimensione | 1 byte |
Version Format:
- 0x01 = v1.0
- 0x02 = v2.0
- 0x10 = v1.0 (alternative format, if major.minor)
Lambda — lettura della versione:
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);
}
}
Entità 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 Registri del dimmer (0x10-0x1F)
Registri di controllo dei canali del dimmer.
DIM0_LEVEL (0x10) — Livello di luminosità
| Parametro | Valore |
|---|---|
| Indirizzo | 0x10 |
| Accesso | Lettura/Scrittura |
| Dimensione | 1 byte |
| Intervallo | 0-100 (%) |
Values:
- 0 — off (TRIAC does not open)
- 1-99 — dimming (phase-cut)
- 100 — full brightness (minimum delay)
Lambda — scrittura del livello:
// 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 — lettura del livello:
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
Entità ESPHome — Output (base per 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);
}
Entità 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
Entità ESPHome — Number (controllo diretto):
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);
Entità ESPHome — Sensor (rilettura):
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 di dimmerizzazione
| Parametro | Valore |
|---|---|
| Indirizzo | 0x11 |
| Accesso | Lettura/Scrittura |
| Dimensione | 1 byte |
| Intervallo | 0-2 |
Tipi di curve:
| Valore | Nome | Descrizione | Applicazione |
|---|---|---|---|
0 |
LINEAR | Dipendenza lineare | Universale |
1 |
RMS | Quadratica (RMS) | Lampade a incandescenza, alogene |
2 |
LOG | Logaritmica | LED (corrisponde alla percezione visiva) |
Lambda — impostazione della 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 — lettura della 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 {};
Entità 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();
}
}
Entità ESPHome — Sensor (valore numerico):
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 {};
Registri riservati (0x12-0x1F)
| Indirizzo | Nome | Descrizione |
|---|---|---|
0x12 |
DIM1_LEVEL | Canale 1 — riservato |
0x13 |
DIM1_CURVE | Canale 1 — riservato |
0x14 |
DIM2_LEVEL | Canale 2 — riservato |
0x15 |
DIM2_CURVE | Canale 2 — riservato |
0x16 |
DIM3_LEVEL | Canale 3 — riservato |
0x17 |
DIM3_CURVE | Canale 3 — riservato |
0x18-0x1F |
— | Riservato |
4.4 Registri di sistema (0x20-0x2F)
Informazioni di sistema e parametri di calibrazione.
AC_FREQ (0x20) — Frequenza AC
| Parametro | Valore |
|---|---|
| Indirizzo | 0x20 |
| Accesso | Sola lettura |
| Dimensione | 1 byte |
| Valori | 50 o 60 (Hz) |
Lambda — lettura della frequenza:
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 {};
Entità 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) — Periodo della semionda
| Parametro | Valore |
|---|---|
| Indirizzo | 0x21 (L), 0x22 (H) |
| Accesso | Sola lettura |
| Dimensione | 2 byte (16 bit) |
| Unità | microsecondi (us) |
Expected Values:
- 50 Hz: ~10000 us (9000-11000)
- 60 Hz: ~8333 us (7500-9000)
Lambda — lettura del periodo:
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 {};
Entità 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) — Stato della calibrazione
| Parametro | Valore |
|---|---|
| Indirizzo | 0x23 |
| Accesso | Sola lettura |
| Dimensione | 1 byte |
Values:
- 0 — Calibration in progress
- 1 — Calibration complete
Lambda — verifica della calibrazione:
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 {};
Entità 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 Registri di configurazione (0x30-0x3F)
Registri di configurazione del dispositivo.
I2C_ADDRESS (0x30) — Indirizzo I2C del dispositivo
| Parametro | Valore |
|---|---|
| Indirizzo | 0x30 |
| Accesso | Lettura/Scrittura |
| Dimensione | 1 byte |
| Intervallo | 0x08-0x77 |
| Predefinito | 0x50 |
Prohibited Addresses:
- 0x00-0x07 — reserved by I2C
- 0x78-0x7F — reserved by I2C
Lambda — lettura dell'indirizzo attuale:
// 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 — modifica dell'indirizzo:
// 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);
}
Entità ESPHome — Number (per cambiare l'indirizzo):
# 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 — Supporto per più dispositivi:
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 Tabelle di riferimento
Mappa completa dei registri
| Indirizzo | Nome | R/W | Dim. | Intervallo | Descrizione |
|---|---|---|---|---|---|
0x00 |
STATUS | R | 1 | bitmap | Stato del dispositivo |
0x01 |
COMMAND | W | 1 | 0-3 | Comandi di controllo |
0x02 |
ERROR | R | 1 | enum | Ultimo codice di errore |
0x03 |
VERSION | R | 1 | — | Versione del firmware |
0x04-0x0F |
— | — | — | — | Riservato |
0x10 |
DIM0_LEVEL | R/W | 1 | 0-100 | Luminosità canale 0 (%) |
0x11 |
DIM0_CURVE | R/W | 1 | 0-2 | Curva canale 0 |
0x12-0x1F |
DIMx | — | — | — | Riservato (canali 1-3) |
0x20 |
AC_FREQ | R | 1 | 50/60 | Frequenza AC (Hz) |
0x21 |
AC_PERIOD_L | R | 1 | — | Periodo, byte basso (us) |
0x22 |
AC_PERIOD_H | R | 1 | — | Periodo, byte alto |
0x23 |
CALIBRATION | R | 1 | 0-1 | Stato della calibrazione |
0x24-0x2F |
— | — | — | — | Riservato |
0x30 |
I2C_ADDRESS | R/W | 1 | 0x08-0x77 | Indirizzo I2C del dispositivo |
0x31-0x3F |
— | — | — | — | Riservato |
Codici di comando (registro 0x01)
| Codice | Comando | Descrizione |
|---|---|---|
0x00 |
NOP | Nessuna operazione |
0x01 |
RESET | Riavvio software (~3 sec) |
0x02 |
RECALIBRATE | Ricalibrazione della frequenza (~200 ms) |
0x03 |
SWITCH_UART | Passaggio alla modalità UART |
Codici di errore (registro 0x02)
| Codice | Nome | Descrizione |
|---|---|---|
0x00 |
OK | Nessun errore |
0xF9 |
ERR_SYNTAX | Indirizzo di registro non valido |
0xFC |
ERR_NOT_READY | Dispositivo non pronto (non calibrato o errore FLASH) |
0xFD |
ERR_INDEX | Indice canale non valido |
0xFE |
ERR_PARAM | Valore del parametro non valido |
Tipi di curve (registro 0x11)
| Codice | Nome | Formula | Applicazione |
|---|---|---|---|
0 |
LINEAR | out = in | Universale |
1 |
RMS | out = in^2 | Lampade a incandescenza |
2 |
LOG | out = log(in) | Lampade LED |
Cronologia delle modifiche
| Versione | Data | Modifiche |
|---|---|---|
| 1.0 | 2026-02 | Versione iniziale |
← - Esempi Lambda | Indice | Avanti: - FAQ e Risoluzione dei problemi Lambda →