zigbee2mqtt icon indicating copy to clipboard operation
zigbee2mqtt copied to clipboard

Xiaomi ZNCLBL01LM: Template variable warning: 'dict object' has no attribute 'motor_state' when rendering '{{ value_json.motor_state }}'

Open buhito81 opened this issue 3 years ago • 9 comments

What happened?

Very frequent error

Template variable warning: 'dict object' has no attribute 'motor_state' when rendering '{{ value_json.motor_state }}'. I thought I had resolved it in https://github.com/Koenkk/zigbee2mqtt/issues/14023, but that's not the case. I'm a bit lost, but because of this error automations from HA either run/stop running inconsistently. I'd love to help on this, but I don't understand how to change the payload to always include a value or where to find the information for this:

Given that motor_state is in the published payload, this seems to be a HA issue (or a very confusing error message)

I thought I had this fixed, but I don't. motor_state is not in the published payload, please see below

What did you expect to happen?

No errors

How to reproduce it (minimal and precise)

Connect the ZNCLBL01LM device to Zigbee2MQTT

Zigbee2MQTT version

1.27.2 commit: unknown, 1.28.2 commit: unknown

Adapter firmware version

0x26720700

Adapter

ConBee2/RaspBee2

Debug log

2022-11-21 10:22:28.624 DEBUG (MainThread) [homeassistant.components.mqtt.client] Received message on zigbee2mqtt/Bedroom Curtain Right: b'{"action":null,"battery":100,"charging":false,"device_temperature":18,"hooks_state":"locked","last_seen":"2022-11-21T09:22:28.609Z","linkquality":255,"position":72,"power_outage_count":7,"power_source":"battery","running":false,"state":"CLOSE","target_position":72,"update":{"state":"available"},"update_available":true,"voltage":3000}'
2022-11-21 10:22:28.625 DEBUG (MainThread) [homeassistant.components.mqtt.models] Rendering incoming payload '{"action":null,"battery":100,"charging":false,"device_temperature":18,"hooks_state":"locked","last_seen":"2022-11-21T09:22:28.609Z","linkquality":255,"position":72,"power_outage_count":7,"power_source":"battery","running":false,"state":"CLOSE","target_position":72,"update":{"state":"available"},"update_available":true,"voltage":3000}' with variables {'entity_id': 'sensor.bedroom_curtain_right_battery', 'name': 'Bedroom Curtain Right battery', 'this': <template TemplateStateFromEntityId(sensor.bedroom_curtain_right_battery)>} with default value '100' and Template("{{ value_json.battery }}")
2022-11-21 10:22:28.626 DEBUG (MainThread) [homeassistant.components.mqtt.models] Rendering incoming payload '{"action":null,"battery":100,"charging":false,"device_temperature":18,"hooks_state":"locked","last_seen":"2022-11-21T09:22:28.609Z","linkquality":255,"position":72,"power_outage_count":7,"power_source":"battery","running":false,"state":"CLOSE","target_position":72,"update":{"state":"available"},"update_available":true,"voltage":3000}' with variables {'entity_id': 'sensor.bedroom_curtain_right_device_temperature', 'name': 'Bedroom Curtain Right device temperature', 'this': <template TemplateStateFromEntityId(sensor.bedroom_curtain_right_device_temperature)>} with default value '18' and Template("{{ value_json.device_temperature }}")
2022-11-21 10:22:28.626 DEBUG (MainThread) [homeassistant.components.mqtt.models] Rendering incoming payload '{"action":null,"battery":100,"charging":false,"device_temperature":18,"hooks_state":"locked","last_seen":"2022-11-21T09:22:28.609Z","linkquality":255,"position":72,"power_outage_count":7,"power_source":"battery","running":false,"state":"CLOSE","target_position":72,"update":{"state":"available"},"update_available":true,"voltage":3000}' with variables {'entity_id': 'sensor.bedroom_curtain_right_action', 'name': 'Bedroom Curtain Right action', 'this': <template TemplateStateFromEntityId(sensor.bedroom_curtain_right_action)>} with default value 'None' and Template("{{ value_json.action }}")
2022-11-21 10:22:28.626 DEBUG (MainThread) [homeassistant.components.mqtt.models] Rendering incoming payload '{"action":null,"battery":100,"charging":false,"device_temperature":18,"hooks_state":"locked","last_seen":"2022-11-21T09:22:28.609Z","linkquality":255,"position":72,"power_outage_count":7,"power_source":"battery","running":false,"state":"CLOSE","target_position":72,"update":{"state":"available"},"update_available":true,"voltage":3000}' with variables {'entity_id': 'sensor.bedroom_curtain_right_motor_state', 'name': 'Bedroom Curtain Right motor state', 'this': <template TemplateStateFromEntityId(sensor.bedroom_curtain_right_motor_state)>} with default value '' and Template("{{ value_json.motor_state }}")
2022-11-21 10:22:28.626 WARNING (MainThread) [homeassistant.helpers.template] Template variable warning: 'dict object' has no attribute 'motor_state' when rendering '{{ value_json.motor_state }}'
2022-11-21 10:22:28.629 DEBUG (MainThread) [homeassistant.components.mqtt.models] Rendering incoming payload '{"action":null,"battery":100,"charging":false,"device_temperature":18,"hooks_state":"locked","last_seen":"2022-11-21T09:22:28.609Z","linkquality":255,"position":72,"power_outage_count":7,"power_source":"battery","running":false,"state":"CLOSE","target_position":72,"update":{"state":"available"},"update_available":true,"voltage":3000}' with variables {'entity_id': 'sensor.bedroom_curtain_right_hooks_state', 'name': 'Bedroom Curtain Right hooks state', 'this': <template TemplateStateFromEntityId(sensor.bedroom_curtain_right_hooks_state)>} with default value 'locked' and Template("{{ value_json.hooks_state }}")
2022-11-21 10:22:28.630 DEBUG (MainThread) [homeassistant.components.mqtt.models] Rendering incoming payload '{"action":null,"battery":100,"charging":false,"device_temperature":18,"hooks_state":"locked","last_seen":"2022-11-21T09:22:28.609Z","linkquality":255,"position":72,"power_outage_count":7,"power_source":"battery","running":false,"state":"CLOSE","target_position":72,"update":{"state":"available"},"update_available":true,"voltage":3000}' with variables {'entity_id': 'sensor.bedroom_curtain_right_target_position', 'name': 'Bedroom Curtain Right target position', 'this': <template TemplateStateFromEntityId(sensor.bedroom_curtain_right_target_position)>} with default value '72' and Template("{{ value_json.target_position }}")
2022-11-21 10:22:28.630 DEBUG (MainThread) [homeassistant.components.mqtt.models] Rendering incoming payload '{"action":null,"battery":100,"charging":false,"device_temperature":18,"hooks_state":"locked","last_seen":"2022-11-21T09:22:28.609Z","linkquality":255,"position":72,"power_outage_count":7,"power_source":"battery","running":false,"state":"CLOSE","target_position":72,"update":{"state":"available"},"update_available":true,"voltage":3000}' with variables {'entity_id': 'sensor.bedroom_curtain_right_power_source', 'name': 'Bedroom Curtain Right power source', 'this': <template TemplateStateFromEntityId(sensor.bedroom_curtain_right_power_source)>} with default value 'battery' and Template("{{ value_json.power_source }}")
2022-11-21 10:22:28.630 DEBUG (MainThread) [homeassistant.components.mqtt.models] Rendering incoming payload '{"action":null,"battery":100,"charging":false,"device_temperature":18,"hooks_state":"locked","last_seen":"2022-11-21T09:22:28.609Z","linkquality":255,"position":72,"power_outage_count":7,"power_source":"battery","running":false,"state":"CLOSE","target_position":72,"update":{"state":"available"},"update_available":true,"voltage":3000}' with variables {'entity_id': 'binary_sensor.bedroom_curtain_right_running', 'name': 'Bedroom Curtain Right running', 'this': <template TemplateStateFromEntityId(binary_sensor.bedroom_curtain_right_running)>} and Template("{{ value_json.running }}")
2022-11-21 10:22:28.631 DEBUG (MainThread) [homeassistant.components.mqtt.models] Rendering incoming payload '{"action":null,"battery":100,"charging":false,"device_temperature":18,"hooks_state":"locked","last_seen":"2022-11-21T09:22:28.609Z","linkquality":255,"position":72,"power_outage_count":7,"power_source":"battery","running":false,"state":"CLOSE","target_position":72,"update":{"state":"available"},"update_available":true,"voltage":3000}' with variables {'entity_id': 'binary_sensor.bedroom_curtain_right_charging', 'name': 'Bedroom Curtain Right charging', 'this': <template TemplateStateFromEntityId(binary_sensor.bedroom_curtain_right_charging)>} and Template("{{ value_json.charging }}")
2022-11-21 10:22:28.631 DEBUG (MainThread) [homeassistant.components.mqtt.models] Rendering incoming payload '{"action":null,"battery":100,"charging":false,"device_temperature":18,"hooks_state":"locked","last_seen":"2022-11-21T09:22:28.609Z","linkquality":255,"position":72,"power_outage_count":7,"power_source":"battery","running":false,"state":"CLOSE","target_position":72,"update":{"state":"available"},"update_available":true,"voltage":3000}' with variables {'entity_id': 'binary_sensor.bedroom_curtain_right_update_available', 'name': 'Bedroom Curtain Right update available', 'this': <template TemplateStateFromEntityId(binary_sensor.bedroom_curtain_right_update_available)>} and Template("{{ value_json['update']['state'] == "available" }}")
2022-11-21 10:22:28.631 DEBUG (MainThread) [homeassistant.components.mqtt.models] Rendering incoming payload '{"action":null,"battery":100,"charging":false,"device_temperature":18,"hooks_state":"locked","last_seen":"2022-11-21T09:22:28.609Z","linkquality":255,"position":72,"power_outage_count":7,"power_source":"battery","running":false,"state":"CLOSE","target_position":72,"update":{"state":"available"},"update_available":true,"voltage":3000}' with variables {'position_open': 100, 'position_closed': 0, 'tilt_min': 0, 'tilt_max': 100, 'entity_id': 'cover.bedroom_curtain_right', 'name': 'Bedroom Curtain Right', 'this': <template TemplateStateFromEntityId(cover.bedroom_curtain_right)>} and Template("{{ value_json.position }}")
2022-11-21 10:22:28.631 DEBUG (MainThread) [homeassistant.components.mqtt.models] Rendering incoming payload '{"action":null,"battery":100,"charging":false,"device_temperature":18,"hooks_state":"locked","last_seen":"2022-11-21T09:22:28.609Z","linkquality":255,"position":72,"power_outage_count":7,"power_source":"battery","running":false,"state":"CLOSE","target_position":72,"update":{"state":"available"},"update_available":true,"voltage":3000}' with variables {'entity_id': 'cover.bedroom_curtain_right', 'name': 'Bedroom Curtain Right', 'this': <template TemplateStateFromEntityId(cover.bedroom_curtain_right)>} and Template("{% if not value_json.motor_state %} stopped {% else %} {{ value_json.motor_state }} {% endif %}")
2022-11-21 10:22:28.631 WARNING (MainThread) [homeassistant.helpers.template] Template variable warning: 'dict object' has no attribute 'motor_state' when rendering '{% if not value_json.motor_state %} stopped {% else %} {{ value_json.motor_state }} {% endif %}'

