1
0
mirror of https://github.com/home-assistant/core.git synced 2026-07-03 20:56:06 +01:00

Add seat coolers to Teslemetry (#175422)

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Brett Adams
2026-07-04 02:49:18 +10:00
committed by GitHub
parent 02aaf56dc1
commit 89a92be9d7
3 changed files with 108 additions and 1 deletions
@@ -176,6 +176,33 @@ VEHICLE_DESCRIPTIONS: tuple[TeslemetrySelectEntityDescription, ...] = (
HIGH,
],
),
TeslemetrySelectEntityDescription(
# remote_seat_cooler_request uses 1-indexed positions (front-left=1,
# front-right=2), unlike the 0-indexed Seat enum used for heaters.
# Polled state comes from the seat_fan_front_* vehicle_data fields.
key="climate_state_seat_fan_front_left",
select_fn=lambda api, level: api.remote_seat_cooler_request(1, level),
supported_fn=lambda data: bool(data.get("has_seat_cooling")),
streaming_listener=lambda x, y: x.listen_ClimateSeatCoolingFrontLeft(y),
options=[
OFF,
LOW,
MEDIUM,
HIGH,
],
),
TeslemetrySelectEntityDescription(
key="climate_state_seat_fan_front_right",
select_fn=lambda api, level: api.remote_seat_cooler_request(2, level),
supported_fn=lambda data: bool(data.get("has_seat_cooling")),
streaming_listener=lambda x, y: x.listen_ClimateSeatCoolingFrontRight(y),
options=[
OFF,
LOW,
MEDIUM,
HIGH,
],
),
)
@@ -363,6 +363,24 @@
}
},
"select": {
"climate_state_seat_fan_front_left": {
"name": "Seat cooler front left",
"state": {
"high": "[%key:common::state::high%]",
"low": "[%key:common::state::low%]",
"medium": "[%key:common::state::medium%]",
"off": "[%key:common::state::off%]"
}
},
"climate_state_seat_fan_front_right": {
"name": "Seat cooler front right",
"state": {
"high": "[%key:common::state::high%]",
"low": "[%key:common::state::low%]",
"medium": "[%key:common::state::medium%]",
"off": "[%key:common::state::off%]"
}
},
"climate_state_seat_heater_left": {
"name": "Seat heater front left",
"state": {
+63 -1
View File
@@ -16,7 +16,7 @@ from homeassistant.components.select import (
SERVICE_SELECT_OPTION,
)
from homeassistant.components.teslemetry.coordinator import ENERGY_INFO_INTERVAL
from homeassistant.components.teslemetry.select import LOW
from homeassistant.components.teslemetry.select import LEVEL, LOW, MEDIUM, OFF
from homeassistant.const import ATTR_ENTITY_ID, STATE_UNKNOWN, Platform
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
@@ -183,6 +183,68 @@ async def test_select_services(hass: HomeAssistant, mock_vehicle_data) -> None:
call.assert_called_once()
@pytest.mark.parametrize(
("entity_id", "seat_position"),
[
("select.test_seat_cooler_front_left", 1),
("select.test_seat_cooler_front_right", 2),
],
)
async def test_seat_cooler_services(
hass: HomeAssistant,
mock_metadata: AsyncMock,
mock_vehicle_data: AsyncMock,
entity_id: str,
seat_position: int,
) -> None:
"""Test the seat cooler entities send the 1-indexed seat position.
remote_seat_cooler_request is 1-indexed (front-left=1, front-right=2),
unlike the 0-indexed Seat enum used for the seat heaters.
"""
mock_vehicle_data.return_value = VEHICLE_DATA_ALT
metadata = deepcopy(METADATA)
metadata["vehicles"][VEHICLE_VIN]["config"] = {"has_seat_cooling": True}
mock_metadata.return_value = metadata
await setup_platform(hass, [Platform.SELECT])
with patch(
"tesla_fleet_api.teslemetry.Vehicle.remote_seat_cooler_request",
return_value=COMMAND_OK,
) as call:
await hass.services.async_call(
SELECT_DOMAIN,
SERVICE_SELECT_OPTION,
{ATTR_ENTITY_ID: entity_id, ATTR_OPTION: LOW},
blocking=True,
)
assert hass.states.get(entity_id).state == LOW
call.assert_called_once_with(seat_position, LEVEL[LOW])
async def test_seat_cooler_polling(
hass: HomeAssistant,
mock_metadata: AsyncMock,
mock_vehicle_data: AsyncMock,
) -> None:
"""Test the seat cooler entities read polled state from seat_fan_front_*."""
metadata = deepcopy(METADATA)
metadata["vehicles"][VEHICLE_VIN]["polling"] = True
metadata["vehicles"][VEHICLE_VIN]["config"] = {"has_seat_cooling": True}
mock_metadata.return_value = metadata
data = deepcopy(VEHICLE_DATA_ALT)
data["response"]["climate_state"]["seat_fan_front_left"] = 2
data["response"]["climate_state"]["seat_fan_front_right"] = 0
mock_vehicle_data.return_value = data
await setup_platform(hass, [Platform.SELECT])
assert hass.states.get("select.test_seat_cooler_front_left").state == MEDIUM
assert hass.states.get("select.test_seat_cooler_front_right").state == OFF
@pytest.mark.parametrize("response", COMMAND_ERRORS)
async def test_select_command_errors(
hass: HomeAssistant, mock_vehicle_data: AsyncMock, response: dict