Parse attribute reports for ZHA select entity (#89418)

* Parse attribute reports for ZHA select entity

* Add test for checking that select entity attribute reports are parsed
This commit is contained in:
TheJulianJES 2023-03-09 13:01:18 +01:00 committed by GitHub
parent ead3662b7a
commit 3989ef8863
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 102 additions and 1 deletions

View File

@ -26,6 +26,7 @@ from .core.const import (
CHANNEL_ON_OFF, CHANNEL_ON_OFF,
DATA_ZHA, DATA_ZHA,
SIGNAL_ADD_ENTITIES, SIGNAL_ADD_ENTITIES,
SIGNAL_ATTR_UPDATED,
Strobe, Strobe,
) )
from .core.registries import ZHA_ENTITIES from .core.registries import ZHA_ENTITIES
@ -212,6 +213,18 @@ class ZCLEnumSelectEntity(ZhaEntity, SelectEntity):
) )
self.async_write_ha_state() self.async_write_ha_state()
async def async_added_to_hass(self) -> None:
"""Run when about to be added to hass."""
await super().async_added_to_hass()
self.async_accept_signal(
self._channel, SIGNAL_ATTR_UPDATED, self.async_set_state
)
@callback
def async_set_state(self, attr_id: int, attr_name: str, value: Any):
"""Handle state update from channel."""
self.async_write_ha_state()
@CONFIG_DIAGNOSTIC_MATCH(channel_names=CHANNEL_ON_OFF) @CONFIG_DIAGNOSTIC_MATCH(channel_names=CHANNEL_ON_OFF)
class ZHAStartupOnOffSelectEntity( class ZHAStartupOnOffSelectEntity(

View File

@ -2,17 +2,28 @@
from unittest.mock import call, patch from unittest.mock import call, patch
import pytest import pytest
from zhaquirks import (
DEVICE_TYPE,
ENDPOINTS,
INPUT_CLUSTERS,
OUTPUT_CLUSTERS,
PROFILE_ID,
)
from zigpy.const import SIG_EP_PROFILE from zigpy.const import SIG_EP_PROFILE
import zigpy.profiles.zha as zha import zigpy.profiles.zha as zha
from zigpy.quirks import CustomCluster, CustomDevice
import zigpy.types as t
import zigpy.zcl.clusters.general as general import zigpy.zcl.clusters.general as general
from zigpy.zcl.clusters.manufacturer_specific import ManufacturerSpecificCluster
import zigpy.zcl.clusters.security as security import zigpy.zcl.clusters.security as security
from homeassistant.components.zha.select import AqaraMotionSensitivities
from homeassistant.const import STATE_UNKNOWN, EntityCategory, Platform from homeassistant.const import STATE_UNKNOWN, EntityCategory, Platform
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er, restore_state from homeassistant.helpers import entity_registry as er, restore_state
from homeassistant.util import dt as dt_util from homeassistant.util import dt as dt_util
from .common import find_entity_id from .common import async_enable_traffic, find_entity_id, send_attributes_report
from .conftest import SIG_EP_INPUT, SIG_EP_OUTPUT, SIG_EP_TYPE from .conftest import SIG_EP_INPUT, SIG_EP_OUTPUT, SIG_EP_TYPE
@ -29,6 +40,7 @@ def select_select_only():
Platform.NUMBER, Platform.NUMBER,
Platform.SELECT, Platform.SELECT,
Platform.SENSOR, Platform.SENSOR,
Platform.SWITCH,
), ),
): ):
yield yield
@ -323,3 +335,79 @@ async def test_on_off_select_unsupported(
qualifier=select_name.lower(), qualifier=select_name.lower(),
) )
assert entity_id is None assert entity_id is None
class MotionSensitivityQuirk(CustomDevice):
"""Quirk with motion sensitivity attribute."""
class OppleCluster(CustomCluster, ManufacturerSpecificCluster):
"""Aqara manufacturer specific cluster."""
cluster_id = 0xFCC0
ep_attribute = "opple_cluster"
attributes = {
0x010C: ("motion_sensitivity", t.uint8_t, True),
}
def __init__(self, *args, **kwargs):
"""Initialize."""
super().__init__(*args, **kwargs)
# populate cache to create config entity
self._attr_cache.update({0x010C: AqaraMotionSensitivities.Medium})
replacement = {
ENDPOINTS: {
1: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.OCCUPANCY_SENSOR,
INPUT_CLUSTERS: [general.Basic.cluster_id, OppleCluster],
OUTPUT_CLUSTERS: [],
},
}
}
@pytest.fixture
async def zigpy_device_aqara_sensor(hass, zigpy_device_mock, zha_device_joined):
"""Device tracker zigpy Aqara motion sensor device."""
zigpy_device = zigpy_device_mock(
{
1: {
SIG_EP_INPUT: [general.Basic.cluster_id],
SIG_EP_OUTPUT: [],
SIG_EP_TYPE: zha.DeviceType.OCCUPANCY_SENSOR,
}
},
manufacturer="LUMI",
model="lumi.motion.ac02",
quirk=MotionSensitivityQuirk,
)
zha_device = await zha_device_joined(zigpy_device)
zha_device.available = True
await hass.async_block_till_done()
return zigpy_device
async def test_on_off_select_attribute_report(
hass: HomeAssistant, light, zha_device_restored, zigpy_device_aqara_sensor
) -> None:
"""Test ZHA attribute report parsing for select platform."""
zha_device = await zha_device_restored(zigpy_device_aqara_sensor)
cluster = zigpy_device_aqara_sensor.endpoints.get(1).opple_cluster
entity_id = await find_entity_id(Platform.SELECT, zha_device, hass)
assert entity_id is not None
# allow traffic to flow through the gateway and device
await async_enable_traffic(hass, [zha_device])
# test that the state is in default medium state
assert hass.states.get(entity_id).state == AqaraMotionSensitivities.Medium.name
# send attribute report from device
await send_attributes_report(
hass, cluster, {"motion_sensitivity": AqaraMotionSensitivities.Low}
)
assert hass.states.get(entity_id).state == AqaraMotionSensitivities.Low.name