Про умный дом, разношёрстность и закидывание деньгами

Зайчатки разума

Записная книжка айтишника

Про умный дом, разношёрстность и закидывание деньгами

2020-06-30 18:53:30 — Evgeniy Shumilov

  Я уже много тут писал про минимализм и попытки обойтись малым. Иногда стремление к этому выходит за рамки рационального. Скажем, мне намного дешевле с учётом стоимости моего времени купить какую-нибудь железку, чем пытаться сделать её самому, но иногда просто хочется сделать что-то именно своими руками, разобраться. К сожалению, в области радиоэлектроники и микроконтроллеров я дилетант и никак не могу найти времени чтобы в этом достичь хоть какого-то прогресса, но кое-что можно сделать и на этом уровне. Ещё меня постоянно кидает из стороны в сторону и я постоянно переключаюсь с умного дома на 3д печать, с 3д печати на моделирование, с моделирования на что-то ещё. Благо, что зачастую эти сферы соприкасаются друг с другом и навыки, полученные в одной оказываются полезными в иной там, где этого не ожидаешь. 


  Одним из увлечений было SDR - Software Defined Radio. Суть в том, что при помощи специальных устройств можно принимать не только передачу какой-то определённой частоты, но и визуально отображать наличие активности (передачи) в широком спектре частот. Выглядит это примерно так: 

  Далее достаточно выбрать нужную частоту и железо само настроится на её приём. Таким образом можно поймать вещание привычных всем радиостанций, радиопередачи различных служб, телеметрию со спутников и самолётов и много всего прочего. Конечно, подобные железки бывают разного качества, разной степени сложности и, соответственно, цены - от пары десятков долларов до плюс бесконечности. Так вот, прикупил я когда-то в числе прочего один такой небольшой USB приёмник, чтобы иметь возможность подключить его как к смартфону, так и к стационарному компьютеру. Подобные приёмники распространяются обычно для просмотра телевещания на смартфонах, но сфера их применения в умелых руках может быть намного шире. Купил, поразвлекался и забыл где-то на дальней полке.

  И вот, спустя года 4 наткнулся на интересный проект. Суть его заключается в том, что с помощью подобных описанному выше устройств мы перехватываем на частоте 433 мегагерца (или другой, частоту можно указать в качестве параметра при вызове) коды множества радиопультов и в зависимости от их формата декодировать их, выдавая на выходе валидный json, который мы уже можем использовать в собственных целях. Пульты бывают разными - в виде настенных панелей с кнопками, т.е. в формфакторе настенного выключателя, в виде брелоков наподобие тех, которыми снабжаются автомобильные сигнализации, в виде кнопок и т.п..

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

  Существуют версии с одной, двумя и тремя клавишами. Также есть с четырьмя, но в другом дизайне и дороже раза в два. К слову, этот выключатель обошёлся мне всего в 230 с небольшим рублей на Али. После быстрого изучения хэлпа и запуска sudo rtl_433 -F json, при нажатии и отпускании кнопок получаем в консоли следующее (для первой, второй и третьей кнопки соответственно):
 

