If you're evaluating a WATS alternative, this guide walks through the migration path. Common triggers include cost (WATS Analytics runs at EUR 297/mo per module), a preference for Python-first workflows, or wanting to build on an open-source test framework instead of proprietary data converters.
TofuPilot pairs with OpenHTF (Google's open-source test framework) to give you structured test data, real-time analytics, and a REST API without vendor lock-in on the test execution side.
Concept Mapping
WATS and TofuPilot use different terminology for similar concepts. Here's how they map:
| WATS Concept | TofuPilot Equivalent | Notes |
|---|---|---|
| UUT Report | Test Run | One execution of a test sequence on a unit |
| Test Step | Phase | A phase in OpenHTF, containing measurements |
| Numeric Limit Test | Measurement with limits | Defined via htf.Measurement().in_range() |
| String Value Test | Measurement (string) | Any measured value, not just numeric |
| WATS Client / Data Converter | TofuPilot Python SDK | from tofupilot.openhtf import TofuPilot |
| WATS Dashboard | TofuPilot Dashboard | FPY, Cpk, Pareto, control charts at tofupilot.app |
| Test Sequence File | OpenHTF Test | Python script defining phases and measurements |
| Station Registration | Automatic | TofuPilot detects stations from test metadata |
Replacing the WATS Data Converter
With WATS, you typically use a data converter (TestStand, LabVIEW, or custom) to serialize test results and push them to the WATS API. With TofuPilot, you write your test logic in OpenHTF and the SDK handles reporting directly.
Here's a typical test that would replace a WATS data converter workflow:
import openhtf as htf
from openhtf.util import units
from tofupilot.openhtf import TofuPilot
@htf.measures(
htf.Measurement("supply_voltage")
.with_units(units.VOLT)
.in_range(4.75, 5.25),
htf.Measurement("clock_frequency")
.with_units(units.HERTZ)
.in_range(minimum=7.99e6),
htf.Measurement("firmware_version"),
)
def power_and_clock_check(test):
test.measurements.supply_voltage = 5.02
test.measurements.clock_frequency = 8.00e6
test.measurements.firmware_version = "v3.2.1"
@htf.measures(
htf.Measurement("signal_amplitude")
.with_units(units.VOLT)
.in_range(0.9, 1.1),
htf.Measurement("signal_thd")
.in_range(maximum=0.05),
)
def signal_integrity_check(test):
test.measurements.signal_amplitude = 1.01
test.measurements.signal_thd = 0.03
def main():
test = htf.Test(power_and_clock_check, signal_integrity_check)
with TofuPilot(test):
test.execute(test_start=lambda: "SN-10042")
if __name__ == "__main__":
main()No data converter needed. The TofuPilot SDK serializes the OpenHTF test record and uploads it automatically. Each phase maps to what WATS calls a test step, and each measurement carries its value, units, and limits.
Migrating Historical Data
You likely have test history in WATS that you want to preserve. TofuPilot's REST API accepts historical runs with explicit timestamps, so you can backfill without losing chronological context.
First, export your data from WATS (CSV export or API). Then import it:
import csv
from datetime import datetime
from tofupilot import TofuPilotClient
client = TofuPilotClient()
with open("wats_export.csv") as f:
reader = csv.DictReader(f)
for row in reader:
client.create_run(
procedure_id="functional-test",
unit_under_test={
"serial_number": row["SerialNumber"],
"part_number": row["PartNumber"],
},
run_passed=row["Status"] == "Passed",
started_at=datetime.fromisoformat(row["StartTime"]),
duration=float(row["Duration"]),
steps=[
{
"name": row["StepName"],
"step_passed": row["StepStatus"] == "Passed",
"measurements": [
{
"name": row["MeasurementName"],
"measured_value": float(row["Value"]),
"unit": row["Unit"],
"lower_limit": float(row["LowLimit"]) if row["LowLimit"] else None,
"upper_limit": float(row["HighLimit"]) if row["HighLimit"] else None,
}
],
}
],
)For complex WATS exports with nested test steps, flatten them into TofuPilot's phase/measurement structure. Each WATS numeric limit test becomes a measurement with lower_limit and upper_limit.
Parallel Running Strategy
Don't cut over in one shot. Run both systems side by side to validate the migration:
- Week 1. Pick one test station. Add the TofuPilot integration to its tests while keeping the WATS data converter active. Both systems receive the same data.
- Week 2. Compare results in both dashboards. Verify that measurement values, pass/fail outcomes, and station attribution match.
- Week 3. If everything aligns, disable the WATS data converter on that station. Roll out to the next station.
- Repeat until all stations report to TofuPilot only.
Keep your WATS subscription active during this period. You can export a final data snapshot before canceling.
What You Get After Migration
Once your tests report to TofuPilot, you'll find the analytics at tofupilot.app:
- FPY trends by station, product, and time range.
- Cpk and control charts for every measurement, computed automatically.
- Failure Pareto to identify your top failure modes.
- Measurement histograms showing distribution against limits.
- Full traceability per serial number across all test runs.
- REST API for integrating with your MES, ERP, or custom tooling.
These replace the WATS Analytics module. The difference is that your test execution layer is now open-source (OpenHTF), and you're not locked into a proprietary test framework to get analytics.