Skip to main content

python-nanokvm

Async Python client for NanoKVM.

Basic usage

from nanokvm.client import NanoKVMClient
from nanokvm.models import GpioType, MouseButton

async with NanoKVMClient("https://kvm.local/api/") as client:
    await client.authenticate("username", "password")

    info = await client.get_info()
    hardware = await client.get_hardware()
    gpio = await client.get_gpio()

    await client.paste_text("Hello\nworld!")
    await client.mouse_click(MouseButton.LEFT, 0.5, 0.5)
    await client.mouse_move_abs(0.25, 0.75)
    await client.mouse_scroll(0, -3)
    await client.push_button(GpioType.POWER, duration_ms=1000)

    async for frame in client.mjpeg_stream():
        print(frame)

Authentication and permissions

Authentication tries the obfuscated password format first, then plain text only after the credentials are rejected. Pass use_password_obfuscation=False or True to force either mode.

get_account() returns the username and, when provided by the firmware, its role. Older firmware may return None for role. Permission failures raise NanoKVMPermissionError without ending the session:

from nanokvm.client import NanoKVMPermissionError

account = await client.get_account()
try:
    await client.get_images()
except NanoKVMPermissionError as error:
    print(error.status, error.method, error.path)

Non-Pro firmware 2.5.1 and newer has user accounts with the roles admin and user. An admin can manage them:

from nanokvm.models import UserRole

await client.create_user("guest", "password", UserRole.USER)
users = await client.get_users()
await client.update_user("guest", enabled=False)
await client.set_user_password("guest", "new-password")
await client.delete_user("guest")

Updating, deleting or resetting the password of a user ends that user's sessions. The device owner account cannot be disabled, demoted or deleted.

On non-Pro firmware 2.5.1 and newer, changing a password requires the current password and the username must match the authenticated account:

await client.change_password(
    "username",
    "new-password",
    current_password="current-password",
)

Older non-Pro firmware and NanoKVM Pro use the original two-argument call.

A successful password change clears the local session. Starting another login or logging out invalidates in-flight authenticated operations and streams. Superseded operations raise NanoKVMNotAuthenticatedError.

On current non-Pro firmware, logging out revokes every session on the device, not only the caller's. Other clients and open web UI tabs have to log in again.

When an external aiohttp.ClientSession is supplied, it remains owned by the caller. WebSockets retain its connector, headers, proxy cookies, basic auth, proxy settings, and tracing, while isolating the device session cookie. Custom session subclasses and middleware apply only to HTTP requests.

NanoKVMApiError includes the numeric API code. Its original msg and data remain available as attributes but are omitted from automatic diagnostics.

Hardware and firmware support

Each method knows which hardware and application version it needs. The client detects both and raises NanoKVMNotSupportedError before sending a request the device cannot serve:

from nanokvm.client import NanoKVMNotSupportedError

try:
    await client.get_swap_size()
except NanoKVMNotSupportedError as error:
    print(error)  # get_swap_size requires hardware: non-Pro (detected: Pro)

Hardware is detected at login, or on the first call when the client was created from a stored token. Application and image versions are detected on the first version-checked call and kept until the session resets (logout, a new login or an expired session). After a firmware update on a client that stays logged in, call await client.detect_versions() to refresh them. Version strings that are not plain numbers, such as development builds, are treated as supported.

The HDMI controls (get_hdmi_state, reset_hdmi, enable_hdmi, disable_hdmi, set_hdmi_idle_timeout) are available on PCIe hardware only.

Images

upload_image sends a local image to the device and reports progress:

def on_progress(progress):
    print(f"{progress.percentage:.0f}%")

await client.upload_image("debian.iso", progress_callback=on_progress)
await client.mount_image("/data/debian.iso", cdrom=True)
  • Non-Pro devices need application 2.3.1 or newer and accept .iso files with ASCII names. Pass sha256= (2.5.0 or newer) to have the device verify the upload.
  • NanoKVM Pro accepts .iso and .img files.
  • An existing image with the same name raises FileExistsError unless overwrite=True. On NanoKVM Pro, overwriting deletes the existing image before the upload starts, so a failed upload leaves neither copy.

