diff --git a/Actor/app.py b/Actor/app.py index 22773b3..fd79525 100644 --- a/Actor/app.py +++ b/Actor/app.py @@ -3,6 +3,7 @@ import json import threading from flask import Flask, render_template import os +import datetime # Import für Datums- und Zeitstempel # ========================================================== @@ -10,15 +11,13 @@ import os # ========================================================== CHIP_NAMES_FILE = "data.json" -STATE_SAVE_FILE = "current_status.json" # Die Datei, in die der Zustand geschrieben wird +STATE_SAVE_FILE = "current_status.json" 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__) @@ -42,37 +41,49 @@ def load_config(): 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.") - + # 2. Chip-Status initialisieren (Hier wird der Time Active Wert aus der JSON gelesen) 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 - } + time_active = chip_data.get('time_active') - print(f"✅ Starte mit {len(RFID_STATUS)} Chips, geladen aus {CHIP_NAMES_FILE}.") + if time_active: + # Wir speichern den Wert aus der JSON, um ihn beim Start zu laden + RFID_STATUS[chip_id] = { + "Name": chip_name, + "ID": chip_id, + "Status": initial_status, + "Time_Active": time_active + } + else: + # Fallback: Wenn kein Zeitstempel gefunden wird, setze ihn auf jetzt. + RFID_STATUS[chip_id] = { + "Name": chip_name, + "ID": chip_id, + "Status": initial_status, + "Time_Active": datetime.datetime.now().isoformat() + } + + print(f"✅ Starte mit {len(RFID_STATUS)} Chips.") return True except FileNotFoundError: + # ... (Error Handling bleibt gleich) ... 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: + # ... (Error Handling bleibt gleich) ... print(f"❌ KRITISCHER FEHLER: Die Datei {CHIP_NAMES_FILE} ist kein gültiges JSON!") return False except ValueError as e: + # ... (Error Handling bleibt gleich) ... print(f"❌ KONFIGURIERUNGSFEHLER: {e}") return False # ========================================================== -# 💾 Funktion zur Zustandsspeicherung (Korrigierter Block) +# 💾 Funktion zur Zustandsspeicherung (Speichert Status UND Zeit) # ========================================================== def save_state(): @@ -83,24 +94,23 @@ def save_state(): { "name": data['Name'], "id": data['ID'], - "status": str(data['Status']) + "status": str(data['Status']), + "time_active": data['Time_Active'] # Speichern des Zeitstempels } 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) +# ⚙️ Angepasste Funktion (Status-Update, Logging & Time Stamping) # ========================================================== def update_status(chip_id): @@ -114,22 +124,27 @@ def update_status(chip_id): 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.") + # Überprüfung, ob sich der Status tatsächlich geändert hat + if new_status != old_status: + logging_message = "" + 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.") + + # Wichtig: Status und Zeitstempel aktualisieren + RFID_STATUS[chip_id]['Status'] = new_status + RFID_STATUS[chip_id]['Time_Active'] = datetime.datetime.now().isoformat() + - # Speichern des Zustandes nach jeder Änderung save_state() # ========================================================== -# MQTT LOGIK (Verwendet die globalen Variablen) +# MQTT LOGIK (Bleibt unverändert) # ========================================================== def on_connect(client, userdata, flags, rc): @@ -155,14 +170,14 @@ def on_message(client, userdata, msg): def run_mqtt_client(): - """Startet den MQTT-Client im Hintergrundthread mit den konfigurierten Daten.""" + """Startet den MQTT-Client im Hintergrundthread.""" + # ... (Code bleibt gleich) ... 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: @@ -198,5 +213,4 @@ if __name__ == '__main__': 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 index 2a8f40e..ab99608 100644 --- a/Actor/current_status.json +++ b/Actor/current_status.json @@ -3,22 +3,26 @@ { "name": "1", "id": "729558387180", - "status": "0" + "status": "0", + "time_active": "2026-06-10T13:07:21.722653" }, { "name": "2", "id": "987572218311", - "status": "0" + "status": "0", + "time_active": "2026-06-10T13:07:21.722681" }, { "name": "3", "id": "842310768930", - "status": "0" + "status": "0", + "time_active": "2026-06-10T13:07:21.722690" }, { "name": "4", "id": "773910059391", - "status": "0" + "status": "0", + "time_active": "2026-06-10T13:07:21.722698" } ] } \ No newline at end of file diff --git a/Actor/data.json b/Actor/data.json index ba9f273..2399401 100644 --- a/Actor/data.json +++ b/Actor/data.json @@ -8,22 +8,26 @@ { "name": "1", "id": "729558387180", - "status": "0" + "status": "0", + "time_active": "" }, { "name": "2", "id": "987572218311", - "status": "0" + "status": "0", + "time_active": "" }, { "name": "3", "id": "842310768930", - "status": "0" + "status": "0", + "time_active": "" }, { "name": "4", "id": "773910059391", - "status": "0" + "status": "0", + "time_active": "" } ] } \ No newline at end of file diff --git a/Actor/templates/index.html b/Actor/templates/index.html index 032af38..57f8185 100644 --- a/Actor/templates/index.html +++ b/Actor/templates/index.html @@ -4,17 +4,18 @@ RFID Status Tracker +

RFID Chip Status Übersicht

-

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

+

Daten werden über MQTT von Topic "{{ mqtt_topic }}" empfangen. + Status und Dauer basieren auf dem letzten Scan.

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

Seit Statuswechsel:

+ + Lade... +
+ +

Status:

- {% set status_class = 'status-active' if data.Status == 1 else 'status-inactive' %} {{ data.Status }}
-
+
{% endfor %} -
+ + +