import logging from typing import Callable from monitorcontrol import get_monitors logger = logging.getLogger(__name__) VCP_INPUT_SOURCE = 0x60 class MonitorSwitcher: def __init__(self, config_manager): self._config_manager = config_manager self._on_switch_callbacks: list[Callable[[str], None]] = [] def apply_profile(self, profile_id: str) -> None: profile = self._config_manager.get_profile(profile_id) if profile is None: logger.warning("Profile not found: %s", profile_id) return monitors = list(get_monitors()) for input_cfg in profile["monitor_inputs"]: idx = input_cfg["monitor_index"] vcp_value = input_cfg["vcp_value"] if idx >= len(monitors): logger.warning( "Monitor index %d out of range (have %d)", idx, len(monitors) ) continue try: with monitors[idx] as monitor: monitor.vcp.set_vcp_feature(VCP_INPUT_SOURCE, vcp_value) logger.info("Monitor %d -> VCP input %d", idx, vcp_value) except Exception as exc: logger.warning("Monitor %d DDC/CI error: %s", idx, exc) self._config_manager.set_active_profile(profile_id) for cb in self._on_switch_callbacks: cb(profile_id) def on_switch(self, callback: Callable[[str], None]) -> None: self._on_switch_callbacks.append(callback) def list_monitors(self) -> list[dict]: result = [] for idx, monitor_handle in enumerate(get_monitors()): try: with monitor_handle as monitor: current = monitor.vcp.get_vcp_feature(VCP_INPUT_SOURCE) result.append({"index": idx, "current_vcp": current[0]}) except Exception as exc: logger.warning("Cannot query monitor %d: %s", idx, exc) result.append({"index": idx, "current_vcp": None}) return result