Real-time reflow soldering monitor using Topdon TC001/TS001 thermal cameras against the SAC305 (Chip Quik SMD291SNL) reflow profile.
Based on leswright1977/PyThermalCamera with modifications for macOS/Linux support and reflow monitoring features.
- WebUI and CLI — browser-based interface (Nuxt.js + TailwindCSS + Chart.js) or terminal mode (OpenCV + matplotlib)
- Cross-platform — macOS (avfoundation) and Linux (v4l2) camera support
- Smooth SAC305 reference curve — piecewise exponential/cubic/parabolic functions matching the datasheet profile
- ROI and exclusion zones — select a region of interest and exclude hot spots (connectors, clamps)
- Auto-start with debounce — reflow timer starts automatically when average temperature exceeds a configurable threshold
- Live temperature tracking — average, max, and center pixel temperatures plotted against the SAC305 reference
- Phase announcements — audio cues at each phase transition (preheat, soak, reflow, cooling)
- Pace feedback — audio alerts when the live temperature deviates from the target curve
- TS001 auto-ranging — automatic low/high temperature mode switching via USB
- PCB material safety alerts — one-shot notifications when temperatures approach PCB-specific safe peak limits
- Docker support — engine and WebUI run in separate containers for headless setups
- Python 3.10+
ffmpeginstalled and onPATH- Node.js 20+ (for building the WebUI frontend)
- Topdon TC001 or TS001 thermal camera
pip install -r requirements.txtcd web/frontend
npm install
npx nuxt generate
cd ../..# All-in-one (engine + WebUI on same machine)
python reflow.py --web
# Engine-only (e.g. on a Raspberry Pi with the camera)
python run_engine.py --port 8080
# CLI mode with OpenCV + matplotlib
python reflow.py --reflow --device 0 --camera ts001python reflow.py --web [--port 8080]Open http://localhost:8080 in a browser. The UI has:
- Engine endpoint — top bar where you configure the engine address. Leave empty when running locally. Set to
http://<engine-host>:8080when the engine runs on another machine or in Docker. - Camera panel — select device index, camera type (TS001/TC001), connect/disconnect.
- Reflow settings — start threshold, hold time, monitor temperature metric, PCB material.
- ROI & Exclusions — select a region of interest or exclusion zones by dragging on the heatmap canvas.
- Live status — real-time temperatures, phase, pace, elapsed time.
- Chart — Chart.js live plot of avg/max/center temperatures vs SAC305 reference curve.
Run the engine on a machine with the thermal camera attached — no display, no Node.js, no frontend build needed:
# On the Pi / headless machine (only needs Python + ffmpeg):
pip install -r requirements.txt
python run_engine.py --port 8080Then open the WebUI on any other machine (your laptop, a server, etc.) and set the Engine endpoint field to http://<pi-ip>:8080. The WebUI can be:
- The Docker
webuicontainer - A local dev server (
cd web/frontend && npx nuxt dev) - The all-in-one mode on another machine (
python reflow.py --web) — just point the endpoint field at the Pi
Files needed on the engine machine: engine/, web/__init__.py, web/server.py, run_engine.py, sound/, requirements.txt.
python reflow.py --reflow --device <N> [options]| Flag | Default | Description |
|---|---|---|
--device <N> |
0 |
Camera device index |
--camera {ts001,tc001} |
ts001 |
Camera model |
--start-threshold <C> |
35.0 |
Avg temp threshold to auto-start the timer |
--start-hold <s> |
5.0 |
Seconds avg must stay above threshold before starting |
--monitor-temp |
average |
Temperature metric for pace tracking (average/min/max/center) |
--pcb-material |
tg135_generic_fr4 |
PCB material for safe-peak notification |
Workflow:
- ROI selection — click two corners on the heatmap, press ENTER to confirm or ESC to skip.
- Exclusion zones — press 1/2/3 for rectangle/square/circle mode, click two points, ENTER to start.
- Monitoring — two windows: OpenCV heatmap with HUD overlay and matplotlib live plot.
- Exit — press ESC or Ctrl+C. Final plot is saved automatically to
plots/.
Key bindings:
| Key | Action |
|---|---|
ESC |
Quit and save final plot |
s |
Save current plot snapshot |
r |
Rotate heatmap by 90 degrees |
# List available cameras
python reflow.py --list-devices
# Show static SAC305 profile chart
python reflow.py --plot
# Basic thermal view (no reflow features)
python reflow.py --calibrate --device <N>The project provides a two-container setup: an engine container (Python + ffmpeg + camera access) and a WebUI container (nginx serving the Nuxt frontend).
docker compose up --build- Engine:
http://localhost:8080(API + WebSocket) - WebUI:
http://localhost:3000(browser interface)
Open the WebUI at http://localhost:3000 and set the engine endpoint to http://localhost:8080 in the top bar.
The docker-compose.yml passes /dev/video0 to the engine container. Adjust to match your thermal camera device:
# Find your camera device on the host
v4l2-ctl --list-devices
# Edit docker-compose.yml devices section accordinglyThe engine container runs in privileged mode for USB access. For tighter security, use specific --device and --group-add flags instead.
If you only need the engine (e.g., camera is on a remote machine):
docker compose up engineThen point any WebUI instance (local dev, another Docker host, or the standalone build) at http://<engine-host>:8080.
| Phase | Time | Temp | Curve shape |
|---|---|---|---|
| Preheat | 0 - 90 s | 25 - 150 C | Exponential approach |
| Soak + Ramp | 90 - 210 s | 150 - 175 - 217 C | Smooth cubic S-curve |
| Reflow (TAL) | 210 - 270 s | 217 - 249 - 217 C | Parabolic peak |
| Cooling | 270 - 370 s | 217 - 25 C | Exponential decay |
Reference: Chip Quik SMD291SNL datasheet
engine/ # Core logic (no UI dependencies)
profile.py # SAC305 profile math + PCB constants
camera.py # CameraFeed (macOS avfoundation / Linux v4l2)
thermal.py # ThermalData — vectorized temperature extraction
usb_control.py # TS001USB — pyusb low/high temp mode switching
audio.py # AudioPlayer — cross-platform sound playback
heatmap.py # build_heatmap_frame() — BGR ndarray with HUD
monitor.py # ReflowEngine — state machine, process_frame() -> dict
web/
server.py # FastAPI + WebSocket (JPEG frames + JSON telemetry)
frontend/ # Nuxt.js 3 + TailwindCSS + Chart.js
app.vue # Root layout with endpoint bar, heatmap, settings, chart
composables/ # useMonitor.ts — WebSocket, state, API calls
components/ # HeatmapView, SettingsPanel, ReflowChart, etc.
reflow.py # CLI entry point (thin wrapper over engine/)
run_engine.py # Standalone engine server (no frontend needed)
docker/ # Dockerfiles + nginx config
docker-compose.yml # Engine + WebUI containers
sound/ # Audio feedback WAV files
plots/ # Saved plot snapshots (auto-created)
CameraFeed.readFrame()
-> ThermalData.extract_temperatures_fast(roi, exclude_zones)
-> (avg, max, center)
-> ReflowEngine.process_frame()
-> state dict {temps, pace, phase, elapsed, ...}
-> UI renders heatmap + plot from state
See LICENSE.