diff --git a/homeassistant/components/minecraft_server/binary_sensor.py b/homeassistant/components/minecraft_server/binary_sensor.py index 3721a50b1de..51978d388b6 100644 --- a/homeassistant/components/minecraft_server/binary_sensor.py +++ b/homeassistant/components/minecraft_server/binary_sensor.py @@ -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) + async_add_entities( + [ + MinecraftServerBinarySensorEntity(server, description) + for description in BINARY_SENSOR_DESCRIPTIONS + ], + True, + ) -class MinecraftServerStatusBinarySensor(MinecraftServerEntity, BinarySensorEntity): - """Representation of a Minecraft Server status binary sensor.""" +class MinecraftServerBinarySensorEntity(MinecraftServerEntity, BinarySensorEntity): + """Representation of a Minecraft Server binary sensor base entity.""" - _attr_translation_key = KEY_STATUS + entity_description: MinecraftServerBinarySensorEntityDescription - 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, - ) + 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 diff --git a/homeassistant/components/minecraft_server/entity.py b/homeassistant/components/minecraft_server/entity.py index 9048cb94004..4702b42beb9 100644 --- a/homeassistant/components/minecraft_server/entity.py +++ b/homeassistant/components/minecraft_server/entity.py @@ -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: diff --git a/homeassistant/components/minecraft_server/sensor.py b/homeassistant/components/minecraft_server/sensor.py index e17050310a8..cb3be3e58d7 100644 --- a/homeassistant/components/minecraft_server/sensor.py +++ b/homeassistant/components/minecraft_server/sensor.py @@ -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, - ) - - 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 + if self.entity_description.attributes_fn: + self._attr_extra_state_attributes = self.entity_description.attributes_fn( + self._server.data + )