Make Subaru buttons and locks coordinator-backed (#180946)

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
John Pettitt
2026-09-01 10:11:12 +02:00
committed by GitHub
co-authored by Claude Sonnet 5
parent 45c2434230
commit 262dc55b9c
4 changed files with 44 additions and 12 deletions
+3 -4
View File
@@ -17,7 +17,7 @@ from .const import (
VEHICLE_HAS_REMOTE_START,
)
from .coordinator import SubaruConfigEntry, SubaruDataUpdateCoordinator
from .entity import SubaruEntity
from .entity import SubaruCoordinatorEntity
from .remote_service import async_call_remote_service
@@ -58,7 +58,7 @@ async def async_setup_entry(
)
class SubaruButton(SubaruEntity, ButtonEntity):
class SubaruButton(SubaruCoordinatorEntity, ButtonEntity):
"""Class for a Subaru button."""
entity_description: SubaruButtonEntityDescription
@@ -71,9 +71,8 @@ class SubaruButton(SubaruEntity, ButtonEntity):
description: SubaruButtonEntityDescription,
) -> None:
"""Initialize the button for the vehicle."""
super().__init__(vehicle_info, description.key)
super().__init__(vehicle_info, coordinator, description.key)
self.controller = controller
self.coordinator = coordinator
self.entity_description = description
@override
+6 -5
View File
@@ -20,7 +20,7 @@ from .const import (
VEHICLE_NAME,
)
from .coordinator import SubaruConfigEntry
from .entity import SubaruEntity
from .entity import SubaruCoordinatorEntity
from .remote_service import async_call_remote_service
_LOGGER = logging.getLogger(__name__)
@@ -32,10 +32,11 @@ async def async_setup_entry(
async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
"""Set up the Subaru locks by config_entry."""
coordinator = config_entry.runtime_data.coordinator
controller = config_entry.runtime_data.controller
vehicle_info = config_entry.runtime_data.vehicles
async_add_entities(
SubaruLock(vehicle, controller)
SubaruLock(vehicle, controller, coordinator)
for vehicle in vehicle_info.values()
if vehicle[VEHICLE_HAS_REMOTE_SERVICE]
)
@@ -49,7 +50,7 @@ async def async_setup_entry(
)
class SubaruLock(SubaruEntity, LockEntity):
class SubaruLock(SubaruCoordinatorEntity, LockEntity):
"""Representation of a Subaru door lock.
Note that the Subaru API currently does not support
@@ -59,9 +60,9 @@ class SubaruLock(SubaruEntity, LockEntity):
_attr_translation_key = "door_locks"
def __init__(self, vehicle_info, controller):
def __init__(self, vehicle_info, controller, coordinator):
"""Initialize the locks for the vehicle."""
super().__init__(vehicle_info, "door_locks")
super().__init__(vehicle_info, coordinator, "door_locks")
self.controller = controller
self.car_name = vehicle_info[VEHICLE_NAME]
+13 -1
View File
@@ -10,7 +10,7 @@ from homeassistant.components.subaru.const import (
VEHICLE_HAS_EV,
VEHICLE_HAS_REMOTE_START,
)
from homeassistant.const import ATTR_ENTITY_ID
from homeassistant.const import ATTR_ENTITY_ID, STATE_UNAVAILABLE
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import entity_registry as er
@@ -299,3 +299,15 @@ async def test_no_buttons_without_remote_start(
assert entry is None
entry = entity_registry.async_get(VEHICLE_BUTTONS[TEST_VIN_3_G3]["remote_stop"])
assert entry is None
async def test_button_unavailable_on_fetch_failure(
hass: HomeAssistant, subaru_config_entry: MockConfigEntry
) -> None:
"""Test button goes unavailable when the coordinator fails to fetch data."""
await setup_subaru_config_entry(
hass, subaru_config_entry, fetch_effect=SubaruException("403 Error")
)
state = hass.states.get(VEHICLE_BUTTONS[TEST_VIN_2_EV]["remote_start"])
assert state.state == STATE_UNAVAILABLE
+22 -2
View File
@@ -3,6 +3,7 @@
from unittest.mock import patch
import pytest
from subarulink import SubaruException
from voluptuous.error import MultipleInvalid
from homeassistant.components.lock import DOMAIN as LOCK_DOMAIN
@@ -12,12 +13,19 @@ from homeassistant.components.subaru.const import (
SERVICE_UNLOCK_SPECIFIC_DOOR,
UNLOCK_DOOR_DRIVERS,
)
from homeassistant.const import ATTR_ENTITY_ID, SERVICE_LOCK, SERVICE_UNLOCK
from homeassistant.const import (
ATTR_ENTITY_ID,
SERVICE_LOCK,
SERVICE_UNLOCK,
STATE_UNAVAILABLE,
)
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import entity_registry as er
from .conftest import MOCK_API
from .conftest import MOCK_API, setup_subaru_config_entry
from tests.common import MockConfigEntry
MOCK_API_LOCK = f"{MOCK_API}lock"
MOCK_API_UNLOCK = f"{MOCK_API}unlock"
@@ -87,3 +95,15 @@ async def test_unlock_specific_door_invalid(hass: HomeAssistant, ev_entry) -> No
blocking=True,
)
mock_unlock.assert_not_called()
async def test_lock_unavailable_on_fetch_failure(
hass: HomeAssistant, subaru_config_entry: MockConfigEntry
) -> None:
"""Test lock goes unavailable when the coordinator fails to fetch data."""
await setup_subaru_config_entry(
hass, subaru_config_entry, fetch_effect=SubaruException("403 Error")
)
state = hass.states.get(DEVICE_ID)
assert state.state == STATE_UNAVAILABLE