4156dedf5e
Restructure how displays are exposed in Home Assistant:
Each physical monitor is now its own HA device linked to the media-server
hub via `via_device`. The hub keeps the media_player + script buttons; per-
display devices hold the power switch, brightness slider, and the new
capability entities. This lets users place displays in their own area/room
and keeps related entities grouped together in the UI.
New platforms:
- sensor: DisplayResolutionSensor (diagnostic, from EDID)
- binary_sensor: DisplayPrimaryBinarySensor + DisplayPowerControlBinarySensor
(both diagnostic; help users see why a power switch is or isn't created)
- select: DisplayInputSourceSelect (HDMI1/DP1/...), DisplayColorPresetSelect
(color temperature), DisplayPictureModeSelect (VCP 0xDC scene modes)
- number: added DisplayContrastNumber alongside brightness
Other changes:
- display_device helper centralises the per-display DeviceInfo; pulls real
manufacturer/model from EDID; device name no longer prepends the hub
title since via_device already shows the hierarchy.
- api_client gains set_display_{contrast,input_source,color_preset,picture_mode}
and stops forcing `?refresh=true` on every poll so HA can ride the
server's TTL cache instead of triggering full DDC/CI probes per entity.
- select / number entities now check the server's `success` flag and re-
sync from the actual monitor state when a write was silently rejected
(some monitors honor reads but ignore writes for certain DDC/CI codes).
Bumps manifest.json to 0.3.0 - the device topology change is user-visible
and existing brightness/power entities migrate to per-display devices on
first reload (unique_ids are preserved).
57 lines
2.1 KiB
Python
57 lines
2.1 KiB
Python
"""Helpers for building per-display DeviceInfo.
|
|
|
|
Each physical monitor is exposed as its own HA device (linked back to the
|
|
media-server hub via `via_device`) so that per-display entities (power
|
|
switch, brightness, future per-display sensors) cluster together, can be
|
|
placed in their own area/room, and participate in device-based automations.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import Any
|
|
|
|
from homeassistant.config_entries import ConfigEntry
|
|
from homeassistant.helpers.entity import DeviceInfo
|
|
|
|
from .const import DOMAIN
|
|
|
|
|
|
def display_label(monitor: dict[str, Any]) -> str:
|
|
"""Return a user-friendly label for a display monitor.
|
|
|
|
Resolution is appended when available so that two monitors sharing a
|
|
name (e.g. two "Generic PnP Monitor" entries) remain distinguishable.
|
|
"""
|
|
name = monitor.get("name") or f"Monitor {monitor['id']}"
|
|
resolution = monitor.get("resolution")
|
|
if resolution:
|
|
return f"{name} ({resolution})"
|
|
return name
|
|
|
|
|
|
def display_device_identifier(entry: ConfigEntry, monitor_id: int) -> tuple[str, str]:
|
|
"""Return the stable identifier tuple for a per-display device."""
|
|
return (DOMAIN, f"{entry.entry_id}_display_{monitor_id}")
|
|
|
|
|
|
def display_device_info(entry: ConfigEntry, monitor: dict[str, Any]) -> DeviceInfo:
|
|
"""Build DeviceInfo for a per-display device linked to the hub.
|
|
|
|
Prefers the manufacturer/model reported by the monitor's EDID; falls back
|
|
to integration-level defaults so devices still appear sensibly even when
|
|
EDID parsing returns blanks.
|
|
"""
|
|
manufacturer = (monitor.get("manufacturer") or "").strip() or "Remote Media Player"
|
|
model = (monitor.get("model") or "").strip() or "Display"
|
|
|
|
return DeviceInfo(
|
|
identifiers={display_device_identifier(entry, monitor["id"])},
|
|
via_device=(DOMAIN, entry.entry_id),
|
|
# HA's device tree already shows the parent hub above its children
|
|
# via `via_device`, so re-stating the entry title here would just
|
|
# duplicate the hub name on every child row.
|
|
name=display_label(monitor),
|
|
manufacturer=manufacturer,
|
|
model=model,
|
|
)
|