added data logging functionality

This commit is contained in:
Martin Zietz
2021-02-14 15:14:48 +01:00
parent 95295e1f61
commit db81aff2db
5 changed files with 200 additions and 12 deletions
+87 -4
View File
@@ -9,11 +9,13 @@ import numpy as np
import os
from os.path import exists
import threading
from datetime import datetime
import globals as g
import cage_func as func
import csv_threading as csv
import config_handling as config
import csv_logging as log
NORM_FONT = ()
HEADER_FONT = ("Arial", 13, "bold")
@@ -40,7 +42,7 @@ class HelmholtzGUI(Tk):
self.pages = {} # dictionary for storing all pages
for P in [ManualMode, Configuration, ExecuteCSVMode]:
for P in [ManualMode, Configuration, ExecuteCSVMode, ConfigureLogging]:
page = P(mainArea, self)
self.pages[P] = page
page.grid(row=0, column=0, sticky="nsew")
@@ -73,6 +75,8 @@ class TopMenu:
menu.add_cascade(label="Mode", menu=ModeSelector)
ModeSelector.add_command(label="Static Manual Input", command=lambda: self.manual_mode(window))
ModeSelector.add_command(label="Execute CSV Sequence", command=lambda: self.execute_csv_mode(window))
ModeSelector.add_separator()
ModeSelector.add_command(label="Configure Data Logging", command=lambda: self.logging(window))
ModeSelector.add_command(label="Settings...", command=lambda: self.configuration(window))
@staticmethod
@@ -87,6 +91,10 @@ class TopMenu:
def execute_csv_mode(window):
window.show_frame(ExecuteCSVMode)
@staticmethod
def logging(window):
window.show_frame(ConfigureLogging)
class ManualMode(Frame):
@@ -598,7 +606,7 @@ class ExecuteCSVMode(Frame):
pass
def load_csv(self): # load in csv file to be executed
directory = os.path.abspath(os.getcwd()) # get directory of current config file
directory = os.path.abspath(os.getcwd()) # get project directory
# open file selection dialogue and save path of selected file
filename = filedialog.askopenfilename(initialdir=directory, title="Select CSV File",
filetypes=(("Comma Separated Values", "*.csv*"), ("All Files", "*.*")))
@@ -662,11 +670,86 @@ class ConfigureLogging(Frame):
self.parent = parent
self.controller = controller # object on which mainloop() is running, usually main window
self.log_file = None # string containing path of log file
self.regular_logging = False # True if data should be logged regularly
self.grid_rowconfigure(ALL, weight=1)
self.grid_columnconfigure(ALL, weight=1)
row_counter = 0
# Create and place buttons
# Setup frame to house buttons:
self.top_buttons_frame = Frame(self)
self.top_buttons_frame.grid_rowconfigure(ALL, weight=1)
self.top_buttons_frame.grid_columnconfigure(ALL, weight=1)
self.top_buttons_frame.grid(row=row_counter, column=0, sticky=W, padx=20)
self.stop_logging_button = Button(self.top_buttons_frame, text="Stop Logging", command=self.stop_logging,
pady=5, padx=5, font=SMALL_BUTTON_FONT)
self.stop_logging_button.grid(row=0, column=0, padx=5)
self.start_logging_button = Button(self.top_buttons_frame, text="Start Logging", command=self.start_logging,
pady=5, padx=5, font=SMALL_BUTTON_FONT)
self.start_logging_button.grid(row=0, column=0, padx=5)
self.write_to_file_button = Button(self.top_buttons_frame, text="Write data to file", font=SMALL_BUTTON_FONT,
command=self.write_to_file, pady=5, padx=5, state="disabled")
self.write_to_file_button.grid(row=0, column=1, padx=5)
row_counter += 1
# Create checkboxes to select what data to log
self.checkbox_frame = Frame(self)
self.checkbox_frame.grid_rowconfigure(ALL, weight=1)
self.checkbox_frame.grid_columnconfigure(ALL, weight=1)
self.checkbox_frame.grid(row=row_counter, column=0, sticky=W, padx=10, pady=10)
self.checkbox_vars = {} # dictionary containing the bool variables changed by the checkboxes
self.active_keys = [] # list with all the keys relating to the currently ticked checkboxes
# generate and place all the checkboxes:
row = 0
for key in log.axis_data_dict.keys():
self.checkbox_vars[key] = BooleanVar(value=True) # create variable for checkbox and put it in dictionary
checkbox = Checkbutton(self.checkbox_frame, text=key, # generate checkbox
variable=self.checkbox_vars[key], onvalue=True, offvalue=False)
checkbox.grid(row=row, column=0, sticky=W) # place checkbox in UI
row += 1
def page_switch(self): # function that is called when switching to this window
# every class in the UI needs this, even if it doesn't do anything
pass
def start_logging(self):
ui_print("Started data logging.")
self.update_choices() # update list with ticked checkboxes
self.regular_logging = True
log.zero_time = datetime.now()
self.periodic_log(1000) # ToDo: get interval from entry field
self.write_to_file_button["state"] = "disabled"
self.stop_logging_button.tkraise() # switch button to stop
def stop_logging(self):
ui_print("Stopped data logging. Remember to save data to file!")
self.regular_logging = False
self.write_to_file_button["state"] = "normal"
self.start_logging_button.tkraise() # switch button to start
@staticmethod
def write_to_file():
filepath = log.select_file() # select a file to write to
log.write_to_file(log.log_data, filepath) # write logged data to the file
def update_choices(self):
self.active_keys = []
for key in self.checkbox_vars.keys():
if self.checkbox_vars[key].get(): # box is ticked
self.active_keys.append(key)
def periodic_log(self, interval): # logs data in regular intervals (ms)
if self.regular_logging: # logging in intervals is active
log.log_datapoint(self.active_keys) # add datapoint with active keys to log data frame
self.controller.after(interval, lambda: self.periodic_log(interval)) # call function again after interval
class StatusDisplay(Frame):
@@ -716,7 +799,7 @@ class StatusDisplay(Frame):
self.update_labels()
def continuous_label_update(self, controller, interval): # update display values in regular intervals
def continuous_label_update(self, controller, interval): # update display values in regular intervals (ms)
self.update_labels()
if g.app is not None: # app ist still running
# ToDo (optional): prevent call after program close
@@ -766,7 +849,7 @@ class OutputConsole(Frame): # console to print stuff in, similar to standard py
def ui_print(*content): # prints text to built in console
output = ""
for text in content:
output = " ".join((output, str(text))) # append content
output = " ".join((output, str(text))) # merge all contents into one string
if not g.exitFlag:
output = "".join(("\n", output)) # begin new line each time
g.app.OutputConsole.console.insert(END, output) # print to console