mirror of
https://github.com/home-assistant/core.git
synced 2025-07-22 20:57:21 +00:00
Add button platform to Tessie (#106210)
This commit is contained in:
parent
e86ac568e1
commit
8918a9c2c4
@ -16,6 +16,7 @@ from .coordinator import TessieDataUpdateCoordinator
|
|||||||
|
|
||||||
PLATFORMS = [
|
PLATFORMS = [
|
||||||
Platform.BINARY_SENSOR,
|
Platform.BINARY_SENSOR,
|
||||||
|
Platform.BUTTON,
|
||||||
Platform.CLIMATE,
|
Platform.CLIMATE,
|
||||||
Platform.DEVICE_TRACKER,
|
Platform.DEVICE_TRACKER,
|
||||||
Platform.SELECT,
|
Platform.SELECT,
|
||||||
|
84
homeassistant/components/tessie/button.py
Normal file
84
homeassistant/components/tessie/button.py
Normal 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)
|
@ -241,6 +241,14 @@
|
|||||||
"name": "Tire pressure warning rear right"
|
"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": {
|
"switch": {
|
||||||
"charge_state_charge_enable_request": {
|
"charge_state_charge_enable_request": {
|
||||||
"name": "Charge"
|
"name": "Charge"
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
"""Tessie common helpers for tests."""
|
"""Tessie common helpers for tests."""
|
||||||
|
|
||||||
|
from contextlib import contextmanager
|
||||||
from http import HTTPStatus
|
from http import HTTPStatus
|
||||||
from unittest.mock import patch
|
from unittest.mock import AsyncMock, patch
|
||||||
|
|
||||||
from aiohttp import ClientConnectionError, ClientResponseError
|
from aiohttp import ClientConnectionError, ClientResponseError
|
||||||
from aiohttp.client import RequestInfo
|
from aiohttp.client import RequestInfo
|
||||||
@ -9,6 +10,7 @@ from aiohttp.client import RequestInfo
|
|||||||
from homeassistant.components.tessie.const import DOMAIN
|
from homeassistant.components.tessie.const import DOMAIN
|
||||||
from homeassistant.const import CONF_ACCESS_TOKEN
|
from homeassistant.const import CONF_ACCESS_TOKEN
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.helpers.entity import EntityDescription
|
||||||
|
|
||||||
from tests.common import MockConfigEntry, load_json_object_fixture
|
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()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
return mock_entry
|
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)
|
||||||
|
24
tests/components/tessie/test_button.py
Normal file
24
tests/components/tessie/test_button.py
Normal 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()
|
Loading…
x
Reference in New Issue
Block a user