diff --git a/README.md b/README.md index 518a4f6dec..aef76aa834 100644 --- a/README.md +++ b/README.md @@ -418,7 +418,7 @@ The second part is the event data. You only need to supply enough of the event d If you look at another example for the same device: -`(SHORT_PRESS, DIM_UP): {COMMAND: COMMAND_STEP, CLUSTER_ID: 8, ENDPOINT_ID: 1, ARGS: [0, 30, 9],}` +`(SHORT_PRESS, DIM_UP): {COMMAND: COMMAND_STEP, CLUSTER_ID: 8, ENDPOINT_ID: 1, PARAMS: {'step_mode': 0},}` You can see a pattern that illustrates how to match a more complex event. In this case the step command is used for the dim up and dim down buttons so we need to match more of the event data to uniquely match the event. @@ -535,54 +535,6 @@ def test_ts0121_signature(assert_signature_matches_quirk): assert_signature_matches_quirk(zhaquirks.tuya.ts0121_plug.Plug, signature) ``` -# Testing new releases - -Testing a new release of the zha-quirks package before it is released in Home Assistant. - -If you are using Supervised Home Assistant (formerly known as the Hassio/Hass.io distro): - -- Add as "add-on" repository -- Install "Custom deps deployment" addon -- Update config like: - - ```yml - pypi: - - zha-quirks==0.0.38 - apk: [] - ``` - - where 0.0.38 is the new version - -- Start the addon - -If you are instead using some custom python installation of Home Assistant then do this: - -- Activate your python virtual env -- Update package with `pip` - - ```bash - pip install zha-quirks==0.0.38 - ``` - -# Testing quirks in development in docker based install - -If you are using Supervised Home Assistant (formerly known as the Hassio/Hass.io distro) you will need to get access to the home-assistant docker container. Directions below are given for using the portainer add-on to do this, there are other methods as well not covered here. - -- Install the portainer add-on () from Home Assistant Community Add-ons. -- Follow the add-on documentation to un-hide the home-assistant container () -- Stage the update quirk in a directory within your config directory -- Use portainer to access a console in the home-assistant container: - - - -- Access the quirks directory - - on HA > 0.113: /usr/local/lib/python3.8/site-packages/zhaquirks/ - - on HA < 0.113: /usr/local/lib/python3.7/site-packages/zhaquirks/ -- Copy updated/new quirk to zhaquirks directory: `cp -a /config/temp/NEW_QUIRK ./` -- Remove the **pycache** folder so it is regenerated `rm -rf ./__pycache__/` -- Close out the console and restart HA. -- Note: The added/update quirk will not survive a HA version update. - # Thanks - Special thanks to damarco for the majority of the device tracker code diff --git a/setup.py b/setup.py index f53d0ee84e..9df25e4aad 100644 --- a/setup.py +++ b/setup.py @@ -4,7 +4,7 @@ from setuptools import find_packages, setup -VERSION = "0.0.71" +VERSION = "0.0.72" setup( @@ -20,6 +20,6 @@ keywords="zha quirks homeassistant hass", packages=find_packages(exclude=["tests"]), python_requires=">=3", - install_requires=["zigpy>=0.44.1"], + install_requires=["zigpy>=0.44.2"], tests_require=["pytest"], ) diff --git a/tests/test_quirks.py b/tests/test_quirks.py index 54da84ec33..1d17bc5711 100644 --- a/tests/test_quirks.py +++ b/tests/test_quirks.py @@ -18,6 +18,21 @@ import zhaquirks import zhaquirks.bosch.motion from zhaquirks.const import ( + ARGS, + COMMAND, + COMMAND_MOVE, + COMMAND_MOVE_COLOR_TEMP, + COMMAND_MOVE_ON_OFF, + COMMAND_MOVE_SATURATION, + COMMAND_MOVE_TO_LEVEL_ON_OFF, + COMMAND_MOVE_TO_SATURATION, + COMMAND_STEP, + COMMAND_STEP_COLOR_TEMP, + COMMAND_STEP_HUE, + COMMAND_STEP_ON_OFF, + COMMAND_STEP_SATURATION, + COMMAND_STOP, + COMMAND_STOP_ON_OFF, DEVICE_TYPE, ENDPOINTS, INPUT_CLUSTERS, @@ -26,6 +41,7 @@ MODELS_INFO, NODE_DESCRIPTOR, OUTPUT_CLUSTERS, + PARAMS, PROFILE_ID, SKIP_CONFIGURATION, ) @@ -517,3 +533,48 @@ def test_no_module_level_device_automation_triggers(module_name: str) -> None: mod = importlib.import_module(module_name) assert not hasattr(mod, "device_automation_triggers") + + +@pytest.mark.parametrize("quirk", ALL_QUIRK_CLASSES) +def test_migrated_lighting_automation_triggers(quirk: CustomDevice) -> None: + """Ensure quirks with lighting or level control clusters are using PARAMS.""" + + if not hasattr(quirk, "device_automation_triggers"): + return + + for trigger, event in quirk.device_automation_triggers.items(): + if COMMAND not in event: + continue + + command = event[COMMAND] + + # We only consider lighting commands for now + if command in ( + COMMAND_MOVE_SATURATION, + COMMAND_MOVE_TO_SATURATION, + COMMAND_MOVE_COLOR_TEMP, + COMMAND_STEP_HUE, + COMMAND_STEP_SATURATION, + COMMAND_STEP_COLOR_TEMP, + ): + cluster = zcl.clusters.lighting.Color + elif command in ( + COMMAND_MOVE, + COMMAND_MOVE_ON_OFF, + COMMAND_STEP, + COMMAND_STEP_ON_OFF, + COMMAND_STOP, + COMMAND_STOP_ON_OFF, + COMMAND_MOVE_TO_LEVEL_ON_OFF, + ): + cluster = zcl.clusters.general.LevelControl + else: + continue + + if ARGS in event: + raise ValueError(f"ARGS should be migrated to PARAMS: {command!r}") + elif PARAMS not in event: + continue + + schema = cluster.commands_by_name[command].schema + schema(**event[PARAMS]) diff --git a/tests/test_tuya_mcu.py b/tests/test_tuya_mcu.py index 747f873160..c910c7ae12 100644 --- a/tests/test_tuya_mcu.py +++ b/tests/test_tuya_mcu.py @@ -125,3 +125,15 @@ async def test_tuya_mcu_classes(): mcu_version = TuyaMCUCluster.MCUVersion() assert mcu_version assert not mcu_version.version + + # test TuyaClusterData.manufacturer values + t_c_d = TuyaClusterData(manufacturer=foundation.ZCLHeader.NO_MANUFACTURER_ID) + assert t_c_d.manufacturer == -1 + t_c_d = TuyaClusterData(manufacturer=4619) + assert t_c_d.manufacturer == 4619 + t_c_d = TuyaClusterData(manufacturer="4098") + assert t_c_d.manufacturer == 4098 + with pytest.raises(ValueError): + TuyaClusterData(manufacturer="xiaomi") + with pytest.raises(ValueError): + TuyaClusterData(manufacturer=b"") diff --git a/zhaquirks/__init__.py b/zhaquirks/__init__.py index 007ef308cf..5931facedf 100755 --- a/zhaquirks/__init__.py +++ b/zhaquirks/__init__.py @@ -31,6 +31,8 @@ MODELS_INFO, MOTION_EVENT, NODE_DESCRIPTOR, + OCCUPANCY_EVENT, + OCCUPANCY_STATE, OFF, ON, OUTPUT_CLUSTERS, @@ -42,8 +44,6 @@ ) _LOGGER = logging.getLogger(__name__) -OCCUPANCY_STATE = 0 -OCCUPANCY_EVENT = "occupancy_event" class Bus(ListenableMixin): diff --git a/zhaquirks/adeo/color_controller.py b/zhaquirks/adeo/color_controller.py index 5754c964ad..1db36c1052 100644 --- a/zhaquirks/adeo/color_controller.py +++ b/zhaquirks/adeo/color_controller.py @@ -42,6 +42,7 @@ INPUT_CLUSTERS, MODELS_INFO, OUTPUT_CLUSTERS, + PARAMS, PROFILE_ID, SHORT_PRESS, TURN_OFF, @@ -188,49 +189,61 @@ def __init__(self, *args, **kwargs): COMMAND: COMMAND_STEP, CLUSTER_ID: 8, # LevelControl.cluster_id ENDPOINT_ID: 1, - ARGS: [0, 26, 5], + PARAMS: {"step_mode": 0, "step_size": 26, "transition_time": 5}, }, (SHORT_PRESS, DIM_DOWN): { COMMAND: COMMAND_STEP, CLUSTER_ID: 8, # LevelControl.cluster_id ENDPOINT_ID: 1, - ARGS: [1, 26, 5], + PARAMS: {"step_mode": 1, "step_size": 26, "transition_time": 5}, }, (SHORT_PRESS, COLOR_UP): { COMMAND: COMMAND_STEP_COLOR_TEMP, CLUSTER_ID: 768, # Color.cluster_id ENDPOINT_ID: 1, - ARGS: [3, 22, 5, 153, 370], + PARAMS: { + "step_mode": 3, + "step_size": 22, + "transition_time": 5, + "color_temp_min_mireds": 153, + "color_temp_max_mireds": 370, + }, }, (SHORT_PRESS, COLOR_DOWN): { COMMAND: COMMAND_STEP_COLOR_TEMP, CLUSTER_ID: 768, # Color.cluster_id ENDPOINT_ID: 1, - ARGS: [1, 22, 5, 153, 370], + PARAMS: { + "step_mode": 1, + "step_size": 22, + "transition_time": 5, + "color_temp_min_mireds": 153, + "color_temp_max_mireds": 370, + }, }, (SHORT_PRESS, SATURATION_UP): { COMMAND: COMMAND_STEP_SATURATION, CLUSTER_ID: 768, # Color.cluster_id ENDPOINT_ID: 1, - ARGS: [1, 26, 5], + PARAMS: {"step_mode": 1, "step_size": 26, "transition_time": 5}, }, (SHORT_PRESS, SATURATION_DOWN): { COMMAND: COMMAND_STEP_SATURATION, CLUSTER_ID: 768, # Color.cluster_id ENDPOINT_ID: 1, - ARGS: [3, 26, 5], + PARAMS: {"step_mode": 3, "step_size": 26, "transition_time": 5}, }, (SHORT_PRESS, HUE_LEFT): { COMMAND: COMMAND_STEP_HUE, CLUSTER_ID: 768, # Color.cluster_id ENDPOINT_ID: 1, - ARGS: [3, 22, 5], + PARAMS: {"step_mode": 3, "step_size": 22, "transition_time": 5}, }, (SHORT_PRESS, HUE_RIGHT): { COMMAND: COMMAND_STEP_HUE, CLUSTER_ID: 768, # Color.cluster_id ENDPOINT_ID: 1, - ARGS: [1, 22, 5], + PARAMS: {"step_mode": 1, "step_size": 22, "transition_time": 5}, }, (SHORT_PRESS, BUTTON_1): { COMMAND: "view", diff --git a/zhaquirks/aduro/adurolightncc.py b/zhaquirks/aduro/adurolightncc.py index e5717fa084..a39c4d13d1 100644 --- a/zhaquirks/aduro/adurolightncc.py +++ b/zhaquirks/aduro/adurolightncc.py @@ -6,7 +6,6 @@ from zigpy.zcl.clusters.lightlink import LightLink from zhaquirks.const import ( - ARGS, CLUSTER_ID, COMMAND, COMMAND_OFF, @@ -20,6 +19,7 @@ INPUT_CLUSTERS, MODELS_INFO, OUTPUT_CLUSTERS, + PARAMS, PROFILE_ID, SHORT_PRESS, TURN_OFF, @@ -91,12 +91,12 @@ class AdurolightNCC(CustomDevice): COMMAND: COMMAND_STEP, CLUSTER_ID: 8, ENDPOINT_ID: 1, - ARGS: [0, 16, 9], + PARAMS: {"step_mode": 0, "step_size": 16, "transition_time": 9}, }, (SHORT_PRESS, DIM_DOWN): { COMMAND: COMMAND_STEP, CLUSTER_ID: 8, ENDPOINT_ID: 1, - ARGS: [1, 16, 9], + PARAMS: {"step_mode": 1, "step_size": 16, "transition_time": 9}, }, } diff --git a/zhaquirks/aurora/aurora_dimmer.py b/zhaquirks/aurora/aurora_dimmer.py index e57002f1f6..f43ac4abec 100644 --- a/zhaquirks/aurora/aurora_dimmer.py +++ b/zhaquirks/aurora/aurora_dimmer.py @@ -27,6 +27,7 @@ LEFT, MODELS_INFO, OUTPUT_CLUSTERS, + PARAMS, PROFILE_ID, RIGHT, SHORT_PRESS, @@ -177,49 +178,73 @@ class WallSwitchColorCluster(EventableCluster, Color): COMMAND: COMMAND_STEP, CLUSTER_ID: 8, ENDPOINT_ID: 1, - ARGS: [0, 26, 3], + PARAMS: {"step_mode": 0, "step_size": 26, "transition_time": 3}, }, (DIM_DOWN, RIGHT): { COMMAND: COMMAND_STEP, CLUSTER_ID: 8, ENDPOINT_ID: 1, - ARGS: [1, 26, 3], + PARAMS: {"step_mode": 1, "step_size": 26, "transition_time": 3}, }, (COLOR_UP, RIGHT): { COMMAND: COMMAND_STEP_COLOR_TEMP, CLUSTER_ID: 768, ENDPOINT_ID: 1, - ARGS: [3, 47, 3, 153, 454], + PARAMS: { + "step_mode": 3, + "step_size": 47, + "transition_time": 3, + "color_temp_min_mireds": 153, + "color_temp_max_mireds": 454, + }, }, (COLOR_DOWN, RIGHT): { COMMAND: COMMAND_STEP_COLOR_TEMP, CLUSTER_ID: 768, ENDPOINT_ID: 1, - ARGS: [1, 47, 3, 153, 454], + PARAMS: { + "step_mode": 1, + "step_size": 47, + "transition_time": 3, + "color_temp_min_mireds": 153, + "color_temp_max_mireds": 454, + }, }, (DIM_UP, LEFT): { COMMAND: COMMAND_STEP, CLUSTER_ID: 8, ENDPOINT_ID: 2, - ARGS: [0, 26, 3], + PARAMS: {"step_mode": 0, "step_size": 26, "transition_time": 3}, }, (DIM_DOWN, LEFT): { COMMAND: COMMAND_STEP, CLUSTER_ID: 8, ENDPOINT_ID: 2, - ARGS: [1, 26, 3], + PARAMS: {"step_mode": 1, "step_size": 26, "transition_time": 3}, }, (COLOR_UP, LEFT): { COMMAND: COMMAND_STEP_COLOR_TEMP, CLUSTER_ID: 768, ENDPOINT_ID: 1, - ARGS: [3, 47, 3, 153, 454], + PARAMS: { + "step_mode": 3, + "step_size": 47, + "transition_time": 3, + "color_temp_min_mireds": 153, + "color_temp_max_mireds": 454, + }, }, (COLOR_DOWN, LEFT): { COMMAND: COMMAND_STEP_COLOR_TEMP, CLUSTER_ID: 768, ENDPOINT_ID: 1, - ARGS: [1, 47, 3, 153, 454], + PARAMS: { + "step_mode": 1, + "step_size": 47, + "transition_time": 3, + "color_temp_min_mireds": 153, + "color_temp_max_mireds": 454, + }, }, (SHORT_PRESS, RIGHT): { CLUSTER_ID: 6, diff --git a/zhaquirks/const.py b/zhaquirks/const.py index 7888f20b97..4502c5c820 100644 --- a/zhaquirks/const.py +++ b/zhaquirks/const.py @@ -40,7 +40,8 @@ COMMAND_MOVE = "move" COMMAND_MOVE_COLOR_TEMP = "move_color_temp" COMMAND_MOVE_ON_OFF = "move_with_on_off" -COMMAND_MOVE_SATURATION = "move_to_saturation" +COMMAND_MOVE_SATURATION = "move_saturation" +COMMAND_MOVE_TO_SATURATION = "move_to_saturation" COMMAND_MOVE_TO_LEVEL_ON_OFF = "move_to_level_with_on_off" COMMAND_OFF = "off" COMMAND_OFF_WITH_EFFECT = "off_with_effect" @@ -81,10 +82,13 @@ MODELS_INFO = SIG_MODELS_INFO MOTION_EVENT = "motion_event" NODE_DESCRIPTOR = SIG_NODE_DESC +OCCUPANCY_EVENT = "occupancy_event" +OCCUPANCY_STATE = 0 OFF = 0 ON = 1 OPEN = "open" OUTPUT_CLUSTERS = SIG_EP_OUTPUT +PARAMS = "params" PRESS_TYPE = "press_type" PROFILE_ID = SIG_EP_PROFILE QUADRUPLE_PRESS = "remote_button_quadruple_press" diff --git a/zhaquirks/ikea/dimmer.py b/zhaquirks/ikea/dimmer.py index 719b603c14..f16e7b92d3 100644 --- a/zhaquirks/ikea/dimmer.py +++ b/zhaquirks/ikea/dimmer.py @@ -14,10 +14,10 @@ from zigpy.zcl.clusters.lightlink import LightLink from zhaquirks.const import ( - ARGS, CLUSTER_ID, COMMAND, COMMAND_MOVE, + COMMAND_MOVE_ON_OFF, DEVICE_TYPE, ENDPOINT_ID, ENDPOINTS, @@ -25,6 +25,7 @@ LEFT, MODELS_INFO, OUTPUT_CLUSTERS, + PARAMS, PROFILE_ID, RIGHT, ROTATED, @@ -90,15 +91,15 @@ class IkeaDimmer(CustomDevice): device_automation_triggers = { (ROTATED, RIGHT): { - COMMAND: COMMAND_MOVE, + COMMAND: COMMAND_MOVE_ON_OFF, CLUSTER_ID: 8, ENDPOINT_ID: 1, - ARGS: [0, 195], + PARAMS: {"move_mode": 0, "rate": 195}, }, (ROTATED, LEFT): { COMMAND: COMMAND_MOVE, CLUSTER_ID: 8, ENDPOINT_ID: 1, - ARGS: [1, 195], + PARAMS: {"move_mode": 1, "rate": 195}, }, } diff --git a/zhaquirks/ikea/fivebtnremote.py b/zhaquirks/ikea/fivebtnremote.py index c5c88aa8dd..837440aa3c 100644 --- a/zhaquirks/ikea/fivebtnremote.py +++ b/zhaquirks/ikea/fivebtnremote.py @@ -37,6 +37,7 @@ LONG_PRESS, MODELS_INFO, OUTPUT_CLUSTERS, + PARAMS, PROFILE_ID, RIGHT, SHORT_PRESS, @@ -123,25 +124,25 @@ class IkeaTradfriRemote(CustomDevice): COMMAND: COMMAND_STEP_ON_OFF, CLUSTER_ID: 8, ENDPOINT_ID: 1, - ARGS: [0, 43, 5], + PARAMS: {"step_mode": 0, "step_size": 43, "transition_time": 5}, }, (LONG_PRESS, DIM_UP): { COMMAND: COMMAND_MOVE_ON_OFF, CLUSTER_ID: 8, ENDPOINT_ID: 1, - ARGS: [0, 83], + PARAMS: {"move_mode": 0, "rate": 83}, }, (SHORT_PRESS, DIM_DOWN): { COMMAND: COMMAND_STEP, CLUSTER_ID: 8, ENDPOINT_ID: 1, - ARGS: [1, 43, 5], + PARAMS: {"step_mode": 1, "step_size": 43, "transition_time": 5}, }, (LONG_PRESS, DIM_DOWN): { COMMAND: COMMAND_MOVE, CLUSTER_ID: 8, ENDPOINT_ID: 1, - ARGS: [1, 83], + PARAMS: {"move_mode": 1, "rate": 83}, }, (SHORT_PRESS, LEFT): { COMMAND: COMMAND_PRESS, diff --git a/zhaquirks/ikea/fivebtnremotezha.py b/zhaquirks/ikea/fivebtnremotezha.py index 92f8ed90fd..502a94adc1 100644 --- a/zhaquirks/ikea/fivebtnremotezha.py +++ b/zhaquirks/ikea/fivebtnremotezha.py @@ -37,6 +37,7 @@ LONG_PRESS, MODELS_INFO, OUTPUT_CLUSTERS, + PARAMS, PROFILE_ID, RIGHT, SHORT_PRESS, @@ -127,25 +128,25 @@ class IkeaTradfriRemote1(CustomDevice): COMMAND: COMMAND_STEP_ON_OFF, CLUSTER_ID: 8, ENDPOINT_ID: 1, - ARGS: [0, 43, 5], + PARAMS: {"step_mode": 0, "step_size": 43, "transition_time": 5}, }, (LONG_PRESS, DIM_UP): { COMMAND: COMMAND_MOVE_ON_OFF, CLUSTER_ID: 8, ENDPOINT_ID: 1, - ARGS: [0, 83], + PARAMS: {"move_mode": 0, "rate": 83}, }, (SHORT_PRESS, DIM_DOWN): { COMMAND: COMMAND_STEP, CLUSTER_ID: 8, ENDPOINT_ID: 1, - ARGS: [1, 43, 5], + PARAMS: {"step_mode": 1, "step_size": 43, "transition_time": 5}, }, (LONG_PRESS, DIM_DOWN): { COMMAND: COMMAND_MOVE, CLUSTER_ID: 8, ENDPOINT_ID: 1, - ARGS: [1, 83], + PARAMS: {"move_mode": 1, "rate": 83}, }, (SHORT_PRESS, LEFT): { COMMAND: COMMAND_PRESS, @@ -311,25 +312,32 @@ class IkeaTradfriRemote3(IkeaTradfriRemote1): COMMAND: COMMAND_STEP_ON_OFF, CLUSTER_ID: 8, ENDPOINT_ID: 1, - ARGS: [0, 43, 5], + PARAMS: {"step_mode": 0, "step_size": 43, "transition_time": 5}, }, (LONG_PRESS, DIM_UP): { COMMAND: COMMAND_MOVE_ON_OFF, CLUSTER_ID: 8, ENDPOINT_ID: 1, - ARGS: [0, 84], + PARAMS: {"move_mode": 0, "rate": 84}, }, (SHORT_PRESS, DIM_DOWN): { COMMAND: COMMAND_STEP, CLUSTER_ID: 8, ENDPOINT_ID: 1, - ARGS: [1, 43, 5], + PARAMS: { + "step_mode": 1, + "step_size": 43, + "transition_time": 5, + }, }, (LONG_PRESS, DIM_DOWN): { COMMAND: COMMAND_MOVE, CLUSTER_ID: 8, ENDPOINT_ID: 1, - ARGS: [1, 84], + PARAMS: { + "move_mode": 1, + "rate": 84, + }, }, (SHORT_PRESS, LEFT): { COMMAND: COMMAND_PRESS, diff --git a/zhaquirks/ikea/fourbtnremote.py b/zhaquirks/ikea/fourbtnremote.py index 018c7181d1..7d43516c9f 100644 --- a/zhaquirks/ikea/fourbtnremote.py +++ b/zhaquirks/ikea/fourbtnremote.py @@ -34,6 +34,7 @@ LONG_RELEASE, MODELS_INFO, OUTPUT_CLUSTERS, + PARAMS, PROFILE_ID, RIGHT, SHORT_PRESS, @@ -108,7 +109,7 @@ class IkeaTradfriRemote(CustomDevice): COMMAND: COMMAND_MOVE_ON_OFF, CLUSTER_ID: 8, ENDPOINT_ID: 1, - ARGS: [0, 83], + PARAMS: {"move_mode": 0, "rate": 83}, }, (LONG_RELEASE, DIM_UP): { COMMAND: COMMAND_STOP_ON_OFF, @@ -120,7 +121,7 @@ class IkeaTradfriRemote(CustomDevice): COMMAND: COMMAND_MOVE, CLUSTER_ID: 8, ENDPOINT_ID: 1, - ARGS: [1, 83], + PARAMS: {"move_mode": 1, "rate": 83}, }, (LONG_RELEASE, DIM_DOWN): { COMMAND: COMMAND_STOP_ON_OFF, diff --git a/zhaquirks/ikea/shortcutbtn.py b/zhaquirks/ikea/shortcutbtn.py index 36f08d6a37..08b68cdfcf 100644 --- a/zhaquirks/ikea/shortcutbtn.py +++ b/zhaquirks/ikea/shortcutbtn.py @@ -16,7 +16,6 @@ from zigpy.zcl.clusters.lightlink import LightLink from zhaquirks.const import ( - ARGS, CLUSTER_ID, COMMAND, COMMAND_MOVE_ON_OFF, @@ -33,6 +32,7 @@ LONG_RELEASE, MODELS_INFO, OUTPUT_CLUSTERS, + PARAMS, PROFILE_ID, SHORT_PRESS, TURN_ON, @@ -107,7 +107,7 @@ class IkeaTradfriShortcutBtn(CustomDevice): COMMAND: COMMAND_MOVE_ON_OFF, CLUSTER_ID: 8, ENDPOINT_ID: 1, - ARGS: [0, 83], + PARAMS: {"move_mode": 0, "rate": 83}, }, (LONG_RELEASE, DIM_UP): { COMMAND: COMMAND_STOP_ON_OFF, @@ -183,7 +183,7 @@ class IkeaTradfriShortcutBtn2(CustomDevice): COMMAND: COMMAND_MOVE_ON_OFF, CLUSTER_ID: 8, ENDPOINT_ID: 1, - ARGS: [0, 83], + PARAMS: {"move_mode": 0, "rate": 83}, }, (LONG_RELEASE, DIM_UP): { COMMAND: COMMAND_STOP_ON_OFF, diff --git a/zhaquirks/ikea/symfonisk.py b/zhaquirks/ikea/symfonisk.py index 2849fa121b..2c5b07c9fb 100644 --- a/zhaquirks/ikea/symfonisk.py +++ b/zhaquirks/ikea/symfonisk.py @@ -14,7 +14,6 @@ from zigpy.zcl.clusters.lightlink import LightLink from zhaquirks.const import ( - ARGS, CLUSTER_ID, COMMAND, COMMAND_MOVE, @@ -29,6 +28,7 @@ LEFT, MODELS_INFO, OUTPUT_CLUSTERS, + PARAMS, PROFILE_ID, RIGHT, ROTATED, @@ -106,13 +106,13 @@ class IkeaSYMFONISK(CustomDevice): COMMAND: COMMAND_MOVE, CLUSTER_ID: 8, ENDPOINT_ID: 1, - ARGS: [0, 195], + PARAMS: {"move_mode": 0, "rate": 195}, }, (ROTATED, LEFT): { COMMAND: COMMAND_MOVE, CLUSTER_ID: 8, ENDPOINT_ID: 1, - ARGS: [1, 195], + PARAMS: {"move_mode": 1, "rate": 195}, }, (ROTATED, STOP): { COMMAND: COMMAND_STOP, @@ -123,12 +123,12 @@ class IkeaSYMFONISK(CustomDevice): COMMAND: COMMAND_STEP, CLUSTER_ID: 8, ENDPOINT_ID: 1, - ARGS: [0, 1, 0], + PARAMS: {"step_mode": 0, "step_size": 1, "transition_time": 0}, }, (TRIPLE_PRESS, TURN_ON): { COMMAND: COMMAND_STEP, CLUSTER_ID: 8, ENDPOINT_ID: 1, - ARGS: [1, 1, 0], + PARAMS: {"step_mode": 1, "step_size": 1, "transition_time": 0}, }, } diff --git a/zhaquirks/ikea/twobtnremote.py b/zhaquirks/ikea/twobtnremote.py index dae1767e83..431dcb85c3 100644 --- a/zhaquirks/ikea/twobtnremote.py +++ b/zhaquirks/ikea/twobtnremote.py @@ -16,7 +16,6 @@ from zigpy.zcl.clusters.lightlink import LightLink from zhaquirks.const import ( - ARGS, CLUSTER_ID, COMMAND, COMMAND_MOVE, @@ -35,6 +34,7 @@ LONG_RELEASE, MODELS_INFO, OUTPUT_CLUSTERS, + PARAMS, PROFILE_ID, SHORT_PRESS, TURN_OFF, @@ -113,7 +113,7 @@ class IkeaTradfriRemote2Btn(CustomDevice): COMMAND: COMMAND_MOVE_ON_OFF, CLUSTER_ID: 8, ENDPOINT_ID: 1, - ARGS: [0, 83], + PARAMS: {"move_mode": 0, "rate": 83}, }, (LONG_RELEASE, DIM_UP): { COMMAND: COMMAND_STOP_ON_OFF, @@ -125,7 +125,7 @@ class IkeaTradfriRemote2Btn(CustomDevice): COMMAND: COMMAND_MOVE, CLUSTER_ID: 8, ENDPOINT_ID: 1, - ARGS: [1, 83], + PARAMS: {"move_mode": 1, "rate": 83}, }, (LONG_RELEASE, DIM_DOWN): { COMMAND: COMMAND_STOP, diff --git a/zhaquirks/lds/cctswitch.py b/zhaquirks/lds/cctswitch.py index ef192c8fcf..b6a4add5f4 100644 --- a/zhaquirks/lds/cctswitch.py +++ b/zhaquirks/lds/cctswitch.py @@ -32,6 +32,7 @@ LONG_PRESS, MODELS_INFO, OUTPUT_CLUSTERS, + PARAMS, PROFILE_ID, SHORT_PRESS, TURN_ON, @@ -112,24 +113,24 @@ class CCTSwitch(CustomDevice): COMMAND: COMMAND_STEP_ON_OFF, CLUSTER_ID: 8, ENDPOINT_ID: 1, - ARGS: [0, 43, 5], + PARAMS: {"step_mode": 0, "step_size": 43, "transition_time": 5}, }, (LONG_PRESS, DIM_UP): { COMMAND: COMMAND_MOVE_ON_OFF, CLUSTER_ID: 8, ENDPOINT_ID: 1, - ARGS: [0, 83], + PARAMS: {"move_mode": 0, "rate": 83}, }, (SHORT_PRESS, DIM_DOWN): { COMMAND: COMMAND_STEP, CLUSTER_ID: 8, ENDPOINT_ID: 1, - ARGS: [1, 43, 5], + PARAMS: {"step_mode": 1, "step_size": 43, "transition_time": 5}, }, (LONG_PRESS, DIM_DOWN): { COMMAND: COMMAND_MOVE, CLUSTER_ID: 8, ENDPOINT_ID: 1, - ARGS: [1, 83], + PARAMS: {"move_mode": 1, "rate": 83}, }, } diff --git a/zhaquirks/lutron/lzl4bwhl01remote.py b/zhaquirks/lutron/lzl4bwhl01remote.py index 4d22efab37..7bb2464b5d 100644 --- a/zhaquirks/lutron/lzl4bwhl01remote.py +++ b/zhaquirks/lutron/lzl4bwhl01remote.py @@ -13,7 +13,6 @@ from zhaquirks import GroupBoundCluster from zhaquirks.const import ( - ARGS, CLUSTER_ID, COMMAND, COMMAND_MOVE_TO_LEVEL_ON_OFF, @@ -27,6 +26,7 @@ INPUT_CLUSTERS, MODELS_INFO, OUTPUT_CLUSTERS, + PARAMS, PROFILE_ID, SHORT_PRESS, TURN_OFF, @@ -111,24 +111,24 @@ class LutronLZL4BWHL01Remote(CustomDevice): COMMAND: COMMAND_MOVE_TO_LEVEL_ON_OFF, CLUSTER_ID: 8, ENDPOINT_ID: 1, - ARGS: [254, 4], + PARAMS: {"level": 254, "transition_time": 4}, }, (SHORT_PRESS, TURN_OFF): { COMMAND: COMMAND_MOVE_TO_LEVEL_ON_OFF, CLUSTER_ID: 8, ENDPOINT_ID: 1, - ARGS: [0, 4], + PARAMS: {"level": 0, "transition_time": 4}, }, (SHORT_PRESS, DIM_UP): { COMMAND: COMMAND_STEP_ON_OFF, CLUSTER_ID: 8, ENDPOINT_ID: 1, - ARGS: [0, 30, 6], + PARAMS: {"step_mode": 0, "step_size": 30, "transition_time": 6}, }, (SHORT_PRESS, DIM_DOWN): { COMMAND: COMMAND_STEP, CLUSTER_ID: 8, ENDPOINT_ID: 1, - ARGS: [1, 30, 6], + PARAMS: {"step_mode": 1, "step_size": 30, "transition_time": 6}, }, } diff --git a/zhaquirks/sengled/e1e_g7f.py b/zhaquirks/sengled/e1e_g7f.py index 7e6037a06d..d6d2592316 100644 --- a/zhaquirks/sengled/e1e_g7f.py +++ b/zhaquirks/sengled/e1e_g7f.py @@ -17,7 +17,6 @@ from zhaquirks import Bus from zhaquirks.const import ( - ARGS, COMMAND, COMMAND_OFF, COMMAND_ON, @@ -31,6 +30,7 @@ LONG_PRESS, MODELS_INFO, OUTPUT_CLUSTERS, + PARAMS, PROFILE_ID, SHORT_PRESS, TURN_OFF, @@ -201,8 +201,14 @@ def __init__(self, *args, **kwargs): (SHORT_PRESS, TURN_ON): {COMMAND: COMMAND_ON}, (LONG_PRESS, TURN_ON): {COMMAND: "on_long"}, (DOUBLE_PRESS, TURN_ON): {COMMAND: "on_double"}, - (SHORT_PRESS, DIM_UP): {COMMAND: COMMAND_STEP, ARGS: [0, 1, 0]}, - (SHORT_PRESS, DIM_DOWN): {COMMAND: COMMAND_STEP, ARGS: [1, 1, 0]}, + (SHORT_PRESS, DIM_UP): { + COMMAND: COMMAND_STEP, + PARAMS: {"step_mode": 0, "step_size": 1, "transition_time": 0}, + }, + (SHORT_PRESS, DIM_DOWN): { + COMMAND: COMMAND_STEP, + PARAMS: {"step_mode": 1, "step_size": 1, "transition_time": 0}, + }, (SHORT_PRESS, TURN_OFF): {COMMAND: COMMAND_OFF}, (LONG_PRESS, TURN_OFF): {COMMAND: "off_long"}, (DOUBLE_PRESS, TURN_OFF): {COMMAND: "off_double"}, diff --git a/zhaquirks/terncy/__init__.py b/zhaquirks/terncy/__init__.py index 104de80234..5a3646c215 100644 --- a/zhaquirks/terncy/__init__.py +++ b/zhaquirks/terncy/__init__.py @@ -11,7 +11,7 @@ TemperatureMeasurement, ) -from zhaquirks import OCCUPANCY_EVENT, LocalDataCluster, OccupancyOnEvent, _Motion +from zhaquirks import LocalDataCluster, OccupancyOnEvent, _Motion from zhaquirks.const import ( BUTTON, CLUSTER_COMMAND, @@ -19,6 +19,7 @@ DOUBLE_PRESS, LEFT, MOTION_EVENT, + OCCUPANCY_EVENT, ON, PRESS_TYPE, QUADRUPLE_PRESS, diff --git a/zhaquirks/tuya/mcu/__init__.py b/zhaquirks/tuya/mcu/__init__.py index 68a5322840..4742d52632 100644 --- a/zhaquirks/tuya/mcu/__init__.py +++ b/zhaquirks/tuya/mcu/__init__.py @@ -75,7 +75,7 @@ class TuyaClusterData(t.Struct): cluster_attr: str attr_value: int # Maybe also others types? expect_reply: bool - manufacturer: str + manufacturer: int class MoesBacklight(t.enum8): diff --git a/zhaquirks/tuya/ts004f.py b/zhaquirks/tuya/ts004f.py index a4f1ffb180..04467c5fa3 100644 --- a/zhaquirks/tuya/ts004f.py +++ b/zhaquirks/tuya/ts004f.py @@ -21,7 +21,6 @@ from zigpy.zcl.clusters.lightlink import LightLink from zhaquirks.const import ( - ARGS, BUTTON, BUTTON_1, BUTTON_2, @@ -50,6 +49,7 @@ MODEL, MODELS_INFO, OUTPUT_CLUSTERS, + PARAMS, PROFILE_ID, RIGHT, ROTATED, @@ -135,31 +135,31 @@ class TuyaSmartRemote004FROK(CustomDevice): COMMAND: COMMAND_MOVE_SATURATION, ENDPOINT_ID: 1, CLUSTER_ID: 768, - ARGS: [1, 200], + PARAMS: {"move_mode": 1, "rate": 200}, }, (ROTATED_SLOW, RIGHT): { COMMAND: COMMAND_STEP, ENDPOINT_ID: 1, CLUSTER_ID: 8, - ARGS: [0, 13, 1], + PARAMS: {"step_mode": 0, "step_size": 13, "transition_time": 1}, }, # Triggered for both let and right in HA (HA bug). (ROTATED_SLOW, LEFT): { COMMAND: COMMAND_STEP, ENDPOINT_ID: 1, CLUSTER_ID: 8, - ARGS: [1, 13, 1], + PARAMS: {"step_mode": 1, "step_size": 13, "transition_time": 1}, }, (ROTATED_FAST, RIGHT): { COMMAND: COMMAND_STEP, CLUSTER_ID: 8, ENDPOINT_ID: 1, - ARGS: [0, 37, 2], + PARAMS: {"step_mode": 0, "step_size": 37, "transition_time": 2}, }, (ROTATED_FAST, LEFT): { COMMAND: COMMAND_STEP, CLUSTER_ID: 8, ENDPOINT_ID: 1, - ARGS: [1, 37, 2], + PARAMS: {"step_mode": 1, "step_size": 37, "transition_time": 2}, }, (SHORT_PRESS, BUTTON_1): {ENDPOINT_ID: 1, COMMAND: SHORT_PRESS}, (LONG_PRESS, BUTTON_1): {ENDPOINT_ID: 1, COMMAND: LONG_PRESS}, @@ -282,25 +282,25 @@ async def spell(self) -> None: COMMAND: COMMAND_STEP, CLUSTER_ID: 8, ENDPOINT_ID: 1, - ARGS: [0, 51, 10], + PARAMS: {"step_mode": 0, "step_size": 51, "transition_time": 10}, }, (LONG_PRESS, DIM_UP): { COMMAND: COMMAND_MOVE, CLUSTER_ID: 8, ENDPOINT_ID: 1, - ARGS: [0, 51], + PARAMS: {"move_mode": 0, "rate": 51}, }, (SHORT_PRESS, DIM_DOWN): { COMMAND: COMMAND_STEP, CLUSTER_ID: 8, ENDPOINT_ID: 1, - ARGS: [1, 51, 10], + PARAMS: {"step_mode": 1, "step_size": 51, "transition_time": 10}, }, (LONG_PRESS, DIM_DOWN): { COMMAND: COMMAND_MOVE, CLUSTER_ID: 8, ENDPOINT_ID: 1, - ARGS: [1, 51], + PARAMS: {"move_mode": 1, "rate": 51}, }, (LONG_RELEASE, DIM_DOWN): { COMMAND: COMMAND_STOP, @@ -388,25 +388,25 @@ class TuyaSmartRemote004F(CustomDevice): COMMAND: COMMAND_STEP, CLUSTER_ID: 8, ENDPOINT_ID: 1, - ARGS: [0, 51, 10], + PARAMS: {"step_mode": 0, "step_size": 51, "transition_time": 10}, }, (LONG_PRESS, DIM_UP): { COMMAND: COMMAND_MOVE, CLUSTER_ID: 8, ENDPOINT_ID: 1, - ARGS: [0, 51], + PARAMS: {"move_mode": 0, "rate": 51}, }, (SHORT_PRESS, DIM_DOWN): { COMMAND: COMMAND_STEP, CLUSTER_ID: 8, ENDPOINT_ID: 1, - ARGS: [1, 51, 10], + PARAMS: {"step_mode": 1, "step_size": 51, "transition_time": 10}, }, (LONG_PRESS, DIM_DOWN): { COMMAND: COMMAND_MOVE, CLUSTER_ID: 8, ENDPOINT_ID: 1, - ARGS: [1, 51], + PARAMS: {"move_mode": 1, "rate": 51}, }, (LONG_RELEASE, DIM_DOWN): { COMMAND: COMMAND_STOP, diff --git a/zhaquirks/tuya/ts130f.py b/zhaquirks/tuya/ts130f.py index 7af62c8862..81b348ba1b 100644 --- a/zhaquirks/tuya/ts130f.py +++ b/zhaquirks/tuya/ts130f.py @@ -21,6 +21,7 @@ OUTPUT_CLUSTERS, PROFILE_ID, ) +from zhaquirks.tuya import TuyaZBExternalSwitchTypeCluster ATTR_CURRENT_POSITION_LIFT_PERCENTAGE = 0x0008 CMD_GO_TO_LIFT_PERCENTAGE = 0x0005 @@ -332,3 +333,65 @@ class TuyaTS130FTI2(CustomDevice): }, }, } + + +class TuyaTS130ESTC(CustomDevice): + """Tuya ZigBee Curtain Switch Module with External Switch Type Cluster.""" + + signature = { + # SizePrefixedSimpleDescriptor(endpoint=1, profile=260, device_type=0x0202, device_version=1, input_clusters=[0x0000, 0x0004, 0x0005, 0x0006, 0x0102, 0xE001], output_clusters=[0x000a, 0x0019])) + MODEL: "TS130F", + ENDPOINTS: { + 1: { + PROFILE_ID: zha.PROFILE_ID, + DEVICE_TYPE: zha.DeviceType.WINDOW_COVERING_DEVICE, + INPUT_CLUSTERS: [ + Basic.cluster_id, + Groups.cluster_id, + Scenes.cluster_id, + OnOff.cluster_id, + WindowCovering.cluster_id, + TuyaZBExternalSwitchTypeCluster.cluster_id, + ], + OUTPUT_CLUSTERS: [ + Time.cluster_id, + Ota.cluster_id, + ], + }, + 242: { + #