1
0
mirror of https://github.com/home-assistant/core.git synced 2025-12-20 10:59:24 +00:00

Add support for actron air que air conditioners (#156675)

This commit is contained in:
Kurt Chrisford
2025-11-22 08:59:02 +10:00
committed by GitHub
parent 696550a7f2
commit 4e30a5d930
9 changed files with 32 additions and 32 deletions

View File

@@ -1,10 +1,10 @@
"""The Actron Air integration."""
from actron_neo_api import (
ActronAirNeoACSystem,
ActronNeoAPI,
ActronNeoAPIError,
ActronNeoAuthError,
ActronAirACSystem,
ActronAirAPI,
ActronAirAPIError,
ActronAirAuthError,
)
from homeassistant.const import CONF_API_TOKEN, Platform
@@ -23,16 +23,16 @@ PLATFORM = [Platform.CLIMATE]
async def async_setup_entry(hass: HomeAssistant, entry: ActronAirConfigEntry) -> bool:
"""Set up Actron Air integration from a config entry."""
api = ActronNeoAPI(refresh_token=entry.data[CONF_API_TOKEN])
systems: list[ActronAirNeoACSystem] = []
api = ActronAirAPI(refresh_token=entry.data[CONF_API_TOKEN])
systems: list[ActronAirACSystem] = []
try:
systems = await api.get_ac_systems()
await api.update_status()
except ActronNeoAuthError:
except ActronAirAuthError:
_LOGGER.error("Authentication error while setting up Actron Air integration")
raise
except ActronNeoAPIError as err:
except ActronAirAPIError as err:
_LOGGER.error("API error while setting up Actron Air integration: %s", err)
raise

View File

@@ -2,7 +2,7 @@
from typing import Any
from actron_neo_api import ActronAirNeoStatus, ActronAirNeoZone
from actron_neo_api import ActronAirStatus, ActronAirZone
from homeassistant.components.climate import (
FAN_AUTO,
@@ -132,7 +132,7 @@ class ActronSystemClimate(BaseClimateEntity):
return self._status.max_temp
@property
def _status(self) -> ActronAirNeoStatus:
def _status(self) -> ActronAirStatus:
"""Get the current status from the coordinator."""
return self.coordinator.data
@@ -194,7 +194,7 @@ class ActronZoneClimate(BaseClimateEntity):
def __init__(
self,
coordinator: ActronAirSystemCoordinator,
zone: ActronAirNeoZone,
zone: ActronAirZone,
) -> None:
"""Initialize an Actron Air unit."""
super().__init__(coordinator, zone.title)
@@ -221,7 +221,7 @@ class ActronZoneClimate(BaseClimateEntity):
return self._zone.max_temp
@property
def _zone(self) -> ActronAirNeoZone:
def _zone(self) -> ActronAirZone:
"""Get the current zone data from the coordinator."""
status = self.coordinator.data
return status.zones[self._zone_id]

View File

@@ -3,7 +3,7 @@
import asyncio
from typing import Any
from actron_neo_api import ActronNeoAPI, ActronNeoAuthError
from actron_neo_api import ActronAirAPI, ActronAirAuthError
from homeassistant.config_entries import ConfigFlow, ConfigFlowResult
from homeassistant.const import CONF_API_TOKEN
@@ -17,7 +17,7 @@ class ActronAirConfigFlow(ConfigFlow, domain=DOMAIN):
def __init__(self) -> None:
"""Initialize the config flow."""
self._api: ActronNeoAPI | None = None
self._api: ActronAirAPI | None = None
self._device_code: str | None = None
self._user_code: str = ""
self._verification_uri: str = ""
@@ -30,10 +30,10 @@ class ActronAirConfigFlow(ConfigFlow, domain=DOMAIN):
"""Handle the initial step."""
if self._api is None:
_LOGGER.debug("Initiating device authorization")
self._api = ActronNeoAPI()
self._api = ActronAirAPI()
try:
device_code_response = await self._api.request_device_code()
except ActronNeoAuthError as err:
except ActronAirAuthError as err:
_LOGGER.error("OAuth2 flow failed: %s", err)
return self.async_abort(reason="oauth2_error")
@@ -50,7 +50,7 @@ class ActronAirConfigFlow(ConfigFlow, domain=DOMAIN):
try:
await self._api.poll_for_token(self._device_code)
_LOGGER.debug("Authorization successful")
except ActronNeoAuthError as ex:
except ActronAirAuthError as ex:
_LOGGER.exception("Error while waiting for device authorization")
raise CannotConnect from ex
@@ -89,7 +89,7 @@ class ActronAirConfigFlow(ConfigFlow, domain=DOMAIN):
try:
user_data = await self._api.get_user_info()
except ActronNeoAuthError as err:
except ActronAirAuthError as err:
_LOGGER.error("Error getting user info: %s", err)
return self.async_abort(reason="oauth2_error")

View File

@@ -5,7 +5,7 @@ from __future__ import annotations
from dataclasses import dataclass
from datetime import timedelta
from actron_neo_api import ActronAirNeoACSystem, ActronAirNeoStatus, ActronNeoAPI
from actron_neo_api import ActronAirACSystem, ActronAirAPI, ActronAirStatus
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
@@ -23,7 +23,7 @@ ERROR_UNKNOWN = "unknown_error"
class ActronAirRuntimeData:
"""Runtime data for the Actron Air integration."""
api: ActronNeoAPI
api: ActronAirAPI
system_coordinators: dict[str, ActronAirSystemCoordinator]
@@ -33,15 +33,15 @@ AUTH_ERROR_THRESHOLD = 3
SCAN_INTERVAL = timedelta(seconds=30)
class ActronAirSystemCoordinator(DataUpdateCoordinator[ActronAirNeoACSystem]):
class ActronAirSystemCoordinator(DataUpdateCoordinator[ActronAirACSystem]):
"""System coordinator for Actron Air integration."""
def __init__(
self,
hass: HomeAssistant,
entry: ActronAirConfigEntry,
api: ActronNeoAPI,
system: ActronAirNeoACSystem,
api: ActronAirAPI,
system: ActronAirACSystem,
) -> None:
"""Initialize the coordinator."""
super().__init__(
@@ -57,7 +57,7 @@ class ActronAirSystemCoordinator(DataUpdateCoordinator[ActronAirNeoACSystem]):
self.status = self.api.state_manager.get_status(self.serial_number)
self.last_seen = dt_util.utcnow()
async def _async_update_data(self) -> ActronAirNeoStatus:
async def _async_update_data(self) -> ActronAirStatus:
"""Fetch updates and merge incremental changes into the full state."""
await self.api.update_status()
self.status = self.api.state_manager.get_status(self.serial_number)

View File

@@ -12,5 +12,5 @@
"documentation": "https://www.home-assistant.io/integrations/actron_air",
"iot_class": "cloud_polling",
"quality_scale": "bronze",
"requirements": ["actron-neo-api==0.1.84"]
"requirements": ["actron-neo-api==0.1.87"]
}

2
requirements_all.txt generated
View File

@@ -133,7 +133,7 @@ WSDiscovery==2.1.2
accuweather==4.2.2
# homeassistant.components.actron_air
actron-neo-api==0.1.84
actron-neo-api==0.1.87
# homeassistant.components.adax
adax==0.4.0

View File

@@ -121,7 +121,7 @@ WSDiscovery==2.1.2
accuweather==4.2.2
# homeassistant.components.actron_air
actron-neo-api==0.1.84
actron-neo-api==0.1.87
# homeassistant.components.adax
adax==0.4.0

View File

@@ -12,11 +12,11 @@ def mock_actron_api() -> Generator[AsyncMock]:
"""Mock the Actron Air API class."""
with (
patch(
"homeassistant.components.actron_air.ActronNeoAPI",
"homeassistant.components.actron_air.ActronAirAPI",
autospec=True,
) as mock_api,
patch(
"homeassistant.components.actron_air.config_flow.ActronNeoAPI",
"homeassistant.components.actron_air.config_flow.ActronAirAPI",
new=mock_api,
),
):

View File

@@ -3,7 +3,7 @@
import asyncio
from unittest.mock import AsyncMock
from actron_neo_api import ActronNeoAuthError
from actron_neo_api import ActronAirAuthError
from homeassistant import config_entries
from homeassistant.components.actron_air.const import DOMAIN
@@ -76,7 +76,7 @@ async def test_user_flow_oauth2_error(hass: HomeAssistant, mock_actron_api) -> N
"""Test OAuth2 flow with authentication error during device code request."""
# Override the default mock to raise an error
mock_actron_api.request_device_code = AsyncMock(
side_effect=ActronNeoAuthError("OAuth2 error")
side_effect=ActronAirAuthError("OAuth2 error")
)
# Start the flow
@@ -95,7 +95,7 @@ async def test_user_flow_token_polling_error(
"""Test OAuth2 flow with error during token polling."""
# Override the default mock to raise an error during token polling
mock_actron_api.poll_for_token = AsyncMock(
side_effect=ActronNeoAuthError("Token polling error")
side_effect=ActronAirAuthError("Token polling error")
)
# Start the config flow