Аналоговый датчик CO2
Всем привет и наступающими! Захотелось тут сделать пару гаджетов для друзей в их умные дома. И что-то вдруг подумалось — а что они все скучные такие? Давайте же сегодня сделаем датчик в таком форм-факторе, в котором точно не купишь в магазине, будет отличный подарок на Новый Год или Рождество. Ну и ещё что-бы подарить было не стыдно.
Сразу оговорюсь, прибор конечно же не аналоговый, а полностью цифровой. Ламповый тут только дизайн, внутри же ничего сверхъестественного на данный момент времени. Используется народный датчик SenseAir S8 и инструментальный шаговый двигатель для автомобильных приборок.

Дисклеймер: электроника у меня только хобби, так что могут быть неточности и ошибки. Пишите комментарии, поправим. Так же являюсь Луноходом и живу в Германии, что приводит к некоторым особенностям данного поста: цены в евро + в процессе разработки мы будем использовать только софт под Linux.

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

Всё опубликованное здесь и в репозитории лицензировано под GNU GPLv3.
Итак, для начала сформируем требования:
В общем, всё что у нас задумано — уже можно сказать существует. Всё что нужно сделать — это собрать воедино :-)
Изначально я хотел сделать именно «авиационный прибор», но в процессе у меня быстро попросили сделать так же ретро-версию. Соответственно, прибор у нас будет с опциями комплектации, каждая может быть выбрана независимо:
Мне не нравится, что многие хорошие девайсы зачастую сложно найти. Часто никто не париться с названием и делает что-то типа «Advanced Co2 home sensor module», которое невозможно найти или понять — где что.
Придумал название для серии датчиков — Galoped. Название не несёт никакого смысла, просто стоял курил на улице и подумал — надо что-то такое, что было в стиле Икеи, состоящие из слов «Галоперидол» и «Педиатр». Так и придумал.
Небольшая предыстория — сделать «аналоговый» показометр у меня была уже очень давно. Я где-то в году 2012 купил себе двух-стрелочный тахометр от турбовинтового самолёта, который я хотел «оживить». Естественно никто ничего за 10 лет не оживил :) Но идея никуда не девалась, прибор переехал вместе со мной в Германию в 2017 году и до сих пор стоит у меня на столе:

Данный девайс оживить сложно, ему нужно два трёхфазных сигнала, которые вращают контрольные диски внутри, которые через магнитную муфту отклоняют стрелки. Девайс большой и наверняка шумный. Но в принципе это возможно, он может указывать что-то в процентах. В данном случае лучше было-бы воспользоваться современными технологиями и сделать всё с нуля — у меня вроде как всё есть для этого: старенький 3D принтер Ender-3 (ещё самая первая модель) и руки чешутся.
Конечно на рынке есть всякие-разные показометры, например на Алишке полно приборов типа такого:


, но они все сделаны для стритсракеров и мало подходят для разумного примнения. До того момента как я понял на чём подобные приборы работают — думал заказать на пробу, разобрать и посмотреть. Но это не понадобилось, так как оказалось что сделать с нуля в общем будет проще.
Следующий вопрос — а что, собственно, показывать? Можно отображать разные метрики умного дома, с работы или домашней инфраструктуры, но такое слишком специфично. В итоге выбираем уровень CO2 — подходит отлично: таких исполнений датчиков просто нет (я не нашёл ни одного), данная метрика медленно меняется, автономна (можно измерять на месте), кроме того полезна — можно посмотреть когда пора-бы проветрить. У нас в офисе кстати постоянно спорят — надо ли открывать окна или нет, и такой девайс может разрешить подобные спорты путём прямого инструментального измерения. Я не буду в сотый раз расписывать — что такое измерение CO₂ и если тема для вас непонятна — почитать можно например тут. В качестве измерителя выбираем SenseAir S8, как самый авторитетный из народных. Почитать про него и сравнение с другими можно здесь. Ну и конечно же данный прибор может показывать что угодно, строго говоря CO₂ — только лишь пример, что-бы получить законченное устройство.
Когда пришла в голову идея создания нового прибора — казалось что всё просто, берём шаговый моторчик (серву?) и приводим в движение одним из миллиона способов. Но быстро стало понятно что серва не подходит — шумная, неточная и имеет слишком малый угол поворота. Довольно быстро я нагуглил что существует прям народный шаговый двигатель X27-168, точнее — целое их семейство. Довольно быстро нашёл пост замечательного парня guy.carpenter с экспериментами с драйверами данных двигателей. Данные моторчики широко применяются в различных девайсах, например популярны у симмеров. Так же, оказалось что их существует целое большое семейство — например есть варианты с 2-мя стрелками или датчиками нуля (варианты для часов).
Существуют целый семейство и множественные клоны специальных драйверов, которые реализуют алгоритм микростеппинга: когда одна команда от контроллера поворачивает привод не на одно деление (обычно это 1/3°), а на 1/12°. Так же в даташите написано что такой способ является предпочтительным — это повышает точность и уменьшает шум привода.
Для начала заказал сразу шесть моторчиков (комплект обошелся в 12€) и проверил их через рандомные H-Bridge драйвера. В принципе работает, но выглядит очень так себе — точность плохая, шум сильный. В итоге заказал обойму из 10 драйверов VID6608 и стал их ждать.

Первый прототип собрал на макетных платах и приступил к тестированию. В принципе, что-то уже работало, но тут было первое разочарование: собрав прошивку на коленке в platform.io с библиотекой от уважаемого guy.carpenter наткнулся на кучу багов и проблем. Пришлось их на ходу править, что довольно сильно затормозило процесс. В какой-то момент я пришёл к выводу что проще написать свою с нуля, чем разбираться в оригинальной — автор явно потыкался немного, а потом потерял к теме интерес.
С самого начала задумал использовать прошивку Tasmota как основу для девайса, т.к. содержит в себе уже всё что нужно и широко известна. Но тут меня ждало следующее разочарование, что в Tasmota имеется поддержка только H-Bridge драйверов для «обычных» шаговых двигателей.
Итого, формируем наш с вами план — как же нам собрать всё вместе?
Итак, раз решили — надо делать :-) Клонируем проект и погружаемся в документацию. На деле оказалось всё непросто: документация в принципе есть, но довольно отрывочная, пришлось выбрать парочку простых драйверов и использовать как живой пример. Посмотрел как сделано поддержка других библиотек — они просто закоммичены напрямую прямо в репозиторий, не как суб-модули или зависимости. В этот момент я решил что проще написать свою библиотеку и добавить её туда же + драйвер.
Про разработку особо не буду распинаться, сделано всё по образу и подобию уже существующей SwitecX25 — только без багов)) Отличия от старой:
В итоге появилась новая библиотека: arduino-vid6608.
Библиотека использует более простой алгоритм расчёта ускорения, где имеется статический массив расстояние-задержка, и до первой 1/2 пути происходит сравнение расстояния и рост скорости, на второй половине происходит замедление. Функции задания положения асинхронные, функция vid6608::loop() чувствительна к точности вызова функции обновления.
На видео пример работы алгоритма — прибор просто показывает случайные значения. В итоге оставил так — как по мне получилось достаточно реалистично при минимуме вычислений.
Далее выбираем следующий свободный Driver-ID в Тасмоте и занимаем его. Мне достался номер 92, в результате чего появился на свет драйвер xdrv_92_vid6608. Обратите внимание что реализация именно в виде драйвера общего назначения, изначально я думал сделать как display, но у данного класса драйвера нет достаточно точного тайминга для обеспечения плавного движения стрелки.
Сделав первую версию драйвера — сразу же сталкиваемся с двумя новым проблемами:
Решение первой проблемы очевидно: для ESP32 в Tasmota используется FreeRTOS из пакета разработки ESP-IDF, а значит что мы можем использовать примитивы и функции операционной системы реального времени. Собственно решение простое как полено: мы просто заведём обработку обновления в отдельный поток, который по-умолчанию уйдёт на второе ядро (мы будем ставить на плату двух-ядерную версию ESP32):
Хорошо, но данный трюк сработает только для ESP32, а для старой ESP8266 данное решение не канает. В итоге оставил как есть — я не планировал использовать ESP8266, и в принципе драйвер там всё равно работает — только довольно медленно: порядка 20 секунд на каждые 10 градусов движения. Этого всё ещё достаточно для отображения медленно изменяющихся параметров (такие например как температура или количество лайков к статье на муське).
Решение второй проблемы менее очевидно: надо просто добавить вызов функции yield() в процедуру выставления нужного шага:
В этом случае даже многократный вызов в цикле не будет блочить нашу программу и мы избавимся от падения Watchdog.
Ещё хочу коснуться другой проблемы: тайминги. Для красивой отрисовки движения стрелки мы должны выдерживать тайминги вплоть до 0.3мс (300 мкс), что уже средствами таймеров FreeRTOS невозможно. Да, у них есть своя реализация delayMicroseconds(), но посмотрев в исходный код нас ждёт фрустрация: там просто цикл из nop-ов на нужное время. Что просто превращает в тепло время ожидания вместо таймеров. Проблема на данный момент не решена — если кто-то знает хорошее решение — пожалуйста напишите в комментах. Из хорошего: проблема не то что бы большая, она проявляется только во время активного движения стрелки и только на некоторых участках.
В любом случае: патчи успешно приняты в Тасмоту и баги поправлены:
На момент написания обзора драйвер уже включён в релиз Tasmota v15.2.0 Stephan. Обратите внимание что третий пакет изменений (сброс из сохраненного состояния) в релиз попасть не успел, так что база для прошивки пока что всё равно development.
Драйвер добавляет следующие команды:
Драйвер поддерживает до 4 двигателей. Все команды по-умолчанию управляют первым двигателем, могут быть с суффиксом мотора (от 1 до 4), при этом 0 — это все двигатели. Пример: «GaugeSet0 520» — выставит все двигатели в значение 520, «GaugeZero3» — сброс только мотора №3.
Это была одна из главных загадок для меня: я когда только заказал и сидел ждал моторчики, пытался нагуглить или выяснить — как же делают другие? На форумах симмеров предлагали всякие громоздкие решения типа оптических датчиков, а все остальные — просто ничего не писали про это. В старой библиотеке в исходном коде нашёл объяснение — там просто происходило движение назад на всю шкалу, что, видимо, приводило к торможению привода в крайнем положении, после чего текущее положение принималось за нулевое. Это действительно работает, но приводит к долблению нашего моторчика об концевые упоры — непорядок.
Собственно решение: а давайте просто будем запоминать текущее значение «куда-нибудь» и потом использовать его для калибровки. В этом случае можно просто продвинуть стрелку вперёд на остаток от последнего значения, а потом полный круг назад. Если стрелка была в рассинхроне с тем что у нас было записано, то в худшем случае произойдёт долбление либо в начале, либо в конце (смотря куда уехало реальное значение), но в итоге стрелка будет гарантировано в нулевой позиции.
Вопрос только — куда писать? Флеш не подходит, т.к. у него сильно ограничено кол-во записи. Но всё уже придумано до нас: это — сегнетоэлектрическая оперативная память (Ferroelectric RAM, FeRAM или FRAM) — оперативная память, по своему устройству схожая с DRAM, использующая слой сегнетоэлектрика вместо диэлектрического слоя для обеспечения энергонезависимости. Чип стоит недорого и обеспечивает до 10¹² циклов записи, этого должно быть достаточно для чуть больше 31 тысяч лет непрерывной работы при условии записи раз в секунду. Реализация очень простая — давайте просто поставим недорогой чип Fujitsu MB85RC04V FRAM на плату и будем писать туда каждый раз, когда стрелка принимает команду.
Пример восстановления из сохранённого состояния. Всё работает и не долбится где не следует :-)
Вообще, помимо FRAM существуют другие решения, например DRAM с бекапом во флеш при отключении питания и им подобные, но в данном случае это избыточно. Много запоминать нам и не надо, стоит недорого.
Итак, мы отработали основные идеи и можно приступать к дизайну электроники нашего девайса.
Внимание: я буду использовать схему с исправлениями оригинального дизайна. Вы можете заметить отличия от фотографий реального девайса, но схема уже содержит исправления косяков. Это сделано для простоты повторения. Оригинальные схемы могут быть найдены в репозитории, если вас интересует именно изначальное исполнение.
Заходим на EasyEDA и рисуем схему:

