Bump Advantage Air to 0.4.4 (#91147)

This commit is contained in:
Brett Adams 2023-04-17 10:56:57 +10:00 committed by GitHub
parent 263901841f
commit 8fe900885a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 93 additions and 144 deletions

View File

@ -7,7 +7,6 @@ from advantage_air import ApiError, advantage_air
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_IP_ADDRESS, CONF_PORT, Platform
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
@ -53,30 +52,10 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
update_interval=timedelta(seconds=ADVANTAGE_AIR_SYNC_INTERVAL),
)
def error_handle_factory(func):
"""Return the provided API function wrapped.
Adds an error handler and coordinator refresh.
"""
async def error_handle(param):
try:
if await func(param):
await coordinator.async_refresh()
except ApiError as err:
raise HomeAssistantError(err) from err
return error_handle
await coordinator.async_config_entry_first_refresh()
hass.data.setdefault(DOMAIN, {})
hass.data[DOMAIN][entry.entry_id] = {
"coordinator": coordinator,
"aircon": error_handle_factory(api.aircon.async_set),
"lights": error_handle_factory(api.lights.async_set),
"things": error_handle_factory(api.things.async_set),
}
hass.data[DOMAIN][entry.entry_id] = {"coordinator": coordinator, "api": api}
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)

View File

@ -161,67 +161,41 @@ class AdvantageAirAC(AdvantageAirAcEntity, ClimateEntity):
async def async_turn_on(self) -> None:
"""Set the HVAC State to on."""
await self.aircon(
{
self.ac_key: {
"info": {
"state": ADVANTAGE_AIR_STATE_ON,
}
}
}
)
await self.async_update_ac({"state": ADVANTAGE_AIR_STATE_ON})
async def async_turn_off(self) -> None:
"""Set the HVAC State to off."""
await self.aircon(
await self.async_update_ac(
{
self.ac_key: {
"info": {
"state": ADVANTAGE_AIR_STATE_OFF,
}
}
"state": ADVANTAGE_AIR_STATE_OFF,
}
)
async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
"""Set the HVAC Mode and State."""
if hvac_mode == HVACMode.OFF:
await self.aircon(
{self.ac_key: {"info": {"state": ADVANTAGE_AIR_STATE_OFF}}}
)
await self.async_update_ac({"state": ADVANTAGE_AIR_STATE_OFF})
else:
await self.aircon(
await self.async_update_ac(
{
self.ac_key: {
"info": {
"state": ADVANTAGE_AIR_STATE_ON,
"mode": HASS_HVAC_MODES.get(hvac_mode),
}
}
"state": ADVANTAGE_AIR_STATE_ON,
"mode": HASS_HVAC_MODES.get(hvac_mode),
}
)
async def async_set_fan_mode(self, fan_mode: str) -> None:
"""Set the Fan Mode."""
await self.aircon(
{self.ac_key: {"info": {"fan": HASS_FAN_MODES.get(fan_mode)}}}
)
await self.async_update_ac({"fan": HASS_FAN_MODES.get(fan_mode)})
async def async_set_temperature(self, **kwargs: Any) -> None:
"""Set the Temperature."""
if ATTR_TEMPERATURE in kwargs:
await self.aircon(
{self.ac_key: {"info": {"setTemp": kwargs[ATTR_TEMPERATURE]}}}
)
await self.async_update_ac({"setTemp": kwargs[ATTR_TEMPERATURE]})
if ATTR_TARGET_TEMP_LOW in kwargs and ATTR_TARGET_TEMP_HIGH in kwargs:
await self.aircon(
await self.async_update_ac(
{
self.ac_key: {
"info": {
ADVANTAGE_AIR_COOL_TARGET: kwargs[ATTR_TARGET_TEMP_HIGH],
ADVANTAGE_AIR_HEAT_TARGET: kwargs[ATTR_TARGET_TEMP_LOW],
}
}
ADVANTAGE_AIR_COOL_TARGET: kwargs[ATTR_TARGET_TEMP_HIGH],
ADVANTAGE_AIR_HEAT_TARGET: kwargs[ATTR_TARGET_TEMP_LOW],
}
)
@ -260,23 +234,11 @@ class AdvantageAirZone(AdvantageAirZoneEntity, ClimateEntity):
async def async_turn_on(self) -> None:
"""Set the HVAC State to on."""
await self.aircon(
{
self.ac_key: {
"zones": {self.zone_key: {"state": ADVANTAGE_AIR_STATE_OPEN}}
}
}
)
await self.async_update_zone({"state": ADVANTAGE_AIR_STATE_OPEN})
async def async_turn_off(self) -> None:
"""Set the HVAC State to off."""
await self.aircon(
{
self.ac_key: {
"zones": {self.zone_key: {"state": ADVANTAGE_AIR_STATE_CLOSE}}
}
}
)
await self.async_update_zone({"state": ADVANTAGE_AIR_STATE_CLOSE})
async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
"""Set the HVAC Mode and State."""
@ -288,4 +250,4 @@ class AdvantageAirZone(AdvantageAirZoneEntity, ClimateEntity):
async def async_set_temperature(self, **kwargs: Any) -> None:
"""Set the Temperature."""
temp = kwargs.get(ATTR_TEMPERATURE)
await self.aircon({self.ac_key: {"zones": {self.zone_key: {"setTemp": temp}}}})
await self.async_update_zone({"setTemp": temp})

View File

@ -79,48 +79,24 @@ class AdvantageAirZoneVent(AdvantageAirZoneEntity, CoverEntity):
async def async_open_cover(self, **kwargs: Any) -> None:
"""Fully open zone vent."""
await self.aircon(
{
self.ac_key: {
"zones": {
self.zone_key: {"state": ADVANTAGE_AIR_STATE_OPEN, "value": 100}
}
}
}
await self.async_update_zone(
{"state": ADVANTAGE_AIR_STATE_OPEN, "value": 100},
)
async def async_close_cover(self, **kwargs: Any) -> None:
"""Fully close zone vent."""
await self.aircon(
{
self.ac_key: {
"zones": {self.zone_key: {"state": ADVANTAGE_AIR_STATE_CLOSE}}
}
}
)
await self.async_update_zone({"state": ADVANTAGE_AIR_STATE_CLOSE})
async def async_set_cover_position(self, **kwargs: Any) -> None:
"""Change vent position."""
position = round(kwargs[ATTR_POSITION] / 5) * 5
if position == 0:
await self.aircon(
{
self.ac_key: {
"zones": {self.zone_key: {"state": ADVANTAGE_AIR_STATE_CLOSE}}
}
}
)
await self.async_update_zone({"state": ADVANTAGE_AIR_STATE_CLOSE})
else:
await self.aircon(
await self.async_update_zone(
{
self.ac_key: {
"zones": {
self.zone_key: {
"state": ADVANTAGE_AIR_STATE_OPEN,
"value": position,
}
}
}
"state": ADVANTAGE_AIR_STATE_OPEN,
"value": position,
}
)

View File

@ -1,6 +1,9 @@
"""Advantage Air parent entity class."""
from typing import Any
from advantage_air import ApiError
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.entity import DeviceInfo
from homeassistant.helpers.update_coordinator import CoordinatorEntity
@ -17,6 +20,21 @@ class AdvantageAirEntity(CoordinatorEntity):
super().__init__(instance["coordinator"])
self._attr_unique_id: str = self.coordinator.data["system"]["rid"]
def update_handle_factory(self, func, *keys):
"""Return the provided API function wrapped.
Adds an error handler and coordinator refresh, and presets keys.
"""
async def update_handle(*values):
try:
if await func(*keys, *values):
await self.coordinator.async_refresh()
except ApiError as err:
raise HomeAssistantError(err) from err
return update_handle
class AdvantageAirAcEntity(AdvantageAirEntity):
"""Parent class for Advantage Air AC Entities."""
@ -24,7 +42,7 @@ class AdvantageAirAcEntity(AdvantageAirEntity):
def __init__(self, instance: dict[str, Any], ac_key: str) -> None:
"""Initialize common aspects of an Advantage Air ac entity."""
super().__init__(instance)
self.aircon = instance["aircon"]
self.ac_key: str = ac_key
self._attr_unique_id += f"-{ac_key}"
@ -35,6 +53,9 @@ class AdvantageAirAcEntity(AdvantageAirEntity):
model=self.coordinator.data["system"]["sysType"],
name=self.coordinator.data["aircons"][self.ac_key]["info"]["name"],
)
self.async_update_ac = self.update_handle_factory(
instance["api"].aircon.async_update_ac, self.ac_key
)
@property
def _ac(self) -> dict[str, Any]:
@ -47,8 +68,12 @@ class AdvantageAirZoneEntity(AdvantageAirAcEntity):
def __init__(self, instance: dict[str, Any], ac_key: str, zone_key: str) -> None:
"""Initialize common aspects of an Advantage Air zone entity."""
super().__init__(instance, ac_key)
self.zone_key: str = zone_key
self._attr_unique_id += f"-{zone_key}"
self.async_update_zone = self.update_handle_factory(
instance["api"].aircon.async_update_zone, self.ac_key, self.zone_key
)
@property
def _zone(self) -> dict[str, Any]:
@ -61,7 +86,7 @@ class AdvantageAirThingEntity(AdvantageAirEntity):
def __init__(self, instance: dict[str, Any], thing: dict[str, Any]) -> None:
"""Initialize common aspects of an Advantage Air Things entity."""
super().__init__(instance)
self.set = instance["things"]
self._id = thing["id"]
self._attr_unique_id += f"-{self._id}"
@ -72,6 +97,9 @@ class AdvantageAirThingEntity(AdvantageAirEntity):
model="MyPlace",
name=thing["name"],
)
self.async_update_value = self.update_handle_factory(
instance["api"].things.async_update_value, self._id
)
@property
def _data(self) -> dict:
@ -85,8 +113,8 @@ class AdvantageAirThingEntity(AdvantageAirEntity):
async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn the thing on."""
await self.set({self._id: {"id": self._id, "value": 100}})
await self.async_update_value(True)
async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn the thing off."""
await self.set({self._id: {"id": self._id, "value": 0}})
await self.async_update_value(False)

View File

@ -7,11 +7,7 @@ from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity import DeviceInfo
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from .const import (
ADVANTAGE_AIR_STATE_OFF,
ADVANTAGE_AIR_STATE_ON,
DOMAIN as ADVANTAGE_AIR_DOMAIN,
)
from .const import ADVANTAGE_AIR_STATE_ON, DOMAIN as ADVANTAGE_AIR_DOMAIN
from .entity import AdvantageAirEntity, AdvantageAirThingEntity
@ -48,7 +44,7 @@ class AdvantageAirLight(AdvantageAirEntity, LightEntity):
def __init__(self, instance: dict[str, Any], light: dict[str, Any]) -> None:
"""Initialize an Advantage Air Light."""
super().__init__(instance)
self.set = instance["lights"]
self._id: str = light["id"]
self._attr_unique_id += f"-{self._id}"
self._attr_device_info = DeviceInfo(
@ -58,6 +54,9 @@ class AdvantageAirLight(AdvantageAirEntity, LightEntity):
model=light.get("moduleType"),
name=light["name"],
)
self.async_update_state = self.update_handle_factory(
instance["api"].lights.async_update_state, self._id
)
@property
def _data(self) -> dict[str, Any]:
@ -71,11 +70,11 @@ class AdvantageAirLight(AdvantageAirEntity, LightEntity):
async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn the light on."""
await self.set({self._id: {"id": self._id, "state": ADVANTAGE_AIR_STATE_ON}})
await self.async_update_state(True)
async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn the light off."""
await self.set({self._id: {"id": self._id, "state": ADVANTAGE_AIR_STATE_OFF}})
await self.async_update_state(False)
class AdvantageAirLightDimmable(AdvantageAirLight):
@ -83,6 +82,13 @@ class AdvantageAirLightDimmable(AdvantageAirLight):
_attr_supported_color_modes = {ColorMode.ONOFF, ColorMode.BRIGHTNESS}
def __init__(self, instance: dict[str, Any], light: dict[str, Any]) -> None:
"""Initialize an Advantage Air Dimmable Light."""
super().__init__(instance, light)
self.async_update_value = self.update_handle_factory(
instance["api"].lights.async_update_value, self._id
)
@property
def brightness(self) -> int:
"""Return the brightness of this light between 0..255."""
@ -90,12 +96,9 @@ class AdvantageAirLightDimmable(AdvantageAirLight):
async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn the light on and optionally set the brightness."""
data: dict[str, Any] = {
self._id: {"id": self._id, "state": ADVANTAGE_AIR_STATE_ON}
}
if ATTR_BRIGHTNESS in kwargs:
data[self._id]["value"] = round(kwargs[ATTR_BRIGHTNESS] * 100 / 255)
await self.set(data)
return await self.async_update_value(round(kwargs[ATTR_BRIGHTNESS] / 2.55))
return await self.async_update_state(True)
class AdvantageAirThingLight(AdvantageAirThingEntity, LightEntity):
@ -116,11 +119,4 @@ class AdvantageAirThingLightDimmable(AdvantageAirThingEntity, LightEntity):
async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn the light on by setting the brightness."""
await self.set(
{
self._id: {
"id": self._id,
"value": round(kwargs.get(ATTR_BRIGHTNESS, 255) * 100 / 255),
}
}
)
await self.async_update_value(round(kwargs.get(ATTR_BRIGHTNESS, 255) / 2.55))

View File

@ -7,5 +7,5 @@
"iot_class": "local_polling",
"loggers": ["advantage_air"],
"quality_scale": "platinum",
"requirements": ["advantage_air==0.4.2"]
"requirements": ["advantage_air==0.4.4"]
}

View File

@ -58,6 +58,4 @@ class AdvantageAirMyZone(AdvantageAirAcEntity, SelectEntity):
async def async_select_option(self, option: str) -> None:
"""Set the MyZone."""
await self.aircon(
{self.ac_key: {"info": {"myZone": self._name_to_number[option]}}}
)
await self.async_update_ac({"myZone": self._name_to_number[option]})

View File

@ -88,7 +88,7 @@ class AdvantageAirTimeTo(AdvantageAirAcEntity, SensorEntity):
async def set_time_to(self, **kwargs: Any) -> None:
"""Set the timer value."""
value = min(720, max(0, int(kwargs[ADVANTAGE_AIR_SET_COUNTDOWN_VALUE])))
await self.aircon({self.ac_key: {"info": {self._time_key: value}}})
await self.async_update_ac({self._time_key: value})
class AdvantageAirZoneVent(AdvantageAirZoneEntity, SensorEntity):

View File

@ -54,15 +54,11 @@ class AdvantageAirFreshAir(AdvantageAirAcEntity, SwitchEntity):
async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn fresh air on."""
await self.aircon(
{self.ac_key: {"info": {"freshAirStatus": ADVANTAGE_AIR_STATE_ON}}}
)
await self.async_update_ac({"freshAirStatus": ADVANTAGE_AIR_STATE_ON})
async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn fresh air off."""
await self.aircon(
{self.ac_key: {"info": {"freshAirStatus": ADVANTAGE_AIR_STATE_OFF}}}
)
await self.async_update_ac({"freshAirStatus": ADVANTAGE_AIR_STATE_OFF})
class AdvantageAirRelay(AdvantageAirThingEntity, SwitchEntity):

View File

@ -86,7 +86,7 @@ adext==0.4.2
adguardhome==0.6.1
# homeassistant.components.advantage_air
advantage_air==0.4.2
advantage_air==0.4.4
# homeassistant.components.frontier_silicon
afsapi==0.2.7

View File

@ -76,7 +76,7 @@ adext==0.4.2
adguardhome==0.6.1
# homeassistant.components.advantage_air
advantage_air==0.4.2
advantage_air==0.4.4
# homeassistant.components.frontier_silicon
afsapi==0.2.7

View File

@ -90,6 +90,20 @@ async def test_light(hass: HomeAssistant, aioclient_mock: AiohttpClientMocker) -
assert entry
assert entry.unique_id == f"uniqueid-{light_id}"
await hass.services.async_call(
LIGHT_DOMAIN,
SERVICE_TURN_ON,
{ATTR_ENTITY_ID: [entity_id]},
blocking=True,
)
assert aioclient_mock.mock_calls[-2][0] == "GET"
assert aioclient_mock.mock_calls[-2][1].path == "/setLights"
data = loads(aioclient_mock.mock_calls[-2][1].query["json"]).get(light_id)
assert data["id"] == light_id
assert data["state"] == ADVANTAGE_AIR_STATE_ON
assert aioclient_mock.mock_calls[-1][0] == "GET"
assert aioclient_mock.mock_calls[-1][1].path == "/getSystemData"
await hass.services.async_call(
LIGHT_DOMAIN,
SERVICE_TURN_ON,