Как стать автором
Обновить

Проект Смотритель — удаленно управляемый робот на ESP32-CAM

Уровень сложностиСредний
Время на прочтение17 мин
Количество просмотров15K

Разрабатываем робота с нуля - от ИИ-дизайна до полного проектирования и реализации всех компонентов устройства.

Зачем? Ради фана, конечно - этот проект практически квинтессенция моих увлечений - электроника, 3d-печать, программирование микроконтроллеров, ИИ и в целом все, что можно включить в сферу DIY.

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

Тогда

Задумал я проект, страшно сказать, 10 лет назад. У меня уже был репозиторий на github с описанием хотелок и даже некоторой реализацией. Кажется, это даже был мой первый репозиторий, который я без знаний git вел через сайт.

101-arduino

Построено все было на Arduino Uno и платформе DFRobot iRover 5, подключенной к драйверу двигателя с 2 УЗ-дальномерами, без камеры. Реализовать задуманное полностью не было ни сил, ни средств, поэтому проект был отложен на неопределенный срок.

Сейчас

За минувшие 10 лет изменилось многое: появилась куча возможностей, новых устройств. Появился 3д принтер (даже 3), освоена печать различными материалами, опыт программирования, умный дом и вот это вот все.

Поэтому новый план на проект выглядит следующим образом:

  • esp32 cam в качестве контроллера и стриминга видео;

  • своя прошивка с управлением по wifi и BT с передачей видео, фонариком, двумя вариантами управления, симпатичной адаптивной версткой и переключением качества видео;

  • свой дизайн устройства с ИИ (и дизайном вовлечение ИИ не ограничилось);

  • свое разработанное шасси - 2WD, возможно 4WD (технически можно хоть 6WD подключить, но смысла не имеет);

  • полностью 3д-печатный корпус и гусеницы из TPU;

  • зарядная станция, на которую можно приехать и встать удаленно;

  • плагин для подключения к home assistant.

Статья получилась объемной, оглавление не помешает:

  1. Дизайн

  2. Шасси и корпус

  3. Компоненты

  4. Электроника

  5. Зарядная станция

  6. Софт

  7. Интеграция с Home Assistant

  8. Заключение

Дизайн

Идею создания некоего устройства я вынашивал давно, требований было немного - камера впереди, гусеницы, wifi антенна и интересный дизайн (минимализм, футуризм, киберпанк, etc).

От дизайна, а тем более промышленного, я далек, в этом качестве на помощь были приглашены нейросетевые модели. GPT-4o генерировал вариативные промпты по моим требованиям, локально развернутый forge с flux1.dev на борту по каждому промпту генерировал 10 картинок (на 3060 Ti 8Gb 1 генерация занимает ~1 минуту).

По ходу дела и отсмотра результатов корректировались требования, но в конечном итоге было получено и использовано 150 промптов (соответственно, сгенерировано 1500 изображений). Вот пример случайных 100 изображений из всех:

205-collage

Если интересно - можно ознакомиться с диалогом в ChatGpt. Все промпты, часть генераций и фото 10 финалистов можно найти в проекте на github, а я остановился на этом:

208-favorite-design

Какой-то он харизматичный, надеюсь, под его надзором все будут вести себя порядочно.

Шасси и корпус

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

А теперь мы будем изобретать колесо.

В качестве двигателей для небольших устройств выбор как будто не очень большой. Есть моторчики без редукторов, для которых ещё нужно его собрать - такие стоят в iRover 5. Есть с редуктором различных форматов, но с пластиковыми шестернями и выходными валами:

000-motors

Ну и моторчик с полностью металлическим редуктором - GA-12-N-20, есть различные варианты по передаточным числам. Так как металлический редуктор внушает больше доверия - остановимся на таком варианте. По картинкам даже с размерами сложно было осознать, насколько он окажется маленьким:

305-ga12-n-20

Обычно в гусеничных шасси двигатели стоят внутри корпуса, а ролики вращаются на их осях. Но я не придумал ни как избавиться от бокового перекоса ролика при натяжении (в Rover 5 таковой присутствует) ни как удлинить ось.

