Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add additional entities for the Aqara E1 curtain motor to ZHA #108243

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
15 changes: 14 additions & 1 deletion homeassistant/components/zha/binary_sensor.py
Expand Up @@ -74,7 +74,7 @@ class BinarySensor(ZhaEntity, BinarySensorEntity):

_attribute_name: str

def __init__(self, unique_id, zha_device, cluster_handlers, **kwargs):
def __init__(self, unique_id, zha_device, cluster_handlers, **kwargs) -> None:
"""Initialize the ZHA binary sensor."""
super().__init__(unique_id, zha_device, cluster_handlers, **kwargs)
self._cluster_handler = cluster_handlers[0]
Expand Down Expand Up @@ -336,3 +336,16 @@ class AqaraLinkageAlarmState(BinarySensor):
_unique_id_suffix = "linkage_alarm_state"
_attr_device_class: BinarySensorDeviceClass = BinarySensorDeviceClass.SMOKE
_attr_translation_key: str = "linkage_alarm_state"


@CONFIG_DIAGNOSTIC_MATCH(
cluster_handler_names="opple_cluster", models={"lumi.curtain.agl001"}
)
class AqaraE1CurtainMotorOpenedByHandBinarySensor(BinarySensor):
"""Opened by hand binary sensor."""

_unique_id_suffix = "hand_open"
_attribute_name = "hand_open"
_attr_translation_key = "hand_open"
_attr_icon = "mdi:hand-wave"
_attr_entity_category = EntityCategory.DIAGNOSTIC
Expand Up @@ -202,6 +202,9 @@ def __init__(self, cluster: zigpy.zcl.Cluster, endpoint: Endpoint) -> None:
):
self.ZCL_INIT_ATTRS = self.ZCL_INIT_ATTRS.copy()
self.ZCL_INIT_ATTRS["transmit_power"] = True
elif self.cluster.endpoint.model == "lumi.curtain.agl001":
self.ZCL_INIT_ATTRS = self.ZCL_INIT_ATTRS.copy()
self.ZCL_INIT_ATTRS["power_source"] = True


@registries.ZIGBEE_CLUSTER_HANDLER_REGISTRY.register(BinaryInput.cluster_id)
Expand Down
Expand Up @@ -160,6 +160,14 @@ def __init__(self, cluster: zigpy.zcl.Cluster, endpoint: Endpoint) -> None:
"startup_on_off": True,
"decoupled_mode": True,
}
elif self.cluster.endpoint.model == "lumi.curtain.agl001":
self.ZCL_INIT_ATTRS = {
"hooks_state": True,
"hooks_lock": True,
"positions_stored": True,
"light_level": True,
"hand_open": True,
}

async def async_initialize_cluster_handler_specific(self, from_cache: bool) -> None:
"""Initialize cluster handler specific."""
Expand Down
19 changes: 0 additions & 19 deletions homeassistant/components/zha/select.py
Expand Up @@ -471,25 +471,6 @@ class AqaraT2RelayDecoupledMode(ZCLEnumSelectEntity):
_attr_translation_key: str = "decoupled_mode"


class AqaraE1ReverseDirection(types.enum8):
"""Aqara curtain reversal."""

Normal = 0x00
Inverted = 0x01


@CONFIG_DIAGNOSTIC_MATCH(
cluster_handler_names="window_covering", models={"lumi.curtain.agl001"}
)
class AqaraCurtainMode(ZCLEnumSelectEntity):
"""Representation of a ZHA curtain mode configuration entity."""

_unique_id_suffix = "window_covering_mode"
_attribute_name = "window_covering_mode"
_enum = AqaraE1ReverseDirection
_attr_translation_key: str = "window_covering_mode"


class InovelliOutputMode(types.enum1):
"""Inovelli output mode."""

Expand Down
55 changes: 55 additions & 0 deletions homeassistant/components/zha/sensor.py
Expand Up @@ -10,6 +10,8 @@
from typing import TYPE_CHECKING, Any, Self

from zigpy import types
from zigpy.zcl.clusters.closures import WindowCovering
from zigpy.zcl.clusters.general import Basic

from homeassistant.components.climate import HVACAction
from homeassistant.components.sensor import (
Expand Down Expand Up @@ -51,6 +53,7 @@
from .core.const import (
CLUSTER_HANDLER_ANALOG_INPUT,
CLUSTER_HANDLER_BASIC,
CLUSTER_HANDLER_COVER,
CLUSTER_HANDLER_DEVICE_TEMPERATURE,
CLUSTER_HANDLER_ELECTRICAL_MEASUREMENT,
CLUSTER_HANDLER_HUMIDITY,
Expand Down Expand Up @@ -1312,3 +1315,55 @@ class SetpointChangeSource(EnumSensor):
_attr_icon: str = "mdi:thermostat"
_attr_entity_category = EntityCategory.DIAGNOSTIC
_enum = SetpointChangeSourceEnum


@CONFIG_DIAGNOSTIC_MATCH(cluster_handler_names=CLUSTER_HANDLER_COVER)
# pylint: disable-next=hass-invalid-inheritance # needs fixing
class WindowCoveringTypeSensor(EnumSensor):
"""Sensor that displays the type of a cover device."""

_attribute_name: str = WindowCovering.AttributeDefs.window_covering_type.name
_enum = WindowCovering.WindowCoveringType
_unique_id_suffix: str = WindowCovering.AttributeDefs.window_covering_type.name
_attr_translation_key: str = WindowCovering.AttributeDefs.window_covering_type.name
_attr_entity_category = EntityCategory.DIAGNOSTIC
_attr_icon = "mdi:curtains"


@CONFIG_DIAGNOSTIC_MATCH(
cluster_handler_names=CLUSTER_HANDLER_BASIC, models={"lumi.curtain.agl001"}
)
# pylint: disable-next=hass-invalid-inheritance # needs fixing
class AqaraCurtainMotorPowerSourceSensor(EnumSensor):
"""Sensor that displays the power source of the Aqara E1 curtain motor device."""

_attribute_name: str = Basic.AttributeDefs.power_source.name
_enum = Basic.PowerSource
_unique_id_suffix: str = Basic.AttributeDefs.power_source.name
_attr_translation_key: str = Basic.AttributeDefs.power_source.name
_attr_entity_category = EntityCategory.DIAGNOSTIC
_attr_icon = "mdi:battery-positive"


class AqaraE1HookState(types.enum8):
"""Aqara hook state."""

Unlocked = 0x00
Locked = 0x01
Locking = 0x02
Unlocking = 0x03


@CONFIG_DIAGNOSTIC_MATCH(
cluster_handler_names="opple_cluster", models={"lumi.curtain.agl001"}
)
# pylint: disable-next=hass-invalid-inheritance # needs fixing
class AqaraCurtainHookStateSensor(EnumSensor):
"""Representation of a ZHA curtain mode configuration entity."""

_attribute_name = "hooks_state"
_enum = AqaraE1HookState
_unique_id_suffix = "hooks_state"
_attr_translation_key: str = "hooks_state"
_attr_icon: str = "mdi:hook"
_attr_entity_category = EntityCategory.DIAGNOSTIC
15 changes: 15 additions & 0 deletions homeassistant/components/zha/strings.json
Expand Up @@ -566,6 +566,9 @@
},
"ias_zone": {
"name": "IAS zone"
},
"hand_open": {
"name": "Opened by hand"
}
},
"button": {
Expand Down Expand Up @@ -896,6 +899,15 @@
},
"setpoint_change_source": {
"name": "Setpoint change source"
},
"power_source": {
"name": "Power source"
},
"window_covering_type": {
"name": "Window covering type"
},
"hooks_state": {
"name": "Hooks state"
}
},
"switch": {
Expand Down Expand Up @@ -923,6 +935,9 @@
"inverted": {
"name": "Inverted"
},
"hooks_locked": {
"name": "Hooks locked"
},
"smart_bulb_mode": {
"name": "Smart bulb mode"
},
Expand Down
12 changes: 12 additions & 0 deletions homeassistant/components/zha/switch.py
Expand Up @@ -685,3 +685,15 @@ async def _async_on_off(self, invert: bool) -> None:
if send_command:
await self._cluster_handler.write_attributes_safe({name: current_mode})
await self.async_update()


@CONFIG_DIAGNOSTIC_MATCH(
cluster_handler_names="opple_cluster", models={"lumi.curtain.agl001"}
)
class AqaraE1CurtainMotorHooksLockedSwitch(ZHASwitchConfigurationEntity):
"""Representation of a switch that controls whether the curtain motor hooks are locked."""

_unique_id_suffix = "hooks_lock"
_attribute_name = "hooks_lock"
_attr_translation_key = "hooks_locked"
_attr_icon: str = "mdi:lock"