Add two new sensors to Launch Library (#64203)

Co-authored-by: Joakim Sørensen <hi@ludeeus.dev>
This commit is contained in:
Simon Hansen 2022-01-18 20:58:36 +01:00 committed by GitHub
parent 6a0c3843e5
commit d8df62ba1b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 99 additions and 41 deletions

View File

@ -2,11 +2,18 @@
DOMAIN = "launch_library" DOMAIN = "launch_library"
ATTR_AGENCY = "agency" ATTR_LAUNCH_FACILITY = "facility"
ATTR_AGENCY_COUNTRY_CODE = "agency_country_code" ATTR_STREAM_LIVE = "stream_live"
ATTR_LAUNCH_TIME = "launch_time" ATTR_LAUNCH_PAD = "pad"
ATTR_STREAM = "stream" ATTR_LAUNCH_PAD_COUNTRY_CODE = "provider_country_code"
ATTR_LAUNCH_PROVIDER = "provider"
ATTR_WINDOW_START = "window_start"
ATTR_WINDOW_END = "window_end"
ATTRIBUTION = "Data provided by Launch Library." ATTRIBUTION = "Data provided by Launch Library."
DEFAULT_NAME = "Next launch" DEFAULT_NAME = "Next launch"
NEXT_LAUNCH = "next_launch"
LAUNCH_TIME = "launch_time"
LAUNCH_PROBABILITY = "launch_probability"

View File

@ -1,6 +1,9 @@
"""Support for Launch Library sensors.""" """Support for Launch Library sensors."""
from __future__ import annotations from __future__ import annotations
from collections.abc import Callable
from dataclasses import dataclass
from datetime import datetime
import logging import logging
from typing import Any from typing import Any
@ -9,11 +12,12 @@ import voluptuous as vol
from homeassistant.components.sensor import ( from homeassistant.components.sensor import (
PLATFORM_SCHEMA, PLATFORM_SCHEMA,
SensorDeviceClass,
SensorEntity, SensorEntity,
SensorEntityDescription, SensorEntityDescription,
) )
from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry
from homeassistant.const import CONF_NAME from homeassistant.const import CONF_NAME, PERCENTAGE, STATE_UNKNOWN
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant, callback
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
@ -22,15 +26,22 @@ from homeassistant.helpers.update_coordinator import (
CoordinatorEntity, CoordinatorEntity,
DataUpdateCoordinator, DataUpdateCoordinator,
) )
from homeassistant.util.dt import parse_datetime
from .const import ( from .const import (
ATTR_AGENCY, ATTR_LAUNCH_FACILITY,
ATTR_AGENCY_COUNTRY_CODE, ATTR_LAUNCH_PAD,
ATTR_LAUNCH_TIME, ATTR_LAUNCH_PAD_COUNTRY_CODE,
ATTR_STREAM, ATTR_LAUNCH_PROVIDER,
ATTR_STREAM_LIVE,
ATTR_WINDOW_END,
ATTR_WINDOW_START,
ATTRIBUTION, ATTRIBUTION,
DEFAULT_NAME, DEFAULT_NAME,
DOMAIN, DOMAIN,
LAUNCH_PROBABILITY,
LAUNCH_TIME,
NEXT_LAUNCH,
) )
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -41,10 +52,56 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
) )
SENSOR_DESCRIPTION = SensorEntityDescription( @dataclass
key="next_launch", class NextLaunchSensorEntityDescriptionMixin:
icon="mdi:rocket-launch", """Mixin for required keys."""
name=DEFAULT_NAME,
value_fn: Callable[[Launch], datetime | int | str | None]
attributes_fn: Callable[[Launch], dict[str, Any] | None]
@dataclass
class NextLaunchSensorEntityDescription(
SensorEntityDescription, NextLaunchSensorEntityDescriptionMixin
):
"""Describes a Next Launch sensor entity."""
SENSOR_DESCRIPTIONS: tuple[NextLaunchSensorEntityDescription, ...] = (
NextLaunchSensorEntityDescription(
key=NEXT_LAUNCH,
icon="mdi:rocket-launch",
name=DEFAULT_NAME,
value_fn=lambda next_launch: next_launch.name,
attributes_fn=lambda next_launch: {
ATTR_LAUNCH_PROVIDER: next_launch.launch_service_provider.name,
ATTR_LAUNCH_PAD: next_launch.pad.name,
ATTR_LAUNCH_FACILITY: next_launch.pad.location.name,
ATTR_LAUNCH_PAD_COUNTRY_CODE: next_launch.pad.location.country_code,
},
),
NextLaunchSensorEntityDescription(
key=LAUNCH_TIME,
icon="mdi:clock-outline",
name="Launch time",
device_class=SensorDeviceClass.TIMESTAMP,
value_fn=lambda next_launch: parse_datetime(next_launch.net),
attributes_fn=lambda next_launch: {
ATTR_WINDOW_START: next_launch.window_start,
ATTR_WINDOW_END: next_launch.window_end,
ATTR_STREAM_LIVE: next_launch.webcast_live,
},
),
NextLaunchSensorEntityDescription(
key=LAUNCH_PROBABILITY,
icon="mdi:dice-multiple",
name="Launch Probability",
native_unit_of_measurement=PERCENTAGE,
value_fn=lambda next_launch: next_launch.probability
if next_launch.probability != -1
else STATE_UNKNOWN,
attributes_fn=lambda next_launch: None,
),
) )
@ -76,65 +133,59 @@ async def async_setup_entry(
async_add_entities: AddEntitiesCallback, async_add_entities: AddEntitiesCallback,
) -> None: ) -> None:
"""Set up the sensor platform.""" """Set up the sensor platform."""
name = entry.data.get(CONF_NAME, DEFAULT_NAME) name = entry.data.get(CONF_NAME, DEFAULT_NAME)
coordinator = hass.data[DOMAIN] coordinator = hass.data[DOMAIN]
async_add_entities( async_add_entities(
[ NextLaunchSensor(
NextLaunchSensor( coordinator=coordinator,
coordinator, entry_id=entry.entry_id,
entry.entry_id, description=description,
name, name=name if description.key == NEXT_LAUNCH else None,
SENSOR_DESCRIPTION, )
), for description in SENSOR_DESCRIPTIONS
]
) )
class NextLaunchSensor(CoordinatorEntity, SensorEntity): class NextLaunchSensor(CoordinatorEntity, SensorEntity):
"""Representation of the next launch sensor.""" """Representation of the next launch sensors."""
_attr_attribution = ATTRIBUTION _attr_attribution = ATTRIBUTION
_next_launch: Launch | None = None _next_launch: Launch | None = None
entity_description: NextLaunchSensorEntityDescription
def __init__( def __init__(
self, self,
coordinator: DataUpdateCoordinator, coordinator: DataUpdateCoordinator,
entry_id: str, entry_id: str,
name: str, description: NextLaunchSensorEntityDescription,
description: SensorEntityDescription, name: str | None = None,
) -> None: ) -> None:
"""Initialize a Launch Library entity.""" """Initialize a Launch Library sensor."""
super().__init__(coordinator) super().__init__(coordinator)
self._attr_name = name if name:
self._attr_name = name
self._attr_unique_id = f"{entry_id}_{description.key}" self._attr_unique_id = f"{entry_id}_{description.key}"
self.entity_description = description self.entity_description = description
@property @property
def available(self) -> bool: def native_value(self) -> datetime | str | int | None:
"""Return if the sensor is available."""
return super().available and self._next_launch is not None
@property
def native_value(self) -> str | None:
"""Return the state of the sensor.""" """Return the state of the sensor."""
if self._next_launch is None: if self._next_launch is None:
return None return None
return self._next_launch.name return self.entity_description.value_fn(self._next_launch)
@property @property
def extra_state_attributes(self) -> dict[str, Any] | None: def extra_state_attributes(self) -> dict[str, Any] | None:
"""Return the attributes of the sensor.""" """Return the attributes of the sensor."""
if self._next_launch is None: if self._next_launch is None:
return None return None
return { return self.entity_description.attributes_fn(self._next_launch)
ATTR_LAUNCH_TIME: self._next_launch.net,
ATTR_AGENCY: self._next_launch.launch_service_provider.name, @property
ATTR_AGENCY_COUNTRY_CODE: self._next_launch.pad.location.country_code, def available(self) -> bool:
ATTR_STREAM: self._next_launch.webcast_live, """Return if the sensor is available."""
} return super().available and self._next_launch is not None
@callback @callback
def _handle_coordinator_update(self) -> None: def _handle_coordinator_update(self) -> None: