diff --git a/CoreLibrary/ExampleCombined.py b/CoreLibrary/ExampleCombined.py index 8cb6b91..4d29179 100644 --- a/CoreLibrary/ExampleCombined.py +++ b/CoreLibrary/ExampleCombined.py @@ -8,7 +8,7 @@ from time import sleep from Driver import Driver from Sensor import Sensor -LOGGER = logging.getLogger() +LOGGER = logging.getLogger("my_logger") class ExampleDriverWorker(Thread): @@ -60,11 +60,11 @@ class ExampleDriver(Driver, Sensor): def start_measuring(self): self.measureThread.produceData.set() - logging.info("I started meas") + LOGGER.info("I started meas") def stop_measuring(self): self.measureThread.produceData.clear() - logging.info("I stopped meas") + LOGGER.info("I stopped meas") def exit(self): self.stop_measuring() diff --git a/CoreLibrary/ExampleDriver.py b/CoreLibrary/ExampleDriver.py index 3d8119c..b149b2b 100644 --- a/CoreLibrary/ExampleDriver.py +++ b/CoreLibrary/ExampleDriver.py @@ -5,7 +5,7 @@ from queue import Queue from CoreLibrary.Driver import Driver import logging -LOGGER = logging.getLogger() +LOGGER = logging.getLogger("my_logger") class ExampleDriverWorker(Thread): diff --git a/CoreLibrary/ExampleSensor.py b/CoreLibrary/ExampleSensor.py index 03d364a..702cabe 100644 --- a/CoreLibrary/ExampleSensor.py +++ b/CoreLibrary/ExampleSensor.py @@ -6,7 +6,7 @@ from random import random from CoreLibrary.Sensor import Sensor import logging -LOGGER = logging.getLogger() +LOGGER = logging.getLogger("my_logger") class ExampleSensorWorker(Thread): @@ -44,11 +44,11 @@ class ExampleSensor(Sensor): def start_measuring(self): self.measureThread.produceData.set() - logging.info("I started meas") + LOGGER.info("I started meas") def stop_measuring(self): self.measureThread.produceData.clear() - logging.info("I stopped meas") + LOGGER.info("I stopped meas") def exit(self): self.stop_measuring() diff --git a/CoreLibrary/Measurement.py b/CoreLibrary/Measurement.py index 487732e..fc31c94 100644 --- a/CoreLibrary/Measurement.py +++ b/CoreLibrary/Measurement.py @@ -1,20 +1,44 @@ +import datetime +import json +import logging import os +from CoreLibrary.Driver import Driver +from CoreLibrary.Sensor import Sensor + +LOGGER = logging.getLogger("my_logger") + + class Measurement: """ Handle data and write it in a file """ - def attach(self, sensor): - pass - def __init__(self, name, path=None, comment=None, writer=None): self.name = name self.path = os.path.join(path or "./meas_values", self.name) os.makedirs(self.path) self.save_version_text(comment) + self.sensors = {} + self.drivers = {} + self.data_files = {} + self.data_files["log"] = self.create_file("log") - self.data_files = {} # sensor_name: file_handler + def create_file(self, name: str): + return open(os.path.join(self.path, name), "w") + + def attach_sensor(self, sensor: Sensor, name: str): + self.sensors[name] = sensor + + def attach_driver(self, driver: Driver, name: str): + self.drivers[name] = driver + + def attach_combined(self, comb, name: str): + self.attach_sensor(comb, name) + self.attach_driver(comb, name) + + def write_log(self, text: str): + self.data_files["log"].write(str(datetime.datetime.utcnow()) + ":\t" + text + "\n") def append_data(self, sensor_name, data): """ @@ -23,18 +47,21 @@ class Measurement: TODO: file size limit, zip? data: list of tuples: (timestamp, value) """ + if sensor_name not in self.sensors: + return + + LOGGER.info("append-data: " + sensor_name) if sensor_name not in self.data_files: - self.data_files[sensor_name] = open( - os.path.join(self.path, f"{sensor_name}_data.csv"), "w" - ) + self.data_files[sensor_name] = self.create_file(sensor_name) for timestamp, value in zip(data[0], data[1]): self.data_files[sensor_name].write( f"{timestamp.isoformat()}, {timestamp.timestamp()}, {value}\n" ) def save_version_text(self, comment): - with open(os.path.join(self.path, "version.txt"), "w") as file: - file.write("Version 0.1\n") - if comment: - file.write(comment + "\n") - file.write("More descriptions of relevant parameters\n") \ No newline at end of file + params = { + "version": "0.1", + "Start time": datetime.datetime.utcnow().isoformat(), + } + with open(os.path.join(self.path, "params.json"), "w") as file: + json.dump(params, file, indent=4) diff --git a/CoreLibrary/Param_Model.py b/CoreLibrary/Param_Model.py index 40f1691..5b03cbd 100644 --- a/CoreLibrary/Param_Model.py +++ b/CoreLibrary/Param_Model.py @@ -1,3 +1,5 @@ +import logging +from logging.handlers import RotatingFileHandler from time import sleep from threading import Thread, Event @@ -6,17 +8,34 @@ from CoreLibrary.ExampleSensor import ExampleSensor from CoreLibrary.Measurement import Measurement from CoreLibrary.Plot_Data import Plot_Data +LOGGER = logging.getLogger("my_logger") +LOGGER.setLevel(logging.DEBUG) +LOGGER.propagate = False -class ExampleDriverWorker(Thread): - """Communicates with the measuring hardware. Here we only produce random data.""" +# create formatter +formatter = logging.Formatter('%(levelname)s %(asctime)s - %(module)s: %(message)s') +# create console handler and set level to debug +ch = logging.StreamHandler() +ch.setLevel(logging.INFO) +# add formatter to ch +ch.setFormatter(formatter) +# add ch to logger +LOGGER.addHandler(ch) + +fi = RotatingFileHandler("my_logger.log", maxBytes=10**5, backupCount=5) +fi.setLevel(logging.DEBUG) +fi.setFormatter(formatter) +LOGGER.addHandler(fi) + + +class DataWorker(Thread): def __init__(self, pd): super().__init__(name="Data_Worker") self.exit_request = Event() self.pd = pd def run(self): - """Worker method of a python Thread. Called when the Thread is started.""" while not self.exit_request.is_set(): self.pd.refresh() sleep(1) @@ -28,6 +47,8 @@ class Param_Model: self.sensors = {"mess1": ExampleSensor()} self.__plot_data = [] self.__measurement = [] + self.data_worker = DataWorker(self) + self.data_worker.start() def new_measurement(self, name=None, writer=None) -> Measurement: mess = Measurement(name=name) @@ -40,7 +61,8 @@ class Param_Model: return plot_data def refresh(self): - for name, sens in self.sensors: + LOGGER.debug("refresh") + for name, sens in self.sensors.items(): data = sens.get_data for meas in self.__measurement: meas.append_data(name, data) @@ -48,12 +70,17 @@ class Param_Model: pd.append_data(name, data) def stop_measuring(self): - for sens in self.sensors.items(): + for sens in self.sensors.values(): sens.stop_measuring() - pass def start_measuring(self): - pass + for sens in self.sensors.values(): + sens.start_measuring() def exit(self): - pass + LOGGER.warning("entering exit method") + for sens in self.sensors.values(): + sens.exit() + for drv in self.drivers.values(): + drv.exit() + self.data_worker.exit_request.set() diff --git a/CoreLibrary/Plot_Data.py b/CoreLibrary/Plot_Data.py index e2eb81e..f40f775 100644 --- a/CoreLibrary/Plot_Data.py +++ b/CoreLibrary/Plot_Data.py @@ -64,7 +64,7 @@ class Plot_Data: old = self.data["time"][-1] - self.timeout if time.size > 2: drop_index = np.where(time < old)[0] - if len(drop_index) is not 0: + if len(drop_index) != 0: drop_index = drop_index[-1] self.queues[key] = ( self.queues[key][0][drop_index:], diff --git a/CoreLibrary/mess.py b/CoreLibrary/mess.py index 59b4c23..ef87f82 100644 --- a/CoreLibrary/mess.py +++ b/CoreLibrary/mess.py @@ -1,29 +1,44 @@ from time import sleep - +from shutil import rmtree from CoreLibrary.Param_Model import Param_Model from CoreLibrary.Measurement import Measurement +import matplotlib.pyplot as plt + + + +def clean(): + rmtree("meas_values") + + def main(param_model: Param_Model): sensor = param_model.sensors["mess1"] driver = param_model.drivers["treib1"] driver.set_config({"speed": 2}) status = driver.get_status() + plot_data = param_model.get_plot_data() + for speed in [1.0, 2.0, 3.0]: print(speed) driver.set_config({"speed": speed}) measurement = param_model.new_measurement(name=f"penis_{speed}", writer="CSV") - measurement.attach("mess1") + measurement.attach_sensor(sensor=sensor, name="mess1") + measurement.write_log("ich mag ramen") + param_model.start_measuring() + sleep(2) + param_model.stop_measuring() + print("main exited") + + plt.plot(plot_data.data["time"], plot_data.data["mess1"]) + plt.show() - sensor.start_measuring() - sleep(1) - sensor.stop_measuring() - print("test") - sensor.exit() - driver.exit() if __name__ == '__main__': + print("HEADLESS RUN") pd = Param_Model() - main(pd) \ No newline at end of file + clean() + main(pd) + pd.exit() \ No newline at end of file diff --git a/img/green.bmp b/GUI/img/green.bmp similarity index 100% rename from img/green.bmp rename to GUI/img/green.bmp diff --git a/img/red.bmp b/GUI/img/red.bmp similarity index 100% rename from img/red.bmp rename to GUI/img/red.bmp diff --git a/GUI/main.py b/GUI/main.py new file mode 100644 index 0000000..d213c74 --- /dev/null +++ b/GUI/main.py @@ -0,0 +1,17 @@ +import wx + +from main_view import MainFrame + +class MyApp(wx.App): + def OnInit(self): + self.frame = MainFrame() + self.SetTopWindow(self.frame) + self.frame.Show() + return True + + +# end of class MyApp + +if __name__ == "__main__": + app = MyApp(0) + app.MainLoop() \ No newline at end of file diff --git a/GUI/main_view.py b/GUI/main_view.py new file mode 100644 index 0000000..f4d19be --- /dev/null +++ b/GUI/main_view.py @@ -0,0 +1,241 @@ +#!/usr/bin/env python3 + +import importlib.machinery +import logging +from threading import Thread +import wx + +from CoreLibrary.Param_Model import Param_Model + +from plotView import PlotPanel + +LOGGER = logging.getLogger("my_logger") + + +class MainFrame(wx.Frame): + def __init__(self): + wx.Frame.__init__(self, None, wx.ID_ANY, "MESS MICH") + self.configure_window() + + self.green = wx.Bitmap("./GUI/img/green.bmp") + self.red = wx.Bitmap("./GUI/img/red.bmp") + + self.model, self.pd = self.init_api() + # MENU BAR + self.menu_bar() + + # self.status_bar() + # self.tool_bar() + + self.panel = wx.Panel(self, wx.ID_ANY) + grid_sizer_main = wx.GridBagSizer(0, 0) + + self.status = self.status_init(grid_sizer_main) + self.tabs = self.plot_init(grid_sizer_main) + + grid_group = wx.GridBagSizer(10, 0) + grid_sizer_main.Add(grid_group, (0, 2), (2, 1), wx.EXPAND, 0) + self.b_run, self.b_start, self.b_stop = self.init_measurement_buttons(grid_group) + self.plot_buttons(grid_sizer_main) + + self.panel.SetSizer(grid_sizer_main) + + self.Layout() + # end wxGlade + self.timer = wx.Timer(self, wx.ID_ANY) + self.Bind(wx.EVT_CLOSE, self.on_close_window) + self.Bind(wx.EVT_TIMER, self.update, self.timer) + self.timer.Start(100, False) + self.runner_thread = None + + def configure_window(self): + self.SetSize((1920, 1080)) + self.SetTitle("My Fancy Measurements :D") + + def init_api(self): + model = Param_Model() + pd = model.get_plot_data() + + return model, pd + + def menu_bar(self): + frame_menubar = wx.MenuBar() + tmp_menu = wx.Menu() + item = tmp_menu.Append(wx.ID_ANY, "Quit", "") + self.Bind(wx.EVT_MENU, self.on_close_window, item) + frame_menubar.Append(tmp_menu, "File") + self.SetMenuBar(frame_menubar) + + def status_bar(self): + frame_statusbar = self.CreateStatusBar(1) + frame_statusbar.SetStatusWidths([-1]) + # statusbar fields + frame_statusbar_fields = ["frame_statusbar"] + for count, field in enumerate(frame_statusbar_fields): + frame_statusbar.SetStatusText(field, count) + + def tool_bar(self): + frame_toolbar = wx.ToolBar(self, -1) + self.SetToolBar(frame_toolbar) + frame_toolbar.Realize() + + def status_init(self, grid_sizer_main): + sizer_status = wx.GridBagSizer(vgap=5, hgap=5) + grid_sizer_main.Add(sizer_status, (0, 0), (2, 1), wx.EXPAND, 0) + + # STATUS + data = {"over1": False, "over2": True, "motor": 123} + status_dict = {} + for row, (key, val) in enumerate(data.items()): + label = wx.StaticText(self.panel, wx.ID_ANY, key) + sizer_status.Add(label, (row, 0)) + if isinstance(val, bool): + if val: + icon = wx.StaticBitmap(self.panel, bitmap=self.green) + status_dict[key] = icon + sizer_status.Add(icon, (row, 1)) + else: + icon = wx.StaticBitmap(self.panel, bitmap=self.red) + status_dict[key] = icon + sizer_status.Add(icon, (row, 1)) + else: + label = wx.StaticText(self.panel, wx.ID_ANY, str(val)) + status_dict[key] = label + sizer_status.Add(label, (row, 1)) + + return status_dict + + def plot_init(self, grid_sizer_main): + tabs = wx.Notebook(self.panel, wx.ID_ANY) + grid_sizer_main.Add(tabs, (0, 1), (1, 1), wx.EXPAND, 0) + + plot = lambda ax, dat: ax.plot(dat["time"], dat["mess1"]) + update = lambda im, dat: im.set_data(dat["time"], dat["mess1"]) + plot_1 = PlotPanel(tabs, self.pd, plot, update) + tabs.AddPage(plot_1, "Temp") + + plot = lambda ax, dat: ax.plot(dat["mess1"], dat["mess1"]) + update = lambda im, dat: im.set_data(dat["mess1"], dat["mess1"]) + plot_2 = PlotPanel(tabs, self.pd, plot, update) + tabs.AddPage(plot_2, "Multi") + return tabs + + def init_measurement_buttons(self, grid_upper): + grid_sizer_measurement = wx.GridBagSizer(0, 0) + grid_upper.Add(grid_sizer_measurement, (0, 0), (1, 1), wx.EXPAND, 0) + + b_start = wx.Button(self.panel, wx.ID_ANY, "Start") + grid_sizer_measurement.Add(b_start, (0, 0), (1, 1), 0, 0) + + b_stop = wx.Button(self.panel, wx.ID_ANY, "Stop") + grid_sizer_measurement.Add(b_stop, (1, 0), (1, 1), 0, 0) + + b_run = wx.Button(self.panel, wx.ID_ANY, "Run") + grid_sizer_measurement.Add(b_run, (2, 0), (1, 1), 0, 0) + + self.Bind(wx.EVT_BUTTON, self.on_b_start, b_start) + self.Bind(wx.EVT_BUTTON, self.on_b_stop, b_stop) + self.Bind(wx.EVT_BUTTON, self.on_b_run, b_run) + + return b_run, b_start, b_stop + + def plot_buttons(self, grid_sizer_main): + grid_sizer_ctrl_plot = wx.GridBagSizer(0, 0) + grid_sizer_main.Add(grid_sizer_ctrl_plot, (1, 1), (1, 1), wx.EXPAND, 0) + + b_clear = wx.Button(self.panel, wx.ID_ANY, "Clear") + grid_sizer_ctrl_plot.Add(b_clear, (0, 0), (1, 1), 0, 0) + + b_save = wx.Button(self.panel, wx.ID_ANY, "Save") + grid_sizer_ctrl_plot.Add(b_save, (0, 1), (1, 1), 0, 0) + + self.Bind(wx.EVT_BUTTON, self.on_b_clear, b_clear) + self.Bind(wx.EVT_BUTTON, self.on_b_save, b_save) + + def on_close_window(self, _): + self.model.exit() + LOGGER.info("Closing") + wx.Exit() + + def update(self, _): + # Repaint gui + self.tabs.Refresh() + self.model.refresh() + # Unlock if script is finished + if self.runner_thread is not None: + if not self.runner_thread.is_alive(): + self.unlock() + self.runner_thread = None + # update Stuff + data = {"over1": True, "over2": True, "motor": 12} + for key, val in data.items(): + if type(val) is bool: + if val: + self.status[key].SetBitmap(self.green) + else: + self.status[key].SetBitmap(self.red) + else: + self.status[key].SetLabel(str(val)) + + def lock(self): + self.b_run.Disable() + self.b_start.Disable() + + def unlock(self): + self.b_run.Enable() + self.b_start.Enable() + + def on_b_start(self, event): # wxGlade: MyFrame. + LOGGER.info("Event handler 'on_b_start'") + self.model.start_measuring() + event.Skip() + + def on_b_save(self, event): # wxGlade: MyFrame. + LOGGER.info("Event handler 'on_b_save'") + with wx.FileDialog( + self, + "Save csv file", + wildcard="CSV files (*.csv)|*.csv", + style=wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT, + ) as fileDialog: + + if fileDialog.ShowModal() == wx.ID_CANCEL: + return # the user changed their mind + + # save the current contents in the file + pathname = fileDialog.GetPath() + self.model.save_measuring(path=pathname) + event.Skip() + + def on_b_run(self, event): # wxGlade: MyFrame. + LOGGER.info("Event handler 'on_b_run'") + with wx.FileDialog( + self, + "Open PY file", + wildcard="PY files (*.py)|*.py", + style=wx.FD_OPEN | wx.FD_FILE_MUST_EXIST, + ) as fileDialog: + + if fileDialog.ShowModal() == wx.ID_CANCEL: + return # the user changed their mind + + # Proceed loading the file chosen by the user + pathname = fileDialog.GetPath() + script = importlib.machinery.SourceFileLoader("ghf", pathname).load_module() + self.runner_thread = Thread(target=script.main, args=(self.model,)) + self.lock() + self.runner_thread.start() + event.Skip() + + def on_b_stop(self, event): # wxGlade: MyFrame. + self.model.stop_measuring() + LOGGER.info("Event handler 'on_b_stop'") + event.Skip() + + def on_b_clear(self, event): # wxGlade: MyFrame. + self.model.clear() + LOGGER.info("Event handler 'on_b_clear'") + event.Skip() + + +# end of class MyFrame diff --git a/plotView.py b/GUI/plotView.py similarity index 100% rename from plotView.py rename to GUI/plotView.py diff --git a/GUI/status_bar.py b/GUI/status_bar.py new file mode 100644 index 0000000..3c68b7f --- /dev/null +++ b/GUI/status_bar.py @@ -0,0 +1,42 @@ +import wx + + +class StatusPanel(wx.Panel): + def __init__(self, parent, pd): + super().__init__(parent, -1) + #TODO get proper data + data = {"over1":False,"over2":True,"motor":123} + + sizer_status = wx.GridBagSizer(vgap=5, hgap=5) + self.status={} + self.green = wx.Bitmap("./GUI/img/green.bmp") + self.red = wx.Bitmap("./GUI/img/red.bmp") + row = 0 + for key, val in data.items(): + label = wx.StaticText(self, wx.ID_ANY, key) + sizer_status.Add(label, (row,0)) + if type(val) is bool: + if val: + icon = wx.StaticBitmap(self,bitmap=self.green) + self.status[key] = icon + sizer_status.Add(icon, (row,1)) + else: + icon = wx.StaticBitmap(self,bitmap=self.red) + self.status[key] = icon + sizer_status.Add(icon, (row,1)) + else: + label = wx.StaticText(self, wx.ID_ANY, str(val)) + self.status[key] = label + sizer_status.Add(label, (row,1)) + row +=1 + + def update(self): + data = {"over1":True,"over2":True,"motor":12} + for key,val in data.items(): + if type(val) is bool: + if val: + self.status[key].SetBitmap(self.green) + else: + self.status[key].SetBitmap(self.red) + else: + self.status[key].SetLabel(str(val)) diff --git a/view.py b/view.py deleted file mode 100644 index fcf051d..0000000 --- a/view.py +++ /dev/null @@ -1,270 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: UTF-8 -*- -# -# generated by wxGlade 1.0.2 on Sun Jul 4 21:23:20 2021 -# - -import importlib.machinery -import logging -from threading import Thread -import wx - -# begin wxGlade: dependencies -# end wxGlade - -# begin wxGlade: extracode -# end wxGlade -import matplotlib.cm as cm -import matplotlib.cbook as cbook -from matplotlib.backends.backend_wxagg import ( - FigureCanvasWxAgg as FigureCanvas, - NavigationToolbar2WxAgg as NavigationToolbar, -) -from matplotlib.figure import Figure - -from CoreLibrary.Param_Model import Param_Model -#from plotView import PlotPanel -from plotView import PlotPanel - -LOGGER = logging.getLogger("myLogger") - -# begin wxGlade: dependencies -# end wxGlade - -# begin wxGlade: extracode -# end wxGlade - - -class MyFrame(wx.Frame): - def __init__(self, *args, **kwds): - - self.model = Param_Model() - self.pd = self.model.get_plot_data() - - # begin wxGlade: MyFrame.__init__ - kwds["style"] = kwds.get("style", 0) | wx.DEFAULT_FRAME_STYLE - wx.Frame.__init__(self, *args, **kwds) - self.SetSize((1920, 1080)) - self.SetTitle("My Fancy Measurements :D") - - # Menu Bar - self.frame_menubar = wx.MenuBar() - tmp_menu = wx.Menu() - item = tmp_menu.Append(wx.ID_ANY, "Quit", "") - self.Bind(wx.EVT_MENU, self.on_close_window, item) - self.frame_menubar.Append(tmp_menu, "File") - self.SetMenuBar(self.frame_menubar) - # Menu Bar end - - self.frame_statusbar = self.CreateStatusBar(1) - self.frame_statusbar.SetStatusWidths([-1]) - # statusbar fields - frame_statusbar_fields = ["frame_statusbar"] - for i in range(len(frame_statusbar_fields)): - self.frame_statusbar.SetStatusText(frame_statusbar_fields[i], i) - - # Tool Bar - self.frame_toolbar = wx.ToolBar(self, -1) - self.SetToolBar(self.frame_toolbar) - self.frame_toolbar.Realize() - # Tool Bar end - - self.panel_1 = wx.Panel(self, wx.ID_ANY) - - grid_sizer_main = wx.GridBagSizer(0, 0) - - sizer_status = wx.GridBagSizer(vgap=5, hgap=5) - grid_sizer_main.Add(sizer_status, (0, 0), (2, 1), wx.EXPAND, 0) - - # TODO test - data = {"over1":False,"over2":True,"motor":123} - self.status={} - self.green = wx.Bitmap("./img/green.bmp") - self.red = wx.Bitmap("./img/red.bmp") - row = 0 - for key, val in data.items(): - label = wx.StaticText(self.panel_1, wx.ID_ANY, key) - sizer_status.Add(label, (row,0)) - if type(val) is bool: - if val: - icon = wx.StaticBitmap(self.panel_1,bitmap=self.green) - self.status[key] = icon - sizer_status.Add(icon, (row,1)) - else: - icon = wx.StaticBitmap(self.panel_1,bitmap=self.red) - self.status[key] = icon - sizer_status.Add(icon, (row,1)) - else: - label = wx.StaticText(self.panel_1, wx.ID_ANY, str(val)) - self.status[key] = label - sizer_status.Add(label, (row,1)) - row +=1 - - self.tabs = wx.Notebook(self.panel_1, wx.ID_ANY) - grid_sizer_main.Add(self.tabs, (0, 1), (1, 1), wx.EXPAND, 0) - - plot = lambda ax, dat: ax.plot(dat["time"], dat["mess1"]) - update = lambda im, dat: im.set_data(dat["time"], dat["mess1"]) - self.plot_1 = PlotPanel(self.tabs, self.pd, plot, update) - self.tabs.AddPage(self.plot_1, "Temp") - - plot = lambda ax, dat: ax.plot(dat["time"], dat["mess1"]) - update = lambda im, dat: im.set_data(dat["time"], dat["mess1"]) - self.plot_2 = PlotPanel(self.tabs, self.pd, plot, update) - self.tabs.AddPage(self.plot_2, "Multi") - - - - grid_sizer_3 = wx.GridBagSizer(10, 0) - grid_sizer_main.Add(grid_sizer_3, (0, 2), (2, 1), wx.EXPAND, 0) - - grid_sizer_measurement = wx.GridBagSizer(0, 0) - grid_sizer_3.Add(grid_sizer_measurement, (0, 0), (1, 1), wx.EXPAND, 0) - - self.b_start = wx.Button(self.panel_1, wx.ID_ANY, "Start") - grid_sizer_measurement.Add(self.b_start, (0, 0), (1, 1), 0, 0) - - self.b_stop = wx.Button(self.panel_1, wx.ID_ANY, "Stop") - grid_sizer_measurement.Add(self.b_stop, (1, 0), (1, 1), 0, 0) - - self.b_run = wx.Button(self.panel_1, wx.ID_ANY, "Run") - grid_sizer_measurement.Add(self.b_run, (2, 0), (1, 1), 0, 0) - - grid_sizer_5 = wx.GridBagSizer(0, 0) - grid_sizer_3.Add(grid_sizer_5, (1, 0), (1, 1), wx.EXPAND, 0) - - self.button_7 = wx.Button(self.panel_1, wx.ID_ANY, "button_7") - grid_sizer_5.Add(self.button_7, (0, 0), (1, 1), 0, 0) - - self.button_8 = wx.Button(self.panel_1, wx.ID_ANY, "button_8") - grid_sizer_5.Add(self.button_8, (1, 0), (1, 1), 0, 0) - - self.button_9 = wx.Button(self.panel_1, wx.ID_ANY, "button_9") - grid_sizer_5.Add(self.button_9, (2, 0), (1, 1), 0, 0) - - grid_sizer_ctrl_plot = wx.GridBagSizer(0, 0) - grid_sizer_main.Add(grid_sizer_ctrl_plot, (1, 1), (1, 1), wx.EXPAND, 0) - - self.b_clear = wx.Button(self.panel_1, wx.ID_ANY, "Clear") - grid_sizer_ctrl_plot.Add(self.b_clear, (0, 0), (1, 1), 0, 0) - - self.b_save = wx.Button(self.panel_1, wx.ID_ANY, "Save") - grid_sizer_ctrl_plot.Add(self.b_save, (0, 1), (1, 1), 0, 0) - - self.panel_1.SetSizer(grid_sizer_main) - - self.Layout() - # end wxGlade - self.timer = wx.Timer(self, wx.ID_ANY) - self.Bind(wx.EVT_CLOSE, self.on_close_window) - self.Bind(wx.EVT_BUTTON, self.on_b_start, self.b_start) - self.Bind(wx.EVT_BUTTON, self.on_b_stop, self.b_stop) - self.Bind(wx.EVT_BUTTON, self.on_b_clear, self.b_clear) - self.Bind(wx.EVT_BUTTON, self.on_b_save, self.b_save) - self.Bind(wx.EVT_BUTTON, self.on_b_run, self.b_run) - self.Bind(wx.EVT_TIMER, self.update, self.timer) - self.timer.Start(100, False) - self.runner_thread = None - - def on_close_window(self, event): - self.model.exit() - LOGGER.info("Closing") - wx.Exit() - - def update(self, event): - #Repaint gui - self.tabs.Refresh() - self.model.refresh() - #Unlock if script is finished - if self.runner_thread is not None: - if not self.runner_thread.is_alive(): - self.unlock() - self.runner_thread = None - #update Stuff - data = {"over1":True,"over2":True,"motor":12} - for key,val in data.items(): - if type(val) is bool: - if val: - self.status[key].SetBitmap(self.green) - else: - self.status[key].SetBitmap(self.red) - else: - self.status[key].SetLabel(str(val)) - - def lock(self): - self.b_run.Disable() - self.b_start.Disable() - - def unlock(self): - self.b_run.Enable() - self.b_start.Enable() - - def on_b_start(self, event): # wxGlade: MyFrame. - LOGGER.info("Event handler 'on_b_start'") - self.model.start_measuring() - event.Skip() - - def on_b_save(self, event): # wxGlade: MyFrame. - LOGGER.info("Event handler 'on_b_save'") - with wx.FileDialog( - self, - "Save csv file", - wildcard="CSV files (*.csv)|*.csv", - style=wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT, - ) as fileDialog: - - if fileDialog.ShowModal() == wx.ID_CANCEL: - return # the user changed their mind - - # save the current contents in the file - pathname = fileDialog.GetPath() - self.model.save_measuring(path=pathname) - event.Skip() - - def on_b_run(self, event): # wxGlade: MyFrame. - LOGGER.info("Event handler 'on_b_run'") - with wx.FileDialog( - self, - "Open PY file", - wildcard="PY files (*.py)|*.py", - style=wx.FD_OPEN | wx.FD_FILE_MUST_EXIST, - ) as fileDialog: - - if fileDialog.ShowModal() == wx.ID_CANCEL: - return # the user changed their mind - - # Proceed loading the file chosen by the user - pathname = fileDialog.GetPath() - script = importlib.machinery.SourceFileLoader("ghf", pathname).load_module() - self.runner_thread = Thread(target=script.main, args=(self.model,)) - self.lock() - self.runner_thread.start() - event.Skip() - - def on_b_stop(self, event): # wxGlade: MyFrame. - self.model.stop_measuring() - LOGGER.info("Event handler 'on_b_stop'") - event.Skip() - - def on_b_clear(self, event): # wxGlade: MyFrame. - self.model.clear() - LOGGER.info("Event handler 'on_b_clear'") - event.Skip() - - -# end of class MyFrame - - -class MyApp(wx.App): - def OnInit(self): - self.frame = MyFrame(None, wx.ID_ANY, "") - self.SetTopWindow(self.frame) - self.frame.Show() - return True - - -# end of class MyApp - -if __name__ == "__main__": - app = MyApp(0) - app.MainLoop()