core: [BUG] TypeError: 'Status' object is not subscriptable

The problem

While creating a new ZHA Quirk: https://github.com/zigpy/zha-device-handlers/issues/1302#issuecomment-1090904325 this error appeared:

2022-04-06 23:10:57 ERROR (MainThread) [homeassistant.components.websocket_api.http.connection] [140094030063840] 'Status' object is not subscriptable
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/components/websocket_api/commands.py", line 193, in handle_call_service
    await hass.services.async_call(
  File "/usr/src/homeassistant/homeassistant/core.py", line 1634, in async_call
    task.result()
  File "/usr/src/homeassistant/homeassistant/core.py", line 1671, in _execute_service
    await cast(Callable[[ServiceCall], Awaitable[None]], handler.job.target)(
  File "/usr/src/homeassistant/homeassistant/helpers/entity_component.py", line 204, in handle_service
    await service.entity_service_call(
  File "/usr/src/homeassistant/homeassistant/helpers/service.py", line 677, in entity_service_call
    future.result()  # pop exception if have
  File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 955, in async_request_call
    await coro
  File "/usr/src/homeassistant/homeassistant/helpers/service.py", line 714, in _handle_entity_call
    await result
  File "/usr/src/homeassistant/homeassistant/components/light/__init__.py", line 504, in async_handle_light_on_service
    await light.async_turn_on(**filter_turn_on_params(light, params))
  File "/usr/src/homeassistant/homeassistant/components/zha/light.py", line 258, in async_turn_on
    if isinstance(result, Exception) or result[1] is not Status.SUCCESS:
TypeError: 'Status' object is not subscriptable

What version of Home Assistant Core has the issue?

core-2022.4.0

What was the last working version of Home Assistant Core?

No response

What type of installation are you running?

Home Assistant OS

Integration causing the issue

ZHA?

Link to integration documentation on our website

No response

Diagnostics information

No response

Example YAML snippet

No response

Anything in the logs that might be useful for us?

No response

Additional information

No response

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Reactions: 1
  • Comments: 28 (17 by maintainers)

Most upvoted comments

I think there seems to be some slight problem with this implementation that is unrelated to the recent zigpy changes. Is your command being overridden just to prevent the manufacturer code from being sent? If so, I think you don’t need to manually return any status codes or construct any default responses, just return await super().command(... is enough.

Something like this:

class NoManufacturerCluster(CustomCluster):
    """Forces the NO manufacturer id in command."""

    def command(
        self,
        command_id: Union[foundation.GeneralCommand, int, t.uint8_t],
        *args,
        manufacturer: Optional[Union[int, t.uint16_t]] = None,
        expect_reply: bool = True,
        tsn: Optional[Union[int, t.uint8_t]] = None,
    ):
        """Override the default Cluster command."""
        self.debug("Setting the NO manufacturer id in command: %s", command_id)
        return super().command(
            command_id,
            *args,

            # Maybe use kwargs here? It's possible that keeping the args position is 
            # conflicting with something
            manufacturer=zcl.foundation.ZCLHeader.NO_MANUFACTURER_ID,
            expect_reply=expect_reply,
            tsn=tsn,
        )

@javicalle Ok, now when trying to dimm the log shows this:

2022-04-07 12:56:19 DEBUG (MainThread) [zigpy.zcl] [0x7A66:1:0x0008] Setting the NO manufacturer id in command: 4
2022-04-07 12:56:19 DEBUG (MainThread) [zigpy.zcl] [0x7A66:1:0x0008] Sending Tuya Cluster Command. Cluster Command is 4, Arguments are (48, 1, -1, True, None)
2022-04-07 12:56:19 DEBUG (MainThread) [zigpy.zcl] [0x7A66:1:0xef00] tuya_mcu_command: cluster_data=TuyaClusterData(endpoint_id=1, cluster_attr='current_level', attr_value=48, expect_reply=True)
2022-04-07 12:56:19 DEBUG (MainThread) [zigpy.zcl] [0x7A66:1:0xef00] get_dp_mapping --> found DP: 2
2022-04-07 12:56:19 DEBUG (MainThread) [zigpy.zcl] [0x7A66:1:0xef00] from_cluster_data: 2, DPToAttributeMapping(ep_attribute='level', attribute_name='current_level', dp_type=<TuyaDPType.VALUE: 2>, converter=<function TuyaLevelControlManufCluster.<lambda> at 0x7f4e7b116ca0>, dp_converter=<function TuyaLevelControlManufCluster.<lambda> at 0x7f4e7b116d30>, endpoint_id=None)
2022-04-07 12:56:19 DEBUG (MainThread) [zigpy.zcl] [0x7A66:1:0xef00] converted: 188
2022-04-07 12:56:19 DEBUG (MainThread) [zigpy.zcl] [0x7A66:1:0xef00] ztype: 188
2022-04-07 12:56:19 DEBUG (MainThread) [zigpy.zcl] [0x7A66:1:0xef00] from_value: [4, 0, 0, 0, 188]
2022-04-07 12:56:19 DEBUG (MainThread) [zigpy.zcl] [0x7A66:1:0xef00] raw: b'\x00\x00\x00\xbc'
2022-04-07 12:56:19 DEBUG (MainThread) [zigpy.zcl] [0x7A66:1:0xef00] tuya_command: TuyaCommand(status=0, tsn=35, dp=2, data=TuyaData(dp_type=<TuyaDPType.VALUE: 2>, function=0, raw=b'\x00\x00\x00\xbc', *payload=3154116608))
2022-04-07 12:56:19 DEBUG (MainThread) [zigpy.zcl] [0x7A66:1:0xef00] Sending request header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.CLUSTER_COMMAND: 1>, is_manufacturer_specific=True, is_reply=0, disable_default_response=0, reserved=0, *is_cluster=True, *is_general=False), manufacturer=4417, tsn=36, command_id=0, *is_reply=False)
2022-04-07 12:56:19 DEBUG (MainThread) [zigpy.zcl] [0x7A66:1:0xef00] Sending request: set_data(data=TuyaCommand(status=0, tsn=35, dp=2, data=TuyaData(dp_type=<TuyaDPType.VALUE: 2>, function=0, raw=b'\x00\x00\x00\xbc', *payload=3154116608)))
2022-04-07 12:56:19 DEBUG (MainThread) [zigpy.zcl] [0x7A66:1:0xef00] Received ZCL frame: b'\x18\x24\x0B\x00\x83'
2022-04-07 12:56:19 DEBUG (MainThread) [zigpy.zcl] [0x7A66:1:0xef00] Decoded ZCL frame header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.GLOBAL_COMMAND: 0>, is_manufacturer_specific=0, is_reply=1, disable_default_response=1, reserved=0, *is_cluster=False, *is_general=True), tsn=36, command_id=11, *is_reply=True)
2022-04-07 12:56:19 DEBUG (MainThread) [zigpy.zcl] [0x7A66:1:0xef00] Decoded ZCL frame: TuyaLevelControlManufCluster:Default_Response(command_id=0, status=<Status.UNSUP_MANUF_CLUSTER_COMMAND: 131>)

