Перейти до вмісту

Як полагодити Tuya TS0201 Neo в Home Assistant ZHA: щоб температура й вологість нарешті запрацювали

Чому сенсор _TZ3000_qaaysllp губить показники й як це полагодити кастомним quirk

Я придбав сенсор температури, вологості та освітленості Neo Tuya TS0201 (ідентифікатор виробника _TZ3000_qaaysllp, також відомий як NAS-TH02B2), розраховуючи на просте налаштування в ZHA. Спарувався він нормально — батарея й освітленість з'явилися одразу. Але температури й вологості не було зовсім. Жодних сутностей, жодних даних, нічого.

Наявний quirk у zha-device-handlers мав обслуговувати цей пристрій, але не допоміг. Після кількох годин копирсання в захопленнях Zigbee-пакетів і дебаг-логах ZHA я з'ясував, що проблема має три окремі рівні — а апстрімовий quirk закриває лише один із них. У цій статті я розбираю все, що знайшов, і даю робочий фікс.

Симптоми: що ви побачите

Після парування ZHA зазвичай показує:

  • Відсоток заряду батареї — працює нормально
  • Освітленість — працює нормально
  • Температура — сутність відсутня або показує unknown / 0
  • Вологість — сутність відсутня або показує unknown / 0

У логах Home Assistant (з увімкненим дебаг-логуванням ZHA) можна побачити повідомлення на кшталт:

Ignoring message on unknown endpoint 2

Або під час конфігурації пристрою:

UNSUPPORTED_ATTRIBUTE on cluster 0x0402 (TemperatureMeasurement)UNSUPPORTED_ATTRIBUTE on cluster 0x0405 (RelativeHumidity)

Чому так відбувається: першопричина

Ця проблема має три рівні, і щоб сенсор запрацював, треба полагодити всі три. Ось що відбувається під капотом.

Рівень 1: пристрій бреше про свої можливості

Кожен Zigbee-пристрій транслює «простий дескриптор» (simple descriptor), який повідомляє координатору, які кластери (функції) він підтримує і на яких ендпоінтах. TS0201 Neo анонсує таке:

Endpoint 1: Basic, PowerConfiguration, IlluminanceMeasurement, Tuya Alarm (0xE002)

Зверніть увагу, чого бракує: TemperatureMeasurement (0x0402) і RelativeHumidity (0x0405) не зазначені взагалі. Пристрій просто не анонсує, що вміє вимірювати температуру чи вологість.

Рівень 2: дані надходять на неанонсований ендпоінт

Після певної послідовності активації (про неї нижче) пристрій таки починає надсилати дані температури й вологості — але на endpoint 2, про який він координатору ніколи не казав. zigpy, бібліотека Zigbee, яку використовує ZHA, цілком справедливо відкидає ці повідомлення:

Ignoring message on unknown endpoint 2

Наявний апстрімовий quirk у zha-device-handlers (zhaquirks/tuya/ts0201.py) таки додає віртуальний endpoint 2 до моделі пристрою, що частково закриває це. Але він не лагодить інші два рівні.

Рівень 3: бракує послідовності активації

Навіть із визначеним endpoint 2 пристрій не почне репортити температуру й вологість, доки не отримає те, що відоме як «Tuya magic packet» — читання певних атрибутів кластера Basic, передусім — специфічного для виробника атрибута 0xFFFE. Це той самий механізм, який zigbee2mqtt реалізує як tuya.configureMagicPacket.

Апстрімовий quirk для ZHA цей magic packet не надсилає. Без нього endpoint 2 існує в моделі пристрою, але пристрій ніколи не надсилає на нього жодних даних.

Бонусний рівень: UNSUPPORTED_ATTRIBUTE вбиває сутності

Коли ZHA ініціалізує пристрій, вона читає атрибути, щоб вирішити, які сутності Home Assistant створити. Цей пристрій відповідає UNSUPPORTED_ATTRIBUTE (код помилки 0x86) на прямі читання кластерів температури й вологості. Апстрімовий quirk використовує голі ID кластерів на endpoint 2, тож ці читання доходять до пристрою й зазнають невдачі. ZHA бачить помилку й узагалі пропускає створення сутностей.

