Skip to main content

PyKS2

PyPI tests python license

A Python library and CLI for controlling the Pentax K-S2 over its built-in WiFi, built on an extensive, hardware-verified reverse-engineering of the camera's undocumented HTTP API. (A web GUI is planned; see below.)

image

The K-S2 has a WiFi remote-control API, but Pentax never documented it. This project maps the entire surface of the K-S2's API against a physical camera, writes it up as a proper dissection, and ships a clean client that is lighter and more capable than the vendor's own Image Sync app.

Known gaps

This maps what I could exercise on my own body. Two areas are not fully verified:

  • GPS — the optional top-mounted Pentax GPS unit surfaces in exposureModeList but I couldn't test it (I don't own the unit). Untested.
  • Live-view digital zoomPOST /v1/liveview/zoom exists but was gated on my setup: every parameter shape I tried returned errCode 200. It may need a lens or camera state I couldn't reach over the API. No working digital-zoom control was observed.

Everything else is behaviourally verified against the hardware below.

Tested on

  • Body: Pentax K-S2
  • Firmware: 01.10
  • Lenses: smc PENTAX-DA 18–50mm, DA 50–200mm

Other Pentax bodies with the same WiFi stack (K-1, KP, K-70, …) likely share much of this API but are untested, reports welcome.

Two things make this more than "another camera library":

  1. A full protocol dissection and reverse-engineering methodology: the endpoints quirks, and hardware limitations I could exercise on my camera, with the raw captures to back it up.
  2. A design that beats the official app: event-driven via the camera's WebSocket instead of the poll-storm Image Sync uses (~90% of its total requests were just polling one endpoint while interacting with the app actively).

What's here

pyks2/          the library (camera-only HTTP client, typed models, WS events)
  ├─ client.py       K_S2_WiFi, the API client
  ├─ models.py       typed response models (defensive parsing)
  ├─ events.py       /v1/changes WebSocket client (stdlib, zero-dep)
  ├─ constants.py    endpoints + capability enums
  ├─ errors.py       typed exceptions (errCode-aware)
  ├─ _mjpeg.py       shared MJPEG frame parser (sync + async liveview)
  ├─ async_client.py optional async streaming (pyks2[async])
  └─ cli.py          the command-line interface
docs/           the reverse-engineering write-up (GitHub Pages source)
  ├─ PROTOCOL.md     the API dissection
  └─ METHODOLOGY.md  how it was probed (approach, false trails, traffic capture)
examples/       real captured JSON responses + the machine-readable API reference

Quick start

pip install pyks2                     # or: pip install -e .  from a clone

Join the camera's WiFi (PENTAX_XXXXXX), then:

from pyks2 import K_S2_WiFi

cam = K_S2_WiFi()            # defaults to 192.168.0.1
assert cam.ping()

# take one photo safely: records the baseline, fires, waits for the NEW file,
# and downloads it all in one call (af="off" is MF-safe: always releases)
info = cam.capture(af="off", download_to="shot.dng")
print("captured:", info.path)

# change settings (validated by the camera; illegal values raise)
cam.set_camera_params(av="8.0", sv="400")

# ...or use the typed accessors, which also catch camera-controlled fields
# (e.g. av in Sv mode) and raise instead of silently no-opping
cam.set_iso(400)
cam.set_aperture(8.0)

# browse the card
for photo in cam.list_photos():
    print(photo.path)

Event-driven, no polling:

with cam.events() as ev:              # /v1/changes WebSocket
    for change in ev:
        if change.is_storage:         # a frame just landed
            print("captured:", cam.latest_info().path)
        elif change.is_camera:        # a setting changed on the body
            print("settings:", cam.get_camera_params())

Live view (MJPEG):

with cam.liveview() as stream:       # closes the stream (drops the mirror)
    for jpeg in stream:               # on exit, even if you break out early
        open("frame.jpg", "wb").write(jpeg)
        break

Async streaming

pip install pyks2[async] pulls in httpx/websockets for async equivalents of the event stream and live view. Hardware-verified against a physical K-S2 — see VERIFICATION.md.

async with cam.events_async() as ev:
    async for change in ev:
        if change.is_storage:
            print("captured:", cam.latest_info().path)
async for jpeg in cam.iter_liveview_frames_async(max_frames=10):
    ...                               # 720x480 JPEGs; mirror drops on close

Both share their parsing with the sync path — MJPEG framing via pyks2._mjpeg, event decoding via events._payload_to_event — so there is no duplicated protocol logic between sync and async.


CLI

