When your LabVIEW engineer leaves, the first job is to freeze what runs today, the second is to find out what you actually own, and the third is to keep results flowing while you rebuild the riskiest station in Python. Most plants do the first and skip the other two. The order below covers the first 48 hours, the first two weeks and the first 30 days, in that sequence.
The First 48 Hours
Do these before anything else. Each takes an hour or two now and a week a month from now.
- Freeze the deployed builds. Copy the exact executable, the run-time engine installer and every
.inior config file from each station PC to a share. Not the source, the thing that runs. If a station PC dies next week, this is what you reinstall. - Locate the project files. Find every
.lvproj,.vi,.lvlib,.ctl, the TestStand.seqfiles and the build spec that produced each deployed executable. They're often on the engineer's laptop, a personal share or a USB stick in a drawer. - Record the exact runtime versions. LabVIEW version and bitness, the run-time engine on each station, TestStand version, DAQmx and NI-VISA driver versions. A 2019 VI doesn't open cleanly in 2024 without a recompile, and the recompile is where things break.
- Export licence info. Which seats are on subscription, which NI account owns them, when they renew. LabVIEW seats and TestStand deployment licences are subscription-only now. A lapsed renewal means you can't open the source even after you find it.
- Copy everything to a repo. Binary VIs included. Git won't diff them, but it timestamps them, and "the version that was on line 3 the day he left" becomes a commit instead of a memory. The Git documentation covers the basics if the plant has never used it.
Also rotate the station PC passwords and the NI account credentials, and keep read access to the engineer's mailbox for the notice period. Half the instrument workarounds are in email threads.
The First Two Weeks: Inventory
You can't prioritize what you haven't counted. Walk the floor with a laptop and fill in one row per station.
| Station | Product | Volume per week | Who can open the VI | Runtime version | Risk |
|---|---|---|---|---|---|
| FCT-01 | Controller PCBA | 1,200 | Nobody | LabVIEW 2019 RTE, 32-bit | High |
| CAL-03 | IMU module | 800 | Nobody | LabVIEW 2017 RTE | High |
| EOL-02 | Gimbal assembly | 300 | Integrator (NI Alliance Partner) | LabVIEW 2021, TestStand 2021 | Medium |
| BURN-04 | Battery pack | 150 | Test technician (limits only) | LabVIEW 2023 | Low |
Risk is a function of three things: volume, who can open it and how old the runtime is. A high-volume station nobody can open on a runtime NI no longer ships is your first rebuild candidate. A low-volume station a technician can already tweak can wait a year.
Give the inventory a deadline of two weeks and one owner, and have the plant manager sign it. It's the document that turns "we lost our LabVIEW guy" from a panic into a plan with a first row, and it's the one you'll show a candidate or an integrator to explain what the job is.
The inventory is also the first page of the hand-over document you never had. Document a Test Station for Hand-Over has the full template, and Bus Factor in Test Engineering explains how the plant ended up with a column full of "Nobody" in the first place.
Keep Results Flowing
Yield doesn't stop mattering because the engineer left. The one change you can make to a station without opening its sequence is where the results go.
Post each run to TofuPilot's REST API v2. The payload is small, the auth is a bearer token and the station doesn't need Python.
run.json28 lines
{ "outcome": "PASS", "procedure_id": "8122a38c-3fbc-4bf0-881b-24ea1e2cb937", "serial_number": "UAUT-04829", "part_number": "PCB-MAIN-V2", "started_at": "2026-09-14T08:12:04Z", "ended_at": "2026-09-14T08:13:41Z", "phases": [ { "name": "Power Rails", "outcome": "PASS", "started_at": "2026-09-14T08:12:10Z", "ended_at": "2026-09-14T08:12:14Z", "measurements": [ { "name": "rail_3v3", "outcome": "PASS", "measured_value": 3.31, "units": "V", "validators": [ { "operator": ">=", "expected_value": 3.2, "outcome": "PASS" }, { "operator": "<=", "expected_value": 3.4, "outcome": "PASS" } ] } ] } ]}The procedure_id comes from the procedure page in TofuPilot. outcome is one of PASS, FAIL, ERROR, TIMEOUT or ABORTED, and the timestamps are ISO 8601. Phases and measurements are optional, so the minimum viable version is the top six fields. Create one API key per station in TofuPilot and keep it in the station's environment, not inside the VI, so rotating it later doesn't mean a rebuild.
From LabVIEW, the HTTP Client VIs do this in four nodes: Open Handle, Add Header twice (Authorization: Bearer <api key> and Content-Type: application/json), POST to https://www.tofupilot.app/api/v2/runs with the JSON string, Close Handle. Drop it into the existing report SubVI after the TDMS write, so nothing else in the sequence changes. If you'd rather not touch the VI at all, have the station write the JSON to a folder and let a short Python script post it.
upload_run.py21 lines
# Posts one run file to TofuPilot; call it from a folder watcher or System Exec after each testimport jsonimport osimport sysimport requestsAPI_URL = "https://www.tofupilot.app/api/v2/runs"def upload(path): with open(path, encoding="utf-8") as f: payload = json.load(f) headers = {"Authorization": f"Bearer {os.environ['TOFUPILOT_API_KEY']}"} response = requests.post(API_URL, json=payload, headers=headers, timeout=30) response.raise_for_status() print(f"Uploaded run {response.json()['id']} from {path}")if __name__ == "__main__": upload(sys.argv[1])After a week you have FPY per station and a failure Pareto in TofuPilot without anyone having opened a VI. That's the number the plant manager asks for, and it's the number that tells you which station to rebuild first.
The First 30 Days: Rebuild One Station
Take the top row of the inventory and rebuild it in Python with the TofuPilot Framework. The station becomes a folder: procedure.yaml for the sequence and limits, phases/ for the test steps, plugs/ for the instruments, all text and all under Git. Anyone on the team can open it.
procedure.yaml34 lines
# FCT-01 rebuilt: same limits as the LabVIEW station, same serial number formatname: Controller Board FCTversion: 2.0.0unit: serial_number: default_value: "UAUT-00000" part_number: default_value: "PCB-MAIN-V2"plugs: - name: dmm python: plugs.dmm:Multimeter config: address: "TCPIP::192.168.1.100::INSTR"main: - name: Power Rails python: phases.power_rails measurements: - name: rail_3v3 unit: V validators: - operator: ">=" expected_value: 3.2 - operator: "<=" expected_value: 3.4 - name: rail_5v unit: V validators: - operator: ">=" expected_value: 4.8 - operator: "<=" expected_value: 5.2# Reads two rails; the framework checks them against the validators abovedef power_rails(measurements, dmm): measurements.rail_3v3 = dmm.read_voltage(101) # mux channel 101 is the 3V3 rail measurements.rail_5v = dmm.read_voltage(102)Run it side by side with the LabVIEW station on the same units for two weeks. Both post to the same procedure in TofuPilot, so the comparison is a filter on the run list, not a spreadsheet. When the Python station agrees with the old one on every unit, and disagrees only where the old one was wrong, retire the VI. How to Migrate from LabVIEW to Python has the phase-by-phase mapping.
You don't need to convert the rest of the floor this month. Run a Mixed LabVIEW and Python Test Team covers how the two coexist while the inventory shrinks one row at a time.
What Not to Do
Don't hire a contractor to keep the old VI alive indefinitely. A certified NI integrator typically charges a four-figure day rate, and each change request comes back in days to weeks. That's fine for a quarter of bridge cover. As a permanent arrangement it's paying a premium to stand still.
Don't rewrite everything at once. Six stations rebuilt in one quarter is six unvalidated stations and one exhausted engineer. One station, side by side, two weeks, then the next.
Don't skip the side-by-side. The LabVIEW station has ten years of undocumented fixes baked in. The only way to find them is to run both on the same units and look at where they disagree.
Don't recreate the single point of failure in Python. The framework makes the station readable by anyone. Keep it that way with a repo, a README and a second person who has run it.
Start With One Station
Pick the station with the highest volume, or the one only one person can open. Rebuild it in Python with the TofuPilot Framework and run it side by side with the LabVIEW version on the same units for two weeks. Compare the two result sets in TofuPilot before you retire anything.
curl -fsSL https://www.tofupilot.app/install | shtofupilot run ./procedure.yamlThe step-by-step is in How to Migrate from LabVIEW to Python, and the framework is at https://tofupilot.com/products/framework. The Lab tier is free, and tofupilot run works with no account.
