1
0
mirror of https://github.com/home-assistant/core.git synced 2026-02-22 10:55:50 +00:00
Files

163 lines
5.1 KiB
Python

"""Platform for sensor integration for squeezebox."""
from __future__ import annotations
from collections.abc import Callable
from dataclasses import dataclass
from datetime import datetime
import logging
from typing import cast
from homeassistant.components.sensor import (
SensorDeviceClass,
SensorEntity,
SensorEntityDescription,
SensorStateClass,
)
from homeassistant.const import UnitOfTime
from homeassistant.core import HomeAssistant
from homeassistant.helpers.device_registry import format_mac
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from homeassistant.helpers.typing import StateType
from . import SqueezeboxConfigEntry
from .const import (
PLAYER_SENSOR_NEXT_ALARM,
SIGNAL_PLAYER_DISCOVERED,
STATUS_SENSOR_INFO_TOTAL_ALBUMS,
STATUS_SENSOR_INFO_TOTAL_ARTISTS,
STATUS_SENSOR_INFO_TOTAL_DURATION,
STATUS_SENSOR_INFO_TOTAL_GENRES,
STATUS_SENSOR_INFO_TOTAL_SONGS,
STATUS_SENSOR_LASTSCAN,
STATUS_SENSOR_OTHER_PLAYER_COUNT,
STATUS_SENSOR_PLAYER_COUNT,
)
from .entity import LMSStatusEntity, SqueezeboxEntity, SqueezeBoxPlayerUpdateCoordinator
# Coordinator is used to centralize the data updates
PARALLEL_UPDATES = 0
SERVER_STATUS_SENSORS: tuple[SensorEntityDescription, ...] = (
SensorEntityDescription(
key=STATUS_SENSOR_INFO_TOTAL_ALBUMS,
state_class=SensorStateClass.TOTAL,
),
SensorEntityDescription(
key=STATUS_SENSOR_INFO_TOTAL_ARTISTS,
state_class=SensorStateClass.TOTAL,
),
SensorEntityDescription(
key=STATUS_SENSOR_INFO_TOTAL_DURATION,
state_class=SensorStateClass.TOTAL,
device_class=SensorDeviceClass.DURATION,
native_unit_of_measurement=UnitOfTime.SECONDS,
suggested_unit_of_measurement=UnitOfTime.HOURS,
),
SensorEntityDescription(
key=STATUS_SENSOR_INFO_TOTAL_GENRES,
state_class=SensorStateClass.TOTAL,
),
SensorEntityDescription(
key=STATUS_SENSOR_INFO_TOTAL_SONGS,
state_class=SensorStateClass.TOTAL,
),
SensorEntityDescription(
key=STATUS_SENSOR_LASTSCAN,
device_class=SensorDeviceClass.TIMESTAMP,
),
SensorEntityDescription(
key=STATUS_SENSOR_PLAYER_COUNT,
state_class=SensorStateClass.TOTAL,
),
SensorEntityDescription(
key=STATUS_SENSOR_OTHER_PLAYER_COUNT,
state_class=SensorStateClass.TOTAL,
entity_registry_visible_default=False,
),
)
@dataclass(frozen=True, kw_only=True)
class PlayerSensorEntityDescription(SensorEntityDescription):
"""Describes player sensor entity."""
value_fn: Callable[[SqueezeboxSensorEntity], datetime | None]
PLAYER_SENSORS: tuple[PlayerSensorEntityDescription, ...] = (
PlayerSensorEntityDescription(
key=PLAYER_SENSOR_NEXT_ALARM,
translation_key=PLAYER_SENSOR_NEXT_ALARM,
device_class=SensorDeviceClass.TIMESTAMP,
value_fn=lambda sensor: sensor.coordinator.player.alarm_next,
),
)
_LOGGER = logging.getLogger(__name__)
async def async_setup_entry(
hass: HomeAssistant,
entry: SqueezeboxConfigEntry,
async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
"""Platform setup using common elements."""
# Add player sensor entities when player discovered
async def _player_discovered(
player_coordinator: SqueezeBoxPlayerUpdateCoordinator,
) -> None:
_LOGGER.debug(
"Setting up sensor entities for player %s, model %s",
player_coordinator.player.name,
player_coordinator.player.model,
)
async_add_entities(
SqueezeboxSensorEntity(player_coordinator, description)
for description in PLAYER_SENSORS
)
entry.async_on_unload(
async_dispatcher_connect(
hass, f"{SIGNAL_PLAYER_DISCOVERED}{entry.entry_id}", _player_discovered
)
)
async_add_entities(
ServerStatusSensor(entry.runtime_data.coordinator, description)
for description in SERVER_STATUS_SENSORS
)
class ServerStatusSensor(LMSStatusEntity, SensorEntity):
"""LMS Status based sensor from LMS via coordinator."""
@property
def native_value(self) -> StateType:
"""LMS Status directly from coordinator data."""
return cast(StateType, self.coordinator.data[self.entity_description.key])
class SqueezeboxSensorEntity(SqueezeboxEntity, SensorEntity):
"""Representation of player based sensors."""
entity_description: PlayerSensorEntityDescription
def __init__(
self,
coordinator: SqueezeBoxPlayerUpdateCoordinator,
description: PlayerSensorEntityDescription,
) -> None:
"""Initialize the SqueezeBox sensor."""
super().__init__(coordinator)
self.entity_description = description
self._attr_unique_id = f"{format_mac(self._player.player_id)}_{description.key}"
@property
def native_value(self) -> datetime | None:
"""Sensor value directly from player coordinator."""
return self.entity_description.value_fn(self)