О декодировании протокола погодных датчиков Oregon Scientific

Лет десять назад как-то по случаю я купил простенькую погодную станцию Oregon Scientific BAR208HG. Радовала она домочадцев достаточно долго, и продолжает радовать до сих пор. Мне же со временем стало не хватать её функционала и захотелось расширить свои возможности наблюдения за погодой. И тут выяснился один неприятный факт — покупка продвинутой метеостанции от того же Oregon Scientific не давала возможности транслировать показания с её датчиков на старую станцию. Не совпадала версия протокола передачи данных. Примерно в это же время я был вовлечён в такую увлекательную авантюру, как передачу метеоданных на сервис небезызвестного Народного мониторинга. Уже на тот момент сети имелось достаточно много информации о самих погодных станциях и датчиках Oregon, о протоколе передачи данных и методах их расшифровки. Я легко нашёл и несколько готовых программ и библиотек Arduino для приёма и расшифровки сигнала. Вся эта информация показалась мне недостаточно систематизирована, местами неточна, а программы давали удовлетворительный результат только на очень коротких расстояниях. В конечном итоге я пришёл к старой истине: "Хочешь сделать что-то хорошо — сделай сам". Результатом последующих изысканий стало написание вот этой заметки, в которой хотелось бы поделиться полученными знаниями и умениями.


Версии протокола


Вся экосистема Oregon Scientific работает по общему принципу — датчики являются передатчиками, вещающими через строго определённые интервалы времени. Для минимизации коллизий при передаче интервалы вещания для всех датчиков различны, например, для моей станции датчики передают показания с интервалом 39, 41 и 43 секунды на 1-ом, 2-ом и 3-ем канале соответственно. Сами метеостанции являются в свою очередь только приёмниками. Таким образом связь является односторонней. Производитель использует несколько версий протокола передачи данных:


  • Версия 1.0. На этом протоколе работаю разве что пожелтевшие от времени устройства двадцатилетней давности. Я никогда не видел этих устройств ни вживую, ни даже на картинках. Рассказать мне о них решительно нечего,
  • Версия 2.1. — Используется в настоящее время в большинстве продаваемой в России и ближнем зарубежье продукции для домашнего использования. Датчики, работающие на этом протоколе, как правило, имеют малую мощность передатчика, заявленный радиус их действия — около 30м,
  • Версия 3.0 — Изначально применялся в т.н. "профессиональных" метеостанциях, имеющих в своём комплекте анемометр, измеритель осадков и датчик ультрафиолета. Слово "профессиональный" недаром взято в кавычки. Несмотря на заявленные улучшенные характеристики, как, например, радиус действия в 100м, большая часть этих устройств имеет довольно хлипкую конструкцию, недорогую элементную базу и столь же недолговечна, как и продукция для домашнего использования. Некоторое время назад производитель стал переводить и домашний сегмент своих устройств на этот протокол. Какое-то время они продавались и в России, но позже по неизвестным причинам продажи были прекращены. Определить эти изделия можно по индексу "Х" в конце названия. Например, вместо моей BAR208HG была выпущена внешне неотличимая метеостанция BAR208HGX, работающая на 3-ей версии протокола.

Все датчики вещают на несущей частоте 433Мгц. Метод модуляции — ООК (On/Off Key), т.е. банальный "вкл/выкл", как в азбуке Морзе. Во всех версиях протокола используется манчестерское кодирование с разной избыточностью и тактовой частотой 2048Гц. На рисунке ниже приведены методы кодирования информации для обоих рассматриваемых протоколов версий 2.1 и 3.0



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


Пакет данных


В обоих версиях передача данных происходит полубайтами, тетрадами или нибблами. Передача осуществляется младшим битом вперёд.


Пакет данных состоит из ряда полей, начинающихся с преамбулы. Первое отличие протоколов состоит в длине преамбулы. В версии 2.1 она состоит из 4-ёх тетрад Fh, а версии 3.0 — из 6-и таких же тетрад. Для чего нужна преамбула? Для корректного приёма пакета помимо синхронизации приёмника и передатчика, нужно, чтобы автоматическая регулировка усиления (АРУ) приёмника настроилась на уровень сигнала от передатчика. Процесс этот достаточно медленный, и если им пренебречь и лишить пакет преамбулы, то начальные данные будут сильно искажены, и раскодировать их скорее всего не получится.



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


Тип датчика — поле длиной в 4 тетрады. Исходя из этого типа, принимающая сторона должна сделать вывод, известен ли ей этот тип и способна ли она обрабатывать такие пакеты. Ведь тип датчика определяет многое:


  • количество возможных каналов передачи,
  • интервал передачи,
  • размер и тип самих данных, которые передаёт датчик,
  • параметры расчёта проверочного циклического кода, о котором мы поговорим позже.

