Source code for de_twin.holder

"""In-situ holders: the de_autopilot heater duck type plus ``state(t) -> HolderState``.

* :class:`NoHolder` - a plain holder at room temperature.
* :class:`SimHeatingHolder` - MEMS heating (optionally biasing) chip model.
* :class:`ImpulseFollower` - a DENSsolutions holder (or DENS's simulator) via impulsePy.
* :func:`connect_holder` - ``"none" | "sim-heating" | "sim-biasing" | "impulse"``.
"""

from __future__ import annotations

import logging

from .base import (
    DEFAULT_RAMP_RATE,
    DEFAULT_TOLERANCE_C,
    ChannelUnsupported,
    HeaterUnavailable,
    NoHolder,
    Reading,
)
from .impulse import ImpulseFollower
from .sim import SimHeatingHolder

log = logging.getLogger(__name__)


[docs] def connect_holder(spec=None, *, clock=None, strict: bool = False, **kwargs): """Build a holder from a spec string (or return a holder object unchanged). ``"none"`` (or None/"") -> :class:`NoHolder`; ``"sim-heating"`` (aliases "sim", "heating") -> :class:`SimHeatingHolder`; ``"sim-biasing"`` (alias "sim-heating-biasing") -> the same with a bias channel; ``"impulse"`` -> :class:`ImpulseFollower`. If impulsePy is missing or Impulse does not answer, a :class:`SimHeatingHolder` stands in with the reason (autopilot's behaviour) unless ``strict=True``. Extra kwargs go to the holder. """ if spec is not None and not isinstance(spec, str): return spec key = (spec or "none").strip().lower() if key in ("none", "no", "off", ""): return NoHolder(clock=clock) if key in ("sim-heating", "sim", "heating", "sim_heating"): return SimHeatingHolder(clock=clock, **kwargs) if key in ("sim-biasing", "sim-heating-biasing", "biasing", "heating-biasing"): kwargs.setdefault("bias", True) return SimHeatingHolder(clock=clock, **kwargs) if key in ("impulse", "dens", "impulsepy"): try: follower = ImpulseFollower(kwargs.pop("impulse", None), clock=clock) try: log.info("Impulse status: %s", follower._impulse.getStatus()) except AttributeError: pass return follower except Exception as e: if strict: raise reason = ( f"impulsePy is not installed ({e})" if isinstance(e, ImportError) else f"Impulse did not answer ({type(e).__name__}: {e})" ) log.warning("%s; using the simulated heating holder", reason) return SimHeatingHolder(reason=reason, clock=clock, **kwargs) raise ValueError(f"unknown holder spec {spec!r} (none | sim-heating | sim-biasing | impulse)")
__all__ = [ "DEFAULT_RAMP_RATE", "DEFAULT_TOLERANCE_C", "ChannelUnsupported", "HeaterUnavailable", "ImpulseFollower", "NoHolder", "Reading", "SimHeatingHolder", "connect_holder", ]