Skip to content
Concepts & Methodology

Automated Test Reporting with TofuPilot

Learn how to generate automated hardware test reports from TofuPilot data, replacing manual Excel and PDF report creation.

JJulien Buteau
intermediate10 min readMarch 13, 2026

Automated Test Reporting with TofuPilot

Test reports are necessary. Building them manually is not. TofuPilot stores all your test data in a structured format, so reports can be generated automatically instead of assembled by hand in Excel every Friday.

The Manual Reporting Problem

A typical weekly quality report requires:

  1. Export data from each test station (15 min per station)
  2. Merge exports into one spreadsheet (30 min)
  3. Calculate FPY, failure pareto, and measurement stats (45 min)
  4. Build charts (30 min)
  5. Write summary and observations (30 min)
  6. Format and distribute (15 min)

That's 3+ hours every week. For a quality engineer who should be analyzing data, not formatting cells.

What TofuPilot Automates

TofuPilot replaces steps 1-4 entirely. The data is already centralized. The metrics are already computed. The charts are already drawn.

Manual stepTofuPilot equivalent
Export from each stationData uploads automatically
Merge into one spreadsheetAlready in one database
Calculate FPYComputed in real time
Build chartsBuilt-in dashboards
Failure paretoAuto-generated from test results
Measurement distributionsHistograms per measurement

Types of Test Reports

Per-Unit Test Report

A complete record of one unit's test results. Useful for:

  • Customer acceptance documentation
  • Warranty records
  • Regulatory submissions

Contents: serial number, all test procedures run, all measurements with limits, pass/fail status, timestamps.

Batch Summary Report

Aggregate quality data for a production batch. Useful for:

  • Production release decisions
  • Supplier quality reviews
  • Management dashboards

Contents: batch size, FPY, failure pareto, measurement distributions, Cpk values.

Station Performance Report

How each test station is performing. Useful for:

  • Maintenance planning
  • Capacity planning
  • Station qualification

Contents: FPY per station, cycle time, failure modes, measurement distributions.

Generating Reports via the API

Use TofuPilot's API to pull data for custom report formats.

batch_report.py
from tofupilot import TofuPilotClient
from datetime import datetime, timedelta

client = TofuPilotClient()

# Pull all runs for a procedure in the last 7 days
runs = client.get_runs(
    procedure_id="FINAL-FUNCTIONAL-V3",
    limit=500,
)

# Calculate batch statistics
total = len(runs)
passed = sum(1 for r in runs if r["run_passed"])
fpy = passed / total if total > 0 else 0

# Failure mode breakdown
failure_modes = {}
for run in runs:
    if not run["run_passed"]:
        for step in run.get("steps", []):
            if not step["status"]:
                mode = step["name"]
                failure_modes[mode] = failure_modes.get(mode, 0) + 1

print(f"Batch Report - FINAL-FUNCTIONAL-V3")
print(f"Period: Last 7 days")
print(f"Total units: {total}")
print(f"Passed: {passed}")
print(f"FPY: {fpy:.1%}")
print()
print("Top failure modes:")
for mode, count in sorted(failure_modes.items(), key=lambda x: -x[1]):
    print(f"  {mode}: {count} ({count/total:.1%})")

Generating a CSV Export

export_csv.py
import csv
from tofupilot import TofuPilotClient

client = TofuPilotClient()

runs = client.get_runs(
    procedure_id="FINAL-FUNCTIONAL-V3",
    limit=1000,
)

with open("test_report.csv", "w", newline="") as f:
    writer = csv.writer(f)
    writer.writerow(["Serial", "Date", "Status", "Step", "Measurement", "Value", "Unit", "Low Limit", "High Limit", "Pass"])

    for run in runs:
        serial = run["unit_under_test"]["serial_number"]
        date = run["created_at"]
        status = "PASS" if run["run_passed"] else "FAIL"

        for step in run.get("steps", []):
            for m in step.get("measurements", []):
                writer.writerow([
                    serial,
                    date,
                    status,
                    step["name"],
                    m["name"],
                    m["value"],
                    m.get("unit", ""),
                    m.get("limit_low", ""),
                    m.get("limit_high", ""),
                    "PASS" if step["status"] else "FAIL",
                ])

print(f"Exported {len(runs)} runs to test_report.csv")

Report Scheduling

Option A: Cron-Based Reports

weekly_report.py
# Run every Monday at 7 AM via cron
# 0 7 * * 1 python3 /opt/reports/weekly_report.py

from tofupilot import TofuPilotClient
import smtplib
from email.mime.text import MIMEText

client = TofuPilotClient()

# Generate report content
runs = client.get_runs(procedure_id="FINAL-FUNCTIONAL-V3", limit=500)
total = len(runs)
passed = sum(1 for r in runs if r["run_passed"])
fpy = passed / total if total > 0 else 0

report = f"""Weekly Test Report - FINAL-FUNCTIONAL-V3

Units tested: {total}
First-pass yield: {fpy:.1%}
"""

# Send via email
msg = MIMEText(report)
msg["Subject"] = f"Weekly Test Report - FPY {fpy:.1%}"
msg["From"] = "reports@yourcompany.com"
msg["To"] = "quality-team@yourcompany.com"

with smtplib.SMTP("smtp.yourcompany.com") as server:
    server.send_message(msg)

Option B: Dashboard Links

Instead of generating PDF reports, share TofuPilot dashboard links. The recipient sees live data, not a snapshot from when the report was generated.

Advantages over static reports:

  • Always up to date
  • Interactive (filter, drill down, compare)
  • No generation step needed
  • No distribution step needed

Replacing the Weekly Quality Meeting

Instead of spending the first 30 minutes of your quality meeting presenting data, open TofuPilot's dashboard and start the conversation from the data. The meeting shifts from "here's what happened" to "here's what we should do about it."

More Guides

Put this guide into practice