zigpy / zha-device-handlers

ZHA device handlers bridge the functionality gap created when manufacturers deviate from the ZCL specification, handling deviations and exceptions by parsing custom messages to and from Zigbee devices.
Apache License 2.0
747 stars 682 forks source link

[Device Support Request] TS011F _TZ3000_3zofvcaa Zemismart Zigbee Smart Wall Socket ZTB242 (2 AC plugs + 1 USB type A + 1 USB type C) #1610

Closed w35l3y closed 2 years ago

w35l3y commented 2 years ago

Is your feature request related to a problem? Please describe. Device is detected and reports status OK when the command is made from the device itself. When the command is made from the HA, it triggers all endpoints at once.

Describe the solution you'd like Add support for sending commands from HA for each endpoint separately.

Device signature ```yaml { "node_descriptor": "NodeDescriptor(logical_type=, complex_descriptor_available=0, user_descriptor_available=0, reserved=0, aps_flags=0, frequency_band=, mac_capability_flags=, manufacturer_code=4417, maximum_buffer_size=66, maximum_incoming_transfer_size=66, server_mask=10752, maximum_outgoing_transfer_size=66, descriptor_capability_field=, *allocate_address=True, *is_alternate_pan_coordinator=False, *is_coordinator=False, *is_end_device=False, *is_full_function_device=True, *is_mains_powered=True, *is_receiver_on_when_idle=True, *is_router=True, *is_security_capable=False)", "endpoints": { "1": { "profile_id": 260, "device_type": "0x010a", "in_clusters": [ "0x0000", "0x0003", "0x0004", "0x0005", "0x0006", "0xe000", "0xe001" ], "out_clusters": [ "0x000a", "0x0019" ] }, "2": { "profile_id": 260, "device_type": "0x010a", "in_clusters": [ "0x0004", "0x0005", "0x0006", "0xe001" ], "out_clusters": [] }, "3": { "profile_id": 260, "device_type": "0x010a", "in_clusters": [ "0x0004", "0x0005", "0x0006", "0xe001" ], "out_clusters": [] }, "4": { "profile_id": 260, "device_type": "0x010a", "in_clusters": [ "0x0004", "0x0005", "0x0006", "0xe001" ], "out_clusters": [] }, "242": { "profile_id": 41440, "device_type": "0x0061", "in_clusters": [], "out_clusters": [ "0x0021" ] } }, "manufacturer": "_TZ3000_3zofvcaa", "model": "TS011F", "class": "zigpy.device.Device" } ```
Diagnostic information ```yaml { "home_assistant": { "installation_type": "Home Assistant OS", "version": "2022.5.5", "dev": false, "hassio": true, "virtualenv": false, "python_version": "3.9.9", "docker": true, "arch": "aarch64", "timezone": "America/Recife", "os_name": "Linux", "os_version": "5.15.32-v8", "supervisor": "2022.05.3", "host_os": "Home Assistant OS 8.0", "docker_version": "20.10.14", "chassis": "embedded", "run_as_root": true }, "custom_components": { "zha_toolkit": { "version": "v0.8.8", "requirements": [] }, "hacs": { "version": "1.24.5", "requirements": [ "aiogithubapi>=21.11.0" ] }, "multiscrape": { "version": "6.2.0", "requirements": [ "lxml", "beautifulsoup4==4.10.0" ] }, "alexa_media": { "version": "3.11.3", "requirements": [ "alexapy==1.25.5", "packaging>=20.3", "wrapt>=1.12.1" ] }, "smartir": { "version": "1.17.6", "requirements": [ "aiofiles==0.6.0" ] }, "climate_ip": { "version": "3.5.2", "requirements": [ "requests>=2.21.0", "xmljson>=0.2.0" ] } }, "integration_manifest": { "domain": "zha", "name": "Zigbee Home Automation", "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/zha", "requirements": [ "bellows==0.29.0", "pyserial==3.5", "pyserial-asyncio==0.6", "zha-quirks==0.0.73", "zigpy-deconz==0.16.0", "zigpy==0.45.1", "zigpy-xbee==0.14.0", "zigpy-zigate==0.7.4", "zigpy-znp==0.7.0" ], "usb": [ { "vid": "10C4", "pid": "EA60", "description": "*2652*", "known_devices": [ "slae.sh cc2652rb stick" ] }, { "vid": "10C4", "pid": "EA60", "description": "*sonoff*plus*", "known_devices": [ "sonoff zigbee dongle plus" ] }, { "vid": "10C4", "pid": "EA60", "description": "*tubeszb*", "known_devices": [ "TubesZB Coordinator" ] }, { "vid": "1A86", "pid": "7523", "description": "*tubeszb*", "known_devices": [ "TubesZB Coordinator" ] }, { "vid": "1A86", "pid": "7523", "description": "*zigstar*", "known_devices": [ "ZigStar Coordinators" ] }, { "vid": "1CF1", "pid": "0030", "description": "*conbee*", "known_devices": [ "Conbee II" ] }, { "vid": "10C4", "pid": "8A2A", "description": "*zigbee*", "known_devices": [ "Nortek HUSBZB-1" ] }, { "vid": "10C4", "pid": "8B34", "description": "*bv 2010/10*", "known_devices": [ "Bitron Video AV2010/10" ] } ], "codeowners": [ "@dmulcahey", "@adminiuga" ], "zeroconf": [ { "type": "_esphomelib._tcp.local.", "name": "tube*" } ], "after_dependencies": [ "usb", "zeroconf" ], "iot_class": "local_polling", "loggers": [ "aiosqlite", "bellows", "crccheck", "pure_pcapy3", "zhaquirks", "zigpy", "zigpy_deconz", "zigpy_xbee", "zigpy_zigate", "zigpy_znp" ], "is_built_in": true }, "data": { "ieee": "**REDACTED**", "nwk": 22411, "manufacturer": "_TZ3000_3zofvcaa", "model": "TS011F", "name": "_TZ3000_3zofvcaa TS011F", "quirk_applied": false, "quirk_class": "zigpy.device.Device", "manufacturer_code": 4417, "power_source": "Mains", "lqi": 255, "rssi": -81, "last_seen": "2022-06-06T16:31:38", "available": true, "device_type": "Router", "signature": { "node_descriptor": "NodeDescriptor(logical_type=, complex_descriptor_available=0, user_descriptor_available=0, reserved=0, aps_flags=0, frequency_band=, mac_capability_flags=, manufacturer_code=4417, maximum_buffer_size=66, maximum_incoming_transfer_size=66, server_mask=10752, maximum_outgoing_transfer_size=66, descriptor_capability_field=, *allocate_address=True, *is_alternate_pan_coordinator=False, *is_coordinator=False, *is_end_device=False, *is_full_function_device=True, *is_mains_powered=True, *is_receiver_on_when_idle=True, *is_router=True, *is_security_capable=False)", "endpoints": { "1": { "profile_id": 260, "device_type": "0x010a", "in_clusters": [ "0x0000", "0x0003", "0x0004", "0x0005", "0x0006", "0xe000", "0xe001" ], "out_clusters": [ "0x000a", "0x0019" ] }, "2": { "profile_id": 260, "device_type": "0x010a", "in_clusters": [ "0x0004", "0x0005", "0x0006", "0xe001" ], "out_clusters": [] }, "3": { "profile_id": 260, "device_type": "0x010a", "in_clusters": [ "0x0004", "0x0005", "0x0006", "0xe001" ], "out_clusters": [] }, "4": { "profile_id": 260, "device_type": "0x010a", "in_clusters": [ "0x0004", "0x0005", "0x0006", "0xe001" ], "out_clusters": [] }, "242": { "profile_id": 41440, "device_type": "0x0061", "in_clusters": [], "out_clusters": [ "0x0021" ] } } }, "entities": [ { "entity_id": "button.tz3000_3zofvcaa_ts011f_099182c5_identify", "name": "_TZ3000_3zofvcaa TS011F" }, { "entity_id": "switch.tz3000_3zofvcaa_ts011f_099182c5_on_off", "name": "_TZ3000_3zofvcaa TS011F" }, { "entity_id": "switch.tz3000_3zofvcaa_ts011f_099182c5_on_off_2", "name": "_TZ3000_3zofvcaa TS011F" }, { "entity_id": "switch.tz3000_3zofvcaa_ts011f_099182c5_on_off_3", "name": "_TZ3000_3zofvcaa TS011F" }, { "entity_id": "switch.tz3000_3zofvcaa_ts011f_099182c5_on_off_4", "name": "_TZ3000_3zofvcaa TS011F" } ], "neighbors": [], "endpoint_names": [ { "name": "ON_OFF_PLUG_IN_UNIT" }, { "name": "ON_OFF_PLUG_IN_UNIT" }, { "name": "ON_OFF_PLUG_IN_UNIT" }, { "name": "ON_OFF_PLUG_IN_UNIT" }, { "name": "unknown 97 device_type of 0xa1e0 profile id" } ], "user_given_name": null, "device_reg_id": "273f9b4d5dfea30117bf909a4287836d", "area_id": null } } ```
Additional logs ``` From device (I only pressed to turn ON endpoint 4): 2022-06-06 17:11:51 DEBUG (MainThread) [zigpy.zcl] [0x578B:4:0x0006] Received ZCL frame: b'\x08\xd3\n\x00\x00\x10\x01' 2022-06-06 17:11:51 DEBUG (MainThread) [zigpy.zcl] [0x578B:4:0x0006] Decoded ZCL frame header: ZCLHeader(frame_control=FrameControl(frame_type=, is_manufacturer_specific=0, is_reply=1, disable_default_response=0, reserved=0, *is_cluster=False, *is_general=True), tsn=211, command_id=10, *is_reply=True) 2022-06-06 17:11:51 DEBUG (MainThread) [zigpy.zcl] [0x578B:4:0x0006] Decoded ZCL frame: OnOff:Report_Attributes(attribute_reports=[Attribute(attrid=0x0000, value=TypeValue(type=Bool, value=))]) 2022-06-06 17:11:51 DEBUG (MainThread) [zigpy.zcl] [0x578B:4:0x0006] Received command 0x0A (TSN 211): Report_Attributes(attribute_reports=[Attribute(attrid=0x0000, value=TypeValue(type=Bool, value=))]) 2022-06-06 17:11:51 DEBUG (MainThread) [zigpy.zcl] [0x578B:4:0x0006] Attribute report received: on_off= 2022-06-06 17:11:51 DEBUG (MainThread) [zigpy.zcl] [0x578B:4:0x0006] Sending reply header: ZCLHeader(frame_control=FrameControl(frame_type=, is_manufacturer_specific=False, is_reply=1, disable_default_response=1, reserved=0, *is_cluster=False, *is_general=True), tsn=211, command_id=, *is_reply=True) 2022-06-06 17:11:51 DEBUG (MainThread) [zigpy.zcl] [0x578B:4:0x0006] Sending reply: Default_Response(command_id=10, status=) 2022-06-06 17:11:51 DEBUG (MainThread) [zigpy.zcl] [0x578B:4:0x0006] Received ZCL frame: b'\x08\xd3\n\x00\x00\x10\x01' 2022-06-06 17:11:51 DEBUG (MainThread) [zigpy.zcl] [0x578B:4:0x0006] Decoded ZCL frame header: ZCLHeader(frame_control=FrameControl(frame_type=, is_manufacturer_specific=0, is_reply=1, disable_default_response=0, reserved=0, *is_cluster=False, *is_general=True), tsn=211, command_id=10, *is_reply=True) 2022-06-06 17:11:51 DEBUG (MainThread) [zigpy.zcl] [0x578B:4:0x0006] Decoded ZCL frame: OnOff:Report_Attributes(attribute_reports=[Attribute(attrid=0x0000, value=TypeValue(type=Bool, value=))]) 2022-06-06 17:11:51 DEBUG (MainThread) [zigpy.zcl] [0x578B:4:0x0006] Received command 0x0A (TSN 211): Report_Attributes(attribute_reports=[Attribute(attrid=0x0000, value=TypeValue(type=Bool, value=))]) 2022-06-06 17:11:51 DEBUG (MainThread) [zigpy.zcl] [0x578B:4:0x0006] Attribute report received: on_off= 2022-06-06 17:11:51 DEBUG (MainThread) [zigpy.zcl] [0x578B:4:0x0006] Sending reply header: ZCLHeader(frame_control=FrameControl(frame_type=, is_manufacturer_specific=False, is_reply=1, disable_default_response=1, reserved=0, *is_cluster=False, *is_general=True), tsn=211, command_id=, *is_reply=True) 2022-06-06 17:11:51 DEBUG (MainThread) [zigpy.zcl] [0x578B:4:0x0006] Sending reply: Default_Response(command_id=10, status=) From HA (I only pressed to turn OFF endpoint 4): 2022-06-06 17:13:31 DEBUG (MainThread) [zigpy.zcl] [0x578B:4:0x0006] Sending request header: ZCLHeader(frame_control=FrameControl(frame_type=, is_manufacturer_specific=False, is_reply=0, disable_default_response=0, reserved=0, *is_cluster=True, *is_general=False), tsn=223, command_id=0, *is_reply=False) 2022-06-06 17:13:31 DEBUG (MainThread) [zigpy.zcl] [0x578B:4:0x0006] Sending request: off() 2022-06-06 17:13:31 DEBUG (MainThread) [zigpy.zcl] [0x578B:4:0x0006] Received ZCL frame: b'\x18\xdf\x0b\x00\x00' 2022-06-06 17:13:31 DEBUG (MainThread) [zigpy.zcl] [0x578B:4:0x0006] Decoded ZCL frame header: ZCLHeader(frame_control=FrameControl(frame_type=, is_manufacturer_specific=0, is_reply=1, disable_default_response=1, reserved=0, *is_cluster=False, *is_general=True), tsn=223, command_id=11, *is_reply=True) 2022-06-06 17:13:31 DEBUG (MainThread) [zigpy.zcl] [0x578B:4:0x0006] Decoded ZCL frame: OnOff:Default_Response(command_id=0, status=) 2022-06-06 17:13:31 DEBUG (MainThread) [zigpy.zcl] [0x578B:1:0x0006] Received ZCL frame: b'\x18\xd4\n\x00\x00\x10\x00' 2022-06-06 17:13:31 DEBUG (MainThread) [zigpy.zcl] [0x578B:1:0x0006] Decoded ZCL frame header: ZCLHeader(frame_control=FrameControl(frame_type=, is_manufacturer_specific=0, is_reply=1, disable_default_response=1, reserved=0, *is_cluster=False, *is_general=True), tsn=212, command_id=10, *is_reply=True) 2022-06-06 17:13:31 DEBUG (MainThread) [zigpy.zcl] [0x578B:1:0x0006] Decoded ZCL frame: OnOff:Report_Attributes(attribute_reports=[Attribute(attrid=0x0000, value=TypeValue(type=Bool, value=))]) 2022-06-06 17:13:31 DEBUG (MainThread) [zigpy.zcl] [0x578B:1:0x0006] Received command 0x0A (TSN 212): Report_Attributes(attribute_reports=[Attribute(attrid=0x0000, value=TypeValue(type=Bool, value=))]) 2022-06-06 17:13:31 DEBUG (MainThread) [zigpy.zcl] [0x578B:1:0x0006] Attribute report received: on_off= 2022-06-06 17:13:31 DEBUG (MainThread) [zigpy.zcl] [0x578B:2:0x0006] Received ZCL frame: b'\x18\xd5\n\x00\x00\x10\x00' 2022-06-06 17:13:31 DEBUG (MainThread) [zigpy.zcl] [0x578B:2:0x0006] Decoded ZCL frame header: ZCLHeader(frame_control=FrameControl(frame_type=, is_manufacturer_specific=0, is_reply=1, disable_default_response=1, reserved=0, *is_cluster=False, *is_general=True), tsn=213, command_id=10, *is_reply=True) 2022-06-06 17:13:31 DEBUG (MainThread) [zigpy.zcl] [0x578B:2:0x0006] Decoded ZCL frame: OnOff:Report_Attributes(attribute_reports=[Attribute(attrid=0x0000, value=TypeValue(type=Bool, value=))]) 2022-06-06 17:13:31 DEBUG (MainThread) [zigpy.zcl] [0x578B:2:0x0006] Received command 0x0A (TSN 213): Report_Attributes(attribute_reports=[Attribute(attrid=0x0000, value=TypeValue(type=Bool, value=))]) 2022-06-06 17:13:31 DEBUG (MainThread) [zigpy.zcl] [0x578B:2:0x0006] Attribute report received: on_off= 2022-06-06 17:13:31 DEBUG (MainThread) [homeassistant.components.zha.core.channels.base] [0x578B:4:0x0006]: executed 'off' command with args: '()' kwargs: '{}' result: Default_Response(command_id=0, status=) 2022-06-06 17:13:31 DEBUG (MainThread) [zigpy.zcl] [0x578B:3:0x0006] Received ZCL frame: b'\x18\xd6\n\x00\x00\x10\x00' 2022-06-06 17:13:31 DEBUG (MainThread) [zigpy.zcl] [0x578B:3:0x0006] Decoded ZCL frame header: ZCLHeader(frame_control=FrameControl(frame_type=, is_manufacturer_specific=0, is_reply=1, disable_default_response=1, reserved=0, *is_cluster=False, *is_general=True), tsn=214, command_id=10, *is_reply=True) 2022-06-06 17:13:31 DEBUG (MainThread) [zigpy.zcl] [0x578B:3:0x0006] Decoded ZCL frame: OnOff:Report_Attributes(attribute_reports=[Attribute(attrid=0x0000, value=TypeValue(type=Bool, value=))]) 2022-06-06 17:13:31 DEBUG (MainThread) [zigpy.zcl] [0x578B:3:0x0006] Received command 0x0A (TSN 214): Report_Attributes(attribute_reports=[Attribute(attrid=0x0000, value=TypeValue(type=Bool, value=))]) 2022-06-06 17:13:31 DEBUG (MainThread) [zigpy.zcl] [0x578B:3:0x0006] Attribute report received: on_off= 2022-06-06 17:13:31 DEBUG (MainThread) [zigpy.zcl] [0x578B:4:0x0006] Received ZCL frame: b'\x18\xd7\n\x00\x00\x10\x00' 2022-06-06 17:13:31 DEBUG (MainThread) [zigpy.zcl] [0x578B:4:0x0006] Decoded ZCL frame header: ZCLHeader(frame_control=FrameControl(frame_type=, is_manufacturer_specific=0, is_reply=1, disable_default_response=1, reserved=0, *is_cluster=False, *is_general=True), tsn=215, command_id=10, *is_reply=True) 2022-06-06 17:13:32 DEBUG (MainThread) [zigpy.zcl] [0x578B:4:0x0006] Decoded ZCL frame: OnOff:Report_Attributes(attribute_reports=[Attribute(attrid=0x0000, value=TypeValue(type=Bool, value=))]) 2022-06-06 17:13:32 DEBUG (MainThread) [zigpy.zcl] [0x578B:4:0x0006] Received command 0x0A (TSN 215): Report_Attributes(attribute_reports=[Attribute(attrid=0x0000, value=TypeValue(type=Bool, value=))]) 2022-06-06 17:13:32 DEBUG (MainThread) [zigpy.zcl] [0x578B:4:0x0006] Attribute report received: on_off= ```

