Add Cover Platform to Advantage Air (#41757)

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
This commit is contained in:
Brett 2020-10-15 20:45:05 +10:00 committed by GitHub
parent 21cc23244d
commit a2574a4ed5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 246 additions and 1 deletions

View File

@ -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__)

View 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,
}
}
}
}
)

View 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"