Фікс: кастомний quirk для ZHA

Я опублікував робочий quirk, що закриває всі три рівні: ts0201.py — GitHub Gist

Що цей quirk робить інакше

Порівняно з апстрімовою версією, цей quirk додає:

  1. Mixin TuyaCachedReadCluster — перехоплює виклики read_attributes() й повертає кешовані значення (з попередніх репортів) або нульове значення за замовчуванням. Також він викликає _update_attribute(), щоб повідомити ланцюжок слухачів ZHA, забезпечуючи створення сутностей навіть тоді, коли пристрій повертає UNSUPPORTED_ATTRIBUTE.
  2. Magic packet у bind() — коли ZHA налаштовує підписки на репорти на кластері alarm, quirk спершу читає атрибути кластера Basic, зокрема специфічний для Tuya 0xFFFE. Це активує стандартну звітність кластерів пристрою на endpoint 2.
  3. Виправлення бага: ID атрибута alarm_humidity_max — в апстрімовому quirk він стоїть як 0xD00C, але насправді пристрій репортить 0xD00D. Перевірено на живих даних пристрою.
  4. NodeDescriptor — додано до словника заміни (replacement dict), скопійовано з реальної відповіді пристрою.
  5. Кастомні класи кластерів на EP2 — замість голих ID кластерів (які просто маршрутизують повідомлення, але не перевизначають поведінку) quirk використовує класи TuyaTemperatureMeasurement і TuyaRelativeHumidity, що успадковують поведінку кешованого читання.

Встановлення: крок за кроком

Крок 1: створіть каталог для кастомних quirks

Якщо ви ще цього не зробили, створіть каталог для кастомних quirks. Через файловий редактор Home Assistant, SSH або Samba:

/homeassistant/custom_zha_quirks/

Крок 2: завантажте quirk

Завантажте ts0201.py з GitHub Gist і покладіть його в:

/homeassistant/custom_zha_quirks/ts0201.py

Крок 3: налаштуйте ZHA на використання кастомних quirks

Додайте це у свій configuration.yaml:

zha:  custom_quirks_path: /config/custom_zha_quirks

Крок 4: перезапустіть Home Assistant

Потрібен повний перезапуск — не просто перезавантаження конфігурації.

Крок 5: видаліть пристрій і спаруйте його заново

Цей крок важливий. Багато quirks набирають повної чинності лише під час інтерв'ю пристрою (процесу парування). Після перезапуску:

  1. Перейдіть у Settings > Devices & Services > ZHA
  2. Знайдіть пристрій TS0201 і видаліть його
  3. Переведіть сенсор у режим парування (зазвичай довгим натисканням кнопки)
  4. Спаруйте заново через ZHA

Після парування пристрою знадобиться хвилина-дві, щоб повністю налаштуватися (Tuya-пристрої мають ліміт паралелізму приблизно у 2 одночасні запити, тож конфігурація йде послідовно). Коли все завершиться, ви маєте побачити:

  • Температура — оновлюється з реальними значеннями
  • Вологість — оновлюється з реальними значеннями
  • Освітленість — працює як і раніше
  • Батарея — працює як і раніше

Як це працює: технічне занурення

Для тих, хто хоче зрозуміти механіку, ось потік даних після застосування quirk:

Device pairs    → ZHA applies quirk (signature matches _TZ3000_qaaysllp / TS0201)    → Replacement creates virtual EP2 with custom cluster classes
ZHA configures EP1 alarm cluster    → bind() override triggers magic packet    → Reads Basic attributes [0x0000, 0x0001, 0x0004, 0x0005, 0x0007, 0xFFFE]    → 0xFFFE activates the device's reporting mechanism
Device starts sending unsolicited reports on EP2    → TemperatureMeasurement (0x0402): measured_value in hundredths of °C    → RelativeHumidity (0x0405): measured_value in hundredths of %
ZHA reads attributes during init    → TuyaCachedReadCluster intercepts the read    → Returns cached value (or 0 if no report yet)    → Calls _update_attribute() → ZHA creates the HA entity
Ongoing operation    → Device sends reports every ~1 minute (or on significant change)    → zigpy routes to EP2 → custom cluster → _update_attribute() → HA entity updates

Чому _update_attribute() важливий

У zigpy _update_attribute() — це центральний механізм сповіщення. Коли його викликають, він:

  1. Оновлює внутрішній _attr_cache кластера
  2. Запускає колбек zdo.ATTR_UPDATED
  3. ClusterHandler у ZHA отримує його й оновлює сутність Home Assistant

Без виклику _update_attribute() у перевизначенні кешованого читання ZHA ніколи б не дізналася про значення й не створювала б сутностей.

Чому magic packet працює

Атрибут 0xFFFE — це специфічний для Tuya механізм. Його читання каже пристрою: "Я Tuya-обізнаний координатор, будь ласка, починай надсилати мені дані через стандартні ZCL-кластери." Без цього читання пристрій лишається німим на EP2. Це добре задокументовано в кодовій базі zigbee2mqtt як configureMagicPacket.

Підтверджені робочі значення

Після застосування цього quirk ось реальні значення, отримані від пристрою (з дебаг-логів ZHA):

  • TemperatureMeasurement (EP2) — measured_value: 2640 → 26.40 °C
  • RelativeHumidity (EP2) — measured_value: 4100 → 41.00 %
  • IlluminanceMeasurement (EP1) — measured_value: 0 → 0 lux
  • PowerConfiguration (EP1) — battery_percentage_remaining: 200 → 100%

Значення температури й вологості оновлюються приблизно щохвилини або коли виявлено значну зміну (>=0.5°C або >=5% вологості).

FAQ

Чи працює це з моделлю NAS-TH02B2?

Neo NAS-TH02B2 — найпоширеніша фізична модель, яка по Zigbee репортить себе як _TZ3000_qaaysllp / TS0201. Так, цей quirk призначений саме для цього пристрою.

Чи не конфліктуватиме це з апстрімовим quirk?

Ні. Кастомні quirks у custom_zha_quirks мають пріоритет над вбудованими quirks, коли сигнатура пристрою збігається. Апстрімовий quirk буде проігноровано на користь вашого.

Чи потрібен мені для цього zigbee2mqtt?

Ні. Цей фікс цілком для ZHA (вбудованої Zigbee-інтеграції Home Assistant). Якщо ви користуєтеся zigbee2mqtt, підтримка Tuya-пристроїв реалізована інакше — через їхню систему конвертерів, де configureMagicPacket уже вбудований.

Пристрій спарувався, але температура досі показує нуль

Зачекайте 2–3 хвилини після парування. Пристрою потрібно завершити свій перший цикл звітності. Якщо через 5 хвилин усе ще нуль, перевірте свої логи ZHA на наявність magic packet:

[zha.zigbee.cluster_handlers] [0xABCD](tuya_alarm): bind 'Tuya Temperature and Humidity Alarm Cluster' cluster

Якщо ви бачите це, а слідом — читання кластера Basic, то magic packet було надіслано.

Чи можу я використати це з іншими варіантами TS0201?

Цей quirk призначений саме для _TZ3000_qaaysllp. Інші варіанти TS0201 (як-от _TZ3000_fllyghyj, _TZ3000_lfa05ajd, _TZ3210_ncw88jfq) мають іншу поведінку й можуть потребувати інших quirks. Зіставлення сигнатур гарантує, що цей quirk застосовується лише до правильного пристрою.

Моя вологість застрягла на 5%

Це відома проблема, про яку повідомляють деякі користувачі навіть із робочими quirks. Вона може вказувати на апаратний дефект самого сенсора (чипа Sensirion SHTC3), а не на проблему quirk. Спробуйте замінити батарейки й спарувати заново.

Пов'язані ресурси

Якщо ви маєте справу зі схожим Tuya-сенсором, який парується, але не репортить дані в ZHA, описаний тут патерн — відсутній ендпоінт, активація через magic packet, кешовані читання для запобігання UNSUPPORTED_ATTRIBUTE — застосовний до багатьох Tuya-пристроїв, а не лише до TS0201. Сподіваюся, це заощадить вам ті години, які я витратив, щоб у цьому розібратися.

Увімкніть коментарі, прийнявши куки.

Необхідні куки працюють завжди. Куки для статистики та коментарів використовуються лише з вашої згоди. Докладніше