2025-04-03 13:11:20 +02:00

143 lines
5.1 KiB
Python

import tkinter as tk
import serial
import threading
import csv
import serial.tools.list_ports
from datetime import datetime
import pytz
import os
# Set timezone for Amsterdam
AMSTERDAM_TZ = pytz.timezone("Europe/Amsterdam")
# Global variables
recording = False
csv_file = None
csv_writer = None
ser = None
def get_amsterdam_time():
"""Returns the current time in Amsterdam with microseconds."""
return datetime.now(AMSTERDAM_TZ).strftime("%Y-%m-%d %H:%M:%S.%f")
def get_timestamped_filename():
"""Generates a timestamped filename in Amsterdam time."""
timestamp = datetime.now(AMSTERDAM_TZ).strftime("%Y-%m-%d_%H-%M-%S")
return f"sensor_data_{timestamp}.csv"
def list_serial_ports():
"""Returns a list of available serial ports."""
return [port.device for port in serial.tools.list_ports.comports()]
def connect_serial():
"""Connects to the selected serial port."""
global ser
selected_port = port_var.get()
if selected_port:
try:
ser = serial.Serial(selected_port, 115200, timeout=1)
lbl_status.config(text=f"Connected to {selected_port}", fg="green")
threading.Thread(target=read_serial, daemon=True).start()
except Exception as e:
lbl_status.config(text=f"Error: {e}", fg="red")
def read_serial():
"""Reads serial data and updates the GUI while optionally saving to CSV."""
global csv_writer, csv_file
while ser and ser.is_open:
try:
line = ser.readline().decode('utf-8').strip()
values = line.split(",")
if len(values) == 4:
timestamp = get_amsterdam_time()
# Format numbers to keep width fixed
formatted_values = [f"{int(v):>6}" for v in values]
# Update GUI labels
lbl_value1.config(text=formatted_values[0])
lbl_value2.config(text=formatted_values[1])
lbl_value3.config(text=formatted_values[2])
lbl_value4.config(text=formatted_values[3])
# Save to CSV if recording
if recording and csv_writer:
csv_writer.writerow([timestamp] + values)
csv_file.flush() # Ensure data is written immediately
except:
pass
def toggle_recording():
"""Starts or stops data recording with a timestamped filename."""
global recording, csv_file, csv_writer
if not recording:
btn_record.config(text="Stop Recording", fg="red")
# Create a timestamped filename
filename = get_timestamped_filename()
csv_file = open(filename, "w", newline="")
csv_writer = csv.writer(csv_file)
csv_writer.writerow(["Timestamp", "Value 1", "Value 2", "Value 3", "Value 4"])
lbl_status.config(text=f"Recording to {filename}", fg="blue")
recording = True
else:
btn_record.config(text="Start Recording", fg="black")
recording = False
if csv_file:
csv_file.close()
csv_file = None
lbl_status.config(text="Recording Stopped", fg="black")
# Create main GUI window
root = tk.Tk()
root.title("BLE Sensor Data Logger")
root.geometry("400x300") # Set window size
root.resizable(False, False)
# Create a frame for better layout
frame = tk.Frame(root, padx=20, pady=10)
frame.pack(pady=5)
# Dropdown for selecting serial port
tk.Label(frame, text="Select Serial Port:", font=("Arial", 12)).grid(row=0, column=0, sticky="w", padx=5)
port_var = tk.StringVar(root)
ports = list_serial_ports()
port_dropdown = tk.OptionMenu(frame, port_var, *ports)
port_dropdown.grid(row=0, column=1, padx=5)
port_var.set(ports[0] if ports else "No ports found")
# Connect button
btn_connect = tk.Button(frame, text="Connect", font=("Arial", 12), command=connect_serial)
btn_connect.grid(row=0, column=2, padx=5)
# Connection status label
lbl_status = tk.Label(root, text="Not connected", font=("Arial", 10), fg="red")
lbl_status.pack(pady=5)
# Sensor values section
monospace_font = ("Courier", 14, "bold")
tk.Label(frame, text="Value 1:", font=("Arial", 12)).grid(row=1, column=0, sticky="w", padx=10)
lbl_value1 = tk.Label(frame, text="------", font=monospace_font, fg="blue", width=6, anchor="e")
lbl_value1.grid(row=1, column=1, sticky="w")
tk.Label(frame, text="Value 2:", font=("Arial", 12)).grid(row=2, column=0, sticky="w", padx=10)
lbl_value2 = tk.Label(frame, text="------", font=monospace_font, fg="blue", width=6, anchor="e")
lbl_value2.grid(row=2, column=1, sticky="w")
tk.Label(frame, text="Value 3:", font=("Arial", 12)).grid(row=3, column=0, sticky="w", padx=10)
lbl_value3 = tk.Label(frame, text="------", font=monospace_font, fg="blue", width=6, anchor="e")
lbl_value3.grid(row=3, column=1, sticky="w")
tk.Label(frame, text="Value 4:", font=("Arial", 12)).grid(row=4, column=0, sticky="w", padx=10)
lbl_value4 = tk.Label(frame, text="------", font=monospace_font, fg="blue", width=6, anchor="e")
lbl_value4.grid(row=4, column=1, sticky="w")
# Start/Stop Recording Button
btn_record = tk.Button(root, text="Start Recording", font=("Arial", 12), command=toggle_recording)
btn_record.pack(pady=10)
# Run the GUI
root.mainloop()