The Problem
Coffee roasters need to record, analyze, and control roast profiles with precision, but commercial roasting software is expensive and proprietary. Artisan provides an open-source alternative that connects to thermocouple data loggers and PID controllers, giving roasters full control over their process data without vendor lock-in.
What This Does
Artisan is a PyQt-based desktop application for coffee roasting. The core logic lives in src/artisanlib/ with main.py as the primary entry point. It handles real-time data acquisition from roasters (Aillio, Giesen, Ikawa, and others via devices.py), PID control (pid.py, pid_control.py), and roast profile visualization (curves.py, canvas.py).
The src/plus/ directory contains optional commercial features like schedule.py (roast scheduling) and weight.py (green/roasted bean tracking). The doc/help_dialogs/ folder includes a script that converts Excel files to HTML help dialogs.
How It Is Wired
Execution starts at src/artisanlib/main.py and flows through the Qt event loop. The widest blast radius sits in translate (called from 243 places) and setText (207 places) — both are UI text functions, so localization changes ripple across the entire interface. PID (120 callers) and acquire/release (141/146 callers) are the core control and resource-management functions.
The module graph shows no import edges between the 183 internal modules — the static analysis resolved zero edges, meaning the call graph is entirely function-level. This makes the codebase unusually flat at the module level but heavily interconnected at the function level.
External effects are minimal: 28 functions read/write files, 3 run external commands, 14 make network calls (including start -> ws_connect -> ws_handle_reads for WebSocket communication), and 2 perform cryptographic operations. The src/artisanlib/util.py file is the most widely imported (46 files depend on it) and handles file I/O.
How To Use It
git clone https://github.com/moses-y/artisan
cd artisan/src
pip install -r requirements.txt
python artisan.py
The src/pyproject.toml and src/requirements.txt define dependencies. Configuration is embedded in the application; no external config file or environment variables are required. The src/artisan.py script is the launcher. Build scripts exist for Windows (build-win3-pi.bat), macOS (build-macos3.sh), and Linux (build-linux.sh).
Real-World Use
A roaster connects a thermocouple data logger to a laptop running Artisan, starts artisan.py, and selects their roaster model. The software records temperature curves in real time, applies PID control to regulate the roast, and saves the profile for later analysis. The src/plus/schedule.py module handles roast scheduling for production environments.
Code Health & Issues
Static analysis found 219 issues (67 high, 150 medium, 2 low) across three kinds:
- High - Duplicated code blocks: 7,912 repeated 6-line blocks across 149 files, concentrated in
.ci/scripts andsrc/artisanlib/. Extract shared helpers. - High - Deep nesting: 49 instances, worst in
aillio_r1.pyandaillio_r2.pyat 8 levels deep. Flatten with guard clauses. - High - Oversized files: 10 files exceed reasonable size;
comparator.pyhas 1,860 code lines. Split by responsibility.
The code health audit adds seven findings: unpinned GitHub Actions tags (high), missing lockfile (high), no least-privilege GITHUB_TOKEN (medium), no dependency vulnerability scan (medium), large binaries like WenQuanYiZenHei-01.ttf at 11MB (medium), persist-credentials: false not set on checkout (medium), and no job timeouts (low). A committed secret-shaped file src/includes/artisan_public_key.pem was flagged but needs manual verification.
The Bottom Line
Artisan is a mature, feature-complete roasting application with a large module surface and solid test coverage (204 test files, CI via GitHub Actions). The codebase shows its age in duplicated code and oversized files, and the missing lockfile is a real supply-chain risk. For coffee roasters needing a free, full-featured roasting tool, it's the best option available; for developers, expect to navigate a large, tightly-coupled codebase.