Перейти к содержимому

← - Примеры Lambda | Содержание | Далее: - Lambda FAQ и устранение неполадок →


Интеграция ESPHome — Справочник Lambda

Полный справочник по работе с DimmerLink через ESPHome lambda.

Info
**Документ в процессе написания.** DimmerLink активно развивается — новые регистры и функции будут добавляться в этот справочник.



Содержание




4.1 Основы I2C в ESPHome


Конфигурация шины I2C

yaml
i2c:
  sda: GPIO21
  scl: GPIO22
  scan: true
  frequency: 100kHz
  id: bus_a
Параметр Описание Рекомендация
sda Пин данных GPIO21 (по умолчанию для ESP32)
scl Пин тактового сигнала GPIO22 (по умолчанию для ESP32)
scan Сканировать шину при запуске true для отладки
frequency Частота шины 100kHz (DimmerLink Standard Mode)
id Идентификатор шины Обязателен для lambda


Константы и адрес устройства

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

Для использования в lambda:

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


Базовые операции I2C

Запись в регистр

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)

Чтение из регистра

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

Чтение нескольких байт

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


Обработка ошибок

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);
}


Логирование

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


Вспомогательные функции (глобальные)

Для удобства можно определить вспомогательные функции:

yaml
esphome:
  includes:
    - dimmerlink_helpers.h

Файл dimmerlink_helpers.h (в папке конфигурации):

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

Использование в lambda:

cpp
uint8_t data[2] = {dimmerlink::reg::DIM0_LEVEL, 50};
id(bus_a).write(dimmerlink::ADDR, data, 2, true);
Tip
Использование вспомогательного файла необязательно. Все примеры ниже работают и без него.



4.2 Регистры управления (0x00-0x0F)

Регистры управления и состояния устройства.


STATUS (0x00) — Статус устройства

Параметр Значение
Адрес 0x00
Доступ Только чтение
Размер 1 байт

Битовая структура:

Бит Имя Описание
0 READY 1 = Устройство готово (калибровка завершена)
1 ERROR 1 = Последняя операция завершилась с ошибкой
2-7 Зарезервировано

Lambda — чтение статуса:

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 — 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) — Команды управления

Параметр Значение
Адрес 0x01
Доступ Только запись
Размер 1 байт

Доступные команды:

Значение Команда Описание Время выполнения
0x00 NOP Нет операции
0x01 RESET Программный сброс ~3 сек (перезагрузка)
0x02 RECALIBRATE Перекалибровка частоты AC ~200 мс
0x03 SWITCH_UART Переключение в режим UART Мгновенно

Lambda — отправка команды:

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
После команды `SWITCH_UART` устройство перестаёт отвечать по I2C!

Сущность ESPHome — 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) — Код последней ошибки

Параметр Значение
Адрес 0x02
Доступ Только чтение
Размер 1 байт

Коды ошибок:

Код Имя Описание
0x00 OK Нет ошибки
0xF9 ERR_SYNTAX Недопустимый адрес регистра
0xFC ERR_NOT_READY Устройство не готово (не откалибровано или ошибка FLASH)
0xFD ERR_INDEX Недопустимый индекс диммера
0xFE ERR_PARAM Недопустимое значение параметра

Lambda — чтение ошибки:

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 — 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 — Sensor (числовой код):

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) — Версия прошивки

Параметр Значение
Адрес 0x03
Доступ Только чтение
Размер 1 байт

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

Lambda — чтение версии:

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 — 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 Регистры диммера (0x10-0x1F)

Регистры управления каналами диммера.

Info
**Текущая версия:** поддерживается 1 канал (DIM0). Регистры DIM1-DIM3 зарезервированы для будущих версий.


DIM0_LEVEL (0x10) — Уровень яркости

Параметр Значение
Адрес 0x10
Доступ Чтение/Запись
Размер 1 байт
Диапазон 0-100 (%)

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

Warning
Запись значения > 100 вернёт ошибку `ERR_PARAM (0xFE)`.

Lambda — запись уровня:

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 — чтение уровня:

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 — Output (основа для 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 — 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 — Number (прямое управление):

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 — Sensor (обратное считывание):

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) — Кривая диммирования

Параметр Значение
Адрес 0x11
Доступ Чтение/Запись
Размер 1 байт
Диапазон 0-2

Типы кривых:

Значение Имя Описание Применение
0 LINEAR Линейная зависимость Универсальная
1 RMS Квадратичная (RMS) Лампы накаливания, галогенные
2 LOG Логарифмическая LED (соответствует восприятию глаза)
Info
Изменение кривой мгновенно влияет на яркость при текущем уровне.

