commit 507673a8c8b28c0b87bed6042e1050b8d9a1cf3d Author: Tim Date: Tue Jun 9 12:26:26 2026 +0200 Init diff --git a/Actor/app.py b/Actor/app.py new file mode 100644 index 0000000..22773b3 --- /dev/null +++ b/Actor/app.py @@ -0,0 +1,202 @@ +import paho.mqtt.client as mqtt +import json +import threading +from flask import Flask, render_template +import os + + +# ========================================================== +# KONFIGURATION & DATEIEN +# ========================================================== + +CHIP_NAMES_FILE = "data.json" +STATE_SAVE_FILE = "current_status.json" # Die Datei, in die der Zustand geschrieben wird +MQTT_TOPIC = None +MQTT_BROKER = None +MQTT_PORT = None + +# Global State Management: Schlüssel ist die eindeutige ID. +RFID_STATUS = {} +status_lock = threading.Lock() + +app = Flask(__name__) + + +def load_config(): + """Liest alle Konfigurationsdaten (MQTT-Settings und Chip-Status) aus data.json.""" + global RFID_STATUS, MQTT_BROKER, MQTT_TOPIC, MQTT_PORT + print("--- Starte Konfigurationsladen ---") + try: + with open(CHIP_NAMES_FILE, 'r', encoding='utf-8') as f: + data = json.load(f) + + # 1. MQTT Konfiguration auslesen + if "mqtt_config" not in data or not isinstance(data["mqtt_config"], dict): + raise ValueError("Die JSON-Struktur ist falsch. Fehlendes 'mqtt_config' Key.") + + mqtt_cfg = data["mqtt_config"] + MQTT_BROKER = str(mqtt_cfg.get('broker', 'localhost')) + MQTT_PORT = int(mqtt_cfg.get('port', 1883)) + MQTT_TOPIC = str(mqtt_cfg.get('topic', 'Gruppe 14')) + + print(f"✅ MQTT-Einstellungen geladen: Broker={MQTT_BROKER}, Topic={MQTT_TOPIC}") + + + # 2. Chip-Status initialisieren + if "chips" not in data or not isinstance(data["chips"], list): + raise ValueError("Die JSON-Struktur ist falsch. Fehlendes 'chips' Key.") + + for chip_data in data["chips"]: + chip_id = str(chip_data.get('id', 'UNKNOWN')) + chip_name = str(chip_data.get('name', 'N/A')) + initial_status = int(str(chip_data.get('status', '0'))) + + RFID_STATUS[chip_id] = { + "Name": chip_name, + "ID": chip_id, + "Status": initial_status + } + + print(f"✅ Starte mit {len(RFID_STATUS)} Chips, geladen aus {CHIP_NAMES_FILE}.") + return True + + except FileNotFoundError: + print("❌ KRITISCHER FEHLER: Die Datei data.json wurde nicht gefunden!") + print("Bitte erstellen Sie diese Datei und verwenden Sie die korrekte Struktur.") + return False + except json.JSONDecodeError: + print(f"❌ KRITISCHER FEHLER: Die Datei {CHIP_NAMES_FILE} ist kein gültiges JSON!") + return False + except ValueError as e: + print(f"❌ KONFIGURIERUNGSFEHLER: {e}") + return False + +# ========================================================== +# 💾 Funktion zur Zustandsspeicherung (Korrigierter Block) +# ========================================================== + +def save_state(): + """Speichert den gesamten aktuellen RFID_STATUS in die Konfigurationsdatei.""" + global RFID_STATUS + data_to_save = { + "chips": [ + { + "name": data['Name'], + "id": data['ID'], + "status": str(data['Status']) + } for data in RFID_STATUS.values() + ] + } + + try: + with status_lock: + # Innerstes Level der Indentation ist hier entscheidend! + with open(STATE_SAVE_FILE, 'w', encoding='utf-8') as f: + json.dump(data_to_save, f, indent=4) + print(f"\n[💾 SPEICHERT] Status erfolgreich in {STATE_SAVE_FILE} gespeichert.") + except Exception as e: + # Dieser Block muss korrekt unter dem 'try' stehen und einen Fehler abfangen. + print(f"[FEHLER!] Konnte den Zustand nicht speichern: {e}") + + +# ========================================================== +# ⚙️ Angepasste Funktion (Status-Update und Logging) +# ========================================================== + +def update_status(chip_id): + """Aktualisiert den Status, loggt die Änderung UND speichert den Zustand.""" + global RFID_STATUS + + if chip_id not in RFID_STATUS: + print(f"[WARNUNG] Unbekannte oder ungültige ID erkannt: '{chip_id}'. Ignoriere den Statuswechsel.") + return + + with status_lock: + old_status = RFID_STATUS[chip_id]['Status'] + new_status = 1 - old_status + RFID_STATUS[chip_id]['Status'] = new_status + + # Logging der Änderung und Speichern des Zustands + if old_status == 0 and new_status == 1: + logging_message = "✅ AKTIVIERUNG DETEKTIERT! (Von Inaktiv zu Aktiv)" + print(f"\n[!!! STATUS GEÄNDERT !!!] {logging_message} Chip ID '{chip_id}'. Neuer Status: 1.") + elif old_status == 1 and new_status == 0: + logging_message = "⚠️ DEAKTIVIERUNG DETEKTIERT! (Von Aktiv zu Inaktiv)" + print(f"\n[!!! STATUS GEÄNDERT !!!] {logging_message} Chip ID '{chip_id}'. Neuer Status: 0.") + + # Speichern des Zustandes nach jeder Änderung + save_state() + + +# ========================================================== +# MQTT LOGIK (Verwendet die globalen Variablen) +# ========================================================== + +def on_connect(client, userdata, flags, rc): + """Callback bei erfolgreicher Verbindung.""" + if rc == 0: + print("\n✅ MQTT verbunden. Abonniere Topic:", MQTT_TOPIC) + client.subscribe(MQTT_TOPIC) + else: + print(f"\n❌ MQTT Verbindung fehlgeschlagen mit Code {rc}") + +def on_message(client, userdata, msg): + """Callback bei empfangener Nachricht (Plain Text Payload = Chip ID).""" + payload = msg.payload.decode().strip() + + if not payload: + print("[WARNUNG] Empfangen leerer Payload.") + return + + chip_id = payload + + print(f"\n[MQTT] Plain Text ID empfangen: {chip_id}") + update_status(chip_id) + + +def run_mqtt_client(): + """Startet den MQTT-Client im Hintergrundthread mit den konfigurierten Daten.""" + client = mqtt.Client("RFID_Tracker") + client.on_connect = on_connect + client.on_message = on_message + + print("\n[MQTT] Starte Verbindung zum Broker...") + try: + # Nutzung der globalen Variablen (die aus data.json kommen) + client.connect(MQTT_BROKER, MQTT_PORT, 60) + client.loop_start() + except Exception as e: + print(f"\n!!! KRITISCHER FEHLER !!! Broker-Verbindung fehlgeschlagen ({e}). Prüfen Sie die Einstellungen in data.json.") + +# ========================================================== +# WEB-SERVER LOGIK (Flask) - Bleibt unverändert +# ========================================================== + +@app.route('/') +def index(): + """Die Hauptseite, die den aktuellen Status aller RFID Karten anzeigt.""" + global RFID_STATUS + with status_lock: + current_status = dict(RFID_STATUS) + return render_template('index.html', rfid_data=current_status, mqtt_topic=MQTT_TOPIC) + + +if __name__ == '__main__': + # Initialisierung des Chip-Zustandes UND der MQTT Konfiguration + if not load_config(): + print("\n[🛑 ABBRUCH] Das Programm kann wegen eines Fehlers bei der Konfiguration nicht gestartet werden.") + exit() + + mqtt_thread = threading.Thread(target=run_mqtt_client) + mqtt_thread.start() + + # Speichere den initialen Zustand, um die JSON-Datenbank zu befüllen + save_state() + + print("\n============================================================") + print(" *** RFID STATUS TRACKER AKTIV ***") + print("============================================================") + print(f"Statusseite läuft unter: http://0.0.0.0:{MQTT_PORT}/") + + # Start des Webservers auf allen Interfaces (für externen Zugriff) + app.run(host='0.0.0.0', port=5000, debug=True, use_reloader=False) diff --git a/Actor/current_status.json b/Actor/current_status.json new file mode 100644 index 0000000..2a8f40e --- /dev/null +++ b/Actor/current_status.json @@ -0,0 +1,24 @@ +{ + "chips": [ + { + "name": "1", + "id": "729558387180", + "status": "0" + }, + { + "name": "2", + "id": "987572218311", + "status": "0" + }, + { + "name": "3", + "id": "842310768930", + "status": "0" + }, + { + "name": "4", + "id": "773910059391", + "status": "0" + } + ] +} \ No newline at end of file diff --git a/Actor/data.json b/Actor/data.json new file mode 100644 index 0000000..ba9f273 --- /dev/null +++ b/Actor/data.json @@ -0,0 +1,29 @@ +{ + "mqtt_config": { + "broker": "192.168.213.12", + "port": 1883, + "topic": "RFID" + }, + "chips": [ + { + "name": "1", + "id": "729558387180", + "status": "0" + }, + { + "name": "2", + "id": "987572218311", + "status": "0" + }, + { + "name": "3", + "id": "842310768930", + "status": "0" + }, + { + "name": "4", + "id": "773910059391", + "status": "0" + } + ] +} \ No newline at end of file diff --git a/Actor/templates/index.html b/Actor/templates/index.html new file mode 100644 index 0000000..032af38 --- /dev/null +++ b/Actor/templates/index.html @@ -0,0 +1,120 @@ + + + + + + RFID Status Tracker + + + +
+

