mirror of
https://github.com/home-assistant/core.git
synced 2025-12-20 02:48:57 +00:00
Actron Air: Add switch entity platform (#158087)
Co-authored-by: Joostlek <joostlek@outlook.com>
This commit is contained in:
@@ -18,7 +18,7 @@ from .coordinator import (
|
|||||||
ActronAirSystemCoordinator,
|
ActronAirSystemCoordinator,
|
||||||
)
|
)
|
||||||
|
|
||||||
PLATFORM = [Platform.CLIMATE]
|
PLATFORMS = [Platform.CLIMATE, Platform.SWITCH]
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_entry(hass: HomeAssistant, entry: ActronAirConfigEntry) -> bool:
|
async def async_setup_entry(hass: HomeAssistant, entry: ActronAirConfigEntry) -> bool:
|
||||||
@@ -50,10 +50,10 @@ async def async_setup_entry(hass: HomeAssistant, entry: ActronAirConfigEntry) ->
|
|||||||
system_coordinators=system_coordinators,
|
system_coordinators=system_coordinators,
|
||||||
)
|
)
|
||||||
|
|
||||||
await hass.config_entries.async_forward_entry_setups(entry, PLATFORM)
|
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
async def async_unload_entry(hass: HomeAssistant, entry: ActronAirConfigEntry) -> bool:
|
async def async_unload_entry(hass: HomeAssistant, entry: ActronAirConfigEntry) -> bool:
|
||||||
"""Unload a config entry."""
|
"""Unload a config entry."""
|
||||||
return await hass.config_entries.async_unload_platforms(entry, PLATFORM)
|
return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
|
||||||
|
|||||||
30
homeassistant/components/actron_air/icons.json
Normal file
30
homeassistant/components/actron_air/icons.json
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
{
|
||||||
|
"entity": {
|
||||||
|
"switch": {
|
||||||
|
"away_mode": {
|
||||||
|
"default": "mdi:home-export-outline",
|
||||||
|
"state": {
|
||||||
|
"off": "mdi:home-import-outline"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"continuous_fan": {
|
||||||
|
"default": "mdi:fan",
|
||||||
|
"state": {
|
||||||
|
"off": "mdi:fan-off"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"quiet_mode": {
|
||||||
|
"default": "mdi:volume-low",
|
||||||
|
"state": {
|
||||||
|
"off": "mdi:volume-high"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"turbo_mode": {
|
||||||
|
"default": "mdi:fan-plus",
|
||||||
|
"state": {
|
||||||
|
"off": "mdi:fan"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -32,6 +32,22 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"entity": {
|
||||||
|
"switch": {
|
||||||
|
"away_mode": {
|
||||||
|
"name": "Away mode"
|
||||||
|
},
|
||||||
|
"continuous_fan": {
|
||||||
|
"name": "Continuous fan"
|
||||||
|
},
|
||||||
|
"quiet_mode": {
|
||||||
|
"name": "Quiet mode"
|
||||||
|
},
|
||||||
|
"turbo_mode": {
|
||||||
|
"name": "Turbo mode"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"exceptions": {
|
"exceptions": {
|
||||||
"auth_error": {
|
"auth_error": {
|
||||||
"message": "Authentication failed, please reauthenticate"
|
"message": "Authentication failed, please reauthenticate"
|
||||||
|
|||||||
110
homeassistant/components/actron_air/switch.py
Normal file
110
homeassistant/components/actron_air/switch.py
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
"""Switch platform for Actron Air integration."""
|
||||||
|
|
||||||
|
from collections.abc import Awaitable, Callable
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
from homeassistant.components.switch import SwitchEntity, SwitchEntityDescription
|
||||||
|
from homeassistant.const import EntityCategory
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.helpers.device_registry import DeviceInfo
|
||||||
|
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||||
|
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
||||||
|
|
||||||
|
from .const import DOMAIN
|
||||||
|
from .coordinator import ActronAirConfigEntry, ActronAirSystemCoordinator
|
||||||
|
|
||||||
|
PARALLEL_UPDATES = 0
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True, kw_only=True)
|
||||||
|
class ActronAirSwitchEntityDescription(SwitchEntityDescription):
|
||||||
|
"""Class describing Actron Air switch entities."""
|
||||||
|
|
||||||
|
is_on_fn: Callable[[ActronAirSystemCoordinator], bool]
|
||||||
|
set_fn: Callable[[ActronAirSystemCoordinator, bool], Awaitable[None]]
|
||||||
|
is_supported_fn: Callable[[ActronAirSystemCoordinator], bool] = lambda _: True
|
||||||
|
|
||||||
|
|
||||||
|
SWITCHES: tuple[ActronAirSwitchEntityDescription, ...] = (
|
||||||
|
ActronAirSwitchEntityDescription(
|
||||||
|
key="away_mode",
|
||||||
|
translation_key="away_mode",
|
||||||
|
is_on_fn=lambda coordinator: coordinator.data.user_aircon_settings.away_mode,
|
||||||
|
set_fn=lambda coordinator,
|
||||||
|
enabled: coordinator.data.user_aircon_settings.set_away_mode(enabled),
|
||||||
|
),
|
||||||
|
ActronAirSwitchEntityDescription(
|
||||||
|
key="continuous_fan",
|
||||||
|
translation_key="continuous_fan",
|
||||||
|
is_on_fn=lambda coordinator: coordinator.data.user_aircon_settings.continuous_fan_enabled,
|
||||||
|
set_fn=lambda coordinator,
|
||||||
|
enabled: coordinator.data.user_aircon_settings.set_continuous_mode(enabled),
|
||||||
|
),
|
||||||
|
ActronAirSwitchEntityDescription(
|
||||||
|
key="quiet_mode",
|
||||||
|
translation_key="quiet_mode",
|
||||||
|
is_on_fn=lambda coordinator: coordinator.data.user_aircon_settings.quiet_mode_enabled,
|
||||||
|
set_fn=lambda coordinator,
|
||||||
|
enabled: coordinator.data.user_aircon_settings.set_quiet_mode(enabled),
|
||||||
|
),
|
||||||
|
ActronAirSwitchEntityDescription(
|
||||||
|
key="turbo_mode",
|
||||||
|
translation_key="turbo_mode",
|
||||||
|
is_on_fn=lambda coordinator: coordinator.data.user_aircon_settings.turbo_enabled,
|
||||||
|
set_fn=lambda coordinator,
|
||||||
|
enabled: coordinator.data.user_aircon_settings.set_turbo_mode(enabled),
|
||||||
|
is_supported_fn=lambda coordinator: coordinator.data.user_aircon_settings.turbo_supported,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def async_setup_entry(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
entry: ActronAirConfigEntry,
|
||||||
|
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||||
|
) -> None:
|
||||||
|
"""Set up Actron Air switch entities."""
|
||||||
|
system_coordinators = entry.runtime_data.system_coordinators
|
||||||
|
async_add_entities(
|
||||||
|
ActronAirSwitch(coordinator, description)
|
||||||
|
for coordinator in system_coordinators.values()
|
||||||
|
for description in SWITCHES
|
||||||
|
if description.is_supported_fn(coordinator)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class ActronAirSwitch(CoordinatorEntity[ActronAirSystemCoordinator], SwitchEntity):
|
||||||
|
"""Actron Air switch."""
|
||||||
|
|
||||||
|
_attr_has_entity_name = True
|
||||||
|
_attr_entity_category = EntityCategory.CONFIG
|
||||||
|
entity_description: ActronAirSwitchEntityDescription
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
coordinator: ActronAirSystemCoordinator,
|
||||||
|
description: ActronAirSwitchEntityDescription,
|
||||||
|
) -> None:
|
||||||
|
"""Initialize the switch."""
|
||||||
|
super().__init__(coordinator)
|
||||||
|
self.entity_description = description
|
||||||
|
self._attr_unique_id = f"{coordinator.serial_number}_{description.key}"
|
||||||
|
self._attr_device_info = DeviceInfo(
|
||||||
|
identifiers={(DOMAIN, coordinator.serial_number)},
|
||||||
|
manufacturer="Actron Air",
|
||||||
|
name=coordinator.data.ac_system.system_name,
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_on(self) -> bool:
|
||||||
|
"""Return true if the switch is on."""
|
||||||
|
return self.entity_description.is_on_fn(self.coordinator)
|
||||||
|
|
||||||
|
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||||
|
"""Turn the switch on."""
|
||||||
|
await self.entity_description.set_fn(self.coordinator, True)
|
||||||
|
|
||||||
|
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||||
|
"""Turn the switch off."""
|
||||||
|
await self.entity_description.set_fn(self.coordinator, False)
|
||||||
@@ -1 +1,13 @@
|
|||||||
"""Tests for the Actron Air integration."""
|
"""Tests for the Actron Air integration."""
|
||||||
|
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
|
||||||
|
from tests.common import MockConfigEntry
|
||||||
|
|
||||||
|
|
||||||
|
async def setup_integration(hass: HomeAssistant, config_entry: MockConfigEntry) -> None:
|
||||||
|
"""Fixture for setting up the component."""
|
||||||
|
config_entry.add_to_hass(hass)
|
||||||
|
|
||||||
|
await hass.config_entries.async_setup(config_entry.entry_id)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
from collections.abc import Generator
|
from collections.abc import Generator
|
||||||
from unittest.mock import AsyncMock, patch
|
from unittest.mock import AsyncMock, MagicMock, patch
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
@@ -53,9 +53,40 @@ def mock_actron_api() -> Generator[AsyncMock]:
|
|||||||
# Mock refresh token property
|
# Mock refresh token property
|
||||||
api.refresh_token_value = "test_refresh_token"
|
api.refresh_token_value = "test_refresh_token"
|
||||||
|
|
||||||
# Mock other API methods that might be used
|
# Mock get_ac_systems
|
||||||
api.get_systems = AsyncMock(return_value=[])
|
api.get_ac_systems = AsyncMock(
|
||||||
api.get_status = AsyncMock(return_value=None)
|
return_value=[{"serial": "123456", "name": "Test System"}]
|
||||||
|
)
|
||||||
|
|
||||||
|
# Mock state manager
|
||||||
|
api.state_manager = MagicMock()
|
||||||
|
status = api.state_manager.get_status.return_value
|
||||||
|
status.master_info.live_temp_c = 22.0
|
||||||
|
status.ac_system.system_name = "Test System"
|
||||||
|
status.ac_system.serial_number = "123456"
|
||||||
|
status.ac_system.master_wc_model = "Test Model"
|
||||||
|
status.ac_system.master_wc_firmware_version = "1.0.0"
|
||||||
|
status.remote_zone_info = []
|
||||||
|
status.min_temp = 16
|
||||||
|
status.max_temp = 30
|
||||||
|
status.aircon_system.mode = "OFF"
|
||||||
|
status.fan_mode = "LOW"
|
||||||
|
status.set_point = 24
|
||||||
|
status.room_temp = 25
|
||||||
|
status.is_on = False
|
||||||
|
|
||||||
|
# Mock user_aircon_settings for the switch platform
|
||||||
|
settings = status.user_aircon_settings
|
||||||
|
settings.away_mode = False
|
||||||
|
settings.continuous_fan_enabled = False
|
||||||
|
settings.quiet_mode_enabled = False
|
||||||
|
settings.turbo_enabled = False
|
||||||
|
settings.turbo_supported = True
|
||||||
|
|
||||||
|
settings.set_away_mode = AsyncMock()
|
||||||
|
settings.set_continuous_mode = AsyncMock()
|
||||||
|
settings.set_quiet_mode = AsyncMock()
|
||||||
|
settings.set_turbo_mode = AsyncMock()
|
||||||
|
|
||||||
yield api
|
yield api
|
||||||
|
|
||||||
@@ -69,3 +100,12 @@ def mock_config_entry() -> MockConfigEntry:
|
|||||||
data={CONF_API_TOKEN: "test_refresh_token"},
|
data={CONF_API_TOKEN: "test_refresh_token"},
|
||||||
unique_id="test_user_id",
|
unique_id="test_user_id",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def mock_setup_entry() -> Generator[AsyncMock]:
|
||||||
|
"""Mock async_setup_entry."""
|
||||||
|
with patch(
|
||||||
|
"homeassistant.components.actron_air.async_setup_entry", return_value=True
|
||||||
|
) as mock_setup:
|
||||||
|
yield mock_setup
|
||||||
|
|||||||
193
tests/components/actron_air/snapshots/test_switch.ambr
Normal file
193
tests/components/actron_air/snapshots/test_switch.ambr
Normal file
@@ -0,0 +1,193 @@
|
|||||||
|
# serializer version: 1
|
||||||
|
# name: test_switch_entities[switch.test_system_away_mode-entry]
|
||||||
|
EntityRegistryEntrySnapshot({
|
||||||
|
'aliases': set({
|
||||||
|
}),
|
||||||
|
'area_id': None,
|
||||||
|
'capabilities': None,
|
||||||
|
'config_entry_id': <ANY>,
|
||||||
|
'config_subentry_id': <ANY>,
|
||||||
|
'device_class': None,
|
||||||
|
'device_id': <ANY>,
|
||||||
|
'disabled_by': None,
|
||||||
|
'domain': 'switch',
|
||||||
|
'entity_category': <EntityCategory.CONFIG: 'config'>,
|
||||||
|
'entity_id': 'switch.test_system_away_mode',
|
||||||
|
'has_entity_name': True,
|
||||||
|
'hidden_by': None,
|
||||||
|
'icon': None,
|
||||||
|
'id': <ANY>,
|
||||||
|
'labels': set({
|
||||||
|
}),
|
||||||
|
'name': None,
|
||||||
|
'options': dict({
|
||||||
|
}),
|
||||||
|
'original_device_class': None,
|
||||||
|
'original_icon': None,
|
||||||
|
'original_name': 'Away mode',
|
||||||
|
'platform': 'actron_air',
|
||||||
|
'previous_unique_id': None,
|
||||||
|
'suggested_object_id': None,
|
||||||
|
'supported_features': 0,
|
||||||
|
'translation_key': 'away_mode',
|
||||||
|
'unique_id': '123456_away_mode',
|
||||||
|
'unit_of_measurement': None,
|
||||||
|
})
|
||||||
|
# ---
|
||||||
|
# name: test_switch_entities[switch.test_system_away_mode-state]
|
||||||
|
StateSnapshot({
|
||||||
|
'attributes': ReadOnlyDict({
|
||||||
|
'friendly_name': 'Test System Away mode',
|
||||||
|
}),
|
||||||
|
'context': <ANY>,
|
||||||
|
'entity_id': 'switch.test_system_away_mode',
|
||||||
|
'last_changed': <ANY>,
|
||||||
|
'last_reported': <ANY>,
|
||||||
|
'last_updated': <ANY>,
|
||||||
|
'state': 'off',
|
||||||
|
})
|
||||||
|
# ---
|
||||||
|
# name: test_switch_entities[switch.test_system_continuous_fan-entry]
|
||||||
|
EntityRegistryEntrySnapshot({
|
||||||
|
'aliases': set({
|
||||||
|
}),
|
||||||
|
'area_id': None,
|
||||||
|
'capabilities': None,
|
||||||
|
'config_entry_id': <ANY>,
|
||||||
|
'config_subentry_id': <ANY>,
|
||||||
|
'device_class': None,
|
||||||
|
'device_id': <ANY>,
|
||||||
|
'disabled_by': None,
|
||||||
|
'domain': 'switch',
|
||||||
|
'entity_category': <EntityCategory.CONFIG: 'config'>,
|
||||||
|
'entity_id': 'switch.test_system_continuous_fan',
|
||||||
|
'has_entity_name': True,
|
||||||
|
'hidden_by': None,
|
||||||
|
'icon': None,
|
||||||
|
'id': <ANY>,
|
||||||
|
'labels': set({
|
||||||
|
}),
|
||||||
|
'name': None,
|
||||||
|
'options': dict({
|
||||||
|
}),
|
||||||
|
'original_device_class': None,
|
||||||
|
'original_icon': None,
|
||||||
|
'original_name': 'Continuous fan',
|
||||||
|
'platform': 'actron_air',
|
||||||
|
'previous_unique_id': None,
|
||||||
|
'suggested_object_id': None,
|
||||||
|
'supported_features': 0,
|
||||||
|
'translation_key': 'continuous_fan',
|
||||||
|
'unique_id': '123456_continuous_fan',
|
||||||
|
'unit_of_measurement': None,
|
||||||
|
})
|
||||||
|
# ---
|
||||||
|
# name: test_switch_entities[switch.test_system_continuous_fan-state]
|
||||||
|
StateSnapshot({
|
||||||
|
'attributes': ReadOnlyDict({
|
||||||
|
'friendly_name': 'Test System Continuous fan',
|
||||||
|
}),
|
||||||
|
'context': <ANY>,
|
||||||
|
'entity_id': 'switch.test_system_continuous_fan',
|
||||||
|
'last_changed': <ANY>,
|
||||||
|
'last_reported': <ANY>,
|
||||||
|
'last_updated': <ANY>,
|
||||||
|
'state': 'off',
|
||||||
|
})
|
||||||
|
# ---
|
||||||
|
# name: test_switch_entities[switch.test_system_quiet_mode-entry]
|
||||||
|
EntityRegistryEntrySnapshot({
|
||||||
|
'aliases': set({
|
||||||
|
}),
|
||||||
|
'area_id': None,
|
||||||
|
'capabilities': None,
|
||||||
|
'config_entry_id': <ANY>,
|
||||||
|
'config_subentry_id': <ANY>,
|
||||||
|
'device_class': None,
|
||||||
|
'device_id': <ANY>,
|
||||||
|
'disabled_by': None,
|
||||||
|
'domain': 'switch',
|
||||||
|
'entity_category': <EntityCategory.CONFIG: 'config'>,
|
||||||
|
'entity_id': 'switch.test_system_quiet_mode',
|
||||||
|
'has_entity_name': True,
|
||||||
|
'hidden_by': None,
|
||||||
|
'icon': None,
|
||||||
|
'id': <ANY>,
|
||||||
|
'labels': set({
|
||||||
|
}),
|
||||||
|
'name': None,
|
||||||
|
'options': dict({
|
||||||
|
}),
|
||||||
|
'original_device_class': None,
|
||||||
|
'original_icon': None,
|
||||||
|
'original_name': 'Quiet mode',
|
||||||
|
'platform': 'actron_air',
|
||||||
|
'previous_unique_id': None,
|
||||||
|
'suggested_object_id': None,
|
||||||
|
'supported_features': 0,
|
||||||
|
'translation_key': 'quiet_mode',
|
||||||
|
'unique_id': '123456_quiet_mode',
|
||||||
|
'unit_of_measurement': None,
|
||||||
|
})
|
||||||
|
# ---
|
||||||
|
# name: test_switch_entities[switch.test_system_quiet_mode-state]
|
||||||
|
StateSnapshot({
|
||||||
|
'attributes': ReadOnlyDict({
|
||||||
|
'friendly_name': 'Test System Quiet mode',
|
||||||
|
}),
|
||||||
|
'context': <ANY>,
|
||||||
|
'entity_id': 'switch.test_system_quiet_mode',
|
||||||
|
'last_changed': <ANY>,
|
||||||
|
'last_reported': <ANY>,
|
||||||
|
'last_updated': <ANY>,
|
||||||
|
'state': 'off',
|
||||||
|
})
|
||||||
|
# ---
|
||||||
|
# name: test_switch_entities[switch.test_system_turbo_mode-entry]
|
||||||
|
EntityRegistryEntrySnapshot({
|
||||||
|
'aliases': set({
|
||||||
|
}),
|
||||||
|
'area_id': None,
|
||||||
|
'capabilities': None,
|
||||||
|
'config_entry_id': <ANY>,
|
||||||
|
'config_subentry_id': <ANY>,
|
||||||
|
'device_class': None,
|
||||||
|
'device_id': <ANY>,
|
||||||
|
'disabled_by': None,
|
||||||
|
'domain': 'switch',
|
||||||
|
'entity_category': <EntityCategory.CONFIG: 'config'>,
|
||||||
|
'entity_id': 'switch.test_system_turbo_mode',
|
||||||
|
'has_entity_name': True,
|
||||||
|
'hidden_by': None,
|
||||||
|
'icon': None,
|
||||||
|
'id': <ANY>,
|
||||||
|
'labels': set({
|
||||||
|
}),
|
||||||
|
'name': None,
|
||||||
|
'options': dict({
|
||||||
|
}),
|
||||||
|
'original_device_class': None,
|
||||||
|
'original_icon': None,
|
||||||
|
'original_name': 'Turbo mode',
|
||||||
|
'platform': 'actron_air',
|
||||||
|
'previous_unique_id': None,
|
||||||
|
'suggested_object_id': None,
|
||||||
|
'supported_features': 0,
|
||||||
|
'translation_key': 'turbo_mode',
|
||||||
|
'unique_id': '123456_turbo_mode',
|
||||||
|
'unit_of_measurement': None,
|
||||||
|
})
|
||||||
|
# ---
|
||||||
|
# name: test_switch_entities[switch.test_system_turbo_mode-state]
|
||||||
|
StateSnapshot({
|
||||||
|
'attributes': ReadOnlyDict({
|
||||||
|
'friendly_name': 'Test System Turbo mode',
|
||||||
|
}),
|
||||||
|
'context': <ANY>,
|
||||||
|
'entity_id': 'switch.test_system_turbo_mode',
|
||||||
|
'last_changed': <ANY>,
|
||||||
|
'last_reported': <ANY>,
|
||||||
|
'last_updated': <ANY>,
|
||||||
|
'state': 'off',
|
||||||
|
})
|
||||||
|
# ---
|
||||||
@@ -15,7 +15,7 @@ from tests.common import MockConfigEntry
|
|||||||
|
|
||||||
|
|
||||||
async def test_user_flow_oauth2_success(
|
async def test_user_flow_oauth2_success(
|
||||||
hass: HomeAssistant, mock_actron_api: AsyncMock
|
hass: HomeAssistant, mock_actron_api: AsyncMock, mock_setup_entry: AsyncMock
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test successful OAuth2 device code flow."""
|
"""Test successful OAuth2 device code flow."""
|
||||||
# Start the config flow
|
# Start the config flow
|
||||||
@@ -90,7 +90,7 @@ async def test_user_flow_oauth2_error(hass: HomeAssistant, mock_actron_api) -> N
|
|||||||
|
|
||||||
|
|
||||||
async def test_user_flow_token_polling_error(
|
async def test_user_flow_token_polling_error(
|
||||||
hass: HomeAssistant, mock_actron_api
|
hass: HomeAssistant, mock_actron_api, mock_setup_entry: AsyncMock
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test OAuth2 flow with error during token polling."""
|
"""Test OAuth2 flow with error during token polling."""
|
||||||
# Override the default mock to raise an error during token polling
|
# Override the default mock to raise an error during token polling
|
||||||
@@ -179,7 +179,10 @@ async def test_user_flow_duplicate_account(
|
|||||||
|
|
||||||
|
|
||||||
async def test_reauth_flow_success(
|
async def test_reauth_flow_success(
|
||||||
hass: HomeAssistant, mock_actron_api: AsyncMock, mock_config_entry: MockConfigEntry
|
hass: HomeAssistant,
|
||||||
|
mock_actron_api: AsyncMock,
|
||||||
|
mock_config_entry: MockConfigEntry,
|
||||||
|
mock_setup_entry: AsyncMock,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test successful reauthentication flow."""
|
"""Test successful reauthentication flow."""
|
||||||
# Create an existing config entry
|
# Create an existing config entry
|
||||||
|
|||||||
90
tests/components/actron_air/test_switch.py
Normal file
90
tests/components/actron_air/test_switch.py
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
"""Tests for the Actron Air switch platform."""
|
||||||
|
|
||||||
|
from unittest.mock import MagicMock, patch
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
from syrupy.assertion import SnapshotAssertion
|
||||||
|
|
||||||
|
from homeassistant.components.switch import (
|
||||||
|
DOMAIN as SWITCH_DOMAIN,
|
||||||
|
SERVICE_TURN_OFF,
|
||||||
|
SERVICE_TURN_ON,
|
||||||
|
)
|
||||||
|
from homeassistant.const import ATTR_ENTITY_ID, Platform
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.helpers import entity_registry as er
|
||||||
|
|
||||||
|
from . import setup_integration
|
||||||
|
|
||||||
|
from tests.common import MockConfigEntry, snapshot_platform
|
||||||
|
|
||||||
|
|
||||||
|
async def test_switch_entities(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
mock_actron_api: MagicMock,
|
||||||
|
entity_registry: er.EntityRegistry,
|
||||||
|
snapshot: SnapshotAssertion,
|
||||||
|
mock_config_entry: MockConfigEntry,
|
||||||
|
) -> None:
|
||||||
|
"""Test switch entities."""
|
||||||
|
with patch("homeassistant.components.actron_air.PLATFORMS", [Platform.SWITCH]):
|
||||||
|
await setup_integration(hass, mock_config_entry)
|
||||||
|
await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
("entity_id", "method"),
|
||||||
|
[
|
||||||
|
("switch.test_system_away_mode", "set_away_mode"),
|
||||||
|
("switch.test_system_continuous_fan", "set_continuous_mode"),
|
||||||
|
("switch.test_system_quiet_mode", "set_quiet_mode"),
|
||||||
|
("switch.test_system_turbo_mode", "set_turbo_mode"),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
async def test_switch_toggles(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
mock_actron_api: MagicMock,
|
||||||
|
mock_config_entry: MockConfigEntry,
|
||||||
|
entity_id: str,
|
||||||
|
method: str,
|
||||||
|
) -> None:
|
||||||
|
"""Test switch toggles."""
|
||||||
|
with patch("homeassistant.components.actron_air.PLATFORMS", [Platform.SWITCH]):
|
||||||
|
await setup_integration(hass, mock_config_entry)
|
||||||
|
|
||||||
|
status = mock_actron_api.state_manager.get_status.return_value
|
||||||
|
mock_method = getattr(status.user_aircon_settings, method)
|
||||||
|
|
||||||
|
await hass.services.async_call(
|
||||||
|
SWITCH_DOMAIN,
|
||||||
|
SERVICE_TURN_ON,
|
||||||
|
{ATTR_ENTITY_ID: [entity_id]},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
mock_method.assert_awaited_once_with(True)
|
||||||
|
mock_method.reset_mock()
|
||||||
|
|
||||||
|
await hass.services.async_call(
|
||||||
|
SWITCH_DOMAIN,
|
||||||
|
SERVICE_TURN_OFF,
|
||||||
|
{ATTR_ENTITY_ID: [entity_id]},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
mock_method.assert_awaited_once_with(False)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_turbo_mode_not_supported(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
mock_actron_api: MagicMock,
|
||||||
|
mock_config_entry: MockConfigEntry,
|
||||||
|
entity_registry: er.EntityRegistry,
|
||||||
|
) -> None:
|
||||||
|
"""Test turbo mode switch is not created when not supported."""
|
||||||
|
status = mock_actron_api.state_manager.get_status.return_value
|
||||||
|
status.user_aircon_settings.turbo_supported = False
|
||||||
|
|
||||||
|
await setup_integration(hass, mock_config_entry)
|
||||||
|
|
||||||
|
entity_id = "switch.test_system_turbo_mode"
|
||||||
|
assert not hass.states.get(entity_id)
|
||||||
|
assert not entity_registry.async_get(entity_id)
|
||||||
Reference in New Issue
Block a user