UmberHubManager/fiwi/patch_panel.py

61 lines
1.8 KiB
Python

"""
Physical patch panel: front-panel position count for the rack (field workflow).
Stored in fiber_map.json as ``patch_panel``: ``{ "slots": N, "label": "" }``.
USB hub calibrate still walks hub ports; map keys 1…N align with panel positions.
"""
from __future__ import annotations
from dataclasses import dataclass
from typing import Any, Dict, Optional
from fiwi.constants import PANEL_SLOTS
_MAX_SLOTS = 256
@dataclass(frozen=True)
class PatchPanel:
"""Instantiated panel: ``slots`` front-panel positions (numbered 1…slots)."""
slots: int
label: str = ""
def __post_init__(self) -> None:
if self.slots < 1:
raise ValueError("patch panel slots must be >= 1")
if self.slots > _MAX_SLOTS:
raise ValueError(f"patch panel slots must be <= {_MAX_SLOTS}")
def to_map_blob(self) -> Dict[str, Any]:
d: Dict[str, Any] = {"slots": self.slots}
if self.label.strip():
d["label"] = self.label.strip()
return d
@classmethod
def from_map_blob(cls, blob: Any) -> Optional[PatchPanel]:
if not isinstance(blob, dict):
return None
s = blob.get("slots")
if isinstance(s, str) and s.strip().isdigit():
s = int(s.strip())
if not isinstance(s, int) or s < 1:
return None
if s > _MAX_SLOTS:
return None
lab = blob.get("label")
label = lab.strip() if isinstance(lab, str) else ""
return cls(slots=s, label=label)
def effective_panel_slots(doc: Optional[Dict[str, Any]]) -> int:
"""Panel position count from ``doc['patch_panel']``, else ``PANEL_SLOTS``."""
if not isinstance(doc, dict):
return PANEL_SLOTS
pp = PatchPanel.from_map_blob(doc.get("patch_panel"))
if pp is not None:
return pp.slots
return PANEL_SLOTS