Home Assistant Unofficial Reference 2024.12.1
sensor.py
Go to the documentation of this file.
1 """Support for OpenUV sensors."""
2 
3 from __future__ import annotations
4 
5 from collections.abc import Callable, Mapping
6 from dataclasses import dataclass
7 from typing import Any
8 
10  SensorDeviceClass,
11  SensorEntity,
12  SensorEntityDescription,
13  SensorStateClass,
14 )
15 from homeassistant.config_entries import ConfigEntry
16 from homeassistant.const import UV_INDEX, UnitOfTime
17 from homeassistant.core import HomeAssistant
18 from homeassistant.helpers.entity_platform import AddEntitiesCallback
19 from homeassistant.util.dt import as_local, parse_datetime
20 
21 from .const import (
22  DATA_UV,
23  DOMAIN,
24  TYPE_CURRENT_OZONE_LEVEL,
25  TYPE_CURRENT_UV_INDEX,
26  TYPE_CURRENT_UV_LEVEL,
27  TYPE_MAX_UV_INDEX,
28  TYPE_SAFE_EXPOSURE_TIME_1,
29  TYPE_SAFE_EXPOSURE_TIME_2,
30  TYPE_SAFE_EXPOSURE_TIME_3,
31  TYPE_SAFE_EXPOSURE_TIME_4,
32  TYPE_SAFE_EXPOSURE_TIME_5,
33  TYPE_SAFE_EXPOSURE_TIME_6,
34 )
35 from .coordinator import OpenUvCoordinator
36 from .entity import OpenUvEntity
37 
38 ATTR_MAX_UV_TIME = "time"
39 
40 EXPOSURE_TYPE_MAP = {
41  TYPE_SAFE_EXPOSURE_TIME_1: "st1",
42  TYPE_SAFE_EXPOSURE_TIME_2: "st2",
43  TYPE_SAFE_EXPOSURE_TIME_3: "st3",
44  TYPE_SAFE_EXPOSURE_TIME_4: "st4",
45  TYPE_SAFE_EXPOSURE_TIME_5: "st5",
46  TYPE_SAFE_EXPOSURE_TIME_6: "st6",
47 }
48 
49 
50 @dataclass
51 class UvLabel:
52  """Define a friendly UV level label and its minimum UV index."""
53 
54  value: str
55  minimum_index: int
56 
57 
58 UV_LABEL_DEFINITIONS = (
59  UvLabel(value="extreme", minimum_index=11),
60  UvLabel(value="very_high", minimum_index=8),
61  UvLabel(value="high", minimum_index=6),
62  UvLabel(value="moderate", minimum_index=3),
63  UvLabel(value="low", minimum_index=0),
64 )
65 
66 
67 def get_uv_label(uv_index: int) -> str:
68  """Return the UV label for the UV index."""
69  label = next(
70  label for label in UV_LABEL_DEFINITIONS if uv_index >= label.minimum_index
71  )
72  return label.value
73 
74 
75 @dataclass(frozen=True, kw_only=True)
77  """Define a class that describes OpenUV sensor entities."""
78 
79  value_fn: Callable[[dict[str, Any]], int | str]
80 
81 
82 SENSOR_DESCRIPTIONS = (
84  key=TYPE_CURRENT_OZONE_LEVEL,
85  translation_key="current_ozone_level",
86  native_unit_of_measurement="du",
87  state_class=SensorStateClass.MEASUREMENT,
88  value_fn=lambda data: data["ozone"],
89  ),
91  key=TYPE_CURRENT_UV_INDEX,
92  translation_key="current_uv_index",
93  native_unit_of_measurement=UV_INDEX,
94  state_class=SensorStateClass.MEASUREMENT,
95  value_fn=lambda data: data["uv"],
96  ),
98  key=TYPE_CURRENT_UV_LEVEL,
99  translation_key="current_uv_level",
100  device_class=SensorDeviceClass.ENUM,
101  options=[label.value for label in UV_LABEL_DEFINITIONS],
102  value_fn=lambda data: get_uv_label(data["uv"]),
103  ),
105  key=TYPE_MAX_UV_INDEX,
106  translation_key="max_uv_index",
107  native_unit_of_measurement=UV_INDEX,
108  state_class=SensorStateClass.MEASUREMENT,
109  value_fn=lambda data: data["uv_max"],
110  ),
112  key=TYPE_SAFE_EXPOSURE_TIME_1,
113  translation_key="skin_type_1_safe_exposure_time",
114  native_unit_of_measurement=UnitOfTime.MINUTES,
115  state_class=SensorStateClass.MEASUREMENT,
116  value_fn=lambda data: data["safe_exposure_time"][
117  EXPOSURE_TYPE_MAP[TYPE_SAFE_EXPOSURE_TIME_1]
118  ],
119  ),
121  key=TYPE_SAFE_EXPOSURE_TIME_2,
122  translation_key="skin_type_2_safe_exposure_time",
123  native_unit_of_measurement=UnitOfTime.MINUTES,
124  state_class=SensorStateClass.MEASUREMENT,
125  value_fn=lambda data: data["safe_exposure_time"][
126  EXPOSURE_TYPE_MAP[TYPE_SAFE_EXPOSURE_TIME_2]
127  ],
128  ),
130  key=TYPE_SAFE_EXPOSURE_TIME_3,
131  translation_key="skin_type_3_safe_exposure_time",
132  native_unit_of_measurement=UnitOfTime.MINUTES,
133  state_class=SensorStateClass.MEASUREMENT,
134  value_fn=lambda data: data["safe_exposure_time"][
135  EXPOSURE_TYPE_MAP[TYPE_SAFE_EXPOSURE_TIME_3]
136  ],
137  ),
139  key=TYPE_SAFE_EXPOSURE_TIME_4,
140  translation_key="skin_type_4_safe_exposure_time",
141  native_unit_of_measurement=UnitOfTime.MINUTES,
142  state_class=SensorStateClass.MEASUREMENT,
143  value_fn=lambda data: data["safe_exposure_time"][
144  EXPOSURE_TYPE_MAP[TYPE_SAFE_EXPOSURE_TIME_4]
145  ],
146  ),
148  key=TYPE_SAFE_EXPOSURE_TIME_5,
149  translation_key="skin_type_5_safe_exposure_time",
150  native_unit_of_measurement=UnitOfTime.MINUTES,
151  state_class=SensorStateClass.MEASUREMENT,
152  value_fn=lambda data: data["safe_exposure_time"][
153  EXPOSURE_TYPE_MAP[TYPE_SAFE_EXPOSURE_TIME_5]
154  ],
155  ),
157  key=TYPE_SAFE_EXPOSURE_TIME_6,
158  translation_key="skin_type_6_safe_exposure_time",
159  native_unit_of_measurement=UnitOfTime.MINUTES,
160  state_class=SensorStateClass.MEASUREMENT,
161  value_fn=lambda data: data["safe_exposure_time"][
162  EXPOSURE_TYPE_MAP[TYPE_SAFE_EXPOSURE_TIME_6]
163  ],
164  ),
165 )
166 
167 
169  hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
170 ) -> None:
171  """Set up a OpenUV sensor based on a config entry."""
172  coordinators: dict[str, OpenUvCoordinator] = hass.data[DOMAIN][entry.entry_id]
173 
175  [
176  OpenUvSensor(coordinators[DATA_UV], description)
177  for description in SENSOR_DESCRIPTIONS
178  ]
179  )
180 
181 
183  """Define a binary sensor for OpenUV."""
184 
185  entity_description: OpenUvSensorEntityDescription
186 
187  @property
188  def extra_state_attributes(self) -> Mapping[str, Any]:
189  """Return entity specific state attributes."""
190  attrs = {}
191  if self.entity_descriptionentity_description.key == TYPE_MAX_UV_INDEX:
192  if uv_max_time := parse_datetime(self.coordinator.data["uv_max_time"]):
193  attrs[ATTR_MAX_UV_TIME] = as_local(uv_max_time)
194  return attrs
195 
196  @property
197  def native_value(self) -> int | str:
198  """Return the sensor value."""
199  return self.entity_descriptionentity_description.value_fn(self.coordinator.data)
Mapping[str, Any] extra_state_attributes(self)
Definition: sensor.py:188
datetime|None parse_datetime(str|None value)
Definition: sensor.py:138
None async_setup_entry(HomeAssistant hass, ConfigEntry entry, AddEntitiesCallback async_add_entities)
Definition: sensor.py:170
str get_uv_label(int uv_index)
Definition: sensor.py:67
dt.datetime as_local(dt.datetime dattim)
Definition: dt.py:157