В предыдущих статьях мы разобрались, когда поливать и как поливать, а в истории про ретранслятор — как дотянуть связь до дальней теплицы. Осталось закрыть последнее звено: собственно открыть и закрыть воду. Сегодня — про садовый кран POK006. Уличный датчик температуры и влажности POK005 мы при этом перепрыгиваем — он заслуживает отдельного разговора, вернёмся к нему позже.
Кран в нашей линейке полива появился самым последним — и дольше всех казался не нужным вовсе. Дело в том, что готовые Zigbee-краны на рынке уже есть: кто-то до нас взял автономный кран с таймером и переделал его электронику под Zigbee. Мы такими и пользовались — не пару дней для пробы, а пару полноценных сезонов. Они работали, поливали, и идея городить собственный кран выглядела избыточной: всё ведь и так есть, бери да ставь. Перелом наступил, когда мы на практике поняли, чего этим кранам не хватает, — надёжности. Не «в среднем работает», а гарантии, что критический исполнительный механизм сделает то, что ему велено. Вот тогда и появился POK006. Об этом и сага.
Что вообще есть на рынке
Велосипед мы изобретать не любим, поэтому сначала пошли смотреть готовое. И тут выяснилось, что таких кранов — несколько разновидностей, внешне почти неотличимых, но прилично разнящихся и по электронике, и по механике.
По электронике разброс большой. На одном краю — простейший кран с двумя крутилками: как долго поливать и как часто. На другом — «космолёт» с россыпью кнопок, расписанием на неделю, временем полива и иногда даже опциональным датчиком влажности или дождя.
По механике деление принципиальнее. Есть краны с шаровым механизмом — большой проход, работают без давления, прямо самотёком от бочки. А есть «другие» (мы, честно говоря, так и не нашли, как корректно назвать этот механизм) — они требуют минимального давления, обычно от 0.5 атмосферы. Устроены такие краны примерно как чисто механические таймеры полива — те, что с пружиной и крутилкой, — и как клапаны перелива. Они дешевле, но у них два минуса для огородных реалий: во-первых, само требование давления, которого от бочки попросту нет, а во-вторых, они охотно забиваются примесями из поливной воды.
Наш выбор был очевиден: кран с шаровым механизмом, в добротном корпусе, с Zigbee. Корпус и механика тут, к слову, целиком покупные — хороший, относительно доступный на рынке узел, ничего уникального. Вся уникальность POK006 — в электронике и прошивке. И именно к ней мы пришли не от хорошей жизни.
Тот самый кран в боевых условиях — там, где ему и положено работать.
В чём, собственно, проблема
Кран — это критический исполнительный механизм. От того, сработает он или нет, напрямую зависит урожай: растение можно и засушить, и залить, и оба исхода одинаково печальны. А значит, цена единичного сбоя здесь несопоставима с ценой сбоя у датчика, который в худшем случае пропустит одно измерение.
И вот тут начинается разговор про тот самый процент ненадёжности.
Надёжность Zigbee
Zigbee с самого начала задумывался как протокол для сбора данных и управления, поэтому надёжен он «из коробки». Точную цифру назвать сложно, но пусть для разговора будет 99% — вероятность того, что посланная вами команда дойдёт до крана и он переключится.
Много это или мало? На первый взгляд — отлично. Подумаешь, один раз из ста что-то не случится; дачный сезон и то короче в днях. Но есть два «но». Первое — закон подлости: этот единственный промах из сотни непременно придётся на самый неподходящий момент. Второе, и более коварное: когда мы собираем систему из нескольких устройств, общая вероятность её правильной работы перемножается и падает с каждым новым элементом. Несколько кранов, датчиков и сценариев — и заветные «99%» на уровне всей автоматики превращаются во что-то заметно менее радужное.
Как Zigbee добивается высокой надёжности? На нижнем уровне, на уровне протокола, каждое сообщение передаётся с подтверждением от принимающей стороны, а при неудаче делаются автоматические перепосылки. Это так называемое подтверждение канального, MAC-уровня (Media Access Control — нижний уровень доступа к среде): его даёт тот узел, которому пакет передан непосредственно, «из рук в руки». Важно, что контролировать это на уровне логики устройства нельзя или очень сложно — это часть функций Zigbee-стека, по сути аппаратная. Для нас как пользователей это плюс, а для нас как разработчиков — источник неопределённости по энергии: мы попросту не знаем заранее, сколько раз включится передатчик. В идеальном случае — один, при плохой связи — пять. Понимать и контролировать эти процессы критически важно, чтобы обеспечить предсказуемое время работы от ограниченной батареи (тем, кому интересна эта кухня, в самом конце есть отдельный технический P.S.).
Выше по иерархии управления, как правило, тоже есть автоматические перепосылки — либо в логике самого устройства, либо на уровне центрального координатора, — и для пользователя они так же прозрачны. Если совсем упростить: Zigbee знает, дошёл пакет до получателя или нет, и активно работает над доставкой. Именно поэтому в 99 случаях из 100 всё и срабатывает. Важная оговорка: эти 99% — цифра для случая, когда сеть построена правильно (хватает роутеров, нет глухих углов и сильных помех), и над этой правильностью тоже приходится работать — о чём у нас есть отдельный разбор, почему устройство «отваливается» и как это лечить.
Справедливости ради, подтверждениями с перепосылками арсенал Zigbee не исчерпывается. Под ними лежит ещё несколько слоёв: на физическом уровне — расширение спектра DSSS, которое позволяет вытаскивать сигнал даже из-под шума и держать узкополосные помехи; на канальном — CSMA/CA, когда узел перед передачей слушает эфир и не лезет в занятый канал, и проверка целостности каждого кадра по контрольной сумме; на сетевом — то самое mesh-самовосстановление, перестроение маршрута в обход отвалившегося роутера (ровно тот механизм, благодаря которому в истории про ретранслятор сеть переживала утренние «провалы» POK004). Так что радиочасть, что называется, не лыком шита, и мы хорошо представляем, на чём всё держится. Но из всего этого арсенала максимальный вклад в надёжность доставки вносят, по нашему опыту, именно перепосылки с подтверждением.
Кран — это не только электроника
Беда в том, что кран наполовину состоит из механики. А у механики свои сценарии отказа, к радио отношения не имеющие.
Батарейки могут подсесть, и мотору не хватит сил. Шар может покрыться налётом и перестать проворачиваться. В шар может что-то попасть и заклинить его. При повышенном давлении усилия может не хватить, чтобы перекрыть поток. И каждый такой случай роняет наши «99 из 100» ещё ниже — теперь уже по причинам, которые Zigbee в принципе не видит и видеть не может. Усугубляет всё то, что нас рядом нет: о проблеме мы узнаём в лучшем случае с большим, а нередко и с фатальным опозданием.
Хорошо, как победить этот злосчастный процент? И вот тут стало понятно, почему готовых чужих кранов, на которых мы прожили пару сезонов, нам в итоге перестало хватать.
Мы решили, что нам нужна достоверная обратная связь — устройство должно не только получить команду, но и доложить, что реально произошло. Отчасти такую связь даёт датчик влажности, но он медленный, инерционный — пока почва отреагирует, момент упущен. Чуть лучше датчик протока — расходомер. Но всё это косвенные средства контроля. А ведь внутри сам кран точно знает своё состояние: закрыт он, открыт, в движении или застрял. Нужно лишь сделать это состояние доступным по Zigbee.
А вот этого готовые краны и не умели — и в чужой прошивке добавить было нельзя. Именно здесь и закончилась наша жизнь на покупных кранах и началось собственное устройство: честный «отчёт о себе» можно встроить только в свою электронику и свою прошивку.
Доводим до достоверности
Дальше мы пошли по пути наименьшего сопротивления. У нас уже был опыт жизни на готовых кранах, так что мы знали, какая механика себя ведёт прилично, а какая нет: протестировали несколько моделей, выбрали лучшую и связались с её производителем, договорившись о поставке сборочных комплектов без плат управления. Наша зона ответственности — плата и прошивка.
Первым делом появилось то, ради чего всё затевалось, — поле «Состояние 2» с реальным, актуальным положением крана. Переключив кран, теперь можно увидеть, принята ли команда (тронулся ли кран с места) и состоялось ли переключение на самом деле. Но в процессе сделали ещё два улучшения, и оба оказались важными.
В приложении видно сразу две вещи: ползунок из тёмного становится светлым, когда доставка команды подтверждена, а поле «Состояние 2» честно проходит «Закрыт → Движется → Открыт» — кран сам докладывает, что реально делает.
Первое — автоотключение при потере связи. Что будет, если во время полива пропадёт электричество и координатор (центр умного дома), особенно без резервного питания, станет недоступен? Очень не хочется, чтобы кран при этом остался открытым «навсегда». Но как его закрыть, если командовать уже некому? Изучив вопрос, мы нашли, что стандартный Zigbee-кластер управления включением поддерживает команду OnDelayedOff — «включись на время». Это штатное расширение, но поддерживает его мало кто; наш кран стал исключением. Если вместо прямого включения пользоваться этой командой, кран закроется сам, даже если в середине полива потеряет связь с умным домом. Стратегий применения тут несколько: можно сразу задавать максимально допустимое время полива, а можно работать в режиме watchdog — автоматизация каждую минуту продлевает «разрешение быть открытым», и стоит ей замолчать, как кран сам закроется через минуту.
Второе — контроль всей цепочки доставки. В тестовой эксплуатации мы заметили, что кран иногда теряет способность принимать команды. Чаще всего виноват один из промежуточных роутеров. Дело в том, что конечное (батарейное) устройство в Zigbee общается лишь с одним роутером — своим «родителем» (parent). Ему оно отдаёт пакет и от него же получает то самое MAC-подтверждение о приёме. А оно, как мы уже разобрались, означает ровно одно: «сосед, которому я передал пакет из рук в руки, его принял». Дошёл ли пакет дальше, до координатора, — на этом уровне неизвестно. К родителю же кран периодически обращается с вопросом, нет ли для него команды. И вот если что-то ломается выше — где-то между координатором и этим родителем-роутером, — кран остаётся, как ему кажется, полностью исправным: сосед-то его слышит и отвечает. А с точки зрения пользователя кран в этот момент недоступен. Если термины «родитель», «роутер» и «координатор» звучат непривычно — мы разбирали устройство mesh-сети с нуля в отдельной статье.
Решение нашлось в самом Zigbee — передача данных с APS-подтверждением (APS, Application Support Sublayer — прикладной подуровень стека). В отличие от MAC-подтверждения от соседа, APS-подтверждение сквозное: его формирует сам конечный получатель пакета — как правило, координатор, — и оно проходит весь обратный путь до отправителя. Если оно пришло, значит, цела вся цепочка целиком, а не только первый шаг до родителя. Такая передача дороже по энергии (дальний ответ, больше хопов), зато проверяет доставку по-настоящему. Наш кран раз в десять минут отсылает своё актуальное состояние — то самое поле «Состояние 2» — запрашивая APS-подтверждение от координатора. Если несколько раз подряд подтверждения нет — кран понимает, что цепочка где-то порвалась, и активно пытается переподключиться к сети, чтобы восстановить связь, не дожидаясь, пока проблему заметит человек.
В сумме эти три вещи — честный статус, автоотключение и сквозной контроль доставки — и закрывают тот самый процент. Только закрывают они его не там, где можно было бы подумать. Стопроцентной надёжности не существует: радиоканал, севшие батарейки и заклинивший шар никуда не делись, и физически гарантировать, что кран всегда переключится, нельзя в принципе. А вот чего мы добились по-настоящему — это стопроцентной достоверности. Система всегда знает реальное состояние крана и всегда знает, дошла ли команда до места. Если что-то пошло не так — это не остаётся незамеченным: статус честно покажет правду, автоматика отработает закрытие при потере связи, а APS-подтверждение поднимет тревогу, если порвалась цепочка. И вот это уже не фигура речи — это ровно тот результат, ради которого городился весь огород. Надёжность остаётся вероятностной, как ей и положено, но слепых зон в ней больше нет.
Важная оговорка: само поле «Состояние 2» кран отдаёт по стандартному Zigbee, так что увидеть реальное положение крана можно в любой системе умного дома. А вот выжать из этой честности максимум получается в связке с нашим шлюзом POK100 и приложением Управлятор: там статус доставки команды виден прямо в интерфейсе (на гифке выше ползунок из тёмного становится светлым ровно в тот момент, когда команда подтверждена), а в автоматизациях факт доставки можно проверять явно — через оператор ДОШЛО, чтобы сценарий полива не шёл вслепую, а дожидался реального подтверждения от крана. Но это уже тема для отдельного разговора.
Итог
POK006 начинался как самая простая задача во всей линейке — взять готовый кран и научить его говорить по Zigbee. Поначалу мы и вовсе обходились чужими готовыми кранами и считали, что своего не нужно. А закончилось всё самой въедливой вознёй с надёжностью из всех наших устройств. Причина проста: кран — единственное звено полива, у которого ошибка стоит урожая, и «обычно срабатывает» здесь не годится в принципе.
Сделать кран, который сработает всегда, физически нельзя — мотор, батарейки и радио остаются вероятностными. Зато можно сделать кран, про который всегда известна правда: открыт он или закрыт, дошла ли команда, цела ли связь. Именно в этом и вся ценность POK006 — не в красивом корпусе (он покупной и совершенно обычный) и не в хитрой механике, а в трёх неочевидных фишках прошивки: честном отчёте о собственном состоянии, способности закрыться самому при потере связи и умении проверить всю цепочку доставки до координатора. И, как и с остальными устройствами, мы пришли к собственной разработке не потому, что хотелось сделать своё, а потому, что без этой достоверности последнее звено полива оставалось слепой зоной — а значит, не работала спокойно и вся остальная история.
P.S. Для тех, кому интересно заглянуть внутрь
По существу — всё. Если вы пришли за историей устройства, дальше можно не читать: суть POK006 в трёх фишках прошивки, о которых сказано выше. А вот этот раздел — для тех, кто любит, когда «а как оно сделано внутри». Здесь про электронику и про то, как мы воевали с питанием мотора.
Сама по себе электроника крайне простая: силовой выход на мотор и бинарный сенсор-энкодер. Мотор всегда крутится в одну сторону, а энкодер на один оборот шара фиксирует два состояния — открыто и закрыто.
Любопытный момент: при включении кран не знает своего точного положения, потому что состояние фиксируется не абсолютно, а по смене сигнала энкодера — переход «0 → 1» это, скажем, открыто, «1 → 0» — закрыто. Поэтому при старте кран прокручивается, пропуская первый переход, и фиксирует то состояние, в котором оказался на втором. Просто и надёжно.
Главный же вызов по электронике — заставить мотор работать от маленьких батареек (2×AAA). В момент пуска мотор потребляет ток в десятки раз больше рабочего и серьёзно просаживает напряжение. А микроконтроллер уже при напряжении ниже 2 В сбрасывается и теряет контроль над процессом. На свежих батарейках всё прекрасно, но стоило разрядить их на 30–40% — и кран начинал капризничать. Дальше была история из трёх итераций.
Первая идея была простой: раз мотор и микроконтроллер дерутся за одно и то же питание, надо просто убрать контроллер с дороги — на время пуска уложить его в сон, где он почти ничего не ест. Звучит тривиально, но и тут была своя возня: мало просто отправить CC2530 спать, нужно было ещё немного подкрутить сам Zigbee-стек (zStack), чтобы он в самый неподходящий момент не разбудил какую-нибудь свою задачу. Заставить контроллер гарантированно уснуть — оказалось отдельной работой. Но и она не спасла: спящий контроллер потребляет копейки, однако пусковая просадка напряжения бьёт по его шине питания независимо от того, спит он или бодрствует. Сон уменьшил потребление, но не убрал саму просадку.
Вторая попытка была классической: изолировать шину питания контроллера диодом Шоттки и накопительными конденсаторами, чтобы он просто не замечал провала. На практике вышло так себе — по сути, ничего не изменилось, а кое в чём стало даже хуже. Падение напряжения на самом диоде срезало слишком много: даже без пусковых токов минимальное напряжение, при котором кран ещё работал, поднималось на 0.2–0.4 В — а это где-то 20–30% ёмкости батарей, отправленных в утиль ни за что.
Решением стал управляемый диод — MOSFET. Фокус в том, что от детали тут требуются две взаимоисключающие вещи: почти всё время проводить ток без потерь (чтобы не красть ёмкость, как Шоттки), а в момент пуска — наоборот, отрезать контроллер от просевшей шины. Пассивный диод так не умеет, а управляемый MOSFET умеет: он полностью открыт всегда, падение на нём практически нулевое, и лишь на момент пуска мотора контроллер сам его закрывает — отрезает себя от внешнего питания, чтобы пережить просадку на запасённой в конденсаторах энергии. Мотору в это время достаётся вся мощность батарей, а контроллер её не отнимает.
И вот тут вылез самый неочевидный нюанс. Казалось бы, надо запасти энергии на момент засыпания — это и так понятно. А на деле выяснилось, что конденсаторов должно хватить не только чтобы уснуть, но и чтобы потом проснуться: оба перехода контроллер проходит на полном токе (7–8 мА у CC2530 без радио), и только в самой яме сна потребляет смешные 2 мкА. В сумме это около 6 мс «дорогого» питания — три на засыпание, три на пробуждение, — которые конденсатор обязан вытянуть целиком. В первой версии платы ёмкости хватало впритык только на это, и растянуть окно изоляции дольше 6 мс мы уже не могли, а пусковой бросок мотора длится все 50–100 мс. Так что контроллер не пересиживает весь пуск на конденсаторах — он лишь аккуратно ныряет в сон до начала броска и выныривает уже после, а самый «грязный» по питанию участок просто переживает в спящем состоянии, не реагируя на просадку. Зато в итоге схема позволяет дожимать батареи практически досуха — до 1 В на банку.
Тут стоит честно оговориться: гнаться за этим вольтом нас никто не заставлял. На практике даже 50% заряда хватает на пару сезонов, так что «выжать до последнего» — это скорее наш инженерный перфекционизм, чем суровая необходимость. Но раз уж взялись делать аккуратно, грех было оставлять треть ёмкости лежать мёртвым грузом.