Лет десять назад как-то по случаю я купил простенькую погодную станцию 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 я такого решения не нашёл. Посчитав наиболее правильным при обработке такого сигнала вычисление огибающей с попыткой последующего восстановления неверных блоков кода, я написал свою библиотеку, где постарался учесть всю исследованную проблематику. Надо заметить, что в моей реализации такого метода обработки кода требуется значительный объём ОЗУ. Кроме того, программа чувствительна к отклонению тактовой частоты передатчика, что случается, как оказалось, не так уж редко в силу низкого качества используемых в датчиках компонентов, в том числе и кварцевых резонаторов.
tmnhy
Я просто оставлю это здесь: github.com/merbanan/rtl_433/tree/master/src/devices