mirror of
https://github.com/home-assistant/core.git
synced 2025-04-23 08:47:57 +00:00
Implement a reboot-button for Plugwise (#120554)
Co-authored-by: Franck Nijhof <frenck@frenck.nl>
This commit is contained in:
parent
af9b4b98ca
commit
4defc4a58f
52
homeassistant/components/plugwise/button.py
Normal file
52
homeassistant/components/plugwise/button.py
Normal file
@ -0,0 +1,52 @@
|
||||
"""Plugwise Button component for Home Assistant."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from homeassistant.components.button import ButtonDeviceClass, ButtonEntity
|
||||
from homeassistant.const import EntityCategory
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from . import PlugwiseConfigEntry
|
||||
from .const import GATEWAY_ID, REBOOT
|
||||
from .coordinator import PlugwiseDataUpdateCoordinator
|
||||
from .entity import PlugwiseEntity
|
||||
from .util import plugwise_command
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
entry: PlugwiseConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up the Plugwise buttons from a ConfigEntry."""
|
||||
coordinator = entry.runtime_data
|
||||
|
||||
gateway = coordinator.data.gateway
|
||||
async_add_entities(
|
||||
PlugwiseButtonEntity(coordinator, device_id)
|
||||
for device_id in coordinator.data.devices
|
||||
if device_id == gateway[GATEWAY_ID] and REBOOT in gateway
|
||||
)
|
||||
|
||||
|
||||
class PlugwiseButtonEntity(PlugwiseEntity, ButtonEntity):
|
||||
"""Defines a Plugwise button."""
|
||||
|
||||
_attr_device_class = ButtonDeviceClass.RESTART
|
||||
_attr_entity_category = EntityCategory.CONFIG
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
coordinator: PlugwiseDataUpdateCoordinator,
|
||||
device_id: str,
|
||||
) -> None:
|
||||
"""Initialize the button."""
|
||||
super().__init__(coordinator, device_id)
|
||||
self._attr_translation_key = REBOOT
|
||||
self._attr_unique_id = f"{device_id}-reboot"
|
||||
|
||||
@plugwise_command
|
||||
async def async_press(self) -> None:
|
||||
"""Triggers the Plugwise button press service."""
|
||||
await self.coordinator.api.reboot_gateway()
|
@ -17,14 +17,17 @@ FLOW_SMILE: Final = "smile (Adam/Anna/P1)"
|
||||
FLOW_STRETCH: Final = "stretch (Stretch)"
|
||||
FLOW_TYPE: Final = "flow_type"
|
||||
GATEWAY: Final = "gateway"
|
||||
GATEWAY_ID: Final = "gateway_id"
|
||||
LOCATION: Final = "location"
|
||||
PW_TYPE: Final = "plugwise_type"
|
||||
REBOOT: Final = "reboot"
|
||||
SMILE: Final = "smile"
|
||||
STRETCH: Final = "stretch"
|
||||
STRETCH_USERNAME: Final = "stretch"
|
||||
|
||||
PLATFORMS: Final[list[str]] = [
|
||||
Platform.BINARY_SENSOR,
|
||||
Platform.BUTTON,
|
||||
Platform.CLIMATE,
|
||||
Platform.NUMBER,
|
||||
Platform.SELECT,
|
||||
|
@ -7,6 +7,7 @@ from plugwise.exceptions import (
|
||||
ConnectionFailedError,
|
||||
InvalidAuthentication,
|
||||
InvalidXMLError,
|
||||
PlugwiseError,
|
||||
ResponseError,
|
||||
UnsupportedDeviceError,
|
||||
)
|
||||
@ -64,22 +65,23 @@ class PlugwiseDataUpdateCoordinator(DataUpdateCoordinator[PlugwiseData]):
|
||||
|
||||
async def _async_update_data(self) -> PlugwiseData:
|
||||
"""Fetch data from Plugwise."""
|
||||
|
||||
data = PlugwiseData({}, {})
|
||||
try:
|
||||
if not self._connected:
|
||||
await self._connect()
|
||||
data = await self.api.async_update()
|
||||
except ConnectionFailedError as err:
|
||||
raise UpdateFailed("Failed to connect") from err
|
||||
except InvalidAuthentication as err:
|
||||
raise ConfigEntryError("Invalid username or Smile ID") from err
|
||||
raise ConfigEntryError("Authentication failed") from err
|
||||
except (InvalidXMLError, ResponseError) as err:
|
||||
raise UpdateFailed(
|
||||
"Invalid XML data, or error indication received for the Plugwise"
|
||||
" Adam/Smile/Stretch"
|
||||
"Invalid XML data, or error indication received from the Plugwise Adam/Smile/Stretch"
|
||||
) from err
|
||||
except PlugwiseError as err:
|
||||
raise UpdateFailed("Data incomplete or missing") from err
|
||||
except UnsupportedDeviceError as err:
|
||||
raise ConfigEntryError("Device with unsupported firmware") from err
|
||||
except ConnectionFailedError as err:
|
||||
raise UpdateFailed("Failed to connect to the Plugwise Smile") from err
|
||||
else:
|
||||
self.new_devices = set(data.devices) - self._current_devices
|
||||
self._current_devices = set(data.devices)
|
||||
|
@ -55,6 +55,11 @@
|
||||
"name": "Plugwise notification"
|
||||
}
|
||||
},
|
||||
"button": {
|
||||
"reboot": {
|
||||
"name": "Reboot"
|
||||
}
|
||||
},
|
||||
"climate": {
|
||||
"plugwise": {
|
||||
"state_attributes": {
|
||||
|
39
tests/components/plugwise/test_button.py
Normal file
39
tests/components/plugwise/test_button.py
Normal file
@ -0,0 +1,39 @@
|
||||
"""Tests for Plugwise button entities."""
|
||||
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
from homeassistant.components.button import (
|
||||
DOMAIN as BUTTON_DOMAIN,
|
||||
SERVICE_PRESS,
|
||||
ButtonDeviceClass,
|
||||
)
|
||||
from homeassistant.const import ATTR_DEVICE_CLASS, ATTR_ENTITY_ID, STATE_UNKNOWN
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
|
||||
|
||||
async def test_adam_reboot_button(
|
||||
hass: HomeAssistant, mock_smile_adam: MagicMock, init_integration: MockConfigEntry
|
||||
) -> None:
|
||||
"""Test creation of button entities."""
|
||||
state = hass.states.get("button.adam_reboot")
|
||||
assert state
|
||||
assert state.state == STATE_UNKNOWN
|
||||
assert state.attributes.get(ATTR_DEVICE_CLASS) == ButtonDeviceClass.RESTART
|
||||
|
||||
registry = er.async_get(hass)
|
||||
entry = registry.async_get("button.adam_reboot")
|
||||
assert entry
|
||||
assert entry.unique_id == "fe799307f1624099878210aa0b9f1475-reboot"
|
||||
|
||||
await hass.services.async_call(
|
||||
BUTTON_DOMAIN,
|
||||
SERVICE_PRESS,
|
||||
{ATTR_ENTITY_ID: "button.adam_reboot"},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
assert mock_smile_adam.reboot_gateway.call_count == 1
|
||||
mock_smile_adam.reboot_gateway.assert_called_with()
|
@ -7,6 +7,7 @@ from plugwise.exceptions import (
|
||||
ConnectionFailedError,
|
||||
InvalidAuthentication,
|
||||
InvalidXMLError,
|
||||
PlugwiseError,
|
||||
ResponseError,
|
||||
UnsupportedDeviceError,
|
||||
)
|
||||
@ -83,6 +84,7 @@ async def test_load_unload_config_entry(
|
||||
(ConnectionFailedError, ConfigEntryState.SETUP_RETRY),
|
||||
(InvalidAuthentication, ConfigEntryState.SETUP_ERROR),
|
||||
(InvalidXMLError, ConfigEntryState.SETUP_RETRY),
|
||||
(PlugwiseError, ConfigEntryState.SETUP_RETRY),
|
||||
(ResponseError, ConfigEntryState.SETUP_RETRY),
|
||||
(UnsupportedDeviceError, ConfigEntryState.SETUP_ERROR),
|
||||
],
|
||||
@ -219,7 +221,7 @@ async def test_update_device(
|
||||
entity_registry, mock_config_entry.entry_id
|
||||
)
|
||||
)
|
||||
== 28
|
||||
== 29
|
||||
)
|
||||
assert (
|
||||
len(
|
||||
@ -242,7 +244,7 @@ async def test_update_device(
|
||||
entity_registry, mock_config_entry.entry_id
|
||||
)
|
||||
)
|
||||
== 33
|
||||
== 34
|
||||
)
|
||||
assert (
|
||||
len(
|
||||
|
Loading…
x
Reference in New Issue
Block a user