Add Hyperion sensor to report active priority on each instance (#102333)
* Implement code review comments * Update homeassistant/components/hyperion/sensor.py --------- Co-authored-by: Erik Montnemery <erik@montnemery.com>
This commit is contained in:
parent
0134715e2b
commit
58d0420a6b
6 changed files with 408 additions and 1 deletions
210
homeassistant/components/hyperion/sensor.py
Normal file
210
homeassistant/components/hyperion/sensor.py
Normal file
|
@ -0,0 +1,210 @@
|
|||
"""Sensor platform for Hyperion."""
|
||||
from __future__ import annotations
|
||||
|
||||
import functools
|
||||
from typing import Any
|
||||
|
||||
from hyperion import client
|
||||
from hyperion.const import (
|
||||
KEY_COMPONENTID,
|
||||
KEY_ORIGIN,
|
||||
KEY_OWNER,
|
||||
KEY_PRIORITIES,
|
||||
KEY_PRIORITY,
|
||||
KEY_RGB,
|
||||
KEY_UPDATE,
|
||||
KEY_VALUE,
|
||||
KEY_VISIBLE,
|
||||
)
|
||||
|
||||
from homeassistant.components.sensor import SensorEntity, SensorEntityDescription
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.device_registry import DeviceInfo
|
||||
from homeassistant.helpers.dispatcher import (
|
||||
async_dispatcher_connect,
|
||||
async_dispatcher_send,
|
||||
)
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from . import (
|
||||
get_hyperion_device_id,
|
||||
get_hyperion_unique_id,
|
||||
listen_for_instance_updates,
|
||||
)
|
||||
from .const import (
|
||||
CONF_INSTANCE_CLIENTS,
|
||||
DOMAIN,
|
||||
HYPERION_MANUFACTURER_NAME,
|
||||
HYPERION_MODEL_NAME,
|
||||
SIGNAL_ENTITY_REMOVE,
|
||||
TYPE_HYPERION_SENSOR_BASE,
|
||||
TYPE_HYPERION_SENSOR_VISIBLE_PRIORITY,
|
||||
)
|
||||
|
||||
SENSORS = [TYPE_HYPERION_SENSOR_VISIBLE_PRIORITY]
|
||||
PRIORITY_SENSOR_DESCRIPTION = SensorEntityDescription(
|
||||
key="visible_priority",
|
||||
translation_key="visible_priority",
|
||||
icon="mdi:lava-lamp",
|
||||
)
|
||||
|
||||
|
||||
def _sensor_unique_id(server_id: str, instance_num: int, suffix: str) -> str:
|
||||
"""Calculate a sensor's unique_id."""
|
||||
return get_hyperion_unique_id(
|
||||
server_id,
|
||||
instance_num,
|
||||
f"{TYPE_HYPERION_SENSOR_BASE}_{suffix}",
|
||||
)
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up a Hyperion platform from config entry."""
|
||||
entry_data = hass.data[DOMAIN][config_entry.entry_id]
|
||||
server_id = config_entry.unique_id
|
||||
|
||||
@callback
|
||||
def instance_add(instance_num: int, instance_name: str) -> None:
|
||||
"""Add entities for a new Hyperion instance."""
|
||||
assert server_id
|
||||
sensors = [
|
||||
HyperionVisiblePrioritySensor(
|
||||
server_id,
|
||||
instance_num,
|
||||
instance_name,
|
||||
entry_data[CONF_INSTANCE_CLIENTS][instance_num],
|
||||
PRIORITY_SENSOR_DESCRIPTION,
|
||||
)
|
||||
]
|
||||
|
||||
async_add_entities(sensors)
|
||||
|
||||
@callback
|
||||
def instance_remove(instance_num: int) -> None:
|
||||
"""Remove entities for an old Hyperion instance."""
|
||||
assert server_id
|
||||
|
||||
for sensor in SENSORS:
|
||||
async_dispatcher_send(
|
||||
hass,
|
||||
SIGNAL_ENTITY_REMOVE.format(
|
||||
_sensor_unique_id(server_id, instance_num, sensor),
|
||||
),
|
||||
)
|
||||
|
||||
listen_for_instance_updates(hass, config_entry, instance_add, instance_remove)
|
||||
|
||||
|
||||
class HyperionSensor(SensorEntity):
|
||||
"""Sensor class."""
|
||||
|
||||
_attr_has_entity_name = True
|
||||
_attr_should_poll = False
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
server_id: str,
|
||||
instance_num: int,
|
||||
instance_name: str,
|
||||
hyperion_client: client.HyperionClient,
|
||||
entity_description: SensorEntityDescription,
|
||||
) -> None:
|
||||
"""Initialize the sensor."""
|
||||
self.entity_description = entity_description
|
||||
self._client = hyperion_client
|
||||
self._attr_native_value = None
|
||||
self._client_callbacks: dict[str, Any] = {}
|
||||
|
||||
device_id = get_hyperion_device_id(server_id, instance_num)
|
||||
|
||||
self._attr_device_info = DeviceInfo(
|
||||
identifiers={(DOMAIN, device_id)},
|
||||
manufacturer=HYPERION_MANUFACTURER_NAME,
|
||||
model=HYPERION_MODEL_NAME,
|
||||
name=instance_name,
|
||||
configuration_url=self._client.remote_url,
|
||||
)
|
||||
|
||||
@property
|
||||
def available(self) -> bool:
|
||||
"""Return server availability."""
|
||||
return bool(self._client.has_loaded_state)
|
||||
|
||||
async def async_added_to_hass(self) -> None:
|
||||
"""Register callbacks when entity added to hass."""
|
||||
self.async_on_remove(
|
||||
async_dispatcher_connect(
|
||||
self.hass,
|
||||
SIGNAL_ENTITY_REMOVE.format(self._attr_unique_id),
|
||||
functools.partial(self.async_remove, force_remove=True),
|
||||
)
|
||||
)
|
||||
|
||||
self._client.add_callbacks(self._client_callbacks)
|
||||
|
||||
async def async_will_remove_from_hass(self) -> None:
|
||||
"""Cleanup prior to hass removal."""
|
||||
self._client.remove_callbacks(self._client_callbacks)
|
||||
|
||||
|
||||
class HyperionVisiblePrioritySensor(HyperionSensor):
|
||||
"""Class that displays the visible priority of a Hyperion instance."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
server_id: str,
|
||||
instance_num: int,
|
||||
instance_name: str,
|
||||
hyperion_client: client.HyperionClient,
|
||||
entity_description: SensorEntityDescription,
|
||||
) -> None:
|
||||
"""Initialize the sensor."""
|
||||
|
||||
super().__init__(
|
||||
server_id, instance_num, instance_name, hyperion_client, entity_description
|
||||
)
|
||||
|
||||
self._attr_unique_id = _sensor_unique_id(
|
||||
server_id, instance_num, TYPE_HYPERION_SENSOR_VISIBLE_PRIORITY
|
||||
)
|
||||
|
||||
self._client_callbacks = {
|
||||
f"{KEY_PRIORITIES}-{KEY_UPDATE}": self._update_priorities
|
||||
}
|
||||
|
||||
@callback
|
||||
def _update_priorities(self, _: dict[str, Any] | None = None) -> None:
|
||||
"""Update Hyperion priorities."""
|
||||
state_value = None
|
||||
attrs = {}
|
||||
|
||||
for priority in self._client.priorities or []:
|
||||
if not (KEY_VISIBLE in priority and priority[KEY_VISIBLE] is True):
|
||||
continue
|
||||
|
||||
if priority[KEY_COMPONENTID] == "COLOR":
|
||||
state_value = priority[KEY_VALUE][KEY_RGB]
|
||||
else:
|
||||
state_value = priority[KEY_OWNER]
|
||||
|
||||
attrs = {
|
||||
"component_id": priority[KEY_COMPONENTID],
|
||||
"origin": priority[KEY_ORIGIN],
|
||||
"priority": priority[KEY_PRIORITY],
|
||||
"owner": priority[KEY_OWNER],
|
||||
}
|
||||
|
||||
if priority[KEY_COMPONENTID] == "COLOR":
|
||||
attrs["color"] = priority[KEY_VALUE]
|
||||
else:
|
||||
attrs["color"] = None
|
||||
|
||||
self._attr_native_value = state_value
|
||||
self._attr_extra_state_attributes = attrs
|
||||
|
||||
self.async_write_ha_state()
|
Loading…
Add table
Add a link
Reference in a new issue