Implement Keen vents as zha cover devices (#36080)
* Implement Keen vents as cover devices * Update homeassistant/components/zha/cover.py
This commit is contained in:
parent
9212d1c2dc
commit
fe45935f38
4 changed files with 112 additions and 13 deletions
|
@ -98,7 +98,7 @@ DEVICE_CLASS = {
|
|||
zigpy.profiles.zha.DeviceType.DIMMABLE_LIGHT: LIGHT,
|
||||
zigpy.profiles.zha.DeviceType.DIMMABLE_PLUG_IN_UNIT: LIGHT,
|
||||
zigpy.profiles.zha.DeviceType.EXTENDED_COLOR_LIGHT: LIGHT,
|
||||
zigpy.profiles.zha.DeviceType.LEVEL_CONTROLLABLE_OUTPUT: LIGHT,
|
||||
zigpy.profiles.zha.DeviceType.LEVEL_CONTROLLABLE_OUTPUT: COVER,
|
||||
zigpy.profiles.zha.DeviceType.ON_OFF_BALLAST: SWITCH,
|
||||
zigpy.profiles.zha.DeviceType.ON_OFF_LIGHT: LIGHT,
|
||||
zigpy.profiles.zha.DeviceType.ON_OFF_PLUG_IN_UNIT: SWITCH,
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
"""Support for ZHA covers."""
|
||||
import asyncio
|
||||
import functools
|
||||
import logging
|
||||
from typing import List, Optional
|
||||
|
@ -8,6 +9,7 @@ from zigpy.zcl.foundation import Status
|
|||
from homeassistant.components.cover import (
|
||||
ATTR_CURRENT_POSITION,
|
||||
ATTR_POSITION,
|
||||
DEVICE_CLASS_DAMPER,
|
||||
DEVICE_CLASS_SHADE,
|
||||
DOMAIN,
|
||||
CoverEntity,
|
||||
|
@ -278,3 +280,31 @@ class Shade(ZhaEntity, CoverEntity):
|
|||
if not isinstance(res, list) or res[1] != Status.SUCCESS:
|
||||
self.debug("couldn't stop cover: %s", res)
|
||||
return
|
||||
|
||||
|
||||
@STRICT_MATCH(
|
||||
channel_names={CHANNEL_LEVEL, CHANNEL_ON_OFF}, manufacturers="Keen Home Inc"
|
||||
)
|
||||
class KeenVent(Shade):
|
||||
"""Keen vent cover."""
|
||||
|
||||
@property
|
||||
def device_class(self) -> Optional[str]:
|
||||
"""Return the class of this device, from component DEVICE_CLASSES."""
|
||||
return DEVICE_CLASS_DAMPER
|
||||
|
||||
async def async_open_cover(self, **kwargs):
|
||||
"""Open the cover."""
|
||||
position = self._position or 100
|
||||
tasks = [
|
||||
self._level_channel.move_to_level_with_on_off(position * 255 / 100, 1),
|
||||
self._on_off_channel.on(),
|
||||
]
|
||||
results = await asyncio.gather(*tasks, return_exceptions=True)
|
||||
if any([isinstance(result, Exception) for result in results]):
|
||||
self.debug("couldn't open cover")
|
||||
return
|
||||
|
||||
self._is_open = True
|
||||
self._position = position
|
||||
self.async_write_ha_state()
|
||||
|
|
|
@ -61,6 +61,22 @@ def zigpy_shade_device(zigpy_device_mock):
|
|||
return zigpy_device_mock(endpoints)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def zigpy_keen_vent(zigpy_device_mock):
|
||||
"""Zigpy Keen Vent device."""
|
||||
|
||||
endpoints = {
|
||||
1: {
|
||||
"device_type": 3,
|
||||
"in_clusters": [general.LevelControl.cluster_id, general.OnOff.cluster_id],
|
||||
"out_clusters": [],
|
||||
}
|
||||
}
|
||||
return zigpy_device_mock(
|
||||
endpoints, manufacturer="Keen Home Inc", model="SV02-612-MP-1.3"
|
||||
)
|
||||
|
||||
|
||||
@patch(
|
||||
"homeassistant.components.zha.core.channels.closures.WindowCovering.async_initialize"
|
||||
)
|
||||
|
@ -306,3 +322,56 @@ async def test_restore_state(hass, zha_device_restored, zigpy_shade_device):
|
|||
# test that the cover was created and that it is unavailable
|
||||
assert hass.states.get(entity_id).state == STATE_OPEN
|
||||
assert hass.states.get(entity_id).attributes[ATTR_CURRENT_POSITION] == 50
|
||||
|
||||
|
||||
async def test_keen_vent(hass, zha_device_joined_restored, zigpy_keen_vent):
|
||||
"""Test keen vent."""
|
||||
|
||||
# load up cover domain
|
||||
zha_device = await zha_device_joined_restored(zigpy_keen_vent)
|
||||
|
||||
cluster_on_off = zigpy_keen_vent.endpoints.get(1).on_off
|
||||
cluster_level = zigpy_keen_vent.endpoints.get(1).level
|
||||
entity_id = await find_entity_id(DOMAIN, zha_device, hass)
|
||||
assert entity_id is not None
|
||||
|
||||
# test that the cover was created and that it is unavailable
|
||||
assert hass.states.get(entity_id).state == STATE_UNAVAILABLE
|
||||
|
||||
# allow traffic to flow through the gateway and device
|
||||
await async_enable_traffic(hass, [zha_device])
|
||||
await hass.async_block_till_done()
|
||||
|
||||
# test that the state has changed from unavailable to off
|
||||
await send_attributes_report(hass, cluster_on_off, {8: 0, 0: False, 1: 1})
|
||||
assert hass.states.get(entity_id).state == STATE_CLOSED
|
||||
|
||||
# open from UI command fails
|
||||
p1 = patch.object(cluster_on_off, "request", side_effect=asyncio.TimeoutError)
|
||||
p2 = patch.object(cluster_level, "request", AsyncMock(return_value=[4, 0]))
|
||||
|
||||
with p1, p2:
|
||||
await hass.services.async_call(
|
||||
DOMAIN, SERVICE_OPEN_COVER, {"entity_id": entity_id}, blocking=True
|
||||
)
|
||||
assert cluster_on_off.request.call_count == 1
|
||||
assert cluster_on_off.request.call_args[0][0] is False
|
||||
assert cluster_on_off.request.call_args[0][1] == 0x0001
|
||||
assert cluster_level.request.call_count == 1
|
||||
assert hass.states.get(entity_id).state == STATE_CLOSED
|
||||
|
||||
# open from UI command success
|
||||
p1 = patch.object(cluster_on_off, "request", AsyncMock(return_value=[1, 0]))
|
||||
p2 = patch.object(cluster_level, "request", AsyncMock(return_value=[4, 0]))
|
||||
|
||||
with p1, p2:
|
||||
await hass.services.async_call(
|
||||
DOMAIN, SERVICE_OPEN_COVER, {"entity_id": entity_id}, blocking=True
|
||||
)
|
||||
await asyncio.sleep(0)
|
||||
assert cluster_on_off.request.call_count == 1
|
||||
assert cluster_on_off.request.call_args[0][0] is False
|
||||
assert cluster_on_off.request.call_args[0][1] == 0x0001
|
||||
assert cluster_level.request.call_count == 1
|
||||
assert hass.states.get(entity_id).state == STATE_OPEN
|
||||
assert hass.states.get(entity_id).attributes[ATTR_CURRENT_POSITION] == 100
|
||||
|
|
|
@ -1036,16 +1036,16 @@ DEVICES = [
|
|||
}
|
||||
},
|
||||
"entities": [
|
||||
"light.keen_home_inc_sv02_610_mp_1_3_77665544_level_on_off",
|
||||
"cover.keen_home_inc_sv02_610_mp_1_3_77665544_level_on_off",
|
||||
"sensor.keen_home_inc_sv02_610_mp_1_3_77665544_power",
|
||||
"sensor.keen_home_inc_sv02_610_mp_1_3_77665544_pressure",
|
||||
"sensor.keen_home_inc_sv02_610_mp_1_3_77665544_temperature",
|
||||
],
|
||||
"entity_map": {
|
||||
("light", "00:11:22:33:44:55:66:77-1"): {
|
||||
("cover", "00:11:22:33:44:55:66:77-1"): {
|
||||
"channels": ["level", "on_off"],
|
||||
"entity_class": "Light",
|
||||
"entity_id": "light.keen_home_inc_sv02_610_mp_1_3_77665544_level_on_off",
|
||||
"entity_class": "KeenVent",
|
||||
"entity_id": "cover.keen_home_inc_sv02_610_mp_1_3_77665544_level_on_off",
|
||||
},
|
||||
("sensor", "00:11:22:33:44:55:66:77-1-1"): {
|
||||
"channels": ["power"],
|
||||
|
@ -1094,16 +1094,16 @@ DEVICES = [
|
|||
}
|
||||
},
|
||||
"entities": [
|
||||
"light.keen_home_inc_sv02_612_mp_1_2_77665544_level_on_off",
|
||||
"cover.keen_home_inc_sv02_612_mp_1_2_77665544_level_on_off",
|
||||
"sensor.keen_home_inc_sv02_612_mp_1_2_77665544_power",
|
||||
"sensor.keen_home_inc_sv02_612_mp_1_2_77665544_pressure",
|
||||
"sensor.keen_home_inc_sv02_612_mp_1_2_77665544_temperature",
|
||||
],
|
||||
"entity_map": {
|
||||
("light", "00:11:22:33:44:55:66:77-1"): {
|
||||
("cover", "00:11:22:33:44:55:66:77-1"): {
|
||||
"channels": ["level", "on_off"],
|
||||
"entity_class": "Light",
|
||||
"entity_id": "light.keen_home_inc_sv02_612_mp_1_2_77665544_level_on_off",
|
||||
"entity_class": "KeenVent",
|
||||
"entity_id": "cover.keen_home_inc_sv02_612_mp_1_2_77665544_level_on_off",
|
||||
},
|
||||
("sensor", "00:11:22:33:44:55:66:77-1-1"): {
|
||||
"channels": ["power"],
|
||||
|
@ -1152,16 +1152,16 @@ DEVICES = [
|
|||
}
|
||||
},
|
||||
"entities": [
|
||||
"light.keen_home_inc_sv02_612_mp_1_3_77665544_level_on_off",
|
||||
"cover.keen_home_inc_sv02_612_mp_1_3_77665544_level_on_off",
|
||||
"sensor.keen_home_inc_sv02_612_mp_1_3_77665544_power",
|
||||
"sensor.keen_home_inc_sv02_612_mp_1_3_77665544_pressure",
|
||||
"sensor.keen_home_inc_sv02_612_mp_1_3_77665544_temperature",
|
||||
],
|
||||
"entity_map": {
|
||||
("light", "00:11:22:33:44:55:66:77-1"): {
|
||||
("cover", "00:11:22:33:44:55:66:77-1"): {
|
||||
"channels": ["level", "on_off"],
|
||||
"entity_class": "Light",
|
||||
"entity_id": "light.keen_home_inc_sv02_612_mp_1_3_77665544_level_on_off",
|
||||
"entity_class": "KeenVent",
|
||||
"entity_id": "cover.keen_home_inc_sv02_612_mp_1_3_77665544_level_on_off",
|
||||
},
|
||||
("sensor", "00:11:22:33:44:55:66:77-1-1"): {
|
||||
"channels": ["power"],
|
||||
|
|
Loading…
Add table
Reference in a new issue