import time import datetime import pyads import matplotlib.pyplot as plt import matplotlib.dates as mdates # ========================================== # KONFIGURATION # ========================================== AMS_NET_ID = "5.17.17.136.1.1" PLC_PORT = 851 # Standard SPS-Port in TwinCAT 3 TEMP_SYMBOL = 'MAIN.temperature' # Pfad zur Variable in der SPS LOG_FILENAME = "temperature_log.csv" READ_INTERVAL = 1.0 # Ausleseintervall in Sekunden # ========================================== # SETUP LOGDATEI & PLOT # ========================================== try: with open(LOG_FILENAME, 'a', encoding='utf-8') as f: if f.tell() == 0: f.write("Zeitstempel;Temperatur_C\n") except IOError as e: print(f"Fehler beim Erstellen der Log-Datei: {e}") # Matplotlib Live-Plot vorbereiten plt.ion() fig, ax = plt.subplots(figsize=(10, 5)) timestamps = [] temp_values = [] line, = ax.plot([], [], 'r-o', linewidth=2, label="Temperatur (°C)") ax.set_title("TwinCAT SPS Live-Temperaturüberwachung") ax.set_xlabel("Uhrzeit") ax.set_ylabel("Temperatur [°C]") ax.grid(True) ax.legend(loc="upper left") # Datumsformatierung für die X-Achse auf HH:MM:SS festlegen ax.xaxis.set_major_formatter(mdates.DateFormatter('%H:%M:%S')) fig.autofmt_xdate() # ========================================== # HAUPTPROGRAMM # ========================================== def main(): plc = pyads.Connection(AMS_NET_ID, PLC_PORT) try: plc.open() print(f"Verbindung zu TwinCAT PLC ({AMS_NET_ID}:{PLC_PORT}) erfolgreich hergestellt.") print(f"Lese Symbol '{TEMP_SYMBOL}' (PLCTYPE_INT) aus...") print("Schließe das Plot-Fenster oder drücke Strg+C zum Beenden.\n") print(f"{'Zeitstempel':<20} | {'Temperatur (°C)':<15}") print("-" * 38) while plt.fignum_exists(fig.number): loop_start = time.time() now = datetime.datetime.now() time_str = now.strftime("%Y-%m-%d %H:%M:%S") try: # 1. Wert als INT aus der SPS lesen (2-Byte Datentyp) raw_temp = plc.read_by_name(TEMP_SYMBOL, pyads.PLCTYPE_INT) # Falls deine SPS Zehntel-Grad ausgibt (z.B. 215 = 21.5 °C), hier durch 10.0 teilen: temp_val = float(raw_temp) # 2. In Log-Datei schreiben with open(LOG_FILENAME, 'a', encoding='utf-8') as f: f.write(f"{time_str};{temp_val:.2f}\n") # 3. Konsolenausgabe print(f"{time_str:<20} | {temp_val:<15.2f}") # 4. datetime-Objekt direkt für den Plot nutzen timestamps.append(now) temp_values.append(temp_val) # Maximal 60 Messpunkte anzeigen (rollendes Fenster) if len(timestamps) > 60: timestamps.pop(0) temp_values.pop(0) # Plot aktualisieren line.set_xdata(timestamps) line.set_ydata(temp_values) ax.relim() ax.autoscale_view() fig.canvas.draw() fig.canvas.flush_events() except pyads.ADSError as err: print(f"[{time_str}] ADS Fehler beim Lesen: {err}") elapsed = time.time() - loop_start sleep_time = max(0.0, READ_INTERVAL - elapsed) time.sleep(sleep_time) except KeyboardInterrupt: print("\nMessung durch Benutzer abgebrochen.") except Exception as e: print(f"\nUnerwarteter Fehler: {e}") finally: plc.close() plt.ioff() print(f"ADS-Verbindung geschlossen. Daten gespeichert in '{LOG_FILENAME}'.") if __name__ == '__main__': main()