Move Freebox reboot service to a button entity (#65501)

* Add restart button to freebox

* Add warning

* restart => reboot

* Add button tests

Co-authored-by: epenet <epenet@users.noreply.github.com>
This commit is contained in:
epenet 2022-02-09 22:20:24 +01:00 committed by GitHub
parent f4aaa981a1
commit cc5bb556c8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 130 additions and 1 deletions

View file

@ -1,5 +1,6 @@
"""Support for Freebox devices (Freebox v6 and Freebox mini 4K)."""
from datetime import timedelta
import logging
from freebox_api.exceptions import HttpRequestError
import voluptuous as vol
@ -29,6 +30,8 @@ CONFIG_SCHEMA = vol.Schema(
SCAN_INTERVAL = timedelta(seconds=30)
_LOGGER = logging.getLogger(__name__)
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
"""Set up the Freebox integration."""
@ -67,6 +70,13 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
# Services
async def async_reboot(call: ServiceCall) -> None:
"""Handle reboot service call."""
# The Freebox reboot service has been replaced by a
# dedicated button entity and marked as deprecated
_LOGGER.warning(
"The 'freebox.reboot' service is deprecated and "
"replaced by a dedicated reboot button entity; please "
"use that entity to reboot the freebox instead"
)
await router.reboot()
hass.services.async_register(DOMAIN, SERVICE_REBOOT, async_reboot)

View file

@ -0,0 +1,76 @@
"""Support for Freebox devices (Freebox v6 and Freebox mini 4K)."""
from __future__ import annotations
from collections.abc import Awaitable, Callable
from dataclasses import dataclass
from homeassistant.components.button import (
ButtonDeviceClass,
ButtonEntity,
ButtonEntityDescription,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity import DeviceInfo
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from .const import DOMAIN
from .router import FreeboxRouter
@dataclass
class FreeboxButtonRequiredKeysMixin:
"""Mixin for required keys."""
async_press: Callable[[FreeboxRouter], Awaitable]
@dataclass
class FreeboxButtonEntityDescription(
ButtonEntityDescription, FreeboxButtonRequiredKeysMixin
):
"""Class describing Freebox button entities."""
BUTTON_DESCRIPTIONS: tuple[FreeboxButtonEntityDescription, ...] = (
FreeboxButtonEntityDescription(
key="reboot",
name="Reboot Freebox",
device_class=ButtonDeviceClass.RESTART,
async_press=lambda router: router.reboot(),
),
)
async def async_setup_entry(
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
) -> None:
"""Set up the buttons."""
router: FreeboxRouter = hass.data[DOMAIN][entry.unique_id]
entities = [
FreeboxButton(router, description) for description in BUTTON_DESCRIPTIONS
]
async_add_entities(entities, True)
class FreeboxButton(ButtonEntity):
"""Representation of a Freebox button."""
entity_description: FreeboxButtonEntityDescription
def __init__(
self, router: FreeboxRouter, description: FreeboxButtonEntityDescription
) -> None:
"""Initialize a Freebox button."""
self.entity_description = description
self._router = router
self._attr_unique_id = f"{router.mac} {description.name}"
@property
def device_info(self) -> DeviceInfo:
"""Return the device information."""
return self._router.device_info
async def async_press(self) -> None:
"""Press the button."""
await self.entity_description.async_press(self._router)

View file

@ -17,7 +17,7 @@ APP_DESC = {
}
API_VERSION = "v6"
PLATFORMS = [Platform.DEVICE_TRACKER, Platform.SENSOR, Platform.SWITCH]
PLATFORMS = [Platform.BUTTON, Platform.DEVICE_TRACKER, Platform.SENSOR, Platform.SWITCH]
DEFAULT_DEVICE_NAME = "Unknown device"

View file

@ -0,0 +1,43 @@
"""Tests for the Freebox config flow."""
from unittest.mock import Mock, patch
from homeassistant.components.button import DOMAIN as BUTTON_DOMAIN
from homeassistant.components.button.const import SERVICE_PRESS
from homeassistant.components.freebox.const import DOMAIN
from homeassistant.const import ATTR_ENTITY_ID, CONF_HOST, CONF_PORT
from homeassistant.core import HomeAssistant
from homeassistant.setup import async_setup_component
from .const import MOCK_HOST, MOCK_PORT
from tests.common import MockConfigEntry
async def test_reboot_button(hass: HomeAssistant, router: Mock):
"""Test reboot button."""
entry = MockConfigEntry(
domain=DOMAIN,
data={CONF_HOST: MOCK_HOST, CONF_PORT: MOCK_PORT},
unique_id=MOCK_HOST,
)
entry.add_to_hass(hass)
assert await async_setup_component(hass, DOMAIN, {})
await hass.async_block_till_done()
assert hass.config_entries.async_entries() == [entry]
assert router.call_count == 1
assert router().open.call_count == 1
with patch(
"homeassistant.components.freebox.router.FreeboxRouter.reboot"
) as mock_service:
await hass.services.async_call(
BUTTON_DOMAIN,
SERVICE_PRESS,
service_data={
ATTR_ENTITY_ID: "button.reboot_freebox",
},
blocking=True,
)
await hass.async_block_till_done()
mock_service.assert_called_once()