Шесть баков, несколько расписаний

На участке стоит шесть баков: один для обычного мусора, один для пищевых отходов, один для садового компоста, два для переработки и один для стекла. Каждый вывозят по собственному расписанию. Интеграция Waste Collection Schedule для Home Assistant автоматически парсит расписание муниципалитета, что здорово облегчает жизнь.

С дешёвыми Bluetooth-тегами обычно используется RSSI (received signal strength indication) — меру мощности сигнала — для оценки расстояния. Но это очень неточно: сила сигнала зависит от стен, припаркованных машин, отражений, ориентации антенны и даже напряжения батареи в приёмопередатчике. Более слабый сигнал может означать, что бак отошёл дальше, а может просто что-то встало на пути. Это объясняло, почему старая система была настолько фрустрирующей.

Ultra-wideband интересен тем, что измеряет время прохождения сигнала между устройствами. Это даёт точное измерение расстояния без нужды угадывать его по мощности. Конечно, сигналу всё ещё нужно пройти сквозь препятствия, но припаркованные машины это не устранит.

Какое-то время размышлял о более сложных вариантах: сколько якорей понадобится, чтобы определить не только расстояние, но и направление? Или даже точное положение бака на участке? Сколько опорных точек нужно для триангуляции? Для текущей задачи это точно не стоит затрат, но мозг думает, что думает.

Для баков достаточно было просто знать, выехал ли бак из зоны хранения или остаётся на месте. Одного якоря хватило бы для начального тестирования. Установил границу в десять метров: всё ближе — бак дома, дальше — вывезен. Это очень специфично для моего участка, но позволило начать с одной планшетки вместо того, чтобы превращать весь двор в тестовый полигон.

Две платы и прогулка по участку

Первый эксперимент использовал два модуля Makerfabs ESP32-WROVER/DW3000, оба питались от USB. Перед интеграцией с Home Assistant хотелось просто увидеть, как они друг друга видят. Локальный веб-интерфейс позволял разводить платы на расстояние и наблюдать результат без кабеля USB между ними.

Красная плата Makerfabs ESP32-WROVER с подключённым USB, видны UWB-модуль и антенна.

Одна из тестовых плат. Модель DW3000, использованная в экспериментах. Справочник по железу.

Ориентация антенны оказала на результаты больший эффект, чем ожидалось. На расстоянии примерно десять метров разворот плат из горизонтального положения в вертикальное поднял успешность приёма с 37% до 100% в том тесте. Более медленная скорость передачи с более длинной преамбулой тоже помогала там, где изначально быстрая настройка терпела неудачу. Это были полезные находки до того, как начинать проектировать что-либо на основе первых результатов.

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

В записанном позже тесте на измеренное расстояние 10,1 метра радиомодули выдали среднее значение 10,09 метра со стандартным отклонением три сантиметра. Это обнадёживало для проекта, которому нужно только различать, остаётся ли бак в зоне хранения или уехал. Результат менее двух сантиметров был тем, что видел в первой калибровке, а не гарантией такой точности для каждого тега, ориентации или положения на участке.

Прогулка по участку оказалась более информативной. Чтения были надёжны примерно до тридцати метров, дальше начинались перебои. Максимально записанное расстояние было 37,28 метра, но с промежутками. Припаркованная машина могла полностью заблокировать сигнал. Горизонтальная плата в открытом поле и крошечный тег под ободом бака — это совсем разные сценарии.

График UWB-теста с прогулкой: измеренное расстояние растёт и падает, ниже показаны диагностика сигнала и разброса дальности.

Тест с двумя платами на прогулке. Дал хорошую отправную точку; не гарантирует покрытие для установленных баков. Записанные результаты.

Якорь публикует измерения через MQTT, Home Assistant обнаруживает отдельное устройство для каждого тега. Рассматривал компонент ESPHome, но это не добавило бы много к желаемой архитектуре. Нет отдельного сервера BinRange или облачного сервиса, радиомодули могут продолжать измерять, даже если Home Assistant или соединение MQTT недоступны.

Что-то маленькое, чтобы прилепить на бак

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

Изучал варианты самодельных и коммерческих тегов. Ключевой вопрос: смогу ли я запустить собственную прошивку и использовать их с моим якорем. Маленький UWB-тег не автоматически совместим с другим UWB-устройством. В итоге купил теги KKM K4W с процессором nRF52833, радиочастотным модулем DW3110 и акселерометром LIS3DH. Они работают на сменных батарейках CR2477 (на слово, это здоровенные монетные элементы! Раньше я таких не видел).

Две платы Makerfabs обошлись в US$123,64 с доставкой. Десять тегов для тестирования по US$25 каждый, программатор и доставка — ещё US$330. Это то, что потратил на эксперимент в то время, а не текущий список покупок или цена готового набора на шесть баков. Вычисляю ли период окупаемости — лучше не буду.

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

nRF52 мне хорошо знаком, работал с ними годами со времён rlab. Это отличные маломощные микроконтроллеры, которые большую часть времени спят. Если умно управлять расписанием и прерываниями, эти штуки могут работать годами на маленькой батарейке в правильном приложении. Это было намного интереснее, чем то, что делала штатная прошивка.

Свободный девайс Nesso использовал как программатор для пого-контактного разъёма. Начал с одного тега, потом подготовил остальные по очереди: прошил, установил личность, спарил, наклеил этикетку, назначил баку, собрал обратно. Было несколько идентификаторов: этикетка, chip ID, радиоадреса.

Кстати, корпуса тегов идут с уникальными серийными номерами и QR-кодами. Видимо, это нужно для штатного ПО поставщика, но я не нашёл связи с MAC-адресами устройства или другими идентификаторами. По сути, они мне не пригодились. Жаль — если бы это были радиоадреса MAC, например, это было бы полезно!

Тег KKM K4W, закреплённый под ободом зелёного мусорного бака, этикетка не видна.

Тег KKM K4W, прикреплённый к ведру компоста рядом с его ручкой, этикетка не видна.

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

Производитель подключил выход прерывания акселерометра к GPIO процессора nRF, что невероятно полезно. Это позволяет держать nRF в спящем состоянии очень долго, не отправлять никакие сигналы, и пробуждаться только при физическом событии. Когда всё успокаивается, переходит на редкие проверки, UWB-модуль спит между попытками. По умолчанию десять минут при неподвижности; потом изменил установленный флот на тридцать минут через управление в Home Assistant, оставив пятисекундные отчёты при движении.

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

Обновление шести баков без разборки

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

Тестирование и итерация в таких ситуациях — ещё один отличный случай использования AI. Codex помог сгенерировать и смоделировать множество условий тестирования и режимов сбоя, потом разобраться с ними, чтобы развертывание прошивки через воздух было максимально безопасным. Тестировал испорченные образы, прерванные передачи, различные точки потери питания и восстановление watchdog. Также проверил, что происходит при отсутствии якоря: тег должен подтвердить собственное здоровье без ответа по радио, а не забросить рабочую прошивку, потому что не может достучаться до якоря.

Переход от одного тега к нескольким выявил другой сорт проблемы. Запись в библиотеке Bluetooth была размером под одновременные соединения, а не под количество спарённых устройств. Добавление ещё одного тега могло не сработать, даже если его ключи уже сохранены. Исправление позволило новому тегу спариваться без очистки существующих. Шесть баков дали ПО гораздо лучший тест, чем один кооперативный тег на демо.

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

Корпус потребовал несколько попыток

Якорю нужен был чехол, что стало собственным проектом. Начал с OpenSCAD-дизайна с винтами. Первая проверка посадки выглядела обнадёживающе, но маленькие гайки, болты, допуски PLA и подвижная плата сделали сборку раздражительнее, чем хотелось.

Хотелось полностью напечатанный PLA-корпус без винтов: конические локализирующие штифты для платы, напечатанные пружины, чтобы держать её, и крышку, которая не падает. Штифты и пружины сработали. Крышка ездила туда-сюда.

Внутренний бортик улучшил посадку. Более глубокие защёлки улучшили удержание, но крышку всё ещё было легко снять. Сделать эти защёлки такими же глубокими, как стенка — казалось очевидным следующим шагом, пока обе ножки не сломались при вставке. Эта версия отлично получилась в виде двух кусков сломанного пластика.

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

Рендер собранного безвинтового корпуса якоря: синее основание и светлая крышка с вентиляцией.

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

Безвинтовой корпус, отрендеред из его печатных сеток. Цвета и финиш — иллюстративные. Можно напечатать из MakerWorld; файлы дизайна и история менее удачных попыток на GitHub.

Быстрой итерацией с Codex корпус был особенно приятен: мог доработать дизайн, проверить его, напечатать. Но всё равно нужно было взять результат и узнать, не упадёт ли крышка. Геометрическая проверка может установить, что две фигуры должны подогнаться; она не скажет, выживет ли защёлка при вдавливании на место.

