A small USB-C board that prints your GitHub week on a thermal ticket.
Once a week, the board fetches a ticket rendered by the PaperFlux web service (stars, followers, commits of the last 7 days, top languages and repositories) and prints it on a 58 mm thermal printer.
flowchart LR
GH[GitHub REST + GraphQL API] --> WEB
WEB["web/ — Sinatra service<br/>renders a 384 px, 1-bit PNG"] -- HTTPS --> FW
FW["fw/ — ESP32-C3 firmware<br/>on the PaperFlux board"] -- UART --> PR[58 mm thermal printer]
PD[USB-C PD charger] -- 9 V / 5 V --> FW
- Power. The board plugs into a USB-C Power Delivery charger. An AP33772S negotiates 9 V (5 V as a fallback) and powers both the logic and the printer.
- Schedule. The firmware joins WiFi, syncs its clock over NTP and checks once a minute whether a ticket is due. By default, one is due every week.
- Render. When a ticket is due, the board requests
https://paperflux.albanpetit.com/ticket/<username>. The web service collects the user's GitHub statistics, renders an HTML template in headless Chromium and converts the screenshot into a black-and-white PNG exactly as wide as the print head. - Print. The firmware decodes the PNG and streams it to the printer line by line.
| Folder | Contents | Tooling |
|---|---|---|
| web/ | Ticket rendering service, Docker image, Kamal deployment | Ruby 3.3, Sinatra, Ferrum, ImageMagick |
| fw/ | Firmware for the board: USB-C PD, WiFi, scheduling, HTTPS, PNG decoding, printing | PlatformIO, Arduino on ESP32-C3 |
| ecad/ | Schematic, 4-layer PCB, Gerbers, interactive BOM | KiCad |
| mcad/ | Enclosure model and the board's 3D export | FreeCAD |
| doc/ | Bill of materials, component datasheets, photos | — |
| .github/workflows/ | Server setup and continuous deployment of web/ |
GitHub Actions |
Each folder has its own README with the details.
| Block | Part |
|---|---|
| MCU | Espressif ESP32-C3-MINI-1 (WiFi 2.4 GHz, native USB) |
| USB-C PD sink | Diodes AP33772S with two DMN3009SFG MOSFETs on the output |
| 3.3 V rail | Diodes AP63203 buck converter |
| I²C level shifting | TI PCA9306 (3.3 V MCU ↔ 5 V PD controller) |
| USB ESD protection | TI TPD4E02B04 |
| Printer | 58 mm TTL thermal printer (DP-EH400/2), UART at 9600 baud |
| PCB | 33.55 × 50.05 mm, 4 layers, ENIG |
Web service, locally with Docker:
cd web
cp .env.example .env # set GITHUB_TOKEN and SESSION_SECRET
docker compose up -d
curl http://localhost:4568/ticket/<username> > ticket.pngFirmware, with PlatformIO:
cd fw
cp src/wifi-credentials-example.h src/wifi-credentials.h # set SSID and password
pio run --target upload
pio device monitorHardware: open ecad/ecad.kicad_pro in KiCad, after fetching the Espressif
library submodule:
git submodule update --initCommit messages follow:
type(scope): description
- feat: new feature
- fix: bug fix
- docs: documentation only
- style: formatting, indentation, renaming, with no impact on logic
- refactor: code or schematic refactoring without adding or fixing functionality
- perf: performance improvements
- test: adding or updating tests
- build: build system or dependency changes
- ci: continuous integration changes (workflows, actions)
- chore: other changes that do not modify the product itself
- ecad: schematic, PCB, electronic components
- mcad: 3D modelling, mechanics, enclosure
- fw: embedded firmware
- web: web service (server, API, deployment)
- doc: user or developer documentation
- repo: repository structure, scripts, configuration
Short and imperative: "add status LED" rather than "added status LED". Use English or French, but stay consistent.
feat(ecad): add USB-C connector to the schematic
fix(fw): stop the decoder at the end of its data
feat(web): add health check endpoint
docs(repo): add commit convention to the README
MIT