rtl_433 version 20.02-68-g7b2f90f branch master at 202006182343 inputs file rtl_tcp RTL-SDR
Use -h for usage help and see https://triq.org/ for documentation.
Trying conf file at "rtl_433.conf"...
Trying conf file at "/root/.config/rtl_433/rtl_433.conf"...
Trying conf file at "/usr/local/etc/rtl_433/rtl_433.conf"...
Trying conf file at "/etc/rtl_433/rtl_433.conf"...
Registered 125 out of 153 device decoding protocols [ 1-4 8 11-12 15-17 19-21 23 25-26 29-36 38-60 63 67-71 73-100 102-105 108-116 119 121 124-128 130-149 151-153 ]                      
Detached kernel driver
Found Rafael Micro R820T tuner
Exact sample rate is: 250000.000414 Hz
[R82XX] PLL not locked!
Sample rate set to 250000 S/s.
Tuner gain set to Auto.
Tuned to 433.920MHz.
Allocating 15 zero-copy buffers
{"time" : "2020-06-30 18:20:42", "model" : "Akhan-100F14", "id" : 30250, "data" : "0x2 (Unlock)"}
{"time" : "2020-06-30 18:20:42", "model" : "Akhan-100F14", "id" : 30250, "data" : "0x2 (Unlock)"}
{"time" : "2020-06-30 18:20:42", "model" : "Akhan-100F14", "id" : 30250, "data" : "0x2 (Unlock)"}
{"time" : "2020-06-30 18:20:42", "model" : "Akhan-100F14", "id" : 30250, "data" : "0x2 (Unlock)"}
{"time" : "2020-06-30 18:20:42", "model" : "Akhan-100F14", "id" : 30250, "data" : "0x2 (Unlock)"}
{"time" : "2020-06-30 18:20:42", "model" : "Akhan-100F14", "id" : 30250, "data" : "0x2 (Unlock)"}
{"time" : "2020-06-30 18:20:42", "model" : "Akhan-100F14", "id" : 30250, "data" : "0x2 (Unlock)"}
{"time" : "2020-06-30 18:20:42", "model" : "Akhan-100F14", "id" : 30250, "data" : "0x2 (Unlock)"}
{"time" : "2020-06-30 18:20:42", "model" : "Smoke-GS558", "id" : 10807, "unit" : 0, "learn" : 0, "code" : "4546e0"}
{"time" : "2020-06-30 18:20:43", "model" : "Akhan-100F14", "id" : 30250, "data" : "0x4 (Mute)"}
{"time" : "2020-06-30 18:20:43", "model" : "Akhan-100F14", "id" : 30250, "data" : "0x4 (Mute)"}
{"time" : "2020-06-30 18:20:43", "model" : "Akhan-100F14", "id" : 30250, "data" : "0x4 (Mute)"}
{"time" : "2020-06-30 18:20:43", "model" : "Akhan-100F14", "id" : 30250, "data" : "0x4 (Mute)"}
{"time" : "2020-06-30 18:20:43", "model" : "Akhan-100F14", "id" : 30250, "data" : "0x4 (Mute)"}
{"time" : "2020-06-30 18:20:43", "model" : "Akhan-100F14", "id" : 30250, "data" : "0x4 (Mute)"}
{"time" : "2020-06-30 18:20:43", "model" : "Smoke-GS558", "id" : 10807, "unit" : 0, "learn" : 0, "code" : "2546e0"}
{"time" : "2020-06-30 18:20:45", "model" : "Akhan-100F14", "id" : 30250, "data" : "0x8 (Alarm)"}
{"time" : "2020-06-30 18:20:45", "model" : "Akhan-100F14", "id" : 30250, "data" : "0x8 (Alarm)"}
{"time" : "2020-06-30 18:20:45", "model" : "Akhan-100F14", "id" : 30250, "data" : "0x8 (Alarm)"}
{"time" : "2020-06-30 18:20:45", "model" : "Akhan-100F14", "id" : 30250, "data" : "0x8 (Alarm)"}
{"time" : "2020-06-30 18:20:45", "model" : "Akhan-100F14", "id" : 30250, "data" : "0x8 (Alarm)"}
{"time" : "2020-06-30 18:20:45", "model" : "Akhan-100F14", "id" : 30250, "data" : "0x8 (Alarm)"}
{"time" : "2020-06-30 18:20:45", "model" : "Akhan-100F14", "id" : 30250, "data" : "0x8 (Alarm)"}
{"time" : "2020-06-30 18:20:45", "model" : "Akhan-100F14", "id" : 30250, "data" : "0x8 (Alarm)"}
{"time" : "2020-06-30 18:20:45", "model" : "Akhan-100F14", "id" : 30250, "data" : "0x8 (Alarm)"}
{"time" : "2020-06-30 18:20:45", "model" : "Smoke-GS558", "id" : 10807, "unit" : 0, "learn" : 0, "code" : "1546e0"}

  Пока кнопка удерживается, примерно около 20-ти раз в секунду отправляются коды формата Akhan-100F14, затем при отпускании - коды формата Smoke-GS558. Как их интерпретирует библиотека - нам в принципе, не важно. Главное, что результат является повторяемым. И что отлично - повторяемым на площади всей моей двухкомнатной квартиры. Идея следующая - можно направить stdout приложения на вход цикла while в шелле при отпускании в зависимости от количества сигналов типа Smoke-GS558, отправлять в mqtt для каждой из кнопок время удержания - shot/medium/long. 

  Сказано - сделано. Вечером набросал простой скриптик со следующим содержимым:

#!/bin/sh

buttons='
1 0x2 4546e0 0
2 0x4 2546e0 0
3 0x8 1546e0 0
'

! [ -f mqtt.conf ] && echo "Fail to find mqtt.conf file" && exit 1
. ./mqtt.conf
mqtt="mosquitto_pub -h $host -p $port"
[ -n "$user$pass" ] && mqtt="$mqtt -u $user -P $pass"
[ -n "$topicpref" ] && mqtt="$mqtt -t $topicpref" || mqtt="$mqtt -t /rtl433"

