«Умный» дом, часть 2

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

  1. Любое изменение конфигурации системы (добавление пульта или изменение функции одной из кнопок уже установленного) требует доставать стремянку, снимать люстру и привязывать/отвязывать выключатель от её силового блока. Требуется редко, но очень уж геморройно.
  2. Сценарные кнопки на выключателях умеют делают только одно действие — например, выключить все сегменты в люстре одним нажатием. А вот включать их уже надо обычными кнопками, двумя нажатиями.
  3. Расход кнопок на люстру с двумя сегментами — минимум две штуки (по одной на каждый сегмент), при этом управление ей неудобно — чтобы выключить люстру, например, надо посмотреть, какой сегмент включён, и нажать соответствующую ему кнопку. Ну или отвести под одну люстру все три кнопки (сценарную на «выключить всё»), но и это упрощает лишь одну операцию.

Все эти проблемы решаются тем, что у «Ноотехники» есть USB-адаптеры с приёмниками и передатчиками. К ним точно так же привязываются пульты и силовые блоки, а с компом адаптер общается как HID-устройство с очень простой системой команд. Соответственно, при виде этого возникла разумная идея воткнуть оба адаптера в домашний сервер (у меня есть) или просто роутер (тоже есть парочка) и сделать всё управление светом через этот сервер. Тогда силовые блоки привязываются к каналам передатчика один раз перед установкой на своё место, привязать выключатель к приёмнику несложно, а соответствие между каналами приёмника и передатчика задаётся программно. Бонусом появляется возможность сделать веб-интерфейс и мобильное приложение.

Кстати, если роутера нет — можно купить мини-компьютер Wiren Board Smart Home, в котором уже есть приёмник и передатчик 433,92 МГц, а производитель обещает драйверы с поддержкой протокола nooLite. Плюс — это будет одна коробка с горой интерфейсов «умного дома», минус — если вам нужен только nooLite, то два родных адаптера и дешёвый роутер (популярнейший TL-MR3020 подойдёт) выйдут дешевле. Кроме того, очевидно, под драйверы Wiren весь софт, про который я скажу ниже, придётся переделывать.

Screenshot_2014-07-26-22-35-49

Что я получил?

  1. Программную настройку всех выключателей в доме (через веб-интерфейс).
  2. Управление несколькими лампами с помощью одной кнопки выключателя по различным сценариям.
  3. Отдельные события на длинное и короткое нажатия кнопок.
  4. Веб-интерфейс и мобильное приложение.

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

Сразу предупреждаю: сделаны те и только те вещи, которые были нужны мне. Например, нет поддержки RGB-лент и диммеров — у меня их нет. Надо — добавляйте сами или ждите, что может я когда-нибудь. Работает с передатчиком PC1116 (но нет причине не работать с другими моделями) и приёмником RX1164 (но нет причин не работать с более новым RX2164) на обычном ПК под CentOS 6 (мой домашний сервер) и на роутере TP-Link TL-WDR4300 под OpenWRT Attitude Adjustment (но нет причине не работать с традиционным для самоделок дешёвым TL-MR3020).

Описывать по той же причине буду кратко, так что если кто не знает, что такое autoconf и opkg — извините. Инструкция «сделать умный дом для дураков» тут возможна и даже не очень длинна, но цель моя сейчас не в этом.

Теоретически, сайт «Ноотехники» ссылается на сторонние драйверы под Linux (под Windows есть родная управляющая программа), поддерживающие ноолайтовские адаптеры; их наличие и вдохновило мня купить пару адаптеров. Практически же эти драйверы — не более чем демонстрация того, что адаптер вообще работает. Пользоваться ими в реальной жизни не рекомендуется, потому как ад мглы внутри простирается от намертво зашитой в сишный код команды, вызываемой при приходе данных от приёмника, до попросту перепутанных кодов команд в программе конфигурации приёмника.

В общем, дальше из шкафа была вытащена УШМ и произведена лёгкая доработка кода.