Additional context Does anyone have any suggestion where I could start ? I have already copied and modified some examples from https://github.com/zigpy/zha-device-handlers/blob/dev/zhaquirks/tuya/ts011f_plug.py and https://github.com/zigpy/zha-device-handlers/blob/dev/zhaquirks/tuya/ts011f_switch.py but no success. VideoEditor_20220606_052113_1 20220606_163044

When paired with Smart Life, all 4 endpoints work independently.

MattWestb commented 2 years ago

LIDL is having one 3 AC with 4 USB that was working OK but new batch having one new firmware that is making the same as you device. Try patching this quirk for your device https://github.com/zigpy/zha-device-handlers/blob/dev/zhaquirks/lidl/ts011f_plug.py and very likely you can getting all endpoints working OK from ZHA.

Its called "tuya magic spell" ;-))

w35l3y commented 2 years ago

I added cast_tuya_magic_spell_task and cast_tuya_magic_spell to the code and now it is green for TuyaZBOnOffAttributeCluster It used to return an yellow mark.

image

I didn't add TuyaBasicCluster because it doesn't seem to be referenced anywhere.

I had to remove and re-pair the device to make it work... I am still making some tests.

Should I PR at tuya or lidl folder (or elsewhere) ?

MattWestb commented 2 years ago

Looks great !!! I was thinking deleting and paring was not needed but i was wrong and good to knowing. If you is taking the power way and putting it back after one minute is it working OK ? If not you need the basic cluster implementation 2 . One PR is more the welcome and i like using tuya then in the end all is made with tuya code and its hundred of brands out there.

javicalle commented 2 years ago

Hi there, IMHO zhaquirks/tuya/ts011f_plug.py would be a good place to put the quirk.

There is a EnchantedDevice class that I believe that can be extended to get the TMS working:

Just extend your device implementation from it.

MattWestb commented 2 years ago

@javicalle Shall we rewriting our exiting quirks with spells to the new class for the TS004F and the LIDL TS011F or leaving them as they is ?

I think its bad having the spell in all quirks and not in one imported function.

w35l3y commented 2 years ago

Just for future reference...

TS004F : https://github.com/zigpy/zha-device-handlers/blob/b6556169bf641e8f2eb882e8ace4a5a1ab4552d5/zhaquirks/tuya/ts004f.py#L187-L199 TS011F : https://github.com/zigpy/zha-device-handlers/blob/b6556169bf641e8f2eb882e8ace4a5a1ab4552d5/zhaquirks/lidl/ts011f_plug.py#L35-L95 https://github.com/zigpy/zha-device-handlers/blob/b6556169bf641e8f2eb882e8ace4a5a1ab4552d5/zhaquirks/lidl/ts011f_plug.py#L127-L133