The device can also download an image itself:

await client.download_image("https://example.com/debian.iso")
async for status in client.watch_image_download():
    print(status.status, status.percentage)

download_image accepts sha256= and cancel_image_download() stops a download; both need a non-Pro device on 2.5.0 or newer.

Other non-Pro features

  • Application updates: update_application_offline("nanokvm_2.5.1.tar.gz") installs an official package from a local file (2.3.1 or newer); get_update_server and set_update_server manage a custom update server (2.5.1 or newer).
  • MCP and coordinated control (2.5.0 or newer): get_mcp_config, set_mcp_enabled, regenerate_mcp_api_key, get_ai_control_status and set_ai_control_mode.
  • Input region (2.5.1 or newer): get_input_region, set_input_region and get_input_resolution.

SSH

SSH host-key verification is strict by default. Add the device key to the system known-hosts file or pass a separate file with known_hosts. Password authentication does not use an SSH agent or private-key discovery unless allow_agent=True or look_for_keys=True is set. Pass connect_timeout, banner_timeout, or auth_timeout to adjust the connection phases.

from pathlib import Path

from nanokvm.ssh_client import NanoKVMSSH

async with NanoKVMSSH(
    "kvm.local",
    known_hosts=Path.home() / ".ssh" / "known_hosts",
) as ssh:
    await ssh.authenticate("password")

    uptime = await ssh.run_command("cat /proc/uptime")
    disk = await ssh.run_command("df -h /")

Set allow_unknown_host_key=True only for controlled testing; it disables host-key verification. Authentication failures raise NanoKVMSSHAuthenticationError, connection and host-key failures raise NanoKVMSSHConnectionError, and command failures raise NanoKVMSSHCommandError.

HTTPS

Certificates issued by a public or locally trusted CA work without extra configuration:

client = NanoKVMClient("https://kvm.local/api/")

For a self-signed certificate, certificate pinning is recommended:

from nanokvm.utils import async_fetch_remote_fingerprint

fingerprint = await async_fetch_remote_fingerprint("https://kvm.local/api/")
client = NanoKVMClient(
    "https://kvm.local/api/",
    ssl_fingerprint=fingerprint,
)

A custom CA certificate can be supplied instead:

client = NanoKVMClient("https://kvm.local/api/", ssl_ca_cert="/path/to/ca.pem")

Certificate verification can be disabled for testing, but this does not verify the device identity and should not be used in production:

client = NanoKVMClient("https://kvm.local/api/", verify_ssl=False)

Metadata

Release files for nanokvm 1.4.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for nanokvm 1.4.1
File Size Uploaded Provenance Actions
nanokvm-1.4.1.tar.gz 90.2 kB With provenance Details for nanokvm-1.4.1.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for nanokvm 1.4.1
File Interpreter ABI Platform Actions
nanokvm-1.4.1-py3-none-any.whl Python 3 none any Details for nanokvm-1.4.1-py3-none-any.whl

Total release size: 141.2 kB

Release files / nanokvm-1.4.1.tar.gz

Download URL nanokvm-1.4.1.tar.gz
Size 90.2 kB
Tags Source
SHA-256 checksum
How to use checksums
dc7f9ad955b8fa905d8bf99274a1f9b5019d0cc73d57ae1f2eb65a563b30f95a
BLAKE2b-256 checksum
How to use checksums
1703a4576a7687c4391610befc499e94cddcd504e74f1e05cf03c6a584afef20
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 13, 2026.

Transparency log

Release files / nanokvm-1.4.1-py3-none-any.whl

Download URL nanokvm-1.4.1-py3-none-any.whl
Size 51.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
09f7cde1c839c83a1f1259dec0d0ab92500bace1ee9b1cdd68059fb979177a25
BLAKE2b-256 checksum
How to use checksums
09d68352f6462d956a9c71ec9247a0dd88c19999da50054be2e53604d403c416
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 13, 2026.

Transparency log

Security for nanokvm 1.4.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

Both files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for nanokvm-1.4.1.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 13, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page