1. Код упорядочен и собирается не без помощи autoconf/automake.

Ну это понятно, обычное удобство.

2. У всех утилит упорядочены параметры командной строки.

Потому что я не знаю, что двигало человеком, придумавшим синтаксис «—on_ch номер_канала» вместо просто «—on номер_канала». Ну и банальных ошибок и шероховатостей хватало, типа необходимости передавать номер канала в команду, для выполнения которой номер канала не нужен.

3. Исправлены горы найденных ошибок и шероховатостей.

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

4. У утилиты приёмника добавлен конфигурационный файл.

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

5. Утилита приёмника теперь может работать в фоне — демоном.

Очевидная вещь. Консоль ему нужна только при отладке.

6. Для передатчика написан свой демон, данные которому передаются через сокет всеми желающими.

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

7. Информация о работе сыпется в syslog.

Очевидная вещь. Какая команда пришла, какая ушла, предупреждения, если пришла команда с номер канала, который не сконфигурирован, и т.п.

Поехали!

Весь код лежит на GitHub’е. Предыдущие авторы условий лицензирования не указывали, так что, полагаю, лицензия WTFPL. Сборка — как обычно, ./configure && make && make install. В каталоге openwrt лежит Makefile для сборки под, как вы уже догадались, OpenWRT, а также скрипт запуска демонов для /etc/init.d. В каталоге initd лежит скрипт запуска демона приёмника для CentOS 6 (и аналогичных систем).

Ну и в doc лежит README, читайте его, там всё сказано (плюс нижеперечисленные команды с параметром —help выдают краткую справку о себе).

Внутри есть:

  • noolitepc — консольный передатчик. В общем, нужен, только если хочется что-то руками проверить (включить-выключить определённый канал).
  • noolitepcd — демон передатчика. Используется в повседневной жизни, общение через сокет /tmp/noolitepcd.sock.
  • nooliterx — консольный приёмник. Полезен в вариантах nooliterx -i (игнорирует конфигурационный файл, валит в консоль всё принятое — полезно для проверки привязки выключателей, кодов команд и т.п.) и nooliterx -d (уходит в демоны для использования в повседневной жизни).
  • nooliterxcfg — конфигурация приёмника, привязка-отвязка пультов к его каналам.

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

Такая прослойка живёт на GitHub рядом, работает в веб-сервере и написана преимущественно на PHP. PHP и веб-сервер вместо C и компилятора очень удобны тем, что внутренности можно править прямо на лету.

Конфигурация демона приёмника такова:

root@router:~# cat /etc/noolite.conf
# noolite config file
command = wget -q -T 5 "http://localhost/lampcontrol.php?channel=%ch&command=%cm" -O /dev/null &

То есть, поймав что-то от любого привязанного к нему пульта, демон-приёмник вызывает wget, загружающий lampcontrol.php и передающий ему номера канала и команды, полученные от пульта. Соответственно, в lampcontrol.php содержится вся логика, определяющая, что именно делать с этими ценными сведениями.

За указаниями lampcontrol.php лезет в XML-файл switch.xml, имеющий формат:

<?xml version="1.0" encoding="UTF-8"?>
<channels>
<channel id="5" enabled="yes" mode="toggle" command="4">
<lamp channel="1">
<lamp channel="2">
</channel>
</channels>

Что мы тут видим? Что если пришла команда с кодом 4 (это короткое нажатие кнопки выключателя, коды команд есть в руководствах по RX1164 и RX2164), то надо изменить состояние (toggle) ламп, привязанных к каналам 1 и 2 передатчика. Если были включены — выключить, если выключены — включить.

Результат каждого изменения состояния лампы сервер пишет в ДБ sqlite3 — lamps.db — поэтому всегда знает, какая лампа что делает. Это даёт возможность как делать многошаговые алгоритмы, так и просто показывать на веб-интерфейсе текущее состояние ламп. Так как обратно связи от силовых блоков нет, сервер может ошибаться относительно состояния отдельной лампы (команда из-за помех не дошла до силового блока), но при минимально аккуратном размещении антенн это случается редко.

