Home Assistant Unofficial Reference 2024.12.1
number.py
Go to the documentation of this file.
1 """Support for SleepIQ SleepNumber firmness number entities."""
2 
3 from __future__ import annotations
4 
5 from collections.abc import Callable, Coroutine
6 from dataclasses import dataclass
7 from typing import Any, cast
8 
9 from asyncsleepiq import (
10  FootWarmingTemps,
11  SleepIQActuator,
12  SleepIQBed,
13  SleepIQFootWarmer,
14  SleepIQSleeper,
15 )
16 
17 from homeassistant.components.number import NumberEntity, NumberEntityDescription
18 from homeassistant.config_entries import ConfigEntry
19 from homeassistant.core import HomeAssistant, callback
20 from homeassistant.helpers.entity_platform import AddEntitiesCallback
21 
22 from .const import (
23  ACTUATOR,
24  DOMAIN,
25  ENTITY_TYPES,
26  FIRMNESS,
27  FOOT_WARMING_TIMER,
28  ICON_OCCUPIED,
29 )
30 from .coordinator import SleepIQData, SleepIQDataUpdateCoordinator
31 from .entity import SleepIQBedEntity, sleeper_for_side
32 
33 
34 @dataclass(frozen=True, kw_only=True)
36  """Class to describe a SleepIQ number entity."""
37 
38  value_fn: Callable[[Any], float]
39  set_value_fn: Callable[[Any, int], Coroutine[None, None, None]]
40  get_name_fn: Callable[[SleepIQBed, Any], str]
41  get_unique_id_fn: Callable[[SleepIQBed, Any], str]
42 
43 
44 async def _async_set_firmness(sleeper: SleepIQSleeper, firmness: int) -> None:
45  await sleeper.set_sleepnumber(firmness)
46 
47 
49  actuator: SleepIQActuator, position: int
50 ) -> None:
51  await actuator.set_position(position)
52 
53 
54 def _get_actuator_name(bed: SleepIQBed, actuator: SleepIQActuator) -> str:
55  if actuator.side:
56  return (
57  "SleepNumber"
58  f" {bed.name} {actuator.side_full} {actuator.actuator_full} {ENTITY_TYPES[ACTUATOR]}"
59  )
60 
61  return f"SleepNumber {bed.name} {actuator.actuator_full} {ENTITY_TYPES[ACTUATOR]}" # type: ignore[unreachable]
62 
63 
64 def _get_actuator_unique_id(bed: SleepIQBed, actuator: SleepIQActuator) -> str:
65  if actuator.side:
66  return f"{bed.id}_{actuator.side.value}_{actuator.actuator}"
67 
68  return f"{bed.id}_{actuator.actuator}" # type: ignore[unreachable]
69 
70 
71 def _get_sleeper_name(bed: SleepIQBed, sleeper: SleepIQSleeper) -> str:
72  return f"SleepNumber {bed.name} {sleeper.name} {ENTITY_TYPES[FIRMNESS]}"
73 
74 
75 def _get_sleeper_unique_id(bed: SleepIQBed, sleeper: SleepIQSleeper) -> str:
76  return f"{sleeper.sleeper_id}_{FIRMNESS}"
77 
78 
80  foot_warmer: SleepIQFootWarmer, time: int
81 ) -> None:
82  temperature = FootWarmingTemps(foot_warmer.temperature)
83  if temperature != FootWarmingTemps.OFF:
84  await foot_warmer.turn_on(temperature, time)
85 
86  foot_warmer.timer = time
87 
88 
89 def _get_foot_warming_name(bed: SleepIQBed, foot_warmer: SleepIQFootWarmer) -> str:
90  sleeper = sleeper_for_side(bed, foot_warmer.side)
91  return f"SleepNumber {bed.name} {sleeper.name} {ENTITY_TYPES[FOOT_WARMING_TIMER]}"
92 
93 
94 def _get_foot_warming_unique_id(bed: SleepIQBed, foot_warmer: SleepIQFootWarmer) -> str:
95  return f"{bed.id}_{foot_warmer.side.value}_{FOOT_WARMING_TIMER}"
96 
97 
98 NUMBER_DESCRIPTIONS: dict[str, SleepIQNumberEntityDescription] = {
100  key=FIRMNESS,
101  native_min_value=5,
102  native_max_value=100,
103  native_step=5,
104  name=ENTITY_TYPES[FIRMNESS],
105  icon=ICON_OCCUPIED,
106  value_fn=lambda sleeper: cast(float, sleeper.sleep_number),
107  set_value_fn=_async_set_firmness,
108  get_name_fn=_get_sleeper_name,
109  get_unique_id_fn=_get_sleeper_unique_id,
110  ),
112  key=ACTUATOR,
113  native_min_value=0,
114  native_max_value=100,
115  native_step=1,
116  name=ENTITY_TYPES[ACTUATOR],
117  icon=ICON_OCCUPIED,
118  value_fn=lambda actuator: cast(float, actuator.position),
119  set_value_fn=_async_set_actuator_position,
120  get_name_fn=_get_actuator_name,
121  get_unique_id_fn=_get_actuator_unique_id,
122  ),
123  FOOT_WARMING_TIMER: SleepIQNumberEntityDescription(
124  key=FOOT_WARMING_TIMER,
125  native_min_value=30,
126  native_max_value=360,
127  native_step=30,
128  name=ENTITY_TYPES[FOOT_WARMING_TIMER],
129  icon="mdi:timer",
130  value_fn=lambda foot_warmer: foot_warmer.timer,
131  set_value_fn=_async_set_foot_warmer_time,
132  get_name_fn=_get_foot_warming_name,
133  get_unique_id_fn=_get_foot_warming_unique_id,
134  ),
135 }
136 
137 
139  hass: HomeAssistant,
140  entry: ConfigEntry,
141  async_add_entities: AddEntitiesCallback,
142 ) -> None:
143  """Set up the SleepIQ bed sensors."""
144  data: SleepIQData = hass.data[DOMAIN][entry.entry_id]
145 
146  entities: list[SleepIQNumberEntity] = []
147  for bed in data.client.beds.values():
148  entities.extend(
150  data.data_coordinator,
151  bed,
152  sleeper,
153  NUMBER_DESCRIPTIONS[FIRMNESS],
154  )
155  for sleeper in bed.sleepers
156  )
157  entities.extend(
159  data.data_coordinator,
160  bed,
161  actuator,
162  NUMBER_DESCRIPTIONS[ACTUATOR],
163  )
164  for actuator in bed.foundation.actuators
165  )
166  entities.extend(
168  data.data_coordinator,
169  bed,
170  foot_warmer,
171  NUMBER_DESCRIPTIONS[FOOT_WARMING_TIMER],
172  )
173  for foot_warmer in bed.foundation.foot_warmers
174  )
175 
176  async_add_entities(entities)
177 
178 
179 class SleepIQNumberEntity(SleepIQBedEntity[SleepIQDataUpdateCoordinator], NumberEntity):
180  """Representation of a SleepIQ number entity."""
181 
182  entity_description: SleepIQNumberEntityDescription
183  _attr_icon = "mdi:bed"
184 
185  def __init__(
186  self,
187  coordinator: SleepIQDataUpdateCoordinator,
188  bed: SleepIQBed,
189  device: Any,
190  description: SleepIQNumberEntityDescription,
191  ) -> None:
192  """Initialize the number."""
193  self.entity_descriptionentity_description = description
194  self.devicedevice = device
195 
196  self._attr_name_attr_name = description.get_name_fn(bed, device)
197  self._attr_unique_id_attr_unique_id = description.get_unique_id_fn(bed, device)
198  if description.icon:
199  self._attr_icon_attr_icon_attr_icon = description.icon
200 
201  super().__init__(coordinator, bed)
202 
203  @callback
204  def _async_update_attrs(self) -> None:
205  """Update number attributes."""
206  self._attr_native_value_attr_native_value = float(self.entity_descriptionentity_description.value_fn(self.devicedevice))
207 
208  async def async_set_native_value(self, value: float) -> None:
209  """Set the number value."""
210  await self.entity_descriptionentity_description.set_value_fn(self.devicedevice, int(value))
211  self._attr_native_value_attr_native_value = value
212  self.async_write_ha_stateasync_write_ha_state()
None __init__(self, SleepIQDataUpdateCoordinator coordinator, SleepIQBed bed, Any device, SleepIQNumberEntityDescription description)
Definition: number.py:191
SleepIQSleeper sleeper_for_side(SleepIQBed bed, str side)
Definition: entity.py:29
None _async_set_foot_warmer_time(SleepIQFootWarmer foot_warmer, int time)
Definition: number.py:81
str _get_sleeper_name(SleepIQBed bed, SleepIQSleeper sleeper)
Definition: number.py:71
str _get_sleeper_unique_id(SleepIQBed bed, SleepIQSleeper sleeper)
Definition: number.py:75
str _get_foot_warming_name(SleepIQBed bed, SleepIQFootWarmer foot_warmer)
Definition: number.py:89
None _async_set_actuator_position(SleepIQActuator actuator, int position)
Definition: number.py:50
str _get_actuator_unique_id(SleepIQBed bed, SleepIQActuator actuator)
Definition: number.py:64
str _get_foot_warming_unique_id(SleepIQBed bed, SleepIQFootWarmer foot_warmer)
Definition: number.py:94
str _get_actuator_name(SleepIQBed bed, SleepIQActuator actuator)
Definition: number.py:54
None async_setup_entry(HomeAssistant hass, ConfigEntry entry, AddEntitiesCallback async_add_entities)
Definition: number.py:142
None _async_set_firmness(SleepIQSleeper sleeper, int firmness)
Definition: number.py:44