Version 2.0.2
Ize Ribbon is a Raspberry Pi Zero 2 W based writing device with a Waveshare 2.13 inch e-Paper HAT, Bluetooth or USB keyboard input, a local Web UI, Wi-Fi setup, Korean input, automatic power handling, and optional private GitHub repository sync.
The device is designed to keep writing local and fast. Network, GitHub, USB export, and web editing features run around the writing flow instead of blocking typing. if you are looking for thd Ize-Compose, go to https://github.com/ize-studio/ize-compose
Ize Ribbon is intended for trusted local-network use only. Do not expose port 8080 to the public internet.
The fallback access point is intended for first-time local setup and recovery. Use it only on a trusted local network, and change the default password before regular use if the device will be used outside a controlled environment.
- Raspberry Pi Zero 2 W(https://amzn.to/4uDz8aB)
- Waveshare 2.13 inch e-Paper HAT, V4 driver(https://amzn.to/4xv47bx)
- Bluetooth keyboard or USB keyboard
- MicroSD with Raspberry Pi OS Lite
- Optional battery or UPS board with INA219-compatible voltage sensor(https://amzn.to/4xdlUUi)
- Project:
/home/ize/ize-ribbon - Documents:
/home/ize/ize-ribbon/docs - Current document setting:
config.jsonkeydocument - Web UI:
http://ize-ribbon.local:8080 - Setup AP Web UI:
http://10.42.0.1:8080 - GitHub deploy key:
/home/ize/.ssh/ize_ribbon_github_ed25519 - USB export image:
/home/ize/ize-ribbon/usb_share.img - Activity file:
/run/ize-ribbon/activity
The repository includes the required font files:
D2Coding-Ver1.3.2-20180524.ttfNotoSansMono-Regular.ttf
After cloning or copying the project, confirm they exist:
ls /home/ize/ize-ribbon/fonts/D2Coding-Ver1.3.2-20180524.ttf
ls /home/ize/ize-ribbon/fonts/NotoSansMono-Regular.ttfThe Waveshare e-Paper Python library is not bundled. The systemd service expects it at:
/home/ize/e-Paper/RaspberryPi_JetsonNano/python/lib
If your path is different, update WAVESHARE_LIB_DIR in systemd/ize-ribbon.service.
Copying this folder alone is not enough. A working device needs:
- Raspberry Pi OS Lite installed and bootable.
- User, hostname, SSH, and optionally Wi-Fi configured.
- Waveshare e-Paper Python library available on the Pi.
- Included font files present in
fonts/. - This repository copied or cloned to
/home/ize/ize-ribbon. sudo bash scripts/install_pi.shrun once.- A reboot or service restart.
After install_pi.sh finishes, systemd starts the Web UI and e-paper writing app automatically at boot.
These steps describe a new Raspberry Pi Zero 2 W setup from an empty microSD card.
Use Raspberry Pi Imager.
Recommended settings:
- OS: Raspberry Pi OS Lite, 32-bit
- Hostname:
ize-ribbon - Username:
ize - Password: choose your own password
- SSH: enabled
- Wi-Fi: configure if available
- Locale/timezone: your local setting
Boot the Pi and wait until SSH is available.
From your computer:
ssh ize@ize-ribbon.localIf mDNS does not work, find the Pi IP from your router and use:
ssh ize@<device-ip>On the Pi:
sudo apt update
sudo apt install -y git python3-pip python3-pil python3-flask python3-smbus2 network-manager bluez bluetooth rfkillinstall_pi.sh also installs and enables project services, but installing common packages first makes setup failures easier to understand.
The default service file expects:
/home/ize/e-Paper/RaspberryPi_JetsonNano/python/lib
One common setup is:
cd /home/ize
git clone https://github.com/waveshareteam/e-Paper.gitConfirm the driver file exists:
ls /home/ize/e-Paper/RaspberryPi_JetsonNano/python/lib/waveshare_epd/epd2in13_V4.pyIf your Waveshare library is somewhere else, edit:
/home/ize/ize-ribbon/systemd/ize-ribbon.service
and change:
Environment=WAVESHARE_LIB_DIR=/home/ize/e-Paper/RaspberryPi_JetsonNano/python/lib
Recommended:
cd /home/ize
git clone https://github.com/ize-studio/Ize-Ribbon.git ize-ribbonOr copy the project folder manually so that this path exists:
/home/ize/ize-ribbon
The font files should already be present after cloning this repository:
/home/ize/ize-ribbon/fonts
Check:
ls /home/ize/ize-ribbon/fonts/D2Coding-Ver1.3.2-20180524.ttf
ls /home/ize/ize-ribbon/fonts/NotoSansMono-Regular.ttfIf either file is missing, the repository copy is incomplete.
cd /home/ize/ize-ribbon
sudo bash scripts/install_pi.shThis installs systemd service files, enables the app and web server, and prepares the device to start automatically at boot.
If your device uses an INA219-compatible battery voltage sensor, enable I2C:
sudo raspi-configThen go to:
Interface Options > I2C > Enable
Also make sure i2c-dev loads at boot:
echo i2c-dev | sudo tee /etc/modules-load.d/i2c-dev.conf
sudo usermod -aG i2c izeReboot after changing groups or I2C settings.
cd /home/ize/ize-ribbon
sudo bash scripts/setup_usb_gadget.sh
sudo rebootAfter reboot, the device starts these services:
ize-ribbon.service: main writing app on/dev/tty1ize-ribbon-web.service: Web UI on port8080ize-ribbon-idle-shutdown.service: idle power managerize-ribbon-network-fallback.service: Wi-Fi setup fallback
Reboot:
sudo rebootAfter boot, the e-paper display should show startup/network/keyboard status, then the writing screen once a keyboard is available.
Open the Web UI:
http://ize-ribbon.local:8080
or:
http://<device-ip>:8080
Check services:
systemctl is-active ize-ribbon.service
systemctl is-active ize-ribbon-web.service
systemctl is-active ize-ribbon-idle-shutdown.serviceAll should print:
active
Use this checklist when the device does not appear to be working after installation.
Check service:
systemctl status ize-ribbon-web.service
journalctl -u ize-ribbon-web.service -n 80 --no-pagerCheck IP:
hostname -ITry:
http://<device-ip>:8080
If Wi-Fi is not connected, connect to the setup AP:
SSID: Ize-Ribbon
Password: izeribbon
Web UI: http://10.42.0.1:8080
Check main service:
systemctl status ize-ribbon.service
journalctl -u ize-ribbon.service -n 120 --no-pagerCheck Waveshare library path:
ls /home/ize/e-Paper/RaspberryPi_JetsonNano/python/lib/waveshare_epd/epd2in13_V4.pyCheck SPI:
ls /dev/spidev*If missing, enable SPI:
sudo raspi-configThen:
Interface Options > SPI > Enable
Check Linux input devices:
cat /proc/bus/input/devices | grep -i -A4 keyboard
ls /dev/input/event*For Bluetooth keyboards, use the Web UI Bluetooth Keyboard page to scan and connect.
For USB keyboards, plug the keyboard in and restart the app if needed:
sudo systemctl restart ize-ribbon.serviceOpen the Web UI setup AP, or use:
nmcli dev wifi list
nmcli dev wifi connect "<ssid>" password "<password>"The device can still be used for writing when a keyboard is connected, even without Wi-Fi.
In the Web UI, open GitHub Sync and check:
- Repository is
owner/repository. - SSH key exists.
- Public key is added to GitHub repository
Deploy keys. Allow write accessis enabled.Test Connectionsucceeds.Connect Docs Folderhas been pressed.
Manual check:
cd /home/ize/ize-ribbon/docs
git status
git remote -v
ssh -i /home/ize/.ssh/ize_ribbon_github_ed25519 -T git@github.comAt boot, the e-paper screen shows network and keyboard status.
If no keyboard is connected, the device stays on the startup/status screen so the user can find the Web UI and pair or connect a keyboard.
If a keyboard is connected, the device enters the writing screen even when Wi-Fi is not connected. Network setup is always available later through the device menu or Web UI.
If normal Wi-Fi is unavailable, the setup AP remains available:
SSID: Ize-Ribbon
Password: izeribbon
Web UI: http://10.42.0.1:8080
The writing screen shows:
- Top bar: title, input language, keyboard/battery status
- Body: current document text, six visible lines by default
- Bottom bar: current document label and counter
Text is saved locally first. Save and GitHub sync are intentionally separated from display refresh to reduce typing delay.
- Type: insert text
- Enter: newline
- Backspace: delete one character
- ESC: open device menu
- Ctrl+N: create new numbered document
- Ctrl+S: save immediately
- Ctrl+Space: cycle selected input languages
Arrow keys are handled through Linux input events when in menus. Bluetooth and USB keyboards are both detected through /dev/input/event*.
KO input mode composes Hangul inside the app. Ctrl+Space cycles through the selected languages. EN is always present as the first slot.
Fonts:
- Primary:
D2Coding-Ver1.3.2-20180524.ttf - Fallback for characters not found in D2Coding:
NotoSansMono-Regular.ttf
Open the menu with ESC.
Menu items:
New Doc: creates the next numbered document, saves the previous document first, and clears the writing cache for the new document.Docs: opens the document picker.Network: shows Wi-Fi/AP status and Web UI address.Auto Off: selects idle shutdown time.Count: changes bottom counter mode.Power Off: shows the sleep/power-off notice, waits briefly, then shuts down Linux.
Menu controls:
- Up/Down: move selection
- Left/Right: change option values
- Enter: select or confirm
- ESC: go back or close menu
Shows numbered documents such as:
0001:preview text
0002:preview text
Selecting a document changes the current writing file.
Shows either:
WiFi <ssid>
<ip>:8080
or setup AP information:
AP Ize-Ribbon
10.42.0.1:8080
Available values:
10m30m60m
When external power is detected or power state is unknown and configured as safe, idle shutdown is skipped.
Available values:
OFFWordsChars
Open the Web UI from the same network:
http://ize-ribbon.local:8080
http://<device-ip>:8080
When using setup AP:
http://10.42.0.1:8080
The main page shows:
- Version
- Wi-Fi status
- Web UI URL
- Bluetooth keyboard status
- Current input language
- Document table
- Navigation buttons
Main buttons:
New DocumentRefresh USB ExportSettingsGitHub SyncBluetooth KeyboardWi-FiPower Off
The document table shows:
- Document number
- Preview
- Character/word count
- Open button
- Download button
Opening a document provides:
- Text editor
SaveSave and Open on Device
Save and Open on Device writes the web-edited text and makes that file the active device document.
Settings include:
- Counter mode:
OFF,Words,Characters - Auto Off:
10 min,30 min,60 min - Battery display:
autoormanual - Manual battery text
- Input language selection
EN is fixed as the first language. Select up to five total languages including EN.
GitHub Sync lets the device use a private GitHub repository as a writing archive. Documents are saved on the device, backed up to GitHub when Wi-Fi is available, and can also be edited or added from GitHub and brought back to the device during sync. This creates a workflow similar to Freewrite Postbox.
Recommended setup:
- Create a private GitHub repository.
- Open
GitHub Syncin the Ribbon Web UI. - Enter repository as
owner/repository. - Press
Save Repository. - Press
Generate SSH Key. - Copy the displayed public key.
- In GitHub, open the repository settings.
- Go to
Deploy keys. - Add the public key.
- Enable
Allow write access. - Press
Test Connectionin the Web UI. - Press
Connect Docs Folder.
The device uses /home/ize/ize-ribbon/docs as the Git working tree. Existing documents are committed and pushed to the configured repository.
Automatic sync behavior:
- Local document writes are saved immediately.
- Git fetch/commit/push runs in the background.
- Sync only runs when Wi-Fi is connected.
- If Wi-Fi is unavailable, documents remain local and sync later.
- If GitHub and the device both changed, the newer Git commit wins.
- Git work is never required for typing to continue.
Manual actions:
Generate SSH Key: creates the deploy key if missing.Test Connection: verifies GitHub SSH access.Connect Docs Folder: initializes or connectsdocs/to the repo.Sync Now: requests a background sync.
The Bluetooth page provides:
- Adapter status
- Scan button
- Device list
- Connect button
- Advanced MAC address connection form
Normal flow:
- Put the keyboard in pairing mode.
- Press
Scan. - Press
Connectnext to the keyboard.
The device can also use USB keyboards. USB keyboard input is detected through Linux input events and does not require Bluetooth setup.
The Wi-Fi page lists visible SSIDs. Select a network, enter the password, and press Connect.
If the normal network cannot be reached, use the setup AP:
SSID: Ize-Ribbon
Password: izeribbon
Web UI: http://10.42.0.1:8080
Refresh USB Export updates the read-only USB text export image.
The USB export is deliberately read-only to avoid filesystem corruption. Use the Web UI refresh button or:
sudo bash scripts/refresh_usb_export.shBattery display order:
- Linux power supply capacity from
/sys/class/power_supply upoweroracpi, if available- INA219-compatible voltage sensor over I2C
- Manual fallback text
When INA219 voltage is used, the app converts LiPo voltage to an approximate percentage.
I2C requirements:
dtparam=i2c_arm=oni2c-devloaded- user in the
i2cgroup
Power off from the menu or Web UI shows a sleep/power-off notice before shutdown.
Idle shutdown uses the configured Auto Off time. When external power is detected, or when configured to assume external power on unknown power state, idle shutdown is skipped.
Main config.json keys:
title: display titleversion: firmware/software versiondocument: current document pathfont_primary: primary display fontfont_fallback: fallback display font used when a character is missing from the primary fontfont_ko: legacy Korean font keyfont_latin: legacy Latin font keybody_font_size: body text sizeline_gap: body line spacingdisplay_rotation:180for upside-down mountingbody_visible_lines: visible body linesdisplay_tail_chars: text tail used for fast line layoutcount_mode:off,words, orcharsidle_shutdown_enabled: idle shutdown switchidle_shutdown_seconds: idle timeoutselected_languages: active input languagesinput_language_index: current language slotweb_port: Web UI portbattery_source:autoormanualbattery_manual_text: fallback displayassume_external_power_when_unknown: skip idle shutdown when power state is unknowngithub_sync_repo: GitHub repo inowner/repositoryformatgithub_sync_ssh_key: deploy key pathusb_export_image: USB image pathusb_export_mount: USB export mount pathactivity_file: idle activity timestamp path
Restart services:
sudo systemctl restart ize-ribbon.service
sudo systemctl restart ize-ribbon-web.service
sudo systemctl restart ize-ribbon-idle-shutdown.serviceCheck status:
systemctl status ize-ribbon.service
systemctl status ize-ribbon-web.service
systemctl status ize-ribbon-idle-shutdown.serviceView logs:
journalctl -u ize-ribbon.service -f
journalctl -u ize-ribbon-web.service -fManual Git sync check:
cd /home/ize/ize-ribbon/docs
git status
git log --oneline -5- GitHub private repository sync through Web UI
- Deploy key generation from the device
- Automatic document sync between
docs/and private GitHub repositories - Linux input event menu handling
- Improved Bluetooth pairing flow for legacy keyboards
- Bluetooth and USB keyboard detection
- Korean input composition
- D2Coding as the primary bundled font
- Noto Sans Mono fallback only when D2Coding lacks a glyph
- Four-line 16px writing display with corrected line spacing
- Faster cached rendering
- Battery percent from Linux or INA219 voltage
- Network/IP display on device and Web UI
- Wi-Fi setup AP fallback
- Safer new-document cache handling
- Sleep/power-off notice before shutdown
I build strange little writing tools.
If you enjoyed this project, coffee support is welcome.
Ko-fi: https://ko-fi.com/dievesa