Skip to Content

← Tkinter Touchscreen HMI on a Raspberry PLC with Beacons

Fuse test benchRaspberry PLC 19RGPIOHMI / Dashboard

Tkinter Touchscreen HMI on a Raspberry PLC with Beacons — full example

Build a fullscreen Tkinter HMI on a Raspberry PLC touchscreen: live current and temperature displays, mode buttons and stack-light beacons on relays.

Complete, runnable program for the Raspberry PLC 19R (tkinter-gui-beacons-relays.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 — Tkinter GUI on touchscreen + beacons driven by relays

Equipment: Raspberry PLC 19R (Industrial Shields)
Based on:  fuse test bench project

Wiring:
  - HDMI/USB touchscreen connected to the Raspberry PLC
  - R0.1  Green beacon  (test running, all OK)
  - R0.2  Yellow beacon (ready / standby)
  - R0.8  Red beacon    (fault or emergency)

Requirements:
  pip3 install python3-librpiplc
  (Tkinter ships with Raspberry Pi OS)

Integration with the catalog:
  - The live values (current, Vdrop, temperature) come from
    ads1015-differential-adc-autogain.py and ds18b20-1wire-sensor.py.
  - The mode buttons launch fuse-test-sequences.py.
"""

import tkinter as tk
from rpiplc_lib import rpiplc

BEACONS = {"green": "R0.1", "yellow": "R0.2", "red": "R0.8"}


def set_beacon(active_color):
    """Turn on a single beacon and switch off the rest (exclusive state)."""
    for color, relay in BEACONS.items():
        state = rpiplc.HIGH if color == active_color else rpiplc.LOW
        rpiplc.digital_write(relay, state)


class TestBenchGUI:
    """Fullscreen 850x550 GUI designed for fingers: big fonts and buttons."""

    def __init__(self, root):
        self.root = root
        root.title("Fuse test bench")
        root.geometry("850x550")
        root.attributes("-fullscreen", True)  # dedicated touchscreen

        # --- Live display: current / Vdrop / temperature -----------------
        frame = tk.Frame(root, bg="black")
        frame.pack(fill="both", expand=True)

        self.lbl_current = self._display(frame, "CURRENT", "0.00 A", 0)
        self.lbl_vdrop = self._display(frame, "VDROP", "0.0 mV", 1)
        self.lbl_temp = self._display(frame, "TEMPERATURE", "--.- C", 2)

        # --- Mode button bar ---------------------------------------------
        buttons = tk.Frame(root)
        buttons.pack(fill="x", pady=10)
        tk.Button(buttons, text="DIRECT MODE", font=("Arial", 18), height=2,
                  command=self.direct_mode).pack(side="left", expand=True, fill="x")
        tk.Button(buttons, text="AUTOMATIC MODE", font=("Arial", 18), height=2,
                  command=self.automatic_mode).pack(side="left", expand=True, fill="x")
        tk.Button(buttons, text="STOP", font=("Arial", 18), height=2, fg="red",
                  command=self.stop).pack(side="left", expand=True, fill="x")

        set_beacon("yellow")      # startup: bench ready
        self.refresh()            # first refresh cycle

    def _display(self, parent, title, initial, column):
        f = tk.Frame(parent, bg="black")
        f.grid(row=0, column=column, padx=20, pady=40, sticky="nsew")
        parent.grid_columnconfigure(column, weight=1)
        tk.Label(f, text=title, fg="gray", bg="black",
                 font=("Arial", 16)).pack()
        lbl = tk.Label(f, text=initial, fg="lime", bg="black",
                       font=("Arial", 42, "bold"))
        lbl.pack()
        return lbl

    # On the real bench these values come from the acquisition modules
    def read_process(self):
        import random
        return (random.uniform(31.5, 32.5),   # current (A)
                random.uniform(95, 105),      # Vdrop (mV)
                random.uniform(22.0, 23.0))   # temperature (°C)

    def refresh(self):
        """Display cycle: Tkinter is in charge, hardware is read via after()."""
        amps, vdrop, temp = self.read_process()
        self.lbl_current.config(text="%.2f A" % amps)
        self.lbl_vdrop.config(text="%.1f mV" % vdrop)
        self.lbl_temp.config(text="%.1f C" % temp)
        self.root.after(500, self.refresh)  # every 500 ms, no threads

    def direct_mode(self):
        set_beacon("green")
        print("Direct mode: the operator sets the setpoint manually")

    def automatic_mode(self):
        set_beacon("green")
        print("Automatic mode: setpoints loaded from a reference file")

    def stop(self):
        set_beacon("red")
        print("STOP requested from the screen")


def main():
    rpiplc.init("RPIPLC_19R")
    for relay in BEACONS.values():
        rpiplc.pin_mode(relay, rpiplc.OUTPUT)

    root = tk.Tk()
    TestBenchGUI(root)
    root.mainloop()
    set_beacon(None)  # on exit, all beacons off


if __name__ == "__main__":
    main()
Download the full project pack — freeThis example + the related ones + bill of materials