Статья

Внедряем Matter в существующий проект под ESP32. Часть 1: Настраиваем Build систему

LOOKin

В этом цикле статей мы рассмотрим шаг за шагом внедрение Matter в проект на ESP32. Если быть точнее - замену HomeKit на Matter.В данной статье речь пойдет про настройку Build системы для нашего будущего Matter-enabled проекта.
Что имеем: 

  1. Довольно большой по обьему кода проект на ESP32. 
  2. Существующую систему сборки проекта, которая подразумевает сборку под 2 поколения устройств.
  3. Внедренный в прошивку HomeKit в тестовом режиме.
  4. Поддержку таких типов HomeKit устройств, как TV, ресиверы, лампы, выключатели, открывашки окон, кондиционеры, сенсоры температуры и влажности.
  5. Многоуровневые зависимости в проекте, которые позволяют разрабатывать каждый кусок кода независимо без доступа к основной логике.
  6. Желание и необходимость внедрить протокол Matter и полностью заменить им HK.
  7. Активное использование кастомного стека BLE, что затрудняет использование Matter "из коробки".
  8. Активное использование MDNS в прошивке и необходимость поженить его с Matter.
  9. Собственная система провизинга новых устройств, что также затрудняет использование Matter "из коробки".

Чего хотим достичь:

  1. Полностью перейти на протокол Matter для работы с Home.app и всей яблочной экосистемой.
  2. С помощью протокола Matter отказаться от поддержки некоторых плагинов, например для Smart Things, чтобы работа была возможна "из коробки".

LOOKin - экосистема для умного дома для производителей и пользователей.

Мы также выпускаем и свои устройства, например - Умный ИК/BLE пульт LOOKin Remote.


Всё описанное проделывается под операционной системой MacOS.

Шаг 1. Установка Matter

  1. Первое, что необходимо помнить -  для нормальной работы нужна версия esp-idf не ниже 4.4.2, это тоже задача, которая потребует, скорее всего, обновления кода вашей прошивки. До этой версии отсутствует компонент OpenTread, что не позволяет полноценно собрать прошивку.
  2. Скачиваем репозиторий Matter
  3. Открываем консоль, она же терминал, и переходим в корень скаченного репозитория
  4. Необходимо выполнить 2 команды, которые устанавливают все нужные зависимости:
bash
Копировать
source scripts/activate.sh
source scripts/bootstrap.sh

В итоге мы должны получить вот такое жизнеутверждающее сообщение - мы закончили с установкой Matter. Сам процесс длится довольно долго. На первой установке может уйти до 30 минут на то, чтобы второй скрипт закончил свою работу.

Успешное сообщение об установке Matter

Пожалуйста, обратите внимание, что исходники Matter со всеми зависимостями занимают довольно много места.

Размер папки с Matter после установки всех зависимостей

Проверка работоспособности

Перед тем, как двигаться дальше, крайне рекомендую вам проверить саму работу Matter на основе примеров. Например, на основе all-clusters-minimal-app. Для этого:

bash
Копировать
cd Matter/examples/all-clusters-minimal-app/esp32
idf.py flash

После проверки тестового проекта и вдоволь им наигравшись, можно переходить дальше.

Миграция

У нас уже есть HomeKit в экспериментальном режиме, значит есть 2 способа как можно начать замену фреймворка. 
1. Полностью выпилить все упоминания старого функционала и шаг за шагом начать внедрение Matter. 2. Скрыть всю логику уже существующих функций, связанных с HK, и шаг за шагом менять эту логику, используя новый фремворк.
Естественно, каждый волен выбирать свою дорогу, но мы решили пойти вторым путем. - Сначала мы изменили все названия файлов и классов на Matter.- Закомментировали всю логику внутри методов, отвечающих за HK.- Убрали из аргументов функций все упоминания старых классов (иначе бы проект не собрался).- Полностью убрали подключение фреймворка HK.Теперь, шаг за шагом можно начать внедрять новый фреймворк без ущерба для логики работы проекта, однако, смотря вперед, немного шевелятся волосы от того, какой обьем работы нужно провести.

Настройка Build системы

