gicisky-296-bwry
A small Python library and BLE driver for the Gicisky/PICKSMART 2.9" 296x128
BWRY (black/white/red/yellow) e-paper display (device type 0x002E).
Install
pip install -e .
Usage
import asyncio
from PIL import Image
from gicisky_296_bwry import GiciskyTag
async def main():
image = Image.open("status.png") # must be 296x128 RGB
async with GiciskyTag("AA:BB:CC:DD:EE:FF") as tag:
await tag.display(image)
asyncio.run(main())
See examples/display_test_image.py for a runnable four-colour test pattern,
examples/display_tux.py for a Tux (examples/assets/tux.png) sample that
tiles the mascot three times across the panel, or examples/display_photo.py
to fit/quantize any arbitrary photo onto the panel.
Error handling
Failures raise GiciskyError subclasses (GiciskyConnectionError,
GiciskyProtocolError, GiciskyTransferError); a failed or cancelled
upload() disconnects, so call connect() again before retrying.
Timeouts and retry limits are configurable via GiciskyTag keyword
arguments, e.g. GiciskyTag(address, transfer_timeout=60, max_retries=5).
Finding your tag's BLE address
Each tag advertises over BLE and has its address printed on a label next to a
barcode near the connector edge (the last four octets, e.g. 92.83.37.21,
are printed there):
To find the full address (XX:XX:92:83:37:21) for use with this library,
scan for nearby BLE devices:
bluetoothctl scan on
Look for a device named like NEMR92833721 (the digits match the ones
printed on the label). Press Ctrl+C or run bluetoothctl scan off
once you've found it, then use the full XX:XX:XX:XX:XX:XX address with
GiciskyTag(...).
Layout
src/gicisky_296_bwry/
├── __init__.py # public API: GiciskyTag, encode, WIDTH, HEIGHT
├── device.py # BLE connection + vendor GATT protocol
├── encoder.py # Pillow image -> 296x128 BWRY framebuffer bytes
└── exceptions.py # GiciskyError and subclasses
Protocol notes
The tag exposes two GATT characteristics:
fef1: command characteristic (write + notify)fef2: image data characteristic (write + notify)
Upload flow:
0x01 -> request block size
0x02 + size -> announce upcoming image write
0x03 -> request start of transfer
0x05 + block#... -> send framebuffer in blocks until tag replies 0x08 (done)
The framebuffer is a 2-bit-per-pixel packed image (4 pixels/byte) with codes
00=black, 01=white, 10=yellow, 11=red, rotated 90 degrees relative to
the logical 296x128 image (matches the hass-gicisky device profile for this
device type).
Acknowledgements
The BLE protocol and colour/rotation profile for this device type were reverse-engineered with reference to eigger/hass-gicisky, a Home Assistant integration for Gicisky BLE e-paper labels.
Development
pip install -e ".[dev]"
pytest
ruff check .
ruff format .
License
MIT
Metadata
Release files for gicisky-296-bwry 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| gicisky_296_bwry-0.1.0.tar.gz | 286.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| gicisky_296_bwry-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 296.5 kB
Release files / gicisky_296_bwry-0.1.0.tar.gz
| Download URL | gicisky_296_bwry-0.1.0.tar.gz |
|---|---|
| Size | 286.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
1acca35556ef6071c5333c361a9db7e2cb5ff8f4a80339e551f28d9a257d414e
|
|
BLAKE2b-256 checksum How to use checksums |
9869551458e714562981786a1aaa0168409fed92b99d6995871bd9e37e41eedc
|
| 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 Sep 9, 2026.
Transparency logRelease files / gicisky_296_bwry-0.1.0-py3-none-any.whl
| Download URL | gicisky_296_bwry-0.1.0-py3-none-any.whl |
|---|---|
| Size | 9.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
0f15a298a082e9436317b664c018a7195104c2c984019903f387206f84a42dbc
|
|
BLAKE2b-256 checksum How to use checksums |
b3aff9bdc8c5945611e8f91f9d19cc8898ff71dabcf842293bd30233632e99ba
|
| 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 Sep 9, 2026.
Transparency log