📺 TVTOM – RFID Video Player

NFC-Karte draufhalten → Video startet im Vollbild. YouTube oder lokal, per VLC oder Firefox-Kiosk.

PythonRFIDYouTubeVLCTkinter

📊 Wie es funktioniert

1
📡

RFID-Scan

NFC-Karte an RFID-Reader halten. Serial-Port-Thread liest die Tag-ID in Echtzeit.

2
🔍

Lookup

JSON-Config checkt: Ist dieser Tag mit einem Video oder YouTube-Link verknüpft?

3
▶️

Wiedergabe

YouTube: Firefox-Kiosk mit Embed-HTML. Lokal: VLC --fullscreen --play-and-exit.

4
🔄

Wechsel

Gleiche Karte = Stop. Andere Karte = aktuelles Video beenden, neues starten.

💻 Echter Code aus dem Projekt

RFID-Listener-Thread: Serielle Schnittstelle mit Karten-Logik

import serial, threading, subprocess, json, tempfile

class RFIDVLCApp:
    def listen_for_rfid(self):
        """Fortlaufend RFID-Tags vom COM-Port lesen"""
        current_browser_process = None

        while not self.stop_thread:
            try:
                with serial.Serial(
                    port=self.config["comport"],
                    baudrate=self.config["baudrate"],
                    timeout=1) as ser:

                    while not self.stop_thread:
                        line = ser.readline().decode("utf-8").strip()
                        if not line:
                            continue
                            
                        tag_id = line
                        self.last_read_tag = tag_id
                        print(f"RFID-Tag: {tag_id}")

                        if tag_id not in self.config["cards"]:
                            print("Kein Video für diesen Tag")
                            continue

                        media_path = self.config["cards"][tag_id]

                        # Gleicher Tag = Stop
                        if current_browser_process and self.last_read_tag == tag_id:
                            current_browser_process.terminate()
                            current_browser_process = None
                        # Anderer Tag = Wechsel
                        elif current_browser_process and self.last_read_tag != tag_id:
                            current_browser_process.terminate()
                            current_browser_process = None

YouTube vs. lokales Video – automatische Erkennung

                            # YouTube-Link erkannt?
                            if media_path.startswith("http"):
                                # HTML mit Embed-Player erstellen
                                html_file = create_youtube_html(media_path)
                                current_browser_process = subprocess.Popen([
                                    "C:\\Program Files\\Mozilla Firefox\\firefox.exe",
                                    "--kiosk", html_file])
                            else:
                                # Lokales Video mit VLC
                                current_browser_process = subprocess.Popen([
                                    self.config["vlc_path"],
                                    "--fullscreen",
                                    "--play-and-exit",
                                    media_path])

            except serial.SerialException as e:
                print(f"[Warnung] COM-Port: {e}")

YouTube-Embed-HTML-Generator für Kiosk-Mode

def create_youtube_html(youtube_link):
    """HTML-Datei mit YouTube-Embed im Vollbild"""
    video_id = youtube_link.split("v=")[-1].split("&")[0]
    embed_link = f"https://www.youtube.com/embed/{video_id}?autoplay=1&rel=0"

    html_content = f"""<!DOCTYPE html>
<html><head><style>
    body, html {{ margin:0; padding:0; height:100%; overflow:hidden; }}
    iframe {{ position:absolute; top:0; left:0; 
              width:100%; height:100%; border:none; }}
</style></head><body>
    <iframe src="{embed_link}" allowfullscreen></iframe>
</body></html>"""

    with tempfile.NamedTemporaryFile(
        delete=False, suffix=".html") as f:
        f.write(html_content.encode('utf-8'))
        return f.name

Setup-Fenster: Karten-Management mit F12

    def show_setup(self, event=None):
        """F12 öffnet passwortgeschütztes Setup"""
        password = simpledialog.askstring(
            "Setup", "Passwort:", show='*')
        if password == DEFAULT_PASSWORD:
            self.open_setup_window()

    def setup_window(self):
        # COM-Port-Dropdown (erkennt verfügbare Ports)
        com_ports = [port.device 
                     for port in serial.tools.list_ports.comports()]
        port_dropdown = tk.OptionMenu(
            setup_win, self.com_port_var, *com_ports)

        # Baudrate-Dropdown
        baud_rates = [9600, 19200, 38400, 57600, 115200]
        baudrate_dropdown = tk.OptionMenu(
            setup_win, self.baudrate_var, *baud_rates)

        # VLC-Pfad konfigurierbar
        self.vlc_path_var = tk.StringVar(
            value=r"C:\Program Files (x86)\VideoLAN\VLC\vlc.exe")

🎯 Einsatzszenarien

🏛️

Museen & Ausstellungen

Besucher halten NFC-Karte an Leser → Infovideo zum Exponat startet. Keine Touchscreens, hygienisch, intuitiv.

👶

Kinder-Lernstationen

„Tomi" (TVTOM) – Kinder legen Bildkarten auf und sehen Lernvideos. Spielerisch, selbsterklärend.

🏭

Industrie-Schulung

Mitarbeiter-Karte = persönliches Schulungsvideo. Maschinen-Karte = Wartungsanleitung. Direkt am Arbeitsplatz.