Зато прикинул, что моторчик с осью и редуктором в длину соответствует планируемой ширине траков. Почему бы не сделать колесо вокруг моторчика?

Изначально я заказал подшипники минимального размера, внутрь которых бы помещался моторчик - 6802 (15x24x5мм). Но не учёл, что редуктор выступает за габариты моторчика и внутрь не поместился. Поэтому компоновка могла быть только такой:

306-wheel-6802

Этот вариант не очень подходил под мои критерии надёжности, хотя и был теоретически работоспособным. Поэтому подшипники были заменены на следующие по размеру - 6803 (17х26х5мм), а эти составлены для колёс без двигателей.

Еще несколько итераций ушло на подгон зазоров для сборки и на усовершенствование внешней части колеса. Конечная схема приняла следующий вид:

300-main

Моторчик GA12-N-20, 2 подшипника 6803 (17х26х5мм) и 3 детали, распечатанные на FDM принтере (не считая кронштейн крепления к корпусу). Все держится на безлюфтовой посадке, канавки по внешнему периметру диска - одновременно для удержания гусениц и для удержания половинок колеса гусеницей.

Колесо при сборке выглядит так:

000-wheel

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

Гусеницы

Шасси у нас уже есть, нужный периметр гусеницы известен, внутренний профиль определяется колёсами, внешний - дизайном.

Гусеница получилась следующего вида:

406-track-size

Здесь есть несколько моментов, на которые нужно обратить внимание:

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

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

  3. Так как мы печатаем круглую гусеницу, а колеса у нас меньшего диаметра - нужно предусмотреть возможность гусенице беспрепятственно сгибаться до нужного радиуса. Для этого посчитаны и учтены "разрывы" во внутреннем профиле гусениц.

Изначально сделал толщину в 3мм - но напечатанное изделие оказалась избыточным даже для меня, моторчики такую гусеницу крутили с трудом и рывками. В финальном варианте толщина уже 1.2мм (3 периметра при печати соплом 0.4). Печатал тоже на FDM принтере пластиком Bestfilament TPU Soft.

3мм и 1.2мм гусеницы для сравнения:

420-track-3mm-photo

По гибкости и прочности все более чем ок, пруток 1.75мм руками разорвать у меня не вышло, гусеница отлично подходит.

Единственное, где ожидания не были оправданы - зацеп. Поверхность по ощущениям где-то между пластиком и резиной, при перемещении без препятствий все ок, но может проскальзывать при упоре в препятствие - на стену уже не заехать.

Пока не было корпуса сделал плоскую платформу, на которой и проводил эксперименты с гусеницами, здесь оба варианта гусениц для сравнения:

424-track-1mm

Корпус

Моделирование тоже является одной из сфер, которые мне интересны, но в отличие от многих остальных - практики здесь очень мало. Поэтому на помощь здесь еще раз приходит генеративный ИИ.

Берем выбранную картинку, находим первый попавшийся AI img2model генератор (meshy) и наслаждаемся:

000-meshy-fox

Ожидание / реальность, как говорится. На самом деле не все так плохо, давайте возьмем генератор получше - таких несколько, мне больше всех понравился результат от tripo3d (ссылка на модель):

218-tripo3d

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

503-model-grid

Но гусеницы и шасси у нас уже есть, а даже эта кривая сетка модели вполне подходит как основа для ретопологии. Ставим блендер, читаем пару вводных уроков по ретопу и пару вечеров обрисовываем модель, на выходе имеем уже нечто более похожее на реальность (сетка местами все еще ужасна, если это видят 3д-художники - не бейте сильно):

508-retop-4

Дальше в блендере можно накинуть модификатор сглаживания сетки (можно применить несколько раз для лучшего результата), и для сравнения 2 модели - где ретоп, а где генеративная думаю понятно:

511-retop-compare

