Вступление
В процессе выбора решений для умного дома я стараюсь обходить коробочные решения, требующие наличие связи с внешними облаками или имеющие собственные приложения, особенно решения без возможности прямого подключения к устройству. Все доступные метрики сводятся в один интерфейс — zabbix, там же организовывается система оповещений заинтересованных лиц. Ручки управления реализуются в локально расположенном веб-интерфейсе.
Предыдущие статьи:
часть первая (1wire температура, ups, водосчетчик...)
часть вторая (netping, gidrolock, датчики давления...)
Решаемые задачи в этой статье
- Масштабируемая, гибкая система защиты от протечек воды с оповещением через zabbix
- Прочие устройства на 433mhz: звонок, открытие двери и т п
- Запихиваем 1wire в MQTT
Система защиты от протечек
Требования к системе:
- множество датчиков, раскиданных по дому (в моём случае — 6 штук в разных локациях)
- никаких проводов у датчиков
- быстрое закрытие при обнаружении утечки
- вся информация о текущем состоянии в zabbix. Там же — оповещение
Состав системы
- Raspberry PI
- RTL2832U USB тюнер
- Датчики протечек 433mhz
- Netping + кран gidrolock (см предыдущую статью) для перекрытия магистрали
Про железо
В предыдущей статье я описывал решение перекрытия водоснабжения при помощи netping. У меня имеется один проводной датчик для этого решения. Это удобно, если все точки, где может произойти протечка, находятся примерно в одном месте. В моём случае netping установлен прямо на входе магистрали и там же управляет электро-механическим краном gidrolock (см предыдущую статью). Раскидывать netping+gidrolock+проводной датчик по всем точкам — дорого и громоздко. К тому же у меня уже нет возможности протаскивать новые провода по всему дому. Занимать розетки и втюхивать электрокраны — так себе решение. Решение ожидаемое — используем перекрытие общей магистрали на основе сигналов от раскинутых по локациям радио-датчиков.
Из найденного в интернете — куча различных радио-датчиков от готовых систем. Некоторые можно купить отдельно, контроллеры к датчикам покупать не стал, чтобы не плодить дополнительных элементов в схеме.
Чем можно ловить 433mhz? Оказывается — тв-тюнером на определённом чипсете. И стоит он сейчас копейки (я взял на авито за 300р) вот такой:
Заказал к нему отдельную антенку на 12dbi, т к текущая не покрывала весь дом.
Поскольку я пытался минимизировать управляющие компоненты схемы, было желание затянуть тюнер в свой домашний роутер с Openwrt, который и являлся до этого момента ядром решения умного дома для 1wire, modbus, wifi датчиков/протоколов, но, к сожалению, я исчерпал часть его ресурсов (заканчивается место на встроенной флешке под нужный софт, процессор чем-то догружать — уже будут проблемы с работой сети, а нам ещё 4k смотреть в online:), +на USB уже слишком много всего навешено, что влияет на стабильность сбора данных). Решено постепенно выносить функционал умного дома на внешнее устройство — rarpberry pi (под рукой оказалась одна из первых версий).
Про софт
Наигравшись с тв-тюнером в sdr-sharp на стационарном компьютере с windows (попробовав половить чужие рации и переговоры самолётов), стал смотреть, а видит ли «свисток» сами датчики. Да, видит отлично:
Настройка малинки
Я выбрал нативный raspbian. Записал на флешку последний образ под mac/linux:
sudo dd if=2019-07-10-raspbian-buster-lite.img of=/dev/disk2 bs=1048576 conv=sync
Загружаемся, настраиваем сеть и ssh.
Далее — ставим на малинку пакеты rtl-sdr, rtl_433:
sudo apt-get install cmake build-essential python-pip libusb-1.0-0-dev libusb-1.0 python-numpy git
git clone https://github.com/merbanan/rtl_433.git
cd rtl_433/
mkdir build
cd build
cmake ..
make
make install
rtl_433 имеет встроенные протоколы, расшифровывающие данные с разных устройств, работающих в диапазоне 433mhz.
Запускаем rtl_433
rtl_433 -f 433.9e6
Опускаем датчики в воду и получаем заветное:
time : 2019-09-17 15:04:39
model : Smoke detector GS 558 id : 16919
unit : 1 learn : 0 Raw Code : c842e1
Smoke detector? Ок, поставим на оповещение от этих датчиков песню «Smoke on the water»… :)
А если серьёзно — у нас есть id каждого датчика, по которому в будущем мы будем понимать, где именно у нас протечка (а перекрывать-то будем в любом случае).
Про датчики протечки
Уже после настройки софтовой части я заметил, что датчики с aliexpress (левое фото) шлют одиночный сигнал при попадании воды на контакты. Плюс одиночный сигнал, если вода перестаёт замыкать контакты. Меня это никак не устраивает (ожидаемое поведение: постоянно слать alarm-сигнал, когда датчик чувствует воду, т к одиночный сигнал может потеряться). Аналогичное поведение наблюдается, если замкнуть контакты проводом. Но что странно — alarm происходит каждые 2-3 секунды, если замыкать контакты руками (кожей). Тут у меня пока два пердположения: либо китайцы напортачили с замерами сопротивления, либо в датчиках есть какой-то другой режим работы, в котором они ведут себя как-то иначе (например спаренный с контроллером), либо есть и другие частоты (пока не нашёл).
Кстати, отпишите в комментариях, может кто-то работал именно с этими датчиками, можно ли их как-то «научить» слать сигнал о протечке постоянно?
Я отложил эти датчики, в арсенале был ещё один от rubetek (правое фото) и купленный в леруа: GAL SHW-1005 (среднее фото).
Поведение rubetek датчика показалось каким-то совсем непредсказуемым (не прогнозируемая реакция «видит воду/не видит»).
Зато датчик из леруа с ходу показал именно то, что мне и требовалось: есть вода — спамлю в эфир, нет воды — молчу. Единственный его минус — меньший радиус действия, чем у прочих датчиков. Но проблема решена покупкой более чувствительной антенны для приёмника.
MQTT
Как же направить вывод rtl_433 в zabbix? Кормить агенту? Отсылать zabbix_sender-ом, анализируя процесс? Может через syslog?
Тут нужно вспонить, что мой zabbix находится где-то в облаках. И уж точно не стоит перекрывать воду при помощи его триггеров. Пол дома зальёт, пока он примет решение (если вообще будет доступен).
Хорошая новость — rtl_433 умеет слать информацию по MQTT. Из коробки. При этом данные в брокер отправляются в формате json.
Значит нужно:
- Разместить локальный mosquitto брокер (сделаем это на малинке).
- Сливать инфу в брокер с нужным топиком, чтобы потом это можно было парсить.
- Подключиться к брокеру локально на малинке и отправлять команды в netping
- Подключаться к брокеру с места, где будет происходить перенаправление в zabbix ( zabbix-сервер в моём случае тоже является MQTT-клиентом)
Установка-настройка mosquitto MQTT:
apt-get install mosquitto mosquitto-clients
systemctl enable mosquitto
systemctl start mosquitto
Отправляем информацию в брокер с указанием id устройства:
rtl_433 -f 433.88e6 -F mqtt://127.0.0.1,events=/433/[id]
В mqtt клиенте будем получать примерно следующее:
mosquitto_sub -h 127.0.0.1 -t '#' (подписаться на все топики)
/433/16919 {"time":"2019-09-18 11:55:29","model":"Smoke detector GS 558","id":16919,"unit":1,"learn":0,"code":"c842e1"}
Скрипт подключения к брокеру и отправка команды в netping
Набросал простенький скрипт-клиент MQTT, позволяющий при появлении заданного в конфигурации топика запускать ассоциированный с топиком скрипт. Таким образом можно при срабатывании определённого датчика и появлении информации об этом в «Эфире» (например /433/16919) выполнить какое-либо действие (в случае netping — отправить curl запрос на закрытие крана, см предыдущую статью). Ссылка на скрипт — в конце статьи.
Перенаправление в zabbix
Я использовал готовое решение mqtt-zabbix. На его уровне понимаем, в какой item отправить значение (по id).
В keys.cfg указываем:
/433/16919,mqtt.ventilation.waterleak::hostname
где hostname — имя хоста с заведённым item-ом типа «trapper» в Zabbix.
Важно!!! Имя хоста в настройках должно соответствовать отправляемому имени в скрипте, тип item (элемента данных) — подходить для посылаемых данных (например для json — текст), иначе будете ловить ошибки вида:
2019-09-18 14:29:48,749 Got response from Zabbix: {u'info': u'processed: 0; failed: 1; total: 1; seconds spent: 0.000055', u'response': u'success'}
Причём большего дебага (а почему именно failed) от zabbix добиться сложно.
Настраиваем /etc/mqtt-zabbix/mqtt-zabbix.cfg (указываем ip mqtt брокера и адрес zabbix-сервера).
Что ещё подключить по 433?
Да всё что угодно! :)
Датчики метеостанций
Пока ковырялся с беспроводными датчиками протечки, случайно словил сигнал внешнего датчика от метеостанции. Выглядело так:
time : 2019-09-19 10:48:54 Protocol : 56
model : TFA pool temperature sensor Id : 182
Channel : 3 Temperature: 19.3 C
Modulation: ASK Freq : 433.9 MHz
RSSI : -0.1 dB SNR : 35.0 dB Noise : -35.2 dB
time : 2019-09-20 10:57:29 Protocol : 12 brand : OS
model : THN132N House Code: 4
Channel : 3 Battery : OK Celsius : 20.00 C
Modulation: ASK Freq : 432.9 MHz
RSSI : -0.2 dB SNR : 31.5 dB Noise : -31.7 dB
Таким образом, бонусом получил возможность мониторинга температуры точек по радиоканалу с отображением в zabbix. Как раз в некоторые помещения не могу протянуть кабель.
Дверной звонок
Очень многие радио-звонки работают в том же диапазоне частот ~433mhz. Таким образом, мы можем перехватывать нажатие кнопки звонка (даже не обязательно иметь сам звонок, достаточно только кнопки). Зачем? Например чтобы настроить дополнительное оповещение через СМС/в телеграм/whatever или вывести на монитор изображение с камеры.
Мною был куплен звонок: Evology QA-688-E RU.
Чтобы кнопку звонка увидел rtl_433, нужно активировать «тестовые» протоколы, например запустив с опцией «G» или указав конкретный дополнительный протокол, заодно добавим вывод информации о протоколе и частоте:
rtl_433 -f 433.9e6 -G -M protocol -M level -F mqtt://127.0.0.1,events=/433/[id] &
Получим в MQTT:
{"time":"2019-09-30 10:57:00","protocol":72,"model":"RF-tech","id":0,"battery":"LOW","temperature_C":0,"button":0,"mod":"ASK","freq":433.84822,"rssi":-3.5981,"snr":33.77488,"noise":-37.373}
Тут можно заметить id=0. При этом у меня оказалось несколько устройств, определяющихся как RF-tech. У всех у них id был равен 0. В итоге все устройства в zabbix отображаются как один item. Различить то, какое именно устройство сработало, можно только по частоте.
Частоту вытаскиваем в отдельный зависимый item: mqtt.outside.doorbell.freq с предобработкой JSON-ом по $.freq (zabbix это умеет с 4-ой версии).
На этот item делаем триггер с выражением:
{HOME_PI:mqtt.outside.doorbell.freq.last()}>433.8 and {HOME_PI:mqtt.outside.doorbell.freq.last()}<433.81 and {HOME_PI:mqtt.outside.doorbell.freq.nodata(30)}=0
Т.е. если вдруг появилось значение в общем item mqtt.outside.doorbell.freq (nodata) и частота находится в заданном диапазоне между 433.8 и 433.81, можем делать вывод, что нам звонят (и например продублировать звонок в СМС).
Датчики открытия двери/окна
У меня в наличии есть датчик «проникновения» от rubetek. Посылает следующее:
{"time":"2019-09-30 14:11:28","protocol":86,"model":"Smoke detector GS 558","id":12262,"unit":16,"learn":0,"code":"e5fcd0","mod":"ASK","freq":433.85021,"rssi":-3.99241,"snr":33.38058,"noise":-37.373}
закрытие двери:
{"time":"2019-09-30 14:11:28","protocol":68,"model":"Kerui Security","id":46074,"cmd":7,"state":"close","mod":"ASK","freq":433.85021,"rssi":-3.99241,"snr":33.38058,"noise":-37.373}
открытие двери:
{"time":"2019-09-30 14:11:21","protocol":68,"model":"Kerui Security","id":46074,"cmd":14,"state":"open","mod":"ASK","freq":433.85005,"rssi":-11.0148,"snr":25.1088,"noise":-36.1236}
Как только последний радиодатчик был добавлен в zabbix, захотелось всё переделать именно на MQTT. Удобная каталогизация, можно topic-ах определять и место размещения и типы устройств. Получаешь общий эфир всех событий.
1wire to MQTT
Хочу чтобы всё было в MQTT, как минимум для однотипности реализации. Хочу получить общий «эфир» событий и общий подход в реакции на эти события. Безусловно, zabbix решает задачу реакций, и я оставляю на нём оповещения. Но управление хочется сделать более легковестным, приближенным к системе и «эфиру».
Готовые решения ретрансляции состояний датчиков из 1wire сети в MQTT существуют, но мне не подошли. Готовые решения на node либо тащат за собой кучу зависимостей, либо съедали весь процессор малинки. Часть решений из топ 10 в поиске гугла заброшено авторами, часть поддерживают только температурные датчики. Ещё есть класс gateway-ев, собирающих информацию через интерфейс gpio. Всё это мне не подошло.
У меня есть смонтированная псевдо-файловая система с 1wire устройствами в /mnt/1wire, именно оттуда я хочу брать всю необходимую информацию. Для этого достаточно сделать простой однострок на bash, пересылающий данные через mosquitto_pub по каждому из датчиков. Однако появляются вопросы запуска этих скриптов (по крону, загонять в какой-то демон?), нормального представления данных (получение того-же json-а), добавления нового датчика и т п. Чем дальше развивалась мысль — тем больше костылей рождалось. Оказалось проще написать под эту задачу yet another owfs to mqtt шлюз.
Есть файлик конфигурации, в который нужно заносить id датчиков и те файлы из fuse.OWFS, которые мы хотим паблишить в mqtt.
На выходе в mqtt получается такая json-ка:
/1wire/28.0425260a0000 {"type": "DS18B20", "temperature": "30"}
/1wire/28.bf16270a0000 {"type": "DS18B20", "temperature": "7.9375"}
/1wire/26.da2f71010000 {"temperature": "25.2812", "IAD": "1", "CA": "0", "VAD": "0.91", "VDD": "4.59", "type": "DS2438"}
/1wire/28.48b3010b0000 {"type": "DS18B20", "temperature": "40.5625"}
/1wire/1d.6a9306000000 {"type": "DS2423", "counter.B": "9", "counter.A": "9219"}
/1wire/28.61cc260a0000 {"type": "DS18B20", "temperature": "12.5"}
Добавляем в автозапуск, ставим интервал поллинга. Задача решена.
Ссылки
github.com/merbanan/rtl_433 — тула для декодинга радио-протоколов
github.com/kylegordon/mqtt-zabbix — MQTT в Zabbix
github.com/unlo/1wire2mqtt — 1wire в MQTT, MQTT клиент, позволяющий запускать скрипты при появлении топика