0922cc1d68
- 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).
100 lines
3.0 KiB
Python
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,
|
|
}
|