Экспортируем в stl, загружаем в Fusion 360, и долго мучаемся с подгонкой корпуса к шасси, компоновкой всех деталей внутри корпуса, проектируем все необходимые разъемы, углубления, вырезы и вот это все - пришлось повозиться.

В результате имеем подготовленные к печати модели базы и крышки:

519-top
520-bottom

Формы, как ни крути, получились достаточно замысловатыми, проба печати на FDM принтере вышла весьма грубой:

526-fdm-print

Помимо ступенек, с которыми что-то можно было придумать (уменьшить высоту слоя с черновых 0.28, например), были еще и проблемы с отделением поддержек и точностью форм.

По этим причинам я решился попробовать распечатать корпус на фотополимерном принтере (SLA). Сомнения были из-за характеристик напечатанных на SLA деталей - корпус должен выдерживать какие-никакие нагрузки, а детали, напечатанные на фотополимерном принтере обычно довольно хрупкие.

Также я был уверен, что смола даёт большую усадку, причём неравномерную, и опасался проблем с подгонкой. Но вопреки всему тестовая печать калибровочного куба показала отсутствие какой бы то ни было усадки и корпус был напечатан фотополимерником:

528-bottom-sla

Все детали шасси я тоже перепечатал, но на FDM - решил что это проще и быстрее чем красить зеленый пластик в черный цвет (мы же ориентируемся на ИИ-дизайн).

Крышка в длину не поместилась на столе, так что пришлось повернуть, вот так оно печаталось (что-то вроде 8 часов):

527-sla-top

При этом с первой попытки мне не хватило смолы и получился такой терминатор, что поначалу даже хотел его оставить:

529-sla-terminator

Но потом все же перепечатал, а эту оставил на эксперименты. Печатал смолой ABS-Like Resin Pro 2 от Anycubuc, результат удивил прочностью (возможно, из-за толщины, хрупкая художественная печать обычно содержит тонкие элементы).

Про качество говорить не приходится - фотополимерная печать даёт практически финальное качество поверхности под покраску:

535-model-assembled

Компоненты

Не думаю, что здесь получится кого-то удивить, максимально использую готовые модули, полный список деталей таков:

  • Esp32cam - основной мозг - можно ещё найти под названием AI thinker.

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

  • Wifi антенна с коннектором - часто идёт в комплекте с платой.

  • 3 Li-Ion батареи, соединенные последовательно (3s, 12.6v) с держателями.

  • 2 dc-dc понижающих преобразователя (на 12v и на 5v).

  • Драйвер двигателя 2-канальный - L298N, L293D или аналог - у меня L293D из-за меньших габаритов платы, хотя моделировал под L298N.

  • 2 моторчика GA12-N20 с передаточным числом 150 (можно брать 200 - будет резвее). Конструкция шасси позволяет использовать до 6 моторчиков.

  • 12 подшипников 6803 (по два на колесо).

  • BMS плата зарядки для 3s сборок (если планируете заряжать в устройстве).

  • Mosfet IRLML0030 + 1 кОм резистор для управления светодиодами.

  • Переключатель для подачи питания с батареи.

  • Светодиоды и резисторы - по вкусу. У меня в зрачках мощные 8mm белые светодиоды, для подсветки "радужки" - обычные 5mm.

Размещение компонентов внутри корпуса тоже прикидывал в Fusion 360 (и изначально подгонял масштаб модели под их размещение). Отдельное спасибо всем тем людям, которые отрисовывают модели для готовых компонентов и выкладывают в сеть (почти все нашлось на grabcad). Внутри все размещается как-то так:

components

Электроника

Принципиальная схема устройства:

555-scheme

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

Важно, что для использования внешней антенны на плате esp32 нужно запаять соответствующую перемычку, плата по умолчанию работает только со встроенной (на изображении нулевой резистор):

esp32-wifi

Изготовление платы

Esp32-cam поставляется с уже запаянной гребенкой и отладочной платой для подключения и прошивки по usb, припаиваться напрямую к плате не хотелось, а соединительные провода занимают кучу места.

