Home Assistant Unofficial Reference 2024.12.1
sensor.py
Go to the documentation of this file.
1 """Support for Home Assistant iOS app sensors."""
2 
3 from __future__ import annotations
4 
5 from typing import Any
6 
8  SensorDeviceClass,
9  SensorEntity,
10  SensorEntityDescription,
11 )
12 from homeassistant.config_entries import ConfigEntry
13 from homeassistant.const import PERCENTAGE
14 from homeassistant.core import HomeAssistant, callback
15 from homeassistant.helpers.device_registry import DeviceInfo
16 from homeassistant.helpers.dispatcher import async_dispatcher_connect
17 from homeassistant.helpers.entity_platform import AddEntitiesCallback
18 from homeassistant.helpers.icon import icon_for_battery_level
19 from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
20 
21 from . import devices
22 from .const import (
23  ATTR_BATTERY,
24  ATTR_BATTERY_LEVEL,
25  ATTR_BATTERY_STATE,
26  ATTR_BATTERY_STATE_FULL,
27  ATTR_BATTERY_STATE_UNKNOWN,
28  ATTR_BATTERY_STATE_UNPLUGGED,
29  ATTR_DEVICE,
30  ATTR_DEVICE_ID,
31  ATTR_DEVICE_NAME,
32  ATTR_DEVICE_PERMANENT_ID,
33  ATTR_DEVICE_SYSTEM_VERSION,
34  ATTR_DEVICE_TYPE,
35  DOMAIN,
36 )
37 
38 SENSOR_TYPES: tuple[SensorEntityDescription, ...] = (
40  key="level",
41  native_unit_of_measurement=PERCENTAGE,
42  device_class=SensorDeviceClass.BATTERY,
43  ),
45  key="state",
46  translation_key="battery_state",
47  ),
48 )
49 
50 DEFAULT_ICON_LEVEL = "mdi:battery"
51 DEFAULT_ICON_STATE = "mdi:power-plug"
52 
53 
55  hass: HomeAssistant,
56  config: ConfigType,
57  add_entities: AddEntitiesCallback,
58  discovery_info: DiscoveryInfoType | None = None,
59 ) -> None:
60  """Set up the iOS sensor."""
61  # Leave here for if someone accidentally adds platform: ios to config
62 
63 
65  hass: HomeAssistant,
66  config_entry: ConfigEntry,
67  async_add_entities: AddEntitiesCallback,
68 ) -> None:
69  """Set up iOS from a config entry."""
71  IOSSensor(device_name, device, description)
72  for device_name, device in devices(hass).items()
73  for description in SENSOR_TYPES
74  )
75 
76 
78  """Representation of an iOS sensor."""
79 
80  _attr_should_poll = False
81  _attr_has_entity_name = True
82 
83  def __init__(
84  self,
85  device_name: str,
86  device: dict[str, Any],
87  description: SensorEntityDescription,
88  ) -> None:
89  """Initialize the sensor."""
90  self.entity_descriptionentity_description = description
91  self._device_device = device
92 
93  device_id = device[ATTR_DEVICE_ID]
94  self._attr_unique_id_attr_unique_id = f"{description.key}_{device_id}"
95 
96  @property
97  def device_info(self) -> DeviceInfo:
98  """Return information about the device."""
99  return DeviceInfo(
100  identifiers={
101  (
102  DOMAIN,
103  self._device_device[ATTR_DEVICE][ATTR_DEVICE_PERMANENT_ID],
104  )
105  },
106  manufacturer="Apple",
107  model=self._device_device[ATTR_DEVICE][ATTR_DEVICE_TYPE],
108  name=self._device_device[ATTR_DEVICE][ATTR_DEVICE_NAME],
109  sw_version=self._device_device[ATTR_DEVICE][ATTR_DEVICE_SYSTEM_VERSION],
110  )
111 
112  @property
113  def extra_state_attributes(self) -> dict[str, Any]:
114  """Return the device state attributes."""
115  device = self._device_device[ATTR_DEVICE]
116  device_battery = self._device_device[ATTR_BATTERY]
117  return {
118  "Battery State": device_battery[ATTR_BATTERY_STATE],
119  "Battery Level": device_battery[ATTR_BATTERY_LEVEL],
120  "Device Type": device[ATTR_DEVICE_TYPE],
121  "Device Name": device[ATTR_DEVICE_NAME],
122  "Device Version": device[ATTR_DEVICE_SYSTEM_VERSION],
123  }
124 
125  @property
126  def icon(self) -> str:
127  """Return the icon to use in the frontend, if any."""
128  device_battery = self._device_device[ATTR_BATTERY]
129  battery_state = device_battery[ATTR_BATTERY_STATE]
130  battery_level = device_battery[ATTR_BATTERY_LEVEL]
131  charging = True
132  icon_state = DEFAULT_ICON_STATE
133  if battery_state in (
134  ATTR_BATTERY_STATE_FULL,
135  ATTR_BATTERY_STATE_UNPLUGGED,
136  ):
137  charging = False
138  icon_state = f"{DEFAULT_ICON_STATE}-off"
139  elif battery_state == ATTR_BATTERY_STATE_UNKNOWN:
140  battery_level = None
141  charging = False
142  icon_state = f"{DEFAULT_ICON_LEVEL}-unknown"
143 
144  if self.entity_descriptionentity_description.key == "state":
145  return icon_state
146  return icon_for_battery_level(battery_level=battery_level, charging=charging)
147 
148  @callback
149  def _update(self, device: dict[str, Any]) -> None:
150  """Get the latest state of the sensor."""
151  self._device_device = device
152  self._attr_native_value_attr_native_value = self._device_device[ATTR_BATTERY][
153  self.entity_descriptionentity_description.key
154  ]
155  self.async_write_ha_stateasync_write_ha_state()
156 
157  async def async_added_to_hass(self) -> None:
158  """Handle addition to hass: register to dispatch."""
159  self._attr_native_value_attr_native_value = self._device_device[ATTR_BATTERY][
160  self.entity_descriptionentity_description.key
161  ]
162  device_id = self._device_device[ATTR_DEVICE_ID]
163  self.async_on_removeasync_on_remove(
164  async_dispatcher_connect(self.hasshass, f"{DOMAIN}.{device_id}", self._update_update)
165  )
dict[str, Any] extra_state_attributes(self)
Definition: sensor.py:113
None __init__(self, str device_name, dict[str, Any] device, SensorEntityDescription description)
Definition: sensor.py:88
None _update(self, dict[str, Any] device)
Definition: sensor.py:149
None async_on_remove(self, CALLBACK_TYPE func)
Definition: entity.py:1331
None setup_platform(HomeAssistant hass, ConfigType config, AddEntitiesCallback add_entities, DiscoveryInfoType|None discovery_info=None)
Definition: sensor.py:59
None async_setup_entry(HomeAssistant hass, ConfigEntry config_entry, AddEntitiesCallback async_add_entities)
Definition: sensor.py:68
dict[str, dict[str, Any]] devices(HomeAssistant hass)
Definition: __init__.py:237
Callable[[], None] async_dispatcher_connect(HomeAssistant hass, str signal, Callable[..., Any] target)
Definition: dispatcher.py:103
str icon_for_battery_level(int|None battery_level=None, bool charging=False)
Definition: icon.py:169