← Plain-Text Test Reports from a Raspberry PLC in Python
Fuse test benchRaspberry PLC 19RFicherosDatalogging
Plain-Text Test Reports from a Raspberry PLC in Python — full example
Generate timestamped TXT test reports on a Raspberry PLC: header with conditions, per-sample current and resistance table, verdict and operator notes.
Complete, runnable program for the Raspberry PLC 19R (txt-test-reports.py): wiring header, requirements and integration notes included.
Download the full project pack — freeThis example + the related ones + bill of materials
Read-only preview.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
COMPLETE EXAMPLE — Test report generation in TXT
Equipment: Raspberry PLC 19R (Industrial Shields)
Based on: fuse test bench project
Wiring:
- None specific: this module consumes the data produced by the
others (currents from the ADS1015, temperature from the DS18B20,
verdicts from the test sequences).
Requirements:
No pip dependencies: standard library only.
Output:
Test_Reports/Report_YYYY-MM-DD_HH-MM-SS.txt
Plain text: opens on any machine, attaches to email and can be
archived for years without format issues.
Integration with the catalog:
- The 'result' dict comes from fuse-test-sequences.py
- The temperature from ds18b20-1wire-sensor.py
- The measurements from ads1015-differential-adc-autogain.py
"""
import os
from datetime import datetime
REPORTS_DIR = "Test_Reports"
WIDTH = 64 # report line width
def rule(char="-"):
return char * WIDTH + "\n"
def generate_report(test, samples, comments=""):
"""Write the TXT report and return the path of the created file.
test: dict with the test metadata and verdict
samples: list of dicts per sample (current, Vdrop, resistance)
"""
os.makedirs(REPORTS_DIR, exist_ok=True)
now = datetime.now()
filename = "Report_%s.txt" % now.strftime("%Y-%m-%d_%H-%M-%S")
path = os.path.join(REPORTS_DIR, filename)
with open(path, "w", encoding="utf-8") as f:
# --- Header --------------------------------------------------------
f.write(rule("="))
f.write("FUSE TEST REPORT".center(WIDTH) + "\n")
f.write(rule("="))
f.write("Date/time : %s\n" % now.strftime("%d/%m/%Y %H:%M:%S"))
f.write("Test type : %s\n" % test["type"])
f.write("Fuse holder : %s\n" % test["base"])
f.write("Fuse rated In : %.1f A\n" % test["fuse_in"])
f.write("Setpoint : %.1f A\n" % test["setpoint"])
f.write("Ambient temp. : %.1f C\n" % test["temperature_c"])
f.write(rule())
# --- Sample table ----------------------------------------------------
f.write("%-8s %-12s %-12s %-14s %-10s\n"
% ("Sample", "I avg (A)", "Vdrop (mV)", "R (mOhm)", "Status"))
for i, s in enumerate(samples, start=1):
r_mohm = s["vdrop_mv"] / s["i_avg"] if s["i_avg"] > 0 else 0.0
f.write("%-8d %-12.2f %-12.1f %-14.2f %-10s\n"
% (i, s["i_avg"], s["vdrop_mv"], r_mohm, s["status"]))
f.write(rule())
# --- Verdict and comments ---------------------------------------------
f.write("OVERALL RESULT: %s\n" % test["result"])
if comments:
f.write("\nOperator comments:\n%s\n" % comments)
f.write(rule("="))
return path
def main():
# Sample data with the same structure the real bench produces
test = {
"type": "NON_FUSING (1.13 x In)",
"base": "10x38",
"fuse_in": 20.0,
"setpoint": 22.6,
"temperature_c": 22.4, # from the DS18B20
"result": "PASS",
}
samples = [
{"i_avg": 22.58, "vdrop_mv": 101.3, "status": "NOT BLOWN"},
{"i_avg": 22.61, "vdrop_mv": 99.8, "status": "NOT BLOWN"},
{"i_avg": 22.55, "vdrop_mv": 103.1, "status": "NOT BLOWN"},
]
path = generate_report(
test, samples,
comments="Validation batch. No incidents during the test.")
print("Report generated at:", path)
with open(path, encoding="utf-8") as f:
print(f.read())
if __name__ == "__main__":
main()
Download the full project pack — freeThis example + the related ones + bill of materials