The dimmer doesn’t do anything.

Aaaaargh! My fault. Remove the zcl.. Already fixed in comment.

ZHA was explicitly checking isinstance(rsp, list) to handle some types of responses, which was buggy behavior and masked these errors. The Tuya quirks should be updated to return a ZCL default response instead of just a bare Status object.

Something like this:

return foundation.GENERAL_COMMANDS[foundation.GeneralCommand.Default_Response].schema(
    command_id=..., status=...
)

ZHA unit tests should be expanded to include these types of Tuya devices, this bug should have been caught by them.

Issue must be fixed in HA 2022.4.1 I think it is safe to close now.

Thanks @Tropaion

@Tropaion please reopen this issue in case someone else is in the same situation can track the reason.

Thanks.

@javicalle now dimming throws this

2022-04-07 03:39:03 ERROR (MainThread) [homeassistant.components.websocket_api.http.connection] [139796735318432] Failed to convert status=<coroutine object TuyaLevelControl.command at 0x7f24e7b908c0> from type <class 'coroutine'> to <enum 'Status'>
Traceback (most recent call last):
  File "/usr/local/lib/python3.9/site-packages/zigpy/types/struct.py", line 39, in _convert_type
    return self.type(value)
  File "/usr/local/lib/python3.9/site-packages/zigpy/types/basic.py", line 254, in __call__
    value = int(value)
