Skip to content

Models

All response models inherit from a base class with extra="allow" for forward-compatible parsing.

ATX

ATXState

ATX subsystem state.

enabled is False when the ATX plugin is disabled, in which case every action answers HTTP 400.

Source code in src/aiopikvm/models/atx.py
class ATXState(_Base):
    """ATX subsystem state.

    ``enabled`` is ``False`` when the ATX plugin is disabled, in which case
    every action answers HTTP 400.
    """

    enabled: bool
    busy: bool
    acts: ATXActs
    leds: ATXLeds

ATXActs

Which ATX action is running right now.

kvmd guards the power and reset lines separately, so a reset can be pending while the power line is free. ATXState.busy is the two of them combined.

Source code in src/aiopikvm/models/atx.py
class ATXActs(_Base):
    """Which ATX action is running right now.

    kvmd guards the power and reset lines separately, so a reset can be
    pending while the power line is free. ``ATXState.busy`` is the two of
    them combined.
    """

    power: bool
    reset: bool

ATXLeds

ATX LED indicators state.

Source code in src/aiopikvm/models/atx.py
class ATXLeds(_Base):
    """ATX LED indicators state."""

    power: bool
    hdd: bool

HID

HIDState

HID subsystem state.

Mirrors the shape returned by GET /api/hid. connected reports whether the target host has the HID plugged in, and only the MCU-based backends can tell — otg, ch9329 and bt report None. The MCU backends are also the only ones that implement HIDResource.set_connected(), so a bool here says that call does something. A None does not say the reverse: an MCU backend reports it too until its microcontroller has sent a status word carrying the flag.

Source code in src/aiopikvm/models/hid.py
class HIDState(_Base):
    """HID subsystem state.

    Mirrors the shape returned by ``GET /api/hid``. ``connected`` reports
    whether the target host has the HID plugged in, and only the MCU-based
    backends can tell — ``otg``, ``ch9329`` and ``bt`` report ``None``. The
    MCU backends are also the only ones that implement
    [`HIDResource.set_connected()`][aiopikvm.resources.hid.HIDResource.set_connected],
    so a ``bool`` here says that call does something. A ``None`` does not say
    the reverse: an MCU backend reports it too until its microcontroller has
    sent a status word carrying the flag.
    """

    enabled: bool
    online: bool
    busy: bool
    connected: bool | None = None
    keyboard: HIDKeyboard
    mouse: HIDMouse
    jiggler: HIDJiggler

HIDKeyboard

HID keyboard state.

Source code in src/aiopikvm/models/hid.py
class HIDKeyboard(_Base):
    """HID keyboard state."""

    online: bool
    leds: HIDKeyboardLeds
    outputs: HIDOutputs

HIDKeyboardLeds

Keyboard LED state as reported by the target host.

Source code in src/aiopikvm/models/hid.py
class HIDKeyboardLeds(_Base):
    """Keyboard LED state as reported by the target host."""

    caps: bool
    num: bool
    scroll: bool

HIDMouse

HID mouse state.

Source code in src/aiopikvm/models/hid.py
class HIDMouse(_Base):
    """HID mouse state."""

    online: bool
    absolute: bool
    outputs: HIDOutputs

HIDOutputs

Selectable HID output modes for one device.

available is empty and active is an empty string on backends that cannot switch modes at runtime — the OTG keyboard, for instance.

Source code in src/aiopikvm/models/hid.py
class HIDOutputs(_Base):
    """Selectable HID output modes for one device.

    ``available`` is empty and ``active`` is an empty string on backends that
    cannot switch modes at runtime — the OTG keyboard, for instance.
    """

    active: str
    available: list[str]

HIDJiggler

Mouse jiggler — the anti-idle mover built into kvmd.

Two flags that read alike and are not the same. HIDResource.set_params() with jiggler writes active, which is whether it is running now. enabled says the device was configured with a jiggler at all and no API call moves it, so a caller who checks enabled after a write sees it unchanged and concludes the write was ignored.

interval is the idle time in seconds before it starts nudging the pointer, and is likewise read-only over the API.

Source code in src/aiopikvm/models/hid.py
class HIDJiggler(_Base):
    """Mouse jiggler — the anti-idle mover built into kvmd.

    Two flags that read alike and are not the same.
    [`HIDResource.set_params()`][aiopikvm.resources.hid.HIDResource.set_params]
    with ``jiggler`` writes ``active``, which is whether it is running now.
    ``enabled`` says the device was configured with a jiggler at all and no
    API call moves it, so a caller who checks ``enabled`` after a write sees
    it unchanged and concludes the write was ignored.

    ``interval`` is the idle time in seconds before it starts nudging the
    pointer, and is likewise read-only over the API.
    """

    enabled: bool
    active: bool
    interval: int

HIDKeymaps

Keyboard layouts installed on the device.

Returned by GET /api/hid/keymaps; the names are what HIDResource.type_text() accepts as its keymap argument.

Source code in src/aiopikvm/models/hid.py
class HIDKeymaps(_Base):
    """Keyboard layouts installed on the device.

    Returned by ``GET /api/hid/keymaps``; the names are what
    [`HIDResource.type_text()`][aiopikvm.resources.hid.HIDResource.type_text]
    accepts as its ``keymap`` argument.
    """

    default: str
    available: list[str]

MSD

MSDState

MSD subsystem state.

drive and storage are both None while the subsystem is offline — the MSD is disabled in the OTG profile, or kvmd has not finished setting it up. Neither is available without the other.

Source code in src/aiopikvm/models/msd.py
class MSDState(_Base):
    """MSD subsystem state.

    ``drive`` and ``storage`` are both ``None`` while the subsystem is
    offline — the MSD is disabled in the OTG profile, or kvmd has not
    finished setting it up. Neither is available without the other.
    """

    enabled: bool
    online: bool
    busy: bool
    drive: MSDDrive | None = None
    storage: MSDStorage | None = None

MSDDrive

The virtual drive presented to the target host.

Source code in src/aiopikvm/models/msd.py
class MSDDrive(_Base):
    """The virtual drive presented to the target host."""

    cdrom: bool
    connected: bool
    rw: bool
    image: MSDDriveImage | None = None

MSDStorage

MSD storage: what is on it and what is moving in or out of it.

Source code in src/aiopikvm/models/msd.py
class MSDStorage(_Base):
    """MSD storage: what is on it and what is moving in or out of it."""

    images: dict[str, MSDImage]
    parts: dict[str, MSDPart]
    downloading: MSDDownload | None = None
    uploading: MSDUpload | None = None

MSDImage

An image stored in MSD storage.

complete is False for an image whose upload was interrupted; kvmd keeps it in the listing so it can be resumed or removed.

Source code in src/aiopikvm/models/msd.py
class MSDImage(_Base):
    """An image stored in MSD storage.

    ``complete`` is ``False`` for an image whose upload was interrupted; kvmd
    keeps it in the listing so it can be resumed or removed.
    """

    complete: bool
    mod_ts: float
    removable: bool
    size: int
    writable: bool

MSDDriveImage

The image currently in the virtual drive.

