'dict object' has no attribute 'Occupancy' when rendering

Here’s what I suggested to use in my example posted above:

      payload_off: 0
      payload_on: 1

Here’s what you have:

    payload_off: '0'
    payload_on: '1'

See the difference?

That’s why it reports “No matching payload”. The received value for the Occupancy key is an integer value. It’s integer 0 in the following payload example.

{
    "ZbReceived": {
        "0x1252": {
            "Device": "0x1252",
            "Name": "vallhorn-hall",
            "Occupancy": 0,
            "Endpoint": 2,
            "LinkQuality": 89
        }
    }
}

However, your version is configured to look for a string value. It’s looking for '0' for off and '1' for on.

Either remove the quotes surrounding 1 and 0 or use this version that doesn’t use payload_on and payload_off.


  - name: "PIR Vallhorn Landing"
    state_topic: "tele/zigbee-bridge/vallhorn-landing/SENSOR"
    device_class: occupancy
    value_template: >
      {% set x = value_json['ZbReceived']['0x4D91']['Occupancy']
        if value_json['ZbReceived']['0x4D91']['Occupancy'] is defined
        else this.state | default(0, true) %}
      {{ x | int(0) == 1 }}

Ah OK yes I see that the payload is an integer, rather than a string. Sorry to be dumb…So I now have my sensor and my binary sensor defined as below, but am still getting messages in the log…

Sensor:

  - name: "Vallhorn Landing Illuminance"
    device_class: illuminance
    state_topic: "tele/zigbee-bridge/vallhorn-landing/SENSOR"
    value_template: >
      {{ value_json['ZbReceived']['0x4D91']['Illuminance']
        if value_json['ZbReceived']['0x4D91']['Illuminance'] is defined
        else this.state | default(0, true) }}

Binary sensor:

  - name: "PIR Vallhorn Landing"
    state_topic: "tele/zigbee-bridge/vallhorn-landing/SENSOR"
    device_class: occupancy
    value_template: >
        {{ value_json['ZbReceived']['0x4D91']['Occupancy']
          if value_json['ZbReceived']['0x4D91']['Occupancy'] is defined
          else this.state | default(0, true) }}
    payload_off: 0
    payload_on: 1

Log message:

INFO (MainThread) [homeassistant.components.mqtt.binary_sensor] No matching payload found for entity: binary_sensor.pir_vallhorn_landing with state topic: tele/zigbee-bridge/vallhorn-landing/SENSOR. Payload: '{"ZbReceived":{"0x4D91":{"Device":"0x4D91","Name":"vallhorn-landing","Illuminance":17481,"Endpoint":3,"LinkQuality":29}}}', template output: 'off', with value template 'Template<template=({{ value_json['ZbReceived']['0x4D91']['Occupancy']
  if value_json['ZbReceived']['0x4D91']['Occupancy'] is defined
  else this.state | default(0, true) }}) renders=5>'

Change the binary_sensor’s configuration to the version I posted above that doesn’t use payload_on and payload_off.

Hmmm…I seem to be chasing my tail a bit here…so here are the sensor definitions:

  - name: "Vallhorn Landing Illuminance"
    device_class: illuminance
    state_topic: "tele/zigbee-bridge/vallhorn-landing/SENSOR"
    value_template: >
      {{ value_json['ZbReceived']['0x4D91']['Illuminance']
        if value_json['ZbReceived']['0x4D91']['Illuminance'] is defined
        else this.state | default(0, true) }}
  - name: "Vallhorn Hall Illuminance"
    device_class: Illuminance
    state_topic: "tele/zigbee-bridge/vallhorn-hall/SENSOR"
    value_template: >
      {{ value_json['ZbReceived']['0x1252']['Illuminance']
        if value_json['ZbReceived']['0x1252']['Illuminance'] is defined
        else this.state | default(0, true) }}

…and here are the binary sensors:

  - name: "PIR Vallhorn Landing"
    state_topic: "tele/zigbee-bridge/vallhorn-landing/SENSOR"
    device_class: occupancy
    value_template: >
      {% set x = value_json['ZbReceived']['0x4D91']['Occupancy']
        if value_json['ZbReceived']['0x4D91']['Occupancy'] is defined
        else this.state | default(0, true) %}
      {{ x | int(0) == 1 }}
#Vallhorn PIR in Hall
  - name: "PIR Vallhorn Hall"
    state_topic: "tele/zigbee-bridge/vallhorn-hall/SENSOR"
    device_class: occupancy
    value_template: >
      {% set x = value_json['ZbReceived']['0x1252']['Occupancy']
        if value_json['ZbReceived']['0x1252']['Occupancy'] is defined
        else this.state | default(0, true) %}
      {{ x | int(0) == 1 }}

…and these are the error messages that I am now seeing in the log:

ERROR (MainThread) [homeassistant.components.mqtt.models] Exception raised while updating state of sensor.vallhorn_landing_illuminance, topic: 'tele/zigbee-bridge/vallhorn-landing/SENSOR' with payload: b'{"ZbReceived":{"0x4D91":{"Device":"0x4D91","Name":"vallhorn-landing","Occupancy":0,"Endpoint":2,"LinkQuality":34}}}'
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/components/sensor/__init__.py", line 658, in state
    numerical_value = int(value)
                      ^^^^^^^^^^
ValueError: invalid literal for int() with base 10: 'unknown'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/components/sensor/__init__.py", line 661, in state
    numerical_value = float(value)
                      ^^^^^^^^^^^^
ValueError: could not convert string to float: 'unknown'

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/components/mqtt/models.py", line 380, in process_write_state_requests
    entity.async_write_ha_state()
  File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 1000, in async_write_ha_state
    self._async_write_ha_state()
  File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 1126, in _async_write_ha_state
    state, attr, capabilities, shadowed_attr = self.__async_calculate_state()
                                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 1061, in __async_calculate_state
    state = self._stringify_state(available)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 1006, in _stringify_state
    if (state := self.state) is None:
                 ^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/components/sensor/__init__.py", line 665, in state
    raise ValueError(
ValueError: Sensor sensor.vallhorn_landing_illuminance has device class 'illuminance', state class 'None' unit 'None' and suggested precision 'None' thus indicating it has a numeric value; however, it has the non-numeric value: 'unknown' (<class 'str'>)
2024-07-30 21:44:37.676 INFO (MainThread) [homeassistant.components.mqtt.binary_sensor] No matching payload found for entity: binary_sensor.pir_vallhorn_hall with state topic: tele/zigbee-bridge/vallhorn-hall/SENSOR. Payload: '{"ZbReceived":{"0x1252":{"Device":"0x1252","Name":"vallhorn-hall","0006!42":"0058020000","Power":1,"PowerOnlyWhenOn":0,"PowerOnTime":60,"PowerOffWait":0,"Endpoint":1,"LinkQuality":81}}}', template output: 'False', with value template 'Template<template=({% set x = value_json['ZbReceived']['0x1252']['Occupancy']
  if value_json['ZbReceived']['0x1252']['Occupancy'] is defined
  else this.state | default(0, true) %}
{{ x | int(0) == 1 }}) renders=1>'
2024-07-30 21:44:37.677 ERROR (MainThread) [homeassistant.components.mqtt.models] Exception raised while updating state of sensor.vallhorn_hall_illuminance, topic: 'tele/zigbee-bridge/vallhorn-hall/SENSOR' with payload: b'{"ZbReceived":{"0x1252":{"Device":"0x1252","Name":"vallhorn-hall","0006!42":"0058020000","Power":1,"PowerOnlyWhenOn":0,"PowerOnTime":60,"PowerOffWait":0,"Endpoint":1,"LinkQuality":81}}}'
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/components/sensor/__init__.py", line 658, in state
    numerical_value = int(value)
                      ^^^^^^^^^^
ValueError: invalid literal for int() with base 10: 'unknown'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/components/sensor/__init__.py", line 661, in state
    numerical_value = float(value)
                      ^^^^^^^^^^^^
ValueError: could not convert string to float: 'unknown'

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/components/mqtt/models.py", line 380, in process_write_state_requests
    entity.async_write_ha_state()
  File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 1000, in async_write_ha_state
    self._async_write_ha_state()
  File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 1126, in _async_write_ha_state
    state, attr, capabilities, shadowed_attr = self.__async_calculate_state()
                                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 1061, in __async_calculate_state
    state = self._stringify_state(available)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 1006, in _stringify_state
    if (state := self.state) is None:
                 ^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/components/sensor/__init__.py", line 665, in state
    raise ValueError(
ValueError: Sensor sensor.vallhorn_hall_illuminance has device class 'illuminance', state class 'None' unit 'None' and suggested precision 'None' thus indicating it has a numeric value; however, it has the non-numeric value: 'unknown' (<class 'str'>)
2024-07-30 21:44:38.052 INFO (MainThread) [homeassistant.components.mqtt.binary_sensor] No matching payload found for entity: binary_sensor.pir_vallhorn_hall with state topic: tele/zigbee-bridge/vallhorn-hall/SENSOR. Payload: '{"ZbReceived":{"0x1252":{"Device":"0x1252","Name":"vallhorn-hall","Occupancy":1,"Endpoint":2,"LinkQuality":81}}}', template output: 'True', with value template 'Template<template=({% set x = value_json['ZbReceived']['0x1252']['Occupancy']
  if value_json['ZbReceived']['0x1252']['Occupancy'] is defined
  else this.state | default(0, true) %}
{{ x | int(0) == 1 }}) renders=2>'

