mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 13:17:32 +00:00
Add Cover Platform to Advantage Air (#41757)
Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
This commit is contained in:
parent
21cc23244d
commit
a2574a4ed5
@ -13,7 +13,7 @@ from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, Upda
|
|||||||
from .const import ADVANTAGE_AIR_RETRY, DOMAIN
|
from .const import ADVANTAGE_AIR_RETRY, DOMAIN
|
||||||
|
|
||||||
ADVANTAGE_AIR_SYNC_INTERVAL = 15
|
ADVANTAGE_AIR_SYNC_INTERVAL = 15
|
||||||
ADVANTAGE_AIR_PLATFORMS = ["climate"]
|
ADVANTAGE_AIR_PLATFORMS = ["climate", "cover"]
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
132
homeassistant/components/advantage_air/cover.py
Normal file
132
homeassistant/components/advantage_air/cover.py
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
"""Cover platform for Advantage Air integration."""
|
||||||
|
|
||||||
|
from homeassistant.components.cover import (
|
||||||
|
ATTR_POSITION,
|
||||||
|
DEVICE_CLASS_DAMPER,
|
||||||
|
SUPPORT_CLOSE,
|
||||||
|
SUPPORT_OPEN,
|
||||||
|
SUPPORT_SET_POSITION,
|
||||||
|
CoverEntity,
|
||||||
|
)
|
||||||
|
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
||||||
|
|
||||||
|
from .const import ADVANTAGE_AIR_STATE_CLOSE, ADVANTAGE_AIR_STATE_OPEN, DOMAIN
|
||||||
|
|
||||||
|
|
||||||
|
async def async_setup_entry(hass, config_entry, async_add_entities):
|
||||||
|
"""Set up AdvantageAir cover platform."""
|
||||||
|
|
||||||
|
instance = hass.data[DOMAIN][config_entry.entry_id]
|
||||||
|
|
||||||
|
entities = []
|
||||||
|
for ac_key, ac_device in instance["coordinator"].data["aircons"].items():
|
||||||
|
for zone_key, zone in ac_device["zones"].items():
|
||||||
|
# Only add zone vent controls when zone in vent control mode.
|
||||||
|
if zone["type"] == 0:
|
||||||
|
entities.append(AdvantageAirZoneVent(instance, ac_key, zone_key))
|
||||||
|
async_add_entities(entities)
|
||||||
|
|
||||||
|
|
||||||
|
class AdvantageAirZoneVent(CoordinatorEntity, CoverEntity):
|
||||||
|
"""Advantage Air Cover Class."""
|
||||||
|
|
||||||
|
def __init__(self, instance, ac_key, zone_key):
|
||||||
|
"""Initialize the Advantage Air Zone Vent cover entity."""
|
||||||
|
super().__init__(instance["coordinator"])
|
||||||
|
self.async_change = instance["async_change"]
|
||||||
|
self.ac_key = ac_key
|
||||||
|
self.zone_key = zone_key
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _zone(self):
|
||||||
|
return self.coordinator.data["aircons"][self.ac_key]["zones"][self.zone_key]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
"""Return the name."""
|
||||||
|
return f'{self._zone["name"]}'
|
||||||
|
|
||||||
|
@property
|
||||||
|
def unique_id(self):
|
||||||
|
"""Return a unique id."""
|
||||||
|
return f'{self.coordinator.data["system"]["rid"]}-{self.ac_key}-{self.zone_key}'
|
||||||
|
|
||||||
|
@property
|
||||||
|
def device_class(self):
|
||||||
|
"""Return the device class of the vent."""
|
||||||
|
return DEVICE_CLASS_DAMPER
|
||||||
|
|
||||||
|
@property
|
||||||
|
def supported_features(self):
|
||||||
|
"""Return the supported features."""
|
||||||
|
return SUPPORT_OPEN | SUPPORT_CLOSE | SUPPORT_SET_POSITION
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_closed(self):
|
||||||
|
"""Return if vent is fully closed."""
|
||||||
|
return self._zone["state"] == ADVANTAGE_AIR_STATE_CLOSE
|
||||||
|
|
||||||
|
@property
|
||||||
|
def current_cover_position(self):
|
||||||
|
"""Return vents current position as a percentage."""
|
||||||
|
if self._zone["state"] == ADVANTAGE_AIR_STATE_OPEN:
|
||||||
|
return self._zone["value"]
|
||||||
|
return 0
|
||||||
|
|
||||||
|
@property
|
||||||
|
def device_info(self):
|
||||||
|
"""Return parent device information."""
|
||||||
|
return {
|
||||||
|
"identifiers": {(DOMAIN, self.coordinator.data["system"]["rid"])},
|
||||||
|
"name": self.coordinator.data["system"]["name"],
|
||||||
|
"manufacturer": "Advantage Air",
|
||||||
|
"model": self.coordinator.data["system"]["sysType"],
|
||||||
|
"sw_version": self.coordinator.data["system"]["myAppRev"],
|
||||||
|
}
|
||||||
|
|
||||||
|
async def async_open_cover(self, **kwargs):
|
||||||
|
"""Fully open zone vent."""
|
||||||
|
await self.async_change(
|
||||||
|
{
|
||||||
|
self.ac_key: {
|
||||||
|
"zones": {
|
||||||
|
self.zone_key: {"state": ADVANTAGE_AIR_STATE_OPEN, "value": 100}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
async def async_close_cover(self, **kwargs):
|
||||||
|
"""Fully close zone vent."""
|
||||||
|
await self.async_change(
|
||||||
|
{
|
||||||
|
self.ac_key: {
|
||||||
|
"zones": {self.zone_key: {"state": ADVANTAGE_AIR_STATE_CLOSE}}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
async def async_set_cover_position(self, **kwargs):
|
||||||
|
"""Change vent position."""
|
||||||
|
position = round(kwargs[ATTR_POSITION] / 5) * 5
|
||||||
|
if position == 0:
|
||||||
|
await self.async_change(
|
||||||
|
{
|
||||||
|
self.ac_key: {
|
||||||
|
"zones": {self.zone_key: {"state": ADVANTAGE_AIR_STATE_CLOSE}}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
await self.async_change(
|
||||||
|
{
|
||||||
|
self.ac_key: {
|
||||||
|
"zones": {
|
||||||
|
self.zone_key: {
|
||||||
|
"state": ADVANTAGE_AIR_STATE_OPEN,
|
||||||
|
"value": position,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
113
tests/components/advantage_air/test_cover.py
Normal file
113
tests/components/advantage_air/test_cover.py
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
"""Test the Advantage Air Cover Platform."""
|
||||||
|
|
||||||
|
from json import loads
|
||||||
|
|
||||||
|
from homeassistant.components.advantage_air.const import (
|
||||||
|
ADVANTAGE_AIR_STATE_CLOSE,
|
||||||
|
ADVANTAGE_AIR_STATE_OPEN,
|
||||||
|
)
|
||||||
|
from homeassistant.components.cover import (
|
||||||
|
ATTR_POSITION,
|
||||||
|
DEVICE_CLASS_DAMPER,
|
||||||
|
DOMAIN as COVER_DOMAIN,
|
||||||
|
SERVICE_CLOSE_COVER,
|
||||||
|
SERVICE_OPEN_COVER,
|
||||||
|
SERVICE_SET_COVER_POSITION,
|
||||||
|
)
|
||||||
|
from homeassistant.const import ATTR_ENTITY_ID, STATE_OPEN
|
||||||
|
|
||||||
|
from tests.components.advantage_air import (
|
||||||
|
TEST_SET_RESPONSE,
|
||||||
|
TEST_SET_URL,
|
||||||
|
TEST_SYSTEM_DATA,
|
||||||
|
TEST_SYSTEM_URL,
|
||||||
|
add_mock_config,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_cover_async_setup_entry(hass, aioclient_mock):
|
||||||
|
"""Test climate setup without sensors."""
|
||||||
|
|
||||||
|
aioclient_mock.get(
|
||||||
|
TEST_SYSTEM_URL,
|
||||||
|
text=TEST_SYSTEM_DATA,
|
||||||
|
)
|
||||||
|
aioclient_mock.get(
|
||||||
|
TEST_SET_URL,
|
||||||
|
text=TEST_SET_RESPONSE,
|
||||||
|
)
|
||||||
|
|
||||||
|
await add_mock_config(hass)
|
||||||
|
|
||||||
|
registry = await hass.helpers.entity_registry.async_get_registry()
|
||||||
|
|
||||||
|
assert len(aioclient_mock.mock_calls) == 1
|
||||||
|
|
||||||
|
# Test Cover Zone Entity
|
||||||
|
entity_id = "cover.zone_open_without_sensor"
|
||||||
|
state = hass.states.get(entity_id)
|
||||||
|
assert state
|
||||||
|
assert state.state == STATE_OPEN
|
||||||
|
assert state.attributes.get("device_class") == DEVICE_CLASS_DAMPER
|
||||||
|
assert state.attributes.get("current_position") == 100
|
||||||
|
|
||||||
|
entry = registry.async_get(entity_id)
|
||||||
|
assert entry
|
||||||
|
assert entry.unique_id == "uniqueid-ac2-z01"
|
||||||
|
|
||||||
|
await hass.services.async_call(
|
||||||
|
COVER_DOMAIN,
|
||||||
|
SERVICE_CLOSE_COVER,
|
||||||
|
{ATTR_ENTITY_ID: [entity_id]},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
assert len(aioclient_mock.mock_calls) == 3
|
||||||
|
assert aioclient_mock.mock_calls[-2][0] == "GET"
|
||||||
|
assert aioclient_mock.mock_calls[-2][1].path == "/setAircon"
|
||||||
|
data = loads(aioclient_mock.mock_calls[-2][1].query["json"])
|
||||||
|
assert data["ac2"]["zones"]["z01"]["state"] == ADVANTAGE_AIR_STATE_CLOSE
|
||||||
|
assert aioclient_mock.mock_calls[-1][0] == "GET"
|
||||||
|
assert aioclient_mock.mock_calls[-1][1].path == "/getSystemData"
|
||||||
|
|
||||||
|
await hass.services.async_call(
|
||||||
|
COVER_DOMAIN,
|
||||||
|
SERVICE_OPEN_COVER,
|
||||||
|
{ATTR_ENTITY_ID: [entity_id]},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
assert len(aioclient_mock.mock_calls) == 5
|
||||||
|
assert aioclient_mock.mock_calls[-2][0] == "GET"
|
||||||
|
assert aioclient_mock.mock_calls[-2][1].path == "/setAircon"
|
||||||
|
data = loads(aioclient_mock.mock_calls[-2][1].query["json"])
|
||||||
|
assert data["ac2"]["zones"]["z01"]["state"] == ADVANTAGE_AIR_STATE_OPEN
|
||||||
|
assert data["ac2"]["zones"]["z01"]["value"] == 100
|
||||||
|
assert aioclient_mock.mock_calls[-1][0] == "GET"
|
||||||
|
assert aioclient_mock.mock_calls[-1][1].path == "/getSystemData"
|
||||||
|
|
||||||
|
await hass.services.async_call(
|
||||||
|
COVER_DOMAIN,
|
||||||
|
SERVICE_SET_COVER_POSITION,
|
||||||
|
{ATTR_ENTITY_ID: [entity_id], ATTR_POSITION: 50},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
assert len(aioclient_mock.mock_calls) == 7
|
||||||
|
assert aioclient_mock.mock_calls[-2][0] == "GET"
|
||||||
|
assert aioclient_mock.mock_calls[-2][1].path == "/setAircon"
|
||||||
|
data = loads(aioclient_mock.mock_calls[-2][1].query["json"])
|
||||||
|
assert data["ac2"]["zones"]["z01"]["value"] == 50
|
||||||
|
assert aioclient_mock.mock_calls[-1][0] == "GET"
|
||||||
|
assert aioclient_mock.mock_calls[-1][1].path == "/getSystemData"
|
||||||
|
|
||||||
|
await hass.services.async_call(
|
||||||
|
COVER_DOMAIN,
|
||||||
|
SERVICE_SET_COVER_POSITION,
|
||||||
|
{ATTR_ENTITY_ID: [entity_id], ATTR_POSITION: 0},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
assert len(aioclient_mock.mock_calls) == 9
|
||||||
|
assert aioclient_mock.mock_calls[-2][0] == "GET"
|
||||||
|
assert aioclient_mock.mock_calls[-2][1].path == "/setAircon"
|
||||||
|
data = loads(aioclient_mock.mock_calls[-2][1].query["json"])
|
||||||
|
assert data["ac2"]["zones"]["z01"]["state"] == ADVANTAGE_AIR_STATE_CLOSE
|
||||||
|
assert aioclient_mock.mock_calls[-1][0] == "GET"
|
||||||
|
assert aioclient_mock.mock_calls[-1][1].path == "/getSystemData"
|
Loading…
x
Reference in New Issue
Block a user