Create button entities for SleepIQ (#66849)
parent
18f26d312a
commit
d59dbbe859
|
@ -22,7 +22,7 @@ from .coordinator import SleepIQDataUpdateCoordinator
|
|||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
PLATFORMS = [Platform.BINARY_SENSOR, Platform.SENSOR]
|
||||
PLATFORMS = [Platform.BINARY_SENSOR, Platform.BUTTON, Platform.SENSOR]
|
||||
|
||||
CONFIG_SCHEMA = vol.Schema(
|
||||
{
|
||||
|
@ -35,9 +35,6 @@ CONFIG_SCHEMA = vol.Schema(
|
|||
)
|
||||
|
||||
|
||||
PLATFORMS = [Platform.BINARY_SENSOR, Platform.SENSOR]
|
||||
|
||||
|
||||
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
||||
"""Set up sleepiq component."""
|
||||
if DOMAIN in config:
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
"""Support for SleepIQ buttons."""
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Callable
|
||||
from dataclasses import dataclass
|
||||
from typing import Any
|
||||
|
||||
from asyncsleepiq import SleepIQBed
|
||||
|
||||
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 SleepIQDataUpdateCoordinator
|
||||
from .entity import SleepIQEntity
|
||||
|
||||
|
||||
@dataclass
|
||||
class SleepIQButtonEntityDescriptionMixin:
|
||||
"""Describes a SleepIQ Button entity."""
|
||||
|
||||
press_action: Callable[[SleepIQBed], Any]
|
||||
|
||||
|
||||
@dataclass
|
||||
class SleepIQButtonEntityDescription(
|
||||
ButtonEntityDescription, SleepIQButtonEntityDescriptionMixin
|
||||
):
|
||||
"""Class to describe a Button entity."""
|
||||
|
||||
|
||||
ENTITY_DESCRIPTIONS = [
|
||||
SleepIQButtonEntityDescription(
|
||||
key="calibrate",
|
||||
name="Calibrate",
|
||||
press_action=lambda client: client.calibrate(),
|
||||
icon="mdi:target",
|
||||
),
|
||||
SleepIQButtonEntityDescription(
|
||||
key="stop-pump",
|
||||
name="Stop Pump",
|
||||
press_action=lambda client: client.stop_pump(),
|
||||
icon="mdi:stop",
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
entry: ConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up the sleep number buttons."""
|
||||
coordinator: SleepIQDataUpdateCoordinator = hass.data[DOMAIN][entry.entry_id]
|
||||
|
||||
async_add_entities(
|
||||
SleepNumberButton(bed, ed)
|
||||
for bed in coordinator.client.beds.values()
|
||||
for ed in ENTITY_DESCRIPTIONS
|
||||
)
|
||||
|
||||
|
||||
class SleepNumberButton(SleepIQEntity, ButtonEntity):
|
||||
"""Representation of an SleepIQ button."""
|
||||
|
||||
entity_description: SleepIQButtonEntityDescription
|
||||
|
||||
def __init__(
|
||||
self, bed: SleepIQBed, entity_description: SleepIQButtonEntityDescription
|
||||
) -> None:
|
||||
"""Initialize the Button."""
|
||||
super().__init__(bed)
|
||||
self._attr_name = f"SleepNumber {bed.name} {entity_description.name}"
|
||||
self._attr_unique_id = f"{bed.id}-{entity_description.key}"
|
||||
self.entity_description = entity_description
|
||||
|
||||
async def async_press(self) -> None:
|
||||
"""Press the button."""
|
||||
await self.entity_description.press_action(self.bed)
|
|
@ -5,7 +5,7 @@ from asyncsleepiq import SleepIQBed, SleepIQSleeper
|
|||
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.helpers import device_registry
|
||||
from homeassistant.helpers.entity import DeviceInfo
|
||||
from homeassistant.helpers.entity import DeviceInfo, Entity
|
||||
from homeassistant.helpers.update_coordinator import (
|
||||
CoordinatorEntity,
|
||||
DataUpdateCoordinator,
|
||||
|
@ -14,6 +14,20 @@ from homeassistant.helpers.update_coordinator import (
|
|||
from .const import ICON_OCCUPIED, SENSOR_TYPES
|
||||
|
||||
|
||||
class SleepIQEntity(Entity):
|
||||
"""Implementation of a SleepIQ entity."""
|
||||
|
||||
def __init__(self, bed: SleepIQBed) -> None:
|
||||
"""Initialize the SleepIQ entity."""
|
||||
self.bed = bed
|
||||
self._attr_device_info = DeviceInfo(
|
||||
connections={(device_registry.CONNECTION_NETWORK_MAC, bed.mac_addr)},
|
||||
manufacturer="SleepNumber",
|
||||
name=bed.name,
|
||||
model=bed.model,
|
||||
)
|
||||
|
||||
|
||||
class SleepIQSensor(CoordinatorEntity):
|
||||
"""Implementation of a SleepIQ sensor."""
|
||||
|
||||
|
@ -26,14 +40,10 @@ class SleepIQSensor(CoordinatorEntity):
|
|||
sleeper: SleepIQSleeper,
|
||||
name: str,
|
||||
) -> None:
|
||||
"""Initialize the SleepIQ side entity."""
|
||||
"""Initialize the SleepIQ sensor entity."""
|
||||
super().__init__(coordinator)
|
||||
self.bed = bed
|
||||
self.sleeper = sleeper
|
||||
self._async_update_attrs()
|
||||
|
||||
self._attr_name = f"SleepNumber {bed.name} {sleeper.name} {SENSOR_TYPES[name]}"
|
||||
self._attr_unique_id = f"{bed.id}_{sleeper.name}_{name}"
|
||||
self.bed = bed
|
||||
self._attr_device_info = DeviceInfo(
|
||||
connections={(device_registry.CONNECTION_NETWORK_MAC, bed.mac_addr)},
|
||||
manufacturer="SleepNumber",
|
||||
|
@ -41,6 +51,10 @@ class SleepIQSensor(CoordinatorEntity):
|
|||
model=bed.model,
|
||||
)
|
||||
|
||||
self._attr_name = f"SleepNumber {bed.name} {sleeper.name} {SENSOR_TYPES[name]}"
|
||||
self._attr_unique_id = f"{bed.id}_{sleeper.name}_{name}"
|
||||
self._async_update_attrs()
|
||||
|
||||
@callback
|
||||
def _handle_coordinator_update(self) -> None:
|
||||
"""Handle updated data from the coordinator."""
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
"""Common methods for SleepIQ."""
|
||||
from unittest.mock import MagicMock, patch
|
||||
from unittest.mock import create_autospec, patch
|
||||
|
||||
from asyncsleepiq import SleepIQBed, SleepIQSleeper
|
||||
import pytest
|
||||
|
||||
from homeassistant.components.sleepiq import DOMAIN
|
||||
|
@ -24,15 +25,15 @@ def mock_asyncsleepiq():
|
|||
"""Mock an AsyncSleepIQ object."""
|
||||
with patch("homeassistant.components.sleepiq.AsyncSleepIQ", autospec=True) as mock:
|
||||
client = mock.return_value
|
||||
bed = MagicMock()
|
||||
bed = create_autospec(SleepIQBed)
|
||||
client.beds = {BED_ID: bed}
|
||||
bed.name = BED_NAME
|
||||
bed.id = BED_ID
|
||||
bed.mac_addr = "12:34:56:78:AB:CD"
|
||||
bed.model = "C10"
|
||||
bed.paused = False
|
||||
sleeper_l = MagicMock()
|
||||
sleeper_r = MagicMock()
|
||||
sleeper_l = create_autospec(SleepIQSleeper)
|
||||
sleeper_r = create_autospec(SleepIQSleeper)
|
||||
bed.sleepers = [sleeper_l, sleeper_r]
|
||||
|
||||
sleeper_l.side = "L"
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
"""The tests for SleepIQ binary sensor platform."""
|
||||
from homeassistant.components.button import DOMAIN
|
||||
from homeassistant.const import ATTR_ENTITY_ID, ATTR_FRIENDLY_NAME
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
|
||||
from tests.components.sleepiq.conftest import (
|
||||
BED_ID,
|
||||
BED_NAME,
|
||||
BED_NAME_LOWER,
|
||||
setup_platform,
|
||||
)
|
||||
|
||||
|
||||
async def test_button_calibrate(hass, mock_asyncsleepiq):
|
||||
"""Test the SleepIQ calibrate button."""
|
||||
await setup_platform(hass, DOMAIN)
|
||||
entity_registry = er.async_get(hass)
|
||||
|
||||
state = hass.states.get(f"button.sleepnumber_{BED_NAME_LOWER}_calibrate")
|
||||
assert (
|
||||
state.attributes.get(ATTR_FRIENDLY_NAME) == f"SleepNumber {BED_NAME} Calibrate"
|
||||
)
|
||||
|
||||
entity = entity_registry.async_get(f"button.sleepnumber_{BED_NAME_LOWER}_calibrate")
|
||||
assert entity
|
||||
assert entity.unique_id == f"{BED_ID}-calibrate"
|
||||
|
||||
await hass.services.async_call(
|
||||
DOMAIN,
|
||||
"press",
|
||||
{ATTR_ENTITY_ID: f"button.sleepnumber_{BED_NAME_LOWER}_calibrate"},
|
||||
blocking=True,
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
mock_asyncsleepiq.beds[BED_ID].calibrate.assert_called_once()
|
||||
|
||||
|
||||
async def test_button_stop_pump(hass, mock_asyncsleepiq):
|
||||
"""Test the SleepIQ stop pump button."""
|
||||
await setup_platform(hass, DOMAIN)
|
||||
entity_registry = er.async_get(hass)
|
||||
|
||||
state = hass.states.get(f"button.sleepnumber_{BED_NAME_LOWER}_stop_pump")
|
||||
assert (
|
||||
state.attributes.get(ATTR_FRIENDLY_NAME) == f"SleepNumber {BED_NAME} Stop Pump"
|
||||
)
|
||||
|
||||
entity = entity_registry.async_get(f"button.sleepnumber_{BED_NAME_LOWER}_stop_pump")
|
||||
assert entity
|
||||
assert entity.unique_id == f"{BED_ID}-stop-pump"
|
||||
|
||||
await hass.services.async_call(
|
||||
DOMAIN,
|
||||
"press",
|
||||
{ATTR_ENTITY_ID: f"button.sleepnumber_{BED_NAME_LOWER}_stop_pump"},
|
||||
blocking=True,
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
mock_asyncsleepiq.beds[BED_ID].stop_pump.assert_called_once()
|
Loading…
Reference in New Issue