Migrate GPSD extra state attributes to separate states (#122193)

* Migrate GPSD extra state attributes to separate states

* Use common translations

* Address feedback
This commit is contained in:
Jan Rieger 2024-08-13 10:37:43 +02:00 committed by GitHub
parent 6406065e1f
commit 86322973d0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 108 additions and 12 deletions

View File

@ -7,6 +7,15 @@
"2d_fix": "mdi:crosshairs-gps", "2d_fix": "mdi:crosshairs-gps",
"3d_fix": "mdi:crosshairs-gps" "3d_fix": "mdi:crosshairs-gps"
} }
},
"latitude": {
"default": "mdi:latitude"
},
"longitude": {
"default": "mdi:longitude"
},
"elevation": {
"default": "mdi:arrow-up-down"
} }
} }
} }

View File

@ -4,6 +4,7 @@ from __future__ import annotations
from collections.abc import Callable from collections.abc import Callable
from dataclasses import dataclass from dataclasses import dataclass
from datetime import datetime
import logging import logging
from typing import Any from typing import Any
@ -14,10 +15,20 @@ from homeassistant.components.sensor import (
SensorEntity, SensorEntity,
SensorEntityDescription, SensorEntityDescription,
) )
from homeassistant.const import ATTR_LATITUDE, ATTR_LONGITUDE, ATTR_MODE, EntityCategory from homeassistant.const import (
ATTR_LATITUDE,
ATTR_LONGITUDE,
ATTR_MODE,
ATTR_TIME,
EntityCategory,
UnitOfLength,
UnitOfSpeed,
)
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.helpers.device_registry import DeviceEntryType, DeviceInfo from homeassistant.helpers.device_registry import DeviceEntryType, DeviceInfo
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import StateType
from homeassistant.util import dt as dt_util
from . import GPSDConfigEntry from . import GPSDConfigEntry
from .const import DOMAIN from .const import DOMAIN
@ -38,19 +49,73 @@ _MODE_VALUES = {2: "2d_fix", 3: "3d_fix"}
class GpsdSensorDescription(SensorEntityDescription): class GpsdSensorDescription(SensorEntityDescription):
"""Class describing GPSD sensor entities.""" """Class describing GPSD sensor entities."""
value_fn: Callable[[AGPS3mechanism], str | None] value_fn: Callable[[AGPS3mechanism], StateType | datetime]
SENSOR_TYPES: tuple[GpsdSensorDescription, ...] = ( SENSOR_TYPES: tuple[GpsdSensorDescription, ...] = (
GpsdSensorDescription( GpsdSensorDescription(
key="mode", key=ATTR_MODE,
translation_key="mode", translation_key=ATTR_MODE,
name=None, name=None,
entity_category=EntityCategory.DIAGNOSTIC, entity_category=EntityCategory.DIAGNOSTIC,
device_class=SensorDeviceClass.ENUM, device_class=SensorDeviceClass.ENUM,
options=list(_MODE_VALUES.values()), options=list(_MODE_VALUES.values()),
value_fn=lambda agps_thread: _MODE_VALUES.get(agps_thread.data_stream.mode), value_fn=lambda agps_thread: _MODE_VALUES.get(agps_thread.data_stream.mode),
), ),
GpsdSensorDescription(
key=ATTR_LATITUDE,
translation_key=ATTR_LATITUDE,
entity_category=EntityCategory.DIAGNOSTIC,
value_fn=lambda agps_thread: agps_thread.data_stream.lat,
entity_registry_enabled_default=False,
),
GpsdSensorDescription(
key=ATTR_LONGITUDE,
translation_key=ATTR_LONGITUDE,
entity_category=EntityCategory.DIAGNOSTIC,
value_fn=lambda agps_thread: agps_thread.data_stream.lon,
entity_registry_enabled_default=False,
),
GpsdSensorDescription(
key=ATTR_ELEVATION,
translation_key=ATTR_ELEVATION,
entity_category=EntityCategory.DIAGNOSTIC,
device_class=SensorDeviceClass.DISTANCE,
native_unit_of_measurement=UnitOfLength.METERS,
value_fn=lambda agps_thread: agps_thread.data_stream.alt,
suggested_display_precision=2,
entity_registry_enabled_default=False,
),
GpsdSensorDescription(
key=ATTR_TIME,
translation_key=ATTR_TIME,
entity_category=EntityCategory.DIAGNOSTIC,
device_class=SensorDeviceClass.TIMESTAMP,
value_fn=lambda agps_thread: dt_util.parse_datetime(
agps_thread.data_stream.time
),
entity_registry_enabled_default=False,
),
GpsdSensorDescription(
key=ATTR_SPEED,
translation_key=ATTR_SPEED,
entity_category=EntityCategory.DIAGNOSTIC,
device_class=SensorDeviceClass.SPEED,
native_unit_of_measurement=UnitOfSpeed.METERS_PER_SECOND,
value_fn=lambda agps_thread: agps_thread.data_stream.speed,
suggested_display_precision=2,
entity_registry_enabled_default=False,
),
GpsdSensorDescription(
key=ATTR_CLIMB,
translation_key=ATTR_CLIMB,
entity_category=EntityCategory.DIAGNOSTIC,
device_class=SensorDeviceClass.SPEED,
native_unit_of_measurement=UnitOfSpeed.METERS_PER_SECOND,
value_fn=lambda agps_thread: agps_thread.data_stream.climb,
suggested_display_precision=2,
entity_registry_enabled_default=False,
),
) )
@ -96,13 +161,19 @@ class GpsdSensor(SensorEntity):
self.agps_thread = agps_thread self.agps_thread = agps_thread
@property @property
def native_value(self) -> str | None: def native_value(self) -> StateType | datetime:
"""Return the state of GPSD.""" """Return the state of GPSD."""
return self.entity_description.value_fn(self.agps_thread) value = self.entity_description.value_fn(self.agps_thread)
return None if value == "n/a" else value
# Deprecated since Home Assistant 2024.9.0
# Can be removed completely in 2025.3.0
@property @property
def extra_state_attributes(self) -> dict[str, Any]: def extra_state_attributes(self) -> dict[str, Any] | None:
"""Return the state attributes of the GPS.""" """Return the state attributes of the GPS."""
if self.entity_description.key != ATTR_MODE:
return None
return { return {
ATTR_LATITUDE: self.agps_thread.data_stream.lat, ATTR_LATITUDE: self.agps_thread.data_stream.lat,
ATTR_LONGITUDE: self.agps_thread.data_stream.lon, ATTR_LONGITUDE: self.agps_thread.data_stream.lon,

View File

@ -18,7 +18,15 @@
}, },
"entity": { "entity": {
"sensor": { "sensor": {
"latitude": { "name": "[%key:common::config_flow::data::latitude%]" },
"longitude": { "name": "[%key:common::config_flow::data::longitude%]" },
"elevation": { "name": "[%key:common::config_flow::data::elevation%]" },
"time": {
"name": "[%key:component::time_date::selector::display_options::options::time%]"
},
"climb": { "name": "Climb" },
"mode": { "mode": {
"name": "[%key:common::config_flow::data::mode%]",
"state": { "state": {
"2d_fix": "2D Fix", "2d_fix": "2D Fix",
"3d_fix": "3D Fix" "3d_fix": "3D Fix"
@ -28,11 +36,19 @@
"longitude": { "longitude": {
"name": "[%key:common::config_flow::data::longitude%]" "name": "[%key:common::config_flow::data::longitude%]"
}, },
"elevation": { "name": "Elevation" }, "elevation": {
"gps_time": { "name": "Time" }, "name": "[%key:common::config_flow::data::elevation%]"
"speed": { "name": "Speed" }, },
"climb": { "name": "Climb" }, "gps_time": {
"mode": { "name": "Mode" } "name": "[%key:component::time_date::selector::display_options::options::time%]"
},
"speed": {
"name": "[%key:component::sensor::entity_component::speed::name%]"
},
"climb": {
"name": "[%key:component::gpsd::entity::sensor::climb::name%]"
},
"mode": { "name": "[%key:common::config_flow::data::mode%]" }
} }
} }
} }