Add button platform to Tessie (#106210)

This commit is contained in:
Brett Adams 2023-12-22 12:40:55 +10:00 committed by GitHub
parent e86ac568e1
commit 8918a9c2c4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 133 additions and 1 deletions

View File

@ -16,6 +16,7 @@ from .coordinator import TessieDataUpdateCoordinator
PLATFORMS = [
Platform.BINARY_SENSOR,
Platform.BUTTON,
Platform.CLIMATE,
Platform.DEVICE_TRACKER,
Platform.SELECT,

View File

@ -0,0 +1,84 @@
"""Button platform for Tessie integration."""
from __future__ import annotations
from collections.abc import Callable
from dataclasses import dataclass
from tessie_api import (
boombox,
enable_keyless_driving,
flash_lights,
honk,
open_close_rear_trunk,
open_front_trunk,
trigger_homelink,
wake,
)
from homeassistant.components.button import ButtonEntity, ButtonEntityDescription
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from .const import DOMAIN
from .coordinator import TessieDataUpdateCoordinator
from .entity import TessieEntity
@dataclass(frozen=True, kw_only=True)
class TessieButtonEntityDescription(ButtonEntityDescription):
"""Describes a Tessie Button entity."""
func: Callable
DESCRIPTIONS: tuple[TessieButtonEntityDescription, ...] = (
TessieButtonEntityDescription(key="wake", func=wake, icon="mdi:sleep-off"),
TessieButtonEntityDescription(
key="flash_lights", func=flash_lights, icon="mdi:flashlight"
),
TessieButtonEntityDescription(key="honk", func=honk, icon="mdi:bullhorn"),
TessieButtonEntityDescription(
key="trigger_homelink", func=trigger_homelink, icon="mdi:garage"
),
TessieButtonEntityDescription(
key="enable_keyless_driving", func=enable_keyless_driving, icon="mdi:car-key"
),
TessieButtonEntityDescription(key="boombox", func=boombox, icon="mdi:volume-high"),
TessieButtonEntityDescription(key="frunk", func=open_front_trunk, icon="mdi:car"),
TessieButtonEntityDescription(
key="trunk", func=open_close_rear_trunk, icon="mdi:car-back"
),
)
async def async_setup_entry(
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
) -> None:
"""Set up the Tessie Button platform from a config entry."""
coordinators = hass.data[DOMAIN][entry.entry_id]
async_add_entities(
TessieButtonEntity(coordinator, description)
for coordinator in coordinators
for description in DESCRIPTIONS
)
class TessieButtonEntity(TessieEntity, ButtonEntity):
"""Base class for Tessie Buttons."""
entity_description: TessieButtonEntityDescription
def __init__(
self,
coordinator: TessieDataUpdateCoordinator,
description: TessieButtonEntityDescription,
) -> None:
"""Initialize the Button."""
super().__init__(coordinator, description.key)
self.entity_description = description
async def async_press(self) -> None:
"""Press the button."""
await self.run(self.entity_description.func)

View File

@ -241,6 +241,14 @@
"name": "Tire pressure warning rear right"
}
},
"button": {
"wake": { "name": "Wake" },
"flash_lights": { "name": "Flash lights" },
"honk": { "name": "Honk horn" },
"trigger_homelink": { "name": "Homelink" },
"enable_keyless_driving": { "name": "Keyless driving" },
"boombox": { "name": "Play fart" }
},
"switch": {
"charge_state_charge_enable_request": {
"name": "Charge"

View File

@ -1,7 +1,8 @@
"""Tessie common helpers for tests."""
from contextlib import contextmanager
from http import HTTPStatus
from unittest.mock import patch
from unittest.mock import AsyncMock, patch
from aiohttp import ClientConnectionError, ClientResponseError
from aiohttp.client import RequestInfo
@ -9,6 +10,7 @@ from aiohttp.client import RequestInfo
from homeassistant.components.tessie.const import DOMAIN
from homeassistant.const import CONF_ACCESS_TOKEN
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity import EntityDescription
from tests.common import MockConfigEntry, load_json_object_fixture
@ -54,3 +56,16 @@ async def setup_platform(hass: HomeAssistant, side_effect=None):
await hass.async_block_till_done()
return mock_entry
@contextmanager
def patch_description(
key: str, attr: str, descriptions: tuple[EntityDescription]
) -> AsyncMock:
"""Patch a description."""
to_patch = next(filter(lambda x: x.key == key, descriptions))
original = to_patch.func
mock = AsyncMock()
object.__setattr__(to_patch, attr, mock)
yield mock
object.__setattr__(to_patch, attr, original)

View File

@ -0,0 +1,24 @@
"""Test the Tessie button platform."""
from homeassistant.components.button import DOMAIN as BUTTON_DOMAIN, SERVICE_PRESS
from homeassistant.components.tessie.button import DESCRIPTIONS
from homeassistant.const import ATTR_ENTITY_ID
from homeassistant.core import HomeAssistant
from .common import patch_description, setup_platform
async def test_buttons(hass: HomeAssistant) -> None:
"""Tests that the buttons are correct."""
await setup_platform(hass)
# Test wake button
with patch_description("wake", "func", DESCRIPTIONS) as mock_wake:
await hass.services.async_call(
BUTTON_DOMAIN,
SERVICE_PRESS,
{ATTR_ENTITY_ID: ["button.test_wake"]},
blocking=True,
)
mock_wake.assert_called_once()