I imagine this has become frustrating for you and I can understand why.

Let’s try a completely different approach. Six days ago I said the following:

That’s what I suggest you do now. What I am proposing below is something I have tested on my system, using the same JSON payloads your Zigbee Bridge is producing, and it works properly (no error messages).

First create the following automation:

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

Then create the following MQTT Sensors:

  - 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"

Finally create the following MQTT Binary Sensors:

  - 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') }}"

Here are the four entities on my system after I have published illuminance and occupancy data.

The automation listens to all topics beginning with tele/zigbee-bridge/ and then re-publishes their payload to a new, more descriptive topic that includes the device’s name and the specific property type (illuminance or occupancy). For example:
zb/vallhorn-landing/illuminance

Each one of the MQTT Sensors and MQTT Binary Sensors gets its own MQTT topic. The payload published to that topic is a simple integer value. A binary_sensor only gets occupancy data and never illuminance and the sensor only gets illuminance data, not occupancy data. As a result, the entity’s configuration is greatly simplified.


EDIT 1

I added unit_of_measurement: lx to the illuminance sensors. Without specifying that, Home Assistant will report a warning message that the sensor reports a numeric value but lacks a unit of measurement.

EDIT 2

Correction in automation. Overlooked to include lower filter to set property value to lowercase.

Thanks for that. So I have the automation and sensors defined as per your examples, and I see the new messages being published on the zb\ topic, but the sensor states are showing as “unknown” in the Lovelace UI

MQTT sensors:

  - 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"

Binary sensors:

  - 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') }}"

Automation:

alias: zigbee bridge demultiplexer
description: ""
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 }}
      payload: "{{ msg }}"
      retain: true

I have already demonstrated that it works so something is either missing or different on your system. I assume that after you changed the configuration of all four entities that you executed Developer Tools → YAML → Reload Manually Created MQTT Entities.

What are you using to confirm that payloads are published to the following four topics?

zb/vallhorn-landing/illuminance
zb/vallhorn-hall/illuminance
zb/vallhorn-landing/occupancy
zb/vallhorn-hall/occupancy

If you’re using MQTT Explorer, post a screenshot of the topics and at least one payload.


NOTE

When replying to my posts, use the reply icon in my post. This will serve to notify me of your reply.

When you use the Reply button at the bottom of the topic, I am not notified of your reply. In that case the only way I know if you replied is by examining the topic.

Is this a case problem? Source MQTT topics are Illuminance and Occupancy — a quick read of your multiplexer suggests that title case will persist into the output.

1 Like

Yes - that was it! The topic names are indeed case sensitive. I’ve now changed the state_topic in the sensor definitions to zb/vallhorn-landing/Occupancy and zb/vallhorn-landing/Illuminance and all sensors are now in the correct state (and no warnings in the HA log).
Many thanks for all of the help!

1 Like

You’re right! The automation went through several revisions during testing and I ultimately posted the second-to-last version (my excuse is it was very late). :man_facepalming:

Here’s a screenshot of the final working version on my system and it shows that it had a lower filter to convert the property value to lowercase.

My personal preference is to have MQTT topics in lowercase so that’s why lower was added to the final version of the automation which, unfortunately, wasn’t the one I copied into the forum. :roll_eyes:

FWIW, I have corrected the automation posted above so it will work correctly for anyone else wishing to use it.


If lower is not added to the automation then the MQTT topics, in the sensor configurations, must be case-sensitive and use Occupancy and Illuminance.

zb/vallhorn-landing/Illuminance
zb/vallhorn-hall/Illuminance
zb/vallhorn-landing/Occupancy
zb/vallhorn-hall/Occupancy
1 Like

You’re welcome! I’m glad to hear it now works properly and without error/warning messages.

Looking back at this journey makes me realize I should have followed through on my suggestion to use a demultiplexer automation from the very start.

It’s based on the same proven technique I had suggested over five years ago for users of the Sonoff RF Bridge (which also uses one topic to publish different JSON payoads). Back then, the solution involved a combination of automation and python_script but nowadays, due to scripting enhancements, it can be done with just an automation.

If you don’t mind, please move the Solution tag to my post containing the demultiplexer automation. Given that this topic contains over 30 posts, it will help other users jump to the correct solution.