Создаётся база один раз (с помощью create-db.php) перед первым взлётом всей системы. База может порушиться при внезапном выключении роутера, т.к. для неё включена асинхронная запись в файл и расположение журнала в памяти — чтобы не сказывалась неторопливость роутерного флэша; в таком случае надо файл прибить и создать заново, благо ничего особо ценного в нём нет (только текущий статус каждой из 64 возможных ламп). Если вам надежность критична — закомментируйте в lampcontrol.php строчку $db->exec("PRAGMA journal_mode=MEMORY;");, это положит журнал на диск. Включать синхронную запись (соседняя строчка) не советую, будет очень-очень медленно.

  • id — номер канала приёмника, от 1 до 64.
  • enabled — yes или no. Во втором случае команда просто игнорируется; это нужно как для удобного выключения временно ненужных команд, так и для правильной отработки длинных нажатий кнопок, который генерируют две команды — начало нажатия и конец нажатия. Чаще всего второе событие нам не нужно.
  • mode — собственно что делать с лампами по этой команде. Может быть равен «on» — включить, «off» — выключить, «toggle» — переключить, «sequence» — включать по цепочке (при зажигании очередной лампы предыдущая гаснет), «combined» — включать последовательно (при зажигании очередной предыдущая остаётся гореть), «group» — переключать группой (если в группе горит хоть одна лампа, то все гаснут; если ни одной не горит — все зажигаются), «alloff» — выключить все включённые лампы в доме.
  • command — номер команды, приходящей с пульта. По командам различаются типы кнопок на пультах и типы нажатия: короткое или длинное. Типы кнопок нам неважны, так как работающая на сервере логика от них не зависит, и мы можем на любую кнопку навесить что угодно; тип нажатия иногда полезно различать, чтобы повесить на одну кнопку несколько действий. Параметр необязательный (при его отсутствии будут выполняться команды с любыми кодами, кроме в явно виде описанных в других частях XML-файла), но я советую его проставлять — у меня, например, один пульт склонен изредка выдать в эфир команду с чужим номером канала, неверным номером команды и корректным CRC.
  • override — опциональный параметр, yes или no. Нужен только в режимах sequence и combined. Допутим, режим combined, в нём пять групп ламп, до прихода команды горели лампы 1, 2 и 5 (например, 5 включили с другого выключателя, который управляет только ей). При override=yes приход команды с режимом combined переведёт лампы в состояние 1, 2 и 3, override=no — в состояние 1, 2, 3 и 5 (т.е. в первом случае «лишняя» лампа выключится).

Далее идёт перечисление ламп, на которые распространяется данная команда; параметр у каждой лампы один — «channel», номер канала передатчика, к которому привязан соответствующий силовой блок. Исключением является mode=»alloff» — в этом режиме список ламп не нужен вообще, выключаются все включённые лампы в доме.

Можно делать вот так, например:

<channel id="8" enabled="yes" mode="combined" override="yes">
<lamp channel="2"></lamp>
<lamp channel="3"></lamp>
</channel>
<channel id="8" enabled="yes" mode="off" command="5">
<lamp channel="2"></lamp>
<lamp channel="3"></lamp>
</channel>
<channel id="8" enabled="no" command="10">
</channel>

Здесь по короткому нажатию кнопки последовательно включаются два сегмента люстры (цикл выключено — включена лампа 2 — включены лампы 2 и 3 — выключено), а по длинному — люстра либо полностью зажигается (если не горела ни одна лампа), либо полностью гаснет (если горела хотя бы одна). Третий блок как раз отрабатывает команду, приходящую при отпускании кнопки после длинного нажатия; можно прописать в первом блоке параметр command=»4″, тогда третий блок был бы не нужен — команду 10 в таком случае всё равно никто не отработает.

