1
0
mirror of https://github.com/home-assistant/core.git synced 2026-04-02 16:36:08 +01:00
Files
core/homeassistant/components/chess_com/sensor.py
2026-03-25 16:27:58 +01:00

158 lines
4.9 KiB
Python

"""Sensor platform for Chess.com integration."""
from collections.abc import Callable
from dataclasses import dataclass
from typing import TYPE_CHECKING, Any
from chess_com_api import PlayerStats
from homeassistant.components.sensor import (
SensorEntity,
SensorEntityDescription,
SensorStateClass,
)
from homeassistant.const import EntityCategory
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from . import ChessConfigEntry
from .coordinator import ChessCoordinator, ChessData
from .entity import ChessEntity
@dataclass(kw_only=True, frozen=True)
class ChessEntityDescription(SensorEntityDescription):
"""Sensor description for Chess.com player."""
value_fn: Callable[[ChessData], float]
@dataclass(kw_only=True, frozen=True)
class ChessModeEntityDescription(SensorEntityDescription):
"""Sensor description for a Chess.com game mode."""
value_fn: Callable[[dict[str, Any]], float]
PLAYER_SENSORS: tuple[ChessEntityDescription, ...] = (
ChessEntityDescription(
key="followers",
translation_key="followers",
entity_category=EntityCategory.DIAGNOSTIC,
state_class=SensorStateClass.MEASUREMENT,
value_fn=lambda state: state.player.followers,
entity_registry_enabled_default=False,
),
)
GAME_MODE_SENSORS: tuple[ChessModeEntityDescription, ...] = (
ChessModeEntityDescription(
key="rating",
translation_key="rating",
state_class=SensorStateClass.MEASUREMENT,
value_fn=lambda mode: mode["last"]["rating"],
),
ChessModeEntityDescription(
key="won",
translation_key="won",
entity_category=EntityCategory.DIAGNOSTIC,
state_class=SensorStateClass.TOTAL_INCREASING,
value_fn=lambda mode: mode["record"]["win"],
),
ChessModeEntityDescription(
key="lost",
translation_key="lost",
entity_category=EntityCategory.DIAGNOSTIC,
state_class=SensorStateClass.TOTAL_INCREASING,
value_fn=lambda mode: mode["record"]["loss"],
),
ChessModeEntityDescription(
key="draw",
translation_key="draw",
entity_category=EntityCategory.DIAGNOSTIC,
state_class=SensorStateClass.TOTAL_INCREASING,
value_fn=lambda mode: mode["record"]["draw"],
),
)
GAME_MODES: dict[str, Callable[[PlayerStats], dict[str, Any] | None]] = {
"chess_daily": lambda stats: stats.chess_daily,
"chess_rapid": lambda stats: stats.chess_rapid,
"chess_bullet": lambda stats: stats.chess_bullet,
"chess_blitz": lambda stats: stats.chess_blitz,
"chess960_daily": lambda stats: stats.chess960_daily,
}
async def async_setup_entry(
hass: HomeAssistant,
entry: ChessConfigEntry,
async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
"""Initialize the entries."""
coordinator = entry.runtime_data
entities: list[SensorEntity] = [
ChessPlayerSensor(coordinator, description) for description in PLAYER_SENSORS
]
for game_mode, stats_fn in GAME_MODES.items():
if stats_fn(coordinator.data.stats) is not None:
entities.extend(
ChessGameModeSensor(coordinator, description, game_mode, stats_fn)
for description in GAME_MODE_SENSORS
)
async_add_entities(entities)
class ChessPlayerSensor(ChessEntity, SensorEntity):
"""Chess.com player sensor."""
entity_description: ChessEntityDescription
def __init__(
self,
coordinator: ChessCoordinator,
description: ChessEntityDescription,
) -> None:
"""Initialize the sensor."""
super().__init__(coordinator)
self.entity_description = description
self._attr_unique_id = f"{coordinator.config_entry.unique_id}.{description.key}"
@property
def native_value(self) -> float:
"""Return the state of the sensor."""
return self.entity_description.value_fn(self.coordinator.data)
class ChessGameModeSensor(ChessEntity, SensorEntity):
"""Chess.com game mode sensor."""
entity_description: ChessModeEntityDescription
def __init__(
self,
coordinator: ChessCoordinator,
description: ChessModeEntityDescription,
game_mode: str,
stats_fn: Callable[[PlayerStats], dict[str, Any] | None],
) -> None:
"""Initialize the sensor."""
super().__init__(coordinator)
self.entity_description = description
self._stats_fn = stats_fn
self._attr_unique_id = (
f"{coordinator.config_entry.unique_id}.{game_mode}.{description.key}"
)
self._attr_translation_key = f"{game_mode}_{description.translation_key}"
@property
def native_value(self) -> float:
"""Return the state of the sensor."""
mode_data = self._stats_fn(self.coordinator.data.stats)
if TYPE_CHECKING:
assert mode_data is not None
return self.entity_description.value_fn(mode_data)