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

Temporarily remove the device_class, and use:

value_template: "{{ value[:250] }}"

What is the sensor state now?

Ok I now have the sensor defined like this:

  - name: "Vallhorn Landing Illuminance"
    state_topic: "tele/zigbee-bridge/vallhorn-landing/SENSOR"
    value_template: "{{ value_json[:250] }}"
    qos: 1

and I’m getting this in the log:

2024-07-24 13:43:14.328 ERROR (MainThread) [homeassistant.components.mqtt.client] Exception in _state_message_received when handling msg on 'tele/zigbee-bridge/vallhorn-landing/SENSOR': '{"ZbReceived":{"0x4D91":{"Device":"0x4D91","Name":"vallhorn-landing","Illuminance":15440,"Endpoint":3,"LinkQuality":31}}}'
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/components/mqtt/mixins.py", line 1270, in _message_callback
    msg_callback(msg)
  File "/usr/src/homeassistant/homeassistant/components/mqtt/sensor.py", line 293, in _state_message_received
    self._update_state(msg)
  File "/usr/src/homeassistant/homeassistant/components/mqtt/sensor.py", line 235, in _update_state
    payload = template(msg.payload, PayloadSentinel.DEFAULT)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/components/mqtt/models.py", line 352, in async_render_with_possible_json_value
    self._value_template.async_render_with_possible_json_value(
  File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 771, in async_render_with_possible_json_value
    render_result = _render_with_context(
                    ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 2616, in _render_with_context
    return template.render(**kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/jinja2/environment.py", line 1304, in render
    self.environment.handle_exception()
  File "/usr/local/lib/python3.12/site-packages/jinja2/environment.py", line 939, in handle_exception
    raise rewrite_traceback_stack(source=source)
  File "<template>", line 1, in top-level template code
KeyError: slice(None, 250, None)

1000 apologies, should have been {{ value[:250] }}. Edited above, please retry.

I’m hoping to see the (first 250 chars of the) MQTT message, although the error log above does show it, and there’s nothing wrong with your value_template:

Incidentally, why do you have the qos value set?

OK the sensor is now defined as below, but is not picking up the illuminance value. The value for illuminance in the HA console is now:

{"ZbReceived":{"0x4D91":{"Device":"0x4D91","Name":"vallhorn-landing","Illuminance":18573,"Endpoint":3,"LinkQuality":39}}}

The sensor is now defined like this:

  - name: "Vallhorn Landing Illuminance"
    state_topic: "tele/zigbee-bridge/vallhorn-landing/SENSOR"
    value_template: "{{ value[:250] }}"
    qos: 1

TBH I have no idea why I have QoS set!

I’ve just pasted the message received on the MQTT console into the HA Template tool, along with my original value_template (but this time for my other sensor, which is having exactly the same problem). This suggests that the template is fine, but I am still getting warnings in the HA log

2024-07-24 14:38:19.970 WARNING (MainThread) [homeassistant.helpers.template] Template variable warning: 'dict object' has no attribute 'Illuminance' when rendering '{{ value_json['ZbReceived']['0x1252']['Illuminance'] }}'
  - name: "Vallhorn Hall Illuminance"
    device_class: Illuminance
    state_topic: "tele/zigbee-bridge/vallhorn-hall/SENSOR"
    value_template: "{{ value_json['ZbReceived']['0x1252']['Illuminance'] }}"
    qos: 1

You’re using this MQTT topic to receive Illuminance and Occupancy.

tele/zigbee-bridge/vallhorn-hall/SENSOR

Based on what you posted, it appears that sometimes the topic’s payload contains data for Illuminance and other times it contains Occupancy.

The following template expects to receive data for Iluminance.

{{ value_json['ZbReceived']['0x1252']['Illuminance'] }}

What do you think happens when it receives a payload containing data for Occupancy instead? The answer is what you have already observed, it fails with an error message.

'dict object' has no attribute 'Illuminance'

I suggest you enhance the template to confirm the Illuminance attribute is defined before it attempts to use it. If it’s not defined then the template should report the sensor’s existing value.

  - 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) }}
    qos: 1

It wasn’t meant to. That value[250:] is just meant to dump the first 250 characters of the topic into the state, just to check what’s coming through.