buhito81 avatar Nov 21 '22 10:11 buhito81

In case someone mistakes the "update":{"state":"available"} for me not updating the firmware, https://github.com/Koenkk/zigbee2mqtt/issues/13801#event-7331317095 describes this issue (on the Aqara side).

buhito81 avatar Nov 21 '22 10:11 buhito81

It looks like motor_state has only been added to the converter for the device and not as a key / converter in toZigbee - you will need to add an appropriate entry into there if this state can be set. There also isn't a key to convert the value returned from the device in fromZigbee either..

You may be able to get somewhere in the fromZigbee converters by adapting xiaomi_curtain_hagl04_status - in your previous PR, what is the difference between stopped and pause on the device state?

Thanks for your elaborate reply. Since motor_state cannot be controlled/sent (but only received), I take it I'll have to add it to fromZigbee?

I have tried two things;

  1. Looking at xiaomi_curtain_hagl04_status. I understand it takes data from the cluster genMultistateOutput and converts the values from there. I don't seem to be able however to 'get' such an attribute report from within Zigbee2MQTT as there doesn't seem to be something like an attributeReport available:

image

  1. Since apart from owning several ZNCLBL01LM devices I also own several ZNJLBL01LM devices (and they don't seem to have the motor_state errors, I looked at them too. It uses similar functionality in fromZigbee (xiaomi_curtain_acn002_status) and very similar functionality in xiaomi.js.

So I created a custom converter, in order to start changing/reverse engineering (nothing special here, just copied the data from xiaomi.js and added fz.xiaomi_curtain_hagl04_status:

const fz = require('zigbee-herdsman-converters/converters/fromZigbee');
const tz = require('zigbee-herdsman-converters/converters/toZigbee');
const exposes = require('zigbee-herdsman-converters/lib/exposes');
const reporting = require('zigbee-herdsman-converters/lib/reporting');
const extend = require('zigbee-herdsman-converters/lib/extend');
const e = exposes.presets;
const ea = exposes.access;

const definition = {
    zigbeeModel: ['lumi.curtain.acn003', 'lumi.curtain.agl001'],
    model: 'ZNCLBL01LM',
    vendor: 'Xiaomi',
    whiteLabel: [{vendor: 'Xiaomi', model: 'CM-M01'}],
    description: 'Aqara curtain driver E1',
    fromZigbee: [fz.battery, fz.xiaomi_curtain_position_tilt, fz.aqara_opple, fz.power_source, fz.xiaomi_curtain_hagl04_status],
    toZigbee: [tz.xiaomi_curtain_position_state, tz.ZNCLBL01LM_battery_voltage, tz.ZNCLBL01LM_hooks_state,
        tz.power_source, tz.battery_percentage_remaining],
    exposes: [e.cover_position().setAccess('state', ea.ALL), e.battery().withAccess(ea.STATE_GET),
        e.battery_voltage().withAccess(ea.STATE_GET),
        e.device_temperature(),
        e.action(['manual_open', 'manual_close']),
        exposes.enum('motor_state', ea.STATE, ['stopped', 'opening', 'closing', 'pause'])
            .withDescription('Motor state'),
        exposes.binary('running', ea.STATE, true, false)
            .withDescription('Whether the motor is moving or not'),
        exposes.enum('hooks_state', ea.STATE_GET, ['unlocked', 'locked', 'locking', 'unlocking'])
            .withDescription('Hooks state'),
        exposes.numeric('target_position', ea.STATE).withUnit('%').withDescription('Target position'),
        exposes.enum('power_source', ea.STATE_GET, ['battery', 'dc_source']).withDescription('The current power source'),
        exposes.binary('charging', ea.STATE_GET, true, false).withDescription('The current charging state')],
        configure: async (device, coordinatorEndpoint, logger) => {
            const endpoint = device.getEndpoint(1);
            await endpoint.read('genPowerCfg', ['batteryPercentageRemaining']);
            await endpoint.read('aqaraOpple', [0x040B], {manufacturerCode: 0x115f});
            await endpoint.read('aqaraOpple', [0x0428], {manufacturerCode: 0x115f});
            await endpoint.read('genBasic', ['powerSource']);
            await endpoint.read('closuresWindowCovering', ['currentPositionLiftPercentage']);
        },
};

module.exports = definition;

Obviously this'll not work out of the box, so I'm trying to understand where to find the values that are being converted into the motor state and how to retreive them, in order to properly convert them.

I do see however that (at current) the motor_state is sometimes passed, and sometimes isn't:

Zigbee2MQTT:info  2022-11-21 13:05:08: MQTT publish: topic 'zigbee2mqtt/Bedroom Curtain Right', payload '{"action":null,"battery":100,"charging":false,"device_temperature":18,"hooks_state":"locked","last_seen":"2022-11-21T12:05:08.742Z","linkquality":255,"motor_state":"stopped","position":0,"power_outage_count":7,"power_source":"battery","running":false,"state":"OPEN","target_position":0,"update":{"state":"available"},"update_available":true,"voltage":3000}'
Zigbee2MQTT:debug 2022-11-21 13:05:08: Received Zigbee message from 'Bedroom Curtain Right', type 'attributeReport', cluster 'aqaraOpple', data '{"1055":0}' from endpoint 1 with groupID null
Zigbee2MQTT:debug 2022-11-21 13:05:08: lumi.curtain.acn003,lumi.curtain.agl001: Processed data into payload {"target_position":100}
Zigbee2MQTT:info  2022-11-21 13:05:08: MQTT publish: topic 'zigbee2mqtt/Bedroom Curtain Right', payload '{"action":null,"battery":100,"charging":false,"device_temperature":18,"hooks_state":"locked","last_seen":"2022-11-21T12:05:08.842Z","linkquality":255,"motor_state":"stopped","position":0,"power_outage_count":7,"power_source":"battery","running":false,"state":"OPEN","target_position":100,"update":{"state":"available"},"update_available":true,"voltage":3000}'
Zigbee2MQTT:debug 2022-11-21 13:05:09: Received Zigbee message from 'Bedroom Curtain Right', type 'attributeReport', cluster 'aqaraOpple', data '{"1057":0}' from endpoint 1 with groupID null
Zigbee2MQTT:debug 2022-11-21 13:05:09: lumi.curtain.acn003,lumi.curtain.agl001: Processed data into payload {"motor_state":"opening","running":true}
Zigbee2MQTT:info  2022-11-21 13:05:09: MQTT publish: topic 'zigbee2mqtt/Bedroom Curtain Right', payload '{"action":null,"battery":100,"charging":false,"device_temperature":18,"hooks_state":"locked","last_seen":"2022-11-21T12:05:09.825Z","linkquality":255,"motor_state":"opening","position":0,"power_outage_count":7,"power_source":"battery","running":true,"state":"OPEN","target_position":100,"update":{"state":"available"},"update_available":true,"voltage":3000}'
Zigbee2MQTT:debug 2022-11-21 13:05:18: Received Zigbee message from 'Bedroom Curtain Right', type 'attributeReport', cluster 'aqaraOpple', data '{"1057":3}' from endpoint 1 with groupID null
Zigbee2MQTT:debug 2022-11-21 13:05:18: lumi.curtain.acn003,lumi.curtain.agl001: Processed data into payload {"running":false}
Zigbee2MQTT:info  2022-11-21 13:05:18: MQTT publish: topic 'zigbee2mqtt/Bedroom Curtain Right', payload '{"action":null,"battery":100,"charging":false,"device_temperature":18,"hooks_state":"locked","last_seen":"2022-11-21T12:05:18.885Z","linkquality":255,"position":0,"power_outage_count":7,"power_source":"battery","running":false,"state":"OPEN","target_position":100,"update":{"state":"available"},"update_available":true,"voltage":3000}'
Zigbee2MQTT:debug 2022-11-21 13:05:18: Received Zigbee message from 'Bedroom Curtain Right', type 'attributeReport', cluster 'aqaraOpple', data '{"1055":35}' from endpoint 1 with groupID null
Zigbee2MQTT:debug 2022-11-21 13:05:18: lumi.curtain.acn003,lumi.curtain.agl001: Processed data into payload {"target_position":65}
Zigbee2MQTT:info  2022-11-21 13:05:18: MQTT publish: topic 'zigbee2mqtt/Bedroom Curtain Right', payload '{"action":null,"battery":100,"charging":false,"device_temperature":18,"hooks_state":"locked","last_seen":"2022-11-21T12:05:18.916Z","linkquality":255,"position":0,"power_outage_count":7,"power_source":"battery","running":false,"state":"OPEN","target_position":65,"update":{"state":"available"},"update_available":true,"voltage":3000}'
Zigbee2MQTT:debug 2022-11-21 13:05:18: Received Zigbee message from 'Bedroom Curtain Right', type 'attributeReport', cluster 'closuresWindowCovering', data '{"currentPositionLiftPercentage":35}' from endpoint 1 with groupID null
Zigbee2MQTT:info  2022-11-21 13:05:18: MQTT publish: topic 'zigbee2mqtt/Bedroom Curtain Right', payload '{"action":null,"battery":100,"charging":false,"device_temperature":18,"hooks_state":"locked","last_seen":"2022-11-21T12:05:18.943Z","linkquality":255,"position":65,"power_outage_count":7,"power_source":"battery","running":false,"state":"CLOSE","target_position":65,"update":{"state":"available"},"update_available":true,"voltage":3000}'

What am I missing? I'm very sorry if I'm a complete noob or asking very stupid questions here.

buhito81 avatar Nov 21 '22 12:11 buhito81

I guess the first question to ask - do you have an aqara hub that you could temporarily join the device to? - We need to establish if motor_state is something that is actually reported by the device.

The above motor_state values may be a false posititve caused by Zigbee2MQTT caching a state from the use of an incorrect converter. That being said, attributeReport from aqaraOpple looks like an interesting one - without diving deep into how the device works in Z2M, it may be that one of these values is the motor_state..?

I guess the first question to ask - do you have an aqara hub that you could temporarily join the device to? - We need to establish if motor_state is something that is actually reported by the device.

No, I don't. I only have HA running Zigbee2MQTT (ConBee2/RaspBee2)

The above motor_state values may be a false posititve caused by Zigbee2MQTT caching a state from the use of an incorrect converter. That being said, attributeReport from aqaraOpple looks like an interesting one - without diving deep into how the device works in Z2M, it may be that one of these values is the motor_state..?

I had thought about the caching as wel. When I had the issue initially (https://github.com/Koenkk/zigbee2mqtt/issues/14023) I was running a different HA install and after reinstall the issue occured again. Also, is it plausible that this could be caching given the fact that it is now running on a custom converter that I created today?

I figured to use attributeReport tto, but doesn't appear as a valid/existing Attribute, so I don't understand on how to retrieve the values:

image

buhito81 avatar Nov 21 '22 13:11 buhito81

I do have one of these devices and an Aqara hub, just not hooked up to anything at the moment.

I will see if I can get it set up in the next couple of days and see if the Aqara app reports motor_state if it does, I'll have a dig around (possibly do a Zigbee sniff) to see how it is reported

Just found some documentation that someone has done for Deconz: dresden-elektronik/deconz-rest-plugin#6469

It suggests that closuresWindowCovering (Cluster 0x0102) attribute 8 (not sure what this maps to in Z2M) may be where to derive the motor_state but I am not sure that it will give you the behaviour that you require...

I've tried to work through that, but I guess this is a little bit above what I understand...

buhito81 avatar Nov 29 '22 12:11 buhito81

Is it rude to tag @keith-kl here, as he has done most of the work in https://github.com/Koenkk/zigbee-herdsman-converters/pull/4307?

buhito81 avatar Nov 29 '22 12:11 buhito81

This is possibly going to be resolved by https://github.com/Koenkk/zigbee-herdsman-converters/pull/5104

buhito81 avatar Dec 12 '22 11:12 buhito81

Or by https://github.com/Koenkk/zigbee-herdsman-converters/issues/4943

buhito81 avatar Dec 14 '22 09:12 buhito81

This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 7 days

github-actions[bot] avatar Jan 14 '23 00:01 github-actions[bot]

Too bad, but the issue is still very much there...

buhito81 avatar Jan 22 '23 12:01 buhito81