kvmd reports two fields here that the storage listing leaves out, because the drive can also hold an image that is not in storage at all.

Source code in src/aiopikvm/models/msd.py
class MSDDriveImage(MSDImage):
    """The image currently in the virtual drive.

    kvmd reports two fields here that the storage listing leaves out, because
    the drive can also hold an image that is not in storage at all.
    """

    name: str
    in_storage: bool

MSDPart

A partition of the MSD storage. The root one is keyed by "".

Source code in src/aiopikvm/models/msd.py
class MSDPart(_Base):
    """A partition of the MSD storage. The root one is keyed by ``""``."""

    free: int
    size: int
    writable: bool

MSDUpload

Progress of an image being written to storage.

kvmd reports the same three fields in two places: under storage.uploading while a write is in flight, and as the body of the write endpoints themselves — once from /api/msd/write, once per line of the stream /api/msd/write_remote answers with.

name is the name kvmd stored the image under, which is not necessarily the one that was asked for: a prefix is joined on and the whole thing goes through kvmd's file-name validator. size is the total the write was opened for — the request's Content-Length, or the remote's — and written how much of it has landed.

Source code in src/aiopikvm/models/msd.py
class MSDUpload(_Base):
    """Progress of an image being written to storage.

    kvmd reports the same three fields in two places: under
    ``storage.uploading`` while a write is in flight, and as the body of the
    write endpoints themselves — once from ``/api/msd/write``, once per line
    of the stream ``/api/msd/write_remote`` answers with.

    ``name`` is the name kvmd stored the image under, which is not
    necessarily the one that was asked for: a ``prefix`` is joined on and the
    whole thing goes through kvmd's file-name validator. ``size`` is the
    total the write was opened for — the request's ``Content-Length``, or the
    remote's — and ``written`` how much of it has landed.
    """

    name: str
    size: int
    written: int

MSDDownload

Progress of a stored image being read back.

readed is spelled the way kvmd spells it on the wire.

Source code in src/aiopikvm/models/msd.py
class MSDDownload(_Base):
    """Progress of a stored image being read back.

    ``readed`` is spelled the way kvmd spells it on the wire.
    """

    name: str
    size: int
    readed: int

GPIO

GPIOState

GPIO subsystem state.

Mirrors GET /api/gpio: model describes the channels and the web UI layout, state holds their readings. inputs and outputs are shortcuts to the readings, which is what callers almost always want.

This is the shape of the REST response. The gpio WebSocket events carry partial updates and do not validate against it.

Source code in src/aiopikvm/models/gpio.py
class GPIOState(_Base):
    """GPIO subsystem state.

    Mirrors ``GET /api/gpio``: ``model`` describes the channels and the web
    UI layout, ``state`` holds their readings. ``inputs`` and ``outputs`` are
    shortcuts to the readings, which is what callers almost always want.

    This is the shape of the REST response. The ``gpio`` WebSocket events
    carry partial updates and do not validate against it.
    """

    model: GPIOModel
    state: GPIOIOState

    @property
    def inputs(self) -> dict[str, GPIOInput]:
        """Readings of the input channels."""
        return self.state.inputs

    @property
    def outputs(self) -> dict[str, GPIOChannel]:
        """Readings of the output channels."""
        return self.state.outputs

inputs property

Readings of the input channels.

outputs property

Readings of the output channels.

GPIOIOState

Current readings of every configured channel.

Source code in src/aiopikvm/models/gpio.py
class GPIOIOState(_Base):
    """Current readings of every configured channel."""

    inputs: dict[str, GPIOInput]
    outputs: dict[str, GPIOChannel]

GPIOChannel

GPIO output channel state.

busy is True while a switch or pulse is still running, and it is the field to read first: kvmd does not touch the pin for a busy channel, so state is False and online is True for the duration whatever the hardware is doing. That covers a switch to the state the channel already has, which still runs the action and still reads back as off while it does.

GPIOResource.switch() and pulse() answer as the action starts unless they are given wait=True, so a read taken straight after one of them lands inside that window by default.

Source code in src/aiopikvm/models/gpio.py
class GPIOChannel(_Base):
    """GPIO output channel state.

    ``busy`` is ``True`` while a switch or pulse is still running, and it is
    the field to read first: kvmd does not touch the pin for a busy channel,
    so ``state`` is ``False`` and ``online`` is ``True`` for the duration
    whatever the hardware is doing. That covers a switch to the state the
    channel already has, which still runs the action and still reads back as
    off while it does.

    [`GPIOResource.switch()`][aiopikvm.resources.gpio.GPIOResource.switch]
    and [`pulse()`][aiopikvm.resources.gpio.GPIOResource.pulse] answer as
    the action *starts* unless they are given ``wait=True``, so a read taken
    straight after one of them lands inside that window by default.
    """

    online: bool
    state: bool
    busy: bool

GPIOInput

GPIO input channel state.

Source code in src/aiopikvm/models/gpio.py
class GPIOInput(_Base):
    """GPIO input channel state."""

    online: bool
    state: bool

GPIOModel

The static half of the GPIO state: what exists and how it is drawn.

Source code in src/aiopikvm/models/gpio.py
class GPIOModel(_Base):
    """The static half of the GPIO state: what exists and how it is drawn."""

    scheme: GPIOScheme
    view: GPIOView

GPIOScheme

Channels kvmd is configured with, regardless of their current state.

Source code in src/aiopikvm/models/gpio.py
class GPIOScheme(_Base):
    """Channels kvmd is configured with, regardless of their current state."""

    inputs: dict[str, GPIOInputScheme]
    outputs: dict[str, GPIOOutputScheme]

GPIOOutputScheme

Configuration of an output channel.

Source code in src/aiopikvm/models/gpio.py
class GPIOOutputScheme(_Base):
    """Configuration of an output channel."""

    switch: bool
    pulse: GPIOPulse
    hw: GPIOHardware

GPIOInputScheme

Configuration of an input channel.

No capture covers this: the fixture device has no input channels. The shape comes from kvmd's ugpio.py, which builds it two lines away from the output scheme below.

Source code in src/aiopikvm/models/gpio.py
class GPIOInputScheme(_Base):
    """Configuration of an input channel.

    No capture covers this: the fixture device has no input channels. The
    shape comes from kvmd's ``ugpio.py``, which builds it two lines away from
    the output scheme below.
    """

    hw: GPIOHardware

GPIOPulse

Pulse limits of an output channel.

A delay of 0 means the channel does not support pulsing at all — kvmd answers GpioPulseNotSupported.

Source code in src/aiopikvm/models/gpio.py
class GPIOPulse(_Base):
    """Pulse limits of an output channel.

    A ``delay`` of ``0`` means the channel does not support pulsing at all —
    kvmd answers ``GpioPulseNotSupported``.
    """

    delay: float
    min_delay: float
    max_delay: float

GPIOHardware

Driver and pin backing a channel.

Source code in src/aiopikvm/models/gpio.py
class GPIOHardware(_Base):
    """Driver and pin backing a channel."""

    driver: str
    pin: str

GPIOView

Layout hints for the GPIO widget in the PiKVM web UI.

The items are deliberately left as dictionaries. kvmd emits three shapes here — label, input and output, told apart by type — and the captured device has an empty table, so a typed union would rest on kvmd's source alone and no test could hold it honest. This is layout metadata for the web UI; nothing in this client reads it. A None row is a separator.

Source code in src/aiopikvm/models/gpio.py
class GPIOView(_Base):
    """Layout hints for the GPIO widget in the PiKVM web UI.

    The items are deliberately left as dictionaries. kvmd emits three shapes
    here — ``label``, ``input`` and ``output``, told apart by ``type`` — and
    the captured device has an empty table, so a typed union would rest on
    kvmd's source alone and no test could hold it honest. This is layout
    metadata for the web UI; nothing in this client reads it. A ``None`` row
    is a separator.
    """

    header: GPIOViewHeader
    table: list[list[dict[str, Any]] | None]

GPIOViewHeader

Header of the GPIO widget.

Source code in src/aiopikvm/models/gpio.py
class GPIOViewHeader(_Base):
    """Header of the GPIO widget."""

    title: list[dict[str, Any]]

Streamer

StreamerState

Streamer subsystem state.

Mirrors the shape returned by GET /api/streamer. The streamer field is None when no stream clients are connected — kvmd stops the streamer process to save resources.

Source code in src/aiopikvm/models/streamer.py
class StreamerState(_Base):
    """Streamer subsystem state.

    Mirrors the shape returned by ``GET /api/streamer``. The ``streamer``
    field is ``None`` when no stream clients are connected — kvmd stops the
    streamer process to save resources.
    """

    features: StreamerFeatures
    limits: StreamerLimits
    params: StreamerParams
    applied: StreamerParams
    snapshot: StreamerSnapshot
    streamer: Streamer | None = None

Streamer

Running streamer process state.

Present only when the streamer is active. StreamerState.streamer is None when no clients are subscribed and kvmd has shut the streamer process down. h264 is absent unless ustreamer was built and configured with H.264 support.

Source code in src/aiopikvm/models/streamer.py
class Streamer(_Base):
    """Running streamer process state.

    Present only when the streamer is active. ``StreamerState.streamer`` is
    ``None`` when no clients are subscribed and kvmd has shut the streamer
    process down. ``h264`` is absent unless ustreamer was built and configured
    with H.264 support.
    """

    encoder: StreamerEncoder
    instance_id: str
    sinks: StreamerSinks
    source: StreamerSource
    stream: StreamerStream
    h264: StreamerH264 | None = None

StreamerSource

Streamer video source state.

Source code in src/aiopikvm/models/streamer.py
class StreamerSource(_Base):
    """Streamer video source state."""

    online: bool
    resolution: Resolution
    captured_fps: int
    desired_fps: int

Resolution

Video resolution.

Source code in src/aiopikvm/models/streamer.py
class Resolution(_Base):
    """Video resolution."""

    width: int
    height: int

StreamerParams

Streamer parameters.

Mirrors what the device supports: quality is absent when the capture path has no adjustable JPEG quality, resolution only exists on resolution-capable hardware, and the H.264 pair only when H.264 is configured. Used for both the requested parameters and the applied ones.

Source code in src/aiopikvm/models/streamer.py
class StreamerParams(_Base):
    """Streamer parameters.

    Mirrors what the device supports: ``quality`` is absent when the capture
    path has no adjustable JPEG quality, ``resolution`` only exists on
    resolution-capable hardware, and the H.264 pair only when H.264 is
    configured. Used for both the requested parameters and the applied ones.
    """

    desired_fps: int
    quality: int | None = None
    resolution: str | None = None
    h264_bitrate: int | None = None
    h264_gop: int | None = None

StreamerLimits

Limits for the tunable streamer parameters.

Only desired_fps is always present. kvmd adds the H.264 ranges only when H.264 is configured, and available_resolutions only on a device whose capture hardware can switch resolution.

Source code in src/aiopikvm/models/streamer.py
class StreamerLimits(_Base):
    """Limits for the tunable streamer parameters.

    Only ``desired_fps`` is always present. kvmd adds the H.264 ranges only
    when H.264 is configured, and ``available_resolutions`` only on a device
    whose capture hardware can switch resolution.
    """

    desired_fps: StreamerLimitRange
    h264_bitrate: StreamerLimitRange | None = None
    h264_gop: StreamerLimitRange | None = None
    available_resolutions: list[str] | None = None

StreamerLimitRange

Numeric parameter range.

Source code in src/aiopikvm/models/streamer.py
class StreamerLimitRange(_Base):
    """Numeric parameter range."""

    min: int
    max: int

StreamerFeatures

Streamer feature flags.

Source code in src/aiopikvm/models/streamer.py
class StreamerFeatures(_Base):
    """Streamer feature flags."""

    h264: bool
    quality: bool
    resolution: bool

SnapshotImage

A JPEG taken from the video stream, with what ustreamer said about it.

online is False when the frame is the "NO LIVE VIDEO" placeholder rather than a picture of the host, which is the only way to tell the two apart. A saved snapshot returned with load=True carries the same metadata it had when it was taken.

Everything but data is optional: these come from response headers that no capture in this repository pins down, so a header that is absent or unreadable leaves its field unset rather than failing the call. With preview=True the size still describes the source frame, not the scaled-down data.

Source code in src/aiopikvm/models/streamer.py
class SnapshotImage(_Base):
    """A JPEG taken from the video stream, with what ustreamer said about it.

    ``online`` is ``False`` when the frame is the "NO LIVE VIDEO" placeholder
    rather than a picture of the host, which is the only way to tell the two
    apart. A saved snapshot returned with ``load=True`` carries the same
    metadata it had when it was taken.

    Everything but ``data`` is optional: these come from response headers
    that no capture in this repository pins down, so a header that is absent
    or unreadable leaves its field unset rather than failing the call. With
    ``preview=True`` the size still describes the source frame, not the
    scaled-down ``data``.
    """

    data: bytes
    online: bool | None = None
    width: int | None = None
    height: int | None = None
    timestamp: float | None = None

StreamerSnapshot

The snapshot stored on the device, if any.

saved is None until something calls StreamerResource.snapshot() with save=True.

Source code in src/aiopikvm/models/streamer.py
class StreamerSnapshot(_Base):
    """The snapshot stored on the device, if any.

    ``saved`` is ``None`` until something calls
    [`StreamerResource.snapshot()`][aiopikvm.resources.streamer.StreamerResource.snapshot]
    with ``save=True``.
    """

    saved: SavedSnapshot | None = None

SavedSnapshot

Metadata of the snapshot stored on the device.

kvmd keeps the image itself out of the state and reports only what it was: whether the source was live and how big the frame is.

Source code in src/aiopikvm/models/streamer.py
class SavedSnapshot(_Base):
    """Metadata of the snapshot stored on the device.

    kvmd keeps the image itself out of the state and reports only what it
    was: whether the source was live and how big the frame is.
    """

    online: bool
    width: int
    height: int

StreamerEncoder

Streamer encoder configuration.

Source code in src/aiopikvm/models/streamer.py
class StreamerEncoder(_Base):
    """Streamer encoder configuration."""

    quality: int
    type: str

