Home Assistant Unofficial Reference 2024.12.1
sensor.py
Go to the documentation of this file.
1 """Support for Azure DevOps sensors."""
2 
3 from __future__ import annotations
4 
5 from collections.abc import Callable, Mapping
6 from dataclasses import dataclass
7 from datetime import datetime
8 import logging
9 from typing import Any
10 
11 from aioazuredevops.helper import WorkItemState, WorkItemTypeAndState
12 from aioazuredevops.models.build import Build
13 
15  SensorDeviceClass,
16  SensorEntity,
17  SensorEntityDescription,
18 )
19 from homeassistant.core import HomeAssistant
20 from homeassistant.helpers.entity_platform import AddEntitiesCallback
21 from homeassistant.helpers.typing import StateType
22 from homeassistant.util import dt as dt_util
23 
24 from . import AzureDevOpsConfigEntry
25 from .coordinator import AzureDevOpsDataUpdateCoordinator
26 from .entity import AzureDevOpsEntity
27 
28 _LOGGER = logging.getLogger(__name__)
29 
30 
31 @dataclass(frozen=True, kw_only=True)
33  """Class describing Azure DevOps build sensor entities."""
34 
35  attr_fn: Callable[[Build], dict[str, Any] | None] = lambda _: None
36  value_fn: Callable[[Build], datetime | StateType]
37 
38 
39 @dataclass(frozen=True, kw_only=True)
41  """Class describing Azure DevOps work item sensor entities."""
42 
43  value_fn: Callable[[WorkItemState], datetime | StateType]
44 
45 
46 BASE_BUILD_SENSOR_DESCRIPTIONS: tuple[AzureDevOpsBuildSensorEntityDescription, ...] = (
47  # Attributes are deprecated in 2024.7 and can be removed in 2025.1
49  key="latest_build",
50  translation_key="latest_build",
51  attr_fn=lambda build: {
52  "definition_id": (build.definition.build_id if build.definition else None),
53  "definition_name": (build.definition.name if build.definition else None),
54  "id": build.build_id,
55  "reason": build.reason,
56  "result": build.result,
57  "source_branch": build.source_branch,
58  "source_version": build.source_version,
59  "status": build.status,
60  "url": build.links.web if build.links else None,
61  "queue_time": build.queue_time,
62  "start_time": build.start_time,
63  "finish_time": build.finish_time,
64  },
65  value_fn=lambda build: build.build_number,
66  ),
68  key="build_id",
69  translation_key="build_id",
70  entity_registry_visible_default=False,
71  value_fn=lambda build: build.build_id,
72  ),
74  key="reason",
75  translation_key="reason",
76  entity_registry_visible_default=False,
77  value_fn=lambda build: build.reason,
78  ),
80  key="result",
81  translation_key="result",
82  entity_registry_visible_default=False,
83  value_fn=lambda build: build.result,
84  ),
86  key="source_branch",
87  translation_key="source_branch",
88  entity_registry_enabled_default=False,
89  entity_registry_visible_default=False,
90  value_fn=lambda build: build.source_branch,
91  ),
93  key="source_version",
94  translation_key="source_version",
95  entity_registry_visible_default=False,
96  value_fn=lambda build: build.source_version,
97  ),
99  key="queue_time",
100  translation_key="queue_time",
101  device_class=SensorDeviceClass.TIMESTAMP,
102  entity_registry_enabled_default=False,
103  entity_registry_visible_default=False,
104  value_fn=lambda build: parse_datetime(build.queue_time),
105  ),
107  key="start_time",
108  translation_key="start_time",
109  device_class=SensorDeviceClass.TIMESTAMP,
110  entity_registry_visible_default=False,
111  value_fn=lambda build: parse_datetime(build.start_time),
112  ),
114  key="finish_time",
115  translation_key="finish_time",
116  device_class=SensorDeviceClass.TIMESTAMP,
117  entity_registry_visible_default=False,
118  value_fn=lambda build: parse_datetime(build.finish_time),
119  ),
121  key="url",
122  translation_key="url",
123  value_fn=lambda build: build.links.web if build.links else None,
124  ),
125 )
126 
127 BASE_WORK_ITEM_SENSOR_DESCRIPTIONS: tuple[
128  AzureDevOpsWorkItemSensorEntityDescription, ...
129 ] = (
131  key="work_item_count",
132  translation_key="work_item_count",
133  value_fn=lambda work_item_state: len(work_item_state.work_items),
134  ),
135 )
136 
137 
138 def parse_datetime(value: str | None) -> datetime | None:
139  """Parse datetime string."""
140  if value is None:
141  return None
142 
143  return dt_util.parse_datetime(value)
144 
145 
147  hass: HomeAssistant,
148  entry: AzureDevOpsConfigEntry,
149  async_add_entities: AddEntitiesCallback,
150 ) -> None:
151  """Set up Azure DevOps sensor based on a config entry."""
152  coordinator = entry.runtime_data
153  initial_builds: list[Build] = coordinator.data.builds
154 
155  entities: list[SensorEntity] = [
157  coordinator,
158  description,
159  key,
160  )
161  for description in BASE_BUILD_SENSOR_DESCRIPTIONS
162  for key, build in enumerate(initial_builds)
163  if build.project and build.definition
164  ]
165 
166  entities.extend(
168  coordinator,
169  description,
170  key,
171  state_key,
172  )
173  for description in BASE_WORK_ITEM_SENSOR_DESCRIPTIONS
174  for key, work_item_type_state in enumerate(coordinator.data.work_items)
175  for state_key, _ in enumerate(work_item_type_state.state_items)
176  )
177 
178  async_add_entities(entities)
179 
180 
182  """Define a Azure DevOps build sensor."""
183 
184  entity_description: AzureDevOpsBuildSensorEntityDescription
185 
186  def __init__(
187  self,
188  coordinator: AzureDevOpsDataUpdateCoordinator,
189  description: AzureDevOpsBuildSensorEntityDescription,
190  item_key: int,
191  ) -> None:
192  """Initialize."""
193  super().__init__(coordinator)
194  self.entity_descriptionentity_description = description
195  self.item_keyitem_key = item_key
196  self._attr_unique_id_attr_unique_id = (
197  f"{coordinator.data.organization}_"
198  f"{coordinator.data.project.id}_"
199  f"{self.build.definition.build_id}_"
200  f"{description.key}"
201  )
202  self._attr_translation_placeholders_attr_translation_placeholders = {
203  "definition_name": self.buildbuild.definition.name
204  }
205 
206  @property
207  def build(self) -> Build:
208  """Return the build."""
209  return self.coordinator.data.builds[self.item_keyitem_key]
210 
211  @property
212  def native_value(self) -> datetime | StateType:
213  """Return the state."""
214  return self.entity_descriptionentity_description.value_fn(self.buildbuild)
215 
216  @property
217  def extra_state_attributes(self) -> Mapping[str, Any] | None:
218  """Return the state attributes of the entity."""
219  return self.entity_descriptionentity_description.attr_fn(self.buildbuild)
220 
221 
223  """Define a Azure DevOps work item sensor."""
224 
225  entity_description: AzureDevOpsWorkItemSensorEntityDescription
226 
227  def __init__(
228  self,
229  coordinator: AzureDevOpsDataUpdateCoordinator,
230  description: AzureDevOpsWorkItemSensorEntityDescription,
231  wits_key: int,
232  state_key: int,
233  ) -> None:
234  """Initialize."""
235  super().__init__(coordinator)
236  self.entity_descriptionentity_description = description
237  self.wits_keywits_key = wits_key
238  self.state_keystate_key = state_key
239  self._attr_unique_id_attr_unique_id = (
240  f"{coordinator.data.organization}_"
241  f"{coordinator.data.project.id}_"
242  f"{self.work_item_type.name}_"
243  f"{self.work_item_state.name}_"
244  f"{description.key}"
245  )
246  self._attr_translation_placeholders_attr_translation_placeholders = {
247  "item_type": self.work_item_typework_item_type.name,
248  "item_state": self.work_item_statework_item_state.name,
249  }
250 
251  @property
252  def work_item_type(self) -> WorkItemTypeAndState:
253  """Return the work item."""
254  return self.coordinator.data.work_items[self.wits_keywits_key]
255 
256  @property
257  def work_item_state(self) -> WorkItemState:
258  """Return the work item state."""
259  return self.work_item_typework_item_type.state_items[self.state_keystate_key]
260 
261  @property
262  def native_value(self) -> datetime | StateType:
263  """Return the state."""
264  return self.entity_descriptionentity_description.value_fn(self.work_item_statework_item_state)
None __init__(self, AzureDevOpsDataUpdateCoordinator coordinator, AzureDevOpsBuildSensorEntityDescription description, int item_key)
Definition: sensor.py:191
None __init__(self, AzureDevOpsDataUpdateCoordinator coordinator, AzureDevOpsWorkItemSensorEntityDescription description, int wits_key, int state_key)
Definition: sensor.py:233
None async_setup_entry(HomeAssistant hass, AzureDevOpsConfigEntry entry, AddEntitiesCallback async_add_entities)
Definition: sensor.py:150
datetime|None parse_datetime(str|None value)
Definition: sensor.py:138