Якорь теперь настенный, напечатанный корпус внутри большей коробки для уличной электрики рядом с компонентами питания. Это потребовало ещё один заказ Amazon. Релевантные детали:

  • Уличная коробка для электрики с прозрачной крышкой, заявлена как IP67, 8.7 × 6.7 × 4.3 дюйма (£27.99).
  • DIN-монтируемый блок питания 12V DC (£11.09).
  • Модуль DC-to-USB-C PD для преобразования 12V в USB-C питание.
  • Type A RCBO на 10A с защитой от утечки 30mA (£14.00).
  • Три метра кабеля 2.5mm² twin-and-earth (£11.99).
  • Угловой USB-C разъём с кабелем 25см. Нужен был один, но продаются в пачке по шесть (£5.99).

Тот маленький USB-C PD модуль — классный и необычный девайс. Берёт 12V и выдаёт USB-C Power Delivery. Вижу себя заказывающим ещё один.

Это цены из моего заказа, а не текущие котировки. Герметичный корпус, блок питания, USB-C модуль, защита, кабель и разъёмы для напоминания о баках. Я знаю.

На всех шести баках теги установлены. На этом этапе чувствовал себя довольно оптимистично, что всё работает.

Установленный якорь BinRange и компоненты питания внутри прозрачной уличной коробки.

Якорь установлен на стену. Напечатанный корпус внутри большей коробки. Фото установки.

Напоминания и уведомления

Интеграция Waste Collection Schedule заслуживает большой похвалы. Парсинг расписания муниципалитета избавляет от поддержки нескольких повторяющихся дат и от необходимости помнить, какая комбинация баков вывозится. BinRange добавляет физическую информацию о баках, Home Assistant объединяет оба источника.

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

Напоминания сгруппированы в одно сообщение для соответствующих баков: в 18:00 и 21:00 вечером перед вывозом, затем финальное напоминание в 06:00, если они ещё уверенно дома. На следующий день в 18:00 — напоминание внести обратно ещё вывезённые. Автоматизация помнит попытки, так что перезапуск не пошлёт одно сообщение дважды.

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

Уведомление Home Assistant: Общий мусор, Переработка 1 и Стекло должны быть вынесены на завтрашний вывоз.

Уведомление Home Assistant о необходимости вынести баки.

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

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

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

Уведомление Home Assistant: Общий мусор, Переработка 1 и Стекло только что опустошены и могут быть внесены обратно.

Уведомление Home Assistant об опустошении баков и возможности их внесения.

Первый тест в боевых условиях

28 сентября был вывоз садового компоста, который можно было как следует проанализировать. Бак начал движение примерно в 07:05 и вскоре пересёк граничную линию десяти метров. Затем отчёты перестали приходить, пока его вывозили. Когда он вернулся примерно в 10:25, он нёс сохранённый наклон примерно из 09:27, потом пересёк границу обратно в дом и устроился.

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

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

Это также изменило, как хотелось показать бак, который умолк. Изначально вывезённое чтение становилось Неизвестным, когда оно становилось устаревшим. Это была осторожность, но после наблюдения за отъездом бака и потери контакта на краю дороги, замена Вывезен на Неизвестно перестала быть очень полезной.

Живая система теперь помнит наблюдаемый уход как предположительно Вывезен, даже сквозь потерю контакта или перезагрузку Home Assistant. Здоровье связи показано отдельно. Свежее чтение внутри границы нужно, чтобы вернуть бак Домой. Если он последний раз был замечен Дома, а потом замолк, он становится Неизвестным, потому что его уход я не видел. Напоминания о возврате могут использовать Предположительно Вывезен; напоминания о вывозе нуждаются в свежем подтверждении, что бак Дома.

Это делает дисплей ближе к тому, что я реально знаю.

Мем Гладиатора с подписью: 'Это не перепроектировано?'

Ожидание следующих дней вывоза

BinRange установлена и используется. (Пока это пишу, сознаю, что серьёзно загнал этот инструмент в один жанр 🤔)

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

Репозиторий содержит прошивку, файлы корпусов, измеренные результаты и примеры Home Assistant, если интересно посмотреть. Это мой хобби-проект, и я всё ещё разбираюсь, как хорошо он ведёт себя на улице.

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

Большинство люде просто поискали бы кота.