PicPak BLE client
An independent Python client for the PicPak e-ink photo frame.
Disclaimer
This is an independent, unofficial project. It is not affiliated with, authorized by, or endorsed by the makers of PicPak. "PicPak" is used only to identify the hardware this client talks to. It is intended for use with a device you own, to interoperate with hardware you have bought. Use it at your own risk.
Install
Python 3.11 or later is required.
The core library is dependency-free — it implements the raw protocol. Optional extras pull in what each layer needs:
[cli]— thepicpakcommand-line tool (Click, Pillow, bleak, tqdm)[client]— the BLE client only (bleak)[image]— the image encoder only (Pillow)
The picpak command needs the cli extra, so install with it:
pip install "picpak-ble[cli]"
For local development, sync every extra instead:
uv sync --all-extras
On Linux, BLE access may also require the usual BlueZ permissions. Keep the official app disconnected while using this tool.
Use
Find the device:
uv run picpak scan
On macOS the identifier is normally a UUID rather than a hardware MAC address. Inspect the slot table before writing:
uv run picpak slots --device DEVICE_ID
To avoid repeating the identifier, you can set the PICPAK_DEVICE environment variable.
Every command that connects to the screen uses it as the default for --device;
an explicit option still takes precedence.
export PICPAK_DEVICE=DEVICE_ID
uv run picpak slots
uv run picpak name
Upload as many files as desired to the first available slots:
uv run picpak upload --device DEVICE_ID photo1.jpg photo2.png photos/*.jpg
To replace consecutive slots explicitly:
uv run picpak upload --device DEVICE_ID --start-slot 20 --overwrite photos/*.jpg
Add --display-last to show the final uploaded photo. Other useful commands:
uv run picpak info --device DEVICE_ID
uv run picpak name --device DEVICE_ID
uv run picpak name --device DEVICE_ID "Kitchen PicPak"
uv run picpak config --device DEVICE_ID
uv run picpak config --device DEVICE_ID --refresh-interval 3600 --open-door-refresh
uv run picpak bindings --device DEVICE_ID
uv run picpak status --device DEVICE_ID
uv run picpak download --device DEVICE_ID 20 photo.picpak.bin
uv run picpak display --device DEVICE_ID 20
uv run picpak erase --device DEVICE_ID 20 21 22
uv run picpak encode photo.jpg photo.picpak.bin
encode works without a device and is useful for inspecting the exact 30,000-byte photo representation.
Cropping
Both upload and encode take --crop MODE for sources that are not 4:3.
The default, smart, slides the crop window to where the image's saliency is (measured as color contrast against the scene's mean),
and letterboxes onto a white matte instead when no crop could hold most of the salient content.
center always takes the middle crop, and letterbox always fits the whole image.
Dithering
Both upload and encode also take --dither MODE.
The default, app, matches the official app's dithering. There are no tunables here.
--dither perceptual is an alternative tuned for image quality:
serpentine Floyd-Steinberg diffusion in linear light with chroma-weighted Oklab color matching,
clamped to the panel gamut.
--tone Nadjusts its midtone lift:1.0reproduces the source's reflectance exactly (which looks murky on the dim reflective panel), lower values are brighter, and the default 0.45 matches the brightness the app scheme produces.--retention Nsets the fraction of dither error that is diffused; values below 1.0 let near-solid areas collapse to solid ink for extra contrast at some cost in tonal accuracy, and the default 0.65 was picked by comparing values on the physical panel. The perceptual mode also compensates for the panel's actual ink colors using measured values.
Notes
- If the BLE backend reports an implausibly small MTU, the upload command stops before writing.
--chunk-size Ncan override its calculation when the backend has in fact negotiated a larger MTU but does not report it correctly. Use at least 118 bytes and no more thanATT_MTU - 12. - See PROTOCOL.md for the packet layouts, characteristic routing, image palette, and dithering algorithm.
- The current shipping firmware appears to leave the BLE photo-read request unimplemented, so
downloadis expected to time out even though the client-side receiver is complete.
License
Released under the MIT License.
Release files for picpak-ble 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| picpak_ble-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Release files / picpak_ble-0.1.0-py3-none-any.whl
| Download URL | picpak_ble-0.1.0-py3-none-any.whl |
|---|---|
| Size | 26.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
2929e631027852d0ddb905f4a059158a5a22fea6b6e2ffe8af7f45a8f6b4d825
|
|
BLAKE2b-256 checksum How to use checksums |
0ca4f63deb1abda73be1dd18e83bfc0b9d87059e6ab136bfaf4d4c765927dde5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.13
|
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 16, 2026.
Transparency log