Metadata-Version: 2.4
Name: picokvm-client
Version: 0.1.0
Summary: Unofficial Python client for the Luckfox PicoKVM JSON-RPC API
Project-URL: Homepage, https://github.com/onurcelep/picokvm-client
Project-URL: Repository, https://github.com/onurcelep/picokvm-client
Project-URL: Issues, https://github.com/onurcelep/picokvm-client/issues
Author-email: Onur Celep <onurcelep@gmail.com>
License: MIT
License-File: LICENSE
Keywords: automation,hid,jetkvm,jsonrpc,kvm,picokvm
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Testing
Classifier: Topic :: System :: Hardware
Requires-Python: >=3.11
Requires-Dist: click<9,>=8.1
Requires-Dist: httpx>=0.27.0
Requires-Dist: jsonrpcclient>=4.0.0
Requires-Dist: pydantic>=2.0.0
Requires-Dist: typer>=0.9.0
Provides-Extra: dev
Requires-Dist: gitlint>=0.19.1; extra == 'dev'
Requires-Dist: mypy>=1.0.0; extra == 'dev'
Requires-Dist: pre-commit>=3.5.0; extra == 'dev'
Requires-Dist: pytest-mock>=3.12.0; extra == 'dev'
Requires-Dist: pytest>=7.4.0; extra == 'dev'
Requires-Dist: respx>=0.21.0; extra == 'dev'
Requires-Dist: ruff>=0.8.0; extra == 'dev'
Description-Content-Type: text/markdown

# picokvm-client

Python client for the [Luckfox PicoKVM](https://github.com/LuckfoxTECH/kvm).
A thin, synchronous wrapper around its JSON-RPC 2.0 API (`POST /api/rpc`)
and cookie-auth endpoint (`POST /auth/login-local`), built on `httpx` and
`jsonrpcclient`.

> **Unofficial.** Independent, community-built client. Not affiliated with,
> authorized by, or endorsed by Luckfox or JetKVM. "PicoKVM" and "JetKVM"
> belong to their respective owners and are used here only to describe
> compatibility. No vendor source code is included; this reimplements the
> device's public JSON-RPC protocol and standard USB HID Boot-Protocol
> reports.

## Compatibility

Targets the Luckfox PicoKVM. Its firmware is a Luckfox-Pico fork of
[JetKVM](https://github.com/jetkvm/kvm), so the wire protocol currently
overlaps with JetKVM and its other forks. This client is only tested against
the PicoKVM and makes no compatibility promise to JetKVM; a JetKVM is better
served by a dedicated `jetkvm-client`.

## Install

```bash
pip install picokvm-client
# or
uv add picokvm-client
```

## CLI

The package installs a `picokvm` command:

```bash
export PICOKVM_URL=http://kvm.example PICOKVM_PASSWORD=hunter2

picokvm ping
picokvm device-id
picokvm video-state
picokvm type "hello world"
picokvm combo "Ctrl+Alt+Del"
picokvm rpc getJigglerState
```

`--url` and `--password` override the environment variables. Run
`picokvm --help` for the full command list.

> **Safety.** The HID commands (`type`, `key`, `combo`, `click`) inject input
> into whatever host is attached to the KVM. A mistake can lock the keyboard,
> type into the wrong window, or click at random coordinates. Test against a
> throwaway target before using these in automation.

## Library

```python
from picokvm_client import PicoKVMClient

with PicoKVMClient("http://kvm.example", password="hunter2") as kvm:
    if not kvm.ping():
        raise RuntimeError("KVM not responding")

    state = kvm.get_video_state()
    print(f"Video: {state.width}x{state.height}, ready={state.ready}")

    kvm.key_combo("Ctrl+Alt+Del")
    kvm.type_text("hello world\n")
    kvm.click(state.width // 2, state.height // 2)

    kvm.mount_with_http("https://files.example.com/installer.iso")
    kvm.trigger_reset()
```

The client owns an `httpx.Client` that holds the session cookie. Use it as a
context manager so the connection pool and cookie are released on exit.

## Methods

Common operations have typed methods. Anything else on the device is reachable
through `client.rpc(method, **params)`, a generic JSON-RPC call.

| Family            | Typed methods                                                            | Via `.rpc()`       |
|-------------------|--------------------------------------------------------------------------|--------------------|
| HID input         | `keyboard_report`, `abs_mouse_report`, `rel_mouse_report`, `wheel_report`, `get_keyboard_led_state`, `send_usb_wakeup_signal`, `type_text`, `click`, `key_press`, `key_combo` | macros, layout get/set, jiggler |
| Video             | `get_video_state`, `wait_for_video`                                      | EDID, capture      |
| Virtual media     | `mount_with_http`, `mount_built_in_image`, `mount_with_storage`, `unmount_image` | upload, listing |
| Device management | `get_device_id`, `ping`, `reboot`, `send_wol_magic_packet`              | network, OTA, logs |
| Power             | `trigger_power`, `trigger_reset`                                         | hold-power         |
| Auth              | `login` (called automatically by `__enter__` when a password is set)     | logout             |

## Exceptions

All exceptions inherit from `PicoKVMError` (itself a plain `Exception`, no
third-party base). Each carries advisory `exit_code`, `hint`, and `retryable`
attributes that a caller can map onto its own error type.

| Exception        | Raised on                                                |
|------------------|----------------------------------------------------------|
| `AuthError`      | HTTP 401 from login or RPC                               |
| `TransportError` | non-2xx HTTP (other than 401), invalid JSON, network failure |
| `RpcError`       | a JSON-RPC 2.0 `error` response                          |
| `PicoKVMError`   | base class for the above                                 |

## Examples

Runnable scripts in [examples/](examples/) (each reads `PICOKVM_URL` and
`PICOKVM_PASSWORD`):

| Script                                                            | What it does                                   |
|------------------------------------------------------------------|------------------------------------------------|
| [01_login_and_status.py](examples/01_login_and_status.py)        | Connect, ping, print device ID and video state |
| [02_send_text_and_combo.py](examples/02_send_text_and_combo.py)  | Type a string and send a key combo             |
| [03_mount_iso_and_reboot.py](examples/03_mount_iso_and_reboot.py)| Mount an ISO over HTTP and wait for boot        |

## Testing

Tests drive the client through `httpx.MockTransport`, so no sockets are
opened. Each typed method asserts the exact JSON-RPC `method` and `params` it
puts on the wire.

The HID commands (`type_text`, `click`, `key_press`, `key_combo`) are checked
at the payload level only, not against real hardware. Run a manual smoke test
on a throwaway target before relying on them.

## Development

```bash
uv sync --extra dev
pre-commit install --install-hooks
pre-commit install --hook-type commit-msg
git config commit.template .gitmessage
```

Checks: `uv run pytest`, `uv run ruff check src tests`,
`uv run mypy src/picokvm_client --strict`. Commit messages follow `.gitlint`
(subject 10 to 72 chars, body wrapped at 72, `Signed-off-by` required, so use
`git commit -s`).

## Issues

File issues at <https://github.com/onurcelep/picokvm-client/issues>.
