Metadata-Version: 2.4
Name: picpak-ble
Version: 0.1.0
Summary: PicPak BLE protocol spec, client and CLI tool
Project-URL: Homepage, https://github.com/akx/picpak-ble
Project-URL: Repository, https://github.com/akx/picpak-ble
Project-URL: Issues, https://github.com/akx/picpak-ble/issues
Maintainer-email: Aarni Koskela <akx@iki.fi>
License-Expression: MIT
License-File: LICENSE
Keywords: ble,bluetooth,cli,e-ink,photo-frame,picpak
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Multimedia :: Graphics
Classifier: Topic :: System :: Hardware
Requires-Python: >=3.11
Provides-Extra: cli
Requires-Dist: bleak<2,>=0.22; extra == 'cli'
Requires-Dist: click<9,>=8.1; extra == 'cli'
Requires-Dist: pillow<13,>=10; extra == 'cli'
Requires-Dist: tqdm<5,>=4.67; extra == 'cli'
Provides-Extra: client
Requires-Dist: bleak<2,>=0.22; extra == 'client'
Provides-Extra: image
Requires-Dist: pillow<13,>=10; extra == 'image'
Description-Content-Type: text/markdown

# PicPak BLE client

An independent Python client for the [PicPak][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].
"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]` — the `picpak` command-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:

```bash
pip install "picpak-ble[cli]"
```

For local development, sync every extra instead:

```bash
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:

```bash
uv run picpak scan
```

On macOS the identifier is normally a UUID rather than a hardware MAC address.
Inspect the slot table before writing:

```bash
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.

```bash
export PICPAK_DEVICE=DEVICE_ID
uv run picpak slots
uv run picpak name
```

Upload as many files as desired to the first available slots:

```bash
uv run picpak upload --device DEVICE_ID photo1.jpg photo2.png photos/*.jpg
```

To replace consecutive slots explicitly:

```bash
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:

```bash
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 N` adjusts its midtone lift: `1.0` reproduces 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 N` sets 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 N` can 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 than `ATT_MTU - 12`.
* See [PROTOCOL.md](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 `download` is expected to time out even though the client-side receiver is complete.

## License

Released under the [MIT License](LICENSE).

[picpak]: https://www.picpak.tech/