Основа для всего девайса — модуль ESP32-WROOM-32, двух-ядерный, 4Мб флеша. Вы, конечно, можете поставить любой другой в том же форм-факторе.

Данная схема нужна для удалённого сброса кристалла из esptool без необходимости нажимать кнопки сброса/boot. Схема срисована с модуля ESP32-Devkit-v1. Реализует элемент ИЛИ-НЕ для обеспечения очередности сигнала сброса с DTR или RST. Это обеспечивает прошивку через подходящий USB-UART модуль в полностью автоматическом режиме.

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

На данный разъём выведены GPIO 4, 13 и 25 а так же шина I²C, к которой можно подключить дополнительные датчики или исполнительные устройства, например часы. Присутствует питание и земля.

Выполнена на I²C кристалле FRAM памяти MB85RC04V, производства Fujitsu. Имеет на борту 4Кб памяти — довольно скромно по нашим меркам, зато недорого и работает :)
Дальше ничего особо интересного нет, от модуля разведены:
Заказываем и ждём :) У меня случилось что-то с доставкой и я получил платы только недели через три с извинениями. Платы заказаны с установкой деталей с одной стороны, без модуля ESP32 (они у меня были отдельно, плюс я не был уверен что не наделал косяков).

Народные x27-168 и им подобные рекомендуют закреплять мотор посредством пайки. Хорошая идея, в общем, но требует отдельную печатную плату. Для установки двигателя в корпус сделал простой вариантик с выводами как под разъем, так и под пайку.
Собираем и проверяем — всё почти работает :) У первой версии был один косяк — у кнопки 0 не стал ставить подтяжку, т.к. в документации Tasmota утверждалось что при такой конфигурации используется внутренний резистор подтяжки в MCU. Но нет, нифига. Если оставить болтаться в воздухе то кнопка срабатывает, что может приводить к сбросу настроек (при «нажатии» на 45 секунд). Но благо поправить очень просто — кидаем выводной резистор поверх и готово.


Основная плата для привода в EasyEDA Web: oshwlab.com/petrows/galoped-dekad
Breakout плата для привода в EasyEDA: oshwlab.com/petrows/galoped-dekad-drive
Это, наверное, самое важное. В этом разделе мы определим — будет ли наш прибор выглядеть как колхоз или же как что-то приличное. Разумеется, корпус можно полностью сделать на 3D-Принтере, но я эту идею отбросил сразу, по бокам будет видно что корпус печатный, а хотелось что-то более няшное, а значит — покупное и фабрично сделанное. Кроме того, у нас в требованиях пунктик что девайс должен быть простой в повторении. Следовательно, Aliexpress подходит тут слабо — у продавцов часто фактические изделия отличаются в зависимости от времени и может не соответствовать картинке. Ну и внутренности тоже могут быть разных ревизий, а нам надо что-бы всё влезало хорошо.

Начать решил с Ikea. Доводы такие: икея распространена по всему свету и у них изделия строго одинаковые везде. Следовательно, сделать себе такой прибор можно будет практически везде, купить икеевскую штуку можно даже там, где Икеи нет. Посмотрел что у них есть и выбрал Ikea Dekad. Это единственное что подходило более-менее.


Я хочу сказать что этот лот с самого начала мне не очень понравился, думал что будут сложности. Но как же я ошибался! Девайс просто как будто придуман для самоделок. Красивый и ровный корпус, очень технологичный — минимум лишнего, внутри всё на болтах. Циферблат, рамка и стекло — отдельные детали, что позволяет развернуться полёту мысли. Сверху имеется дырка для привода звонка — который электрический и приводится в действие электромотором. Его можно оставить и например удивлять пользователя громким звонком, если CO₂ высоковат. Но я решил что это будет перебор :)

От оригинального будильника нам понадобится: собственно корпус, стекло, рамка (я так думал тогда, на самом деле — не совсем), гайки и ножки из нержавейки, а так же пипка от стрелки — мы её запрессуем в нашу.
Что мы узнали на данном шаге:
Лицо нашего прибора — тут всё должно быть максимально по красоте. У меня ушло на это больше времени чем планировалось. Начал с того что нашёл видео, где мужик делает круговую шкалу в Inkscape. Сделал по аналогии — у меня только более свежая версия, там были небольшие отличия. У меня ушло много времени что бы разобраться — для того что бы модификатор «Шаблон по кривой» работал — ваш образец кусочка шкалы должен быть одной целой кривой, тогда всё делается правильно. Документ делаем сразу под будку само-обслуживания фото-печати, под 10х15.

Открываем фотку авиационного прибора — нашего талисмана и вдохновляемся :) На самом деле на дизайн ушло несколько дней, плюс я его в процессе несколько раз менял — поменял отображение мертвой зоны, зеленые и красные секторальные линии сделал более похожими на реальный прибор.

И, сразу делаем версию ретро:

Для дизайна шкалы мы должны определить минимальные и максимальные значения. Смотрим на даташит на наш моторчик x27.168 и видим что полный оборот — это 315° (на самом деле 320°, но на момент дизайна шкалы я этого не знал). Теперь прикидываем: у нас есть 315*12 шагов, надо захватить примерно подходящий диапазон и минимизировать вычисления (особенно деление). Так же нужно сделать небольшую «мертвую зону» (для индикации не-готовности прибора). Рассчитываем: оставляем 15° на отображение мертвой зоны, итого у нас остаётся 300° значащего диапазона. Разбиваем его на 18 кусочков, получается что мы можем отобразить от 400 до 2200 ppm, а самое главное, что при этом получаем ровное соответствие:

Идём в DM и печатаем нашу чудо-полиграфию в будке. У нас это удовольствие стоит примерно 30 копеек при печати малыми тиражами. У нас при печате в будке есть только глянцевая фото-бумага, матовую надо заказывать. Я думал что это проблема, планировал сбрызнуть матовым лаком — но это не нужно, всё выглядит супер и так.

Дальше сталкиваемся с проблемой — а как нам сделать красивую дырку в центре, что бы это не выглядело как колхоз? Я пытался просверлить или прорезать, получилось так себе. В итоге решение пришло такое — я заказал на Amazon пробойники для кожи. Просто пробить молотком получается плохо, но если зажать пробойник в патрон шуруповерта и «просверлить», то получается идеально ровное и красивое отверстие.
Вот тут я больше всего провозился в итоге. Изначально план был простой — в Икеевском будильнике штатная рамка как будто прям сделана для подсветки, она полу-прозрачная, изнутри накатка — выглядит супер. Но на деле оказалось всё не так просто.

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

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

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

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

Пример рамки из «прозрачного» пластика, как видите тоже — так себе. В этом разделе довольно кратко, но я напечатал и проверил кучу вариантов, с диодами внутри кольца, снаружи, ближе к стеклу и циферблату — результат плохой.

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

На фото пример с RGB лентой, изолентой и промежуточной черной рамкой. Подробности можете посмотреть на 3D моделях. Филаментная лента встаёт в ту же рамку без модификаций.

Адресуемые диоды так же поззволяют делать разные эффекты, например секторальную подсветку или менять цвет в зависимости от показаний прибора. Секторальная смотрится в целом плохо — она даёт яркий блик на противоположную сторону прибора.
В итоге оба варианта подсветки ставим в двух-составное кольцо, каких-либо эффектов в стоке предоставлять не будем, вкл-выкл да регулировка яркости. Тут конечно есть ещё много чего подумать, но думаю отложу пока до следующих версий.
Теперь самое время сделать пластиковую часть нашего чудо-прибора. Большая часть видимой компоненты (корпус, циферблат) у нас уже выглядят хорошо, осталось только позаботится о задней стенке, стрелке и закрыть дырку наверху корпуса (от механизма звонка). Открываем FreeCAD и приступаем к черчению наших деталей. Кстати, я думал что довольно неплохо знаком с данной CAD-Программой, но решил перед началом посмотреть обучающие видео, нашёл канал Димы Гога тоже из Германии, и просто офигел — я не знал можно сказать ничего. Большое спасибо ему, я сделал всё что нужно гораздо быстрее. Всем очень рекомендую, кто хочет научится делать красивые детали быстро и эффективно.
Итак, шкалу сделали, но что по ней ездить должно? Я над этим долго думал, гуглил по форумам. Там предлагают много чего — вырезать из старой карточки, пробивать, выпиливать руками из металла. Я решил всё-таки попробовать напечатать аккуратно на 3D принтере с максимальным разрешением. Если печатать вверх ногами на хорошей подложке то поверхность получается ровной, по ней даже не видно особо — что она печатная. Я в процессе поиска оптимальной формы и технологии сделал наверное штук сто этих стрелок, они у меня теперь валяются повсюду.

У меня есть любимый лак из Lidl — краска для глушителей. Она даёт прикольную матовую поверхность, я сразу решил черную часть стрелки сбрызнуть именно им. Печатаем, красим — сначала попку, потом саму стрелку белым лаком, который подрезал у своей Фрау.

Получается примерно так. Я изначально хотел заморачиваться с краской, которая в темноте светится, но потом не стал делать — лучше сделать подсветку всего прибора. Так что просто красим доступными красками / лаком и получается хорошо.

Теперь важный момент — берем оригинальную пипку от икеевского будильника, сверлим 1.8мм дырку в стрелке и запрессовываем в тисках пипку в нашу стрелку. Получается здорово — наша стрелка выглядит уже почти как настоящая в самолёте. Кроме того — она идеально плотно насаживается на вал мотора, ничего мудрить с креплением не надо. Ретро-версия стрелки выглядит почти так же и не окрашивается вообще, печатаю сразу черным пластиком.
В целом, прибор состоит из деталей: рамка (если комплектация с подсветкой, иначе используем оригинальную ikea), передняя панель с седлом для мотора и платы, задняя крышка, крышечьки для датчиков S8 и Климата (если устанавливается).


Вот так выглядит сборочный чертёж. Совмещаем детали, крутим-вертим и смотрим — что-бы все дырки совпадали, ничего не мешало друг другу. Из хитрого оказалось только разве что вычислить — где точно находятся дырки крепления в икеевскоом корпусе: они разнесены на 30° и 34° от вертикальной оси.

Отдельно пришлось повозиться с крышечьками — для датчиков S8 и климата. В итоге остановился на таком — крышка S8 вставляется изнутри и держится просто прижимом (или можно капнуть клея для верности), датчик климата ставится на болты к крышке. Так как оба датчика — опция, то крышки могут не устанавливаться (у меня пока что никто не просил версию без измерения CO₂ на борту, в этом случае надо будет сделать особую крышечьку — или просто удалить дырку под него).

Так же на этом этапе генерим 2D-чертеж, для инструкции для будущих пользователей :) Я для этого создал Page во FreeCad и разместил там нужный View с изометрическим видом продукта, осталось только экспортировать куда следует.

Печатаем все детали, снмиаем и очищаем. Прототипы делал из PLA. Все детали финального устройства печатал пластиком PETG черного цвета, рамка подсветки из «прозрачного». Корпусные детали и рамки — 0.2 мм слой, заполнение 20%, обдув 20%. Крышечьки датчиков и стрелка — 0.1 мм слой. Обязательно включите ironing для получения красивых плоских поверхностей, особенно которые торчат наружу.
Изначально я всё собирал на саморезах М2.3 для пластика, но быстро надоело — выглядит хуже, вопросы к прочности, добавляет «дешевизны» к виду нашего серьёзного спец-изделия. Специально для устройства обзавелся болтами М2 и М3 с головкой под шестигранник из нержавеющей стали. Крепление в пластик будет на вплавляемые втулки — просто изумительная штука оказалась, как я без них жил раньше?

Винтики выглядят куда более солидно, придаёт ещё немножко «авиационного» стиля. Кое-что нужно взять от икеевского будильника (гайки и шайбы М3, пару саморезов М2 для врепления USB-C порта, если у вас нет своих).
Итак, давайте теперь соединим всё вместе! Наконец-то увидим, что за франкенштейн у нас тут получается. Выбираем комплектацию для сборки: Авиационный стиль, подсветка ламповая, оба датчика установлены.

Для сборки у нас уже должны быть все детали, что остались от предыдущих шагов или изысканий. Ну или просто печатаем новые на 3D и 2D принтерах, заказываем платы, разьёмы, провода. Раскладываем это всё на столе и любуюмся. Для сборки нужно вообще следующее:

Первым делом устанавливаем кристалл ESP32. Я заказывал без установки оного, т.к. у меня они были и не хотел рисковать возможным браком. Потом всё проклял — установка лютый геморрой, один модуль запорол. Заказывайте установку на заводе вместе с платой — будет тоже самое по цене и гемора намного меньше.

Сразу после установки важно проверить работоспособность — заливаем прошивку и проверяем что прибор приходит в сознание. Можно залить любую Тасмоту, потом закатаем что нужно по воздуху. Я использую данный адаптер, он имеет нужные выходы RST и DTR (обратите внимание что DTR вынесен на боковую гребенку — я сначала тупил и перепутал его с CTS и испортил одну плату, думая что сотворил непотребное). В этом случае чип прошивается напрямую через esptool или platform.io. Если такого адаптера нет, то подойдёт любой, главное что бы был совместимый с 3.3В, контакты для входа в режим прошивки коротите тогда руками. Питание лучше подавать внешнее — 3.3В в моей версии отладочного разьёма от адаптера хватало для прошивки, но уже не хватало для первого запуска. В вашей версии платы эта проблема решена (выведено 5В), но в любом случае лучше внешнее питание рекомендуется — вдруг что. В этом случае подключаем только землю от адаптера, иначе можно попалить.

Ура! Кажется что мы ничего не запороли. Пока что :)

Запаиваем остальное — разъёмы и собсвтенно нашего героя дня — VID6608. Его ставить куда легче чем ESP32, накосячить сложнее. Обязательно прозванивайте ноги после установки! У меня всё выглядело супер, но половина ног на деле не звонилась. Если плохо припаяли то будет выглядить так: привод будет дергаться хаотично вместо плавного движения. Устанавливаем всё остальное — разъемы кнопки и прочее.

Устанавливаем гильзы под винты M2. Установка очень прстая — ставим на отверстие и вдавливаем пяльником, всё получается ровно и красиво.

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

После установки привода можно вырезать и приклеить лицевую панель. Подготавливаем стрелку, прессуем в неё пипку и красим. После этого можно собрать всё вместе.

На данном этапе нам важно выставить стрелку точно в ноль. Для этого натягиваем стрелку как получится (ставится она очень туго, не стесняемся), потом проворачиваем моторчик до упора (без сигнала он свободно крутится) в нуль и проворачиваем аккуратно стрелку, пока она не будет точно в начале мертвой зоны, это истинный ноль шкалы.

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

Готовим филаментную ленту — припаиваемся к выводам под прямым углом и мастрячим разьём. У меня так же припаяна корректирующая цепь: редистор на 220 Ом и конденсатор подавления пульсаций. В версии платы, что вы увидите в EasyEDA данные детали уже установлены (на момент создания самой первой версии я ещё был в сомнениях по поводу подсветки).

Устанавливаем ленту в рамку, лучше всего развернуть её «мутной» частью внутрь. Для удобства можно подклеить прозрачным скотчем. Так же подкладываем немного скотча между лепестками контактов для изоляции, нормально запихнуть в теормоусадку нет места. Подрезаем ленту так, что бы ровненько сходилось — у нас тогда будет минимальный темный кусочек подсветки.

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

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

Подсоедияем все разьёмы и устанавливаем основную плату, ориенируем её датчиками вниз. Закручиваем всё красивенькими винтами М2.

В задней крышке привинчиваем разьём USB-C на шурупчики, просунув его изнутри. Можно использовать оригинальные серебристые Ikea от будильника, но у меня есть анодированные черные, они выглядят получше. Устанавливаем решётку датчика S8, сам датчик и помещаем крышку на место, прикручиваем всё на два винта М2.

Натыкаем наш климатический датчик на разьём и прикручиваем крышечьку сверху на ещё два болта М2. Сборка завершена :-)

Отдаляем на расстояние вытянутой руки, включаем и проверяем что всё работает. Обратите внимание что без начальной конфигурации прибор даже не будет вызывать калибровку «из коробки», нам необходимо настроить Тасмоту и подготовить агрегат к работе.
Первым делом надо настроить наш «модуль». Какие ноги где сидят и что делалют. Для упрощения жизни я сделал темплейты (версия для RGB и Ламповых подсветок): отличия в одной ноге — она либо на WS2812B либо на транзистор диммера ламповой. Шаблон можно применить руками, но удобнее это сделать сразу в прошивке. Кроме того, нам понадобится парочка #define: по-умолчанию у Тасмоты нет поддержки ни AHT20, ни моего замечательного драйвера. Создаём файл tasmota/user_config_override.h:
Так же, для выбора уже конкретной комплектации выбираем один из двух вариантов в виде файла tasmota/user/user_config_hw.h:
, это было для ламповой, для RGB:
Для ленивых: идём в раздел Releases моего проекта и качаем там готовую.
Остались уже совсем мелочи: надо всё проверить и присоединить стрелку к показаниям CO₂. К счастью, в прошивке ничего даже модифицировать не надо — у Tasmota имеется Berry script в версии для ESP32, так что просто напишем скриптик и закинем в агрегат. Для автозапуска надо именовать данный чудо-файл как autoexec.be:
Данный файл в репе. Функционально состоит из двух частей — чтение / запись в FRAM и функция чтения показания CO₂:
Данный вызов вешает вызов кэллбека co2_update при обновлении. Как видите — проще некуда. Теперь наш прибор ожил и будет что-то показывать.

Так же прибор должен показывать показания датчиков и положение стрелки в веб-интерфейсе. В зависимости от комплектации будет либо диммер «ламповой» подсветки, либо выбор цвета для RGB. Дальше уже дело техники — следуйте инструкциям Tasmota что-бы настроить интеграцию в Умный Дом и прочее, наша прошивка отличается только базовой конфигурацией и все фичи доступны.
Точную стоимость сильно зависит от кол-ва изготавливаемых экземпляров и что у вас есть уже в наличии. В моём случае чисто по железу получилось порядка 50€ за прибор, и это при условии что 3Д-принтер у меня свой и корпусные детали получаеются условно-бесплатные. Если кому-то нужен точный расчёт то пишите в каменты — добавлю в обзор.
Вот такое у нас с вами получилось чудо техники — что думаете по поводу?

И руки размяли и подарить не стыдно. Ну и ещё в Тасмоту хороший драйвер добавили. Вообще, устройство конечно легко кастомизируется и адаптируется под суровую реальность:
Что думаю надо бы в будущем улучшить (возможно когда вычитаете этот обзор то уже что-то сделано, см обновления в репе):
Исходники проекта: github.com/petrows/smarthome-galoped-dekad. В репе сейчас небольшой бардак из тестовых деталей и нет нормального Readme — не было времени прибраться, наведу порядок чуть позже. Но всё тем не менее есть.
Если у вас ещё есть хорошие идеи — делитесь, прикрутим. На этом всем желаю хорошего дня.
Сразу оговорюсь, прибор конечно же не аналоговый, а полностью цифровой. Ламповый тут только дизайн, внутри же ничего сверхъестественного на данный момент времени. Используется народный датчик SenseAir S8 и инструментальный шаговый двигатель для автомобильных приборок.

Дисклеймер: электроника у меня только хобби, так что могут быть неточности и ошибки. Пишите комментарии, поправим. Так же являюсь Луноходом и живу в Германии, что приводит к некоторым особенностям данного поста: цены в евро + в процессе разработки мы будем использовать только софт под Linux.

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

Всё опубликованное здесь и в репозитории лицензировано под GNU GPLv3.
Характеристики прибора
Итак, для начала сформируем требования:
- Измерение уровня CO2 с хорошей точностью и отзывчивостью;
- Измерение стандартных климатических параметров: температура, влажность и давление;
- Передача всего этого намеренного добра в умный дом;
- Отображение текущего уровня на аналоговом дисплее прибора стрелкой;
- Прибор должен иметь подсветку;
- Веб-интерфейс с отображением статуса, настройками, обновлением прошивки и проч — это важно что бы девайс можно было подарить кому-то и этот кто-то мог с ним разобраться сам;
- Желательно что бы это не выглядело как страшное DIY;
- Устройство должно быть легкое в повторении и не содержать уникальных компонентов;
В общем, всё что у нас задумано — уже можно сказать существует. Всё что нужно сделать — это собрать воедино :-)
Изначально я хотел сделать именно «авиационный прибор», но в процессе у меня быстро попросили сделать так же ретро-версию. Соответственно, прибор у нас будет с опциями комплектации, каждая может быть выбрана независимо:
- Стиль шкалы: «авиационный» и «ретро», так же ставится соответствующая стрелка;
- Подсветка: без подсветки, «ламповая» и «RGB» — я не люблю RGB, особенно что его пихают везде где не следовало бы, но в данном случае можно дать юзеру свободу выбора — это важнее;
- Датчики: CO₂, климата — могут быть установлены в любой комбинации, так же вообще без датчиков — в этом случае прибор будет управляться только внешней командой (например через шину MQTT, или любой логикой на базе Tasmota правил или Berry — в общем на что фантазии хватит);
Нейминг и маркетинг
Мне не нравится, что многие хорошие девайсы зачастую сложно найти. Часто никто не париться с названием и делает что-то типа «Advanced Co2 home sensor module», которое невозможно найти или понять — где что.
Придумал название для серии датчиков — Galoped. Название не несёт никакого смысла, просто стоял курил на улице и подумал — надо что-то такое, что было в стиле Икеи, состоящие из слов «Галоперидол» и «Педиатр». Так и придумал.
Разработка концепции
Небольшая предыстория — сделать «аналоговый» показометр у меня была уже очень давно. Я где-то в году 2012 купил себе двух-стрелочный тахометр от турбовинтового самолёта, который я хотел «оживить». Естественно никто ничего за 10 лет не оживил :) Но идея никуда не девалась, прибор переехал вместе со мной в Германию в 2017 году и до сих пор стоит у меня на столе:

Данный девайс оживить сложно, ему нужно два трёхфазных сигнала, которые вращают контрольные диски внутри, которые через магнитную муфту отклоняют стрелки. Девайс большой и наверняка шумный. Но в принципе это возможно, он может указывать что-то в процентах. В данном случае лучше было-бы воспользоваться современными технологиями и сделать всё с нуля — у меня вроде как всё есть для этого: старенький 3D принтер Ender-3 (ещё самая первая модель) и руки чешутся.
Конечно на рынке есть всякие-разные показометры, например на Алишке полно приборов типа такого:
Приборы с алишки


, но они все сделаны для стритсракеров и мало подходят для разумного примнения. До того момента как я понял на чём подобные приборы работают — думал заказать на пробу, разобрать и посмотреть. Но это не понадобилось, так как оказалось что сделать с нуля в общем будет проще.
Следующий вопрос — а что, собственно, показывать? Можно отображать разные метрики умного дома, с работы или домашней инфраструктуры, но такое слишком специфично. В итоге выбираем уровень CO2 — подходит отлично: таких исполнений датчиков просто нет (я не нашёл ни одного), данная метрика медленно меняется, автономна (можно измерять на месте), кроме того полезна — можно посмотреть когда пора-бы проветрить. У нас в офисе кстати постоянно спорят — надо ли открывать окна или нет, и такой девайс может разрешить подобные спорты путём прямого инструментального измерения. Я не буду в сотый раз расписывать — что такое измерение CO₂ и если тема для вас непонятна — почитать можно например тут. В качестве измерителя выбираем SenseAir S8, как самый авторитетный из народных. Почитать про него и сравнение с другими можно здесь. Ну и конечно же данный прибор может показывать что угодно, строго говоря CO₂ — только лишь пример, что-бы получить законченное устройство.
Когда пришла в голову идея создания нового прибора — казалось что всё просто, берём шаговый моторчик (серву?) и приводим в движение одним из миллиона способов. Но быстро стало понятно что серва не подходит — шумная, неточная и имеет слишком малый угол поворота. Довольно быстро я нагуглил что существует прям народный шаговый двигатель X27-168, точнее — целое их семейство. Довольно быстро нашёл пост замечательного парня guy.carpenter с экспериментами с драйверами данных двигателей. Данные моторчики широко применяются в различных девайсах, например популярны у симмеров. Так же, оказалось что их существует целое большое семейство — например есть варианты с 2-мя стрелками или датчиками нуля (варианты для часов).
Существуют целый семейство и множественные клоны специальных драйверов, которые реализуют алгоритм микростеппинга: когда одна команда от контроллера поворачивает привод не на одно деление (обычно это 1/3°), а на 1/12°. Так же в даташите написано что такой способ является предпочтительным — это повышает точность и уменьшает шум привода.
Для начала заказал сразу шесть моторчиков (комплект обошелся в 12€) и проверил их через рандомные H-Bridge драйвера. В принципе работает, но выглядит очень так себе — точность плохая, шум сильный. В итоге заказал обойму из 10 драйверов VID6608 и стал их ждать.

Первый прототип собрал на макетных платах и приступил к тестированию. В принципе, что-то уже работало, но тут было первое разочарование: собрав прошивку на коленке в platform.io с библиотекой от уважаемого guy.carpenter наткнулся на кучу багов и проблем. Пришлось их на ходу править, что довольно сильно затормозило процесс. В какой-то момент я пришёл к выводу что проще написать свою с нуля, чем разбираться в оригинальной — автор явно потыкался немного, а потом потерял к теме интерес.
С самого начала задумал использовать прошивку Tasmota как основу для девайса, т.к. содержит в себе уже всё что нужно и широко известна. Но тут меня ждало следующее разочарование, что в Tasmota имеется поддержка только H-Bridge драйверов для «обычных» шаговых двигателей.
Итого, формируем наш с вами план — как же нам собрать всё вместе?
- Добавляем поддержку инструментальных шаговых двигателей в Tasmota
- Находим подходящий корпус-донор (часы-будильник)
- Проектируем и заказываем печатную плату
- Проектируем и печатаем корпусные детали
- Придумываем подсветку как-нибудь
- Собираем это вместе и придумываем че-нибудь, что-бы это всё вместе заработало :-)
Добавляем поддержку инструментальных двигателей в Tasmota
Итак, раз решили — надо делать :-) Клонируем проект и погружаемся в документацию. На деле оказалось всё непросто: документация в принципе есть, но довольно отрывочная, пришлось выбрать парочку простых драйверов и использовать как живой пример. Посмотрел как сделано поддержка других библиотек — они просто закоммичены напрямую прямо в репозиторий, не как суб-модули или зависимости. В этот момент я решил что проще написать свою библиотеку и добавить её туда же + драйвер.
Про разработку особо не буду распинаться, сделано всё по образу и подобию уже существующей SwitecX25 — только без багов)) Отличия от старой:
- Поддержка управления только через драйвер VID6608 и им подобным — прямое управление бессмысленно, кмк
- Поддержка настроек кривых ускорения
- Поддержка выставления нуля из сохранённого положения
- Меньше вычислений на шаг, проще алгоритм управления
- Более точное соответствие даташиту, старая не заботилась о некоторых таймингах, которые требует даташит
В итоге появилась новая библиотека: arduino-vid6608.
Библиотека использует более простой алгоритм расчёта ускорения, где имеется статический массив расстояние-задержка, и до первой 1/2 пути происходит сравнение расстояния и рост скорости, на второй половине происходит замедление. Функции задания положения асинхронные, функция vid6608::loop() чувствительна к точности вызова функции обновления.
На видео пример работы алгоритма — прибор просто показывает случайные значения. В итоге оставил так — как по мне получилось достаточно реалистично при минимуме вычислений.
Далее выбираем следующий свободный Driver-ID в Тасмоте и занимаем его. Мне достался номер 92, в результате чего появился на свет драйвер xdrv_92_vid6608. Обратите внимание что реализация именно в виде драйвера общего назначения, изначально я думал сделать как display, но у данного класса драйвера нет достаточно точного тайминга для обеспечения плавного движения стрелки.
Сделав первую версию драйвера — сразу же сталкиваемся с двумя новым проблемами:
- Движение стрелки очень медленное — из-за того что функция цикла не вызывается в Tasmota с достаточным разрешением
- Функция выставления в ноль при запуске вызывает срабатывание Watchdog в некоторых случаях — из-за блокировки главного потока на слишком большое время
Решение первой проблемы очевидно: для ESP32 в Tasmota используется FreeRTOS из пакета разработки ESP-IDF, а значит что мы можем использовать примитивы и функции операционной системы реального времени. Собственно решение простое как полено: мы просто заведём обработку обновления в отдельный поток, который по-умолчанию уйдёт на второе ядро (мы будем ставить на плату двух-ядерную версию ESP32):
// Start background RTOS thread -> required for precision timing
xTaskCreate(
VID6608XvTask, /* Function to implement the task */
"VID6608XvTask", /* Name of the task */
1024, /* Stack size in words */
NULL, /* Task input parameter */
0, /* Priority of the task, lowest */
NULL /* Task handle. */
);
...
void VID6608XvTask(void *) {
while(true) {
...
driver->loop();
...
/*
If we dont need to move any -> go sleep.
This will delay next move begin up to 500ms, but freeds up CPU a lot.
*/
if (!needToMove) {
vTaskDelay(500 / portTICK_PERIOD_MS);
}
}
}
Хорошо, но данный трюк сработает только для ESP32, а для старой ESP8266 данное решение не канает. В итоге оставил как есть — я не планировал использовать ESP8266, и в принципе драйвер там всё равно работает — только довольно медленно: порядка 20 секунд на каждые 10 градусов движения. Этого всё ещё достаточно для отображения медленно изменяющихся параметров (такие например как температура или количество лайков к статье на муське).
Решение второй проблемы менее очевидно: надо просто добавить вызов функции yield() в процедуру выставления нужного шага:
void vid6608::step(vid6608::MoveDirection direction, uint16_t delayUs) {
...
// We should keep resources reserved by others
yield();
}
В этом случае даже многократный вызов в цикле не будет блочить нашу программу и мы избавимся от падения Watchdog.
Ещё хочу коснуться другой проблемы: тайминги. Для красивой отрисовки движения стрелки мы должны выдерживать тайминги вплоть до 0.3мс (300 мкс), что уже средствами таймеров FreeRTOS невозможно. Да, у них есть своя реализация delayMicroseconds(), но посмотрев в исходный код нас ждёт фрустрация: там просто цикл из nop-ов на нужное время. Что просто превращает в тепло время ожидания вместо таймеров. Проблема на данный момент не решена — если кто-то знает хорошее решение — пожалуйста напишите в комментах. Из хорошего: проблема не то что бы большая, она проявляется только во время активного движения стрелки и только на некоторых участках.
В любом случае: патчи успешно приняты в Тасмоту и баги поправлены:
- Добавление драйвера
- Исправление багов многопоточности (я забил на создание синхронизационных объектов, пока не собрал реальный девайс)
- Добавление поддержки сброса из сохраненного состояния и исправление багов по-меньше
На момент написания обзора драйвер уже включён в релиз Tasmota v15.2.0 Stephan. Обратите внимание что третий пакет изменений (сброс из сохраненного состояния) в релиз попасть не успел, так что база для прошивки пока что всё равно development.
Драйвер добавляет следующие команды:
- GaugeZero N — процедура калибровки, опциональная начальная позиция (см следующий раздел)
- GaugeSet N — выставить положение в абсолютном значении шагов мотора, от 0 до 3840 (320*12)
- GaugePercent N — выставить положение в процентах, от 0 до 100
Драйвер поддерживает до 4 двигателей. Все команды по-умолчанию управляют первым двигателем, могут быть с суффиксом мотора (от 1 до 4), при этом 0 — это все двигатели. Пример: «GaugeSet0 520» — выставит все двигатели в значение 520, «GaugeZero3» — сброс только мотора №3.
Калибровка привода
Это была одна из главных загадок для меня: я когда только заказал и сидел ждал моторчики, пытался нагуглить или выяснить — как же делают другие? На форумах симмеров предлагали всякие громоздкие решения типа оптических датчиков, а все остальные — просто ничего не писали про это. В старой библиотеке в исходном коде нашёл объяснение — там просто происходило движение назад на всю шкалу, что, видимо, приводило к торможению привода в крайнем положении, после чего текущее положение принималось за нулевое. Это действительно работает, но приводит к долблению нашего моторчика об концевые упоры — непорядок.
Собственно решение: а давайте просто будем запоминать текущее значение «куда-нибудь» и потом использовать его для калибровки. В этом случае можно просто продвинуть стрелку вперёд на остаток от последнего значения, а потом полный круг назад. Если стрелка была в рассинхроне с тем что у нас было записано, то в худшем случае произойдёт долбление либо в начале, либо в конце (смотря куда уехало реальное значение), но в итоге стрелка будет гарантировано в нулевой позиции.
Вопрос только — куда писать? Флеш не подходит, т.к. у него сильно ограничено кол-во записи. Но всё уже придумано до нас: это — сегнетоэлектрическая оперативная память (Ferroelectric RAM, FeRAM или FRAM) — оперативная память, по своему устройству схожая с DRAM, использующая слой сегнетоэлектрика вместо диэлектрического слоя для обеспечения энергонезависимости. Чип стоит недорого и обеспечивает до 10¹² циклов записи, этого должно быть достаточно для чуть больше 31 тысяч лет непрерывной работы при условии записи раз в секунду. Реализация очень простая — давайте просто поставим недорогой чип Fujitsu MB85RC04V FRAM на плату и будем писать туда каждый раз, когда стрелка принимает команду.
Пример восстановления из сохранённого состояния. Всё работает и не долбится где не следует :-)
Вообще, помимо FRAM существуют другие решения, например DRAM с бекапом во флеш при отключении питания и им подобные, но в данном случае это избыточно. Много запоминать нам и не надо, стоит недорого.
Аппаратная реализация
Итак, мы отработали основные идеи и можно приступать к дизайну электроники нашего девайса.
Внимание: я буду использовать схему с исправлениями оригинального дизайна. Вы можете заметить отличия от фотографий реального девайса, но схема уже содержит исправления косяков. Это сделано для простоты повторения. Оригинальные схемы могут быть найдены в репозитории, если вас интересует именно изначальное исполнение.
Заходим на EasyEDA и рисуем схему:

Основа для всего девайса — модуль ESP32-WROOM-32, двух-ядерный, 4Мб флеша. Вы, конечно, можете поставить любой другой в том же форм-факторе.
Схема сброса

Данная схема нужна для удалённого сброса кристалла из esptool без необходимости нажимать кнопки сброса/boot. Схема срисована с модуля ESP32-Devkit-v1. Реализует элемент ИЛИ-НЕ для обеспечения очередности сигнала сброса с DTR или RST. Это обеспечивает прошивку через подходящий USB-UART модуль в полностью автоматическом режиме.
Драйвер привода

Собственно — самое главное :) Драйвер привода, двух-канальный. В стоке девайс собран с одной стрелкой, но может быть оснащён двойной при необходимости. Чип не управляется схемой сброса с MCU, как это рекомендует даташит, так как у меня чипы с алишки VID6608 реагировали неадекватно — возможно не-оригиналы :) В любом случае, прижать резет к питанию и поставить рекомендуемые конденсаторы — базовый минимум, работает как надо тогда.
Разъём расширения

На данный разъём выведены GPIO 4, 13 и 25 а так же шина I²C, к которой можно подключить дополнительные датчики или исполнительные устройства, например часы. Присутствует питание и земля.
Схема памяти положения привода

Выполнена на I²C кристалле FRAM памяти MB85RC04V, производства Fujitsu. Имеет на борту 4Кб памяти — довольно скромно по нашим меркам, зато недорого и работает :)
Всё остальное
Дальше ничего особо интересного нет, от модуля разведены:
- Кнопка сброса для ручного привода EN. Сбрасывает кристалл при необходимости. Для отсутствия сброса без необходимости предусмотрены цепи подтяжки и конденсатор против дребезга.
- Кнопка GPIO34: настроена как «Кнопка 0» в Tasmota. При однократном нажатии включает/выключает подсветку, при зажатии на 45 секунд сбрасывает настройки и активирует первоначальную настройку через точку доступа.
- Кнопка boot: зажимает GPIO0, переводит в режим прошивки, если нажата одновременно с EN. Данной кнопки нет на фотографиях, добавлена позже.
- Датчик SemseAir S8, подключён к GPIO 16 и 17 для коммуникации, порт калибровки подключён к GPIO 19
- Модуль ANT20+BMP280, подключён к I²C, измеряет температуру, влажность и давление. Является опцией, при отсутствии данных просто не будет.
- Управление подсветкой «ретро» выполнена на схеме биполярного транзистора с открытым затвором — может управлять чем-то ещё разумеется
Печатные платы
Заказываем и ждём :) У меня случилось что-то с доставкой и я получил платы только недели через три с извинениями. Платы заказаны с установкой деталей с одной стороны, без модуля ESP32 (они у меня были отдельно, плюс я не был уверен что не наделал косяков).

Народные x27-168 и им подобные рекомендуют закреплять мотор посредством пайки. Хорошая идея, в общем, но требует отдельную печатную плату. Для установки двигателя в корпус сделал простой вариантик с выводами как под разъем, так и под пайку.
Собираем и проверяем — всё почти работает :) У первой версии был один косяк — у кнопки 0 не стал ставить подтяжку, т.к. в документации Tasmota утверждалось что при такой конфигурации используется внутренний резистор подтяжки в MCU. Но нет, нифига. Если оставить болтаться в воздухе то кнопка срабатывает, что может приводить к сбросу настроек (при «нажатии» на 45 секунд). Но благо поправить очень просто — кидаем выводной резистор поверх и готово.


Основная плата для привода в EasyEDA Web: oshwlab.com/petrows/galoped-dekad
Breakout плата для привода в EasyEDA: oshwlab.com/petrows/galoped-dekad-drive
Корпус прибора
Это, наверное, самое важное. В этом разделе мы определим — будет ли наш прибор выглядеть как колхоз или же как что-то приличное. Разумеется, корпус можно полностью сделать на 3D-Принтере, но я эту идею отбросил сразу, по бокам будет видно что корпус печатный, а хотелось что-то более няшное, а значит — покупное и фабрично сделанное. Кроме того, у нас в требованиях пунктик что девайс должен быть простой в повторении. Следовательно, Aliexpress подходит тут слабо — у продавцов часто фактические изделия отличаются в зависимости от времени и может не соответствовать картинке. Ну и внутренности тоже могут быть разных ревизий, а нам надо что-бы всё влезало хорошо.

Начать решил с Ikea. Доводы такие: икея распространена по всему свету и у них изделия строго одинаковые везде. Следовательно, сделать себе такой прибор можно будет практически везде, купить икеевскую штуку можно даже там, где Икеи нет. Посмотрел что у них есть и выбрал Ikea Dekad. Это единственное что подходило более-менее.


Я хочу сказать что этот лот с самого начала мне не очень понравился, думал что будут сложности. Но как же я ошибался! Девайс просто как будто придуман для самоделок. Красивый и ровный корпус, очень технологичный — минимум лишнего, внутри всё на болтах. Циферблат, рамка и стекло — отдельные детали, что позволяет развернуться полёту мысли. Сверху имеется дырка для привода звонка — который электрический и приводится в действие электромотором. Его можно оставить и например удивлять пользователя громким звонком, если CO₂ высоковат. Но я решил что это будет перебор :)

От оригинального будильника нам понадобится: собственно корпус, стекло, рамка (я так думал тогда, на самом деле — не совсем), гайки и ножки из нержавейки, а так же пипка от стрелки — мы её запрессуем в нашу.
Что мы узнали на данном шаге:
- Габариты прибора: цилиндр примерно 95 на 50 мм
- Диаметр шкалы
- Название приобретает суффикс от своей сущности: Galoped-dekad
Циферблат
Лицо нашего прибора — тут всё должно быть максимально по красоте. У меня ушло на это больше времени чем планировалось. Начал с того что нашёл видео, где мужик делает круговую шкалу в Inkscape. Сделал по аналогии — у меня только более свежая версия, там были небольшие отличия. У меня ушло много времени что бы разобраться — для того что бы модификатор «Шаблон по кривой» работал — ваш образец кусочка шкалы должен быть одной целой кривой, тогда всё делается правильно. Документ делаем сразу под будку само-обслуживания фото-печати, под 10х15.

Открываем фотку авиационного прибора — нашего талисмана и вдохновляемся :) На самом деле на дизайн ушло несколько дней, плюс я его в процессе несколько раз менял — поменял отображение мертвой зоны, зеленые и красные секторальные линии сделал более похожими на реальный прибор.

И, сразу делаем версию ретро:

Для дизайна шкалы мы должны определить минимальные и максимальные значения. Смотрим на даташит на наш моторчик x27.168 и видим что полный оборот — это 315° (на самом деле 320°, но на момент дизайна шкалы я этого не знал). Теперь прикидываем: у нас есть 315*12 шагов, надо захватить примерно подходящий диапазон и минимизировать вычисления (особенно деление). Так же нужно сделать небольшую «мертвую зону» (для индикации не-готовности прибора). Рассчитываем: оставляем 15° на отображение мертвой зоны, итого у нас остаётся 300° значащего диапазона. Разбиваем его на 18 кусочков, получается что мы можем отобразить от 400 до 2200 ppm, а самое главное, что при этом получаем ровное соответствие:
(300*12) / (2200-400) = 2, то есть у нас получается ровно два шага привода на 1 ppm. Это очень удобно, потому что тогда переводить одно значение в другое можно просто сдвигом на 1 бит влево или вправо, что гораздо быстрее других математических операций в MCU. Ну и у нас остаётся так же лишних 5° за пределами шкалы (и даташита) — но я просто забил на это, т.к. узнал об этом я гораздо позже и не стал ради этого переделывать. Но то значение обязательно надо учитывать при калибровке.
Идём в DM и печатаем нашу чудо-полиграфию в будке. У нас это удовольствие стоит примерно 30 копеек при печати малыми тиражами. У нас при печате в будке есть только глянцевая фото-бумага, матовую надо заказывать. Я думал что это проблема, планировал сбрызнуть матовым лаком — но это не нужно, всё выглядит супер и так.

Дальше сталкиваемся с проблемой — а как нам сделать красивую дырку в центре, что бы это не выглядело как колхоз? Я пытался просверлить или прорезать, получилось так себе. В итоге решение пришло такое — я заказал на Amazon пробойники для кожи. Просто пробить молотком получается плохо, но если зажать пробойник в патрон шуруповерта и «просверлить», то получается идеально ровное и красивое отверстие.
Подсветка
Вот тут я больше всего провозился в итоге. Изначально план был простой — в Икеевском будильнике штатная рамка как будто прям сделана для подсветки, она полу-прозрачная, изнутри накатка — выглядит супер. Но на деле оказалось всё не так просто.

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

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

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

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

Пример рамки из «прозрачного» пластика, как видите тоже — так себе. В этом разделе довольно кратко, но я напечатал и проверил кучу вариантов, с диодами внутри кольца, снаружи, ближе к стеклу и циферблату — результат плохой.

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

На фото пример с RGB лентой, изолентой и промежуточной черной рамкой. Подробности можете посмотреть на 3D моделях. Филаментная лента встаёт в ту же рамку без модификаций.

Адресуемые диоды так же поззволяют делать разные эффекты, например секторальную подсветку или менять цвет в зависимости от показаний прибора. Секторальная смотрится в целом плохо — она даёт яркий блик на противоположную сторону прибора.
В итоге оба варианта подсветки ставим в двух-составное кольцо, каких-либо эффектов в стоке предоставлять не будем, вкл-выкл да регулировка яркости. Тут конечно есть ещё много чего подумать, но думаю отложу пока до следующих версий.
Корпусные детали
Теперь самое время сделать пластиковую часть нашего чудо-прибора. Большая часть видимой компоненты (корпус, циферблат) у нас уже выглядят хорошо, осталось только позаботится о задней стенке, стрелке и закрыть дырку наверху корпуса (от механизма звонка). Открываем FreeCAD и приступаем к черчению наших деталей. Кстати, я думал что довольно неплохо знаком с данной CAD-Программой, но решил перед началом посмотреть обучающие видео, нашёл канал Димы Гога тоже из Германии, и просто офигел — я не знал можно сказать ничего. Большое спасибо ему, я сделал всё что нужно гораздо быстрее. Всем очень рекомендую, кто хочет научится делать красивые детали быстро и эффективно.
Стрелка
Итак, шкалу сделали, но что по ней ездить должно? Я над этим долго думал, гуглил по форумам. Там предлагают много чего — вырезать из старой карточки, пробивать, выпиливать руками из металла. Я решил всё-таки попробовать напечатать аккуратно на 3D принтере с максимальным разрешением. Если печатать вверх ногами на хорошей подложке то поверхность получается ровной, по ней даже не видно особо — что она печатная. Я в процессе поиска оптимальной формы и технологии сделал наверное штук сто этих стрелок, они у меня теперь валяются повсюду.

