
С каждым днём всё ближе обжигающее японское лето, поэтому я всё больше думал о своей давней идее: дистанционном управлении кондиционером воздуха в моей спальне через Интернет. Простым нажатием кнопки за десять минут до отправления ко сну я мог бы включить кондиционер, который бы превращал спальню в прохладный комфортный оазис к тому моменту, как я почищу зубы и поднимусь на второй этаж. В прошлом году это так и осталось идеей; в этом году я довёл её до реализации.
Хотя идея дистанционного управления кондиционером далеко не нова (многие уже проложили этот путь до меня, став для меня источником вдохновения), я считаю, что моя реализация достаточно уникальна.
Самым простым было купить необходимые компоненты — Raspberry Pi Zero WH и Infrared Transceiver Hat; нетерпеливо ждать их оказалось уже не так легко.
После получения заказа я осознал, что transceiver hat прибыл без самого инфракрасного датчика и инфракрасных диодов, поэтому мне пришлось заказать необходимые компоненты с Amazon, самостоятельно припаять их и убедиться, что я могу получать инфракрасный сигнал в Raspberry Pi OS при помощи команды LIRC с интуитивно понятным названием
mode2
.
На этом этапе мне нужно было принять важное решение: насколько амбициозным я хочу сделать проект? У меня было четыре варианта.
Первая сложность связана с сигналами пульта кондиционера. В отличие от пультов телевизоров или ламп, которые обычно отправляют при каждом нажатии на кнопку один и тот же сигнал, позволяя приёмнику интерпретировать и согласовывать состояние, пульты кондиционеров сами хранят состояние и при каждом нажатии кнопки передают целиком обновлённое состояние. Возникает вопрос: устроит ли меня простая запись и воспроизведение нескольких известных состояний пульта, или я хочу погрузиться глубже — декодировать, проанализировать и воспроизводить сигнал любого нужного состояния?
Вторая сложность связана с развёртыванием веб-сервера, предоставляющего интерфейс пользователя для управления кондиционером. Выбрать ли мне простое развёртывание веб-сервера Phoenix на Raspberry Pi OS или пойти поболее сложному, но, безусловно, и более крутому пути связывания Phoenix с Nerves?
В обоих случаях я выбрал вторые варианты, более безумные, но и, бесспорно, более впечатляющие. Давайте сначала поговорим о Nerves.

[1] Примечание: изначально я припаял только один IR-диод, потому что так выглядели платы во всех статьях, которые я видел в Интернете. Результат меня разочаровал, потому что плата никак не реагировала на мои команды. Расстроившись, я наудачу прикрепил ещё один диод, даже не припаяв его, ни на что особо не надеясь. Затем я проверил диоды объективом своего iPhone и, к своему искреннему удивлению, увидел, что они оба испускают инфракрасное излучение. Думаю, это связано с сектором
SJ1
, соединённым каплей припоя на большинстве плат, но не на моей; впрочем, эту теорию я не проверял.▍ Elixir на встроенных системах
Nerves — это одна из самых существенных библиотек Elixir. Phoenix позволяет писать веб-серверы, превосходящие по скорости гепарда, Ecto позволяет общаться с широким спектром баз данных, а Nx позволяет подчинить себе мощь машинного обучения и искусственного интеллекта. Nerves же позволяет беспроблемно развёртывать Elixir на встроенных устройствах, например, на Raspberry Pi. И у меня наконец-то появилась возможность воспользоваться ею!
Nerves объединяет ваше приложение с урезанным ядром Linux и несколькими необходимыми утилитами в прошивку, которую можно «прожечь» на карту microSD, что позволит встроенному устройству напрямую загружать BEAM (Erlang Virtual Machine). Такой минималистичный подход, в отличие от развёртывания приложения Elixir в полнофункциональной Raspberry Pi OS, обеспечивает множество преимуществ:
- Весь бандл операционной системы и приложения занимает десятки, а не сотни мегабайтов[2]; [2] К тому же он потребляет микроскопический объём памяти.
- система загружается и делает приложение доступным за секунды, а не за десятки секунд;
- обновления приложения и его зависимостей обрабатываются как часть вашего кода, а не через медленный и сложный в воспроизведении менеджер пакетов;
- благодаря малому количеству ПО вектор атаки существенно меньше;
- вместо работы с системами init Linux вы определяете приложения Erlang;
- при этом всё равно сохраняется способность ядра Linux взаимодействовать с оборудованием через драйверы Linux.
Создание и запуск базового приложения Nerves оказались очень лёгким процессом, зато гораздо сложнее было заставить работать в Nerves инфракрасный приёмник и передатчик; недостаточно было просто выполнить
apt install lirc
и отредактировать config.txt
, как в Raspberry Pi OS.К счастью, Nerves может похвастаться потрясающей документацией, помогающей в течение всего процесса настройки системы. Даже несмотря на то. что в половине случаев я почти не понимал, что делаю, мне удалось
упаковать lirc-tools
в пользовательское пространство, внедрить поддержку инфракрасного пульта управления в ядро Linux и настроить свой проект Nerves на работу с этой операционной системой. Но потом… ничего не произошло, устройства /dev/lircX
не стали доступны сразу волшебным образом.Оказалось, что нужно было выполнить ещё несколько шагов и преодолеть ещё несколько препятствий. В частности:
- для начала нужно было
переписать стандартный fwup.conf
, чтобы позже можно былопереписать стандартный config.txt
и загрузить мой device tree overlay; в результате выполнения этого шага я получил доступ к крайне необходимым устройствам/dev/lirc0
и/dev/lirc1
; - заменить
поломанный плагин default.so
LIRC на тот, который я вежливоукралпозаимствовал из моей предыдущей установки Raspberry Pi OS; очевидно, что это некорректный способ решения проблемы, поэтому я сообщил о баге разработчикам Nerves, но он может быть актуальным, пока разработчики это не исправят; - создавать при запуске
папку /var/run/lirc
, чтобы LIRC мог создавать свои файлы сокета и PID, а затем воспользоваться MuonTrap для запускаlircd
— это гораздо проще, чем работа с системой init!; -
сконфигурировать параметры LIRC, наложив
overlayfs
поверх стандартной файловой системы; -
переопределить erlinit.config
так, чтобыtmpfs
монтировалась в/etc/lirc/lircd.conf.d
с возможностью записи — Nerves монтирует рутовую файловую систему в режиме «только для чтения», поэтому это необходимо для создания конфигураций LIRC на лету!
Закончив с этим, я приступил к написанию простого декодера сигналов, который должен превращать вывод команды LIRC
mode2
в строку CSV; затем можно будет импортировать её в Google Sheets для анализа!
▍ Взламываем код
Прочитав упомянутые выше статьи, я начал догадываться, что инфракрасный сигнал пульта закодирован модифицированной версией [3] протокола NEC. Этот протокол представляет двоичный ноль в виде последовательностей кратковременных импульсов (562,5 мкс), за которыми идёт короткая пауза, а двоичную единицу — в виде последовательностей кратковременных импульсов, за которыми следует длинная пауза (1,6875 мс) [4].
[3] Модифицированной, потому что, по крайней мере, согласно найденной мной спецификации, протокол NEC достаточно строго относится к общей структуре сигнала; он начинается с пакета импульсов 9 мс, за которым идёт пауза 4,5 мс; затем следует сочетание
address
и address’
(логической инверсии), а заканчивается сигнал command
и command’
. Ничто из этого не оказалось применимо к сигналу, генерируемому пультом моего кондиционера: вначале шёл пакет импульсов 4,5 мс и пауза 4,5 мс; address
и address’
присутствовали только в первых двух датаграммах, но отсутствовали в третьей; вместо одного блока из command
и command’
было два блока команд, а в некоторых ситуациях второй блок command’
заменялся другой структурой (иными словами, Toshiba отказалась от блока чётности command’
и использовала этот раздел под другие цели).[4] Кстати, именно из-за этого строгого тайминга мне пришлось использовать LIRC для отправки сигналов с моей стороны. Когда я попробовал передавать сигнал при помощи только одного кода Elixir, мне не удавалось подобрать тайминг достаточно верно.
Благодаря упомянутому в предыдущем разделе декодеру (позже исправленному, чтобы он различал части начала и конца блока) мой процесс работы стал похож на нечто такое:
- открываем SSH-подключение к моему приложению Nerves, чтобы получить доступ к приложению через IEx shell, не в
bash
или чём-то подобном; - вызываем функцию моего декодера, которая использует MuonTrap для запуска
mode2
, 3 секунды ждёт вывода, а затем прекращаетmode2
(mode2
выполняется бесконечно, но меня интересует сканирование только одной команды за раз); - нажимаем кнопку на пульте дистанционного управления кондиционером для сканирования отправляемого кода; делаем упор на внесение наименьших возможных изменений[5] по сравнению с ранее отсканированной командой, чтобы с лёгкостью различать части сигнала;
- берём декодированную строку CSV и вставляем её в мою огромную Google-таблицу.
[5] Например, на одном этапе я сканирую код, обозначающий режим охлаждения при 20,0°C с автоматической скоростью вентилятор. На следующем этапе я оставляю тот же режим и скорость вентилятора, но поднимаю температуру на один градус. Разница между этими двумя сигналами покажет, где в сигнале закодирована температура. (На самом деле, оказалось, что она закодирована в двух местах — половина градуса 20,5°C хранилась далеко от целой части.)
Когда я говорю «огромную», я подразумеваю действительно огромную Google-таблицу.

[6] Если кто-то найдёт логику или причину подобного кодирования температуры, то я с удовольствием выслушаю. Она не увеличивается монотонно со значением температуры и я не смог найти никакой логики даже с учётом разной endianness.
Единственное, с чем было немного сложно разобраться, был самый последний байт — контрольная сумма. К счастью, это оказалась простая сумма байтов в третьей датаграмме (минус часть с переполнением); это даже не потребовало учёта различий в endianness.
Имея на руках готовую таблицу, можно было приступать к написанию (а потом и исправлению) модуля кодировщика, который сможет преобразовать любое состояние в представление сигнала, понятное кондиционеру. К счастью, кондиционер в моей гостиной уже был умным и в то же время понимал сигнал, испускаемый пультом кондиционера в спальне; поэтому я мог воспользоваться преимуществом цикла обратной связи: пробуем отправить сигнал → проверяем в мобильном приложении умного кондиционера, понял ли он его так, как должен.
Спустя несколько часов я смог полностью управлять кондиционером из сессии SSH, а ещё через несколько часов у меня уже был очень простой, но функциональный веб-интерфейс, созданный при помощи Phoenix и LiveView[7]. Меня не перестаёт удивлять то, что благодаря всего двум строкам на LiveView можно синхронизировать состояние между двумя браузерными окнами на двух разных устройствах. Поистине волшебное чувство!
[7] Забавный факт: фундамент UI я сгенерировал, отправив фото пульта своего кондиционера на Claude.ai и попросив ИИ сгенерировать код на HTML и TailwindCSS, который бы был похож на предмет из реального мира.

Меня сильно впечатлила простота и увлекательность разработки моего первого IoT-устройства при помощи Nerves, поэтому я уже придумываю новые идеи для дальнейшей реализации.
Кроме того, я благодарю сообщество Elixir/Nerves в канале
#nerves
на официальном Discord-сервере Elixir. Оно стало источником вдохновения и оказало огромную поддержку!Telegram-канал со скидками, розыгрышами призов и новостями IT ?

