Add sensor entity descriptions in Minecraft Server (#99971)

* Add sensor entity descriptions

* Fix review findings

* Fix type of value function to avoid inline lambda if conditions and add attribute function to avoid extra sensor entity class

* Correct name of binary sensor base entity

* Simplify adding of entities in platforms

* Do not use keyword arguments while adding entities
This commit is contained in:
elmurato 2023-09-10 10:20:26 +02:00 committed by GitHub
parent 4153181cd3
commit 1f3b3b1be3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 146 additions and 158 deletions

View File

@ -1,7 +1,10 @@
"""The Minecraft Server binary sensor platform."""
from dataclasses import dataclass
from homeassistant.components.binary_sensor import (
BinarySensorDeviceClass,
BinarySensorEntity,
BinarySensorEntityDescription,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
@ -12,6 +15,21 @@ from .const import DOMAIN, ICON_STATUS, KEY_STATUS
from .entity import MinecraftServerEntity
@dataclass
class MinecraftServerBinarySensorEntityDescription(BinarySensorEntityDescription):
"""Class describing Minecraft Server binary sensor entities."""
BINARY_SENSOR_DESCRIPTIONS = [
MinecraftServerBinarySensorEntityDescription(
key=KEY_STATUS,
translation_key=KEY_STATUS,
device_class=BinarySensorDeviceClass.CONNECTIVITY,
icon=ICON_STATUS,
),
]
async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
@ -20,28 +38,32 @@ async def async_setup_entry(
"""Set up the Minecraft Server binary sensor platform."""
server = hass.data[DOMAIN][config_entry.entry_id]
# Create entities list.
entities = [MinecraftServerStatusBinarySensor(server)]
# Add binary sensor entities.
async_add_entities(entities, True)
class MinecraftServerStatusBinarySensor(MinecraftServerEntity, BinarySensorEntity):
"""Representation of a Minecraft Server status binary sensor."""
_attr_translation_key = KEY_STATUS
def __init__(self, server: MinecraftServer) -> None:
"""Initialize status binary sensor."""
super().__init__(
server=server,
entity_type=KEY_STATUS,
icon=ICON_STATUS,
device_class=BinarySensorDeviceClass.CONNECTIVITY,
async_add_entities(
[
MinecraftServerBinarySensorEntity(server, description)
for description in BINARY_SENSOR_DESCRIPTIONS
],
True,
)
class MinecraftServerBinarySensorEntity(MinecraftServerEntity, BinarySensorEntity):
"""Representation of a Minecraft Server binary sensor base entity."""
entity_description: MinecraftServerBinarySensorEntityDescription
def __init__(
self,
server: MinecraftServer,
description: MinecraftServerBinarySensorEntityDescription,
) -> None:
"""Initialize binary sensor base entity."""
super().__init__(server=server)
self.entity_description = description
self._attr_unique_id = f"{server.unique_id}-{description.key}"
self._attr_is_on = False
async def async_update(self) -> None:
"""Update status."""
"""Update binary sensor state."""
self._attr_is_on = self._server.online

View File

@ -19,23 +19,16 @@ class MinecraftServerEntity(Entity):
def __init__(
self,
server: MinecraftServer,
entity_type: str,
icon: str,
device_class: str | None,
) -> None:
"""Initialize base entity."""
self._server = server
self._attr_icon = icon
self._attr_unique_id = f"{self._server.unique_id}-{entity_type}"
self._attr_device_info = DeviceInfo(
identifiers={(DOMAIN, self._server.unique_id)},
identifiers={(DOMAIN, server.unique_id)},
manufacturer=MANUFACTURER,
model=f"Minecraft Server ({self._server.data.version})",
name=self._server.name,
sw_version=f"{self._server.data.protocol_version}",
model=f"Minecraft Server ({server.data.version})",
name=server.name,
sw_version=str(server.data.protocol_version),
)
self._attr_device_class = device_class
self._extra_state_attributes = None
self._disconnect_dispatcher: CALLBACK_TYPE | None = None
async def async_update(self) -> None:

View File

@ -1,13 +1,18 @@
"""The Minecraft Server sensor platform."""
from __future__ import annotations
from homeassistant.components.sensor import SensorEntity
from collections.abc import Callable, MutableMapping
from dataclasses import dataclass
from typing import Any
from homeassistant.components.sensor import SensorEntity, SensorEntityDescription
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import UnitOfTime
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import StateType
from . import MinecraftServer
from . import MinecraftServer, MinecraftServerData
from .const import (
ATTR_PLAYERS_LIST,
DOMAIN,
@ -29,6 +34,84 @@ from .const import (
from .entity import MinecraftServerEntity
@dataclass
class MinecraftServerEntityDescriptionMixin:
"""Mixin values for Minecraft Server entities."""
value_fn: Callable[[MinecraftServerData], StateType]
attributes_fn: Callable[[MinecraftServerData], MutableMapping[str, Any]] | None
@dataclass
class MinecraftServerSensorEntityDescription(
SensorEntityDescription, MinecraftServerEntityDescriptionMixin
):
"""Class describing Minecraft Server sensor entities."""
def get_extra_state_attributes_players_list(
data: MinecraftServerData,
) -> dict[str, list[str]]:
"""Return players list as extra state attributes, if available."""
extra_state_attributes = {}
players_list = data.players_list
if players_list is not None and len(players_list) != 0:
extra_state_attributes[ATTR_PLAYERS_LIST] = players_list
return extra_state_attributes
SENSOR_DESCRIPTIONS = [
MinecraftServerSensorEntityDescription(
key=KEY_VERSION,
translation_key=KEY_VERSION,
icon=ICON_VERSION,
value_fn=lambda data: data.version,
attributes_fn=None,
),
MinecraftServerSensorEntityDescription(
key=KEY_PROTOCOL_VERSION,
translation_key=KEY_PROTOCOL_VERSION,
icon=ICON_PROTOCOL_VERSION,
value_fn=lambda data: data.protocol_version,
attributes_fn=None,
),
MinecraftServerSensorEntityDescription(
key=KEY_PLAYERS_MAX,
translation_key=KEY_PLAYERS_MAX,
native_unit_of_measurement=UNIT_PLAYERS_MAX,
icon=ICON_PLAYERS_MAX,
value_fn=lambda data: data.players_max,
attributes_fn=None,
),
MinecraftServerSensorEntityDescription(
key=KEY_LATENCY,
translation_key=KEY_LATENCY,
native_unit_of_measurement=UnitOfTime.MILLISECONDS,
suggested_display_precision=0,
icon=ICON_LATENCY,
value_fn=lambda data: data.latency,
attributes_fn=None,
),
MinecraftServerSensorEntityDescription(
key=KEY_MOTD,
translation_key=KEY_MOTD,
icon=ICON_MOTD,
value_fn=lambda data: data.motd,
attributes_fn=None,
),
MinecraftServerSensorEntityDescription(
key=KEY_PLAYERS_ONLINE,
translation_key=KEY_PLAYERS_ONLINE,
native_unit_of_measurement=UNIT_PLAYERS_ONLINE,
icon=ICON_PLAYERS_ONLINE,
value_fn=lambda data: data.players_online,
attributes_fn=get_extra_state_attributes_players_list,
),
]
async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
@ -37,151 +120,41 @@ async def async_setup_entry(
"""Set up the Minecraft Server sensor platform."""
server = hass.data[DOMAIN][config_entry.entry_id]
# Create entities list.
entities = [
MinecraftServerVersionSensor(server),
MinecraftServerProtocolVersionSensor(server),
MinecraftServerLatencySensor(server),
MinecraftServerPlayersOnlineSensor(server),
MinecraftServerPlayersMaxSensor(server),
MinecraftServerMOTDSensor(server),
]
# Add sensor entities.
async_add_entities(entities, True)
async_add_entities(
[
MinecraftServerSensorEntity(server, description)
for description in SENSOR_DESCRIPTIONS
],
True,
)
class MinecraftServerSensorEntity(MinecraftServerEntity, SensorEntity):
"""Representation of a Minecraft Server sensor base entity."""
entity_description: MinecraftServerSensorEntityDescription
def __init__(
self,
server: MinecraftServer,
entity_type: str,
icon: str,
unit: str | None = None,
device_class: str | None = None,
description: MinecraftServerSensorEntityDescription,
) -> None:
"""Initialize sensor base entity."""
super().__init__(server, entity_type, icon, device_class)
self._attr_native_unit_of_measurement = unit
super().__init__(server)
self.entity_description = description
self._attr_unique_id = f"{server.unique_id}-{description.key}"
@property
def available(self) -> bool:
"""Return sensor availability."""
return self._server.online
class MinecraftServerVersionSensor(MinecraftServerSensorEntity):
"""Representation of a Minecraft Server version sensor."""
_attr_translation_key = KEY_VERSION
def __init__(self, server: MinecraftServer) -> None:
"""Initialize version sensor."""
super().__init__(server=server, entity_type=KEY_VERSION, icon=ICON_VERSION)
async def async_update(self) -> None:
"""Update version."""
self._attr_native_value = self._server.data.version
"""Update sensor state."""
self._attr_native_value = self.entity_description.value_fn(self._server.data)
class MinecraftServerProtocolVersionSensor(MinecraftServerSensorEntity):
"""Representation of a Minecraft Server protocol version sensor."""
_attr_translation_key = KEY_PROTOCOL_VERSION
def __init__(self, server: MinecraftServer) -> None:
"""Initialize protocol version sensor."""
super().__init__(
server=server,
entity_type=KEY_PROTOCOL_VERSION,
icon=ICON_PROTOCOL_VERSION,
if self.entity_description.attributes_fn:
self._attr_extra_state_attributes = self.entity_description.attributes_fn(
self._server.data
)
async def async_update(self) -> None:
"""Update protocol version."""
self._attr_native_value = self._server.data.protocol_version
class MinecraftServerLatencySensor(MinecraftServerSensorEntity):
"""Representation of a Minecraft Server latency sensor."""
_attr_translation_key = KEY_LATENCY
def __init__(self, server: MinecraftServer) -> None:
"""Initialize latency sensor."""
super().__init__(
server=server,
entity_type=KEY_LATENCY,
icon=ICON_LATENCY,
unit=UnitOfTime.MILLISECONDS,
)
async def async_update(self) -> None:
"""Update latency."""
self._attr_native_value = self._server.data.latency
class MinecraftServerPlayersOnlineSensor(MinecraftServerSensorEntity):
"""Representation of a Minecraft Server online players sensor."""
_attr_translation_key = KEY_PLAYERS_ONLINE
def __init__(self, server: MinecraftServer) -> None:
"""Initialize online players sensor."""
super().__init__(
server=server,
entity_type=KEY_PLAYERS_ONLINE,
icon=ICON_PLAYERS_ONLINE,
unit=UNIT_PLAYERS_ONLINE,
)
async def async_update(self) -> None:
"""Update online players state and device state attributes."""
self._attr_native_value = self._server.data.players_online
extra_state_attributes = {}
players_list = self._server.data.players_list
if players_list is not None and len(players_list) != 0:
extra_state_attributes[ATTR_PLAYERS_LIST] = players_list
self._attr_extra_state_attributes = extra_state_attributes
class MinecraftServerPlayersMaxSensor(MinecraftServerSensorEntity):
"""Representation of a Minecraft Server maximum number of players sensor."""
_attr_translation_key = KEY_PLAYERS_MAX
def __init__(self, server: MinecraftServer) -> None:
"""Initialize maximum number of players sensor."""
super().__init__(
server=server,
entity_type=KEY_PLAYERS_MAX,
icon=ICON_PLAYERS_MAX,
unit=UNIT_PLAYERS_MAX,
)
async def async_update(self) -> None:
"""Update maximum number of players."""
self._attr_native_value = self._server.data.players_max
class MinecraftServerMOTDSensor(MinecraftServerSensorEntity):
"""Representation of a Minecraft Server MOTD sensor."""
_attr_translation_key = KEY_MOTD
def __init__(self, server: MinecraftServer) -> None:
"""Initialize MOTD sensor."""
super().__init__(
server=server,
entity_type=KEY_MOTD,
icon=ICON_MOTD,
)
async def async_update(self) -> None:
"""Update MOTD."""
self._attr_native_value = self._server.data.motd