Веб-интерфейс лежит в файле index.php и выводит либо план квартиры (в данном случае нарисованный в Sweet Home 3D), если его открывают с планшета или ПК, либо перечень кнопок, если открывают с мобильника. Расположение ламп на плане квартиры и их названия берутся из файла lamps.xml

<?xml version="1.0" encoding="UTF-8"?>
<channels>
<channel id="2" title="Ванная">
<image x="174" y="238" position="left"/>
</channel>
<channel id="3" title="Ванная">
<image x="194" y="238" position="right"/>
</channel>
</channels>

Здесь описаны две секции освещения в ванной — их силовые блоки привязаны к каналам 2 и 3 передатчика, на плане квартиры они расположены в точка {174; 238} и {194; 238} пикселей, кнопки включения и выключения надо нарисовать слева от первой и справа от второй лампы. Параметр «position» не обязателен — если он не указан, кнопки рисуются справа.

lamps

Чтобы не править XML-файлы руками, ходя на сервер по SSH — к веб-интерфейсу прикручена простая админка, внутри которой живёт редактор XML на JavaScript. Она на данный момент практически никак не заточена под конкретную задачу, так что всё в ней всё равно пишется руками. Пароль для входа задаётся непосредственно в файле admin/index.php в первом if’е (по умолчанию admin/admin).

На роутере для работы всего этого добра нужны libusb-1.0, lighttpd, lighttpd-mod-cgi, php5, php5-cgi, php5-mod-simplexml, php5-mod-xml, php5-mod-sqlite3. С учётом, что на этом же роутере у меня крутится ещё и аудиосервер (mpd), его собственного флэша не хватает категорически — поэтому в него воткнута флэшка и настроен overlay, так что все новые пакеты устанавливаются на флэшку. Так как в роутере всего два USB-порта, в него воткнут приличный хаб, в котором уже стоят флэшка, приёмник и передатчик:

OLYMPUS DIGITAL CAMERA

Как нетрудно заметить, приёмник и передатчик выглядят, мягко говоря, не совсем так, как на сайте «Ноотехники». Дело в том, что у них, как и у силовых блоков, антенны сделаны из мягкого многожильного провода — а для обеспечения максимальной стабильности связи антенна должна быть прямой, жёсткой и вертикальной (ибо диаграмма направленности — максимум усиления в перпендикулярной антенне плоскости). Поэтому я разобрал родные корпуса, поменял антенны на 170 мм (четверть длины волны) жёсткого провода (сойдёт одна жила обычного электромонтажного провода сечением 1,5—2,5 мм²) и упаковал всё в термоусадку. В качестве флэшки — SanDisk Cruzer Fit 8 ГБ, маленький, незаметный и при этом выдающий весьма пристойную скорость даже на работе с маленькими блоками.

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

Естественно, выпускать роутер в интернет не советую — по крайней мере, пока вы не сделаете авторизацию при заходе на управление вашим светом снаружи.

Кажется, всё рассказал.

Напишу ли руководство «установка умного дома nooLite на TP-Link MR3020 для чайников» — ХЗ. Сделает ли «Ноотехника» из бессмысленного Ethernet-шлюза такой сервер — тем более ХЗ.

Что удобного можно сделать в конкретной квартире:

  • Управление одной лампой из нескольких мест: например, выключать люстру у входа в комнату и у изголовья кровати, включать свет на кухне собственно с кухни и из начала коридора, к ней ведущего.
  • Раздельное управление сегментами в любой люстре, вплоть до отдельного управления хоть каждой лампочкой — и всё это одной кнопкой пульта.
  • Отдельные «взрослые» выключатели на стене высоко и «детские» с управлением только частью ламп на стене низко.
  • Кнопка «выключить всё» на выходе из квартиры.
  • Кнопка «выключить весь свет в кухне-ванной-сортире-прихожей» на пультах в комнатах.
  • Ну и само собой, в качестве нагрузки могут выступать не только лампы, а вообще что угодно, втыкающееся в розетку.

Полезные ссылки:

Эта заметка в LiveJournal. Текст тот же, но часто там бывает много комментариев.