GITLAB CI для ESP32 и Arduino CLI

Я тут подумал, что давно про программирование ничего не писал. А тут и повод появился. Жорик-аннигилятор ведь вовсю обрастает кодом, который, естественно, хранится на домашнем GitLab сервере, но который всё ещё ни тестами не покрыт, ни билдится автоматически.. В общем, всячески игнорирует блага цивилизации.

Тут, конечно, есть некоторая уважительная причина — код пишется же на микроконтроллере, билдится через Arduino IDE, и с точки зрения CI/CD тут не сразу непонятно, с какой стороны ко всему этому подходить. Всё-таки, если тестировать, то.. как? Вводить какой-нибудь hardware abstraction layer? Или вот если автоматически собирать проект на GitLab сервере, то как тогда избавиться от окошек Arduino и делать всё исключительно в консоли? И как вообще спустя 2 месяца после начала проекта вспомнить, что за пакеты я устанавливал и откуда?

С тестами у меня уже какие-то мысли намечаются, но с автоматическими билдами и Continuous Integration вообще у Arduino, оказывается, всё вполне себе хорошо уже сейчас. Всего пара часов гугла и вот оно, работает. Теперь буду делиться впечатлениями.

Секретный рецепт

Если очень кратно, то есть такая штука как arduino-cli, которая, пусть всё ещё и живёт в preview версии, вполне способна заменить своего взрослого оконного собрата. А дальше всё просто: берём гитлаб сервер, у которого настроен хотя бы один gitlab-runner (а иначе кто будет собирать билды?), в проект кладём .gitlab-ci.yml, чтобы runner знал, что именно входит в билд, и изнутри дёргаем arduino-cli.

Так как сам по себе GitLab CI слегка выходит за рамки этого поста, то вот ссылка на мой старый пост про сам GitLab, второй — про docker executors, один из которых будет сегодня использоваться, и мы сразу перейдём к созданию .gitlab-ci.yml файла, настройки build окружения и самому билду. Поехали.

1. .gitlab-ci.yml

Значит, .gitlab-ci.yml будет простым — запросит билд в docker контейнере, установит внутри arduino-cli и библиотеки для проекта, и в качестве единственной стадии сборки скомпилирует проект.

Почему в docker контейнере? Просто я не люблю захламлять живую систему временными и большей частью бесполезными пакетами. А так запустил контейнер, поделал дела, да и выбросил его на помойку.

Запрашиваем билд в docker контейнере

На моём GitLab сервере зарегистрирован всего один gitlab-runner, который, по счастливому совпадению, сконфигурирован как docker-executor, и поэтому любые пришедшие к нему билды он будет запускать прямиком в докер контейнере. Более того, он и помечен тэгом docker, так что для того, чтобы навсегда гарантировать, что мои esp32 билды пойдут именно туда, этот же тэг я буду использовать и в .gitlab-ci.yml файле.

Для docker раннера ещё стоит указать какой именно образ контейнера мы хотим использовать, дабы он не скатился к дефолтному. На сегодня ubuntu:18.04 мне вполне хватит, так что заготовка для .gitlab-ci.yml становится похожей вот на что:

2. Настройка окружения

Устанавливаем arduino-cli

arduino-cli скачивается как обычный архив. Но так как кроме него мне нужно ещё будет настроить поддержку esp32 и установить уйму зависимостей, то стоит сразу завести какой-нибудь setup-build-env.sh файл и складывать всё великолепие в него. Начнём с малого:

Хотите верьте, хотите нет, но этого достаточно, чтобы привнести немного arduino в командную строку. Так как всё богатство запускается в контейнере, то по умолчанию это будет делать root, так что всякие sudo нам бесполезны.

Добавляем поддержку esp32

Теперь нужно заново научить arduino любить esp32. В Arduino IDE я помню ходил в меню board managers, регистрировал какой-то URL и радовался, когда esp32 борды появлялись в списке доступных. Похожий ритуал потребуется и тут, но уже из командной строки:

Всё очень просто: создаём .arduino-cli.yaml файл (произвольное имя, никакого скрытого смысла), записываем в него урл от esp32 настроек и устанавливаем, собственно, его поддержку. Чтобы узнать, что core install должен устанавливать именно esp32:esp32, я сначала запускал что-то вроде arduino-cli core search esp32 --config-file /root/.arduino-cli.yaml.

Теперь можно, например, вызывать arduino-cli board listall и подсмотреть полное имя своей esp32 платы. В будущем оно очень понадобится для компиляции. В моём случае это был ESP32 Dev Board с идентификатором esp32:esp32:esp32.

Устанавливаем стандартные пакеты

За время своей короткой жизни Жорик-Аннигилятор успел обзавестить уймой зависимостей — для bmp280 сенсора, для аккселерометра, для асинхронного веб-сервера, и т.п. Я уже успел позабыть, что до этого устанавливал, но на то она и continuous integration, чтобы ронять компиляцию до тех пор, пока не вспомнишь. Я нашёл пять стандартных пакетов, без который мой проект уже не собрать, и заботливо переустановил их через тот же arduino-cli:

Устанавливаем нестандартные пакеты

Кроме стандартных пакетов была ещё и стопка нестандартных, клонированных с гитхаба и сложенных в папке libraries Arduino. Тот же трюк можно повторить и здесь. Главное, найти, где именно arduino-cli хранит свои библиотеки.

К счастью, это можно сделать через тот же arduino-cli, команду config dump.

Итак:

Добавляем python и pyserial

У esp32 есть ещё 2 зависимости, о которых нечасто говорят вслух — python и pyserial, без которых проект, в общем, тоже не собрать. Всё это тоже вспоминаем кидаем в конфиг:

Всё вместе

Собрав все куски кода вместе в create-build-env.sh файл…

…и попросив .gitlab-ci.yml запустить его перед билдом…

… мы получим вполне полноценный CI, которому не хватает лишь самой команды компиляции. Конечно, установка всего и вся для каждого билда просто трындец как неэффективна и по-хорошему setup-build-env.sh нужно было «впаять» прямо в контейнер. Но для начала сойдёт и так.

3. Собственно, шаг компиляции

Дальше всё вполне примитивно. После запуска команды arduino-cli board listall я выяснил, что «официальное» имя моей esp32 платы esp32:esp32:esp32. Файл проекта называется robot.ino, поэтому, сложив слово compile с двумя словами выше, получится вот такая строка:

Из-за того, что preview версия arduino-cli умудряется напортачить с дефолтным именем прошивки, пришлось явно указать, как назвать бинарник на выходе — -o ignored.bin. И это всё!

Гранд-финал

Вот так теперь выглядит финальный .gitlab-ci.yml файл:

Добавив его в проект и впервые запушив на сервер, получится вот такая неземная красота:

Мораль

В общем, делать continuous integration для esp32 и arduino проектов вполне себе можно. То, что у меня получилось, не особо образец для подражания — что-то можно оптимизировать, всё ещё не хватает тестов, но всё-таки это реально работает и по очкам ведёт у «нет CI вообще»! И теперь по крайней мере конфигурация зависимостей ясно прописана в коде, а не просто как-то работает на отдельно взятом лаптопе. В общем, со всех сторон вин.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *