Skip to content

Commit

Permalink
Change to TuyaEnchantableCluster that can be subclassed by any bind…
Browse files Browse the repository at this point in the history
…-able cluster class
  • Loading branch information
TheJulianJES committed Mar 24, 2023
1 parent 5d08a45 commit 6778fae
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 12 deletions.
6 changes: 3 additions & 3 deletions tests/test_tuya.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
)
from zhaquirks.tuya import (
Data,
TuyaEnchantableOnOffCluster,
TuyaEnchantableCluster,
TuyaManufClusterAttributes,
TuyaNewManufCluster,
)
Expand Down Expand Up @@ -1586,13 +1586,13 @@ def test_tuya_spell_devices_valid():
continue
for cluster in endpoint[INPUT_CLUSTERS] + endpoint[OUTPUT_CLUSTERS]:
if not isinstance(cluster, int) and issubclass(
cluster, TuyaEnchantableOnOffCluster
cluster, TuyaEnchantableCluster
):
enchanted_clusters += 1

# one EnchantedDevice must have at least one enchanted cluster
if enchanted_clusters == 0:
pytest.fail(
f"{quirk} does not have a cluster subclassing `TuyaEnchantableOnOffCluster` on endpoint 1 "
f"{quirk} does not have a cluster subclassing `TuyaEnchantableCluster` on endpoint 1 "
f"as required by the Tuya spell."
)
26 changes: 21 additions & 5 deletions zhaquirks/tuya/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -527,8 +527,24 @@ async def write_attributes(self, attributes, manufacturer=None):
return [[foundation.WriteAttributesStatusRecord(foundation.Status.SUCCESS)]]


class TuyaEnchantableOnOffCluster(CustomCluster, OnOff):
"""Tuya On/Off cluster that casts a magic spell if TUYA_SPELL is set."""
class TuyaEnchantableCluster(CustomCluster):
"""Tuya cluster that casts a magic spell if `TUYA_SPELL` is set.
Preferably, make the device inherit from `EnchantedDevice` and use a subclass of this class in the replacement.
This will only work for clusters that ZHA calls bind() on.
At the moment, ZHA does not do this for:
- Basic cluster
- Identify cluster
- Groups cluster
- OTA cluster
- GreenPowerProxy cluster
- LightLink cluster
- non-registered manufacturer specific clusters
Make sure to add a subclass of TuyaEnchantableCluster to the quirk replacement. Tests will fail if this is not done.
Classes like TuyaOnOff, TuyaZBOnOffAttributeCluster, TuyaSmartRemoteOnOffCluster already inherit from this class.
"""

async def bind(self):
"""Bind cluster and start casting the spell if necessary."""
Expand All @@ -550,7 +566,7 @@ async def spell(self):
self.debug("Executed spell on Tuya device %s", self.endpoint.device.ieee)


class TuyaOnOff(TuyaEnchantableOnOffCluster):
class TuyaOnOff(TuyaEnchantableCluster, OnOff):
"""Tuya On/Off cluster for On/Off device."""

def __init__(self, *args, **kwargs):
Expand Down Expand Up @@ -944,7 +960,7 @@ class PowerOnState(t.enum8):
LastState = 0x02


class TuyaZBOnOffAttributeCluster(TuyaEnchantableOnOffCluster):
class TuyaZBOnOffAttributeCluster(TuyaEnchantableCluster, OnOff):
"""Tuya Zigbee On Off cluster with extra attributes."""

attributes = OnOff.attributes.copy()
Expand All @@ -954,7 +970,7 @@ class TuyaZBOnOffAttributeCluster(TuyaEnchantableOnOffCluster):
attributes.update({0x8004: ("switch_mode", SwitchMode)})


class TuyaSmartRemoteOnOffCluster(TuyaEnchantableOnOffCluster, EventableCluster):
class TuyaSmartRemoteOnOffCluster(TuyaEnchantableCluster, OnOff, EventableCluster):
"""TuyaSmartRemoteOnOffCluster: fire events corresponding to press type."""

rotate_type = {
Expand Down
9 changes: 5 additions & 4 deletions zhaquirks/tuya/mcu/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from zigpy.quirks import CustomDevice
import zigpy.types as t
from zigpy.zcl import foundation
from zigpy.zcl.clusters.general import LevelControl
from zigpy.zcl.clusters.general import LevelControl, OnOff

from zhaquirks import Bus, DoublingPowerConfigurationCluster
from zhaquirks.tuya import (
Expand All @@ -18,7 +18,7 @@
PowerOnState,
TuyaCommand,
TuyaDatapointData,
TuyaEnchantableOnOffCluster,
TuyaEnchantableCluster,
TuyaLocalCluster,
TuyaNewManufCluster,
TuyaTimePayload,
Expand Down Expand Up @@ -355,7 +355,7 @@ def handle_mcu_connection_status(
return foundation.Status.SUCCESS


class TuyaOnOff(TuyaEnchantableOnOffCluster, TuyaLocalCluster):
class TuyaOnOff(TuyaEnchantableCluster, OnOff, TuyaLocalCluster):
"""Tuya MCU OnOff cluster."""

async def command(
Expand Down Expand Up @@ -666,7 +666,8 @@ class TuyaLevelControlManufCluster(TuyaMCUCluster):
class EnchantedDevice(CustomDevice):
"""Class for Tuya devices which need to be unlocked by casting a 'spell'. This happens during binding.
To make sure the spell is cast, the device needs to implement `TuyaEnchantableOnOffCluster` or a subclass of it.
To make sure the spell is cast, the device needs to implement a subclass of `TuyaEnchantableCluster`.
For more information, see the documentation of `TuyaEnchantableCluster`.
"""

TUYA_SPELL = True

0 comments on commit 6778fae

Please sign in to comment.