Значение поля "Канал" задаётся переключателем под крышкой батарейного отсека датчика. Значение же поля "Идентификатор" меняется каждый раз после сброса или смены батареек. Идентификатор позволяет работать нескольким датчикам и метеостанциям, каждому со своим, даже если все они находятся в непосредственной близости друг к другу. Предполагается, что перевод погодной станции в режим поиска датчика и одновременный сброс датчика с большой долей вероятности приведёт к тому, что первым придёт сигнал именно от только что сброшенного датчика. Приёмник запоминает его идентификатор, и до следующего вызова процедуры поиска будет игнорировать все аналогичные датчики, работающие на этом же канале, но с иными идентификаторами. Важно отметить, что значение идентификатора выбирается только из определённого множества, а не может быть случайным.


Поле "Батарея" размером в одну тетраду содержит несколько информационных битов:


  • бит3 (& 4h) сигнализирует о разряженной батарее передатчика. Например для моего THGN132N, работающего от пальчиковой батарейки, бит выставляется при падении напряжения до 1.3В.
  • бит4 (& 8h) выставлен в течение первых 30-и минут с момена старта. Вероятно, датчик с выставленным битом имеет приоритет в режиме поиска погодной станцией.
  • бит1 (& 1h) выставлен в период с 30-ой по 60-ую минуту с момента старта.

Размер и наполнение поля "Данные" определяется типом датчика. Я собрал в сети информацию о данных и методах её расшифровки для наиболее распространённых типов:



Поле "Контрольная сумма" — первая ступень проверки целостности полученных данных. Рассчитывается она, как однобайтовая сумма всех тетрад начиная с поля типа датчика и заканчивая данными. Например, для пакета


5D5314D01510950AC13B529


Контрольная сумма будет равна:


5h + Dh + 5h + 3h + 1h + 4h + Dh + 0h + 1h + 5h + 1h + 0h + 9h + 5h + 0h + Ah + Ch + 1h + 3h = 5Bh


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


Поле CRC8 — вторая ступень проверки целостности данных. В обеих версиях протокола используется алгоритм CRC8-CCITT с порождающим полиномом 07h. Поскольку в пакете принят обратный порядок передачи битов от младшего к старшему, то и расчёт ведётся в таком же порядке для полей начиная от "типа" и заканчивая "данными". Различие в расчёте между версиями 2.1 и 3.0 заключается в том, что в версии 2.1 из расчёта исключено поле "ID" и стартовая сумма не всегда равна нулю а определяется типом датчика. Например, для пакета датчика THN132N (версия 2.1)


EC401B183520D33F


расчёт производится с начальным значением D6h для последовательности


CRC8-CCITT( D6h < E < C < 4 < 0 < 1 < 8 < 3 < 5 < 2 < 0 ) = F3h


Для пакета же датчика PCR800 (версия 3.0), имеющего вид


29140EC00000279410142E


рассчёт производится с нулевым начальным значением для последовательности


CRC8-CCITT( 00h < 2 < 9 < 1 < 4 < 0 < E < C < 0 < 0 < 0 < 0 < 0 < 2 < 7 < 9 < 4 < 1 < 0) = E2h


В сводной таблице приведены основные параметры наиболее распространённых датчиков.


Практическая реализация


Хотелось бы немного рассказать о своём опыте реализации декодировщика протокола. Опробованные мной декодировщики для платформы Arduino ориентированы на работу с устойчивым, неискажённым сигналом и обеспечивают уверенный приём только на очень малых расстояниях между датчиком и приёмником. С увеличением этого расстояния микроконтроллер с внешним приёмником теряет связь намного быстрее, чем "родная" погодная станция. Подключение осциллографа к выходу приёмника даёт ответ на вопрос, почему это происходит. На осциллограммах показан сигнал от THGN132N на выходе приёмника при различном удалении датчика.



Видно, что с увеличением расстояния, когда уровень принимаемого сигнала падает, на него начинают накладываться шумы, приводящие к дроблению и сужению импульсов, появлению иных помех на цифровом выходе приёмника. Вероятно разработчики из Oregon знакомы с этой проблемой и научились её решать, а вот для Arduino я такого решения не нашёл. Посчитав наиболее правильным при обработке такого сигнала вычисление огибающей с попыткой последующего восстановления неверных блоков кода, я написал свою библиотеку, где постарался учесть всю исследованную проблематику. Надо заметить, что в моей реализации такого метода обработки кода требуется значительный объём ОЗУ. Кроме того, программа чувствительна к отклонению тактовой частоты передатчика, что случается, как оказалось, не так уж редко в силу низкого качества используемых в датчиках компонентов, в том числе и кварцевых резонаторов.

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

    0
    Я просто оставлю это здесь: github.com/merbanan/rtl_433/tree/master/src/devices
      0
      вот такой
      image
      купленный в конце 90-х ловко подхватил внешний датчик от нынешних Орегонов. Подскажите, это какая версия?
        +1
        На вашей фотографии не видно, что за модель. Но можно пойти логическим путём. В 90-ых 3-ей версии ещё не было, а современные датчики определённо не 1-ой версии. Методом исключения получаем версию 2.
          0
          Модель не написана, скорей всего когда-то сзади была приклеена бумажка, которая со временем просто оторвалась.
          Орегон конечно впечатляет, внешний датчик 20+ лет жил под солнцем дождями снегом ветром, в итоге только контакты батареек надо чистить время от времени. Сейчас докупил датчик и еще одну станцию, они обе ловят датчики друг друга. В наше время это просто чудеса какие то )
        0
        Да… А мой BAR388HG уже давно требует замены. Сначала отказала синхронизация времени DCF-77 (Британский аналог и не работал никогда) — году этак на 10 работы. На 12-ом начали глючить кварцы. Разбирал, пропаивал. Второй год с грустью жду момента замены батареек. Шансы на то что станция не перенесет эту операцию просто шкалят. Надо б поменять, но Oregon нынче редок. А за вменяемые деньги внутренняя/внешняя температура + влажность, давление, фазы луны, нормально идущие часы — да так, чтоб год от комплекта батареек работала вообще нереально. Потому спасибо. Было бы время прикрутить к выносному датчику USB интерфейс. Может быть еще бы и послужил.
          0
          Кварцы желательно не пропаивать, а менять. Проблема в том, что в некоторых станциях их два. Один — часовой — работает собственно на часы, декодирование сигнала с приёмников 433МГц и DCF77. С ним всё просто, купить можно в любом ларьке, торгующим радиодеталями.
          Назначение второго мне неясно, и он не часовой. Как-то ради интереса менял их местами — оба приёмника глохли, а часы шли значительно быстрее.
            0
            Спасибо. Конечно, при возможности надо менять. Только вот… Давно я ее ремонтировал. Даже фотографий не найти. Но в памяти осталось три кварца на несущей плате и еще пара на платах «второго этажа». При этом единственный легкодоступный это 32.768-ой. Остальные просто так не купишь. Потому и пропаивал, а не менял. Впрочем, давно это было… В любом случае свои деньги станция отработала уже не однократно. Видимо просто пришла пора ее поменять. Обидно даже не то, что оно сломалось — обидно что прогресс свернул не туда. Цветные дисплеи, питание от сети… Где б найти точно такую… Или хотя бы максимально похожую… Уж больно хорошо раз в год батарейки менять.
            Потому хорошо, что благодаря статье возможно удастся продлить жизнь выносному датчику, но… Если честно, то сомнительно. Он интересен был именно в связке со станцией. И еще — раз уж Вы ковырялись… Скажите, а при таком варианте в чем смысл соединения датчика со станцией? У меня в инструкции было — после замены батареек ОДНОВРЕМЕННО сбросить станцию и датчик. Они некоторое время после сброса данные чаще шлют?
              0
              Смысл одновременного сброса датчика и станции в следующем.
              Станция после сброса (или перехода в режим поиска датчиков) в течение определённого времени ожидает сигналы по всем каналам. Первый пойманный на каком-то определённом канале сигнал от датчика и будет зарегистрирован как «свой». Станция запоминает его идентификатор и временную метку передачи. После перехода в штатный режим станция не только не воспринимает датчики с другими идентификаторами, но, судя по всему, для экономии электричества даже приёмник включает только в те моменты времени, когда должны прийти сигналы от зарегистрированных датчиков.
              Передатчик же после сброса посылает первый пакет через несколько секунд после старта. Да ещё в довесок и выставляет бит в пакете, навроде как «я имею приоритет, меня только что сбросили». Как-то так.
                0
                Спасибо за пояснение.
                  0
                  Спасибо. Если когда-нить решусь сделать USB приемник для ПК/маршрутизатора буду знать.
                    0
                    Arduino + 433 приемник — все ловит и показывает даже на мониторе ))
                      0
                      Скорее stm32f103 или что-то подобное (думаю в виде USB HID) + 433 приемник в виде флешки. С питанием от USB. Возможно для применения в смежных решениях. Допустим, мониторинг температуры/влажности в тепличках с перцами или… не перцами =)
            0
            Интересно с какой целью реализовали целый 2 варианта проверки корректности принятых данных?
              0
              Это уже вопрос к разработчикам. Можно было бы ограничиться расчётом только CRC8, поскольку контрольная сумма — так себе метод. На первых парах пользовался только суммой — регулярно пару раз в неделю она пропускала ошибки, да ещё какие!
              0
              Теперь понятно, почему, когда я использую библиотеку из ранее когда-то опубликованной статьи на хабре — радиус действия вообще почти 1 метр, все что дальше- тупо не приходит в лог. Менял антенны, батарейки и прочее — не помогло. Попробую вашу бибилотеку
                +1

                Интересно было бы посмотреть на сигналы с последней картинки через SDR. Может, получить нужную дальность мешают какие-то ограничения приёмника.

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

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