Unless it’s something as simple as °qos` filtering, I’m beginning to think that the hex-like dict key might not be being handled properly on its way through the system. It works fine in the template editor.

Two things to try:

  1. Remove the qos line. I wonder if that’s filtering out the message…

  2. As a test, bypass the hexy attribute with this (or the Occupancy version instead):

value_template: "{{ ((value_json['ZbReceived'].values())|first)['Illuminance'] }}"

I removed the QoS line and used your value_template (but for the Occupancy attribute). This is what I now see in the log:

2024-07-25 11:28:38.988 WARNING (MainThread) [homeassistant.helpers.template] Template variable warning: 'dict object' has no attribute 'Occupancy' when rendering '{{ ((value_json['ZbReceived'].values())|first)['Occupancy'] }}'

This is very bizarre. Try it without the reference to Occupancy (and no device_class) just to see the structure:

value_template: "{{ (value_json['ZbReceived'].values())|first }}"

I wonder if you’re getting multiple messages on the topic, some of which have Occupancy and some don’t. If that’s the case, use Taras’s solution above.

My understanding is that one MQTT topic is used to publish the values of multiple sensors and their properties (i.e. the topic’s data is multiplexed).

That means sometime the JSON payload is for one sensor and one of its properties, other times it’s for the same sensor but another property and yet other times it’s for a completely different sensor. .

FWIW, this might be a good candidate for using a demultiplexing automation.

1 Like

Ah OK thanks that makes sense. I do indeed have one MQTT topic publishing two sensors (Occupancy and Illuninance). I’ve modified the definition as per your suggestion, Taras, but I’m now getting a “no matching payload” message in the logs. At this point there had been no Occupancy messages published on that topic.

This is the message in the HA log:

2024-07-27 13:10:04.589 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":14149,"Endpoint":3,"LinkQuality":39}}}', template output: '14149', with value template 'Template<template=({{ value_json['ZbReceived']['0x4D91']['Illuminance']
  if value_json['ZbReceived']['0x4D91']['Illuminance'] is defined
  else this.state | default(0, true) }}) renders=123>'

This is how my MQTT sensor is defined:

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

This is an example of an Illuminance MQTT message which is being received:

13:12:45.216 MQT: tele/zigbee-bridge/vallhorn-landing/SENSOR = {"ZbReceived":{"0x4D91":{"Device":"0x4D91","Name":"vallhorn-landing","Illuminance":13424,"Endpoint":3,"LinkQuality":39}}}

I think you defined the sensor in the wrong place.

The configuration I provided is for a sensor but the error message you posted indicates you put the sensor’s configuration under binary_sensor.

2024-07-27 13:10:04.589 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”:14149,“Endpoint”:3,“LinkQuality”:39}}}’,
template output: ‘14149’,
with value template
‘Template<template=({{ value_json[‘ZbReceived’][‘0x4D91’][‘Illuminance’]
if value_json[‘ZbReceived’][‘0x4D91’][‘Illuminance’] is defined
else this.state | default(0, true) }}) renders=123>’

As you can see, the template extracted and reported the correct illuminance value (14149) but because you defined it as a binary_sensor, that value is not considered to be valid for a Binary Sensor.

Move the sensor’s configuration to the correct place, under sensor: not binary_sensor:

I also suggest you specify the unit_of_measurement and provide a unique_id. For example, here is what I tested on my system:

mqtt:
  - sensor:
      - name: "Vallhorn Landing Illuminance"
        unique_id: vallhorn_landing_illuminance_2024_07_27
        device_class: illuminance
        unit_of_measurement: lx
        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) }}

After reloading “Manually Configured MQTT Entities”, the sensor appeared in Developer tools → States with an initial value of unknown. I then used MQTT Explorer to publish the payload you posted above and here is the result:

OK thanks. Since I also need to define binary sensors for motion detection/Occupancy - monitoring the same MQTT topic - what value_template should I use for the binary sensor?

So for example this is how my binary sensor is currently defined:

  - name: "PIR Vallhorn Landing"
    state_topic: "tele/zigbee-bridge/vallhorn-landing/SENSOR"
    value_template: "{{ ((value_json['ZbReceived'].values())|first)['Occupancy'] }}"
    payload_off: '0'
    payload_on: '1'

…and results in these messages in the log:

WARNING (MainThread) [homeassistant.helpers.template] Template variable warning: 'dict object' has no attribute 'Occupancy' when rendering '{{ ((value_json['ZbReceived'].values())|first)['Occupancy'] }}'

You’re welcome!

Please consider marking my post above with the Solution tag. It will automatically place a check-mark next to the topic’s title which signals to other users that this topic has been resolved. This helps users find answers to similar questions.

For more information about the Solution tag, refer to guideline 21 in the FAQ.


I need to see an example of the payload sent when occupancy is reported in order to confirm the values provided for the “Occupancy” key. The following example, for an MQTT Binary Sensor, assumes the values are numeric 1 and 0.

    - name: "PIR Vallhorn Landing"
      unique_id: pir_vallhorn_landing_2024_07_27
      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

If the values are not numeric 1 and 0 or are strings, then the template will need modifications.

Done - thanks again.

This is an example of the Occupancy payload:

tele/zigbee-bridge/vallhorn-hall/SENSOR = {"ZbReceived":{"0x1252":{"Device":"0x1252","Name":"vallhorn-hall","Occupancy":0,"Endpoint":2,"LinkQuality":89}}}

Thanks for the payload sample. The assumption was correct; the occupancy values are numeric 1 and 0.

So this is the code that I have for the binary occupancy sensors:

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

The log is still reporting the messages below, I guess when it encounters the Illuminance message on the same topic. Is this expected behaviour?

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":16989,"Endpoint":3,"LinkQuality":29}}}', template output: 'on', with value template 'Template<template=({{ value_json['ZbReceived']['0x4D91']['Occupancy']
  if value_json['ZbReceived']['0x4D91']['Occupancy'] is defined

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.