cd `dirname "$0"`
! [ -f mqtt.conf ] && echo "Fail to find mqtt.conf file" && exit 1
. ./mqtt.conf

rtl_433 -F json -M utc |
    while IFS= read -r line; do
        code=`echo "$line" | sed '/"data"/!d;s/^.* "data" : "//;s/ .*$//'`
        if [ -n "$code" ]; then
            button=`echo "$buttons" | awk '$2~/'"$code"'/ {print $1}'`
            if [ -n "$button" ]; then
                buttons=`echo "$buttons" | awk '{ if ($1~/^'$button'$/) {print $1" "$2" "$3" "$4+1} else {print $0}}'`
            else
                echo "Found unknown code: $code"
            fi
        else
            code=`echo "$line" | sed 's/^.* "code" : "//;s/".*//'`
            if [ -n "$code" ]; then
                button=`echo "$buttons" | awk '$3~/'"$code"'/ {print $1}'`
                count=`echo "$buttons" | awk '$3~/'"$code"'/ {print $4}'`
                if [ -n "$button" ]; then
                    buttons=`echo "$buttons" | awk '{ if ($1~/^'$button'$/) {print $1" "$2" "$3" "0} else {print $0}}'`
                    if [ "$count" -lt 6 ]; then
                        l='short'
                    elif [ "$count" -lt 17 ]; then
                        l='middle'
                    else
                        l='long'
                    fi
                    echo "$(date '+%F %T') Button $button is up after $l press ($count)"
                    $mqtt/button_$button/$l -m '1'
                else
                    echo "Found unknown code: $code"
                fi
            fi
        fi
    done

  В массиве buttons для каждой из кнопок хранится поле data для формата Akhan-100F14, поле code для формата Smoke-GS558 и количество текущих повторений. Данные учётной записи для подключения к mqtt серверу подтягиваются из файла mqtt.conf: 

host=hostname
port=1883
user=username
pass=password
topicpref=

  Теперь при нажатии кнопок в соответствующие mqtt топики /rtl433/button_1/short, /rtl433/button_3/long и т.п. попадает единица. Таким образом мы имеем 9 триггеров, к которым можем привязывать произвольные действия на стороне системы умного дома. Например, в Home Assistant, на который я не так давно переехал с Majordomo, пример привязки короткого нажатия на первую кнопку выглядит так:

- alias: 'RFButton1Short'
  trigger:
    platform: mqtt
    topic: /rtl433/button_1/short
    payload: "1"
    # encoding: "utf-8"
  action:
    - service: light.toggle
      entity_id: light.torsher

  Просто, дёшево, сердито. Приклеил панель за боковину шкафа купе, внутри которого у меня стоят 3д принтеры и нажатие первой кнопки включает торшер, а её удержание - запускает скрипт на octoprint, который в свою очередь включает питание принтера, ждёт, когда тот станет доступен, подключается и запускает преднагрев стола и сопла для печати PETG пластиком. Очень удобно, даже шкаф теперь не нужно открывать. Но самое главное - у меня теперь появился механизм, который позволяет дёшево и просто интегрировать новые выключатели в систему умного дома. И, если подумать, то не только выключатели. Можно сделать дешёвые бинарные датчики (скажем, открытия или протечки), работающие от батареек годами. Если я повешу на каждое окно и дверь в моей двухкомнатной квартире датчик открытия двери, которые считаются дешёвыми, то получится круглая сумма. Окна на балконе - 2 створки, окна в комнате и на кухне - ещё по 2 створки, окно из комнаты на балкон и дверь - ещё 2 датчика, двери в большую и маленькую комнаты, на кухню, в туалет и ванную - в общей сложности нужно 13 датчиков. В среднем датчик открытия двери/окна у Xiaomi стоит от 650 рублей. Перемножаем, получаем 8450 рублей. Посмотрим, насколько мне получится уменьшить эту сумму, если я попробую сделать датчики сам. Расскажу как-нибудь в одной из следующих статей. Если повезёт и у меня получится утрамбовать код, обеспечивающий глубокий сон, прерывания и отправку сигнала в килобайт вместе с загрузчиком, то в качестве микроконтроллера я планирую использовать AtTiny13 (10 штук стоит 200 рублей и они у меня уже есть), если не получится - AtTiny44.

Теги: smarthome, automatization, lifehack, minimalism

comments powered by Disqus