Skip to content

Commit

Permalink
Merge branch 'release/0.0.70'
Browse files Browse the repository at this point in the history
  • Loading branch information
dmulcahey committed Apr 7, 2022

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
2 parents d26dce5 + 31a703b commit 3926965
Showing 21 changed files with 380 additions and 64 deletions.
16 changes: 16 additions & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
@@ -66,6 +66,22 @@ error_summary = True
install_types = True
non_interactive = True

disable_error_code =
arg-type,
assignment,
attr-defined,
call-arg,
dict-item,
index,
misc,
no-any-return,
no-untyped-call,
no-untyped-def,
override,
return-value,
union-attr,
var-annotated

[pydocstyle]
ignore =
D202,
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
@@ -4,7 +4,7 @@

from setuptools import find_packages, setup

VERSION = "0.0.69"
VERSION = "0.0.70"


setup(
9 changes: 9 additions & 0 deletions tests/test_quirks.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""General quirk tests."""
from __future__ import annotations

import importlib
from pathlib import Path
from unittest import mock

@@ -508,3 +509,11 @@ def test_zigpy_custom_cluster_pollution() -> None:
raise RuntimeError(
f"Custom clusters must subclass `CustomCluster`: {non_zigpy_clusters}"
)


@pytest.mark.parametrize("module_name", {q.__module__ for q in ALL_QUIRK_CLASSES})
def test_no_module_level_device_automation_triggers(module_name: str) -> None:
"""Ensure no quirk module has a module-level `device_automation_triggers` dict."""

mod = importlib.import_module(module_name)
assert not hasattr(mod, "device_automation_triggers")
12 changes: 6 additions & 6 deletions tests/test_tuya.py
Original file line number Diff line number Diff line change
@@ -236,28 +236,28 @@ async def test_singleswitch_requests(zigpy_device_from_quirk, quirk):
tuya_cluster.endpoint, "request", return_value=foundation.Status.SUCCESS
) as m1:

status = await switch_cluster.command(0x0000)
rsp = await switch_cluster.command(0x0000)
m1.assert_called_with(
61184,
2,
b"\x01\x02\x00\x00\x01\x01\x01\x00\x01\x00",
expect_reply=True,
command_id=0,
)
assert status == 0
assert rsp.status == 0

status = await switch_cluster.command(0x0001)
rsp = await switch_cluster.command(0x0001)
m1.assert_called_with(
61184,
4,
b"\x01\x04\x00\x00\x03\x01\x01\x00\x01\x01",
expect_reply=True,
command_id=0,
)
assert status == 0
assert rsp.status == 0

status = await switch_cluster.command(0x0002)
assert status == foundation.Status.UNSUP_CLUSTER_COMMAND
rsp = await switch_cluster.command(0x0002)
assert rsp.status == foundation.Status.UNSUP_CLUSTER_COMMAND


def test_ts0121_signature(assert_signature_matches_quirk):
8 changes: 4 additions & 4 deletions tests/test_tuya_dimmer.py
Original file line number Diff line number Diff line change
@@ -30,7 +30,7 @@ async def test_command(zigpy_device_from_quirk, quirk):
with mock.patch.object(
tuya_cluster.endpoint, "request", return_value=foundation.Status.SUCCESS
) as m1:
status = await switch2_cluster.command(0x0001)
rsp = await switch2_cluster.command(0x0001)

m1.assert_called_with(
61184,
@@ -39,9 +39,9 @@ async def test_command(zigpy_device_from_quirk, quirk):
expect_reply=True,
command_id=0,
)
assert status == foundation.Status.SUCCESS
assert rsp.status == foundation.Status.SUCCESS

status = await dimmer1_cluster.command(0x0000, 225)
rsp = await dimmer1_cluster.command(0x0000, 225)

m1.assert_called_with(
61184,
@@ -50,7 +50,7 @@ async def test_command(zigpy_device_from_quirk, quirk):
expect_reply=True,
command_id=0,
)
assert status == foundation.Status.SUCCESS
assert rsp.status == foundation.Status.SUCCESS


@pytest.mark.parametrize(
10 changes: 5 additions & 5 deletions tests/test_tuya_mcu.py
Original file line number Diff line number Diff line change
@@ -85,17 +85,17 @@ async def test_tuya_methods(zigpy_device_from_quirk, quirk):
m1.assert_not_called()

result_3 = await dimmer2_cluster.command(0x0006)
assert result_3 == foundation.Status.UNSUP_CLUSTER_COMMAND
assert result_3.status == foundation.Status.UNSUP_CLUSTER_COMMAND

with mock.patch.object(tuya_cluster, "tuya_mcu_command") as m1:
status = await switch1_cluster.command(0x0001)
rsp = await switch1_cluster.command(0x0001)

m1.assert_called_once_with(tcd_switch1_on)
assert status == foundation.Status.SUCCESS
assert rsp.status == foundation.Status.SUCCESS

status = await switch1_cluster.command(0x0004)
rsp = await switch1_cluster.command(0x0004)
m1.assert_called_once_with(tcd_switch1_on) # no extra calls
assert status == foundation.Status.UNSUP_CLUSTER_COMMAND
assert rsp.status == foundation.Status.UNSUP_CLUSTER_COMMAND


async def test_tuya_mcu_classes():
1 change: 1 addition & 0 deletions zhaquirks/const.py
Original file line number Diff line number Diff line change
@@ -57,6 +57,7 @@
COMMAND_STEP_SATURATION = "step_saturation"
COMMAND_STOP = "stop"
COMMAND_STOP_MOVE_STEP = "stop_move_step"
COMMAND_STOP_ON_OFF = "stop_with_on_off"
COMMAND_TILT = "Tilt"
COMMAND_TOGGLE = "toggle"
COMMAND_TRIPLE = "triple"
29 changes: 14 additions & 15 deletions zhaquirks/ikea/dimmer.py
Original file line number Diff line number Diff line change
@@ -88,18 +88,17 @@ class IkeaDimmer(CustomDevice):
}
}


device_automation_triggers = {
(ROTATED, RIGHT): {
COMMAND: COMMAND_MOVE,
CLUSTER_ID: 8,
ENDPOINT_ID: 1,
ARGS: [0, 195],
},
(ROTATED, LEFT): {
COMMAND: COMMAND_MOVE,
CLUSTER_ID: 8,
ENDPOINT_ID: 1,
ARGS: [1, 195],
},
}
device_automation_triggers = {
(ROTATED, RIGHT): {
COMMAND: COMMAND_MOVE,
CLUSTER_ID: 8,
ENDPOINT_ID: 1,
ARGS: [0, 195],
},
(ROTATED, LEFT): {
COMMAND: COMMAND_MOVE,
CLUSTER_ID: 8,
ENDPOINT_ID: 1,
ARGS: [1, 195],
},
}
10 changes: 7 additions & 3 deletions zhaquirks/ikea/fourbtnremote.py
Original file line number Diff line number Diff line change
@@ -22,7 +22,7 @@
COMMAND_OFF,
COMMAND_ON,
COMMAND_PRESS,
COMMAND_STOP,
COMMAND_STOP_ON_OFF,
DEVICE_TYPE,
DIM_DOWN,
DIM_UP,
@@ -110,7 +110,11 @@ class IkeaTradfriRemote(CustomDevice):
ENDPOINT_ID: 1,
ARGS: [0, 83],
},
(LONG_RELEASE, DIM_UP): {COMMAND: COMMAND_STOP, CLUSTER_ID: 8, ENDPOINT_ID: 1},
(LONG_RELEASE, DIM_UP): {
COMMAND: COMMAND_STOP_ON_OFF,
CLUSTER_ID: 8,
ENDPOINT_ID: 1,
},
(SHORT_PRESS, TURN_OFF): {COMMAND: COMMAND_OFF, CLUSTER_ID: 6, ENDPOINT_ID: 1},
(LONG_PRESS, DIM_DOWN): {
COMMAND: COMMAND_MOVE,
@@ -119,7 +123,7 @@ class IkeaTradfriRemote(CustomDevice):
ARGS: [1, 83],
},
(LONG_RELEASE, DIM_DOWN): {
COMMAND: COMMAND_STOP,
COMMAND: COMMAND_STOP_ON_OFF,
CLUSTER_ID: 8,
ENDPOINT_ID: 1,
},
78 changes: 77 additions & 1 deletion zhaquirks/ikea/shortcutbtn.py
Original file line number Diff line number Diff line change
@@ -22,7 +22,7 @@
COMMAND_MOVE_ON_OFF,
COMMAND_OFF,
COMMAND_ON,
COMMAND_STOP,
COMMAND_STOP_ON_OFF,
DEVICE_TYPE,
DIM_UP,
DOUBLE_PRESS,
@@ -100,6 +100,82 @@ class IkeaTradfriShortcutBtn(CustomDevice):
}
}

device_automation_triggers = {
(SHORT_PRESS, TURN_ON): {COMMAND: COMMAND_ON, CLUSTER_ID: 6, ENDPOINT_ID: 1},
(DOUBLE_PRESS, TURN_ON): {COMMAND: COMMAND_OFF, CLUSTER_ID: 6, ENDPOINT_ID: 1},
(LONG_PRESS, DIM_UP): {
COMMAND: COMMAND_MOVE_ON_OFF,
CLUSTER_ID: 8,
ENDPOINT_ID: 1,
ARGS: [0, 83],
},
(LONG_RELEASE, DIM_UP): {
COMMAND: COMMAND_STOP_ON_OFF,
CLUSTER_ID: 8,
ENDPOINT_ID: 1,
},
}


class IkeaTradfriShortcutBtn2(CustomDevice):
"""Custom device representing IKEA of Sweden TRADFRI shortcut button with IKEA cluster."""

signature = {
# <SimpleDescriptor endpoint=1 profile=260 device_type=2080
# device_version=1
# input_clusters=[0, 1, 3, 9, 32, 4096, 64636]
# output_clusters=[3, 4, 6, 8, 25, 4096]>
MODELS_INFO: [(IKEA, "TRADFRI SHORTCUT Button")],
ENDPOINTS: {
1: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.NON_COLOR_CONTROLLER,
INPUT_CLUSTERS: [
Basic.cluster_id,
PowerConfiguration.cluster_id,
Identify.cluster_id,
Alarms.cluster_id,
PollControl.cluster_id,
LightLink.cluster_id,
0xFC7C, # IKEA Cluster
],
OUTPUT_CLUSTERS: [
Identify.cluster_id,
Groups.cluster_id,
OnOff.cluster_id,
LevelControl.cluster_id,
Ota.cluster_id,
LightLink.cluster_id,
],
}
},
}

replacement = {
ENDPOINTS: {
1: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.NON_COLOR_CONTROLLER,
INPUT_CLUSTERS: [
Basic.cluster_id,
PowerConfiguration1CRCluster,
Identify.cluster_id,
Alarms.cluster_id,
PollControl.cluster_id,
LightLinkCluster,
],
OUTPUT_CLUSTERS: [
Identify.cluster_id,
Groups.cluster_id,
OnOff.cluster_id,
LevelControl.cluster_id,
Ota.cluster_id,
LightLink.cluster_id,
],
}
}
}

device_automation_triggers = {
(SHORT_PRESS, TURN_ON): {COMMAND: COMMAND_ON, CLUSTER_ID: 6, ENDPOINT_ID: 1},
(DOUBLE_PRESS, TURN_ON): {COMMAND: COMMAND_OFF, CLUSTER_ID: 6, ENDPOINT_ID: 1},
3 changes: 2 additions & 1 deletion zhaquirks/ikea/twobtnremote.py
Original file line number Diff line number Diff line change
@@ -24,6 +24,7 @@
COMMAND_OFF,
COMMAND_ON,
COMMAND_STOP,
COMMAND_STOP_ON_OFF,
DEVICE_TYPE,
DIM_DOWN,
DIM_UP,
@@ -115,7 +116,7 @@ class IkeaTradfriRemote2Btn(CustomDevice):
ARGS: [0, 83],
},
(LONG_RELEASE, DIM_UP): {
COMMAND: COMMAND_STOP,
COMMAND: COMMAND_STOP_ON_OFF,
CLUSTER_ID: 8,
ENDPOINT_ID: 1,
},
3 changes: 2 additions & 1 deletion zhaquirks/osram/switchmini.py
Original file line number Diff line number Diff line change
@@ -26,6 +26,7 @@
COMMAND_OFF,
COMMAND_ON,
COMMAND_STOP,
COMMAND_STOP_ON_OFF,
DEVICE_TYPE,
ENDPOINT_ID,
ENDPOINTS,
@@ -118,7 +119,7 @@ class OsramSwitchMini(CustomDevice):
device_automation_triggers = {
(SHORT_PRESS, BUTTON_1): {COMMAND: COMMAND_ON, ENDPOINT_ID: 1},
(LONG_PRESS, BUTTON_1): {COMMAND: COMMAND_MOVE_ON_OFF, ENDPOINT_ID: 1},
(LONG_RELEASE, BUTTON_1): {COMMAND: COMMAND_STOP, ENDPOINT_ID: 1},
(LONG_RELEASE, BUTTON_1): {COMMAND: COMMAND_STOP_ON_OFF, ENDPOINT_ID: 1},
(SHORT_PRESS, BUTTON_2): {
COMMAND: COMMAND_MOVE_TO_LEVEL_ON_OFF,
ENDPOINT_ID: 3,
15 changes: 12 additions & 3 deletions zhaquirks/tuya/__init__.py
Original file line number Diff line number Diff line change
@@ -670,11 +670,17 @@ async def command(
"""Implement thermostat commands."""

if command_id != 0x0000:
return [command_id, foundation.Status.UNSUP_CLUSTER_COMMAND]
return foundation.GENERAL_COMMANDS[
foundation.GeneralCommand.Default_Response
].schema(
command_id=command_id, status=foundation.Status.UNSUP_CLUSTER_COMMAND
)

mode, offset = args
if mode not in (self.SetpointMode.Heat, self.SetpointMode.Both):
return [command_id, foundation.Status.INVALID_VALUE]
return foundation.GENERAL_COMMANDS[
foundation.GeneralCommand.Default_Response
].schema(command_id=command_id, status=foundation.Status.INVALID_VALUE)

attrid = self.attributes_by_name["occupied_heating_setpoint"].id

@@ -689,7 +695,9 @@ async def command(
{"occupied_heating_setpoint": current + offset * 10},
manufacturer=manufacturer,
)
return [command_id, res[0].status]
return foundation.GENERAL_COMMANDS[
foundation.GeneralCommand.Default_Response
].schema(command_id=command_id, status=res[0].status)


class TuyaUserInterfaceCluster(LocalDataCluster, UserInterface):
@@ -840,6 +848,7 @@ class TuyaZBOnOffAttributeCluster(CustomCluster, OnOff):
"""Tuya Zigbee On Off cluster with extra attributes."""

attributes = OnOff.attributes.copy()
attributes.update({0x8000: ("child_lock", t.Bool)})
attributes.update({0x8001: ("backlight_mode", SwitchBackLight)})
attributes.update({0x8002: ("power_on_state", PowerOnState)})
attributes.update({0x8004: ("switch_mode", SwitchMode)})
Loading

0 comments on commit 3926965

Please sign in to comment.