Files
hms-mediaengine/packages/capabilities/hms_capabilities/probe.py
T
HMS MediaEngine Agent 0922cc1d68 Phase 0: Repository-Initialisierung nach Bauplan v1.2
- Struktur gemäß §8 (Eigentumsgrenzen), PLAN.md als normative Basis
- Pflichtdokumente: STATUS.md, ERRORS.md, TEST_REPORT.md, CHANGELOG.md, ADRs
- ADR-0001 Python 3.13-Pin, ADR-0002 GStreamer 1.28.6-Pin (Windows),
  ADR-0003 IPC TCP+MessagePack v1
- Kernpakete: hms_protocol, hms_domain, hms_parameter, hms_artnet,
  hms_adaptive, hms_capabilities, hms_plugin_sdk
- Renderer-Spike: D3D11-Primärpfad + Dev-GL-Pfad (§36 Nr. 4-5)
- Control Core: FastAPI REST + WebSocket (§36 Nr. 9)
- Beispielplugins: Passthrough + Gaussian Blur (3 Adaptive-Quality-
  Varianten, HLSL/GLSL/GLES)
- Tools: Art-Net-Emulator, Fixture-Generator (Master32/Layer64-CSV),
  Capability-Probe
- JSON-Schemas: IPC, Plugin, Projekt, Cluster
- 121 Unit-/Integrationstests grün, Ruff grün

Gate 0 bleibt offen: Hardwaremessungen nur auf echter Windows-Referenz-
hardware gültig (§29.7, §33).
2026-09-11 00:36:59 +02:00

100 lines
3.0 KiB
Python

"""Capability-Probe (PLAN.md §5, §5.2).
Phase 0: plattformneutrale Basis-Erkennung (CPU/RAM/OS) und Tier-Vergabe
nach gemessenen Fakten. GPU-/Decoder-/Display-Erkennung läuft auf dem
Zielsystem (D3D11/GL/GLES); hier kein Fake-Ergebnis (§33: keine nicht
getestete Dekodierung als Hardwarebeschleunigung ausgeben).
"""
from __future__ import annotations
import enum
class CapabilityTier(enum.StrEnum):
DESKTOP_FULL = "DESKTOP_FULL"
DESKTOP_LITE = "DESKTOP_LITE"
PI_LITE = "PI_LITE"
HEADLESS_CONTROL = "HEADLESS_CONTROL"
# Mindest-VRAM für DESKTOP_FULL (§5)
_DESKTOP_FULL_MIN_VRAM_GB = 8.0
def detect_cpu_ram() -> dict[str, object]:
"""Basis-Hardwareinformationen (plattformneutral, ohne Fake)."""
import os
import platform
info: dict[str, object] = {
"os": platform.system(),
"os_release": platform.release(),
"machine": platform.machine(),
"cpu_count": os.cpu_count() or 1,
"ram_total_gb": _ram_gb(),
}
return info
def _ram_gb() -> float:
"""RAM in GB; Linux via /proc/meminfo, sonst -1 (unbekannt, nicht geraten)."""
try:
with open("/proc/meminfo", encoding="ascii") as fh:
for line in fh:
if line.startswith("MemTotal:"):
kib = int(line.split()[1])
return round(kib / (1024 * 1024), 2)
except (OSError, ValueError):
pass
return -1.0
class CapabilityReport:
"""Ergebnis des Capability-Selbsttests (Phase 0: Skelett).
GPU/Decoder/Displays werden auf dem Zielsystem gemessen und hier
ergänzt; ein Report ohne GPU-Messung kann kein DESKTOP-Tier vergeben.
"""
def __init__(self) -> None:
self.cpu_ram = detect_cpu_ram()
self.gpu: dict[str, object] | None = None
self.decoders: dict[str, object] | None = None
self.displays: dict[str, object] | None = None
self.tier: CapabilityTier | None = None
self.fingerprint: str = "" # an Messwerte gebunden (§5.2)
def conclude_tier(
self,
has_gpu: bool,
vram_gb: float | None,
decode_ok: bool,
has_display: bool,
) -> CapabilityTier | None:
"""Vergibt das Tier nach gemessenen Fakten; None wenn unklar.
Unklar bedeutet: Gate 0 darf nicht grün melden, solange keine
Messwerte vorliegen (§33).
"""
if not has_display:
self.tier = CapabilityTier.HEADLESS_CONTROL
return self.tier
if not has_gpu or not decode_ok:
return None
if vram_gb is not None and vram_gb >= _DESKTOP_FULL_MIN_VRAM_GB:
self.tier = CapabilityTier.DESKTOP_FULL
else:
self.tier = CapabilityTier.DESKTOP_LITE
return self.tier
def as_dict(self) -> dict[str, object]:
return {
"cpu_ram": self.cpu_ram,
"gpu": self.gpu,
"decoders": self.decoders,
"displays": self.displays,
"tier": self.tier.value if self.tier else None,
"fingerprint": self.fingerprint,
}