From 307ae5306682efc3439d55ed6ef7f8fab51e5744 Mon Sep 17 00:00:00 2001 From: Brett Adams Date: Thu, 11 Jul 2024 17:03:46 +1000 Subject: [PATCH] Add sunroof to Tessie (#121743) --- homeassistant/components/tessie/cover.py | 59 ++++++++++++-- homeassistant/components/tessie/strings.json | 3 + tests/components/tessie/fixtures/online.json | 2 +- .../components/tessie/fixtures/vehicles.json | 2 +- .../tessie/snapshots/test_cover.ambr | 81 +++++++++++++++++++ .../tessie/snapshots/test_diagnostics.ambr | 2 +- tests/components/tessie/test_cover.py | 1 + 7 files changed, 140 insertions(+), 10 deletions(-) diff --git a/homeassistant/components/tessie/cover.py b/homeassistant/components/tessie/cover.py index 6fdd950b809..109bdbce2bf 100644 --- a/homeassistant/components/tessie/cover.py +++ b/homeassistant/components/tessie/cover.py @@ -2,14 +2,17 @@ from __future__ import annotations +from itertools import chain from typing import Any from tessie_api import ( close_charge_port, + close_sunroof, close_windows, open_close_rear_trunk, open_front_trunk, open_unlock_charge_port, + vent_sunroof, vent_windows, ) @@ -36,14 +39,25 @@ async def async_setup_entry( data = entry.runtime_data async_add_entities( - klass(vehicle) - for klass in ( - TessieWindowEntity, - TessieChargePortEntity, - TessieFrontTrunkEntity, - TessieRearTrunkEntity, + chain( + ( + klass(vehicle) + for klass in ( + TessieWindowEntity, + TessieChargePortEntity, + TessieFrontTrunkEntity, + TessieRearTrunkEntity, + ) + for vehicle in data.vehicles + ), + ( + TessieSunroofEntity(vehicle) + for vehicle in data.vehicles + if vehicle.data_coordinator.data.get( + "vehicle_config_sun_roof_installed" + ) + ), ) - for vehicle in data.vehicles ) @@ -161,3 +175,34 @@ class TessieRearTrunkEntity(TessieEntity, CoverEntity): if self._value == TessieCoverStates.OPEN: await self.run(open_close_rear_trunk) self.set((self.key, TessieCoverStates.CLOSED)) + + +class TessieSunroofEntity(TessieEntity, CoverEntity): + """Cover entity for the sunroof.""" + + _attr_device_class = CoverDeviceClass.WINDOW + _attr_supported_features = CoverEntityFeature.OPEN | CoverEntityFeature.CLOSE + + def __init__(self, vehicle: TessieVehicleData) -> None: + """Initialize the sensor.""" + super().__init__(vehicle, "vehicle_state_sun_roof_state") + + @property + def is_closed(self) -> bool | None: + """Return if the cover is closed or not.""" + return self._value == TessieCoverStates.CLOSED + + @property + def current_cover_position(self) -> bool | None: + """Return the percentage open.""" + return self.get("vehicle_state_sun_roof_percent_open") + + async def async_open_cover(self, **kwargs: Any) -> None: + """Open sunroof.""" + await self.run(vent_sunroof) + self.set((self.key, TessieCoverStates.OPEN)) + + async def async_close_cover(self, **kwargs: Any) -> None: + """Close sunroof.""" + await self.run(close_sunroof) + self.set((self.key, TessieCoverStates.CLOSED)) diff --git a/homeassistant/components/tessie/strings.json b/homeassistant/components/tessie/strings.json index 873c8ba055e..dd8ac39f4e5 100644 --- a/homeassistant/components/tessie/strings.json +++ b/homeassistant/components/tessie/strings.json @@ -235,6 +235,9 @@ }, "vehicle_state_rt": { "name": "Trunk" + }, + "vehicle_state_sun_roof_state": { + "name": "Sunroof" } }, "select": { diff --git a/tests/components/tessie/fixtures/online.json b/tests/components/tessie/fixtures/online.json index ed49b4bfd75..c81a84e6c1b 100644 --- a/tests/components/tessie/fixtures/online.json +++ b/tests/components/tessie/fixtures/online.json @@ -173,7 +173,7 @@ "roof_color": "RoofColorGlass", "seat_type": null, "spoiler_type": "None", - "sun_roof_installed": null, + "sun_roof_installed": true, "supports_qr_pairing": false, "third_row_seats": "None", "timestamp": 1701139037461, diff --git a/tests/components/tessie/fixtures/vehicles.json b/tests/components/tessie/fixtures/vehicles.json index 359e23f9cdd..e43fb0a7b1d 100644 --- a/tests/components/tessie/fixtures/vehicles.json +++ b/tests/components/tessie/fixtures/vehicles.json @@ -190,7 +190,7 @@ "roof_color": "RoofColorGlass", "seat_type": null, "spoiler_type": "None", - "sun_roof_installed": null, + "sun_roof_installed": true, "supports_qr_pairing": false, "third_row_seats": "None", "timestamp": 1701139037461, diff --git a/tests/components/tessie/snapshots/test_cover.ambr b/tests/components/tessie/snapshots/test_cover.ambr index ff04c528244..8c8c9a48c11 100644 --- a/tests/components/tessie/snapshots/test_cover.ambr +++ b/tests/components/tessie/snapshots/test_cover.ambr @@ -95,6 +95,87 @@ 'state': 'closed', }) # --- +# name: test_covers[cover.test_none-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'cover', + 'entity_category': None, + 'entity_id': 'cover.test_none', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': None, + 'platform': 'tessie', + 'previous_unique_id': None, + 'supported_features': , + 'translation_key': 'vehicle_state_sun_roof_state', + 'unique_id': 'VINVINVIN-vehicle_state_sun_roof_state', + 'unit_of_measurement': None, + }) +# --- +# name: test_covers[cover.test_sunroof-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'cover', + 'entity_category': None, + 'entity_id': 'cover.test_sunroof', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Sunroof', + 'platform': 'tessie', + 'previous_unique_id': None, + 'supported_features': , + 'translation_key': 'vehicle_state_sun_roof_state', + 'unique_id': 'VINVINVIN-vehicle_state_sun_roof_state', + 'unit_of_measurement': None, + }) +# --- +# name: test_covers[cover.test_sunroof-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'window', + 'friendly_name': 'Test Sunroof', + 'supported_features': , + }), + 'context': , + 'entity_id': 'cover.test_sunroof', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'open', + }) +# --- # name: test_covers[cover.test_trunk-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ diff --git a/tests/components/tessie/snapshots/test_diagnostics.ambr b/tests/components/tessie/snapshots/test_diagnostics.ambr index a399f56c94d..24e1374f63a 100644 --- a/tests/components/tessie/snapshots/test_diagnostics.ambr +++ b/tests/components/tessie/snapshots/test_diagnostics.ambr @@ -329,7 +329,7 @@ 'vehicle_config_roof_color': 'RoofColorGlass', 'vehicle_config_seat_type': None, 'vehicle_config_spoiler_type': 'None', - 'vehicle_config_sun_roof_installed': None, + 'vehicle_config_sun_roof_installed': True, 'vehicle_config_supports_qr_pairing': False, 'vehicle_config_third_row_seats': 'None', 'vehicle_config_timestamp': 1701139037461, diff --git a/tests/components/tessie/test_cover.py b/tests/components/tessie/test_cover.py index b731add10f8..be4dda3ec7b 100644 --- a/tests/components/tessie/test_cover.py +++ b/tests/components/tessie/test_cover.py @@ -42,6 +42,7 @@ async def test_covers( ("cover.test_charge_port_door", "open_unlock_charge_port", "close_charge_port"), ("cover.test_frunk", "open_front_trunk", False), ("cover.test_trunk", "open_close_rear_trunk", "open_close_rear_trunk"), + ("cover.test_sunroof", "vent_sunroof", "close_sunroof"), ): # Test open windows if openfunc: