Используем беспроводной выключатель на 433МГц для управления ПК

    Привет, Geektimes Habr.

    У меня дома скопилось несколько беспроводных выключателей на 433МГц, стало интересно, можно ли их использовать для каких-либо задач, например для управления компьютером или для интегрирования в систему «умного дома».

    Эти выключатели удобны своей дешевизной и стабильной работой, выглядят они примерно так:



    Как это работает, и что с ними можно сделать (гусары молчать:), подробности под катом.

    Теория


    Скажу сразу — как работает такой выключатель, я не знаю, хотя и примерно догадываюсь. Значит нужно будет произвести небольшой reverse engineering.

    Первым делом сигнал нужно принять, для чего используем многим уже известный RTL-SDR приемник, у радиолюбителей часто называемый просто «свисток». Этот девайс ценой всего в 10$ позволяет принимать радиосигналы в диапазоне примерно от 50 до 1250МГц, для нас то что нужно. Тема старая, но если кто не читал — читайте.

    Делаем первый шаг анализа — внимательно смотрим на выключатель. Обнаруживаем что сзади на корпусе у него написано «Made in China» (кто бы мог подумать?) и, что более важно, указана частота 433МГц. Теперь можно подключить SDR-приемник, запустить SDR# и убедиться, что данные действительно передаются.



    Симметрия сигнала на спектре подсказывает про наличие AM-модуляции. Кстати справа виден более слабый «чужой» сигнал — их тоже можно принимать и декодировать, про них будет подробнее сказано отдельно. Впрочем, вернемся к сигналу. Записываем его в формате обычного WAV и нажимаем кнопки на пульте — для примера я нажал кнопки ON и OFF на канале «1».

    Открываем звуковой файл в любом аудиоредакторе, и воспользуемся для сравнения сигналов другим профессиональным инструментом аналитиков — программой Paint. Размещаем 2 сигнала c разных кнопок один над другим, чтобы увидеть разницу:



    Нетрудно видеть, что мы имеем обычную битовую последовательность, отличие в которой как раз в одном бите, соответствующем кнопке ON или OFF. Пока кнопка нажата, выключатель просто циклически повторяет эту последовательность в эфир со скоростью 20 раз в секунду. Дешево и просто, даже если одна последовательность исказится при передаче, другая будет принята.

    Из этого кстати можно сделать один важный вывод — сигналы таких выключателей (речь о дешевых моделях) передаются в эфир «как есть», без какой-либо аутентификации, защиты или шифрования. Такой выключатель или беспроводную розетку с таким выключателем не стоит использовать для каких-то ответственных функций, например для включения мощных обогревателей или тем более для открытия входной двери или гаража. Дело тут даже не в хакерах (шанс что кто-то будет взламывать мой дом беспроводным способом я оцениваю меньше чем шанс падения на мой дом МКС), а в том, что сосед может случайно купить такой же выключатель, и коды у них могут совпасть (впрочем на выключателе есть возможность выбора между 4 каналами). По моему опыту использования, 2-3 раза за год выключатель таки включался «сам», то ли помеха, то ли действительно принимался далекий сигнал от такой же модели.

    Разумеется, это не относится к более сложным системам, таким как Lora или Philips Hue, там с шифрованием все впорядке.

    Впрочем, вернемся к нашей задаче. Можно написать декодер таких сигналов самостоятельно, но к счастью, это уже сделали до нас, в проекте называемом «rtl_433». Изначально программа была создана для Linux, Windows-версию можно скачать по адресу Linux версию можно скачать с GitHub.

    Запускаем программу из командной строки: «rtl_433.exe -F json»



    Мы получили данные, осталось написать программу для их обработки.

    Raspberry Pi


    Первое, что интересно рассмотреть, это Raspberry Pi. Для установки rtl_433 на Raspbian распаковываем архив и выполняем следующие команды.

    sudo apt-get install libtool libusb-1.0.0-dev librtlsdr-dev rtl-sdr build-essential autoconf cmake pkg-config
    cd rtl_433/
    autoreconf --install
    ./configure
    make
    make install

    Вторым шагом, напишем программу которая будет получать эти данные, и в зависимости от них, выполнять нужные действия. Код на Python весьма несложный:

    from __future__ import print_function
    
    import os, sys, io
    import json
    import subprocess
    
    print("RTLSDR listening started")
    transmitter_name = "Waveman Switch Transmitter"
    transmitter_channel = 1
    
    proc = subprocess.Popen(["rtl_433 -F json"], stdout=subprocess.PIPE, shell=True)
    while True:
        try:
            line = proc.stdout.readline().encode('ascii','ignore')
            proc.poll()
            data = json.loads(line)
            print(data)
            m,st,ch,btn= data['model'],data['state'],data['channel'],data['button']
            if m==transmitter_name and ch==transmitter_channel and btn==1 and st=='on':
                print("ON")
            elif m==transmitter_name and ch==transmitter_channel and btn==1 and st=='off':
                print("OFF")
        except KeyboardInterrupt:
            break
        except:
            pass
    
    print("RTLSDR listening done")

    Чтобы запустить код, нужно сохранить его в файле (например rtl_listen.py) и запустить командой «python rtl_listen.py».

    Как можно видеть, программа запускает процесс с помощью subprocess.Popen и читает из него данные. Дальше все просто, код вполне читабельный, и внести изменения будет не сложно. В данном примере, при нажатии кнопки «1» выводится сообщение print(«ON»), вместо этого можно делать что-то другое, например, активировать пин GPIO, включать реле, посылать данные на сервер и пр. Перед использованием будет необходимо заодно поменять имя transmitter_name на название той модели пульта, который будет использоваться.

    Кстати, сам RTL-SDR-приемник по сравнению с Raspberry Pi выглядит так:



    Windows


    К сожалению, под Windows 10 вышеприведенный код не заработал. Но как подсказал поиск на github, работает асинхронное чтение данных из отдельного потока. Почему так, выяснять было лень, просто приведу под спойлером работающий код.

    Исходный код
    from __future__ import print_function
    
    import os, sys
    import subprocess
    import time
    import threading
    import Queue
    import json
    
    class AsynchronousFileReader(threading.Thread):
        # Helper class to implement asynchronous reading
        def __init__(self, fd, queue):
            assert isinstance(queue, Queue.Queue)
            assert callable(fd.readline)
            threading.Thread.__init__(self)
            self._fd = fd
            self._queue = queue
    
        def run(self):
            # The body of the tread: read lines and put them on the queue.
            for line in iter(self._fd.readline, ''):
                self._queue.put(line)
    
        def eof(self):
            # Check whether there is no more content to expect
            return not self.is_alive() and self._queue.empty()
    
    def replace(string):
        while '  ' in string:
            string = string.replace('  ', ' ')
        return string
    
    
    def read_rtl_data():
        process = subprocess.Popen(["rtl_433.exe", "-F", "json"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    
        # Launch the asynchronous readers of stdout and stderr.
        stdout_queue = Queue.Queue()
        stdout_reader = AsynchronousFileReader(process.stdout, stdout_queue)
        stdout_reader.start()
        stderr_queue = Queue.Queue()
        stderr_reader = AsynchronousFileReader(process.stderr, stderr_queue)
        stderr_reader.start()
    
        transmitter_name = "Waveman Switch Transmitter"
        transmitter_channel = 1
    
        # Check the queues if we received some output
        while not stdout_reader.eof() or not stderr_reader.eof():
            # Show what we received from standard output.
            while not stdout_queue.empty():
               line = stdout_queue.get()
               print("Line1:", repr(line))
               data = json.loads(line)
               # print("Data:", repr(line))
               m,st,ch,btn= data['model'],data['state'],data['channel'],data['button']
               if m==transmitter_name and ch==transmitter_channel and btn==1 and st=='on':
                   print("ON")
               elif m==transmitter_name and ch==transmitter_channel and btn==1 and st=='off':
                   print("OFF")
    
            # Show what we received from standard error.
            while not stderr_queue.empty():
                line = replace(stderr_queue.get())
                print("Line2:", line)
    
            # Sleep a bit before asking the readers again.
            time.sleep(0.1)
    
        stdout_reader.join()
        stderr_reader.join()
    
        # Close subprocess' file descriptors.
        process.stdout.close()
        process.stderr.close()
    
    if __name__ == '__main__':
        print("RTLSDR listening started")
        
        read_rtl_data()
        
        print("RTLSDR listening done")
    


    С этим кодом мы можем использовать любые действия в обработчике, логика такая же как и в коде на Raspberry Pi.

    Пример: допустим, у нас есть компьютер, выделенный под домашний кинотеатр, и мы хотим выключать его нажатием кнопки с пульта. Заменяем код 'print(«OFF»)' на

                   os.system('shutdown -s')
                   sys.exit(0)

    После чего, компьютер будет выключаться по нажатию соответствующей кнопки. Разумеется, кроме «shutdown -s» можно использовать любую другую команду Windows, стоит лишь учитывать что команды будут посылаться многократно, пока кнопка пульта нажата, чтобы избежать такого дублирования, нужно усовершенствовать код.

    Заключение


    Как можно видеть, все довольно-таки просто, и есть место для экспериментов. Наконец, небольшой бонус для тех кто дочитал до сюда. На 433МГц работает большое количество разных устройств, которые rtl_433 может декодировать, можно просто оставить программу работать несколько часов, и посмотреть что «поймается». Под спойлером пример такого лога, записанного ранее:

    Лог
    2018-01-10 21:15:17 : Prologue sensor : 5 : 15
    Channel: 1
    Battery: OK
    Button: 0
    Temperature: 6.00 C
    Humidity: 11 %

    2018-01-10 21:15:28 : inFactory sensor
    ID: 71
    Temperature: 6.67 °C
    Humidity: 99 %

    2018-01-10 21:16:07 : Toyota : TPMS : 61511475 : 60e5006b : CRC

    2018-01-10 21:20:33 : Prologue sensor : 5 : 15
    Channel: 1
    Battery: OK
    Button: 0
    Temperature: 6.00 C
    Humidity: 11 %
    : Waveman Switch Transmitter
    id: A
    channel: 2
    button: 1
    state: on
    : Waveman Switch Transmitter
    id: A
    channel: 2
    button: 1
    state: on
    : Waveman Switch Transmitter
    id: A
    channel: 2
    button: 1
    state: on

    2018-01-10 21:21:21 : Akhan 100F14 remote keyless entry
    ID (20bit): 0x41
    Data (4bit): 0x4 (Mute)
    : Waveman Switch Transmitter
    id: A
    channel: 2
    button: 1
    state: off

    2018-01-10 21:32:31 : Ford : TPMS : 00268b1f : a34a0e : CHECKSUM
    2018-01-10 21:32:32 : Ford : TPMS : 00268a5c : 9c440e : CHECKSUM
    2018-01-10 21:32:37 : Ford : TPMS : 016dbfce : 99430e : CHECKSUM
    2018-01-10 21:32:39 : Ford : TPMS : 002671a0 : 9c4a0e : CHECKSUM


    Есть интересные данные, например давление в шинах у соседского автомобиля (TPMS, tire-pressure monitoring system), или наружняя температура +6 с чьего-то датчика. Это позволяет например, выводить наружнюю температуру, если у соседей случайно окажется совместимая с этим протоколом метеостанция.

    Всем удачных экспериментов.

    Disclaimer: Очевидно, что использование SDR и цифровой обработки для чтения сигналов OOK-модуляции — это по сути, стрельба из пушки по воробьям. Возможно, на aliexpress существуют готовые приемники за 1-2$, которые делают то же самое, с меньшей ценой и меньшим энергопотреблением. Если кто знает такие модели, напишите в комментариях.

    Комментарии 22

      +2
      Обычно все подобные пульты на 433 МГц прекрасно ловятся на подобные приемники, на выходе получается двоичный сигнал, который легко расшифровывается программой.
        0
        Спасибо, как-нибудь попробую к ардуине прикрутить.
          +3
          Если будете пробовать — берите как минимум на супергетеродине(PT4303-S). На Алике есть еще дешевле модули их категорически не советую, с ними одни проблемы.
          0

          А можно ли использовать такие модули как удлинитель UART? До какой скорости?

            0
            Я сейчас проект делаю на вот таких модулях:
            E32-433T20S2T (http://www.cdebyte.com/en/product-view-news.aspx?id=227)
            В него чистый UART с микроконтроллера входит и выходит. Дальность передачи до 3 км.
            Протокол с распределенным спектром (LoRa), помехозащищенность очень высокая, есть избыточность передачи для коррекции ошибок. Сам тестировал в поселке на 1 км — все ок (больше не нужно было).
            В общем, очень вкусный модулечек, только цена у него дороже, зато разработка быстрее — не надо вкуривать весь мануал на SX1278. Там этим мелкая STM8 занимается.
              0
              Теоретически конечно можно, но не рекомендуется, т.к. канал общий на все устройства, будет забиваться, а все пульты передают короткие пакеты, которые почти не занимают канал. Можно сделать на NRF24, они могут использовать разные каналы, есть режим подтверждения для гарантированной доставки пакетов.
                0
                Есть готовые радиомодемы на 433 или 866МГц, специально для UART, их часто на квадрокоптерах используют, типа таких www.dx.com/p/433mhz-single-ttl-3d-robotics-3dr-radio-telemetry-kit-for-apm-apm2-blue-green-235604

                Скорость 9600 если память не изменяет.
              +1

              Почитайте о проекте rflink на Arduino mega.
              http://www.rflink.nl/blog2/wiring
              Я его в связке с domoticz использую для управления парой релешек 433МГц.
              Единственный минус — ловит много лишнего (например автосигнализации), чем забивает список девайсов.

                0
                Если не ошибаюсь, с RTL SDR работает ещё и GNURadio, поддерживающий подключение плагинов, среди которых наверняка можно найти бинарный декодер.
                  0
                  Да, gnuradio работает с rtlsdr, и есть основанные на gnuradio декодеры, например для метеостанций Oregon — github.com/kevinmehall/rtlsdr-433m-sensor

                  Но это надо дописывать код, готовых блоков именно для пультов (или даже просто чтобы возвращал бинарный поток с синхронизацией по началу пакета) я не нашел. Есть вот такой подход, для некоторых пультов видимо работает, у меня не заработало: blog.compass-security.com/2016/09/software-defied-radio-sdr-and-decoding-on-off-keying-ook
                  0
                  Китайские пульты в частоту шлют сразу json строку?
                    0
                    Нет конечно, параметр «rtl_433 -F json» задается в декодере. Декодер внутри уже имеет образцы сигналов наиболее популярных пультов.
                    0
                    Брал из «этой же серии», аля китайской, дешевый звонок (входной на дверь) и использовал как радиокнопку. Принесли мне старые часы «Электроника» (модель не помню, на газоразрядных индикаторах), 1985 года. Дедушке нужно было удаленно отключать будильник на них. Так вот, нашел в звонке, где приемник выдает лог. 1 на вход звуковой микросхемы при получении сигнала с кнопки, повесил на эту линию триггер шмитта с реле — и все этот в разрыв копки включения будильника в часах (разрывала просто выход на динамик). Результат достигнут, дешево и работает уже пару лет. Часы, конечно, на лампах — тема…
                      0

                      Вот это да…
                      А вскрыть корпус и посмотреть начинку (маркировку микросхемы кодера) — это не спортивно?


                      Китайский производители обычно пихают в такие розетки и пультики ширпотребовские кодеры/декодеры PT2262/PT2272 + отдельные стандартные модули передатчика/приемника. Анализировать протокол на уровне радиосигнала для стандартного ширпотреба с доступными спецификациями — это какое то извращенное удовольствие.

                        +1
                        Из готовых решений можно посмотреть в сторону sonoff rf bridge (не реклама). Умеет как получать, так и передавать сигналы 433 МГц. Плюс имеет WiFi. Сделана на основе популярного ESP8266. Можно подключать к различным системам умного дома. А обилие прошивок для ESP8266 позволяет расширить функционал и отойти от китайских проприетарных облачных сервисов
                        • НЛО прилетело и опубликовало эту надпись здесь
                            0
                            Интересны приёмничек. А вот это тоже оно? Или даже вот это?
                            0
                            > Разумеется, это не относится к более сложным системам, таким как Lora или Philips Hue, там с шифрованием все впорядке.

                            Не то, чтобы совсем всё в порядке. Вот, новость пару лет давности про взлом Philips Hue
                            xakep.ru/2016/11/08/philips-hue-sos
                            Но лучше, чем с китайскими модулями, конечно.

                            Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                            Самое читаемое