Поэтому для коммутации была изготовлена своя плата (ну и mosfet с резистором размещен здесь же). Ранее делал пару плат ЛУТом, но раз мы тут осваиваем новые технологии - решил попробовать фоторезист.

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

В любом случае нам нужно подготовить шаблоны платы (слои меди, шелкографии и паяльной маски). Фоторезист и маска негативне, поэтому и шаблоны соответствующие (засвечиваться будут чёрные участки):

000-board-svg

Дальше нам нужно как-то преобразовать эти svg в формат, понятный принтеру. Мой Photon Mono X6Ks не понимает ничего кроме своего собственного формата, поэтому нужно сделать stl модель. На просторах сети есть множество различных способов с кучей софта (фотошоп, различные CAD, UVTools и вот это все) - даже инструкции выглядят достаточно громоздко.

Но у нас же тут бум ИИ, а задача выдавливания SVG в STL кажется достаточно тривиальной - напишем свою реализацию. Несколько попыток ушло на то, чтобы заставить все это работать приемлемо, в конечном итоге получилась утилита svg2stl (написана Sonnet 3.7

в Cursor). Указывается физический размер пикселя, для моего фотополимерника он составляет 0,034мм, модель с таким разрешением выглядит так (дорожки 0.5мм):

566-stl

Для позиционирования платы соорудил нечто из пленки от "файла" для документов и прямоугольных пластин, оставшихся от тестирования принтера. Размещал ничего не вымеряя, на глаз по картинке с принтера (это ультрафиолет, смотреть только через очки или камеру):

570-photon-stand

Засвечивал 20 секунд, дальше все более-менее стандартно: кальцинированая сода для проявки, лимонная кислота с перекисью для отравления, раствор щелочи для смывки фоторезиста и плата получилась даже с дорожкой между пятаками в 0.3мм (3 подхода и 7 образцов ушло на понимание техпроцесса):

580-board-cu

Паяльную маску нанес и засветил по такой же схеме. Процесс оказался настолько прост, что я решил и шелкографию сделать паяльной маской (изначально задумавался о ЛУТ). Приведу только фото платы с нанесенной шелкографией в импровизированном солярии (самодельный бокс для УФ-засветки), потому что красивое:

584-board-silk-solar

Компоновка всего этого железа в корпусе следующая:

601-assembled

Если немного раскидать, чтобы были видны основные компоненты:

602-disassembled

Зарядная станция

Раз уж одна из целей - удалённое управление - стоит озаботиться и вопросом питания.

Батарею расширять некуда - размеры и так минимально возможные. Значит, нужна зарядка, да такая, чтобы на неё можно было встать по видеосвязи. Также нужна индикация процесса заряда и некая контактная пара. Что-то подобное зарядным станциям роботов пылесосов, но из доступных материалов.

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

Руководствуясь все той же избыточной надёжностью были приобретены медный пруток 5мм и пластины 20х20х1.5мм. Под них и был спроектирован корпус зарядной станции:

внешний вид без пластин

В качестве источника энергии взял внешний блок питания для 3S батарей, подходящее гнездо для разъёма которого по счастливой случайности у меня нашлось в закромах. Детали получилось подогнать достаточно плотно, но без закусываний. Пластины на 1 пружине в углу со стороны стержня работают идеально:

805-springs

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

Финальный вид изделия таков:

809-charger-cad
815-charger-ready

Ну и робот, стоящий на зарядке. Фокусное расстояние камеры не позволяет видеть все чётко, но для индикации такого вида достаточно.

820-robot-charging

Картинка в трансляции выглядит так (от разрешения не сильно зависит из-за фокуса, но здесь оно низкое):

840-stream

Что касается схемы зарядки самого робота - внутри стоит ещё 3S BMS плата, контролирующая заряд и обеспечивающая поддержание одинакового напряжения на банках. Можно было бы обойтись и без неё, многие заряжают 3s сборки напрямую, но я предпочитаю более безопасный вариант.

