mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 05:07:41 +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
|
||||
|
||||
ADVANTAGE_AIR_SYNC_INTERVAL = 15
|
||||
ADVANTAGE_AIR_PLATFORMS = ["climate"]
|
||||
ADVANTAGE_AIR_PLATFORMS = ["climate", "cover"]
|
||||
|
||||
_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