Skip to content

Commit

Permalink
Merge branch 'release/0.0.98'
Browse files Browse the repository at this point in the history
  • Loading branch information
dmulcahey committed Apr 27, 2023
2 parents a3e54a2 + 0f4cab4 commit 3771237
Show file tree
Hide file tree
Showing 10 changed files with 194 additions and 35 deletions.
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

from setuptools import find_packages, setup

VERSION = "0.0.97"
VERSION = "0.0.98"


setup(
Expand Down
5 changes: 4 additions & 1 deletion tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""Fixtures for all tests."""

from unittest.mock import AsyncMock
from unittest.mock import AsyncMock, Mock

import pytest
import zigpy.application
Expand Down Expand Up @@ -191,6 +191,9 @@ def __getattr__(self, key):
return self.endpoints.get(key)

test_dev = FakeDevice(signature)
test_dev._application = Mock()
test_dev._application._dblistener = None

device = zigpy.quirks.get_device(test_dev)
assert isinstance(device, quirk)

Expand Down
2 changes: 1 addition & 1 deletion tests/test_konke.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ async def test_konke_button(zigpy_device_from_quirk, quirk):
"""Test Konke button remotes."""

device = zigpy_device_from_quirk(quirk)
cluster = device.endpoints[1].custom_on_off
cluster = device.endpoints[1].konke_on_off

listener = mock.MagicMock()
cluster.add_listener(listener)
Expand Down
17 changes: 15 additions & 2 deletions tests/test_quirks.py
Original file line number Diff line number Diff line change
Expand Up @@ -700,8 +700,21 @@ def test_attributes_updated_not_replaced(quirk: CustomDevice) -> None:
base_cluster = list(base_clusters)[0]

# Ensure the attribute IDs are extended
if not set(base_cluster.attributes) <= set(cluster.attributes):
base_attr_ids = set(base_cluster.attributes)
quirk_attr_ids = set(cluster.attributes)

if not base_attr_ids <= quirk_attr_ids:
pytest.fail(
f"Cluster {cluster} deletes parent class's attributes instead of"
f" extending them: {base_attr_ids - quirk_attr_ids}"
)

# Ensure the attribute names are extended
base_attr_names = {a.name for a in base_cluster.attributes.values()}
quirk_attr_names = {a.name for a in cluster.attributes.values()}

if not base_attr_names <= quirk_attr_names:
pytest.fail(
f"Cluster {cluster} deletes parent class's attributes instead of"
f" extending them: {base_cluster}"
f" extending them: {base_attr_names - quirk_attr_names}"
)
49 changes: 24 additions & 25 deletions zhaquirks/konke/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,19 @@
KONKE = "Konke"


class KonkeButtonEvent(t.enum8):
Single = 0x80
Double = 0x81
Hold = 0x82


PRESS_TYPES = {
KonkeButtonEvent.Single: COMMAND_SINGLE,
KonkeButtonEvent.Double: COMMAND_DOUBLE,
KonkeButtonEvent.Hold: COMMAND_HOLD,
}


class OccupancyCluster(LocalDataCluster, OccupancyOnEvent):
"""Occupancy cluster."""

Expand All @@ -31,14 +44,17 @@ class MotionCluster(MotionWithReset):
send_occupancy_event: bool = True


class KonkeOnOffCluster(CustomCluster, OnOff):
class KonkeOnOffCluster(CustomCluster):
"""Konke OnOff cluster implementation."""

PRESS_TYPES = {0x80: COMMAND_SINGLE, 0x81: COMMAND_DOUBLE, 0x82: COMMAND_HOLD}
ep_attribute = "custom_on_off"
cluster_id = OnOff.cluster_id
ep_attribute = "konke_on_off"

attributes = OnOff.attributes.copy()
attributes[0x0000] = (PRESS_TYPE, t.uint8_t)
attributes[0x0000] = ("konke_button_event", KonkeButtonEvent)

server_commands = OnOff.server_commands.copy()
client_commands = OnOff.client_commands.copy()

def handle_cluster_general_request(
self,
Expand All @@ -60,30 +76,13 @@ def handle_cluster_general_request(
return

attr = args[0][0]
if attr.attrid != 0x0000:

if attr.attrid != self.attributes_by_name["konke_button_event"].id:
return

value = attr.value.value
event_args = {
PRESS_TYPE: self.PRESS_TYPES.get(value, value),
COMMAND_ID: value,
PRESS_TYPE: PRESS_TYPES[value],
COMMAND_ID: value.value, # to maintain backwards compatibility
}
self.listener_event(ZHA_SEND_EVENT, event_args[PRESS_TYPE], event_args)

def deserialize(self, data):
"""Deserialize fix for Konke butchered Bool ZCL type."""
try:
return super().deserialize(data)
except ValueError:
hdr, data = zigpy.zcl.foundation.ZCLHeader.deserialize(data)
if (
hdr.frame_control.is_cluster
or hdr.command_id
!= zigpy.zcl.foundation.GeneralCommand.Report_Attributes
):
raise
attr_id, data = t.uint16_t.deserialize(data)
attr = zigpy.zcl.foundation.Attribute(
attr_id, zigpy.zcl.foundation.TypeValue(t.uint8_t, data[1])
)
return hdr, [[attr]]
8 changes: 7 additions & 1 deletion zhaquirks/philips/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,19 @@
}


class OccupancyCluster(CustomCluster, OccupancySensing):
class PhilipsOccupancySensing(CustomCluster):
"""Philips occupancy cluster."""

cluster_id = OccupancySensing.cluster_id
ep_attribute = "philips_occupancy"

attributes = OccupancySensing.attributes.copy()
attributes[0x0030] = ("sensitivity", t.uint8_t, True)
attributes[0x0031] = ("sensitivity_max", t.uint8_t, True)

server_commands = OccupancySensing.server_commands.copy()
client_commands = OccupancySensing.client_commands.copy()


class PhilipsBasicCluster(CustomCluster, Basic):
"""Philips Basic cluster."""
Expand Down
6 changes: 3 additions & 3 deletions zhaquirks/philips/motion.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
OUTPUT_CLUSTERS,
PROFILE_ID,
)
from zhaquirks.philips import PHILIPS, SIGNIFY, OccupancyCluster
from zhaquirks.philips import PHILIPS, SIGNIFY, PhilipsOccupancySensing


class BasicCluster(CustomCluster, Basic):
Expand Down Expand Up @@ -106,7 +106,7 @@ class PhilipsMotion(CustomDevice):
Identify.cluster_id,
IlluminanceMeasurement.cluster_id,
TemperatureMeasurement.cluster_id,
OccupancyCluster,
PhilipsOccupancySensing,
],
OUTPUT_CLUSTERS: [Ota.cluster_id],
},
Expand Down Expand Up @@ -152,7 +152,7 @@ class SignifyMotion(CustomDevice):
Identify.cluster_id,
IlluminanceMeasurement.cluster_id,
TemperatureMeasurement.cluster_id,
OccupancyCluster,
PhilipsOccupancySensing,
],
OUTPUT_CLUSTERS: [
Basic.cluster_id,
Expand Down
92 changes: 92 additions & 0 deletions zhaquirks/tuya/ts011f_plug.py
Original file line number Diff line number Diff line change
Expand Up @@ -1210,3 +1210,95 @@ class Plug_CB_Metering(EnchantedDevice):
},
},
}


class Plug_2AC_var05(EnchantedDevice):
"""Immax TS0011F 2 outlet plug."""

signature = {
MODEL: "TS011F",
ENDPOINTS: {
1: {
# "profile_id": 260,
# "device_type": "0x010a",
# "in_clusters": ["0x0000","0x0003","0x0004","0x0005","0x0006","0x0702","0x0b04","0xe000","0xe001"],
# "out_clusters": ["0x000a","0x0019"]
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.ON_OFF_PLUG_IN_UNIT,
INPUT_CLUSTERS: [
Basic.cluster_id,
Identify.cluster_id,
Groups.cluster_id,
Scenes.cluster_id,
OnOff.cluster_id,
Metering.cluster_id,
ElectricalMeasurement.cluster_id,
TuyaZBE000Cluster.cluster_id,
TuyaZBExternalSwitchTypeCluster.cluster_id,
],
OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
},
2: {
# "profile_id": 260,
# "device_type": "0x010a",
# "in_clusters": ["0x0004","0x0005","0x0006","0xe001"],
# "out_clusters": []
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.ON_OFF_PLUG_IN_UNIT,
INPUT_CLUSTERS: [
Groups.cluster_id,
Scenes.cluster_id,
OnOff.cluster_id,
TuyaZBExternalSwitchTypeCluster.cluster_id,
],
OUTPUT_CLUSTERS: [],
},
242: {
# "profile_id": 41440,
# "device_type": "0x0061",
# "in_clusters": [],
# "out_clusters": ["0x0021"]
PROFILE_ID: 41440,
DEVICE_TYPE: 97,
INPUT_CLUSTERS: [],
OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
},
},
}
replacement = {
ENDPOINTS: {
1: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.ON_OFF_PLUG_IN_UNIT,
INPUT_CLUSTERS: [
Basic.cluster_id,
Identify.cluster_id,
Groups.cluster_id,
Scenes.cluster_id,
TuyaZBOnOffAttributeCluster,
TuyaZBMeteringCluster,
TuyaZBElectricalMeasurement,
TuyaZBE000Cluster,
TuyaZBExternalSwitchTypeCluster,
],
OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
},
2: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.ON_OFF_PLUG_IN_UNIT,
INPUT_CLUSTERS: [
Groups.cluster_id,
Scenes.cluster_id,
TuyaZBOnOffAttributeCluster,
TuyaZBExternalSwitchTypeCluster,
],
OUTPUT_CLUSTERS: [],
},
242: {
PROFILE_ID: 41440,
DEVICE_TYPE: 97,
INPUT_CLUSTERS: [],
OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
},
},
}
2 changes: 1 addition & 1 deletion zhaquirks/xiaomi/aqara/feeder_acn001.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ def _parse_feeder_attribute(self, value: bytes) -> None:
self._update_attribute(
ZCL_LAST_FEEDING_SOURCE, OppleCluster.FeedingSource(feeding_source)
)
self._update_attribute(ZCL_LAST_FEEDING_SIZE, int(feeding_size))
self._update_attribute(ZCL_LAST_FEEDING_SIZE, int(feeding_size, base=16))
elif attribute == PORTIONS_DISPENSED:
portions_per_day, _ = types.uint16_t_be.deserialize(attribute_value)
self._update_attribute(ZCL_PORTIONS_DISPENSED, portions_per_day)
Expand Down
46 changes: 46 additions & 0 deletions zhaquirks/xiaomi/aqara/roller_curtain_e1.py
Original file line number Diff line number Diff line change
Expand Up @@ -300,3 +300,49 @@ class RollerE1AQ_2(RollerE1AQ):
},
},
}


class RollerE1AQ_3(RollerE1AQ):
"""Aqara Roller Shade Driver E1 (version 3) device."""

signature = {
MODELS_INFO: [(LUMI, "lumi.curtain.acn002")],
ENDPOINTS: {
# <SizePrefixedSimpleDescriptor endpoint=1 profile=260 device_type=514
# device_version=1
# input_clusters=[0, 2, 3, 4, 5, 6, 9, 13, 19, 258]
# output_clusters=[10, 25]>
1: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.WINDOW_COVERING_DEVICE,
INPUT_CLUSTERS: [
Alarms.cluster_id,
AnalogOutput.cluster_id,
Basic.cluster_id,
DeviceTemperature.cluster_id,
Groups.cluster_id,
Identify.cluster_id,
MultistateOutput.cluster_id,
OnOff.cluster_id,
Scenes.cluster_id,
WindowCovering.cluster_id,
],
OUTPUT_CLUSTERS: [
Ota.cluster_id,
Time.cluster_id,
],
},
# <SizePrefixedSimpleDescriptor endpoint=242 profile=41440 device_type=97
# device_version=0,
# input_clusters=[]
# output_clusters=[33]>
242: {
PROFILE_ID: 41440,
DEVICE_TYPE: 0x0061,
INPUT_CLUSTERS: [],
OUTPUT_CLUSTERS: [
GreenPowerProxy.cluster_id,
],
},
},
}

0 comments on commit 3771237

Please sign in to comment.