850-bms

Из-за избыточной упругости пружин поставить робота на зарядку дело нетривиальное - он отпружинивает и остается без контакта, нужно ловить нужное положение. Думаю, схема на магнитах была бы легче в использовании. До её реализации я не добрался, возможно, зарядную станцию будет ждать апгрейд.

Софт

Esp32cam - довольно популярный контроллер. Управляемые по wifi девайсы с камерой - также очень популярны. Но несмотря на все это мне не удалось найти сколь угодно пригодной прошивки - чтобы и управление устройством было удобным и работа с камерой и симпатичный дизайн.

Отдельно интерфейс для камеры с кучей настроек - пожалуйста, но самое близкое, что я нашел для дистанционного управления, выглядело вот так:

701-popular-ui

Причем этот или похожий интерфейс встречается почти во всех даже самых популярных видео и инструкциях.

Железо у нас не ограничено 2 двигателями, поэтому и интерфейс будем делать свой. Что в нем будет:

  • настройка разрешения и качества видео, старт и остановка стрима;

  • 2 режима управления - джойстик и слайдеры (как в танке или тракторе - 2 рычага, отвечающие за левый и правый мотор);

  • активация подключения к Bluetooth пульту с выводом состояния;

  • управление яркостью светодиодов (яркие led в глазах);

  • отображение значения FPS при трансляции;

  • адаптивная верстка и полноэкранный режим.

Прошивку я написал в Cursor c Sonnet 3.7, про процесс писать смысла не вижу, весь хабр последнее время завален статьями на тему вайб-кодинга. Скажу лишь, что с Си и программированием под esp32 у ИИ много больше проблем, чем с более популярными языками (python, js, php, etc). Без самостоятельного погружения в тему никак.

Результат получился таковым, окно настроек и режим управления джойстиком:

705-joystick

Режим управления слайдером:

706-sliders

Опишу наиболее интересные технические аспекты прошивки, рожденные коллективным бессознательным.

Разработано под Platformio с Arduino framework и с использованием FreeRTOS (инструкцию по включению функций сбора статистики я описывал в прошлой статье именно в рамках этого проекта). Т.е. все задачи (BT, стриминг, http, управление двигателями, лог загрузки) разделены на FreeRTOS задачи и распределены по ядрам (esp32 - двухядерный).

Весь UI написан в одном html файле, который при прошивке транслируется в Си, при этом сжимаясь в gzip - экономим память, ресурсы и время загрузки страницы. Фокус с gzip подсмотрел на гитхаб, но к трансляции в Си пришел сам - при использовании SPIFFS для хранения ресурсов есть дополнительные сложности в виде необходимости отдельной прошивки этих ресурсов и сложностей с OTA (прошивка по воздуху - пока не реализована). Да и наш объем html настолько мал, что не стоит отдельного хранения.

Мой BT-джойстик - это аппаратура Radiomaster TX12 (v1) с модулем ELRS, который научился прикидываться BT-джойстиком после обновления прошивки внешнего модуля - изначально хотел реализовать связь по ELSR с rx-приемником, но пока остановился на BT.

910-app

С форматом и структурой передачи данных через Bluetooth я особо не разбирался ввиду отсутствия времени и желания тратить на это время - силами ИИ по логам были определены байты из пакета, которые отвечают за X и Y левого и правого джойстика - они и были использованы для управления в тех же режимах, как в веб-интерфейсе. Если решите подключить свой джойстик - помимо изменения названия устройства в конфиге наверняка придется менять и обработку BT-пакетов.

С управлением слайдерами все прозрачно - каждый устанавливает значение двигателя в диапазоне [-1; 1]. А вот с джойстиком такая логика управления оказалась неочевидна. Поэтому мой джойстик работает так (только эту схему я делал, пожалуй, час):

707-joystick-work

Несмотря на то, что визуально джойстик круглый, зона управления - квадрат (также и на аппаратуре, кстати). Управление линейное, левый верхний угол - [1;0] (левый двигатель максимально вперед, правый стоит), средняя точка наверху - [1;1] (полный вперед), остальные по аналогии.