StreamerH264

H.264 encoder runtime state.

Source code in src/aiopikvm/models/streamer.py
class StreamerH264(_Base):
    """H.264 encoder runtime state."""

    bitrate: int
    fps: int
    gop: int
    online: bool

StreamerSinks

Streamer output sinks.

Source code in src/aiopikvm/models/streamer.py
class StreamerSinks(_Base):
    """Streamer output sinks."""

    h264: StreamerSinkInfo
    jpeg: StreamerSinkInfo

StreamerSinkInfo

Sink (jpeg/h264) client status.

Source code in src/aiopikvm/models/streamer.py
class StreamerSinkInfo(_Base):
    """Sink (jpeg/h264) client status."""

    has_clients: bool

StreamerStream

Stream connection statistics.

Source code in src/aiopikvm/models/streamer.py
class StreamerStream(_Base):
    """Stream connection statistics."""

    clients: int
    clients_stat: dict[str, StreamerClientStat]
    queued_fps: int

StreamerClientStat

One MJPEG client of the streamer, as ustreamer accounts for it.

Every field but fps echoes the query the client connected with, so a caller that passed a key to StreamerResource.mjpeg() can find its own row: the id these are keyed by is ustreamer's, assigned at connect and not known to the client that owns it.

Attributes:

Name Type Description
fps int

Frames per second ustreamer is sending this client.

key str

The key query parameter it connected with, "" if none.

extra_headers bool

Whether it asked for the X-UStreamer-* part headers.

advance_headers bool

Whether it asked for the Chromium workaround.

dual_final_frames bool

Whether it asked for the Safari workaround.

zero_data bool

Whether it asked for part headers without the JPEG data.

Source code in src/aiopikvm/models/streamer.py
class StreamerClientStat(_Base):
    """One MJPEG client of the streamer, as ustreamer accounts for it.

    Every field but ``fps`` echoes the query the client connected with, so a
    caller that passed a ``key`` to
    [`StreamerResource.mjpeg()`][aiopikvm.resources.streamer.StreamerResource.mjpeg]
    can find its own row: the id these are keyed by is ustreamer's, assigned
    at connect and not known to the client that owns it.

    Attributes:
        fps: Frames per second ustreamer is sending this client.
        key: The ``key`` query parameter it connected with, ``""`` if none.
        extra_headers: Whether it asked for the ``X-UStreamer-*`` part headers.
        advance_headers: Whether it asked for the Chromium workaround.
        dual_final_frames: Whether it asked for the Safari workaround.
        zero_data: Whether it asked for part headers without the JPEG data.
    """

    fps: int
    key: str = ""
    extra_headers: bool = False
    advance_headers: bool = False
    dual_final_frames: bool = False
    zero_data: bool = False

MJPEGFrame

One frame of the MJPEG stream, with what its part headers said.

data is a complete JPEG; the rest comes from the part headers, so a field is set only when the header was there and could be read. Without extra_headers=True only timestamp arrives — everything else is a X-UStreamer-* header ustreamer sends on request. headers keeps the raw part headers, including the timing ones this model does not name.

Attributes:

Name Type Description
data bytes

The JPEG bytes, empty when the stream was opened with zero_data=True.

timestamp float | None

X-Timestamp, a Unix time with microseconds.

online bool | None

Whether the frame is a picture of the host rather than the "NO LIVE VIDEO" placeholder.

width int | None

Frame width in pixels.

height int | None

Frame height in pixels.

dropped int | None

How many frames ustreamer dropped for this client so far.

client_fps int | None

The rate ustreamer is sending this client.

latency float | None

Seconds between grabbing the frame and sending it.

headers dict[str, str]

Every part header, as received.

Source code in src/aiopikvm/models/streamer.py
class MJPEGFrame(_Base):
    """One frame of the MJPEG stream, with what its part headers said.

    ``data`` is a complete JPEG; the rest comes from the part headers, so a
    field is set only when the header was there and could be read. Without
    ``extra_headers=True`` only ``timestamp`` arrives — everything else is a
    ``X-UStreamer-*`` header ustreamer sends on request. ``headers`` keeps the
    raw part headers, including the timing ones this model does not name.

    Attributes:
        data: The JPEG bytes, empty when the stream was opened with
            ``zero_data=True``.
        timestamp: ``X-Timestamp``, a Unix time with microseconds.
        online: Whether the frame is a picture of the host rather than the
            "NO LIVE VIDEO" placeholder.
        width: Frame width in pixels.
        height: Frame height in pixels.
        dropped: How many frames ustreamer dropped for this client so far.
        client_fps: The rate ustreamer is sending this client.
        latency: Seconds between grabbing the frame and sending it.
        headers: Every part header, as received.
    """

    data: bytes
    timestamp: float | None = None
    online: bool | None = None
    width: int | None = None
    height: int | None = None
    dropped: int | None = None
    client_fps: int | None = None
    latency: float | None = None
    headers: dict[str, str] = Field(default_factory=dict)

OCRInfo

OCR capability metadata returned by GET /api/streamer/ocr.

Source code in src/aiopikvm/models/streamer.py
class OCRInfo(_Base):
    """OCR capability metadata returned by ``GET /api/streamer/ocr``."""

    enabled: bool
    langs: OCRLangs

OCRLangs

Available and default OCR languages.

Source code in src/aiopikvm/models/streamer.py
class OCRLangs(_Base):
    """Available and default OCR languages."""

    available: list[str]
    default: list[str]

Media

MediaState

What the kvmd-media daemon offers, as GET /api/media returns it.

The same object arrives as the first frame of a MediaWebSocket opened without a format, where it is on MediaWebSocket.media.

Attributes:

Name Type Description
video MediaVideoFormats

The video formats the daemon can send.

Source code in src/aiopikvm/models/media.py
class MediaState(_Base):
    """What the kvmd-media daemon offers, as ``GET /api/media`` returns it.

    The same object arrives as the first frame of a
    [`MediaWebSocket`][aiopikvm.MediaWebSocket] opened without a format, where
    it is on [`MediaWebSocket.media`][aiopikvm.MediaWebSocket.media].

    Attributes:
        video: The video formats the daemon can send.
    """

    video: MediaVideoFormats

MediaVideoFormats

The video formats the daemon is configured with.

A format the daemon does not serve is simply absent, which is what makes both fields optional: a PiKVM v3 with H.264 offloaded to the hardware encoder publishes h264 and nothing else, and asking a MediaWebSocket for a format that is not here is refused with HTTP 400 before the socket exists.

Attributes:

Name Type Description
h264 MediaH264 | None

H.264 metadata, None when the daemon has no H.264 source.

jpeg MediaJPEG | None

MJPEG metadata, None when the daemon has no JPEG source.

Source code in src/aiopikvm/models/media.py
class MediaVideoFormats(_Base):
    """The video formats the daemon is configured with.

    A format the daemon does not serve is simply absent, which is what makes
    both fields optional: a PiKVM v3 with H.264 offloaded to the hardware
    encoder publishes ``h264`` and nothing else, and asking a
    [`MediaWebSocket`][aiopikvm.MediaWebSocket] for a format that is not here
    is refused with HTTP 400 before the socket exists.

    Attributes:
        h264: H.264 metadata, ``None`` when the daemon has no H.264 source.
        jpeg: MJPEG metadata, ``None`` when the daemon has no JPEG source.
    """

    h264: MediaH264 | None = None
    jpeg: MediaJPEG | None = None

