Open-source init script for the DASUNG Paperlike 13K 2025 color e-ink display. Replaces the proprietary PaperLikeClient app with a standalone Python script.
Works on Linux and macOS. The CH340 USB-serial control channel is the same on both;
Linux-specific bits (DRM EDID detection, xrandr dithering, XDG_RUNTIME_DIR socket
path) are auto-skipped on macOS.
- Python 3 + pyserial (
pip install pyserial) - USB-C upstream cable from Paperlike's data port to the host (carries video + USB data over the same cable on the 2025 Color)
- Linux: ch341 kernel module (usually loaded automatically) and the user in
dialoutgroup - macOS (11+): nothing to install — built-in
AppleUSBCHCOMdriver enumerates the CH340 as/dev/cu.usbserial-XXXXautomatically when the cable is plugged in
pip install pyserial
sudo usermod -aG dialout $USER # allow serial port access
# Log out and back in for group change to take effect# Use a venv to avoid PEP 668 / external-managed-environment issues:
python3 -m venv .venv
.venv/bin/pip install pyserial
# Then invoke the script via .venv/bin/python3 paperlike_init_linux.py …The Unix-socket daemon path falls back to /tmp/paperlike-<UID>.sock on macOS
(since there's no XDG_RUNTIME_DIR); everything else is identical.
# Init and keep display alive (recommended):
python3 paperlike_init_linux.py --daemon
# Single-shot init (display will deactivate without keepalive):
python3 paperlike_init_linux.py
# Adjust display settings (can combine multiple):
python3 paperlike_init_linux.py --mode 3 # Display mode 1-6
python3 paperlike_init_linux.py --brightness 32 # Brightness 0-64
python3 paperlike_init_linux.py --speed 5 # Speed 1-8
python3 paperlike_init_linux.py --temperature 3 # Color temperature 0-5
python3 paperlike_init_linux.py --front-light 1 # Front light (0=off, 1=warm, 2=cold)
python3 paperlike_init_linux.py --dither off # MCU dithering (on/off)
python3 paperlike_init_linux.py --no-dither-init --daemon # Skip mac-derived dither init (Windows-like colors)
python3 paperlike_init_linux.py --refresh # Force full refresh
python3 paperlike_init_linux.py --query # Query device info
python3 paperlike_init_linux.py --mode 3 --brightness 32 --daemon # Combine
python3 paperlike_init_linux.py --send 0x02 0x03 # Send raw command| Mode | Name |
|---|---|
| 1 | Fast |
| 2 | Fast+ |
| 3 | Balance |
| 4 | Text |
| 5 | Text+ |
| 6 | Read |
When the daemon is running, commands from other instances are automatically
forwarded via a Unix socket ($XDG_RUNTIME_DIR/paperlike.sock). No need to
stop the daemon to change settings:
python3 paperlike_init_linux.py --daemon & # start daemon
python3 paperlike_init_linux.py --brightness 50 # forwarded to daemon
python3 paperlike_init_linux.py --mode 1 # forwarded to daemon
python3 paperlike_init_linux.py --query # forwarded to daemonBy default the script disables GPU dithering (xrandr / AMD debugfs on Linux,
no-op on macOS) and sends MCU 0x20,0x01 to deactivate the MCU's own dithering
during init and on every daemon tick. This matches the behaviour of the
original Mac-side init the script was adapted from.
On some Linux setups the resulting colors look off compared to the Windows
reference driver (which leaves both untouched). Pass --no-dither-init to
skip both steps in init and in the daemon refresh loop. The display still
activates normally — Mac dither suppression is not required for activation.
In daemon mode, the script handles USB disconnect and reconnect automatically.
When the display is unplugged, it waits for the device to reappear (the serial
port path may change, e.g. ttyUSB2 -> ttyUSB3) and re-runs the full init.
# /etc/systemd/system/paperlike.service
[Unit]
Description=Paperlike 13K Display Init
After=multi-user.target
[Service]
Type=simple
ExecStart=/usr/bin/python3 /path/to/paperlike_init_linux.py --daemon
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.targetsudo systemctl enable --now paperlike.service- Display: Paperlike 13K 2025 Color, 3200x2400 @ 37Hz
- Connection: USB-C (DisplayPort Alt Mode + USB data)
- Control: CH340 serial (VID:PID 0x1a86:0x7523) at 115200 8N1
24 ASCII hex characters, UPPERCASE (MCU is case-sensitive):
5FF5 CC OO PPPPPPPPPPPP A0FA
| | | └ trailer
| | └ payload (6 bytes, usually zeros)
| └ option byte
└ command byte
| CMD | OPT | Description |
|---|---|---|
| 0x01 | 1-8 | Set speed/threshold |
| 0x02 | 1-6 | Set display mode |
| 0x03 | 1 | Force refresh |
| 0x07 | 0-2 | Set front light mode (0=off, 1=warm, 2=cold) |
| 0x08 | 0-5 | Set color temperature |
| 0x09 | 0-64 | Set brightness |
| 0x0A | * | Query (opt selects parameter) |
| 0x20 | 0/1 | Dithering control (0=enable/deactivate, 1=disable/activate) |
The display stays active only with periodic 0x20 0x01 commands (~10s interval).
On shutdown, send 0x20 0x00 to deactivate cleanly.