Есть и зоны разворота - два небольших сектора слева и справа по центру - в этих зонах двигатели вращаются в противоположные стороны так, чтобы устройство поворачивало на месте влево или вправо соответственно (тоже линейно, в крайних положениях на максимальной мощности). Центр джойстика при этом - мертвая зона. Вся эта логика реализована на стороне контроллера (пороги конфигурируются), фронтенд передает только "координаты".

MJPEG стриминг, управляющие сигналы, запрос статуса BT, смена качества картинки - все реализовано HTTP-запросами. Так как esp32 не супер производительный http-сервер, положение стиков передается при изменении с ограничением в ~200мс (т.е. при непрерывном изменении положения обновление будет улетать каждые 200 мс), при сбросе положения в 0 задержки нет.

Немного об упомянутой проблеме с изначальной схемой: я планировал замерять напряжение батареи через аналоговый вход esp32-cam - для чего на схеме изображен делитель напряжения. Увы, ADC2 контроллера задействуется при работе WiFi, причем на нем работают абсолютно все аналоговые входы, выведенные на гребенку esp32-cam. Решения, кроме установки отдельного чипа с подключением по SPI/UART, я пока не нашел - поэтому и измерения и вывода в интерфейс уровня заряда нет (что обидно - я сначала реальзовал это полностью в прошивке, включая интерфейс, и только после в логах увидел ошибку, что ADC2 уже занят WiFi соединением).

все аналоговые пины платы задействуют ADC2

Из нюансов, которые могу отметить - скорость передачи видео (FPS) очень сильно зависит от качества сигнала wifi. Разведенная на плате антенна при этом работает, но на удалении от точки доступа работает достаточно посредственно, у меня качество плавало в зависимости от времени работы стрима (причем чем дольше стрим и горячее плата - тем лучше передача) и от наличия рядом объектов, усиливающих или блокирующих сигнал (условно, при касании рукой платы сигнал становился четким). При подключении внешней антенны эти проблемы частично ушли - не забывайте только запаять перемычку на плате для переключения на внешнюю антенну.

По итогу получилось весьма удобное управление как из браузера мышкой, так и со смартфона и физического джойстика.

Интеграция с Home Assistant

Проект в том числе позиционируется как удаленный мониторинг, но как его сделать, если устройство доступно только из внутренней сети? Вариант в лоб - пробросить доступ к устройству вовне (роутер и белый IP, туннель на сервер, сторонний сервис), но придется самостоятельно решать вопросы с безопасностью. Устройства умного дома, а тем более DIY устройства редко с этим заморачиваются, а зря.

Мы пойдем по пути встраивания устройства в существующую экосистему - у меня есть Home Assistant с публичным доступом (через свой VPS) - на него перекинем вопросы с безопасностью, нужно только реализовать интеграцию.

Казалось бы - у нас уже есть готовый html интерфейс робота с http-запросами, есть куча передовых ИИ, которые могут делать что угодно - интеграция даже без глубоких знаний python и home assistant не должна доставить проблем?

1000-mem

Прокси

Изначально я пошел по пути проксирования web-интерфейса робота в интерфейс Home Assistant. В результате совместной разработки получилась интеграция с следующими возможностями:

  • добавление и установка через HACS (пользовательский репозиторий);

  • для добавления интеграции нужно указать IP-адрес робота во внутренней сети;

  • добавляется lovelace-карточка (ui Home Assistant), которая показывает статус робота (в сети или нет) и кнопку открытия интерфейса;

  • в iframe открывается стандартный web-интерфейс робота, все запросы заворачиваются в самописный прокси.

Из интересного по реализации - сам прокси, который добавляет свой js-код при открытии оригинальной страницы в iframe, чтобы переопределить все url, к которым осуществляются запросы. Чем-то похоже на встраивание рекламы в незащищенный http трафик некоторыми мобильными операторами.

