Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds Tuya _TZE200_ya4ft0w4, Converts Tuya Motion quirks to v2 #3612

Draft
wants to merge 5 commits into
base: dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 0 additions & 49 deletions tests/test_tuya.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
"""Tests for Tuya quirks."""

import asyncio
import base64
import datetime
import struct
Expand All @@ -26,7 +25,6 @@
ON,
OUTPUT_CLUSTERS,
PROFILE_ID,
ZONE_STATUS_CHANGE_COMMAND,
)
from zhaquirks.tuya import Data, TuyaManufClusterAttributes, TuyaNewManufCluster
import zhaquirks.tuya.sm0202_motion
Expand Down Expand Up @@ -54,7 +52,6 @@
ZCL_TUYA_BUTTON_2_SINGLE_PRESS = b"\tN\x06\x01\x1f\x02\x04\x00\x01\x00"
ZCL_TUYA_BUTTON_2_DOUBLE_PRESS = b"\tj\x06\x03\x10\x02\x04\x00\x01\x01"
ZCL_TUYA_BUTTON_2_LONG_PRESS = b"\tl\x06\x03\x12\x02\x04\x00\x01\x02"
ZCL_TUYA_MOTION = b"\tL\x01\x00\x05\x03\x04\x00\x01\x02"
ZCL_TUYA_SWITCH_ON = b"\tQ\x02\x006\x01\x01\x00\x01\x01"
ZCL_TUYA_SWITCH_OFF = b"\tQ\x02\x006\x01\x01\x00\x01\x00"
ZCL_TUYA_ATTRIBUTE_617_TO_179 = b"\tp\x02\x00\x02i\x02\x00\x04\x00\x00\x00\xb3"
Expand Down Expand Up @@ -100,33 +97,6 @@
ZCL_TUYA_EHEAT_TARGET_TEMP = b"\t3\x01\x03\x05\x10\x02\x00\x04\x00\x00\x00\x15"


@pytest.mark.parametrize("quirk", (zhaquirks.tuya.ts0601_motion.TuyaMotion,))
async def test_motion(zigpy_device_from_quirk, quirk):
"""Test tuya motion sensor."""

motion_dev = zigpy_device_from_quirk(quirk)

motion_cluster = motion_dev.endpoints[1].ias_zone
motion_listener = ClusterListener(motion_cluster)

tuya_cluster = motion_dev.endpoints[1].tuya_manufacturer

# send motion on Tuya manufacturer specific cluster
hdr, args = tuya_cluster.deserialize(ZCL_TUYA_MOTION)
with mock.patch.object(motion_cluster, "reset_s", 0):
tuya_cluster.handle_message(hdr, args)

assert len(motion_listener.cluster_commands) == 1
assert motion_listener.cluster_commands[0][1] == ZONE_STATUS_CHANGE_COMMAND
assert motion_listener.cluster_commands[0][2][0] == ON

await asyncio.gather(asyncio.sleep(0), asyncio.sleep(0), asyncio.sleep(0))

assert len(motion_listener.cluster_commands) == 2
assert motion_listener.cluster_commands[1][1] == ZONE_STATUS_CHANGE_COMMAND
assert motion_listener.cluster_commands[1][2][0] == OFF


@pytest.mark.parametrize("quirk", (zhaquirks.tuya.ts0601_switch.TuyaSingleSwitchTI,))
async def test_singleswitch_state_report(zigpy_device_from_quirk, quirk):
"""Test tuya single switch."""
Expand Down Expand Up @@ -1628,25 +1598,6 @@ def test_ts0601_valve_signature(assert_signature_matches_quirk):
assert_signature_matches_quirk(zhaquirks.tuya.ts0601_valve.TuyaValve, signature)


def test_ts0601_motion_signature(assert_signature_matches_quirk):
"""Test TS0601 motion by TreatLife remote signature is matched to its quirk."""
signature = {
"node_descriptor": "NodeDescriptor(logical_type=<LogicalType.EndDevice: 2>, complex_descriptor_available=0, user_descriptor_available=0, reserved=0, aps_flags=0, frequency_band=<FrequencyBand.Freq2400MHz: 8>, mac_capability_flags=<MACCapabilityFlags.AllocateAddress: 128>, manufacturer_code=4417, maximum_buffer_size=66, maximum_incoming_transfer_size=66, server_mask=10752, maximum_outgoing_transfer_size=66, descriptor_capability_field=<DescriptorCapability.NONE: 0>, *allocate_address=True, *is_alternate_pan_coordinator=False, *is_coordinator=False, *is_end_device=True, *is_full_function_device=False, *is_mains_powered=False, *is_receiver_on_when_idle=False, *is_router=False, *is_security_capable=False)",
"endpoints": {
"1": {
"profile_id": 260,
"device_type": "0x0051",
"in_clusters": ["0x0000", "0x0004", "0x0005", "0xef00"],
"out_clusters": ["0x000a", "0x0019"],
}
},
"manufacturer": "_TZE200_ppuj1vem",
"model": "TS0601",
"class": "zigpy.device.Device",
}
assert_signature_matches_quirk(zhaquirks.tuya.ts0601_motion.NeoMotion, signature)


def test_multiple_attributes_report():
"""Test a multi attribute report from Tuya device."""

Expand Down
64 changes: 64 additions & 0 deletions tests/test_tuya_motion.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
"""Tests for Tuya quirks."""

import pytest
from zigpy.zcl import foundation
from zigpy.zcl.clusters.measurement import OccupancySensing

from tests.common import ClusterListener
import zhaquirks
import zhaquirks.tuya
from zhaquirks.tuya.mcu import TuyaMCUCluster

ZCL_TUYA_MOTION = b"\tL\x01\x00\x05\x01\x01\x00\x01\x01" # DP 1
ZCL_TUYA_MOTION_V2 = b"\tL\x01\x00\x05\x65\x01\x00\x01\x01" # DP 101
ZCL_TUYA_MOTION_V3 = b"\tL\x01\x00\x05\x03\x04\x00\x01\x02" # DP 3, enum


zhaquirks.setup()


@pytest.mark.parametrize(
"model,manuf,occ_msg",
[
("_TZE200_ya4ft0w4", "TS0601", ZCL_TUYA_MOTION),
("_TZE200_7hfcudw5", "TS0601", ZCL_TUYA_MOTION_V2),
("_TZE200_ppuj1vem", "TS0601", ZCL_TUYA_MOTION_V2),
("_TZE200_ar0slwnd", "TS0601", ZCL_TUYA_MOTION),
("_TZE200_mrf6vtua", "TS0601", ZCL_TUYA_MOTION),
("_TZE200_sfiy5tfs", "TS0601", ZCL_TUYA_MOTION),
("_TZE204_sooucan5", "TS0601", ZCL_TUYA_MOTION),
("_TZE200_wukb7rhc", "TS0601", ZCL_TUYA_MOTION),
("_TZE204_qasjif9e", "TS0601", ZCL_TUYA_MOTION),
("_TZE200_ztc6ggyl", "TS0601", ZCL_TUYA_MOTION),
("_TZE204_ztc6ggyl", "TS0601", ZCL_TUYA_MOTION),
("_TZE204_ztqnh5cg", "TS0601", ZCL_TUYA_MOTION),
("_TYST11_i5j6ifxj", "5j6ifxj", ZCL_TUYA_MOTION_V3),
("_TYST11_7hfcudw5", "hfcudw5", ZCL_TUYA_MOTION_V3),
],
)
async def test_tuya_motion_quirk(zigpy_device_from_v2_quirk, model, manuf, occ_msg):
"""Test Tuya Motion Quirks."""
quirked_device = zigpy_device_from_v2_quirk(model, manuf)
ep = quirked_device.endpoints[1]

assert ep.tuya_manufacturer is not None
assert isinstance(ep.tuya_manufacturer, TuyaMCUCluster)

assert ep.occupancy is not None
assert isinstance(ep.occupancy, OccupancySensing)

occupancy_listener = ClusterListener(ep.occupancy)

hdr, data = ep.tuya_manufacturer.deserialize(occ_msg)
status = ep.tuya_manufacturer.handle_get_data(data.data)

assert status == foundation.Status.SUCCESS

zcl_occupancy_id = OccupancySensing.AttributeDefs.occupancy.id

assert len(occupancy_listener.attribute_updates) == 1
assert occupancy_listener.attribute_updates[0][0] == zcl_occupancy_id
assert (
occupancy_listener.attribute_updates[0][1]
== OccupancySensing.Occupancy.Occupied
)
Loading
Loading