From 9ea39f4f54b8a2a2b46b5b28d669c27e05915d2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20Wei=C3=9Fer?= Date: Sun, 27 Jun 2021 15:20:44 +0200 Subject: [PATCH] Group models meta model, execute script --- measurement.py | 71 ++++++++++++++++++++++++++++++++ model.py | 96 +++++++++++++++++++------------------------ my_control_script.py | 17 ++++++++ wxglade_out.py | 97 ++++++++++++++++++++++++++++++++------------ 4 files changed, 202 insertions(+), 79 deletions(-) create mode 100644 measurement.py create mode 100644 my_control_script.py diff --git a/measurement.py b/measurement.py new file mode 100644 index 0000000..ee5e95f --- /dev/null +++ b/measurement.py @@ -0,0 +1,71 @@ +import numpy as np +from datetime import datetime +from threading import Thread, Event +from time import sleep, time +from queue import Queue +from random import random + + +class MeasureWork(Thread): + """ Communicates with the measuring hardware. Here we only produce random data. """ + + def __init__(self, message_queue): + super().__init__(name="Measure") + self.message_queue = message_queue + self.produceData = Event() + self.exit_request = Event() + self.file = open("temp.csv", "w") + + def run(self): + """ Worker method of a python Thread. Called when the Thread is started. """ + while not self.exit_request.is_set(): + if self.produceData.is_set(): + temp = random() + ts = datetime.now() + self.message_queue.put((ts, temp)) + self.file.write(f"{ts} - {temp}\n") + else: + self.file.flush() + sleep(1) + + +class Measurement(object): + """docstring for Model.""" + + def __init__(self): + super(Measurement, self).__init__() + self.data = [] + self.t = [] + self.measureQueue = Queue() + self.measureThread = MeasureWork(self.measureQueue) + self.measureThread.start() + + def start_measuring(self): + self.measureThread.produceData.set() + print("I started meas") + + def save_measuring(self, path="temp_temp.csv"): + print("I saved meas") + np.savetxt(path, np.array(self.data)) + + def stop_measuring(self): + self.measureThread.produceData.clear() + print("I stopped meas") + + def clear(self): + self.data = [] + self.t = [] + print("I cleared meas") + + def exit(self): + self.stop_measuring() + self.measureThread.exit_request.set() + + @property + def get_data(self): + while not self.measureQueue.empty(): + t, data = self.measureQueue.get() + self.data.append(data) + self.t.append(t) + print(self.data) + return self.t, self.data diff --git a/model.py b/model.py index ebd97d5..0fe098d 100644 --- a/model.py +++ b/model.py @@ -1,63 +1,51 @@ -import numpy as np -from datetime import datetime -from threading import Thread, Event -from time import sleep, time -from queue import Queue -from random import random +""" +API for scripting measurements and drivers + +Data: +- dict with sensor data (temp, pressure, current) +- dict with drivers (magnetic field control) +""" +from measurement import Measurement -class MeasureWork(Thread): - def __init__(self, message_queue): - super().__init__(name="Measure") - self.message_queue = message_queue - self.produceData = Event() - self.file = open("temp.csv", "w") - - def run(self): - while True: - if self.produceData.is_set(): - temp = random() - ts = datetime.now() - self.message_queue.put((ts, temp)) - self.file.write(f"{ts} - {temp}\n") - else: - self.file.flush() - sleep(1) - - -class Model(object): - """docstring for Model.""" - +class Model: def __init__(self): - super(Model, self).__init__() - self.data = [] - self.t = [] - self.measureQueue = Queue() - self.measureThread = MeasureWork(self.measureQueue) - self.measureThread.start() + self.sensors = {"temp": Measurement()} + self.drivers = [] + pass - def startMeasureing(self): - self.measureThread.produceData.set() - print("I started meas") + def start_measuring(self): + for sens in self.sensors.values(): + sens.start_measuring() - def saveMeasureing(self, path='temp_temp.csv'): - print("I saved meas") - np.savetxt(path, np.array(self.data)) + def save_measuring(self, path="temp_temp.csv"): + for sens in self.sensors.values(): + sens.save_measuring() - def stopMeasureing(self): - self.measureThread.produceData.clear() - print("I started meas") + def stop_measuring(self): + for sens in self.sensors.values(): + sens.stop_measuring() def clear(self): - self.data = [] - self.t = [] - print("I started meas") + for sens in self.sensors.values(): + sens.clear() - @property - def getData(self): - while not self.measureQueue.empty(): - t, data = self.measureQueue.get() - self.data.append(data) - self.t.append(t) - print(self.data) - return self.t, self.data \ No newline at end of file + def exit(self): + for sens in self.sensors.values(): + sens.exit() + + +""" + init() + sensoren = [] + + + for mag in range(10): + drive_to_value("MagnetFelied1", mag) + start_measuring("volt", "filename") + + + + + +""" \ No newline at end of file diff --git a/my_control_script.py b/my_control_script.py new file mode 100644 index 0000000..425c6f7 --- /dev/null +++ b/my_control_script.py @@ -0,0 +1,17 @@ +from time import sleep +import model + + +def main(param_model): + param_model.start_measuring() + with open("script_output.log", "w") as my_file: + for i in range(20): + sleep(0.5) + x, y = param_model.sensors["temp"].get_data + my_file.write(f"x: {x}, y: {y}\n") + param_model.stop_measuring() + + +if __name__ == "__main__": + print("wrong call") + # main(model.Model()) diff --git a/wxglade_out.py b/wxglade_out.py index 6fca553..5520172 100644 --- a/wxglade_out.py +++ b/wxglade_out.py @@ -3,7 +3,8 @@ # # generated by wxGlade 1.0.2 on Sun Jun 20 19:31:43 2021 # - +import importlib.machinery +from threading import Thread import wx from model import Model @@ -38,23 +39,25 @@ class PlotPanel(wx.Panel): sizer.Add(self.toolbar, 0, wx.GROW) self.SetSizer(sizer) self.Fit() - self.Bind(wx.EVT_PAINT, self.OnPaint, self) + self.Bind(wx.EVT_PAINT, self.on_paint, self) + self.ax = None + self.im = None self.init_plot_data() + self.x = self.y = None def init_plot_data(self): self.ax = self.fig.add_subplot() - self.x, self.y = self.model.getData + self.x, self.y = self.model.sensors["temp"].get_data (self.im,) = self.ax.plot(self.x, self.y, "-.") self.toolbar.update() # Not sure why this is needed - ADS - def GetToolBar(self): + def get_toolbar(self): # You will need to override GetToolBar if you are using an # unmanaged toolbar in your frame return self.toolbar - def OnPaint(self, event): - print("Paint") - self.x, self.y = self.model.getData + def on_paint(self, event): + self.x, self.y = self.model.sensors["temp"].get_data # print(self.x) self.im.set_data(self.x, self.y) self.ax.relim() @@ -70,7 +73,7 @@ class MyFrame(wx.Frame): kwds["style"] = kwds.get("style", 0) | wx.DEFAULT_FRAME_STYLE wx.Frame.__init__(self, *args, **kwds) - self.SetSize((400, 300)) + self.SetSize((500, 400)) self.SetTitle("frame") self.panel_1 = wx.Panel(self, wx.ID_ANY) @@ -86,9 +89,12 @@ class MyFrame(wx.Frame): self.b_clear = wx.Button(self.panel_1, wx.ID_ANY, "Clear") grid_sizer_1.Add(self.b_clear, (0, 2), (1, 1), 0, 0) - self.b_save = wx.Button(self.panel_1, wx.ID_ANY, "Speichern") + self.b_save = wx.Button(self.panel_1, wx.ID_ANY, "Save") grid_sizer_1.Add(self.b_save, (0, 3), (1, 1), 0, 0) + self.b_run = wx.Button(self.panel_1, wx.ID_ANY, "Run") + grid_sizer_1.Add(self.b_run, (0, 4), (1, 1), 0, 0) + self.plot = PlotPanel(self.panel_1, self.model) self.plot.SetMinSize((300, 300)) grid_sizer_1.Add(self.plot, (1, 0), (1, 3), wx.EXPAND, 0) @@ -100,24 +106,44 @@ class MyFrame(wx.Frame): self.timer = wx.Timer(self, wx.ID_ANY) self.Layout() - self.Bind(wx.EVT_BUTTON, self.onBstart, self.b_start) - self.Bind(wx.EVT_BUTTON, self.offBstop, self.b_stop) - self.Bind(wx.EVT_BUTTON, self.delBclear, self.b_clear) - self.Bind(wx.EVT_BUTTON, self.onBsave, self.b_save) + 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 # end wxGlade + def on_close_window(self, event): + self.model.exit() + print("Closing") + wx.Exit() + def update(self, event): self.plot.Refresh() + if self.runner_thread is not None: + if not self.runner_thread.is_alive(): + self.unlock() + self.runner_thread = None - def onBstart(self, event): # wxGlade: MyFrame. - print("Event handler 'onBstart'") - self.model.startMeasureing() + 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. + print("Event handler 'on_b_start'") + self.model.start_measuring() event.Skip() - def onBsave(self, event): # wxGlade: MyFrame. - print("Event handler 'onBsave'") + def on_b_save(self, event): # wxGlade: MyFrame. + print("Event handler 'on_b_save'") with wx.FileDialog( self, "Save csv file", @@ -130,17 +156,33 @@ class MyFrame(wx.Frame): # save the current contents in the file pathname = fileDialog.GetPath() - self.model.saveMeasureing(path=pathname) + self.model.save_measuring(path=pathname) event.Skip() - def offBstop(self, event): # wxGlade: MyFrame. - self.model.stopMeasureing() - print("Event handler 'offBstop'") + def on_b_run(self, event): # wxGlade: MyFrame. + print("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() + print("Event handler 'on_b_stop'") event.Skip() - def delBclear(self, event): # wxGlade: MyFrame. + def on_b_clear(self, event): # wxGlade: MyFrame. self.model.clear() - print("Event handler 'delBclear'") + print("Event handler 'on_b_clear'") event.Skip() @@ -148,6 +190,10 @@ class MyFrame(wx.Frame): class MeinErsterMessApp(wx.App): + def __init__(self): + super().__init__() + self.frame = None + def OnInit(self): self.frame = MyFrame(None, wx.ID_ANY, "") self.SetTopWindow(self.frame) @@ -157,6 +203,7 @@ class MeinErsterMessApp(wx.App): # end of class MeinErsterMessApp + if __name__ == "__main__": - app = MeinErsterMessApp(0) + app = MeinErsterMessApp() app.MainLoop()