Lambda — установка кривой:

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 — чтение кривой:

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 — 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 — Sensor (числовое значение):

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 {};


Зарезервированные регистры (0x12-0x1F)

Адрес Имя Описание
0x12 DIM1_LEVEL Канал 1 — зарезервирован
0x13 DIM1_CURVE Канал 1 — зарезервирован
0x14 DIM2_LEVEL Канал 2 — зарезервирован
0x15 DIM2_CURVE Канал 2 — зарезервирован
0x16 DIM3_LEVEL Канал 3 — зарезервирован
0x17 DIM3_CURVE Канал 3 — зарезервирован
0x18-0x1F Зарезервировано
Info
Будущие версии DimmerLink могут поддерживать до 4 каналов диммирования.



4.4 Системные регистры (0x20-0x2F)

Системная информация и параметры калибровки.


AC_FREQ (0x20) — Частота AC

Параметр Значение
Адрес 0x20
Доступ Только чтение
Размер 1 байт
Значения 50 или 60 (Гц)

Lambda — чтение частоты:

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 — 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) — Период полуволны

Параметр Значение
Адрес 0x21 (L), 0x22 (H)
Доступ Только чтение
Размер 2 байта (16 бит)
Единицы микросекунды (мкс)

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

Lambda — чтение периода:

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 — 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) — Статус калибровки

Параметр Значение
Адрес 0x23
Доступ Только чтение
Размер 1 байт

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

Lambda — проверка калибровки:

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 — 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 Регистры конфигурации (0x30-0x3F)

Регистры конфигурации устройства.


I2C_ADDRESS (0x30) — I2C-адрес устройства

Параметр Значение
Адрес 0x30
Доступ Чтение/Запись
Размер 1 байт
Диапазон 0x08-0x77
По умолчанию 0x50
Important
После записи нового адреса устройство **немедленно** начинает отвечать по новому адресу. Старый адрес перестаёт работать. Изменение сохраняется в EEPROM.

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

Lambda — чтение текущего адреса:

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 — изменение адреса:

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
После изменения адреса необходимо обновить конфигурацию ESPHome!

Сущность ESPHome — Number (для изменения адреса):

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 — Поддержка нескольких устройств:

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 Справочные таблицы


Полная карта регистров

Адрес Имя Ч/З Размер Диапазон Описание
0x00 STATUS Ч 1 bitmap Статус устройства
0x01 COMMAND З 1 0-3 Команды управления
0x02 ERROR Ч 1 enum Код последней ошибки
0x03 VERSION Ч 1 Версия прошивки
0x04-0x0F Зарезервировано
0x10 DIM0_LEVEL Ч/З 1 0-100 Яркость канала 0 (%)
0x11 DIM0_CURVE Ч/З 1 0-2 Кривая канала 0
0x12-0x1F DIMx Зарезервировано (каналы 1-3)
0x20 AC_FREQ Ч 1 50/60 Частота AC (Гц)
0x21 AC_PERIOD_L Ч 1 Период, младший байт (мкс)
0x22 AC_PERIOD_H Ч 1 Период, старший байт
0x23 CALIBRATION Ч 1 0-1 Статус калибровки
0x24-0x2F Зарезервировано
0x30 I2C_ADDRESS Ч/З 1 0x08-0x77 I2C-адрес устройства
0x31-0x3F Зарезервировано


Коды команд (регистр 0x01)

Код Команда Описание
0x00 NOP Нет операции
0x01 RESET Программный сброс (~3 сек)
0x02 RECALIBRATE Перекалибровка частоты (~200 мс)
0x03 SWITCH_UART Переключение в режим UART


Коды ошибок (регистр 0x02)

Код Имя Описание
0x00 OK Нет ошибки
0xF9 ERR_SYNTAX Недопустимый адрес регистра
0xFC ERR_NOT_READY Устройство не готово (не откалибровано или ошибка FLASH)
0xFD ERR_INDEX Недопустимый индекс канала
0xFE ERR_PARAM Недопустимое значение параметра


Типы кривых (регистр 0x11)

Код Имя Формула Применение
0 LINEAR out = in Универсальная
1 RMS out = in^2 Лампы накаливания
2 LOG out = log(in) LED-лампы



Журнал изменений

Версия Дата Изменения
1.0 2026-02 Первоначальная версия

← - Примеры Lambda | Содержание | Далее: - Lambda FAQ и устранение неполадок →