English | Беларуская | Русский
A Python-based CLI tool for automated image uploading to Gicisky/PICKSMART Electronic Shelf Labels (ESL) via Bluetooth Low Energy (BLE).
- End-to-End Automation: Fully scriptable replacement for the browser-based Web Bluetooth uploader.
- Optimized for 2.9" BWR: Pre-configured for 296×128 Red/White/Black ESL tags.
- Advanced Image Pipeline:
- Automatic alpha-channel flattening (composite onto white background).
- Smart resizing & centering.
- Mandatory 90° matrix rotation for the
0x0033device profile.
- Robust BLE Transport:
- MTU negotiation (up to 247 bytes).
- Explicit Write Requests for connection stability.
- Built-in 50ms inter-block delay to prevent tag buffer overflows.
RAW HEXmode for low-level protocol debugging.
- Python:
3.12or3.13 - OS: Linux (tested on Ubuntu/Pop!_OS) with BlueZ stack
- Hardware: BLE-compatible adapter
- Permissions: User access to the Bluetooth subsystem
- Clone the repository:
git clone https://github.com/51n1au5k1/PICKSMART-BLE-ESL-Uploader.git cd PICKSMART-BLE-ESL-Uploader
Create a virtual environment and install dependencies:
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt(Linux only) Grant Bluetooth permissions to avoid using sudo:
sudo usermod -aG bluetooth $USER
# Log out and back in, or reboot to applyAutomatically scans for devices named NEMR...:
python main.py --image assets/your_label.png --verboseSkip auto-scan and connect directly:
python main.py --address FF:FF:92:99:04:78 --image assets/test.pngSend a pre-recorded 9472-byte payload for low-level debugging:
python main.py --address FF:FF:92:99:04:78 --raw-hex debug/dump.txt| Component | Value / Description |
|---|---|
| GATT Service | 0xFEF0 |
Control Characteristic (0xFEF1) |
0x01 (Block Size), 0x02 (Screen Info), 0x03 (Start Transfer) |
Data Characteristic (0xFEF2) |
Receives image blocks. Format: [Block Index (4B LE)] + [Data (240B)] |
| Total Payload Size | 9472 bytes |
| Plane 1 (B/W) | 4736 bytes (1 bpp, 0 = black, 1 = white) |
| Plane 2 (Red) | 4736 bytes (1 bpp, 1 = red) |
Some tags ignore MTU negotiation.
Fix: manually connect via bluetoothctl before running the script:
bluetoothctl connect FF:FF:92:99:04:78ESL tags process data slowly.
Fix: the script already includes a 50 ms inter-block delay. If issues persist, increase BLOCK_DELAY in app/transport/bleak_backend.py.
Ensure your user is in the bluetooth group and that you have fully logged out and back in after running usermod.
├── main.py # CLI entry point & argument parsing
├── app/
│ ├── image_codec.py # Image processing & BWR bitstream generation
│ ├── protocol.py # GATT command construction & payload formatting
│ └── transport/
│ └── bleak_backend.py # BLE communication logic (bleak-based)
└── requirements.txt
Pull requests are welcome. Please follow the existing code style and ensure compatibility with Python 3.12+.
Licensed under the MIT License.