Комментарии (26)
GennPen
29.05.2024 13:15+7дистанционном управлении кондиционером воздуха в моей спальне через Интернет
И чем это отличается от управления пультом? Это не добавляет "умности" кондиционеру, а только расширяет область его управления.
И для этого достаточно было бы обычной ESP32.
ArtPlotnikov
29.05.2024 13:15+3Тоже подумал про это. ESP32 или вообще arduino nano с bluetooth сойдёт, а Raspberry для этого как микроскопом забивать гвозди.
GennPen
29.05.2024 13:15+3На RP Pi Zero можно было бы вообще поднять MQTT, на который натравить Sleep As Android и с помощью этого всего сделать автоматический вход и выход в ночной режим, без всяких пультов. Вот это более-менее напоминало бы "умный" кондиционер.
ArtPlotnikov
29.05.2024 13:15+2Если сервер MQTT на Raspberry, то надо ещё доступ извне открыть (динамический DNS или купить IP у провайдера). Будем рациональными) Нужно для зубной щётки сделать подставку с датчиком/контактом/герконом и ардуиной с модулем RF. Если на часах ночное время и щётку сняли с подставки, то ардуина отправляет сигнал другой ардуинке, которая запускает кондиционер. В этом случае не зависим от интернета.
GennPen
29.05.2024 13:15+1Если сервер MQTT на Raspberry, то надо ещё доступ извне открыть (динамический DNS или купить IP у провайдера).
Зачем, если клиент внутри домашней сети?
ArtPlotnikov
29.05.2024 13:15+1Тогда и MQTT не нужен ради одной команды "включи кондёр". Простой Webhook сойдёт.
ginkage
29.05.2024 13:15+2Да даже ESP8266 достаточно: https://habr.com/ru/articles/419963/
GennPen
29.05.2024 13:15Да, более чем достаточно. Но у ESP32 есть аппаратный модуль RMT, через который очень удобно работать с приемом/отправкой ИК-сигналов. Да и по цене он не на столько дороже.
ginkage
29.05.2024 13:15+1Всё так. При желании можно было бы даже ZigBee использовать, с той же ESP32-C6, и всё равно было бы столь же недорого, плюс стандартные протоколы для климат-контроля.
А вот Raspberry Pi Zero тут откровенно избыточно.
sekuzmin
29.05.2024 13:15+1Nerves — это одна из самых существенных библиотек Elixir. Phoenix позволяет писать веб-серверы, превосходящие по скорости гепарда
Нужно всего лишь дождаться, пока Raspberry Pi Zero загрузит операционку и стартанет вот это вот все.
Меня сильно впечатлила простота и увлекательность разработки моего первого IoT-устройства при помощи Nerves
Толи еще будет если открыть для себя MicroPython для Raspberry Pico или esp32.
safari2012
29.05.2024 13:15Когда-то, много лет тому назад я спросил брата, что он хочет получить от меня на новоселье. Он подумал и сказал, хочу дистанционное управление кондеями, чтобы приехал и с работы и свежо...
Я сваял схему с ESP8266, ИК передатчиком и приемником и датчиком температуры для обратной связи и облачным blynk на борту. Так я начал увлекаться IOT и DYI.
А брат, получив девайс и поигравшись сказал "круто", купил себе Broadlink, чтобы заодно управлять всем остальным в гостиной и все остались довольны :)
vagon333
29.05.2024 13:15+1Может недопонял, но современные кондиционеры имеют опцию управления через WiFi.
Неделю назад ставил сплит со стандартной опцией WiFi.
Если что, летом у меня ад и это был 4ый сплит, вдобавок к центральному.GARANDDMI
29.05.2024 13:15+1/Я включаю кондиционер через "умную" WiFi розетку.
vagon333
29.05.2024 13:15Прекрасное решение, но WiFi розетка не знает температуру и работает как On/Off, что не всегда приемлемо для современного кондиционера c inverter (управления компрессором по DC с изменяемым напряжением).
WiFi в кондиционере регулирует режим, температуру, влажность и, конечно, On/Off.
Sigest
29.05.2024 13:15+1Так это видимо совсем недавно появилось. 5 лет назад ставил себе сплит кондеры и никакого управления по вайфай не было. Я не стал себе паять всякие малинки, купил обычный китайский ИК передатчик с возможностью подключения к вайфаю, и теперь удаленно управляю. Бонусом еще пару устройств в комнате повесил на этот дешевый ик девайс
ABy
29.05.2024 13:15Сейчас даже в бюджетных моделях на плате управления встречается разъем для подключения wi-fi модуля, но самого модуля в комплектации кондиционера нет.
anton_tereshko
29.05.2024 13:15+1не все современные кондеи умные, 2 недели назад ставил Daikin split + 2 головы и управление по wi-fi только в мечтах моих
Javian
29.05.2024 13:15+3Некоторые за это денег хотят, иначе превратятся в тыкву через месяц. И обычного ИК пульта у них нет. - Daichi Alpha - кондиционер по подписке
Облачный кондиционер работает только при наличии двустороннего доступа к интернет через Wi-Fi* и оплаченной подписке на Облачный сервис Даичи
ABy
29.05.2024 13:15Производители кондиционеров наверное думают: "Ну а чем мы хуже производителей принтеров?"
De_Gun
29.05.2024 13:15Простите, я конечно понимаю, что вы сделали это решение своими руками... Но точно не проще бы было готовое решение купить?
https://aliexpress.ru/item/1005004516014637.html?sku_id=12000030593071117&spm=a2g2w.productlist.search_results.0.e2177537QchYgH
roman901
29.05.2024 13:15На самом деле - для подобных самоделок вообще больше не понимаю зачем писать какой-то код. Кусок ямла на 15-20 строк с помощи esphome.io превращается в офигенное умное устройство с интеграцией в HomeAssistant...
venanen
29.05.2024 13:15Так есть же уже куча готовых решений эмуляторов ИК пультов, которые без проблем интегрируются в умный дом.
diakin
Кучеряво живут разработчики в Японии!
Semy
Если это Токио, то там может быть очень крохотная квартирка с кроватью на втором этаже. Типа такого: https://wl-adme.cf.tsp.li/resize/728x/webp/1a6/bc6/d2ae6c5096aeb5caa3c95ee4c3.jpg.webp
DGN
А как там дышать, наверху? Всегда удивляла такая конфигурация.