javicalle commented 2 years ago

I'm not sure if the code of the LIDL device is the same since it seems much more complex to me (it has tries, rejoin, ...) and I don't dare to modify it.

I think that apart from the LIDL we only have the TuyaSmartRemote004FDMS, can it be? https://github.com/zigpy/zha-device-handlers/blob/b6556169bf641e8f2eb882e8ace4a5a1ab4552d5/zhaquirks/tuya/ts004f.py#L184-L200 Pretty sure we can refactor it to use the new class.

MattWestb commented 2 years ago

The TS004F is in real world only only being sent to the device then its being new joined then the quirk is being loaded. Then HA is starting is being triggered but ZHA have not initiated the coordinator so its not being sent to the device. Its exactly what the TS004F is needing and is working well.

Some devices that is main powered can needing the spell casted after power off and on then the TS004F method is not working and need being triggered in one other way. I have not testing the LIDL method then my power strips is on old firmware that is working OK without the spell and its have other cluster settings on the end points and its not being updated by tuya ZBGW. I think its kicking the device so its rejoining (with the network OK) and being in init mode then sending the spell = very good is its working OK.

Some TS0602 / MCU device looks needing it and also most (O)LED temperature / humidity / light sensors combis.

Only critical is timing and the attribute read and write is needed being sent after getting the network key and before the device us getting the updated TC link key (its being in init mode).

Or letting the spell in the quirks that needing it for not distorting working devices ?