Skip to content

Commit

Permalink
Ignore missing default reply for GLEDOPTO AC dimmer (#2330)
Browse files Browse the repository at this point in the history
* Use `NoReplyMixin` for GLEDOPTO dimmer

* Move `NoReplyMixin` to main `__init__.py` file
  • Loading branch information
TheJulianJES authored Apr 11, 2023
1 parent 529e630 commit fb5d256
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 39 deletions.
38 changes: 38 additions & 0 deletions zhaquirks/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,44 @@ def from_signature(
return device


class NoReplyMixin:
"""A simple mixin.
Allows a cluster to have configurable list of command
ids that do not generate an explicit reply.
"""

void_input_commands: set[int] = {}

async def command(self, command, *args, expect_reply=None, **kwargs):
"""Override the default Cluster command.
expect_reply behavior is based on void_input_commands.
Note that this method changes the default value of
expect_reply to None. This allows the caller to explicitly force
expect_reply to true.
"""

if expect_reply is None and command in self.void_input_commands:
cmd_expect_reply = False
elif expect_reply is None:
cmd_expect_reply = True # the default
else:
cmd_expect_reply = expect_reply

rsp = await super().command(
command, *args, expect_reply=cmd_expect_reply, **kwargs
)

if expect_reply is None and command in self.void_input_commands:
# Pretend we received a default reply
return foundation.GENERAL_COMMANDS[
foundation.GeneralCommand.Default_Response
].schema(command_id=command, status=foundation.Status.SUCCESS)

return rsp


def setup(custom_quirks_path: str | None = None) -> None:
"""Register all quirks with zigpy, including optional custom quirks."""

Expand Down
77 changes: 77 additions & 0 deletions zhaquirks/gledopto/glsd001.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
"""Quirk for GLEDOPTO GL-SD-001."""

from zigpy.profiles import zha
from zigpy.quirks import CustomCluster, CustomDevice
from zigpy.zcl.clusters.general import (
Basic,
Groups,
Identify,
LevelControl,
OnOff,
Ota,
Scenes,
)
from zigpy.zcl.clusters.lightlink import LightLink

from zhaquirks import NoReplyMixin
from zhaquirks.const import (
DEVICE_TYPE,
ENDPOINTS,
INPUT_CLUSTERS,
MODELS_INFO,
OUTPUT_CLUSTERS,
PROFILE_ID,
)


class LevelControlNoReply(NoReplyMixin, CustomCluster, LevelControl):
"""LevelControl cluster that does not require default responses."""

void_input_commands = {cmd.id for cmd in LevelControl.commands_by_name.values()}


class GledoptoGlSd001(CustomDevice):
"""Gledopto GL-SD-001 dimmer custom device implementation."""

signature = {
MODELS_INFO: [("GLEDOPTO", "GL-SD-001")],
ENDPOINTS: {
1: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.DIMMABLE_LIGHT,
INPUT_CLUSTERS: [
Basic.cluster_id,
Identify.cluster_id,
Groups.cluster_id,
Scenes.cluster_id,
OnOff.cluster_id,
LevelControl.cluster_id,
LightLink.cluster_id,
],
OUTPUT_CLUSTERS: [
Ota.cluster_id,
],
},
},
}

replacement = {
ENDPOINTS: {
1: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.DIMMABLE_LIGHT,
INPUT_CLUSTERS: [
Basic.cluster_id,
Identify.cluster_id,
Groups.cluster_id,
Scenes.cluster_id,
OnOff.cluster_id,
LevelControlNoReply,
LightLink.cluster_id,
],
OUTPUT_CLUSTERS: [
Ota.cluster_id,
],
},
},
}
40 changes: 1 addition & 39 deletions zhaquirks/kof/kof_mr101z.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@

from zigpy.profiles import zha
from zigpy.quirks import CustomCluster, CustomDevice
from zigpy.zcl import foundation
from zigpy.zcl.clusters.general import (
Basic,
Groups,
Expand All @@ -21,6 +20,7 @@
)
from zigpy.zcl.clusters.hvac import Fan

from zhaquirks import NoReplyMixin
from zhaquirks.const import (
DEVICE_TYPE,
ENDPOINTS,
Expand All @@ -31,44 +31,6 @@
)


class NoReplyMixin:
"""A simple mixin.
Allows a cluster to have configurable list of command
ids that do not generate an explicit reply.
"""

void_input_commands: set[int] = {}

async def command(self, command, *args, expect_reply=None, **kwargs):
"""Override the default Cluster command.
expect_reply behavior is based on void_input_commands.
Note that this method changes the default value of
expect_reply to None. This allows the caller to explicitly force
expect_reply to true.
"""

if expect_reply is None and command in self.void_input_commands:
cmd_expect_reply = False
elif expect_reply is None:
cmd_expect_reply = True # the default
else:
cmd_expect_reply = expect_reply

rsp = await super().command(
command, *args, expect_reply=cmd_expect_reply, **kwargs
)

if expect_reply is None and command in self.void_input_commands:
# Pretend we received a default reply
return foundation.GENERAL_COMMANDS[
foundation.GeneralCommand.Default_Response
].schema(command_id=command, status=foundation.Status.SUCCESS)

return rsp


class KofBasic(NoReplyMixin, CustomCluster, Basic):
"""KOF Basic Cluster."""

Expand Down

0 comments on commit fb5d256

Please sign in to comment.