Everything the library does, from a terminal:

pyks2 ping
pyks2 info                          # model, firmware, battery (%), storage
pyks2 shoot --af off --wait --download shot.dng
pyks2 settings                      # show current settings
pyks2 settings av=8.0 sv=400        # set them
pyks2 lists                         # capability lists (dropdown sources)
pyks2 browse --limit 20             # list photos
pyks2 download 100_1507/IMGP1974.DNG --size view -o preview.jpg
pyks2 liveview -o frame.jpg
pyks2 watch --resolve               # stream camera events live

pyks2 info reports the K-S2 battery as an integer percentage. In practice the camera reports values like 100, 66, and 0, plus a hot thermal state flag in status/device.


Web GUI

A browser-based control panel is planned, full Image-Sync parity plus extensions (live view, remote capture, touch-to-focus, a settings panel driven by the camera's own capability lists, an idle-safe gallery, and event-driven updates), served by a thin local backend that reuses this library so it runs on any OS in any browser. Not yet included in this release, the library and CLI are the shipping surfaces.


The reverse engineering

The heart of this project is the write-up. Highlights:

  • The API surface I mapped spans 38 endpoint templates, organised as five read groups (constants/params/variables/status/props) × four subsystems (camera/lens/liveview/device), plus capture/focus/photo/ liveview actions and a WebSocket. The main gaps I could not verify were GPS and LiveView Zoom.
  • Two protocol laws every client must respect: the real status is in the body's errCode (not the HTTP status), and datetime/numeric formats are inconsistent across endpoints.
  • Hardware interlocks mapped and explained: the AF/MF lever, mode dial, and movie mode are physical-only; movie mode disables WiFi entirely; opening the SD-card door kills the connection; and the camera's WiFi access point uses client isolation (which shaped how the official app's traffic had to be captured).
  • How Image Sync actually works, captured off the wire — and why this client's event-driven design is better.

Start with docs/PROTOCOL.md, then docs/METHODOLOGY.md. The raw evidence is in examples/ and the machine-readable spec is examples/API_REFERENCE.json.


Development & tests

git clone https://github.com/PICKLERICK2005/pyks2.git
cd pyks2
pip install -e ".[dev]"     # installs pytest, mypy, ruff (+ the async extra)
pytest -q                    # 70 tests, no camera required

The test suite runs entirely against captured fixtures (examples/*.json) via a mock camera in tests/conftest.py, so it needs no hardware. Tests also serve as executable documentation of the API's behaviour — including the trickier findings (async capture, the Bulb correction, dynamic capability lists).

Compatibility

Verified against a Pentax K-S2, firmware 01.10. Other Pentax bodies (K-1, KP, K-70, K-3…) share much of this API family but differ in specifics. Running the probing approach in docs/METHODOLOGY.md on another body and sending the diffs is the most useful contribution you could make!

Gaps

The only remaining gaps in this project would be:

  1. The endpoint affiliated with the GPS module
  2. The Liveview Zoom endpoint

Both of which likely require a corresponding hardware addon.

License

MIT — see LICENSE.

Acknowledgements

The 2016 K-1 WiFi analysis on the pentax forums was a useful starting point for hypotheses. Everything here was independently verified against a physical K-S2. This project inspects only the camera's own network behaviour and my own hardware; it contains no vendor code or any unmentioned references.

Release files for pyks2 1.1.0

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

Source distribution (sdist)

Source distribution for pyks2 1.1.0
File Size Uploaded
pyks2-1.1.0.tar.gz 100.8 kB Details

Built distribution (wheel)

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

Total release size: 134.0 kB

Release files / pyks2-1.1.0.tar.gz

Download URL pyks2-1.1.0.tar.gz
Size 100.8 kB
Tags Source
SHA-256 checksum
How to use checksums
ec63def301417a102689364ff228ff2f9357972f0d77f5f158efe294c0e057f6
BLAKE2b-256 checksum
How to use checksums
effb8760d19f6cd3ba6c8e0967ba1c0f8aad3227185291c3f139f1d0049201d4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.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 Jul 29, 2026.

Transparency log

Release files / pyks2-1.1.0-py3-none-any.whl

Download URL pyks2-1.1.0-py3-none-any.whl
Size 33.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
8df411a5c2aa8d9a5da9c2b7513afc9f5d046d363e70f695a84428c060afbc29
BLAKE2b-256 checksum
How to use checksums
53715d2a2e9f502541486e621b6ea66c10e134350148586c2709d360d655c363
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.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 Jul 29, 2026.

Transparency log
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