RFID Chip Status Übersicht

+

Daten werden über MQTT von Topic "{{ mqtt_topic }}" empfangen.

+ + {% for chip_id, data in rfid_data.items() %} +
+ + + {{ data.Name }} +
(ID: {{ data.ID }})
+
+ + +
+

Status:

+ + {% set status_class = 'status-active' if data.Status == 1 else 'status-inactive' %} + + {{ data.Status }} + +
+ +
+ {% endfor %} + +
+ + diff --git a/IDs.json b/IDs.json new file mode 100644 index 0000000..2a8f40e --- /dev/null +++ b/IDs.json @@ -0,0 +1,24 @@ +{ + "chips": [ + { + "name": "1", + "id": "729558387180", + "status": "0" + }, + { + "name": "2", + "id": "987572218311", + "status": "0" + }, + { + "name": "3", + "id": "842310768930", + "status": "0" + }, + { + "name": "4", + "id": "773910059391", + "status": "0" + } + ] +} \ No newline at end of file diff --git a/sensor.py b/sensor.py new file mode 100644 index 0000000..9c02ec9 --- /dev/null +++ b/sensor.py @@ -0,0 +1,43 @@ +import time +import socket +import subprocess +import logging + +import RPi.GPIO as GPIO +from mfrc522 import SimpleMFRC522 +reader = SimpleMFRC522() + +log = logging.getLogger('werkzeug') +log.setLevel(logging.ERROR) +#try: +# while True: +# (status, TagType) = reader.MFRC522_Request(MFRC522.PICC_REQIDL) +# if status == MFRC522.MI_OK: +# (status, uid) = reader.MFRC522_Anticoll() +# if status == MFRC522.MI_OK: +# uid_str = "-".join([str(x) for x in uid[:4]]) +# print(f"Tag erkannt! UID: {uid_str}") +# time.sleep(0.1) + +#state 0 = nicht da? +#state 1 = ist da? + + +try: + while True: + id, text = reader.read() + idz = str(id) + import subprocess + subprocess.run([ + "mosquitto_pub", + "-h", "192.168.213.12", # -h -> Host; IP des Brokers + "-t", "RFID", # -t -> Topic; "Gruppe" + "-m", idz # -m -> Message; sendende Nachricht + ]) + + print("RFID",id) + time.sleep(10) + +finally: + GPIO.cleanup() + print("\nProgramm beendet.")