Если в сообщении на общем MQTT-топике нет нужного ключа, шаблоны датчиков выдают предупреждения вида 'dict object' has no attribute 'Occupancy', а состояние может теряться. В трех ветках форума помогло разделение значений по отдельным топикам с сохранением сообщений у брокера.
Как выглядит проблема
Предупреждения Template variable warning сообщают об отсутствии ключа в пришедшем сообщении и не означают сломанную интеграцию.
- Шаблонные датчики Occupancy (присутствие) и Illuminance (освещенность) на общем топике пишут в журнал предупреждения об отсутствующем атрибуте. В ветках форума это датчики Vallhorn за Tasmota Zigbee-мостом.
- Датчики контроллера Siemens LOGO 8.4, разделяющие один топик
LOGO_Pub, выдают ошибки отсутствующего ключа и становятсяunknown- их состояние неизвестно - после перезапуска Home Assistant. - Состояние датчика теряется, когда на тот же топик приходит сообщение с другим параметром.
Типичные записи в журнале выглядят так.
WARNING (MainThread) [homeassistant.helpers.template] Template variable warning: 'dict object' has no attribute 'Occupancy' when rendering '{{ value_json['ZbReceived']['0x4D91']['Occupancy'] }}'
2024-10-24 11:21:59.260 ERROR (MainThread) [homeassistant.helpers.template] Error parsing value: 'dict object' has no attribute 'I4' (value: {"state":{"reported":{"$logotime":1729768864}}}, template: {{ value_json['state']['reported']['I4']['value'][0] }})
После перезапуска Home Assistant датчики LOGO выдают ошибки ValueError и сообщения о неудачном обновлении сущности.
ValueError: Sensor sensor.ai2 has device class 'None', state class 'None' unit 'V' and suggested precision 'None' thus indicating it has a numeric value; however, it has the non-numeric value: 'unknown' (<class 'str'>)
Exception raised while updating state of sensor.ai2, topic: 'LOGO_Pub' with payload: b'{"state":{"reported":{"$logotime":1729772603}}}'
Exception raised while updating state of sensor.ai1, topic: 'LOGO_Pub' with payload: b'{"state":{"reported":{"$logotime":1729772603}}}'
Сообщения от Tasmota Zigbee-моста содержат объект ZbReceived. У Siemens LOGO часть сообщений несет только отметку времени $logotime без значений датчиков.
Причина
В двух ветках форума причиной назвали сообщения с разными наборами параметров на одном топике.
| Причина | Как проверить | Что сделать |
|---|---|---|
| В сообщении на общем топике нет ключа, который читает шаблон датчика | Сравнить ключ в шаблоне с содержимым сообщения в записи журнала | Автоматизацией разнести значения по топикам с сохранением сообщений и указать каждому датчику свой state_topic - топик состояния |
Рабочее решение
Автоматизация разделяет сообщения общего топика по свойствам и публикует значения с retain: true - брокер сохраняет сообщение. Такой разделитель называют демультиплексором. Сообщения без нужных ключей, например с одной отметкой времени, нужно пропускать. Ниже пример для Tasmota Zigbee из ветки форума.
alias: zigbee bridge demultiplexer
trigger:
- platform: mqtt
topic: tele/zigbee-bridge/#
variables:
address: "{{ trigger.payload_json.ZbReceived.keys() | first }}"
properties:
- Occupancy
- Illuminance
property: >
{{ set(trigger.payload_json.ZbReceived[address].keys()).intersection(set(properties))
| first | default(none, true) }}
msg: >
{{ trigger.payload_json.ZbReceived[address][property]
if property is not none else property }}
condition:
- condition: template
value_template: "{{ property is not none }}"
action:
- service: mqtt.publish
data:
topic: "zb/{{ trigger.topic.split('/')[2] }}/{{ property | lower }}"
payload: "{{ msg }}"
retain: true
В примере имя устройства берется из третьего сегмента исходного топика, а название свойства переводится в нижний регистр. Как устроены автоматизации и переменные триггера, разобрано в гайде по автоматизациям.
Дальше MQTT-датчики в YAML подписываются на свои топики. Базовая настройка сенсоров и двоичных сенсоров разобрана в гайде по MQTT и Mosquitto.
- name: "Vallhorn Landing Illuminance"
device_class: illuminance
unit_of_measurement: lx
state_topic: "zb/vallhorn-landing/illuminance"
- name: "Vallhorn Hall Illuminance"
device_class: Illuminance
unit_of_measurement: lx
state_topic: "zb/vallhorn-hall/illuminance"
- name: "PIR Vallhorn Landing"
state_topic: "zb/vallhorn-landing/occupancy"
device_class: occupancy
value_template: "{{ iif(value|int(0) == 1, 'ON', 'OFF') }}"
- name: "PIR Vallhorn Hall"
state_topic: "zb/vallhorn-hall/occupancy"
device_class: occupancy
value_template: "{{ iif(value|int(0) == 1, 'ON', 'OFF') }}"
Шаблон двоичного датчика превращает числовые 1 и 0 в ON и OFF.
В трех ветках форума о разделении топиков сообщили четыре раза как об успешном решении, сообщений о неудаче нет. По документации MQTT-интеграции, сохраненное retained-сообщение на топике состояния воспроизводится при старте, чтобы восстановить состояние датчика.
Если не помогло
В обсуждениях форума пять приемов получили по одному сообщению о неудаче в одной ветке каждый. Еще у семи вариантов итог частичный или неизвестный.
Не сработали:
- Попытка посмотреть содержимое сообщения срезом
{{ value_json[:250] }}- получена ошибкаKeyError: slice(None, 250, None). - Обход шестнадцатеричного адреса через первый элемент
ZbReceivedс одновременным отказом отqos- вариантvalue_template: "{{ ((value_json['ZbReceived'].values())|first)['Illuminance'] }}"не сработал. - Защита доступа к Occupancy с сохранением
this.stateи числовымиpayload_on: 1иpayload_off: 0. - Булев шаблон Occupancy без
payload_onиpayload_off- тоже без результата. - Шаблонный датчик на MQTT-триггере вместо MQTT-сенсора - не сработал.
Частичный результат дали два варианта:
- Проверка
is definedс откатом наthis.state, например{{ value_json.state.reported.I1.value[0] if value_json.state.reported.I1 is defined else this.state }}- эффект частичный в двух ветках. - Временное снятие
device_classи показ среза{{ value[:250] }}- один частичный результат в одной ветке.
Еще предложили посмотреть первый элемент ZbReceived без Occupancy и device_class, перенести конфигурацию освещенности под sensor и добавить unit_of_measurement и unique_id. У каждого из этих двух вариантов одна ветка, итоги неизвестны.
Частые вопросы
Чем различаются value и value_json?
value содержит исходное сообщение как текст, а value_json - результат разбора JSON. По документации текстовая переменная доступна всегда, а разобранные данные - только при корректном JSON во входящем сообщении. Поэтому для просмотра исходного текста в обсуждении использовали срез value. Обе переменные описаны в документации по шаблонам.
Какие значения задавать payload_on и payload_off?
Эти опции задают строками. Они определяют значения сообщения для состояний включено и выключено у двоичного MQTT-датчика. В документации двоичных MQTT-датчиков есть пример со значениями ‘1’ и ‘0’ в кавычках. В журнале Vallhorn также встречались сообщения No matching payload found с результатами шаблона ‘on’, ‘True’ и ‘False’.
Чем смотреть полезную нагрузку MQTT?
В одной ветке форума предложили MQTT Explorer для просмотра сообщений брокера, итог неизвестен. В сообщениях Vallhorn встречаются объект ZbReceived и поля Occupancy и Illuminance. У Siemens LOGO значения находятся внутри state и reported, а часть сообщений содержит лишь $logotime. При просмотре полезно сопоставить эти поля с ключом, к которому обращается шаблон датчика.
Как перечитать MQTT-сущности после правки YAML?
Используйте действие mqtt.reload - оно перечитывает MQTT-сущности из YAML-конфигурации. В одной ветке форума советовали перезагрузить сущности после изменения определений, но результат остался неизвестным. Там упоминалось название Manually Created MQTT Entities; в документации MQTT-интеграции для этой операции указано действие mqtt.reload. Именно его можно использовать как ориентир при применении изменений конфигурации.
Что проверяет шаблон доступности AI2?
Он проверяет наличие AI2 и то, что его значение является числом. В одной ветке форума предложили такой вариант для LOGO, итог неизвестен. В документации MQTT-сенсора шаблон доступности извлекает доступность устройства из availability_topic, а результат сравнивается с сообщениями доступности. В предложении для AI2 проверка обращалась к первому элементу value внутри AI2.