MediaH264

What the daemon says about its H.264 source.

Attributes:

Name Type Description
profile_level_id str

The SDP profile-level-id of the stream, e.g. "42E01F" for constrained baseline at level 3.1. A WebRTC or SDP consumer needs it to describe the track it is about to receive; a caller that only wants the frames can ignore it.

Source code in src/aiopikvm/models/media.py
class MediaH264(_Base):
    """What the daemon says about its H.264 source.

    Attributes:
        profile_level_id: The SDP ``profile-level-id`` of the stream, e.g.
            ``"42E01F"`` for constrained baseline at level 3.1. A WebRTC or
            SDP consumer needs it to describe the track it is about to
            receive; a caller that only wants the frames can ignore it.
    """

    profile_level_id: str

MediaJPEG

What the daemon says about its JPEG source.

Nothing, on every kvmd this release was checked against: the daemon has no metadata to publish for MJPEG the way it does for H.264. The model exists so that the format shows up as present rather than as an unnamed extra when a device serves it.

Source code in src/aiopikvm/models/media.py
class MediaJPEG(_Base):
    """What the daemon says about its JPEG source.

    Nothing, on every kvmd this release was checked against: the daemon has
    no metadata to publish for MJPEG the way it does for H.264. The model
    exists so that the format shows up as present rather than as an unnamed
    extra when a device serves it.
    """

MediaFrame

One frame off the media socket.

Attributes:

Name Type Description
data bytes

The frame as the daemon sent it. For H.264 that is Annex B — a 00 00 00 01 start code, then the NAL header — and one message can carry several NAL units, an SPS and a PPS ahead of the keyframe they describe.

key bool | None

Whether this frame is a keyframe. None on a socket opened with a format, which sends the frame and nothing else; the flag only exists in the operation the format-less socket uses.

Source code in src/aiopikvm/models/media.py
class MediaFrame(_Base):
    """One frame off the media socket.

    Attributes:
        data: The frame as the daemon sent it. For H.264 that is Annex B —
            a ``00 00 00 01`` start code, then the NAL header — and one
            message can carry several NAL units, an SPS and a PPS ahead of
            the keyframe they describe.
        key: Whether this frame is a keyframe. ``None`` on a socket opened
            with a format, which sends the frame and nothing else; the flag
            only exists in the operation the format-less socket uses.
    """

    data: bytes
    key: bool | None = None

WebRTC

WebRTCFeatures

What this build of the ustreamer plugin can do.

Attributes:

Name Type Description
audio bool

Whether the device has a capture audio device, i.e. whether the host's sound can be streamed to the client.

mic bool

Whether the device has a playback audio device, i.e. whether the client's microphone can be sent to the host.

ice WebRTCICE

The ICE server the plugin suggests.

Source code in src/aiopikvm/models/webrtc.py
class WebRTCFeatures(_Base):
    """What this build of the ustreamer plugin can do.

    Attributes:
        audio: Whether the device has a capture audio device, i.e. whether the
            host's sound can be streamed to the client.
        mic: Whether the device has a playback audio device, i.e. whether the
            client's microphone can be sent to the host.
        ice: The ICE server the plugin suggests.
    """

    audio: bool = False
    mic: bool = False
    ice: WebRTCICE = WebRTCICE()

WebRTCICE

The ICE server the plugin suggests.

Attributes:

Name Type Description
url str | None

A STUN or TURN URL, e.g. "stun:stun.l.google.com:19302". It is whatever JANUS_USTREAMER_WEB_ICE_URL was set to on the device, falling back to the plugin's compiled-in default, and it can name a host on the public internet. The client does not use it unless it is asked to — see the ice_servers argument of PiKVM.webrtc(). None when the plugin was built without one.

Source code in src/aiopikvm/models/webrtc.py
class WebRTCICE(_Base):
    """The ICE server the plugin suggests.

    Attributes:
        url: A STUN or TURN URL, e.g. ``"stun:stun.l.google.com:19302"``. It
            is whatever ``JANUS_USTREAMER_WEB_ICE_URL`` was set to on the
            device, falling back to the plugin's compiled-in default, and it
            can name a host on the public internet. The client does not use it
            unless it is asked to — see the ``ice_servers`` argument of
            [`PiKVM.webrtc()`][aiopikvm.PiKVM.webrtc]. ``None`` when the
            plugin was built without one.
    """

    url: str | None = None

WebRTCEvent

One message Janus sent that answers nothing this client asked for.

These arrive whenever Janus has something to say: the peer connection came up, the link is congested, the peer connection ended, the session timed out. The plugin's own pushes arrive the same way, since it answers a request by pushing an event rather than by replying to it, which is why plugindata can be set on one of these.

An answer to something this client did send never arrives here — it is consumed where the request was made — so the transaction such an answer carries, and the error block a refusal carries, have no field here. A Janus-level refusal reaches a caller as WebRTCError instead.

Attributes:

Name Type Description
janus str

The kind — "webrtcup", "slowlink", "hangup", "timeout", "event", "media", and whatever a newer Janus adds.

sender int | None

The handle the message concerns. None on a message about the session as a whole.

session_id int | None

The session the message concerns.

plugindata WebRTCPluginData | None

The plugin's payload on an "event", None on anything else.

jsep WebRTCJSEP | None

The SDP beside a plugin push, which is how the offer arrives.

type str | None

On "media", which kind of media it is about — "video" or "audio".

mid str | None

On "media", the media identifier from the SDP — "v" for the ustreamer plugin's video, "a" for its audio.

receiving bool | None

On "media", whether packets of that kind are arriving. Janus events this for the media it receives, so a session that only watches never sees one.

uplink bool | None

On "slowlink", whether the congested direction is the one towards Janus.

lost int | None

On "slowlink", how many packets went missing.

reason str | None

On "hangup", why the peer connection ended.

