Add Support for SleepIQ Foot Warmers (#105931)
* Add foot warmer support * Add Tests for foot warmers * Move attr options out of constructor * Change options to lowercase * Update test and translations * Switch back to entity * Update homeassistant/components/sleepiq/strings.json --------- Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
This commit is contained in:
parent
51a50fc134
commit
615cd56f03
8 changed files with 271 additions and 11 deletions
|
@ -11,12 +11,16 @@ ICON_OCCUPIED = "mdi:bed"
|
||||||
IS_IN_BED = "is_in_bed"
|
IS_IN_BED = "is_in_bed"
|
||||||
PRESSURE = "pressure"
|
PRESSURE = "pressure"
|
||||||
SLEEP_NUMBER = "sleep_number"
|
SLEEP_NUMBER = "sleep_number"
|
||||||
|
FOOT_WARMING_TIMER = "foot_warming_timer"
|
||||||
|
FOOT_WARMER = "foot_warmer"
|
||||||
ENTITY_TYPES = {
|
ENTITY_TYPES = {
|
||||||
ACTUATOR: "Position",
|
ACTUATOR: "Position",
|
||||||
FIRMNESS: "Firmness",
|
FIRMNESS: "Firmness",
|
||||||
PRESSURE: "Pressure",
|
PRESSURE: "Pressure",
|
||||||
IS_IN_BED: "Is In Bed",
|
IS_IN_BED: "Is In Bed",
|
||||||
SLEEP_NUMBER: "SleepNumber",
|
SLEEP_NUMBER: "SleepNumber",
|
||||||
|
FOOT_WARMING_TIMER: "Foot Warming Timer",
|
||||||
|
FOOT_WARMER: "Foot Warmer",
|
||||||
}
|
}
|
||||||
|
|
||||||
LEFT = "left"
|
LEFT = "left"
|
||||||
|
|
|
@ -29,6 +29,14 @@ def device_from_bed(bed: SleepIQBed) -> DeviceInfo:
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def sleeper_for_side(bed: SleepIQBed, side: str) -> SleepIQSleeper:
|
||||||
|
"""Find the sleeper for a side or the first sleeper."""
|
||||||
|
for sleeper in bed.sleepers:
|
||||||
|
if sleeper.side == side:
|
||||||
|
return sleeper
|
||||||
|
return bed.sleepers[0]
|
||||||
|
|
||||||
|
|
||||||
class SleepIQEntity(Entity):
|
class SleepIQEntity(Entity):
|
||||||
"""Implementation of a SleepIQ entity."""
|
"""Implementation of a SleepIQ entity."""
|
||||||
|
|
||||||
|
|
|
@ -5,16 +5,23 @@ from collections.abc import Callable, Coroutine
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from typing import Any, cast
|
from typing import Any, cast
|
||||||
|
|
||||||
from asyncsleepiq import SleepIQActuator, SleepIQBed, SleepIQSleeper
|
from asyncsleepiq import SleepIQActuator, SleepIQBed, SleepIQFootWarmer, SleepIQSleeper
|
||||||
|
|
||||||
from homeassistant.components.number import NumberEntity, NumberEntityDescription
|
from homeassistant.components.number import NumberEntity, NumberEntityDescription
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.core import HomeAssistant, callback
|
from homeassistant.core import HomeAssistant, callback
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
|
||||||
from .const import ACTUATOR, DOMAIN, ENTITY_TYPES, FIRMNESS, ICON_OCCUPIED
|
from .const import (
|
||||||
|
ACTUATOR,
|
||||||
|
DOMAIN,
|
||||||
|
ENTITY_TYPES,
|
||||||
|
FIRMNESS,
|
||||||
|
FOOT_WARMING_TIMER,
|
||||||
|
ICON_OCCUPIED,
|
||||||
|
)
|
||||||
from .coordinator import SleepIQData, SleepIQDataUpdateCoordinator
|
from .coordinator import SleepIQData, SleepIQDataUpdateCoordinator
|
||||||
from .entity import SleepIQBedEntity
|
from .entity import SleepIQBedEntity, sleeper_for_side
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
|
@ -69,6 +76,21 @@ def _get_sleeper_unique_id(bed: SleepIQBed, sleeper: SleepIQSleeper) -> str:
|
||||||
return f"{sleeper.sleeper_id}_{FIRMNESS}"
|
return f"{sleeper.sleeper_id}_{FIRMNESS}"
|
||||||
|
|
||||||
|
|
||||||
|
async def _async_set_foot_warmer_time(
|
||||||
|
foot_warmer: SleepIQFootWarmer, time: int
|
||||||
|
) -> None:
|
||||||
|
foot_warmer.timer = time
|
||||||
|
|
||||||
|
|
||||||
|
def _get_foot_warming_name(bed: SleepIQBed, foot_warmer: SleepIQFootWarmer) -> str:
|
||||||
|
sleeper = sleeper_for_side(bed, foot_warmer.side)
|
||||||
|
return f"SleepNumber {bed.name} {sleeper.name} {ENTITY_TYPES[FOOT_WARMING_TIMER]}"
|
||||||
|
|
||||||
|
|
||||||
|
def _get_foot_warming_unique_id(bed: SleepIQBed, foot_warmer: SleepIQFootWarmer) -> str:
|
||||||
|
return f"{bed.id}_{foot_warmer.side.value}_{FOOT_WARMING_TIMER}"
|
||||||
|
|
||||||
|
|
||||||
NUMBER_DESCRIPTIONS: dict[str, SleepIQNumberEntityDescription] = {
|
NUMBER_DESCRIPTIONS: dict[str, SleepIQNumberEntityDescription] = {
|
||||||
FIRMNESS: SleepIQNumberEntityDescription(
|
FIRMNESS: SleepIQNumberEntityDescription(
|
||||||
key=FIRMNESS,
|
key=FIRMNESS,
|
||||||
|
@ -94,6 +116,18 @@ NUMBER_DESCRIPTIONS: dict[str, SleepIQNumberEntityDescription] = {
|
||||||
get_name_fn=_get_actuator_name,
|
get_name_fn=_get_actuator_name,
|
||||||
get_unique_id_fn=_get_actuator_unique_id,
|
get_unique_id_fn=_get_actuator_unique_id,
|
||||||
),
|
),
|
||||||
|
FOOT_WARMING_TIMER: SleepIQNumberEntityDescription(
|
||||||
|
key=FOOT_WARMING_TIMER,
|
||||||
|
native_min_value=30,
|
||||||
|
native_max_value=360,
|
||||||
|
native_step=30,
|
||||||
|
name=ENTITY_TYPES[FOOT_WARMING_TIMER],
|
||||||
|
icon="mdi:timer",
|
||||||
|
value_fn=lambda foot_warmer: foot_warmer.timer,
|
||||||
|
set_value_fn=_async_set_foot_warmer_time,
|
||||||
|
get_name_fn=_get_foot_warming_name,
|
||||||
|
get_unique_id_fn=_get_foot_warming_unique_id,
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -125,6 +159,15 @@ async def async_setup_entry(
|
||||||
NUMBER_DESCRIPTIONS[ACTUATOR],
|
NUMBER_DESCRIPTIONS[ACTUATOR],
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
for foot_warmer in bed.foundation.foot_warmers:
|
||||||
|
entities.append(
|
||||||
|
SleepIQNumberEntity(
|
||||||
|
data.data_coordinator,
|
||||||
|
bed,
|
||||||
|
foot_warmer,
|
||||||
|
NUMBER_DESCRIPTIONS[FOOT_WARMING_TIMER],
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
async_add_entities(entities)
|
async_add_entities(entities)
|
||||||
|
|
||||||
|
@ -148,6 +191,8 @@ class SleepIQNumberEntity(SleepIQBedEntity[SleepIQDataUpdateCoordinator], Number
|
||||||
|
|
||||||
self._attr_name = description.get_name_fn(bed, device)
|
self._attr_name = description.get_name_fn(bed, device)
|
||||||
self._attr_unique_id = description.get_unique_id_fn(bed, device)
|
self._attr_unique_id = description.get_unique_id_fn(bed, device)
|
||||||
|
if description.icon:
|
||||||
|
self._attr_icon = description.icon
|
||||||
|
|
||||||
super().__init__(coordinator, bed)
|
super().__init__(coordinator, bed)
|
||||||
|
|
||||||
|
|
|
@ -1,16 +1,22 @@
|
||||||
"""Support for SleepIQ foundation preset selection."""
|
"""Support for SleepIQ foundation preset selection."""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from asyncsleepiq import Side, SleepIQBed, SleepIQPreset
|
from asyncsleepiq import (
|
||||||
|
FootWarmingTemps,
|
||||||
|
Side,
|
||||||
|
SleepIQBed,
|
||||||
|
SleepIQFootWarmer,
|
||||||
|
SleepIQPreset,
|
||||||
|
)
|
||||||
|
|
||||||
from homeassistant.components.select import SelectEntity
|
from homeassistant.components.select import SelectEntity
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.core import HomeAssistant, callback
|
from homeassistant.core import HomeAssistant, callback
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
|
||||||
from .const import DOMAIN
|
from .const import DOMAIN, FOOT_WARMER
|
||||||
from .coordinator import SleepIQData, SleepIQDataUpdateCoordinator
|
from .coordinator import SleepIQData, SleepIQDataUpdateCoordinator
|
||||||
from .entity import SleepIQBedEntity
|
from .entity import SleepIQBedEntity, SleepIQSleeperEntity, sleeper_for_side
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_entry(
|
async def async_setup_entry(
|
||||||
|
@ -20,11 +26,17 @@ async def async_setup_entry(
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Set up the SleepIQ foundation preset select entities."""
|
"""Set up the SleepIQ foundation preset select entities."""
|
||||||
data: SleepIQData = hass.data[DOMAIN][entry.entry_id]
|
data: SleepIQData = hass.data[DOMAIN][entry.entry_id]
|
||||||
async_add_entities(
|
entities: list[SleepIQBedEntity] = []
|
||||||
SleepIQSelectEntity(data.data_coordinator, bed, preset)
|
for bed in data.client.beds.values():
|
||||||
for bed in data.client.beds.values()
|
for preset in bed.foundation.presets:
|
||||||
for preset in bed.foundation.presets
|
entities.append(SleepIQSelectEntity(data.data_coordinator, bed, preset))
|
||||||
|
for foot_warmer in bed.foundation.foot_warmers:
|
||||||
|
entities.append(
|
||||||
|
SleepIQFootWarmingTempSelectEntity(
|
||||||
|
data.data_coordinator, bed, foot_warmer
|
||||||
)
|
)
|
||||||
|
)
|
||||||
|
async_add_entities(entities)
|
||||||
|
|
||||||
|
|
||||||
class SleepIQSelectEntity(SleepIQBedEntity[SleepIQDataUpdateCoordinator], SelectEntity):
|
class SleepIQSelectEntity(SleepIQBedEntity[SleepIQDataUpdateCoordinator], SelectEntity):
|
||||||
|
@ -59,3 +71,46 @@ class SleepIQSelectEntity(SleepIQBedEntity[SleepIQDataUpdateCoordinator], Select
|
||||||
await self.preset.set_preset(option)
|
await self.preset.set_preset(option)
|
||||||
self._attr_current_option = option
|
self._attr_current_option = option
|
||||||
self.async_write_ha_state()
|
self.async_write_ha_state()
|
||||||
|
|
||||||
|
|
||||||
|
class SleepIQFootWarmingTempSelectEntity(
|
||||||
|
SleepIQSleeperEntity[SleepIQDataUpdateCoordinator], SelectEntity
|
||||||
|
):
|
||||||
|
"""Representation of a SleepIQ foot warming temperature select entity."""
|
||||||
|
|
||||||
|
_attr_icon = "mdi:heat-wave"
|
||||||
|
_attr_options = [e.name.lower() for e in FootWarmingTemps]
|
||||||
|
_attr_translation_key = "foot_warmer_temp"
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
coordinator: SleepIQDataUpdateCoordinator,
|
||||||
|
bed: SleepIQBed,
|
||||||
|
foot_warmer: SleepIQFootWarmer,
|
||||||
|
) -> None:
|
||||||
|
"""Initialize the select entity."""
|
||||||
|
self.foot_warmer = foot_warmer
|
||||||
|
sleeper = sleeper_for_side(bed, foot_warmer.side)
|
||||||
|
super().__init__(coordinator, bed, sleeper, FOOT_WARMER)
|
||||||
|
self._async_update_attrs()
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def _async_update_attrs(self) -> None:
|
||||||
|
"""Update entity attributes."""
|
||||||
|
self._attr_current_option = FootWarmingTemps(
|
||||||
|
self.foot_warmer.temperature
|
||||||
|
).name.lower()
|
||||||
|
|
||||||
|
async def async_select_option(self, option: str) -> None:
|
||||||
|
"""Change the current preset."""
|
||||||
|
temperature = FootWarmingTemps[option.upper()]
|
||||||
|
timer = self.foot_warmer.timer or 120
|
||||||
|
|
||||||
|
if temperature == 0:
|
||||||
|
await self.foot_warmer.turn_off()
|
||||||
|
else:
|
||||||
|
await self.foot_warmer.turn_on(temperature, timer)
|
||||||
|
|
||||||
|
self._attr_current_option = option
|
||||||
|
await self.coordinator.async_request_refresh()
|
||||||
|
self.async_write_ha_state()
|
||||||
|
|
|
@ -23,5 +23,17 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"entity": {
|
||||||
|
"select": {
|
||||||
|
"foot_warmer_temp": {
|
||||||
|
"state": {
|
||||||
|
"off": "Off",
|
||||||
|
"low": "Low",
|
||||||
|
"medium": "Medium",
|
||||||
|
"high": "High"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,9 +6,11 @@ from unittest.mock import AsyncMock, MagicMock, create_autospec, patch
|
||||||
|
|
||||||
from asyncsleepiq import (
|
from asyncsleepiq import (
|
||||||
BED_PRESETS,
|
BED_PRESETS,
|
||||||
|
FootWarmingTemps,
|
||||||
Side,
|
Side,
|
||||||
SleepIQActuator,
|
SleepIQActuator,
|
||||||
SleepIQBed,
|
SleepIQBed,
|
||||||
|
SleepIQFootWarmer,
|
||||||
SleepIQFoundation,
|
SleepIQFoundation,
|
||||||
SleepIQLight,
|
SleepIQLight,
|
||||||
SleepIQPreset,
|
SleepIQPreset,
|
||||||
|
@ -34,6 +36,7 @@ SLEEPER_L_NAME_LOWER = SLEEPER_L_NAME.lower().replace(" ", "_")
|
||||||
SLEEPER_R_NAME_LOWER = SLEEPER_R_NAME.lower().replace(" ", "_")
|
SLEEPER_R_NAME_LOWER = SLEEPER_R_NAME.lower().replace(" ", "_")
|
||||||
PRESET_L_STATE = "Watch TV"
|
PRESET_L_STATE = "Watch TV"
|
||||||
PRESET_R_STATE = "Flat"
|
PRESET_R_STATE = "Flat"
|
||||||
|
FOOT_WARM_TIME = 120
|
||||||
|
|
||||||
SLEEPIQ_CONFIG = {
|
SLEEPIQ_CONFIG = {
|
||||||
CONF_USERNAME: "user@email.com",
|
CONF_USERNAME: "user@email.com",
|
||||||
|
@ -86,6 +89,7 @@ def mock_bed() -> MagicMock:
|
||||||
light_2.is_on = False
|
light_2.is_on = False
|
||||||
bed.foundation.lights = [light_1, light_2]
|
bed.foundation.lights = [light_1, light_2]
|
||||||
|
|
||||||
|
bed.foundation.foot_warmers = []
|
||||||
return bed
|
return bed
|
||||||
|
|
||||||
|
|
||||||
|
@ -120,6 +124,8 @@ def mock_asyncsleepiq_single_foundation(
|
||||||
preset.side = Side.NONE
|
preset.side = Side.NONE
|
||||||
preset.side_full = "Right"
|
preset.side_full = "Right"
|
||||||
preset.options = BED_PRESETS
|
preset.options = BED_PRESETS
|
||||||
|
|
||||||
|
mock_bed.foundation.foot_warmers = []
|
||||||
yield client
|
yield client
|
||||||
|
|
||||||
|
|
||||||
|
@ -166,6 +172,18 @@ def mock_asyncsleepiq(mock_bed: MagicMock) -> Generator[MagicMock, None, None]:
|
||||||
preset_r.side_full = "Right"
|
preset_r.side_full = "Right"
|
||||||
preset_r.options = BED_PRESETS
|
preset_r.options = BED_PRESETS
|
||||||
|
|
||||||
|
foot_warmer_l = create_autospec(SleepIQFootWarmer)
|
||||||
|
foot_warmer_r = create_autospec(SleepIQFootWarmer)
|
||||||
|
mock_bed.foundation.foot_warmers = [foot_warmer_l, foot_warmer_r]
|
||||||
|
|
||||||
|
foot_warmer_l.side = Side.LEFT
|
||||||
|
foot_warmer_l.timer = FOOT_WARM_TIME
|
||||||
|
foot_warmer_l.temperature = FootWarmingTemps.MEDIUM
|
||||||
|
|
||||||
|
foot_warmer_r.side = Side.RIGHT
|
||||||
|
foot_warmer_r.timer = FOOT_WARM_TIME
|
||||||
|
foot_warmer_r.temperature = FootWarmingTemps.OFF
|
||||||
|
|
||||||
yield client
|
yield client
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -156,3 +156,41 @@ async def test_actuators(hass: HomeAssistant, mock_asyncsleepiq) -> None:
|
||||||
mock_asyncsleepiq.beds[BED_ID].foundation.actuators[
|
mock_asyncsleepiq.beds[BED_ID].foundation.actuators[
|
||||||
0
|
0
|
||||||
].set_position.assert_called_with(42)
|
].set_position.assert_called_with(42)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_foot_warmer_timer(hass: HomeAssistant, mock_asyncsleepiq) -> None:
|
||||||
|
"""Test the SleepIQ foot warmer number values for a bed with two sides."""
|
||||||
|
entry = await setup_platform(hass, DOMAIN)
|
||||||
|
entity_registry = er.async_get(hass)
|
||||||
|
|
||||||
|
state = hass.states.get(
|
||||||
|
f"number.sleepnumber_{BED_NAME_LOWER}_{SLEEPER_L_NAME_LOWER}_foot_warming_timer"
|
||||||
|
)
|
||||||
|
assert state.state == "120.0"
|
||||||
|
assert state.attributes.get(ATTR_ICON) == "mdi:timer"
|
||||||
|
assert state.attributes.get(ATTR_MIN) == 30
|
||||||
|
assert state.attributes.get(ATTR_MAX) == 360
|
||||||
|
assert state.attributes.get(ATTR_STEP) == 30
|
||||||
|
assert (
|
||||||
|
state.attributes.get(ATTR_FRIENDLY_NAME)
|
||||||
|
== f"SleepNumber {BED_NAME} {SLEEPER_L_NAME} Foot Warming Timer"
|
||||||
|
)
|
||||||
|
|
||||||
|
entry = entity_registry.async_get(
|
||||||
|
f"number.sleepnumber_{BED_NAME_LOWER}_{SLEEPER_L_NAME_LOWER}_foot_warming_timer"
|
||||||
|
)
|
||||||
|
assert entry
|
||||||
|
assert entry.unique_id == f"{BED_ID}_L_foot_warming_timer"
|
||||||
|
|
||||||
|
await hass.services.async_call(
|
||||||
|
DOMAIN,
|
||||||
|
SERVICE_SET_VALUE,
|
||||||
|
{
|
||||||
|
ATTR_ENTITY_ID: f"number.sleepnumber_{BED_NAME_LOWER}_{SLEEPER_L_NAME_LOWER}_foot_warming_timer",
|
||||||
|
ATTR_VALUE: 300,
|
||||||
|
},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert mock_asyncsleepiq.beds[BED_ID].foundation.foot_warmers[0].timer == 300
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
"""Tests for the SleepIQ select platform."""
|
"""Tests for the SleepIQ select platform."""
|
||||||
from unittest.mock import MagicMock
|
from unittest.mock import MagicMock
|
||||||
|
|
||||||
|
from asyncsleepiq import FootWarmingTemps
|
||||||
|
|
||||||
from homeassistant.components.select import DOMAIN, SERVICE_SELECT_OPTION
|
from homeassistant.components.select import DOMAIN, SERVICE_SELECT_OPTION
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
ATTR_ENTITY_ID,
|
ATTR_ENTITY_ID,
|
||||||
|
@ -15,8 +17,15 @@ from .conftest import (
|
||||||
BED_ID,
|
BED_ID,
|
||||||
BED_NAME,
|
BED_NAME,
|
||||||
BED_NAME_LOWER,
|
BED_NAME_LOWER,
|
||||||
|
FOOT_WARM_TIME,
|
||||||
PRESET_L_STATE,
|
PRESET_L_STATE,
|
||||||
PRESET_R_STATE,
|
PRESET_R_STATE,
|
||||||
|
SLEEPER_L_ID,
|
||||||
|
SLEEPER_L_NAME,
|
||||||
|
SLEEPER_L_NAME_LOWER,
|
||||||
|
SLEEPER_R_ID,
|
||||||
|
SLEEPER_R_NAME,
|
||||||
|
SLEEPER_R_NAME_LOWER,
|
||||||
setup_platform,
|
setup_platform,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -115,3 +124,74 @@ async def test_single_foundation_preset(
|
||||||
mock_asyncsleepiq_single_foundation.beds[BED_ID].foundation.presets[
|
mock_asyncsleepiq_single_foundation.beds[BED_ID].foundation.presets[
|
||||||
0
|
0
|
||||||
].set_preset.assert_called_with("Zero G")
|
].set_preset.assert_called_with("Zero G")
|
||||||
|
|
||||||
|
|
||||||
|
async def test_foot_warmer(hass: HomeAssistant, mock_asyncsleepiq: MagicMock) -> None:
|
||||||
|
"""Test the SleepIQ select entity for foot warmers."""
|
||||||
|
entry = await setup_platform(hass, DOMAIN)
|
||||||
|
entity_registry = er.async_get(hass)
|
||||||
|
|
||||||
|
state = hass.states.get(
|
||||||
|
f"select.sleepnumber_{BED_NAME_LOWER}_{SLEEPER_L_NAME_LOWER}_foot_warmer"
|
||||||
|
)
|
||||||
|
assert state.state == FootWarmingTemps.MEDIUM.name.lower()
|
||||||
|
assert state.attributes.get(ATTR_ICON) == "mdi:heat-wave"
|
||||||
|
assert (
|
||||||
|
state.attributes.get(ATTR_FRIENDLY_NAME)
|
||||||
|
== f"SleepNumber {BED_NAME} {SLEEPER_L_NAME} Foot Warmer"
|
||||||
|
)
|
||||||
|
|
||||||
|
entry = entity_registry.async_get(
|
||||||
|
f"select.sleepnumber_{BED_NAME_LOWER}_{SLEEPER_L_NAME_LOWER}_foot_warmer"
|
||||||
|
)
|
||||||
|
assert entry
|
||||||
|
assert entry.unique_id == f"{SLEEPER_L_ID}_foot_warmer"
|
||||||
|
|
||||||
|
await hass.services.async_call(
|
||||||
|
DOMAIN,
|
||||||
|
SERVICE_SELECT_OPTION,
|
||||||
|
{
|
||||||
|
ATTR_ENTITY_ID: f"select.sleepnumber_{BED_NAME_LOWER}_{SLEEPER_L_NAME_LOWER}_foot_warmer",
|
||||||
|
ATTR_OPTION: "off",
|
||||||
|
},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
mock_asyncsleepiq.beds[BED_ID].foundation.foot_warmers[
|
||||||
|
0
|
||||||
|
].turn_off.assert_called_once()
|
||||||
|
|
||||||
|
state = hass.states.get(
|
||||||
|
f"select.sleepnumber_{BED_NAME_LOWER}_{SLEEPER_R_NAME_LOWER}_foot_warmer"
|
||||||
|
)
|
||||||
|
assert state.state == FootWarmingTemps.OFF.name.lower()
|
||||||
|
assert state.attributes.get(ATTR_ICON) == "mdi:heat-wave"
|
||||||
|
assert (
|
||||||
|
state.attributes.get(ATTR_FRIENDLY_NAME)
|
||||||
|
== f"SleepNumber {BED_NAME} {SLEEPER_R_NAME} Foot Warmer"
|
||||||
|
)
|
||||||
|
|
||||||
|
entry = entity_registry.async_get(
|
||||||
|
f"select.sleepnumber_{BED_NAME_LOWER}_{SLEEPER_R_NAME_LOWER}_foot_warmer"
|
||||||
|
)
|
||||||
|
assert entry
|
||||||
|
assert entry.unique_id == f"{SLEEPER_R_ID}_foot_warmer"
|
||||||
|
|
||||||
|
await hass.services.async_call(
|
||||||
|
DOMAIN,
|
||||||
|
SERVICE_SELECT_OPTION,
|
||||||
|
{
|
||||||
|
ATTR_ENTITY_ID: f"select.sleepnumber_{BED_NAME_LOWER}_{SLEEPER_R_NAME_LOWER}_foot_warmer",
|
||||||
|
ATTR_OPTION: "high",
|
||||||
|
},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
mock_asyncsleepiq.beds[BED_ID].foundation.foot_warmers[
|
||||||
|
1
|
||||||
|
].turn_on.assert_called_once()
|
||||||
|
mock_asyncsleepiq.beds[BED_ID].foundation.foot_warmers[
|
||||||
|
1
|
||||||
|
].turn_on.assert_called_with(FootWarmingTemps.HIGH, FOOT_WARM_TIME)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue