143 lines
5.1 KiB
Python
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()
|