Home Assistant (HA) — это универсальная платформа с открытым исходным кодом, которая превращает ваш умный дом в единую экосистему. Её главная сила — в способности объединять устройства разных протоколов (Zigbee, Wi-Fi, Bluetooth) и производителей в единую экосистему. Но что делать, если ваше устройство не поддерживается "из коробки"? Ответ прост: создайте свою интеграцию! В этой статье я покажу, как добавить поддержку кондиционеров Hitachi через облачное API вендора.

За время работы с Home Assistant я уже несколько раз сталкивался с необходимостью доработок. В очередной раз такая необходимость возникла при покупке кондиционеров Hitachi. Сейчас все современный модели оснащены WiFi, плюсом производитель не забыл о старых моделях выпустив для них отдельный модуль который подключается к разъему для внешних термостатов.

WiFi Адаптер для кондиционеров Hitachi
WiFi Адаптер для кондиционеров Hitachi

Основной минус, что всё это работает только с проприетарным приложением, ни о каком HomeKit или других экосистемах даже и речь нет.

Когда нужна кастомная интеграция?

  1. Устройство не поддерживается — например, новые модели или DIY-проекты.

  2. Проприетарные системы — как в случае с кондиционерами из моего опыта, где общение с устройством возможно только через закрытое API.

  3. Специфические требования — необходимость расширения функционала стандартных компонентов.

В этой статье я опущу подробности реверс инжиниринга протокола, там оказалось всё достаточно просто, доступа к самом устройству я получить не смог из-за HTTPS, а вот декомпиляция приложения дала возможность воспользоваться REST API облака производителя в полном объеме.

В итоге что мы имеем, REST API для отправки команд и функцию обновления статуса устройств через web socket, давайте превратим это в рабочую интеграцию.

Подготовка окружения

Необходимые инструменты

  1. Home Assistant Core — можно экспериментировать на готовой инсталляции либо поднять тестовую копию

  2. Python 3.10+ — HA написан на Python, и все интеграции также разрабатываются на нем, нужно конечно же базовое знание языка, но никакого rocket science, я 15 лет программирую только на Java но пары часов мануалов по Python мне хватило, чтобы начать писать интеграции под HA

  3. VS Code или PyCharm — для редактирования кода

Структура проекта

Структура

Каждая интеграция представляет собой отдельный Python пакет, находящийся в папке custom_compomets. К примеру если наша интеграция будет называться air_cloud то относительно корня корня HA путь будет выглядеть /custom_compomets/air_cloud.
Что же внутри пакета:

custom_components/
    air_cloud/
        __init__.py         # Инициализация интеграции
        config_flow.py      # UI конфигурации
        climate.py          # Реализация климатического устройства
        manifest.json       # Метаданные интеграции
        api.py              # Обёртка для API вендора 
        consts.py           # Константы 
        translations/
            en.json         # Локализация на английский
            ru.json         # Локализация на русский

Создание manifest.json

Файл manifest.json — основной источник информации об интеграции. Пример:

{
  "domain": "air_cloud",
  "name": "AirCloud",
  "version": "2.0.0",
  "iot_class": "cloud_push",
  "config_flow": true,
  "documentation": "https://github.com/your_repo/docs",
  "requirements": ["aiohttp>=3.9.3", "websockets>=10.4"],
  "codeowners": ["@your_username"]
}

В данном файле описывается название, версия, зависимости библиотек, и прочая служебная информация, из важных моментов, поле domain это фактически уникальный идентификатор вашей интеграции.

Реализация инициализации (__init__.py)

Интеграция должна зарегистрировать себя в HA. В __init__.py для этого используются функция async_setup_entry. Функция исполняется при каждом запуске HA, где происходит загрузки настроек и устройств, для нашего примера реализация будет следующей

Добавление конфигурационного потока (config_flow.py)

Интеграция может быть сконфигурирована через файл configuration.yaml, но это неудобно и с недавнего времени не рекомендовано сообществом HA. Для настройки через UI описывается метод async_step_user в config_flow

async def async_step_user(self, user_input=None):  
    if user_input is not None:  
        login = user_input[CONF_EMAIL]  
        password = user_input[CONF_PASSWORD]  
        temp_adjust = user_input.get(CONF_TEMP_ADJUST)  
  
        if await AirCloudApi(login, password).validate_credentials():  
            return self.async_create_entry(title=login, data=user_input)  
  
        return self.async_show_form(  
            step_id="user",  
            data_schema=self.user_schema,  
            errors={"base": "invalid_credentials"}  
        )  
  
    return self.async_show_form(  
        step_id="user",  
        data_schema=self.user_schema  
    )

Конфигурация устройств (climate.py)

HA работает с устройствами посредством реализации заранее заготовленный в функция в платформах switch(выключаль), light(свет), sensor(датчик) и тп. В нашем случае будет (climate) климат.

Нам необходимо сделать реализацию класса ClimateEntity описав методы взаимодействия с устройством fan_mode, turn_on, turn_off, set_temperature и тп, пример кода:

async def async_turn_on(self):  
    self._power = "ON"  
    await self.__execute_command()  
    
  async def async_turn_off(self):  
    self._power = "OFF"  
    await self.__execute_command()

async def async_set_fan_mode(self, fan_mode):  
    self._update_lock = True  
  
    if fan_mode == FAN_AUTO:  
        self._fan_speed = "AUTO"  
    elif fan_mode == FAN_LOW:  
        self._fan_speed = "LV1"  
    elif fan_mode == FAN_MIDDLE:  
        self._fan_speed = "LV2"  
    elif fan_mode == FAN_MEDIUM:  
        self._fan_speed = "LV3"  
    elif fan_mode == FAN_HIGH:  
        self._fan_speed = "LV4"  
    else:  
        self._fan_speed = "AUTO"  
  
    await self.__execute_command()

Все их тут перечислять не буду, в конце статьи будет ссылка на github, где можно будет посмотреть на код детальнее. Но смысл следующий, каждый метод отвечает за вызов соответствующей функции из HA, после чего происходит интерпретация полученного значения и вызов API вендора.

После описываем загрузку устройств из API создавая экземпляр класса для каждого в функции async_setup_entry

async def async_setup_entry(hass, config_entry, async_add_devices):  
    api = hass.data[DOMAIN][API]  
    temp_adjust = hass.data[DOMAIN][CONF_TEMP_ADJUST]  
  
    entities = []  
    family_ids = await api.load_family_ids()  
    for family_id in family_ids:  
        family_devices = await api.load_climate_data(family_id)  
        for device in family_devices:  
            entities.append(AirCloudClimateEntity(api, device, temp_adjust, family_id))  
  
    if entities:  
        async_add_devices(entities)

Локализация интерфейса

Для каждого языка заводится отдельный файл в формате json содержащий строки и их id.
Пример файла translations/en.json:

{
  "config": {
    "step": {
      "user": {
        "title": "Authentication",
        "data": {
          "email": "Email",
          "password": "Password"
        }
      }
    },
    "error": {
      "invalid_auth": "Invalid credentials"
    }
  }
}

Логотип

Шаги для отображения лого интеграции, выглядят не совсем логично, но почему-то сообщество HA задумало именно так. Необходимо выполнить PR в репозиторий https://github.com/home-assistant/brands по описанным в readme правилам.

Обновление и публикация

Cамый сложный способ публикации это Pull Request непосредственно в HA, но для этого интеграция должна соответствовать достаточно строгим правилам:

  • Соответствие PEP8

  • 100% покрытие mypy

  • Асинхронная реализация методов

  • Подробная документация

  • Основной минус обновление возможно только в формате релизов самого HA.

Вариант намного проще установка через Home Assistant Community Store (HACS), для этого лишь необходимо размести итерацию на Git Hub и добавить hacs.json в корень репозитория, пример:

{
  "name": "AirCloud",
  "domains": ["climate"],
  "homeassistant": "2023.8.0"
}

Таким образом через механизм релизов Git Hub вы получите возможность самостоятельно управлять релизами своей интеграции.

Заключение

Создание кастомной интеграции для Home Assistant — это не только способ добавить поддержку "нестандартных" устройств, но и отличная возможность углубиться в архитектуру умного дома. Даже если ваш код далек от идеала, не стесняйтесь делиться им с сообществом — многие пользователи будут благодарны за готовое решение, а совместными усилиями можно довести интеграцию до совершенства.
Надеюсь, эта статья поможет вам лучше понять процесс создания кастомных интеграций для Home Assistant и вдохновит вас на новые проекты!

Ссылки

Полный исходный код интеграции рассмотренной в статье можно найти на моём Github

Официальная документация HA

Комментарии (1)


  1. Anonym
    30.01.2025 17:05

    Не хотите компонент на поддержку взять? )

    https://github.com/Anonym-tsk/homeassistant-climate-xiaomi-remote