mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 19:27:45 +00:00
Re-add "deactivate air conditioning" button to bmw_connected_drive (#94765)
This commit is contained in:
parent
2092bd225d
commit
f1a54a510c
@ -124,7 +124,6 @@ omit =
|
||||
homeassistant/components/bluetooth_tracker/*
|
||||
homeassistant/components/bmw_connected_drive/__init__.py
|
||||
homeassistant/components/bmw_connected_drive/binary_sensor.py
|
||||
homeassistant/components/bmw_connected_drive/button.py
|
||||
homeassistant/components/bmw_connected_drive/coordinator.py
|
||||
homeassistant/components/bmw_connected_drive/lock.py
|
||||
homeassistant/components/bmw_connected_drive/notify.py
|
||||
|
@ -34,6 +34,7 @@ class BMWButtonEntityDescription(ButtonEntityDescription):
|
||||
[MyBMWVehicle], Coroutine[Any, Any, RemoteServiceStatus]
|
||||
] | None = None
|
||||
account_function: Callable[[BMWDataUpdateCoordinator], Coroutine] | None = None
|
||||
is_available: Callable[[MyBMWVehicle], bool] = lambda _: True
|
||||
|
||||
|
||||
BUTTON_TYPES: tuple[BMWButtonEntityDescription, ...] = (
|
||||
@ -55,6 +56,13 @@ BUTTON_TYPES: tuple[BMWButtonEntityDescription, ...] = (
|
||||
icon="mdi:hvac",
|
||||
remote_function=lambda vehicle: vehicle.remote_services.trigger_remote_air_conditioning(),
|
||||
),
|
||||
BMWButtonEntityDescription(
|
||||
key="deactivate_air_conditioning",
|
||||
icon="mdi:hvac-off",
|
||||
name="Deactivate air conditioning",
|
||||
remote_function=lambda vehicle: vehicle.remote_services.trigger_remote_air_conditioning_stop(),
|
||||
is_available=lambda vehicle: vehicle.is_remote_climate_stop_enabled,
|
||||
),
|
||||
BMWButtonEntityDescription(
|
||||
key="find_vehicle",
|
||||
translation_key="find_vehicle",
|
||||
@ -86,7 +94,7 @@ async def async_setup_entry(
|
||||
[
|
||||
BMWButton(coordinator, vehicle, description)
|
||||
for description in BUTTON_TYPES
|
||||
if not coordinator.read_only
|
||||
if (not coordinator.read_only and description.is_available(vehicle))
|
||||
or (coordinator.read_only and description.enabled_when_read_only)
|
||||
]
|
||||
)
|
||||
|
@ -1,9 +1,11 @@
|
||||
"""Tests for the for the BMW Connected Drive integration."""
|
||||
|
||||
from pathlib import Path
|
||||
from urllib.parse import urlparse
|
||||
|
||||
from bimmer_connected.api.authentication import MyBMWAuthentication
|
||||
from bimmer_connected.const import (
|
||||
REMOTE_SERVICE_POSITION_URL,
|
||||
VEHICLE_CHARGING_DETAILS_URL,
|
||||
VEHICLE_STATE_URL,
|
||||
VEHICLES_URL,
|
||||
@ -115,6 +117,18 @@ def mock_vehicles() -> respx.Router:
|
||||
router.get(VEHICLE_CHARGING_DETAILS_URL).mock(
|
||||
side_effect=vehicle_charging_sideeffect
|
||||
)
|
||||
|
||||
# Get vehicle position after remote service
|
||||
router.post(urlparse(REMOTE_SERVICE_POSITION_URL).netloc).mock(
|
||||
httpx.Response(
|
||||
200,
|
||||
json=load_json_object_fixture(
|
||||
FIXTURE_PATH / "remote_service" / "eventposition.json",
|
||||
integration=BMW_DOMAIN,
|
||||
),
|
||||
)
|
||||
)
|
||||
|
||||
return router
|
||||
|
||||
|
||||
|
@ -0,0 +1,12 @@
|
||||
{
|
||||
"positionData": {
|
||||
"status": "OK",
|
||||
"position": {
|
||||
"latitude": 123.456,
|
||||
"longitude": 34.5678,
|
||||
"formattedAddress": "some_formatted_address",
|
||||
"heading": 121
|
||||
}
|
||||
},
|
||||
"errorDetails": null
|
||||
}
|
137
tests/components/bmw_connected_drive/snapshots/test_button.ambr
Normal file
137
tests/components/bmw_connected_drive/snapshots/test_button.ambr
Normal file
@ -0,0 +1,137 @@
|
||||
# serializer version: 1
|
||||
# name: test_entity_state_attrs
|
||||
list([
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'attribution': 'Data provided by MyBMW',
|
||||
'friendly_name': 'i4 eDrive40 Flash lights',
|
||||
'icon': 'mdi:car-light-alert',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'button.i4_edrive40_flash_lights',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'unknown',
|
||||
}),
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'attribution': 'Data provided by MyBMW',
|
||||
'friendly_name': 'i4 eDrive40 Sound horn',
|
||||
'icon': 'mdi:bullhorn',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'button.i4_edrive40_sound_horn',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'unknown',
|
||||
}),
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'attribution': 'Data provided by MyBMW',
|
||||
'friendly_name': 'i4 eDrive40 Activate air conditioning',
|
||||
'icon': 'mdi:hvac',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'button.i4_edrive40_activate_air_conditioning',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'unknown',
|
||||
}),
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'attribution': 'Data provided by MyBMW',
|
||||
'friendly_name': 'i4 eDrive40 Deactivate air conditioning',
|
||||
'icon': 'mdi:hvac-off',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'button.i4_edrive40_deactivate_air_conditioning',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'unknown',
|
||||
}),
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'attribution': 'Data provided by MyBMW',
|
||||
'friendly_name': 'i4 eDrive40 Find vehicle',
|
||||
'icon': 'mdi:crosshairs-question',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'button.i4_edrive40_find_vehicle',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'unknown',
|
||||
}),
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'attribution': 'Data provided by MyBMW',
|
||||
'friendly_name': 'i4 eDrive40 Refresh from cloud',
|
||||
'icon': 'mdi:refresh',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'button.i4_edrive40_refresh_from_cloud',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'unknown',
|
||||
}),
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'attribution': 'Data provided by MyBMW',
|
||||
'friendly_name': 'i3 (+ REX) Flash lights',
|
||||
'icon': 'mdi:car-light-alert',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'button.i3_rex_flash_lights',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'unknown',
|
||||
}),
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'attribution': 'Data provided by MyBMW',
|
||||
'friendly_name': 'i3 (+ REX) Sound horn',
|
||||
'icon': 'mdi:bullhorn',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'button.i3_rex_sound_horn',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'unknown',
|
||||
}),
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'attribution': 'Data provided by MyBMW',
|
||||
'friendly_name': 'i3 (+ REX) Activate air conditioning',
|
||||
'icon': 'mdi:hvac',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'button.i3_rex_activate_air_conditioning',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'unknown',
|
||||
}),
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'attribution': 'Data provided by MyBMW',
|
||||
'friendly_name': 'i3 (+ REX) Find vehicle',
|
||||
'icon': 'mdi:crosshairs-question',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'button.i3_rex_find_vehicle',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'unknown',
|
||||
}),
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'attribution': 'Data provided by MyBMW',
|
||||
'friendly_name': 'i3 (+ REX) Refresh from cloud',
|
||||
'icon': 'mdi:refresh',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'button.i3_rex_refresh_from_cloud',
|
||||
'last_changed': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'unknown',
|
||||
}),
|
||||
])
|
||||
# ---
|
79
tests/components/bmw_connected_drive/test_button.py
Normal file
79
tests/components/bmw_connected_drive/test_button.py
Normal file
@ -0,0 +1,79 @@
|
||||
"""Test BMW buttons."""
|
||||
from bimmer_connected.vehicle.remote_services import RemoteServices
|
||||
import pytest
|
||||
import respx
|
||||
from syrupy.assertion import SnapshotAssertion
|
||||
|
||||
from homeassistant.components.bmw_connected_drive.coordinator import (
|
||||
BMWDataUpdateCoordinator,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
from . import setup_mocked_integration
|
||||
|
||||
|
||||
async def test_entity_state_attrs(
|
||||
hass: HomeAssistant,
|
||||
bmw_fixture: respx.Router,
|
||||
snapshot: SnapshotAssertion,
|
||||
) -> None:
|
||||
"""Test button options and values."""
|
||||
|
||||
# Setup component
|
||||
assert await setup_mocked_integration(hass)
|
||||
|
||||
# Get all button entities
|
||||
assert hass.states.async_all("button") == snapshot
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("entity_id"),
|
||||
[
|
||||
("button.i4_edrive40_flash_lights"),
|
||||
("button.i4_edrive40_sound_horn"),
|
||||
("button.i4_edrive40_activate_air_conditioning"),
|
||||
("button.i4_edrive40_deactivate_air_conditioning"),
|
||||
("button.i4_edrive40_find_vehicle"),
|
||||
],
|
||||
)
|
||||
async def test_update_triggers_success(
|
||||
hass: HomeAssistant,
|
||||
entity_id: str,
|
||||
bmw_fixture: respx.Router,
|
||||
) -> None:
|
||||
"""Test button press."""
|
||||
|
||||
# Setup component
|
||||
assert await setup_mocked_integration(hass)
|
||||
BMWDataUpdateCoordinator.async_update_listeners.reset_mock()
|
||||
|
||||
# Test
|
||||
await hass.services.async_call(
|
||||
"button",
|
||||
"press",
|
||||
blocking=True,
|
||||
target={"entity_id": entity_id},
|
||||
)
|
||||
assert RemoteServices.trigger_remote_service.call_count == 1
|
||||
assert BMWDataUpdateCoordinator.async_update_listeners.call_count == 1
|
||||
|
||||
|
||||
async def test_refresh_from_cloud(
|
||||
hass: HomeAssistant,
|
||||
bmw_fixture: respx.Router,
|
||||
) -> None:
|
||||
"""Test button press for deprecated service."""
|
||||
|
||||
# Setup component
|
||||
assert await setup_mocked_integration(hass)
|
||||
BMWDataUpdateCoordinator.async_update_listeners.reset_mock()
|
||||
|
||||
# Test
|
||||
await hass.services.async_call(
|
||||
"button",
|
||||
"press",
|
||||
blocking=True,
|
||||
target={"entity_id": "button.i4_edrive40_refresh_from_cloud"},
|
||||
)
|
||||
assert RemoteServices.trigger_remote_service.call_count == 0
|
||||
assert BMWDataUpdateCoordinator.async_update_listeners.call_count == 2
|
Loading…
x
Reference in New Issue
Block a user