TypeError: int() argument must be a string, a bytes-like object or a number, not 'coroutine'
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/components/websocket_api/commands.py", line 193, in handle_call_service
    await hass.services.async_call(
  File "/usr/src/homeassistant/homeassistant/core.py", line 1634, in async_call
    task.result()
  File "/usr/src/homeassistant/homeassistant/core.py", line 1671, in _execute_service
    await cast(Callable[[ServiceCall], Awaitable[None]], handler.job.target)(
  File "/usr/src/homeassistant/homeassistant/helpers/entity_component.py", line 204, in handle_service
    await service.entity_service_call(
  File "/usr/src/homeassistant/homeassistant/helpers/service.py", line 677, in entity_service_call
    future.result()  # pop exception if have
  File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 955, in async_request_call
    await coro
  File "/usr/src/homeassistant/homeassistant/helpers/service.py", line 714, in _handle_entity_call
    await result
  File "/usr/src/homeassistant/homeassistant/components/light/__init__.py", line 504, in async_handle_light_on_service
    await light.async_turn_on(**filter_turn_on_params(light, params))
  File "/usr/src/homeassistant/homeassistant/components/zha/light.py", line 242, in async_turn_on
    result = await self._level_channel.move_to_level_with_on_off(
  File "/usr/src/homeassistant/homeassistant/components/zha/core/channels/base.py", line 59, in wrapper
    result = await command(*args, **kwds)
  File "/config/custom_zha_quirks/ts0601_dimmer.py", line 54, in command
    return foundation.GENERAL_COMMANDS[foundation.GeneralCommand.Default_Response].schema(command_id=command_id, status=status)
  File "/usr/local/lib/python3.9/site-packages/zigpy/types/struct.py", line 115, in __new__
    setattr(instance, name, field._convert_type(value))
  File "/usr/local/lib/python3.9/site-packages/zigpy/types/struct.py", line 41, in _convert_type
    raise ValueError(
ValueError: Failed to convert status= from type  to 

@Tropaion could you test one change?

Over your quirk file replace the NoManufacturerCluster class definition:

class NoManufacturerCluster(CustomCluster):
    """Forces the NO manufacturer id in command."""

    async def command(
        self,
        command_id: Union[foundation.GeneralCommand, int, t.uint8_t],
        *args,
        manufacturer: Optional[Union[int, t.uint16_t]] = None,
        expect_reply: bool = True,
        tsn: Optional[Union[int, t.uint8_t]] = None,
    ):
        """Override the default Cluster command."""
        self.debug("Setting the NO manufacturer id in command: %s", command_id)
        status = await super().command(
            command_id,
            *args,
            foundation.ZCLHeader.NO_MANUFACTURER_ID,
            expect_reply,
            tsn,
        )

        return foundation.GENERAL_COMMANDS[foundation.GeneralCommand.Default_Response].schema(command_id=command_id, status=status)

You will need to add the foundation import:

from zigpy.zcl import foundation

Check if dimm commands get fixed (the on/off must still fail).

It’s late here. I will continue tomorrow.

They should be returning something that matches what normal lights return. For my IKEA lights, it’s a ZCL default response with a successful status code.