У меня есть любимый лак из Lidl — краска для глушителей. Она даёт прикольную матовую поверхность, я сразу решил черную часть стрелки сбрызнуть именно им. Печатаем, красим — сначала попку, потом саму стрелку белым лаком, который подрезал у своей Фрау.

Получается примерно так. Я изначально хотел заморачиваться с краской, которая в темноте светится, но потом не стал делать — лучше сделать подсветку всего прибора. Так что просто красим доступными красками / лаком и получается хорошо.

Теперь важный момент — берем оригинальную пипку от икеевского будильника, сверлим 1.8мм дырку в стрелке и запрессовываем в тисках пипку в нашу стрелку. Получается здорово — наша стрелка выглядит уже почти как настоящая в самолёте. Кроме того — она идеально плотно насаживается на вал мотора, ничего мудрить с креплением не надо. Ретро-версия стрелки выглядит почти так же и не окрашивается вообще, печатаю сразу черным пластиком.
Интерьер
В целом, прибор состоит из деталей: рамка (если комплектация с подсветкой, иначе используем оригинальную ikea), передняя панель с седлом для мотора и платы, задняя крышка, крышечьки для датчиков S8 и Климата (если устанавливается).


Вот так выглядит сборочный чертёж. Совмещаем детали, крутим-вертим и смотрим — что-бы все дырки совпадали, ничего не мешало друг другу. Из хитрого оказалось только разве что вычислить — где точно находятся дырки крепления в икеевскоом корпусе: они разнесены на 30° и 34° от вертикальной оси.

Отдельно пришлось повозиться с крышечьками — для датчиков S8 и климата. В итоге остановился на таком — крышка S8 вставляется изнутри и держится просто прижимом (или можно капнуть клея для верности), датчик климата ставится на болты к крышке. Так как оба датчика — опция, то крышки могут не устанавливаться (у меня пока что никто не просил версию без измерения CO₂ на борту, в этом случае надо будет сделать особую крышечьку — или просто удалить дырку под него).

Так же на этом этапе генерим 2D-чертеж, для инструкции для будущих пользователей :) Я для этого создал Page во FreeCad и разместил там нужный View с изометрическим видом продукта, осталось только экспортировать куда следует.

Печатаем все детали, снмиаем и очищаем. Прототипы делал из PLA. Все детали финального устройства печатал пластиком PETG черного цвета, рамка подсветки из «прозрачного». Корпусные детали и рамки — 0.2 мм слой, заполнение 20%, обдув 20%. Крышечьки датчиков и стрелка — 0.1 мм слой. Обязательно включите ironing для получения красивых плоских поверхностей, особенно которые торчат наружу.
Крепёж
Изначально я всё собирал на саморезах М2.3 для пластика, но быстро надоело — выглядит хуже, вопросы к прочности, добавляет «дешевизны» к виду нашего серьёзного спец-изделия. Специально для устройства обзавелся болтами М2 и М3 с головкой под шестигранник из нержавеющей стали. Крепление в пластик будет на вплавляемые втулки — просто изумительная штука оказалась, как я без них жил раньше?

Винтики выглядят куда более солидно, придаёт ещё немножко «авиационного» стиля. Кое-что нужно взять от икеевского будильника (гайки и шайбы М3, пару саморезов М2 для врепления USB-C порта, если у вас нет своих).
Окончательная сборка продукта
Итак, давайте теперь соединим всё вместе! Наконец-то увидим, что за франкенштейн у нас тут получается. Выбираем комплектацию для сборки: Авиационный стиль, подсветка ламповая, оба датчика установлены.

Для сборки у нас уже должны быть все детали, что остались от предыдущих шагов или изысканий. Ну или просто печатаем новые на 3D и 2D принтерах, заказываем платы, разьёмы, провода. Раскладываем это всё на столе и любуюмся. Для сборки нужно вообще следующее:
- Будильник Ikea DEKAD
- Печатные детали: передняя и задняя крышки, верхняя крышка, крышечька датчиков CO₂ и климата, две детали рамки подсветки
- Крепёж: Винты M3 (2 шт), Винты M2 (10 шт), Втулки для пластика M2 (10 шт)
- Филаментная лента подсветки (26 см или длиннее) и провода к ней
- Печатные платы: основная и двигателя
- Двигатель X27-168, выводы на задней стороне
- Модуль ESP32-WROOM32E (4Mb)
- Чип VID6608
- Датчик SenseAir S8
- Датчик климата — AHT20 / BMP280 модуль
- SMD кнопки 3х6, высота любая — у меня 4.5 мм
- Разъёмы JST-PH 2.54 и провода: 2-pin (2 шт), 4-pin (1 шт). Мне обжимать впадлу, взял уже обжатые
- Разьём питания USB-C
- Провода, гребенки, паяльник, хорошее настроение и решительность :)

Первым делом устанавливаем кристалл ESP32. Я заказывал без установки оного, т.к. у меня они были и не хотел рисковать возможным браком. Потом всё проклял — установка лютый геморрой, один модуль запорол. Заказывайте установку на заводе вместе с платой — будет тоже самое по цене и гемора намного меньше.

Сразу после установки важно проверить работоспособность — заливаем прошивку и проверяем что прибор приходит в сознание. Можно залить любую Тасмоту, потом закатаем что нужно по воздуху. Я использую данный адаптер, он имеет нужные выходы RST и DTR (обратите внимание что DTR вынесен на боковую гребенку — я сначала тупил и перепутал его с CTS и испортил одну плату, думая что сотворил непотребное). В этом случае чип прошивается напрямую через esptool или platform.io. Если такого адаптера нет, то подойдёт любой, главное что бы был совместимый с 3.3В, контакты для входа в режим прошивки коротите тогда руками. Питание лучше подавать внешнее — 3.3В в моей версии отладочного разьёма от адаптера хватало для прошивки, но уже не хватало для первого запуска. В вашей версии платы эта проблема решена (выведено 5В), но в любом случае лучше внешнее питание рекомендуется — вдруг что. В этом случае подключаем только землю от адаптера, иначе можно попалить.

Ура! Кажется что мы ничего не запороли. Пока что :)

Запаиваем остальное — разъёмы и собсвтенно нашего героя дня — VID6608. Его ставить куда легче чем ESP32, накосячить сложнее. Обязательно прозванивайте ноги после установки! У меня всё выглядело супер, но половина ног на деле не звонилась. Если плохо припаяли то будет выглядить так: привод будет дергаться хаотично вместо плавного движения. Устанавливаем всё остальное — разъемы кнопки и прочее.

Устанавливаем гильзы под винты M2. Установка очень прстая — ставим на отверстие и вдавливаем пяльником, всё получается ровно и красиво.

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

После установки привода можно вырезать и приклеить лицевую панель. Подготавливаем стрелку, прессуем в неё пипку и красим. После этого можно собрать всё вместе.

На данном этапе нам важно выставить стрелку точно в ноль. Для этого натягиваем стрелку как получится (ставится она очень туго, не стесняемся), потом проворачиваем моторчик до упора (без сигнала он свободно крутится) в нуль и проворачиваем аккуратно стрелку, пока она не будет точно в начале мертвой зоны, это истинный ноль шкалы.

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

Готовим филаментную ленту — припаиваемся к выводам под прямым углом и мастрячим разьём. У меня так же припаяна корректирующая цепь: редистор на 220 Ом и конденсатор подавления пульсаций. В версии платы, что вы увидите в EasyEDA данные детали уже установлены (на момент создания самой первой версии я ещё был в сомнениях по поводу подсветки).

Устанавливаем ленту в рамку, лучше всего развернуть её «мутной» частью внутрь. Для удобства можно подклеить прозрачным скотчем. Так же подкладываем немного скотча между лепестками контактов для изоляции, нормально запихнуть в теормоусадку нет места. Подрезаем ленту так, что бы ровненько сходилось — у нас тогда будет минимальный темный кусочек подсветки.

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

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

Подсоедияем все разьёмы и устанавливаем основную плату, ориенируем её датчиками вниз. Закручиваем всё красивенькими винтами М2.

В задней крышке привинчиваем разьём USB-C на шурупчики, просунув его изнутри. Можно использовать оригинальные серебристые Ikea от будильника, но у меня есть анодированные черные, они выглядят получше. Устанавливаем решётку датчика S8, сам датчик и помещаем крышку на место, прикручиваем всё на два винта М2.

Натыкаем наш климатический датчик на разьём и прикручиваем крышечьку сверху на ещё два болта М2. Сборка завершена :-)

Отдаляем на расстояние вытянутой руки, включаем и проверяем что всё работает. Обратите внимание что без начальной конфигурации прибор даже не будет вызывать калибровку «из коробки», нам необходимо настроить Тасмоту и подготовить агрегат к работе.
Конфигурация
Первым делом надо настроить наш «модуль». Какие ноги где сидят и что делалют. Для упрощения жизни я сделал темплейты (версия для RGB и Ламповых подсветок): отличия в одной ноге — она либо на WS2812B либо на транзистор диммера ламповой. Шаблон можно применить руками, но удобнее это сделать сразу в прошивке. Кроме того, нам понадобится парочка #define: по-умолчанию у Тасмоты нет поддержки ни AHT20, ни моего замечательного драйвера. Создаём файл tasmota/user_config_override.h:
// Required features for this project:
// [I2cDriver43] Enable AHT20/AM2301B instead of AHT1x humidity and temperature sensor (I2C address 0x38) (+0k8 code)
#ifndef USE_AHT2x
#define USE_AHT2x
#endif
// [I2cDriver10] Enable BMP085/BMP180/BMP280/BME280 sensors (I2C addresses 0x76 and 0x77) (+4k4 code)
#ifndef USE_BMP
#define USE_BMP
#endif
// Add support for SenseAir K30, K70 and S8 CO2 sensor (+2k3 code)
#ifndef USE_SENSEAIR
#define USE_SENSEAIR
#endif
// Add support for VID6608 Automotive analog gauge driver (+0k7 code)
#define USE_VID6608
// Reset VID6608 on init (default: true), change if you control this manually
#define VID6608_RESET_ON_INIT false
// Enable WS2812 leds number (any HW model)
#undef WS2812_LEDS
// If RGB backlight is used, it will have 40 LED's
#define WS2812_LEDS 40
// Template defaults, apply on flash reset.0
// You may skip this templay application, in this case please apply manually (see README.md)
// Read from file, generated by ./bin/build.sh or CI
#include "user/user_config_hw.h"
// Activate template on reset/flash new
#undef MODULE
#define MODULE USER_MODULE
Так же, для выбора уже конкретной комплектации выбираем один из двух вариантов в виде файла tasmota/user/user_config_hw.h:
/*
Part for Galoped-dekad hw version:
* Backlight: Retro
*/
#undef FRIENDLY_NAME
#define FRIENDLY_NAME "Galoped-dekad-retro"
#define USER_TEMPLATE "{\"NAME\":\"Galoped-dekad-retro\",\"GPIO\":[1,1,1,1,1,1,1,1,1,1,416,0,1600,1632,1,1,0,640,608,1,0,1,12160,12192,0,0,0,0,1,1,32,1,1,0,0,1],\"FLAG\":0,\"BASE\":1}"
, это было для ламповой, для RGB:
/*
Part for Galoped-dekad hw version:
* Backlight: RGB
*/
#undef FRIENDLY_NAME
#define FRIENDLY_NAME "Galoped-dekad-rgb"
#define USER_TEMPLATE "{\"NAME\":\"Galoped-dekad-rgb\",\"GPIO\":[1,1,1,1,1,1,1,1,1,1,0,1376,1600,1632,1,1,0,640,608,1,0,1,12160,12192,0,0,0,0,1,1,32,1,1,0,0,1],\"FLAG\":0,\"BASE\":1}"
Как видите — отличие в одном пине и названии модуля — что бы не забыть :) Теперь можно собрать прошивку. Для ленивых: идём в раздел Releases моего проекта и качаем там готовую.
Остались уже совсем мелочи: надо всё проверить и присоединить стрелку к показаниям CO₂. К счастью, в прошивке ничего даже модифицировать не надо — у Tasmota имеется Berry script в версии для ESP32, так что просто напишем скриптик и закинем в агрегат. Для автозапуска надо именовать данный чудо-файл как autoexec.be:
# Connect and preare i2c FRAM MB85RC04V
var fram_addr = 0x50
var wire = tasmota.wire_scan(fram_addr)
# Address in FRAM to store last gauge position
var addr_pos = 0x0000
# Check initialization
if !wire
print("FRAM not found")
end
# Function to write FRAM memory, 2 bytes
def fram_write_u16(addr, data)
if !wire
return 0
end
# Split address and data into two bytes
var addr_hi = (addr >> 8) & 0x7F
var addr_lo = addr & 0xFF
var data_hi = (data >> 8)
var data_lo = data & 0xFF
# ---------------- WRITE ----------------
wire._begin_transmission(fram_addr)
wire._write(addr_hi)
wire._write(addr_lo)
wire._write(data_hi)
wire._write(data_lo)
wire._end_transmission(true)
end
# Function to read FRAM memory, 2 bytes
def fram_read_u16(addr)
if !wire
return 0
end
# Split address and data into two bytes
var addr_hi = (addr >> 8) & 0x7F
var addr_lo = addr & 0xFF
# ---------------- READ ----------------
wire._begin_transmission(fram_addr)
wire._write(addr_hi)
wire._write(addr_lo)
wire._end_transmission(true)
wire._request_from(fram_addr, 2)
var value_hi = wire._read()
var value_lo = wire._read()
var value = (value_hi << 8) | value_lo
return value
end
# Read last gauge position from FRAM
var last_gauge_pos = fram_read_u16(addr_pos)
if last_gauge_pos
print("FRAM gauge pos read:", last_gauge_pos)
end
# Call Reset option from saved position, and save zero
tasmota.cmd("GaugeZero " + str(last_gauge_pos))
fram_write_u16(addr_pos, 0)
# Function to update Gauge position on CO2 change
def co2_update(value, trigger)
var drivePos = 180 + ((int(value) - 400) * 2)
if last_gauge_pos != drivePos
tasmota.cmd("GaugeSet " + str(drivePos))
last_gauge_pos = drivePos
# Save current position into FRAM
fram_write_u16(addr_pos, int(drivePos))
end
end
# Add rule to monitor CO2 changes
tasmota.add_rule("S8#CarbonDioxide", co2_update)
Данный файл в репе. Функционально состоит из двух частей — чтение / запись в FRAM и функция чтения показания CO₂:
tasmota.add_rule("S8#CarbonDioxide", co2_update)Данный вызов вешает вызов кэллбека co2_update при обновлении. Как видите — проще некуда. Теперь наш прибор ожил и будет что-то показывать.

Так же прибор должен показывать показания датчиков и положение стрелки в веб-интерфейсе. В зависимости от комплектации будет либо диммер «ламповой» подсветки, либо выбор цвета для RGB. Дальше уже дело техники — следуйте инструкциям Tasmota что-бы настроить интеграцию в Умный Дом и прочее, наша прошивка отличается только базовой конфигурацией и все фичи доступны.
Стоимость прибора
Точную стоимость сильно зависит от кол-ва изготавливаемых экземпляров и что у вас есть уже в наличии. В моём случае чисто по железу получилось порядка 50€ за прибор, и это при условии что 3Д-принтер у меня свой и корпусные детали получаеются условно-бесплатные. Если кому-то нужен точный расчёт то пишите в каменты — добавлю в обзор.
Выводы и мысли на будущее
Вот такое у нас с вами получилось чудо техники — что думаете по поводу?

И руки размяли и подарить не стыдно. Ну и ещё в Тасмоту хороший драйвер добавили. Вообще, устройство конечно легко кастомизируется и адаптируется под суровую реальность:
- Внешний вид: я написал имена людей на циферблате (кому дарил) — получается прикольный подарок в виде уникального гаджета, который в магазине не купишь;
- Прибор конечно может показывать что угодно, как с датчиков, так и с внешнего управления; Тут уже на что хватит воображения — температура, влажность, черти в ступе или остаток рабочего дня на сегодня
- На плате имеется разьём расширения, который может в себя принять в общем что угодно — I²C датчики, дисплеи и прочее;
- Плата может управлять двумя двигателями — как одним сдвоенным с двумя стрелками, так и двумя отдельно;
- Можно докинуть ещё одну VID6608 или заменить на VID6606 — в этом случае можно будет рулить сразу 4-мя приводами;
- Можно управлять оригинальным мотором будильника и громко звонить когда надо :-)
Что думаю надо бы в будущем улучшить (возможно когда вычитаете этот обзор то уже что-то сделано, см обновления в репе):
- Думаю что надо-бы добавить работу с FRAM в саму Тасмоту, это неудобно что мы читаем-пишем в скрипте, думаю можно сделать автоматическую запись и чтение при калибровке. Но вот не уверен что такое примут — наверное такой патч слишком уж специфичный;
- Надо разделить один 8-пиновый разьём для двух двигателей на два по 4: такое решение оказалось очень неудобное;
- Разъёмы все надо перевернуть на 180°, оказалось что невозможно поставить угловые при текущей компоновке — так было бы удобнее;
- Идея с Breakout-board для двигателя оказалось не очень хорошей — это сильно усложняет конструкцию и вообще бестолковое решение. Думаю хорошая универсальная печатная крышечька с креплением проводов напрямую будет получше;
- Надо-бы добавить индикацию статуса какую на плату, а то юзеру невозможно понять — она живая там вообще или нет;
- Использованный USB-C коннектор работает только с USB-A-C кабелем, USB-C-C не подходит. Не критично, но безусловно минус;
Исходники проекта: github.com/petrows/smarthome-galoped-dekad. В репе сейчас небольшой бардак из тестовых деталей и нет нормального Readme — не было времени прибраться, наведу порядок чуть позже. Но всё тем не менее есть.
Если у вас ещё есть хорошие идеи — делитесь, прикрутим. На этом всем желаю хорошего дня.
Самые обсуждаемые обзоры
| +27 |
1045
44
|
| +31 |
1194
28
|
© «ДМБ»
За подход отдельный респект, оверинжиниринг дикий, конечно, но мне-ли судить, создателю камина с деталями от 3d принтера)))
А читал окол 30 минут и понял, что я сдаюсь :)
Дочитаю позже. Это надо осмыслить…