mirror of
https://github.com/home-assistant/core.git
synced 2025-07-09 22:37:11 +00:00
Code Quality Improvements for Advantage Air (#77695)
Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>
This commit is contained in:
parent
4fbf44cced
commit
fa7f04c34b
@ -7,6 +7,7 @@ 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
|
||||
|
||||
@ -60,7 +61,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
if await func(param):
|
||||
await coordinator.async_refresh()
|
||||
except ApiError as err:
|
||||
_LOGGER.warning(err)
|
||||
raise HomeAssistantError(err) from err
|
||||
|
||||
return error_handle
|
||||
|
||||
@ -69,8 +70,8 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
hass.data.setdefault(DOMAIN, {})
|
||||
hass.data[DOMAIN][entry.entry_id] = {
|
||||
"coordinator": coordinator,
|
||||
"async_change": error_handle_factory(api.aircon.async_set),
|
||||
"async_set_light": error_handle_factory(api.lights.async_set),
|
||||
"aircon": error_handle_factory(api.aircon.async_set),
|
||||
"lights": error_handle_factory(api.lights.async_set),
|
||||
}
|
||||
|
||||
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
|
||||
|
@ -1,6 +1,8 @@
|
||||
"""Binary Sensor platform for Advantage Air integration."""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
from homeassistant.components.binary_sensor import (
|
||||
BinarySensorDeviceClass,
|
||||
BinarySensorEntity,
|
||||
@ -26,15 +28,16 @@ async def async_setup_entry(
|
||||
instance = hass.data[ADVANTAGE_AIR_DOMAIN][config_entry.entry_id]
|
||||
|
||||
entities: list[BinarySensorEntity] = []
|
||||
for ac_key, ac_device in instance["coordinator"].data["aircons"].items():
|
||||
entities.append(AdvantageAirFilter(instance, ac_key))
|
||||
for zone_key, zone in ac_device["zones"].items():
|
||||
# Only add motion sensor when motion is enabled
|
||||
if zone["motionConfig"] >= 2:
|
||||
entities.append(AdvantageAirZoneMotion(instance, ac_key, zone_key))
|
||||
# Only add MyZone if it is available
|
||||
if zone["type"] != 0:
|
||||
entities.append(AdvantageAirZoneMyZone(instance, ac_key, zone_key))
|
||||
if aircons := instance["coordinator"].data.get("aircons"):
|
||||
for ac_key, ac_device in aircons.items():
|
||||
entities.append(AdvantageAirFilter(instance, ac_key))
|
||||
for zone_key, zone in ac_device["zones"].items():
|
||||
# Only add motion sensor when motion is enabled
|
||||
if zone["motionConfig"] >= 2:
|
||||
entities.append(AdvantageAirZoneMotion(instance, ac_key, zone_key))
|
||||
# Only add MyZone if it is available
|
||||
if zone["type"] != 0:
|
||||
entities.append(AdvantageAirZoneMyZone(instance, ac_key, zone_key))
|
||||
async_add_entities(entities)
|
||||
|
||||
|
||||
@ -45,13 +48,13 @@ class AdvantageAirFilter(AdvantageAirAcEntity, BinarySensorEntity):
|
||||
_attr_entity_category = EntityCategory.DIAGNOSTIC
|
||||
_attr_name = "Filter"
|
||||
|
||||
def __init__(self, instance, ac_key):
|
||||
def __init__(self, instance: dict[str, Any], ac_key: str) -> None:
|
||||
"""Initialize an Advantage Air Filter sensor."""
|
||||
super().__init__(instance, ac_key)
|
||||
self._attr_unique_id += "-filter"
|
||||
|
||||
@property
|
||||
def is_on(self):
|
||||
def is_on(self) -> bool:
|
||||
"""Return if filter needs cleaning."""
|
||||
return self._ac["filterCleanStatus"]
|
||||
|
||||
@ -61,14 +64,14 @@ class AdvantageAirZoneMotion(AdvantageAirZoneEntity, BinarySensorEntity):
|
||||
|
||||
_attr_device_class = BinarySensorDeviceClass.MOTION
|
||||
|
||||
def __init__(self, instance, ac_key, zone_key):
|
||||
def __init__(self, instance: dict[str, Any], ac_key: str, zone_key: str) -> None:
|
||||
"""Initialize an Advantage Air Zone Motion sensor."""
|
||||
super().__init__(instance, ac_key, zone_key)
|
||||
self._attr_name = f'{self._zone["name"]} motion'
|
||||
self._attr_unique_id += "-motion"
|
||||
|
||||
@property
|
||||
def is_on(self):
|
||||
def is_on(self) -> bool:
|
||||
"""Return if motion is detect."""
|
||||
return self._zone["motion"] == 20
|
||||
|
||||
@ -79,13 +82,13 @@ class AdvantageAirZoneMyZone(AdvantageAirZoneEntity, BinarySensorEntity):
|
||||
_attr_entity_registry_enabled_default = False
|
||||
_attr_entity_category = EntityCategory.DIAGNOSTIC
|
||||
|
||||
def __init__(self, instance, ac_key, zone_key):
|
||||
def __init__(self, instance: dict[str, Any], ac_key: str, zone_key: str) -> None:
|
||||
"""Initialize an Advantage Air Zone MyZone sensor."""
|
||||
super().__init__(instance, ac_key, zone_key)
|
||||
self._attr_name = f'{self._zone["name"]} myZone'
|
||||
self._attr_unique_id += "-myzone"
|
||||
|
||||
@property
|
||||
def is_on(self):
|
||||
def is_on(self) -> bool:
|
||||
"""Return if this zone is the myZone."""
|
||||
return self._zone["number"] == self._ac["myZone"]
|
||||
|
@ -70,12 +70,13 @@ async def async_setup_entry(
|
||||
instance = hass.data[ADVANTAGE_AIR_DOMAIN][config_entry.entry_id]
|
||||
|
||||
entities: list[ClimateEntity] = []
|
||||
for ac_key, ac_device in instance["coordinator"].data["aircons"].items():
|
||||
entities.append(AdvantageAirAC(instance, ac_key))
|
||||
for zone_key, zone in ac_device["zones"].items():
|
||||
# Only add zone climate control when zone is in temperature control
|
||||
if zone["type"] != 0:
|
||||
entities.append(AdvantageAirZone(instance, ac_key, zone_key))
|
||||
if aircons := instance["coordinator"].data.get("aircons"):
|
||||
for ac_key, ac_device in aircons.items():
|
||||
entities.append(AdvantageAirAC(instance, ac_key))
|
||||
for zone_key, zone in ac_device["zones"].items():
|
||||
# Only add zone climate control when zone is in temperature control
|
||||
if zone["type"] != 0:
|
||||
entities.append(AdvantageAirZone(instance, ac_key, zone_key))
|
||||
async_add_entities(entities)
|
||||
|
||||
|
||||
@ -92,37 +93,37 @@ class AdvantageAirAC(AdvantageAirAcEntity, ClimateEntity):
|
||||
ClimateEntityFeature.TARGET_TEMPERATURE | ClimateEntityFeature.FAN_MODE
|
||||
)
|
||||
|
||||
def __init__(self, instance, ac_key):
|
||||
def __init__(self, instance: dict[str, Any], ac_key: str) -> None:
|
||||
"""Initialize an AdvantageAir AC unit."""
|
||||
super().__init__(instance, ac_key)
|
||||
if self._ac.get("myAutoModeEnabled"):
|
||||
self._attr_hvac_modes = AC_HVAC_MODES + [HVACMode.AUTO]
|
||||
|
||||
@property
|
||||
def target_temperature(self):
|
||||
def target_temperature(self) -> float:
|
||||
"""Return the current target temperature."""
|
||||
return self._ac["setTemp"]
|
||||
|
||||
@property
|
||||
def hvac_mode(self):
|
||||
def hvac_mode(self) -> HVACMode | None:
|
||||
"""Return the current HVAC modes."""
|
||||
if self._ac["state"] == ADVANTAGE_AIR_STATE_ON:
|
||||
return ADVANTAGE_AIR_HVAC_MODES.get(self._ac["mode"])
|
||||
return HVACMode.OFF
|
||||
|
||||
@property
|
||||
def fan_mode(self):
|
||||
def fan_mode(self) -> str | None:
|
||||
"""Return the current fan modes."""
|
||||
return ADVANTAGE_AIR_FAN_MODES.get(self._ac["fan"])
|
||||
|
||||
async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
|
||||
"""Set the HVAC Mode and State."""
|
||||
if hvac_mode == HVACMode.OFF:
|
||||
await self.async_change(
|
||||
await self.aircon(
|
||||
{self.ac_key: {"info": {"state": ADVANTAGE_AIR_STATE_OFF}}}
|
||||
)
|
||||
else:
|
||||
await self.async_change(
|
||||
await self.aircon(
|
||||
{
|
||||
self.ac_key: {
|
||||
"info": {
|
||||
@ -135,14 +136,14 @@ class AdvantageAirAC(AdvantageAirAcEntity, ClimateEntity):
|
||||
|
||||
async def async_set_fan_mode(self, fan_mode: str) -> None:
|
||||
"""Set the Fan Mode."""
|
||||
await self.async_change(
|
||||
await self.aircon(
|
||||
{self.ac_key: {"info": {"fan": HASS_FAN_MODES.get(fan_mode)}}}
|
||||
)
|
||||
|
||||
async def async_set_temperature(self, **kwargs: Any) -> None:
|
||||
"""Set the Temperature."""
|
||||
temp = kwargs.get(ATTR_TEMPERATURE)
|
||||
await self.async_change({self.ac_key: {"info": {"setTemp": temp}}})
|
||||
await self.aircon({self.ac_key: {"info": {"setTemp": temp}}})
|
||||
|
||||
|
||||
class AdvantageAirZone(AdvantageAirZoneEntity, ClimateEntity):
|
||||
@ -155,7 +156,7 @@ class AdvantageAirZone(AdvantageAirZoneEntity, ClimateEntity):
|
||||
_attr_hvac_modes = ZONE_HVAC_MODES
|
||||
_attr_supported_features = ClimateEntityFeature.TARGET_TEMPERATURE
|
||||
|
||||
def __init__(self, instance, ac_key, zone_key):
|
||||
def __init__(self, instance: dict[str, Any], ac_key: str, zone_key: str) -> None:
|
||||
"""Initialize an AdvantageAir Zone control."""
|
||||
super().__init__(instance, ac_key, zone_key)
|
||||
self._attr_name = self._zone["name"]
|
||||
@ -164,26 +165,26 @@ class AdvantageAirZone(AdvantageAirZoneEntity, ClimateEntity):
|
||||
)
|
||||
|
||||
@property
|
||||
def hvac_mode(self):
|
||||
def hvac_mode(self) -> HVACMode:
|
||||
"""Return the current state as HVAC mode."""
|
||||
if self._zone["state"] == ADVANTAGE_AIR_STATE_OPEN:
|
||||
return HVACMode.HEAT_COOL
|
||||
return HVACMode.OFF
|
||||
|
||||
@property
|
||||
def current_temperature(self):
|
||||
def current_temperature(self) -> float:
|
||||
"""Return the current temperature."""
|
||||
return self._zone["measuredTemp"]
|
||||
|
||||
@property
|
||||
def target_temperature(self):
|
||||
def target_temperature(self) -> float:
|
||||
"""Return the target temperature."""
|
||||
return self._zone["setTemp"]
|
||||
|
||||
async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
|
||||
"""Set the HVAC Mode and State."""
|
||||
if hvac_mode == HVACMode.OFF:
|
||||
await self.async_change(
|
||||
await self.aircon(
|
||||
{
|
||||
self.ac_key: {
|
||||
"zones": {self.zone_key: {"state": ADVANTAGE_AIR_STATE_CLOSE}}
|
||||
@ -191,7 +192,7 @@ class AdvantageAirZone(AdvantageAirZoneEntity, ClimateEntity):
|
||||
}
|
||||
)
|
||||
else:
|
||||
await self.async_change(
|
||||
await self.aircon(
|
||||
{
|
||||
self.ac_key: {
|
||||
"zones": {self.zone_key: {"state": ADVANTAGE_AIR_STATE_OPEN}}
|
||||
@ -202,6 +203,4 @@ class AdvantageAirZone(AdvantageAirZoneEntity, ClimateEntity):
|
||||
async def async_set_temperature(self, **kwargs: Any) -> None:
|
||||
"""Set the Temperature."""
|
||||
temp = kwargs.get(ATTR_TEMPERATURE)
|
||||
await self.async_change(
|
||||
{self.ac_key: {"zones": {self.zone_key: {"setTemp": temp}}}}
|
||||
)
|
||||
await self.aircon({self.ac_key: {"zones": {self.zone_key: {"setTemp": temp}}}})
|
||||
|
@ -1,9 +1,14 @@
|
||||
"""Config Flow for Advantage Air integration."""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
from advantage_air import ApiError, advantage_air
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant import config_entries
|
||||
from homeassistant.const import CONF_IP_ADDRESS, CONF_PORT
|
||||
from homeassistant.data_entry_flow import FlowResult
|
||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
|
||||
from .const import ADVANTAGE_AIR_RETRY, DOMAIN
|
||||
@ -25,7 +30,9 @@ class AdvantageAirConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
|
||||
DOMAIN = DOMAIN
|
||||
|
||||
async def async_step_user(self, user_input=None):
|
||||
async def async_step_user(
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
) -> FlowResult:
|
||||
"""Get configuration from the user."""
|
||||
errors = {}
|
||||
if user_input:
|
||||
|
@ -30,12 +30,13 @@ async def async_setup_entry(
|
||||
|
||||
instance = hass.data[ADVANTAGE_AIR_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))
|
||||
entities: list[CoverEntity] = []
|
||||
if aircons := instance["coordinator"].data.get("aircons"):
|
||||
for ac_key, ac_device in 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)
|
||||
|
||||
|
||||
@ -49,7 +50,7 @@ class AdvantageAirZoneVent(AdvantageAirZoneEntity, CoverEntity):
|
||||
| CoverEntityFeature.SET_POSITION
|
||||
)
|
||||
|
||||
def __init__(self, instance, ac_key, zone_key):
|
||||
def __init__(self, instance: dict[str, Any], ac_key: str, zone_key: str) -> None:
|
||||
"""Initialize an Advantage Air Zone Vent."""
|
||||
super().__init__(instance, ac_key, zone_key)
|
||||
self._attr_name = self._zone["name"]
|
||||
@ -68,7 +69,7 @@ class AdvantageAirZoneVent(AdvantageAirZoneEntity, CoverEntity):
|
||||
|
||||
async def async_open_cover(self, **kwargs: Any) -> None:
|
||||
"""Fully open zone vent."""
|
||||
await self.async_change(
|
||||
await self.aircon(
|
||||
{
|
||||
self.ac_key: {
|
||||
"zones": {
|
||||
@ -80,7 +81,7 @@ class AdvantageAirZoneVent(AdvantageAirZoneEntity, CoverEntity):
|
||||
|
||||
async def async_close_cover(self, **kwargs: Any) -> None:
|
||||
"""Fully close zone vent."""
|
||||
await self.async_change(
|
||||
await self.aircon(
|
||||
{
|
||||
self.ac_key: {
|
||||
"zones": {self.zone_key: {"state": ADVANTAGE_AIR_STATE_CLOSE}}
|
||||
@ -92,7 +93,7 @@ class AdvantageAirZoneVent(AdvantageAirZoneEntity, CoverEntity):
|
||||
"""Change vent position."""
|
||||
position = round(kwargs[ATTR_POSITION] / 5) * 5
|
||||
if position == 0:
|
||||
await self.async_change(
|
||||
await self.aircon(
|
||||
{
|
||||
self.ac_key: {
|
||||
"zones": {self.zone_key: {"state": ADVANTAGE_AIR_STATE_CLOSE}}
|
||||
@ -100,7 +101,7 @@ class AdvantageAirZoneVent(AdvantageAirZoneEntity, CoverEntity):
|
||||
}
|
||||
)
|
||||
else:
|
||||
await self.async_change(
|
||||
await self.aircon(
|
||||
{
|
||||
self.ac_key: {
|
||||
"zones": {
|
||||
|
@ -1,5 +1,7 @@
|
||||
"""Advantage Air parent entity class."""
|
||||
|
||||
from typing import Any
|
||||
|
||||
from homeassistant.helpers.entity import DeviceInfo
|
||||
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
||||
|
||||
@ -11,20 +13,20 @@ class AdvantageAirEntity(CoordinatorEntity):
|
||||
|
||||
_attr_has_entity_name = True
|
||||
|
||||
def __init__(self, instance):
|
||||
def __init__(self, instance: dict[str, Any]) -> None:
|
||||
"""Initialize common aspects of an Advantage Air entity."""
|
||||
super().__init__(instance["coordinator"])
|
||||
self._attr_unique_id = self.coordinator.data["system"]["rid"]
|
||||
self._attr_unique_id: str = self.coordinator.data["system"]["rid"]
|
||||
|
||||
|
||||
class AdvantageAirAcEntity(AdvantageAirEntity):
|
||||
"""Parent class for Advantage Air AC Entities."""
|
||||
|
||||
def __init__(self, instance, ac_key):
|
||||
def __init__(self, instance: dict[str, Any], ac_key: str) -> None:
|
||||
"""Initialize common aspects of an Advantage Air ac entity."""
|
||||
super().__init__(instance)
|
||||
self.async_change = instance["async_change"]
|
||||
self.ac_key = ac_key
|
||||
self.aircon = instance["aircon"]
|
||||
self.ac_key: str = ac_key
|
||||
self._attr_unique_id += f"-{ac_key}"
|
||||
|
||||
self._attr_device_info = DeviceInfo(
|
||||
@ -36,19 +38,19 @@ class AdvantageAirAcEntity(AdvantageAirEntity):
|
||||
)
|
||||
|
||||
@property
|
||||
def _ac(self):
|
||||
def _ac(self) -> dict[str, Any]:
|
||||
return self.coordinator.data["aircons"][self.ac_key]["info"]
|
||||
|
||||
|
||||
class AdvantageAirZoneEntity(AdvantageAirAcEntity):
|
||||
"""Parent class for Advantage Air Zone Entities."""
|
||||
|
||||
def __init__(self, instance, ac_key, zone_key):
|
||||
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 = zone_key
|
||||
self.zone_key: str = zone_key
|
||||
self._attr_unique_id += f"-{zone_key}"
|
||||
|
||||
@property
|
||||
def _zone(self):
|
||||
def _zone(self) -> dict[str, Any]:
|
||||
return self.coordinator.data["aircons"][self.ac_key]["zones"][self.zone_key]
|
||||
|
@ -24,9 +24,9 @@ async def async_setup_entry(
|
||||
|
||||
instance = hass.data[ADVANTAGE_AIR_DOMAIN][config_entry.entry_id]
|
||||
|
||||
entities = []
|
||||
if "myLights" in instance["coordinator"].data:
|
||||
for light in instance["coordinator"].data["myLights"]["lights"].values():
|
||||
entities: list[LightEntity] = []
|
||||
if my_lights := instance["coordinator"].data.get("myLights"):
|
||||
for light in my_lights["lights"].values():
|
||||
if light.get("relay"):
|
||||
entities.append(AdvantageAirLight(instance, light))
|
||||
else:
|
||||
@ -39,11 +39,11 @@ class AdvantageAirLight(AdvantageAirEntity, LightEntity):
|
||||
|
||||
_attr_supported_color_modes = {ColorMode.ONOFF}
|
||||
|
||||
def __init__(self, instance, light):
|
||||
def __init__(self, instance: dict[str, Any], light: dict[str, Any]) -> None:
|
||||
"""Initialize an Advantage Air Light."""
|
||||
super().__init__(instance)
|
||||
self.async_set_light = instance["async_set_light"]
|
||||
self._id = light["id"]
|
||||
self.lights = instance["lights"]
|
||||
self._id: str = light["id"]
|
||||
self._attr_unique_id += f"-{self._id}"
|
||||
self._attr_device_info = DeviceInfo(
|
||||
identifiers={(ADVANTAGE_AIR_DOMAIN, self._attr_unique_id)},
|
||||
@ -54,7 +54,7 @@ class AdvantageAirLight(AdvantageAirEntity, LightEntity):
|
||||
)
|
||||
|
||||
@property
|
||||
def _light(self):
|
||||
def _light(self) -> dict[str, Any]:
|
||||
"""Return the light object."""
|
||||
return self.coordinator.data["myLights"]["lights"][self._id]
|
||||
|
||||
@ -65,11 +65,11 @@ class AdvantageAirLight(AdvantageAirEntity, LightEntity):
|
||||
|
||||
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||
"""Turn the light on."""
|
||||
await self.async_set_light({"id": self._id, "state": ADVANTAGE_AIR_STATE_ON})
|
||||
await self.lights({"id": self._id, "state": ADVANTAGE_AIR_STATE_ON})
|
||||
|
||||
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||
"""Turn the light off."""
|
||||
await self.async_set_light({"id": self._id, "state": ADVANTAGE_AIR_STATE_OFF})
|
||||
await self.lights({"id": self._id, "state": ADVANTAGE_AIR_STATE_OFF})
|
||||
|
||||
|
||||
class AdvantageAirLightDimmable(AdvantageAirLight):
|
||||
@ -84,7 +84,7 @@ class AdvantageAirLightDimmable(AdvantageAirLight):
|
||||
|
||||
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||
"""Turn the light on and optionally set the brightness."""
|
||||
data = {"id": self._id, "state": ADVANTAGE_AIR_STATE_ON}
|
||||
data: dict[str, Any] = {"id": self._id, "state": ADVANTAGE_AIR_STATE_ON}
|
||||
if ATTR_BRIGHTNESS in kwargs:
|
||||
data["value"] = round(kwargs[ATTR_BRIGHTNESS] * 100 / 255)
|
||||
await self.async_set_light(data)
|
||||
await self.lights(data)
|
||||
|
@ -1,4 +1,6 @@
|
||||
"""Select platform for Advantage Air integration."""
|
||||
from typing import Any
|
||||
|
||||
from homeassistant.components.select import SelectEntity
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
@ -19,9 +21,10 @@ async def async_setup_entry(
|
||||
|
||||
instance = hass.data[ADVANTAGE_AIR_DOMAIN][config_entry.entry_id]
|
||||
|
||||
entities = []
|
||||
for ac_key in instance["coordinator"].data["aircons"]:
|
||||
entities.append(AdvantageAirMyZone(instance, ac_key))
|
||||
entities: list[SelectEntity] = []
|
||||
if aircons := instance["coordinator"].data.get("aircons"):
|
||||
for ac_key in aircons:
|
||||
entities.append(AdvantageAirMyZone(instance, ac_key))
|
||||
async_add_entities(entities)
|
||||
|
||||
|
||||
@ -31,7 +34,7 @@ class AdvantageAirMyZone(AdvantageAirAcEntity, SelectEntity):
|
||||
_attr_icon = "mdi:home-thermometer"
|
||||
_attr_name = "MyZone"
|
||||
|
||||
def __init__(self, instance, ac_key):
|
||||
def __init__(self, instance: dict[str, Any], ac_key: str) -> None:
|
||||
"""Initialize an Advantage Air MyZone control."""
|
||||
super().__init__(instance, ac_key)
|
||||
self._attr_unique_id += "-myzone"
|
||||
@ -52,6 +55,6 @@ class AdvantageAirMyZone(AdvantageAirAcEntity, SelectEntity):
|
||||
|
||||
async def async_select_option(self, option: str) -> None:
|
||||
"""Set the MyZone."""
|
||||
await self.async_change(
|
||||
await self.aircon(
|
||||
{self.ac_key: {"info": {"myZone": self._name_to_number[option]}}}
|
||||
)
|
||||
|
@ -1,6 +1,9 @@
|
||||
"""Sensor platform for Advantage Air integration."""
|
||||
from __future__ import annotations
|
||||
|
||||
from decimal import Decimal
|
||||
from typing import Any
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.sensor import (
|
||||
@ -35,17 +38,18 @@ async def async_setup_entry(
|
||||
instance = hass.data[ADVANTAGE_AIR_DOMAIN][config_entry.entry_id]
|
||||
|
||||
entities: list[SensorEntity] = []
|
||||
for ac_key, ac_device in instance["coordinator"].data["aircons"].items():
|
||||
entities.append(AdvantageAirTimeTo(instance, ac_key, "On"))
|
||||
entities.append(AdvantageAirTimeTo(instance, ac_key, "Off"))
|
||||
for zone_key, zone in ac_device["zones"].items():
|
||||
# Only show damper and temp sensors when zone is in temperature control
|
||||
if zone["type"] != 0:
|
||||
entities.append(AdvantageAirZoneVent(instance, ac_key, zone_key))
|
||||
entities.append(AdvantageAirZoneTemp(instance, ac_key, zone_key))
|
||||
# Only show wireless signal strength sensors when using wireless sensors
|
||||
if zone["rssi"] > 0:
|
||||
entities.append(AdvantageAirZoneSignal(instance, ac_key, zone_key))
|
||||
if aircons := instance["coordinator"].data.get("aircons"):
|
||||
for ac_key, ac_device in aircons.items():
|
||||
entities.append(AdvantageAirTimeTo(instance, ac_key, "On"))
|
||||
entities.append(AdvantageAirTimeTo(instance, ac_key, "Off"))
|
||||
for zone_key, zone in ac_device["zones"].items():
|
||||
# Only show damper and temp sensors when zone is in temperature control
|
||||
if zone["type"] != 0:
|
||||
entities.append(AdvantageAirZoneVent(instance, ac_key, zone_key))
|
||||
entities.append(AdvantageAirZoneTemp(instance, ac_key, zone_key))
|
||||
# Only show wireless signal strength sensors when using wireless sensors
|
||||
if zone["rssi"] > 0:
|
||||
entities.append(AdvantageAirZoneSignal(instance, ac_key, zone_key))
|
||||
async_add_entities(entities)
|
||||
|
||||
platform = entity_platform.async_get_current_platform()
|
||||
@ -62,7 +66,7 @@ class AdvantageAirTimeTo(AdvantageAirAcEntity, SensorEntity):
|
||||
_attr_native_unit_of_measurement = ADVANTAGE_AIR_SET_COUNTDOWN_UNIT
|
||||
_attr_entity_category = EntityCategory.DIAGNOSTIC
|
||||
|
||||
def __init__(self, instance, ac_key, action):
|
||||
def __init__(self, instance: dict[str, Any], ac_key: str, action: str) -> None:
|
||||
"""Initialize the Advantage Air timer control."""
|
||||
super().__init__(instance, ac_key)
|
||||
self.action = action
|
||||
@ -71,21 +75,21 @@ class AdvantageAirTimeTo(AdvantageAirAcEntity, SensorEntity):
|
||||
self._attr_unique_id += f"-timeto{action}"
|
||||
|
||||
@property
|
||||
def native_value(self):
|
||||
def native_value(self) -> Decimal:
|
||||
"""Return the current value."""
|
||||
return self._ac[self._time_key]
|
||||
|
||||
@property
|
||||
def icon(self):
|
||||
def icon(self) -> str:
|
||||
"""Return a representative icon of the timer."""
|
||||
if self._ac[self._time_key] > 0:
|
||||
return "mdi:timer-outline"
|
||||
return "mdi:timer-off-outline"
|
||||
|
||||
async def set_time_to(self, **kwargs):
|
||||
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.async_change({self.ac_key: {"info": {self._time_key: value}}})
|
||||
await self.aircon({self.ac_key: {"info": {self._time_key: value}}})
|
||||
|
||||
|
||||
class AdvantageAirZoneVent(AdvantageAirZoneEntity, SensorEntity):
|
||||
@ -95,21 +99,21 @@ class AdvantageAirZoneVent(AdvantageAirZoneEntity, SensorEntity):
|
||||
_attr_state_class = SensorStateClass.MEASUREMENT
|
||||
_attr_entity_category = EntityCategory.DIAGNOSTIC
|
||||
|
||||
def __init__(self, instance, ac_key, zone_key):
|
||||
def __init__(self, instance: dict[str, Any], ac_key: str, zone_key: str) -> None:
|
||||
"""Initialize an Advantage Air Zone Vent Sensor."""
|
||||
super().__init__(instance, ac_key, zone_key=zone_key)
|
||||
self._attr_name = f'{self._zone["name"]} vent'
|
||||
self._attr_unique_id += "-vent"
|
||||
|
||||
@property
|
||||
def native_value(self):
|
||||
def native_value(self) -> Decimal:
|
||||
"""Return the current value of the air vent."""
|
||||
if self._zone["state"] == ADVANTAGE_AIR_STATE_OPEN:
|
||||
return self._zone["value"]
|
||||
return 0
|
||||
return Decimal(0)
|
||||
|
||||
@property
|
||||
def icon(self):
|
||||
def icon(self) -> str:
|
||||
"""Return a representative icon."""
|
||||
if self._zone["state"] == ADVANTAGE_AIR_STATE_OPEN:
|
||||
return "mdi:fan"
|
||||
@ -123,19 +127,19 @@ class AdvantageAirZoneSignal(AdvantageAirZoneEntity, SensorEntity):
|
||||
_attr_state_class = SensorStateClass.MEASUREMENT
|
||||
_attr_entity_category = EntityCategory.DIAGNOSTIC
|
||||
|
||||
def __init__(self, instance, ac_key, zone_key):
|
||||
def __init__(self, instance: dict[str, Any], ac_key: str, zone_key: str) -> None:
|
||||
"""Initialize an Advantage Air Zone wireless signal sensor."""
|
||||
super().__init__(instance, ac_key, zone_key)
|
||||
self._attr_name = f'{self._zone["name"]} signal'
|
||||
self._attr_unique_id += "-signal"
|
||||
|
||||
@property
|
||||
def native_value(self):
|
||||
def native_value(self) -> Decimal:
|
||||
"""Return the current value of the wireless signal."""
|
||||
return self._zone["rssi"]
|
||||
|
||||
@property
|
||||
def icon(self):
|
||||
def icon(self) -> str:
|
||||
"""Return a representative icon."""
|
||||
if self._zone["rssi"] >= 80:
|
||||
return "mdi:wifi-strength-4"
|
||||
@ -157,13 +161,13 @@ class AdvantageAirZoneTemp(AdvantageAirZoneEntity, SensorEntity):
|
||||
_attr_entity_registry_enabled_default = False
|
||||
_attr_entity_category = EntityCategory.DIAGNOSTIC
|
||||
|
||||
def __init__(self, instance, ac_key, zone_key):
|
||||
def __init__(self, instance: dict[str, Any], ac_key: str, zone_key: str) -> None:
|
||||
"""Initialize an Advantage Air Zone Temp Sensor."""
|
||||
super().__init__(instance, ac_key, zone_key)
|
||||
self._attr_name = f'{self._zone["name"]} temperature'
|
||||
self._attr_unique_id += "-temp"
|
||||
|
||||
@property
|
||||
def native_value(self):
|
||||
def native_value(self) -> Decimal:
|
||||
"""Return the current value of the measured temperature."""
|
||||
return self._zone["measuredTemp"]
|
||||
|
@ -23,10 +23,11 @@ async def async_setup_entry(
|
||||
|
||||
instance = hass.data[ADVANTAGE_AIR_DOMAIN][config_entry.entry_id]
|
||||
|
||||
entities = []
|
||||
for ac_key, ac_device in instance["coordinator"].data["aircons"].items():
|
||||
if ac_device["info"]["freshAirStatus"] != "none":
|
||||
entities.append(AdvantageAirFreshAir(instance, ac_key))
|
||||
entities: list[SwitchEntity] = []
|
||||
if aircons := instance["coordinator"].data.get("aircons"):
|
||||
for ac_key, ac_device in aircons.items():
|
||||
if ac_device["info"]["freshAirStatus"] != "none":
|
||||
entities.append(AdvantageAirFreshAir(instance, ac_key))
|
||||
async_add_entities(entities)
|
||||
|
||||
|
||||
@ -36,24 +37,24 @@ class AdvantageAirFreshAir(AdvantageAirAcEntity, SwitchEntity):
|
||||
_attr_icon = "mdi:air-filter"
|
||||
_attr_name = "Fresh air"
|
||||
|
||||
def __init__(self, instance, ac_key):
|
||||
def __init__(self, instance: dict[str, Any], ac_key: str) -> None:
|
||||
"""Initialize an Advantage Air fresh air control."""
|
||||
super().__init__(instance, ac_key)
|
||||
self._attr_unique_id += "-freshair"
|
||||
|
||||
@property
|
||||
def is_on(self):
|
||||
def is_on(self) -> bool:
|
||||
"""Return the fresh air status."""
|
||||
return self._ac["freshAirStatus"] == ADVANTAGE_AIR_STATE_ON
|
||||
|
||||
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||
"""Turn fresh air on."""
|
||||
await self.async_change(
|
||||
await self.aircon(
|
||||
{self.ac_key: {"info": {"freshAirStatus": ADVANTAGE_AIR_STATE_ON}}}
|
||||
)
|
||||
|
||||
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||
"""Turn fresh air off."""
|
||||
await self.async_change(
|
||||
await self.aircon(
|
||||
{self.ac_key: {"info": {"freshAirStatus": ADVANTAGE_AIR_STATE_OFF}}}
|
||||
)
|
||||
|
@ -1,4 +1,6 @@
|
||||
"""Advantage Air Update platform."""
|
||||
from typing import Any
|
||||
|
||||
from homeassistant.components.update import UpdateEntity
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
@ -26,7 +28,7 @@ class AdvantageAirApp(AdvantageAirEntity, UpdateEntity):
|
||||
|
||||
_attr_name = "App"
|
||||
|
||||
def __init__(self, instance):
|
||||
def __init__(self, instance: dict[str, Any]) -> None:
|
||||
"""Initialize the Advantage Air App."""
|
||||
super().__init__(instance)
|
||||
self._attr_device_info = DeviceInfo(
|
||||
@ -40,12 +42,12 @@ class AdvantageAirApp(AdvantageAirEntity, UpdateEntity):
|
||||
)
|
||||
|
||||
@property
|
||||
def installed_version(self):
|
||||
def installed_version(self) -> str:
|
||||
"""Return the current app version."""
|
||||
return self.coordinator.data["system"]["myAppRev"]
|
||||
|
||||
@property
|
||||
def latest_version(self):
|
||||
def latest_version(self) -> str:
|
||||
"""Return if there is an update."""
|
||||
if self.coordinator.data["system"]["needsUpdate"]:
|
||||
return "Needs Update"
|
||||
|
@ -1,6 +1,8 @@
|
||||
"""Test the Advantage Air Climate Platform."""
|
||||
from json import loads
|
||||
|
||||
import pytest
|
||||
|
||||
from homeassistant.components.advantage_air.climate import (
|
||||
HASS_FAN_MODES,
|
||||
HASS_HVAC_MODES,
|
||||
@ -20,9 +22,10 @@ from homeassistant.components.climate.const import (
|
||||
HVACMode,
|
||||
)
|
||||
from homeassistant.const import ATTR_ENTITY_ID, ATTR_TEMPERATURE
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
|
||||
from tests.components.advantage_air import (
|
||||
from . import (
|
||||
TEST_SET_RESPONSE,
|
||||
TEST_SET_URL,
|
||||
TEST_SYSTEM_DATA,
|
||||
@ -184,12 +187,13 @@ async def test_climate_async_failed_update(hass, aioclient_mock):
|
||||
|
||||
assert len(aioclient_mock.mock_calls) == 1
|
||||
|
||||
await hass.services.async_call(
|
||||
CLIMATE_DOMAIN,
|
||||
SERVICE_SET_TEMPERATURE,
|
||||
{ATTR_ENTITY_ID: ["climate.ac_one"], ATTR_TEMPERATURE: 25},
|
||||
blocking=True,
|
||||
)
|
||||
with pytest.raises(HomeAssistantError):
|
||||
await hass.services.async_call(
|
||||
CLIMATE_DOMAIN,
|
||||
SERVICE_SET_TEMPERATURE,
|
||||
{ATTR_ENTITY_ID: ["climate.ac_one"], ATTR_TEMPERATURE: 25},
|
||||
blocking=True,
|
||||
)
|
||||
assert len(aioclient_mock.mock_calls) == 2
|
||||
assert aioclient_mock.mock_calls[-1][0] == "GET"
|
||||
assert aioclient_mock.mock_calls[-1][1].path == "/setAircon"
|
||||
|
Loading…
x
Reference in New Issue
Block a user