Окей, пробуем собрать проект. И снова неудача - необходимо подключить компоненты и исходники Matter к текущему проекту.
Для этого достаточно изменить два CMakeLists.txt файла - один для проекта, другой, собственно, для основного компонента прошивки.

Для проекта:

bash
Копировать
set(EXTRA_COMPONENT_DIRS 
    "${CMAKE_CURRENT_LIST_DIR}/../Toolchain/matter/config/esp32/components"
    "${CMAKE_CURRENT_LIST_DIR}/../Toolchain/matter/examples/common/QRCode"
    "drivers libs src drivers/Periphery")

Для основного компонента:

bash
Копировать
idf_component_register(
  INCLUDE_DIRS 
    "Matter/include"
    "include" 
    PRIV_INCLUDE_DIRS
    "${CMAKE_SOURCE_DIR}/../Toolchain/matter/zzz_generated/bridge-app"
    "${CMAKE_CURRENT_LIST_DIR}/include"
    "${CMAKE_SOURCE_DIR}/../Toolchain/matter/examples/providers"
    SRCS
    "${srcs}"
    "${CMAKE_CURRENT_LIST_DIR}"
    "${CMAKE_SOURCE_DIR}/../Toolchain/matter/zzz_generated/bridge-app/zap-generated"
    "${CMAKE_SOURCE_DIR}/../Toolchain/matter/zzz_generated/app-common/app-common/zap-generated/attributes"
    "${CMAKE_SOURCE_DIR}/../Toolchain/matter/zzz_generated/app-common/app-common/zap-generated"
    "${CMAKE_SOURCE_DIR}/../Toolchain/matter/src/app/server"
    "${CMAKE_SOURCE_DIR}/../Toolchain/matter/src/app/util"
    "${CMAKE_SOURCE_DIR}/../Toolchain/matter/src/app/reporting"
    "${CMAKE_SOURCE_DIR}/../Toolchain/matter/src/app/clusters/access-control-server"
    "${CMAKE_SOURCE_DIR}/../Toolchain/matter/src/app/clusters/administrator-commissioning-server"
    "${CMAKE_SOURCE_DIR}/../Toolchain/matter/src/app/clusters/basic"
    "${CMAKE_SOURCE_DIR}/../Toolchain/matter/src/app/clusters/bridged-device-basic-information-server"
    "${CMAKE_SOURCE_DIR}/../Toolchain/matter/src/app/clusters/level-control"
    "${CMAKE_SOURCE_DIR}/../Toolchain/matter/src/app/clusters/identify-server"
    "${CMAKE_SOURCE_DIR}/../Toolchain/matter/src/app/clusters/diagnostic-logs-server"
    "${CMAKE_SOURCE_DIR}/../Toolchain/matter/src/app/clusters/ethernet-network-diagnostics-server"
    "${CMAKE_SOURCE_DIR}/../Toolchain/matter/src/app/clusters/localization-configuration-server"
    "${CMAKE_SOURCE_DIR}/../Toolchain/matter/src/app/clusters/time-format-localization-server"
    "${CMAKE_SOURCE_DIR}/../Toolchain/matter/src/app/clusters/fixed-label-server"
    "${CMAKE_SOURCE_DIR}/../Toolchain/matter/src/app/clusters/user-label-server"
    "${CMAKE_SOURCE_DIR}/../Toolchain/matter/src/app/clusters/thread-network-diagnostics-server"
    "${CMAKE_SOURCE_DIR}/../Toolchain/matter/src/app/clusters/wifi-network-diagnostics-server"
    "${CMAKE_SOURCE_DIR}/../Toolchain/matter/src/app/clusters/software-diagnostics-server"
    "${CMAKE_SOURCE_DIR}/../Toolchain/matter/src/app/clusters/switch-server"
    "${CMAKE_SOURCE_DIR}/../Toolchain/matter/src/app/clusters/general-diagnostics-server"
    "${CMAKE_SOURCE_DIR}/../Toolchain/matter/src/app/clusters/group-key-mgmt-server"
    "${CMAKE_SOURCE_DIR}/../Toolchain/matter/src/app/clusters/descriptor"
    "${CMAKE_SOURCE_DIR}/../Toolchain/matter/src/app/clusters/network-commissioning"
    "${CMAKE_SOURCE_DIR}/../Toolchain/matter/src/app/clusters/on-off-server"
    "${CMAKE_SOURCE_DIR}/../Toolchain/matter/src/app/clusters/operational-credentials-server"
    "${CMAKE_SOURCE_DIR}/../Toolchain/matter/src/app/clusters/general-commissioning-server"
    "${CMAKE_SOURCE_DIR}/../Toolchain/matter/examples/platform/esp32/route_hook"
    "${CMAKE_SOURCE_DIR}/../Toolchain/matter/examples/platform/esp32/common"
    "${CMAKE_SOURCE_DIR}/../Toolchain/matter/examples/providers"

Окей, поехали дальше, пробуем собрать решение через idf.py build снова и снова получаем проблему:

bash
Копировать
The 'gn' command was not found.  Make sure you have GN installed.Or have
  followed necessary build preparations stated in BUILDING.md.

Решаем через MacPorts:

bash
Копировать
sudo port install gn-devel

Не забудьте, что для того, чтобы ваша текущая консоль приняла изменения, необходимо ее обновить, либо выполнить следующую команду:

bash
Копировать
source ~/.zprofile

Правда перед этим еще и пришлось MacPorts поставить собственной персоной :)
Вроде как успех, поехали дальше!

