Skip to Content

← 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