Home Assistant Unofficial Reference 2024.12.1
sensor.py
Go to the documentation of this file.
1 """Sensor platform for GPSD integration."""
2 
3 from __future__ import annotations
4 
5 from collections.abc import Callable
6 from dataclasses import dataclass
7 from datetime import datetime
8 import logging
9 from typing import Any
10 
11 from gps3.agps3threaded import AGPS3mechanism
12 
14  SensorDeviceClass,
15  SensorEntity,
16  SensorEntityDescription,
17 )
18 from homeassistant.const import (
19  ATTR_LATITUDE,
20  ATTR_LONGITUDE,
21  ATTR_MODE,
22  ATTR_TIME,
23  EntityCategory,
24  UnitOfLength,
25  UnitOfSpeed,
26 )
27 from homeassistant.core import HomeAssistant
28 from homeassistant.helpers.device_registry import DeviceEntryType, DeviceInfo
29 from homeassistant.helpers.entity_platform import AddEntitiesCallback
30 from homeassistant.helpers.typing import StateType
31 from homeassistant.util import dt as dt_util
32 
33 from . import GPSDConfigEntry
34 from .const import DOMAIN
35 
36 _LOGGER = logging.getLogger(__name__)
37 
38 ATTR_CLIMB = "climb"
39 ATTR_ELEVATION = "elevation"
40 ATTR_GPS_TIME = "gps_time"
41 ATTR_SPEED = "speed"
42 
43 DEFAULT_NAME = "GPS"
44 
45 _MODE_VALUES = {2: "2d_fix", 3: "3d_fix"}
46 
47 
48 @dataclass(frozen=True, kw_only=True)
50  """Class describing GPSD sensor entities."""
51 
52  value_fn: Callable[[AGPS3mechanism], StateType | datetime]
53 
54 
55 SENSOR_TYPES: tuple[GpsdSensorDescription, ...] = (
57  key=ATTR_MODE,
58  translation_key=ATTR_MODE,
59  name=None,
60  entity_category=EntityCategory.DIAGNOSTIC,
61  device_class=SensorDeviceClass.ENUM,
62  options=list(_MODE_VALUES.values()),
63  value_fn=lambda agps_thread: _MODE_VALUES.get(agps_thread.data_stream.mode),
64  ),
66  key=ATTR_LATITUDE,
67  translation_key=ATTR_LATITUDE,
68  entity_category=EntityCategory.DIAGNOSTIC,
69  value_fn=lambda agps_thread: agps_thread.data_stream.lat,
70  entity_registry_enabled_default=False,
71  ),
73  key=ATTR_LONGITUDE,
74  translation_key=ATTR_LONGITUDE,
75  entity_category=EntityCategory.DIAGNOSTIC,
76  value_fn=lambda agps_thread: agps_thread.data_stream.lon,
77  entity_registry_enabled_default=False,
78  ),
80  key=ATTR_ELEVATION,
81  translation_key=ATTR_ELEVATION,
82  entity_category=EntityCategory.DIAGNOSTIC,
83  device_class=SensorDeviceClass.DISTANCE,
84  native_unit_of_measurement=UnitOfLength.METERS,
85  value_fn=lambda agps_thread: agps_thread.data_stream.alt,
86  suggested_display_precision=2,
87  entity_registry_enabled_default=False,
88  ),
90  key=ATTR_TIME,
91  translation_key=ATTR_TIME,
92  entity_category=EntityCategory.DIAGNOSTIC,
93  device_class=SensorDeviceClass.TIMESTAMP,
94  value_fn=lambda agps_thread: dt_util.parse_datetime(
95  agps_thread.data_stream.time
96  ),
97  entity_registry_enabled_default=False,
98  ),
100  key=ATTR_SPEED,
101  translation_key=ATTR_SPEED,
102  entity_category=EntityCategory.DIAGNOSTIC,
103  device_class=SensorDeviceClass.SPEED,
104  native_unit_of_measurement=UnitOfSpeed.METERS_PER_SECOND,
105  value_fn=lambda agps_thread: agps_thread.data_stream.speed,
106  suggested_display_precision=2,
107  entity_registry_enabled_default=False,
108  ),
110  key=ATTR_CLIMB,
111  translation_key=ATTR_CLIMB,
112  entity_category=EntityCategory.DIAGNOSTIC,
113  device_class=SensorDeviceClass.SPEED,
114  native_unit_of_measurement=UnitOfSpeed.METERS_PER_SECOND,
115  value_fn=lambda agps_thread: agps_thread.data_stream.climb,
116  suggested_display_precision=2,
117  entity_registry_enabled_default=False,
118  ),
119 )
120 
121 
123  hass: HomeAssistant,
124  config_entry: GPSDConfigEntry,
125  async_add_entities: AddEntitiesCallback,
126 ) -> None:
127  """Set up the GPSD component."""
129  [
130  GpsdSensor(
131  config_entry.runtime_data,
132  config_entry.entry_id,
133  description,
134  )
135  for description in SENSOR_TYPES
136  ]
137  )
138 
139 
141  """Representation of a GPS receiver available via GPSD."""
142 
143  _attr_has_entity_name = True
144 
145  entity_description: GpsdSensorDescription
146 
147  def __init__(
148  self,
149  agps_thread: AGPS3mechanism,
150  unique_id: str,
151  description: GpsdSensorDescription,
152  ) -> None:
153  """Initialize the GPSD sensor."""
154  self.entity_descriptionentity_description = description
155  self._attr_device_info_attr_device_info = DeviceInfo(
156  identifiers={(DOMAIN, unique_id)},
157  entry_type=DeviceEntryType.SERVICE,
158  )
159  self._attr_unique_id_attr_unique_id = f"{unique_id}-{self.entity_description.key}"
160 
161  self.agps_threadagps_thread = agps_thread
162 
163  @property
164  def native_value(self) -> StateType | datetime:
165  """Return the state of GPSD."""
166  value = self.entity_descriptionentity_description.value_fn(self.agps_threadagps_thread)
167  return None if value == "n/a" else value
168 
169  # Deprecated since Home Assistant 2024.9.0
170  # Can be removed completely in 2025.3.0
171  @property
172  def extra_state_attributes(self) -> dict[str, Any] | None:
173  """Return the state attributes of the GPS."""
174  if self.entity_descriptionentity_description.key != ATTR_MODE:
175  return None
176 
177  return {
178  ATTR_LATITUDE: self.agps_threadagps_thread.data_stream.lat,
179  ATTR_LONGITUDE: self.agps_threadagps_thread.data_stream.lon,
180  ATTR_ELEVATION: self.agps_threadagps_thread.data_stream.alt,
181  ATTR_GPS_TIME: self.agps_threadagps_thread.data_stream.time,
182  ATTR_SPEED: self.agps_threadagps_thread.data_stream.speed,
183  ATTR_CLIMB: self.agps_threadagps_thread.data_stream.climb,
184  ATTR_MODE: self.agps_threadagps_thread.data_stream.mode,
185  }
dict[str, Any]|None extra_state_attributes(self)
Definition: sensor.py:172
StateType|datetime native_value(self)
Definition: sensor.py:164
None __init__(self, AGPS3mechanism agps_thread, str unique_id, GpsdSensorDescription description)
Definition: sensor.py:152
None async_setup_entry(HomeAssistant hass, GPSDConfigEntry config_entry, AddEntitiesCallback async_add_entities)
Definition: sensor.py:126