Приветствую всех любителей домашней автоматизации. Решил поделиться опытом использования беспроводных Xiaomi устройств с интерфейсом ZigBee. Я, честно говоря, против применения любых беспроводных устройств в любой автоматизации, от серьезных АСУТП больших объектов до малой автоматики типа охранно-пожарной сигнализации или умного дома, но… Решения Xiaomi подкупили дешевизной, доступностью, отличным дизайном и множеством положительных отзывов от пользователей, решил попробовать.
Этот пост следует воспринимать, как пошаговую инструкцию для интеграции ZigBee устройств в инфраструктуру умного дома. Описанное здесь ни в коем случае не является аксиомой и можно найти много других способов подключения ZigBee устройств. Если всё же пропускать детальное описание, то можно составить впечатление о сложности или легкости объединения устройств от разных производителей в одну локальную платформу на примере ZigBee и ioBroker (о нём чуть позже). Я расскажу в этой статье, как подключить устройства к умному дому, отобразить информацию с них на планшете или просто в браузере и отправить сообщения через телеграм о смене состояния устройств. Если я вас заинтересовал, то прошу под кат.
По замыслу производителя Xiaomi, пользователи должны использовать родное приложение с облачным подключением и Wi-Fi шлюз для устройств ZigBee. Однако уже давно известен способ активации режима разработчика в приложении для получения управляющего токена. Таким образом внутри локальной сети можно общаться со шлюзом, что и позволяет проделать драйвер mihome, который идет в составе ioBroker.
ioBroker — это открытая платформа для IoT, в том числе для построения систем типа «умный дом». Что такое ioBroker можно почитать в предыдущей статье.
Сейчас мой умный дом «крутится» на ARM-плате Cubietruck с некоторым «обвесом» в виде жесткого диска на 80Гб, аккумуляторной батарей на 5000мАч, USB-мастера сети 1-wire, USB-RS485 преобразователя для опроса устройств по протоколу modbus. ОС Armbian установлена на жесткий диск с переносом корневого раздела, на карте памяти microSD остался только загрузчик.
Своё знакомство с беспроводными устройствами Xiaomi я начал с покупки датчиков температуры и влажности. На тот момент была единственная возможность их интеграции — драйвер mihome, который упоминался выше.
Драйвер mihome
Добавить драйвер в систему очень просто, нужно кликнуть на кнопке “+” в списке доступных драйверов и наблюдать процесс установки.
Установку и первоначальную настройку родного Android-приложения Mi Home описывать не буду, можно посмотреть на странице github драйвера или в интернете. Итак, режим разработчика активирован, токен получен, настраиваем адаптер mihome, сохраняем и запускаем, если он не был запущен.
В дереве объектов должен появиться шлюз Xiaomi и подключенные в приложении Mi Home устройства.
Далее можно настроить только что созданные объекты. К примеру, хранение истории датчиков температуры и влажности. Я использую для исторических данных драйвер SQL с настройкой на БД SQLite.
Настройка хранения истории переменной производится в окне объектов системы: нужно в иерархии объектов добраться до самой переменной и нажать справа кнопку с гаечным ключом. На вкладке «Настройки» у меня по сенсорам активировано хранение истории — только изменения переменной.
Другие настройки:
- минимальный интервал 10 секунд — если переменная будет изменяться чаще, то запись в БД будет игнорироваться
- запись значений каждые 300 секунд (5 минут) — если переменная не изменяется более 5 минут, в БД все равно запишется текущее значение
- тип значения — число
- срок хранения — 1 год
Добавление новых устройств происходит через родное приложение. Т.е. надо осуществить сопряжение нового девайса со шлюзом согласно прилагаемой инструкции и после этого он автоматически появится в списке объектов ioBroker.
Драйвер zigbee
Мне было неудобно пользоваться родным приложением Xiaomi, тем более что надо покупать шлюз с китайским штекером, который в моем случае, кроме как для общения с устройствами, ни для чего не пригодился. Да, его можно использовать как подсветку-ночник или задействовать в каких то сценариях датчик освещенности. В интернете можно найти инструкции как «скормить» шлюзу плейлист для воспроизведения собственных радиостанций, но у меня ничего из этого не прижилось. Плюс к этому, не давала покоя мысль, что мои данные куда-то утекают, где-то обрабатываются и хранятся.
Один из активных пользователей платформы ioBroker нашел в интернете библиотеку zigbee-shepherd на node.js, в которой было упоминание о подключении устройств Xiaomi. На её базе был написан драйвер для ioBroker, причем автор этого драйвера не ограничился только устройствами Xiaomi, список поддерживаемых устройств постоянно дополняется и доступен на github странице проекта.
В качестве координатора сети предполагается использовать недорогие готовые устройства на базе чипов CC25хх от TI. Можно купить готовые ZigBee-модули как с подключением по USB и встроенной антенной, так и модели подороже-посерьезнее: с внешней антенной, усилителем, подключением через UART.
Для работы с драйвером, надо только сменить прошивку. Таким образом получается, что для работы этого драйвера не нужен дорогостоящий шлюз, не нужны сети Wi-Fi. «Точкой входа» является координатор — устройство на базе чипа СС25хх со специальной прошивкой. Через координатор происходит непосредственное общение zigbee-устройств и системы «Умный дом», а также привязка новых устройств.
В качестве координатора я использую готовую плату на базе чипа СС2530 с внешней антенной, которую подключил к серверу через UART.
Для прошивки устройства был куплен специальный дебагер SmartRF04EB, порт microUSB которого я подключил к компьютеру, а модуль ZigBee подключил с помощью проводков для отладки по схеме:
СС2530 | Плата SmartRF04EB |
---|---|
P22 | DC |
P21 | DD |
RST | RESET |
GND | GND |
VCC | 3.3V |
На странице github проекта качаем прошивку (именно для этого устройства файл называется CC2530ZNP-Pro-Secure_LinkKeyJoin.hex) и программу для прошивки (flash-programmer), после установки которой в систему добавляются нужные драйвера.
При подключении платы-дебагера в USB-порт компьютера в программе сразу отобразится подключенное устройство. Нужно только указать путь к файлу-прошивке и нажать кнопку “Perform Actions”
ZigBee-модуль портами P03 (Rx) и Р02 (Tx) подключен в UART4 (в ОС как ttyS4) платы cubietruck, питание 3V3, GND взял на соседних pin. Для устойчивой работы еще надо порты P20, P4, P5 самого координатора подтянуть к земле. Как писал выше, я использую ОС Armbian, порт UART активируется очень просто, с помощью команды armbian-config в разделе System — Hardware нужно активировать нужный порт и перезагрузить систему.
Драйвер zigbee добавляется из админки одним кликом.
В моем случае координатор подключен в порт /dev/ttyS4 (как писал выше), указываем его в настройках.
Остальные настройки можно оставить по-умолчанию. После первого запуска драйвера, нужно провести сопряжение (добавление) устройств. Полная инструкция на github, сопряжение через этот драйвер немного сложнее чем через родное приложение, но у меня не возникло проблем.
Итак, для примера добавим кнопку Xiaomi (серия Mijia), для этого нажимаем зеленую кнопку в настройках драйвера и, следуя инструкции, сначала зажимаем кнопку сопряжения на тыльной стороне скрепкой, пока не начнет мигать светодиод, затем кликаем этой кнопкой примерно раз в 2 секунды, видим прогресс сопряжения.
Квартира у меня не большая, со всеми устройствами связь стабильная, даже с датчиком открытия двери на лестничной площадке (ЖБ стена в 100мм и расстояние 5м по прямой). Проблемы начались, когда я решил добавить датчик температуры и влажности уличного воздуха, который установил на наружней стене дома со стороны утепленной лоджии. Сигнал слабого датчика, который к тому же находился на улице, не добивал до шкафа автоматики. Решить проблему можно просто — надо добавить роутер в состав сети ZigBee и расположить его ближе к датчику. Некоторые беспроводные устройства, к примеру, розетка Xiaomi могут работать в качестве роутера, но у меня не было подобных устройств. Покупать дорогую розетку или управляемую лампочку только для “проброса” данных от датчика на улице я не хотел. Как оказалось, для тех же оконечных девайсов на базе чипа СС25хх есть специальная прошивка, которая позволяет их использовать как роутер в системе. В итоге я добавил роутер на базе чипа СС2531 с подключением USB. Подробно на процессе прошивки останавливаться не буду, схему и сам файл прошивки можно найти на странице github проекта.
Так как по сути, общение с модулем через USB-порт не происходит, я его временно включил в зарядку с USB-портом и вставил в розетку на кухне. В ближайшем будущем планирую расположить стационарно в нормальном корпусе на лоджии и с нормальным питанием от домашнего ИБП.
Процесс добавления роутера в систему прост: нажимаем кнопку сопряжения в драйвере и на включенном роутере несколько раз нажимаем кнопку S2, пока устройства не соединятся.
Добавим для примера датчик температуры/влажности, который я расположил на лоджии снаружи и который должен работать через роутер.
Можно просто сделать сопряжение через драйвер и датчик должен подключиться через роутер, если он ближе. Но можно принудительно указать чтобы сопряжение шло через конкретный роутер, для этого в списке устройств на иконке роутера надо нажать зеленую кнопку сопряжения.
Убедимся что датчик правильно подключился — посмотрим карту сети.
На карте показаны линии сопряжения устройств с указанием качества сигнала между сегментами сети. Как писал выше, у меня небольшая однушка 35 кв.м., поэтому карта довольно скромная. С разрешения других пользователей, опубликую возможные варианты с картой побольше.
Функционал некоторых устройств Xiaomi через этот адаптер даже немного больше, чем через родное приложение и драйвер mihome. В будущем хочу расширить немного сеть и попробовать новые устройства, в частности умный привод для штор и сенсор-кубик.
Драйвер Material
Данные мы получили, исполнительные механизмы привязали, что теперь с ними делать? Для начала давайте отобразим в красивом интерфейсе. У меня есть большой проект в драйвере VIS, который существует в нескольких версиях под разные разрешения, но там материала достаточно на отдельную статью. Возможно она будет следующей.
Для простого и быстрого вывода на экран данных и управления различными устройствами, я использую драйвер material. Установка как обычно в пару кликов. Плитки интерфейса отображают данные исходя из настроек категорий, которые добавляются в одноименном окне админки интерфейса. Список категорий ограничен только фантазией, я использую схему «комната-функция», по ним и происходит группировка. Добавил все комнаты (кухня, коридор, комната, балкон и т.п.) и функции (освещение, датчики, системные и т.п.).
Теперь в окне настройки объектов системы, нужно для переменных, которые будут выводиться на экран, указать комнату, функцию и назначить роль (для правильного отображения). Пример — комнатный настенный датчик температуры и влажности Xiaomi, подключенный через Bluetooth.
Исходя из этих настроек, плитка будет выводить на экран данные, подтянется иконка, и у объектов определенного типа будет доступно управление.
Пример 1. Вывод всей информации по одной категории — функции. Освещение во всей квартире.
Пример 2. Вывод всей информации по комнате — Ванная комната.
Пример 3. Вольтаж и уровень разряда батарей всех беспроводных устройств Xiaomi.
Этот драйвер у меня работает для локального управления системой с мобильного телефона, стационарного планшета на стене. Иногда я подключаюсь через VPN. Для управления и просмотра состояний удаленно, получения уведомлений, я использую драйвер telegram.
Драйвер Telegram
Установку уже описывать не буду, сразу пробежимся по настройкам. Я использую режим работы через периодический опрос (по-умолчанию 300мс) и соединение через прокси-сервер. Чтобы получить token, нужно немного «пообщаться» с создателем ботов — BotFather. Процесс простой — находите поиском этого бота, даете команду на создание нового, указываете его уникальное имя и ключ ваш, указываем его в настройках драйвера и, для безопасности, обязательно указываем пароль «приветствия». Его ваш бот будет спрашивать при общении с новым пользователем.
Теперь нужно настроить кейсы общения через бота. Для этого можно использовать драйвер text2command или JavaScript. Так исторически сложилось, что я использую JavaScript как в виде текста, так и блоками Blockly. Установка драйвера JS не должна вызвать трудностей, настройка в данном кейсе не нужна. После установки и запуска нужно включить отображение меню для создания и редактирования скриптов.
Пример 1. Оповещения.
Для начала давайте попробуем отправить уведомление об открытии, к примеру, входной двери. У меня стоит датчик-геркон беспроводной Xiaomi на входной двери. Мониторю как жена гуляет с мелким пока я на работе. Создадим новый скрипт в группе common.
Укажем что будет «рисовать» в blockly и назовем «telegram_bot».
В группе «События» возьмем блок реакции на изменение переменной и перетащим на рабочее поле.
Далее выберем ID объекта на который подписываемся, вставим проверку объекта через «если» — «иначе если» на значение true/false. В итоге должно получится примерно следующее.
Отлично, теперь бежим, открываем дверь — закрываем дверь и видим сообщения в telegram.
Пример 2. Управление освещением через меню.
Пример посложнее, сделаем управление освещением кнопками меню в telegram. Здесь уже придется немного покодить, т.е. при создании скрипта нужно выбрать JS. Задача примерно такая: сделать кнопки в виде меню с выводом статуса светильников сразу в текст подписи кнопок. Еще постараться сделать так, чтобы при нажатии на кнопку, состояние освещения инвертировалось и статус тут же обновлялся в тексте кнопки появлением/исчезновением лампочки. Плюс к тому, если меню уже запущено и вручную клавишей включили/выключили свет, нужно чтобы меню также обновлялось со статусами светильников.
Код примерно следующий у меня получился:
//Подписи кнопок меню и ID каналов управления освещением
const LIGHT1 = 'Комн ночн', CH_LIGHT1 = 'mqtt.0.PLC55_Lighting.lighting.MainRoom_main1';
const LIGHT2 = 'Комн осн', CH_LIGHT2 = 'mqtt.0.PLC55_Lighting.lighting.MainRoom_main2';
const LIGHT3 = 'Комн подсв', CH_LIGHT3 = 'mqtt.0.PLC55_Lighting.lighting.MainRoom_sec';
const LIGHT4 = 'Кух свет', CH_LIGHT4 = 'mqtt.0.PLC55_Lighting.lighting.Kitchen_main';
const LIGHT5 = 'Кух подсв1', CH_LIGHT5 = 'mqtt.0.PLC55_Lighting.lighting.Kitchen_sec_top';
const LIGHT6 = 'Кух подсв2', CH_LIGHT6 = 'mqtt.0.PLC55_Lighting.lighting.Kitchen_sec_bottom';
const LIGHT7 = 'Ванна осн', CH_LIGHT7 = 'mqtt.0.PLC55_Lighting.lighting.BathRoom_main';
const LIGHT8 = 'Кор осн', CH_LIGHT8 = 'mqtt.0.PLC55_Lighting.lighting.Hall_main';
const LIGHT9 = 'Балкон осн', CH_LIGHT9 = 'mqtt.0.PLC55_Lighting.lighting.Balcon_main';
//Отправка самого меню в телеграм
function sendLightMenu(message_text) {
//Получаем текущее состояние светильников
var l1 = getState(CH_LIGHT1).val ? '' : '';
var l2 = getState(CH_LIGHT2).val ? '' : '';
var l3 = getState(CH_LIGHT3).val ? '' : '';
var l4 = getState(CH_LIGHT4).val ? '' : '';
var l5 = getState(CH_LIGHT5).val ? '' : '';
var l6 = getState(CH_LIGHT6).val ? '' : '';
var l7 = getState(CH_LIGHT7).val ? '' : '';
var l8 = getState(CH_LIGHT8).val ? '' : '';
var l9 = getState(CH_LIGHT9).val ? '' : '';
//Отправляем меню
sendTo('telegram.0', {
text: message_text,
reply_markup: {
keyboard: [
[LIGHT1+l1, LIGHT2+l2, LIGHT3+l3],
[LIGHT4+l4, LIGHT5+l5, LIGHT6+l6],
[LIGHT7+l7, LIGHT8+l8, LIGHT9+l9]
],
resize_keyboard: true,
one_time_keyboard: true
}
});
}
//Изменение состояния освещения
function changeLight(room, channel) {
//Проверяем доступность контроллера освещения
var alive = getState("mqtt.0.info.connection").val;
if (alive.includes("PLC55_Lighting")) {
if (getState(channel).val) {
setState(channel, false, false, function () {
sendLightMenu(room+' ВЫКЛ');
});
} else {
setState(channel, true, false, function () {
sendLightMenu(room+' ВКЛ');
});
}
} else {
sendLightMenu('Контроллер освещения OFFLINE');
}
}
//Подписываемся на переменную request драйвера телеграмм, любое изменения без подтверждения
on({id: "telegram.0.communicate.request", ack: false, change: 'any'}, function (obj) {
var msg = obj.state.val;
var command = obj.state.val.substring(obj.state.val.indexOf(']')+1);
var user = obj.state.val.substring(obj.state.val.indexOf('[')+1,obj.state.val.indexOf(']'));
var chat_id = getState("telegram.0.communicate.requestChatId").val;
var message_id = getState("telegram.0.communicate.requestMessageId").val;
var handled = false;
//Выводим меню по типичным начальным командам
if (command == '/start' || command == '/menu' || command == 'меню' || command == 'Меню') {
sendLightMenu("Меню");
handled = true;
}
//######################## Lighting menu and commands ################
if (command == LIGHT1 || command == LIGHT1+'') {
changeLight(LIGHT1, CH_LIGHT1);
handled = true;
}
if (command == LIGHT2 || command == LIGHT2+'') {
changeLight(LIGHT2, CH_LIGHT2);
handled = true;
}
if (command == LIGHT3 || command == LIGHT3+'') {
changeLight(LIGHT3, CH_LIGHT3);
handled = true;
}
if (command == LIGHT4 || command == LIGHT4+'') {
changeLight(LIGHT4, CH_LIHT4);
handled = true;
}
if (command == LIGHT5 || command == LIGHT5+'') {
changeLight(LIGHT5, CH_LIGHT5);
handled = true;
}
if (command == LIGHT6 || command == LIGHT6+'') {
changeLight(LIGHT6, CH_LIGHT6);
handled = true;
}
if (command == LIGHT7 || command == LIGHT7+'') {
changeLight(LIGHT7, CH_LIGHT7);
handled = true;
}
if (command == LIGHT8 || command == LIGHT8+'') {
changeLight(LIGHT8, CH_LIGHT8);
handled = true;
}
if (command == LIGHT9 || command == LIGHT9+'') {
changeLight(LIGHT9, CH_LIGHT9);
handled = true;
}
//Если команда не совпала ни с одним вариантом, то передаем её в драйвер text2command
if (!handled) {
sendTo('text2command.0', {
text: command.replace(///g, '#').replace(/_/g, ' '),
id: chat_id,
user: user
}, function (response) {
if (response && response.response) {
sendTo('telegram.0', {user: user, text: response.response});
}
});
}
});
//Если вручную переключили свет, просто обновим меню
on({id: /^mqtt.0.PLC55_Lighting.lighting..*$/, ack: true, change: 'ne'}, function (obj) {
sendLightMenu("Ручное управление");
});
//При рестарте драйвера или скрипта сразу отправляем меню
sendLightMenu("Меню");
В итоге должно получиться примерно так:
Заключение
Статья получилась длинной, но надеюсь полезной, и может она облегчит некоторым пользователям жизнь или сподвигнет кого-нибудь на создание своего умного дома.
На данный момент моя система умного дома на базе ioBroker «крутится» уже 4 года и я вполне ей доволен. К ней кроме ZigBee ещё подключено несколько самодельных контроллеров по MQTT и HTTP для управления освещением, вентиляцией и прочими системами, сеть температурных датчиков по шине 1-wire, устройство мониторинга параметров электросети по шине RS485 и протоколу modbus RTU и много чего еще.
В моей копилке решений для умного дома накопилось много идей, хотя, наверное их надо воспринимать скорее, как копилка проблем для умного дома (те кто в теме поймут, о чём я). Оставляйте свои пожелания в комментариях, чтобы помочь мне определиться с темой следующей статьи.
Автор: Андрей Андреев