mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 19:27:45 +00:00
Ensure state update after BMW remote service execution (#93745)
Co-authored-by: rikroe <rikroe@users.noreply.github.com>
This commit is contained in:
parent
24290e5d08
commit
52ef4a3b75
@ -122,7 +122,4 @@ class BMWButton(BMWBaseEntity, ButtonEntity):
|
|||||||
)
|
)
|
||||||
await self.entity_description.account_function(self.coordinator)
|
await self.entity_description.account_function(self.coordinator)
|
||||||
|
|
||||||
# Always update HA states after a button was executed.
|
|
||||||
# BMW remote services that change the vehicle's state update the local object
|
|
||||||
# when executing the service, so only the HA state machine needs further updates.
|
|
||||||
self.coordinator.async_update_listeners()
|
self.coordinator.async_update_listeners()
|
||||||
|
@ -68,6 +68,8 @@ class BMWLock(BMWBaseEntity, LockEntity):
|
|||||||
self.async_write_ha_state()
|
self.async_write_ha_state()
|
||||||
await self.vehicle.remote_services.trigger_remote_door_lock()
|
await self.vehicle.remote_services.trigger_remote_door_lock()
|
||||||
|
|
||||||
|
self.coordinator.async_update_listeners()
|
||||||
|
|
||||||
async def async_unlock(self, **kwargs: Any) -> None:
|
async def async_unlock(self, **kwargs: Any) -> None:
|
||||||
"""Unlock the car."""
|
"""Unlock the car."""
|
||||||
_LOGGER.debug("%s: unlocking doors", self.vehicle.name)
|
_LOGGER.debug("%s: unlocking doors", self.vehicle.name)
|
||||||
@ -79,6 +81,8 @@ class BMWLock(BMWBaseEntity, LockEntity):
|
|||||||
self.async_write_ha_state()
|
self.async_write_ha_state()
|
||||||
await self.vehicle.remote_services.trigger_remote_door_unlock()
|
await self.vehicle.remote_services.trigger_remote_door_unlock()
|
||||||
|
|
||||||
|
self.coordinator.async_update_listeners()
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def _handle_coordinator_update(self) -> None:
|
def _handle_coordinator_update(self) -> None:
|
||||||
"""Handle updated data from the coordinator."""
|
"""Handle updated data from the coordinator."""
|
||||||
|
@ -116,3 +116,5 @@ class BMWNumber(BMWBaseEntity, NumberEntity):
|
|||||||
await self.entity_description.remote_service(self.vehicle, value)
|
await self.entity_description.remote_service(self.vehicle, value)
|
||||||
except MyBMWAPIError as ex:
|
except MyBMWAPIError as ex:
|
||||||
raise HomeAssistantError(ex) from ex
|
raise HomeAssistantError(ex) from ex
|
||||||
|
|
||||||
|
self.coordinator.async_update_listeners()
|
||||||
|
@ -124,3 +124,5 @@ class BMWSelect(BMWBaseEntity, SelectEntity):
|
|||||||
option,
|
option,
|
||||||
)
|
)
|
||||||
await self.entity_description.remote_service(self.vehicle, option)
|
await self.entity_description.remote_service(self.vehicle, option)
|
||||||
|
|
||||||
|
self.coordinator.async_update_listeners()
|
||||||
|
@ -101,9 +101,13 @@ class BMWSwitch(BMWBaseEntity, SwitchEntity):
|
|||||||
except MyBMWAPIError as ex:
|
except MyBMWAPIError as ex:
|
||||||
raise HomeAssistantError(ex) from ex
|
raise HomeAssistantError(ex) from ex
|
||||||
|
|
||||||
|
self.coordinator.async_update_listeners()
|
||||||
|
|
||||||
async def async_turn_off(self, **kwargs: Any) -> None:
|
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||||
"""Turn the switch off."""
|
"""Turn the switch off."""
|
||||||
try:
|
try:
|
||||||
await self.entity_description.remote_service_off(self.vehicle)
|
await self.entity_description.remote_service_off(self.vehicle)
|
||||||
except MyBMWAPIError as ex:
|
except MyBMWAPIError as ex:
|
||||||
raise HomeAssistantError(ex) from ex
|
raise HomeAssistantError(ex) from ex
|
||||||
|
|
||||||
|
self.coordinator.async_update_listeners()
|
||||||
|
@ -1,11 +1,15 @@
|
|||||||
"""Fixtures for BMW tests."""
|
"""Fixtures for BMW tests."""
|
||||||
|
|
||||||
from unittest.mock import AsyncMock
|
from unittest.mock import AsyncMock, Mock
|
||||||
|
|
||||||
from bimmer_connected.api.authentication import MyBMWAuthentication
|
from bimmer_connected.api.authentication import MyBMWAuthentication
|
||||||
from bimmer_connected.vehicle.remote_services import RemoteServices, RemoteServiceStatus
|
from bimmer_connected.vehicle.remote_services import RemoteServices, RemoteServiceStatus
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
from homeassistant.components.bmw_connected_drive.coordinator import (
|
||||||
|
BMWDataUpdateCoordinator,
|
||||||
|
)
|
||||||
|
|
||||||
from . import mock_login, mock_vehicles
|
from . import mock_login, mock_vehicles
|
||||||
|
|
||||||
|
|
||||||
@ -20,5 +24,11 @@ async def bmw_fixture(monkeypatch):
|
|||||||
AsyncMock(return_value=RemoteServiceStatus({"eventStatus": "EXECUTED"})),
|
AsyncMock(return_value=RemoteServiceStatus({"eventStatus": "EXECUTED"})),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
monkeypatch.setattr(
|
||||||
|
BMWDataUpdateCoordinator,
|
||||||
|
"async_update_listeners",
|
||||||
|
Mock(),
|
||||||
|
)
|
||||||
|
|
||||||
with mock_vehicles():
|
with mock_vehicles():
|
||||||
yield mock_vehicles
|
yield mock_vehicles
|
||||||
|
@ -7,6 +7,9 @@ import pytest
|
|||||||
import respx
|
import respx
|
||||||
from syrupy.assertion import SnapshotAssertion
|
from syrupy.assertion import SnapshotAssertion
|
||||||
|
|
||||||
|
from homeassistant.components.bmw_connected_drive.coordinator import (
|
||||||
|
BMWDataUpdateCoordinator,
|
||||||
|
)
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.exceptions import HomeAssistantError
|
from homeassistant.exceptions import HomeAssistantError
|
||||||
|
|
||||||
@ -43,6 +46,7 @@ async def test_update_triggers_success(
|
|||||||
|
|
||||||
# Setup component
|
# Setup component
|
||||||
assert await setup_mocked_integration(hass)
|
assert await setup_mocked_integration(hass)
|
||||||
|
BMWDataUpdateCoordinator.async_update_listeners.reset_mock()
|
||||||
|
|
||||||
# Test
|
# Test
|
||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
@ -53,6 +57,7 @@ async def test_update_triggers_success(
|
|||||||
target={"entity_id": entity_id},
|
target={"entity_id": entity_id},
|
||||||
)
|
)
|
||||||
assert RemoteServices.trigger_remote_service.call_count == 1
|
assert RemoteServices.trigger_remote_service.call_count == 1
|
||||||
|
assert BMWDataUpdateCoordinator.async_update_listeners.call_count == 1
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
@ -71,6 +76,7 @@ async def test_update_triggers_fail(
|
|||||||
|
|
||||||
# Setup component
|
# Setup component
|
||||||
assert await setup_mocked_integration(hass)
|
assert await setup_mocked_integration(hass)
|
||||||
|
BMWDataUpdateCoordinator.async_update_listeners.reset_mock()
|
||||||
|
|
||||||
# Test
|
# Test
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
@ -82,6 +88,7 @@ async def test_update_triggers_fail(
|
|||||||
target={"entity_id": entity_id},
|
target={"entity_id": entity_id},
|
||||||
)
|
)
|
||||||
assert RemoteServices.trigger_remote_service.call_count == 0
|
assert RemoteServices.trigger_remote_service.call_count == 0
|
||||||
|
assert BMWDataUpdateCoordinator.async_update_listeners.call_count == 0
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
@ -103,6 +110,7 @@ async def test_update_triggers_exceptions(
|
|||||||
|
|
||||||
# Setup component
|
# Setup component
|
||||||
assert await setup_mocked_integration(hass)
|
assert await setup_mocked_integration(hass)
|
||||||
|
BMWDataUpdateCoordinator.async_update_listeners.reset_mock()
|
||||||
|
|
||||||
# Setup exception
|
# Setup exception
|
||||||
monkeypatch.setattr(
|
monkeypatch.setattr(
|
||||||
@ -121,3 +129,4 @@ async def test_update_triggers_exceptions(
|
|||||||
target={"entity_id": "number.i4_edrive40_target_soc"},
|
target={"entity_id": "number.i4_edrive40_target_soc"},
|
||||||
)
|
)
|
||||||
assert RemoteServices.trigger_remote_service.call_count == 1
|
assert RemoteServices.trigger_remote_service.call_count == 1
|
||||||
|
assert BMWDataUpdateCoordinator.async_update_listeners.call_count == 0
|
||||||
|
@ -4,6 +4,9 @@ import pytest
|
|||||||
import respx
|
import respx
|
||||||
from syrupy.assertion import SnapshotAssertion
|
from syrupy.assertion import SnapshotAssertion
|
||||||
|
|
||||||
|
from homeassistant.components.bmw_connected_drive.coordinator import (
|
||||||
|
BMWDataUpdateCoordinator,
|
||||||
|
)
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
|
|
||||||
from . import setup_mocked_integration
|
from . import setup_mocked_integration
|
||||||
@ -41,6 +44,7 @@ async def test_update_triggers_success(
|
|||||||
|
|
||||||
# Setup component
|
# Setup component
|
||||||
assert await setup_mocked_integration(hass)
|
assert await setup_mocked_integration(hass)
|
||||||
|
BMWDataUpdateCoordinator.async_update_listeners.reset_mock()
|
||||||
|
|
||||||
# Test
|
# Test
|
||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
@ -51,6 +55,7 @@ async def test_update_triggers_success(
|
|||||||
target={"entity_id": entity_id},
|
target={"entity_id": entity_id},
|
||||||
)
|
)
|
||||||
assert RemoteServices.trigger_remote_service.call_count == 1
|
assert RemoteServices.trigger_remote_service.call_count == 1
|
||||||
|
assert BMWDataUpdateCoordinator.async_update_listeners.call_count == 1
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
@ -69,6 +74,7 @@ async def test_update_triggers_fail(
|
|||||||
|
|
||||||
# Setup component
|
# Setup component
|
||||||
assert await setup_mocked_integration(hass)
|
assert await setup_mocked_integration(hass)
|
||||||
|
BMWDataUpdateCoordinator.async_update_listeners.reset_mock()
|
||||||
|
|
||||||
# Test
|
# Test
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
@ -80,3 +86,4 @@ async def test_update_triggers_fail(
|
|||||||
target={"entity_id": entity_id},
|
target={"entity_id": entity_id},
|
||||||
)
|
)
|
||||||
assert RemoteServices.trigger_remote_service.call_count == 0
|
assert RemoteServices.trigger_remote_service.call_count == 0
|
||||||
|
assert BMWDataUpdateCoordinator.async_update_listeners.call_count == 0
|
||||||
|
@ -7,6 +7,9 @@ import pytest
|
|||||||
import respx
|
import respx
|
||||||
from syrupy.assertion import SnapshotAssertion
|
from syrupy.assertion import SnapshotAssertion
|
||||||
|
|
||||||
|
from homeassistant.components.bmw_connected_drive.coordinator import (
|
||||||
|
BMWDataUpdateCoordinator,
|
||||||
|
)
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.exceptions import HomeAssistantError
|
from homeassistant.exceptions import HomeAssistantError
|
||||||
|
|
||||||
@ -22,6 +25,7 @@ async def test_entity_state_attrs(
|
|||||||
|
|
||||||
# Setup component
|
# Setup component
|
||||||
assert await setup_mocked_integration(hass)
|
assert await setup_mocked_integration(hass)
|
||||||
|
BMWDataUpdateCoordinator.async_update_listeners.reset_mock()
|
||||||
|
|
||||||
# Get all switch entities
|
# Get all switch entities
|
||||||
assert hass.states.async_all("switch") == snapshot
|
assert hass.states.async_all("switch") == snapshot
|
||||||
@ -44,6 +48,7 @@ async def test_update_triggers_success(
|
|||||||
|
|
||||||
# Setup component
|
# Setup component
|
||||||
assert await setup_mocked_integration(hass)
|
assert await setup_mocked_integration(hass)
|
||||||
|
BMWDataUpdateCoordinator.async_update_listeners.reset_mock()
|
||||||
|
|
||||||
# Test
|
# Test
|
||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
@ -53,6 +58,7 @@ async def test_update_triggers_success(
|
|||||||
target={"entity_id": entity_id},
|
target={"entity_id": entity_id},
|
||||||
)
|
)
|
||||||
assert RemoteServices.trigger_remote_service.call_count == 1
|
assert RemoteServices.trigger_remote_service.call_count == 1
|
||||||
|
assert BMWDataUpdateCoordinator.async_update_listeners.call_count == 1
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
@ -74,6 +80,7 @@ async def test_update_triggers_exceptions(
|
|||||||
|
|
||||||
# Setup component
|
# Setup component
|
||||||
assert await setup_mocked_integration(hass)
|
assert await setup_mocked_integration(hass)
|
||||||
|
BMWDataUpdateCoordinator.async_update_listeners.reset_mock()
|
||||||
|
|
||||||
# Setup exception
|
# Setup exception
|
||||||
monkeypatch.setattr(
|
monkeypatch.setattr(
|
||||||
@ -98,3 +105,4 @@ async def test_update_triggers_exceptions(
|
|||||||
target={"entity_id": "switch.i4_edrive40_climate"},
|
target={"entity_id": "switch.i4_edrive40_climate"},
|
||||||
)
|
)
|
||||||
assert RemoteServices.trigger_remote_service.call_count == 2
|
assert RemoteServices.trigger_remote_service.call_count == 2
|
||||||
|
assert BMWDataUpdateCoordinator.async_update_listeners.call_count == 0
|
||||||
|
Loading…
x
Reference in New Issue
Block a user