И все бы ничего, но мне так и не удалось ни пробросить механизм аутентификации Home Assistant через iframe, ни использовать long-lived токен (документация умалчивает как его можно проверять, все найденные варианты оказались недоступны в актуальной версии, да и светить его небезопасно) или короткоживущий authSig в контексте прокси (подписанный токен уникален для каждого url, этот вариант не очень подходит для iframe, который сам к себе делает кучу запросов).

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

Все по новой

Из уже работающего решения пришлось выкинуть почти все, что было написано, кроме проверки статуса, и реализовать свой интерфейс в Home Assistant, который без iframe взаимодействует с сервером. Такую интеграцию можно считать нативной, используется штатный механизм аутентификации, т.к. без iframe браузер прокидывает в запросы заголовки авторизации (если запросы посылать не обычным fetch, а через api hass).

Но авторизация через заголовки работает не везде - использовать в img.src для стрима такую ссылку не выйдет, на этот случай у hass есть механизм подписанных ссылок. Т.е. вы через websockets получаете подписанную короткоживущую ссылку (добавляется параметр authSig) и подставляете в контейнер для стриминга видео - подпись проверяется 1 раз при получении запроса и дальше стрим может жить вечно. После использования ссылки подпись инвалидируется, так что ссылка получается одноразовой и её перехват ничего не даст. Штатные компоненты трансляции видео с камер работают по этой же схеме.

Актуальная версия интеграции умеет не все - нет работы с BT, нет переключения режима между джойстиком и слайдером и нет отдельного включения отображения FPS - он отображается всегда.

Минималистичная карточка в дашборде
Минималистичная карточка в дашборде
Нативной диалоговое окно
Нативное диалоговое окно

Еще в копилку неочевидных решений hass - чтобы добавить лого для своей кастомной интеграции - нужно отправить PR в специально созданный для этого отдельный репозиторий brands. Поэтому моя интеграция пока иконкой не обзавелась, хотя она даже отрисована - впоследствии добавлю.

Заключение

Финальный вид после покраски с включенными на 1% светодиодами в глазах:

fin

Проект занял 3 месяца почти всего моего свободного времени и не случился бы (как минимум так скоро) без Хабра. Лучший мотиватор для меня - дедлайн. Спасибо Технотексту-7, в котором я решил принять участие и который меня дедлайном обеспечил.

Статья достаточно объемная, но если вдруг какие-то разделы показались вам похожими на инструкцию по рисованию совы - еще более развернуто (по суммарному объему контента в ~2 раза) об этапах можете почитать в моем блоге на сайте (не тг) - не все опубликовано, выйдет еще ~5 отдельных статей.

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

Ссылки

Проект - полностью opensource, всё что реализовано можно скачать и использовать:

  • модели для печати (stp, stl, f3z архив Fusion 360) - models/ или проект на thingiverse.

  • схема и чертежи платы (KiCad) - board/;

  • прошивка для esp32cam с web-интерфейсом - esp32-caretaker;

  • интеграция с Home Assistant - hass-caretaker;

  • утилита для конвертации svg в stl для засветки фоторезиста на фотополимерном принтере - svg2stl.

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

Для тех, кто соблюдает ограничения - видео залито на яндекс диск.

P.S. Если нашли лису - лайк за внимательность.

Теги:
Хабы:
+90
Комментарии24

Публикации

Истории

Ближайшие события

19 марта – 28 апреля
Экспедиция «Рэйдикс»
Нижний НовгородЕкатеринбургНовосибирскВладивостокИжевскКазаньТюменьУфаИркутскЧелябинскСамараХабаровскКрасноярскОмск
24 апреля
VK Go Meetup 2025
Санкт-ПетербургОнлайн
25 – 26 апреля
IT-конференция Merge Tatarstan 2025
Казань
14 мая
LinkMeetup
Москва
5 июня
Конференция TechRec AI&HR 2025
МоскваОнлайн
20 – 22 июня
Летняя айти-тусовка Summer Merge
Ульяновская область