Source code in src/aiopikvm/models/webrtc.py
class WebRTCEvent(_Base):
    """One message Janus sent that answers nothing this client asked for.

    These arrive whenever Janus has something to say: the peer connection came
    up, the link is congested, the peer connection ended, the session timed
    out. The plugin's own pushes arrive the same way, since it answers a
    request by pushing an event rather than by replying to it, which is why
    ``plugindata`` can be set on one of these.

    An answer to something this client *did* send never arrives here — it is
    consumed where the request was made — so the ``transaction`` such an
    answer carries, and the ``error`` block a refusal carries, have no field
    here. A Janus-level refusal reaches a caller as
    [`WebRTCError`][aiopikvm.WebRTCError] instead.

    Attributes:
        janus: The kind — ``"webrtcup"``, ``"slowlink"``, ``"hangup"``,
            ``"timeout"``, ``"event"``, ``"media"``, and whatever a newer
            Janus adds.
        sender: The handle the message concerns. ``None`` on a message about
            the session as a whole.
        session_id: The session the message concerns.
        plugindata: The plugin's payload on an ``"event"``, ``None`` on
            anything else.
        jsep: The SDP beside a plugin push, which is how the offer arrives.
        type: On ``"media"``, which kind of media it is about — ``"video"`` or
            ``"audio"``.
        mid: On ``"media"``, the media identifier from the SDP — ``"v"`` for
            the ustreamer plugin's video, ``"a"`` for its audio.
        receiving: On ``"media"``, whether packets of that kind are arriving.
            Janus events this for the media it *receives*, so a session that
            only watches never sees one.
        uplink: On ``"slowlink"``, whether the congested direction is the one
            towards Janus.
        lost: On ``"slowlink"``, how many packets went missing.
        reason: On ``"hangup"``, why the peer connection ended.
    """

    janus: str
    sender: int | None = None
    session_id: int | None = None
    plugindata: WebRTCPluginData | None = None
    jsep: WebRTCJSEP | None = None
    type: str | None = None
    mid: str | None = None
    receiving: bool | None = None
    uplink: bool | None = None
    lost: int | None = None
    reason: str | None = None

WebRTCJSEP

An SDP, as Janus carries one.

Only one message in a session has it: the plugin's answer to watch, which is the offer this client owes an answer to.

Attributes:

Name Type Description
type str

"offer" on everything the device sends; "answer" is what this client sends back inside start.

sdp str

The session description itself.

Source code in src/aiopikvm/models/webrtc.py
class WebRTCJSEP(_Base):
    """An SDP, as Janus carries one.

    Only one message in a session has it: the plugin's answer to ``watch``,
    which is the offer this client owes an answer to.

    Attributes:
        type: ``"offer"`` on everything the device sends; ``"answer"`` is what
            this client sends back inside ``start``.
        sdp: The session description itself.
    """

    type: str
    sdp: str

WebRTCPluginData

One plugin payload, as Janus wraps it.

Attributes:

Name Type Description
plugin str

The plugin package, "janus.plugin.ustreamer" for everything this client sends.

data WebRTCPluginEvent

What the plugin itself said.

Source code in src/aiopikvm/models/webrtc.py
class WebRTCPluginData(_Base):
    """One plugin payload, as Janus wraps it.

    Attributes:
        plugin: The plugin package, ``"janus.plugin.ustreamer"`` for
            everything this client sends.
        data: What the plugin itself said.
    """

    plugin: str
    data: WebRTCPluginEvent

WebRTCPluginEvent

What the ustreamer plugin itself said.

Either a result or an error, never both. An error here is a plugin error and rides inside a message Janus considers successful — Janus's own errors are a different shape, at the top level of the message.

Attributes:

Name Type Description
ustreamer str

Always "event"; the plugin stamps every message it pushes with it.

result WebRTCResult | None

The answer, when the request succeeded.

error_code int | None

The plugin's own code — 400 for a body with no request or one whose request is not a string, 405 for a request name it does not implement. None when the request succeeded.

error str | None

The text beside that code, e.g. "Not implemented".

Source code in src/aiopikvm/models/webrtc.py
class WebRTCPluginEvent(_Base):
    """What the ustreamer plugin itself said.

    Either a result or an error, never both. An error here is a *plugin*
    error and rides inside a message Janus considers successful — Janus's own
    errors are a different shape, at the top level of the message.

    Attributes:
        ustreamer: Always ``"event"``; the plugin stamps every message it
            pushes with it.
        result: The answer, when the request succeeded.
        error_code: The plugin's own code — 400 for a body with no ``request``
            or one whose ``request`` is not a string, 405 for a request name
            it does not implement. ``None`` when the request succeeded.
        error: The text beside that code, e.g. ``"Not implemented"``.
    """

    ustreamer: str = "event"
    result: WebRTCResult | None = None
    error_code: int | None = None
    error: str | None = None

WebRTCResult

The plugin's answer to a request that succeeded.

The plugin names the status and then repeats it as the key its payload hangs off, so a features answer is {"status": "features", "features": {...}} and a started answer is {"status": "started"} with nothing beside it.

Attributes:

Name Type Description
status str

"started" after watch and after start, "stopped" after stop, "features" after features.

features WebRTCFeatures | None

The payload of a features answer, None otherwise.

Source code in src/aiopikvm/models/webrtc.py
class WebRTCResult(_Base):
    """The plugin's answer to a request that succeeded.

    The plugin names the status and then repeats it as the key its payload
    hangs off, so a ``features`` answer is ``{"status": "features",
    "features": {...}}`` and a ``started`` answer is ``{"status": "started"}``
    with nothing beside it.

    Attributes:
        status: ``"started"`` after ``watch`` and after ``start``,
            ``"stopped"`` after ``stop``, ``"features"`` after ``features``.
        features: The payload of a ``features`` answer, ``None`` otherwise.
    """

    status: str
    features: WebRTCFeatures | None = None

Switch

SwitchState

KVM switch state.

Mirrors GET /api/switch. Every list is indexed by port number, and all of them are empty on a PiKVM without a switch — which is also the only configuration the fixtures cover.

Source code in src/aiopikvm/models/switch.py
class SwitchState(_Base):
    """KVM switch state.

    Mirrors ``GET /api/switch``. Every list is indexed by port number, and all
    of them are empty on a PiKVM without a switch — which is also the only
    configuration the fixtures cover.
    """

    model: SwitchModel
    summary: SwitchSummary
    edids: SwitchEdids
    colors: SwitchColors
    video: SwitchLinks
    usb: SwitchLinks
    beacons: SwitchBeacons
    atx: SwitchAtx

SwitchSummary

Which port is currently selected.

active_port is -1 when nothing is selected, and active_id is then an empty string. synced is False while the units are still catching up with the state kvmd wants them in.

Source code in src/aiopikvm/models/switch.py
class SwitchSummary(_Base):
    """Which port is currently selected.

    ``active_port`` is ``-1`` when nothing is selected, and ``active_id`` is
    then an empty string. ``synced`` is ``False`` while the units are still
    catching up with the state kvmd wants them in.
    """

    active_port: int
    active_id: str
    synced: bool

SwitchModel

The static half of the switch state.

units and ports are empty until the units have reported in, and stay empty on a PiKVM with no switch attached.

Source code in src/aiopikvm/models/switch.py
class SwitchModel(_Base):
    """The static half of the switch state.

    ``units`` and ``ports`` are empty until the units have reported in, and
    stay empty on a PiKVM with no switch attached.
    """

    firmware: SwitchFirmware
    units: list[SwitchUnit]
    ports: list[SwitchPort]
    limits: SwitchLimits

SwitchPort

A port of the switch chain.

id is what the web UI shows: "3" on a single unit, "2.3" once more than one unit is chained. Ports are addressed by their numeric index everywhere in the API, not by this string.

Source code in src/aiopikvm/models/switch.py
class SwitchPort(_Base):
    """A port of the switch chain.

    ``id`` is what the web UI shows: ``"3"`` on a single unit, ``"2.3"`` once
    more than one unit is chained. Ports are addressed by their numeric index
    everywhere in the API, not by this string.
    """

    unit: int
    channel: int
    name: str
    id: str
    atx: SwitchPortAtx
    video: SwitchPortVideo