Но не тут то было - у нас новая ошибка!

bash
Копировать
CMake Error at /Users/XXX/Documents/LOOKin/Firmware/Toolchain/esp-idf/tools/cmake/component.cmake:368 (__component_get_property):
  __component_get_property Function invoked with incorrect arguments for
  function named: __component_get_property
Call Stack (most recent call first):
  /Users/XXX/Documents/LOOKin/Firmware/Toolchain/matter/config/esp32/components/chip/CMakeLists.txt:318 (idf_component_get_property)

После достаточно долгого поиска по исходникам (возможно, вам это поможет), обнаружилось, что matter в текущем виде поддерживает только компонент main и не умеет работать с кастовыми названиями компонентов. 
Быстрого скриптового решения не нашлось, поэтому на первое время захардкодили новое название в источниках Matter и поехали далее. К этому вопросу нужно будет обязательно вернуться обратно позже.
Для тех, кому это может быть нужно:

bash
Копировать
config/esp32/components/chip/CMakeLists.txt в строке 318 нужно заменить второй параметр у функции idf_component_get_property на название вашего компонента

И вот, после очередной попытки сборки проекта, на экране появляются заветные надписи:

bash
Копировать
-- Configuring done
-- Generating done
-- Build files have been written to: /Users/XXX/Documents/LOOKin/Firmware/Source/build

Прошивка собирается, далее уже внедрение Matter!

Проблемы с инклудами

И тут же начались проблемы с инклудами (куда без них). Компилятор стал ругаться на ошибки  с подключением файлов из Matter.
Например, вот на эту строку:

bash
Копировать
#include 

Для решения проблем с зависимостью, ищем необходимые файлы и каждый из них добавляем в CMakeLists.txt уровня основного компонента нужные пути в переменную INCLUDE_DIRS Получившийся CMakeLists.txt (убрали некоторые строки для чистоты)

bash
Копировать
set(SRC_FILES 
    "(список исходных файлов)")

idf_component_register(
	PRIV_INCLUDE_DIRS
	"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/zzz_generated/bridge-app"

	"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/examples/providers"
	INCLUDE_DIRS
	"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src"
	"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/util"
	"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/third_party/nlio/repo/include"
	"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/third_party/nlassert/repo/include"
	SRCS
	"${SRC_FILES}"
	"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/zzz_generated/bridge-app/zap-generated"
	"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/zzz_generated/app-common/app-common/zap-generated/attributes"
	"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/zzz_generated/app-common/app-common/zap-generated"
	"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/server"
	"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/util"
	"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/reporting"
	"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/access-control-server"
	"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/administrator-commissioning-server"
	"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/basic"
	"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/bridged-device-basic-information-server"
	"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/level-control"
	"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/identify-server"
	"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/diagnostic-logs-server"
	"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/ethernet-network-diagnostics-server"
	"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/localization-configuration-server"
	"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/time-format-localization-server"
	"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/fixed-label-server"
	"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/user-label-server"
	"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/thread-network-diagnostics-server"
	"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/wifi-network-diagnostics-server"
	"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/software-diagnostics-server"
	"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/switch-server"
	"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/general-diagnostics-server"
	"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/group-key-mgmt-server"
	"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/descriptor"
	"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/network-commissioning"
	"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/on-off-server"
	"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/operational-credentials-server"
	"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/general-commissioning-server"
	"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/examples/platform/esp32/route_hook"
	"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/examples/platform/esp32/common"
	"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/examples/providers"
	PRIV_REQUIRES chip QRCode bt
	REQUIRES 
	"(список компонентов)")

target_compile_options(${COMPONENT_LIB} PRIVATE "-D LOG_LOCAL_LEVEL=ESP_LOG_DEBUG")

set_property(TARGET ${COMPONENT_LIB} PROPERTY CXX_STANDARD 17)
target_compile_options(${COMPONENT_LIB} PRIVATE "-DCHIP_HAVE_CONFIG_H")
target_compile_options(${COMPONENT_LIB} PUBLIC
           "-DCHIP_ADDRESS_RESOLVE_IMPL_INCLUDE_HEADER=")

flashing_script()

Снова пробуем собрать проект и получаем новую крайне интересную ошибку:

bash
Копировать
../third_party/connectedhomeip/src/lib/core/CHIPConfig.h:39:10: fatal error: core/CHIPBuildConfig.h: No such file or directory
 #include 

Cуть проблемы: При начале компиляции matter готовит необходимые дефолтные конфиги, а в проекте есть несколько компонентов, ссылающихся на основной компонент. В этом случае меняется уровень вложенности и конструкция из CMakeLists.txt не позволяет найти нужный файл. 

Вариантов решения 3:

1. Убрать флаг CHIP_HAVE_CONFIG_H из компиляции. Как хардкод допустимо, но лучше так не делать.

Если все-таки решили идти этим путем, то:
- Комментируем #target_compile_options(${COMPONENT_LIB} PRIVATE «-DCHIP_HAVE_CONFIG_H") в файле CMakeLists.txt на уровне основного проекта - Из строки в CMakeLists.txt в корне проекта убираем добавление флага CHIP_HAVE_CONFIG_H

Было:

bash
Копировать
idf_build_set_property(CXX_COMPILE_OPTIONS "-std=gnu++17;-Os;-DCHIP_HAVE_CONFIG_H" APPEND) 

Стало:

bash
Копировать
idf_build_set_property(CXX_COMPILE_OPTIONS "-std=gnu++17;-Os" APPEND)

2. Прописать в CMakeLists.txt полные пути до нужных директорий. Все вроде хорошо, но у каждого из разработчиков пути разные и это усложнит командную работу над проектом.

3. Убрать любые вхождения файлов из основного проекта в компоненты проекта. Это самый сложный путь, так как придется переписывать компоненты, но он самый верный с точки зрения дальнейшей работы над проектом.

Выбираем третий вариант и переписываем компоненты.

В связи с переходом на C++ 14/17 (если вы использовали 11 ранее) необходимо поменять void app_main(void) на void app_main()
Ну и не забываем про extern "C" 😁

И вот мы у цели - наш проект стал собираться!

Имеем 131 ошибку и 208 варнингов - план работ понятен.Теперь уже в консоли стали появляться ошибки, связанные именно с самим кодом. Цель выполнена - окружение настроено.

В следующей статье дневника попробуем сопоставить отличия в Matter и HomeKit и, заодно, разобраться в Python библиотеках Matter.
Спасибо за внимание!

Это первый опыт написания таких заметок с полей
Пожалуйста, оставьте обратную связь - продолжать или нет писать про внедрение Matter в проект.

Конечно писать 😎 много непонятного, но я по себе знаю, как «вылежавшийся» материал становится актуальным много лет спустя.
Конечно писать, тема сейчас будет очень востребованной, а информация критически важной
я конечно все понимаю
это наверное очень интересно так помучатся
но может быть имеет смысл пойти к первоисточнику и сделать что они говорят ?

Вернуться назад
Вернуться назад