SwitchPortAtx

ATX configuration of a port.

Source code in src/aiopikvm/models/switch.py
class SwitchPortAtx(_Base):
    """ATX configuration of a port."""

    click_delays: SwitchAtxClickDelays

SwitchPortVideo

Video configuration of a port.

Source code in src/aiopikvm/models/switch.py
class SwitchPortVideo(_Base):
    """Video configuration of a port."""

    dummy: bool

SwitchAtxClickDelays

How long each ATX button is held, in seconds.

Source code in src/aiopikvm/models/switch.py
class SwitchAtxClickDelays(_Base):
    """How long each ATX button is held, in seconds."""

    power: float
    power_long: float
    reset: float

SwitchUnit

One switch unit in the chain.

Source code in src/aiopikvm/models/switch.py
class SwitchUnit(_Base):
    """One switch unit in the chain."""

    firmware: SwitchUnitFirmware

SwitchUnitFirmware

Firmware running on one physical unit.

Source code in src/aiopikvm/models/switch.py
class SwitchUnitFirmware(_Base):
    """Firmware running on one physical unit."""

    version: int
    devbuild: bool

SwitchFirmware

Protocol version the switch subsystem speaks.

A constant of the kvmd build, unrelated to the firmware running on the units — that one is SwitchUnitFirmware.

Source code in src/aiopikvm/models/switch.py
class SwitchFirmware(_Base):
    """Protocol version the switch subsystem speaks.

    A constant of the kvmd build, unrelated to the firmware running on the
    units — that one is [`SwitchUnitFirmware`][aiopikvm.SwitchUnitFirmware].
    """

    version: int

SwitchLimits

What the switch accepts for the tunable port parameters.

Source code in src/aiopikvm/models/switch.py
class SwitchLimits(_Base):
    """What the switch accepts for the tunable port parameters."""

    atx: SwitchAtxLimits

SwitchAtxLimits

ATX limits of the switch.

Source code in src/aiopikvm/models/switch.py
class SwitchAtxLimits(_Base):
    """ATX limits of the switch."""

    click_delays: SwitchAtxClickDelayLimits

SwitchAtxClickDelayLimits

Allowed ranges for the three ATX click delays.

Source code in src/aiopikvm/models/switch.py
class SwitchAtxClickDelayLimits(_Base):
    """Allowed ranges for the three ATX click delays."""

    power: SwitchAtxClickDelayLimit
    power_long: SwitchAtxClickDelayLimit
    reset: SwitchAtxClickDelayLimit

SwitchAtxClickDelayLimit

Allowed range for one ATX click delay.

Source code in src/aiopikvm/models/switch.py
class SwitchAtxClickDelayLimit(_Base):
    """Allowed range for one ATX click delay."""

    default: float
    min: float
    max: float

SwitchEdids

The EDID catalogue.

all is keyed by EDID id — "default" always exists — and used lists the id in effect on each port, in port order.

Source code in src/aiopikvm/models/switch.py
class SwitchEdids(_Base):
    """The EDID catalogue.

    ``all`` is keyed by EDID id — ``"default"`` always exists — and ``used``
    lists the id in effect on each port, in port order.
    """

    all: dict[str, EDID]
    used: list[str]

EDID

An EDID the switch can present to a port.

parsed is None when kvmd could not decode the blob.

Source code in src/aiopikvm/models/switch.py
class EDID(_Base):
    """An EDID the switch can present to a port.

    ``parsed`` is ``None`` when kvmd could not decode the blob.
    """

    name: str
    data: str
    parsed: EDIDInfo | None = None

EDIDInfo

The fields kvmd decodes out of an EDID blob.

monitor_name and monitor_serial are None when the blob has no descriptor block for them.

Source code in src/aiopikvm/models/switch.py
class EDIDInfo(_Base):
    """The fields kvmd decodes out of an EDID blob.

    ``monitor_name`` and ``monitor_serial`` are ``None`` when the blob has no
    descriptor block for them.
    """

    mfc_id: str
    product_id: int
    serial: int
    monitor_name: str | None = None
    monitor_serial: str | None = None
    audio: bool

SwitchColors

Indicator colours, one per port role.

Source code in src/aiopikvm/models/switch.py
class SwitchColors(_Base):
    """Indicator colours, one per port role."""

    inactive: SwitchColor
    active: SwitchColor
    flashing: SwitchColor
    beacon: SwitchColor
    bootloader: SwitchColor

SwitchColor

One indicator colour.

blink_ms of 0 means a steady light.

Source code in src/aiopikvm/models/switch.py
class SwitchColor(_Base):
    """One indicator colour.

    ``blink_ms`` of ``0`` means a steady light.
    """

    red: int
    green: int
    blue: int
    brightness: int
    blink_ms: int

Per-port link sensors, in port order.

Source code in src/aiopikvm/models/switch.py
class SwitchLinks(_Base):
    """Per-port link sensors, in port order."""

    links: list[bool]

SwitchBeacons

Which beacons are lit: one flag per port, and one per unit link.

Source code in src/aiopikvm/models/switch.py
class SwitchBeacons(_Base):
    """Which beacons are lit: one flag per port, and one per unit link."""

    uplinks: list[bool]
    downlinks: list[bool]
    ports: list[bool]

SwitchAtx

ATX state of every port, in port order.

Source code in src/aiopikvm/models/switch.py
class SwitchAtx(_Base):
    """ATX state of every port, in port order."""

    busy: list[bool]
    leds: SwitchAtxLeds

SwitchAtxLeds

ATX LED readings, one entry per port.

Source code in src/aiopikvm/models/switch.py
class SwitchAtxLeds(_Base):
    """ATX LED readings, one entry per port."""

    power: list[bool]
    hdd: list[bool]

Info

InfoState

Device information, one attribute per kvmd submanager.

Every field is optional, for two reasons that look the same from here: get_info() can ask for a subset, and the WebSocket sends one submanager per event, so a snapshot taken early has only what has arrived. meta and extras are also nullable at the source — kvmd returns None for either when it cannot parse the files behind them — and that is indistinguishable here from not having been asked for.

meta is left untyped on purpose. It is a YAML file the device's owner writes, and kvmd reads exactly one thing out of it: it replaces server.host when that is set to @auto. Nothing else about its shape is kvmd's to promise.

Source code in src/aiopikvm/models/info.py
class InfoState(_Base):
    """Device information, one attribute per kvmd submanager.

    Every field is optional, for two reasons that look the same from here:
    [`get_info()`][aiopikvm.resources.system.SystemResource.get_info] can ask
    for a subset, and the WebSocket sends one submanager per event, so a
    snapshot taken early has only what has arrived. ``meta`` and ``extras``
    are also nullable at the source — kvmd returns ``None`` for either when
    it cannot parse the files behind them — and that is indistinguishable
    here from not having been asked for.

    ``meta`` is left untyped on purpose. It is a YAML file the device's owner
    writes, and kvmd reads exactly one thing out of it: it replaces
    ``server.host`` when that is set to ``@auto``. Nothing else about its
    shape is kvmd's to promise.
    """

    auth: InfoAuth | None = None
    extras: dict[str, InfoExtra] | None = None
    fan: InfoFan | None = None
    health: InfoHealth | None = None
    meta: dict[str, Any] | None = None
    node: InfoNode | None = None
    system: InfoSystem | None = None
    uptime: InfoUptime | None = None

InfoAuth

Whether kvmd requires authentication.

Source code in src/aiopikvm/models/info.py
class InfoAuth(_Base):
    """Whether kvmd requires authentication."""

    enabled: bool

InfoNode

Host name of the device itself, as its kernel reports it.

Source code in src/aiopikvm/models/info.py
class InfoNode(_Base):
    """Host name of the device itself, as its kernel reports it."""

    host: str

InfoUptime

How long the device has been up.

Source code in src/aiopikvm/models/info.py
class InfoUptime(_Base):
    """How long the device has been up."""

    total: int
    parts: InfoUptimeParts

InfoUptimeParts

The uptime split up, so a caller does not have to divide.

Source code in src/aiopikvm/models/info.py
class InfoUptimeParts(_Base):
    """The uptime split up, so a caller does not have to divide."""

    days: int
    hours: int
    minutes: int
    seconds: int

InfoHealth

Load, temperature and throttling.

throttling is None wherever vcgencmd cannot be run — kvmd reads it from the Raspberry Pi firmware and has no other source.

Source code in src/aiopikvm/models/info.py
class InfoHealth(_Base):
    """Load, temperature and throttling.

    ``throttling`` is ``None`` wherever ``vcgencmd`` cannot be run — kvmd
    reads it from the Raspberry Pi firmware and has no other source.
    """

    temp: InfoTemp
    cpu: InfoCPU
    mem: InfoMem
    throttling: InfoThrottling | None

InfoTemp

Temperature readings, in degrees Celsius.

Source code in src/aiopikvm/models/info.py
class InfoTemp(_Base):
    """Temperature readings, in degrees Celsius."""

    cpu: float | None

InfoCPU

CPU load, as a whole-number percentage.

Source code in src/aiopikvm/models/info.py
class InfoCPU(_Base):
    """CPU load, as a whole-number percentage."""

    percent: float | None

InfoMem

Memory use. All three are None together when the read fails.

Source code in src/aiopikvm/models/info.py
class InfoMem(_Base):
    """Memory use. All three are ``None`` together when the read fails."""

    percent: float | None
    total: int | None
    available: int | None

InfoThrottling

Throttling state, decoded from the firmware's bit field.

Source code in src/aiopikvm/models/info.py
class InfoThrottling(_Base):
    """Throttling state, decoded from the firmware's bit field."""

    raw_flags: int
    parsed_flags: InfoThrottlingFlags
    ignore_past: bool

InfoThrottlingFlags

The three conditions a Raspberry Pi reports.

Source code in src/aiopikvm/models/info.py
class InfoThrottlingFlags(_Base):
    """The three conditions a Raspberry Pi reports."""

    undervoltage: InfoThrottlingFlag
    freq_capped: InfoThrottlingFlag
    throttled: InfoThrottlingFlag

InfoThrottlingFlag

One throttling condition, now and since boot.

past stays True once it has happened, which is why kvmd has an ignore_past setting for it.

Source code in src/aiopikvm/models/info.py
class InfoThrottlingFlag(_Base):
    """One throttling condition, now and since boot.

    ``past`` stays ``True`` once it has happened, which is why kvmd has an
    ``ignore_past`` setting for it.
    """

    now: bool
    past: bool

InfoFan

Fan controller state.

state is whatever the kvmd-fan daemon answers on its own socket, so it is left untyped: it belongs to another program, and a device without that daemon reports monitored false and state None. The same None also means kvmd asked and got no answer.

Source code in src/aiopikvm/models/info.py
class InfoFan(_Base):
    """Fan controller state.

    ``state`` is whatever the ``kvmd-fan`` daemon answers on its own socket,
    so it is left untyped: it belongs to another program, and a device
    without that daemon reports ``monitored`` false and ``state`` ``None``.
    The same ``None`` also means kvmd asked and got no answer.
    """

    monitored: bool
    state: dict[str, Any] | None

InfoSystem

Versions and hardware identity.

Source code in src/aiopikvm/models/info.py
class InfoSystem(_Base):
    """Versions and hardware identity."""

    kvmd: InfoKvmd
    streamer: InfoStreamer
    kernel: InfoKernel
    platform: InfoPlatform

InfoKvmd

The kvmd version, which is what this client's floor is stated in.

Source code in src/aiopikvm/models/info.py
class InfoKvmd(_Base):
    """The kvmd version, which is what this client's floor is stated in."""

    version: str

InfoKernel

uname of the device.

Source code in src/aiopikvm/models/info.py
class InfoKernel(_Base):
    """``uname`` of the device."""

    system: str
    release: str
    version: str
    machine: str

InfoStreamer

The streamer binary kvmd is configured to run.

version is an empty string and features an empty mapping when kvmd could not run it — not None, which is why neither is nullable.

Source code in src/aiopikvm/models/info.py
class InfoStreamer(_Base):
    """The streamer binary kvmd is configured to run.

    ``version`` is an empty string and ``features`` an empty mapping when
    kvmd could not run it — not ``None``, which is why neither is nullable.
    """

    app: str
    version: str
    features: dict[str, bool]

InfoPlatform

What the device is.

base and serial come from the device tree and model, video and board from kvmd's platform file; any of the five is None when the file behind it could not be read. type is a constant in kvmd's source, not a reading.

Source code in src/aiopikvm/models/info.py
class InfoPlatform(_Base):
    """What the device is.

    ``base`` and ``serial`` come from the device tree and ``model``,
    ``video`` and ``board`` from kvmd's platform file; any of the five is
    ``None`` when the file behind it could not be read. ``type`` is a
    constant in kvmd's source, not a reading.
    """

    type: str
    base: str | None
    serial: str | None
    model: str | None
    video: str | None
    board: str | None

InfoExtra

One entry of the extras catalogue.

An extra is a manifest.yaml shipped beside kvmd, so its contents are whatever its author wrote and every field here is optional. kvmd itself only writes two pairs into it: enabled and started when the manifest names a daemon, and port resolved to an integer when the manifest names one as a config path. Anything else the manifest carries is kept as an extra attribute.

Source code in src/aiopikvm/models/info.py
class InfoExtra(_Base):
    """One entry of the extras catalogue.

    An extra is a ``manifest.yaml`` shipped beside kvmd, so its contents are
    whatever its author wrote and every field here is optional. kvmd itself
    only writes two pairs into it: ``enabled`` and ``started`` when the
    manifest names a ``daemon``, and ``port`` resolved to an integer when the
    manifest names one as a config path. Anything else the manifest carries
    is kept as an extra attribute.
    """

    name: str | None = None
    description: str | None = None
    icon: str | None = None
    path: str | None = None
    place: int | None = None
    daemon: str | None = None
    port: int | None = None
    enabled: bool | None = None
    started: bool | None = None