class BindTests(unittest.TestCase): def setUp(self): with open('tests/yaml/simple.yaml') as f: sc = io.import_from_yaml(f) self.interpreter = Interpreter(sc) # Stabilization self.interpreter.execute_once() def test_bind(self): with open('tests/yaml/simple.yaml') as f: other_sc = io.import_from_yaml(f) other_interpreter = Interpreter(other_sc) self.interpreter.bind(other_interpreter) self.assertIn(other_interpreter.queue, self.interpreter._bound) self.interpreter.raise_event(InternalEvent('test')) self.assertTrue(self.interpreter._internal_events.pop(), Event('test')) self.assertTrue(other_interpreter._external_events.pop(), Event('test')) def test_bind_callable(self): with open('tests/yaml/simple.yaml') as f: other_sc = io.import_from_yaml(f) other_interpreter = Interpreter(other_sc) self.interpreter.bind(other_interpreter.queue) self.assertIn(other_interpreter.queue, self.interpreter._bound) self.interpreter.raise_event(InternalEvent('test')) self.assertTrue(self.interpreter._internal_events.pop(), Event('test')) self.assertTrue(other_interpreter._external_events.pop(), Event('test'))
class RemoteElevatorTests(unittest.TestCase): def setUp(self): with open('docs/examples/elevator.yaml') as f: elevator = io.import_from_yaml(f) with open('docs/examples/elevator_buttons.yaml') as f: buttons = io.import_from_yaml(f) self.elevator = Interpreter(elevator) self.buttons = Interpreter(buttons) self.buttons.bind(self.elevator) def test_button(self): self.assertEqual(self.elevator.context['current'], 0) self.buttons.queue(Event('button_2_pushed')) self.buttons.execute() event = self.elevator._events.pop() self.assertEqual(event.name, 'floorSelected') self.assertEqual(event.data['floor'], 2) self.buttons.queue(Event('button_2_pushed')) self.buttons.execute() self.elevator.execute() self.assertEqual(self.elevator.context['current'], 2) def test_button_0_on_groundfloor(self): self.assertEqual(self.elevator.context['current'], 0) self.buttons.queue(Event('button_0_pushed')) self.buttons.execute() self.elevator.execute() self.assertEqual(self.elevator.context['current'], 0)
class BindTests(unittest.TestCase): def setUp(self): with open('tests/yaml/simple.yaml') as f: sc = io.import_from_yaml(f) self.interpreter = Interpreter(sc) # Stabilization self.interpreter.execute_once() def test_bind(self): with open('tests/yaml/simple.yaml') as f: other_sc = io.import_from_yaml(f) other_interpreter = Interpreter(other_sc) self.interpreter.bind(other_interpreter) self.assertIn(other_interpreter.queue, self.interpreter._bound) self.interpreter.raise_event(InternalEvent('test')) self.assertTrue(self.interpreter._internal_events.pop(), Event('test')) self.assertTrue(other_interpreter._external_events.pop(), Event('test')) def test_bind_callable(self): with open('tests/yaml/simple.yaml') as f: other_sc = io.import_from_yaml(f) other_interpreter = Interpreter(other_sc) self.interpreter.bind(other_interpreter.queue) self.assertIn(other_interpreter.queue, self.interpreter._bound) self.interpreter.raise_event(InternalEvent('test')) self.assertTrue(self.interpreter._internal_events.pop(), Event('test')) self.assertTrue(other_interpreter._external_events.pop(), Event('test'))
class RemoteElevatorTests(unittest.TestCase): def setUp(self): with open('docs/examples/elevator/elevator.yaml') as f: elevator = io.import_from_yaml(f) with open('docs/examples/elevator/elevator_buttons.yaml') as f: buttons = io.import_from_yaml(f) self.elevator = Interpreter(elevator) self.buttons = Interpreter(buttons) self.buttons.bind(self.elevator) def test_button(self): self.assertEqual(self.elevator.context['current'], 0) self.buttons.queue(Event('button_2_pushed')) self.buttons.execute() event = self.elevator._external_events.pop() self.assertEqual(event.name, 'floorSelected') self.assertEqual(event.data['floor'], 2) self.buttons.queue(Event('button_2_pushed')) self.buttons.execute() self.elevator.execute() self.assertEqual(self.elevator.context['current'], 2) def test_button_0_on_groundfloor(self): self.assertEqual(self.elevator.context['current'], 0) self.buttons.queue(Event('button_0_pushed')) self.buttons.execute() self.elevator.execute() self.assertEqual(self.elevator.context['current'], 0)
class BindTests(unittest.TestCase): def setUp(self): sc = io.import_from_yaml(open('tests/yaml/simple.yaml')) self.interpreter = Interpreter(sc) def test_bind(self): other_sc = io.import_from_yaml(open('tests/yaml/simple.yaml')) other_interpreter = Interpreter(other_sc) self.interpreter.bind(other_interpreter) self.assertEqual(self.interpreter._bound, [other_interpreter.send]) self.interpreter.send(Event('test'), internal=True) self.assertTrue(self.interpreter._events.pop(), Event('test')) self.assertTrue(other_interpreter._events.pop(), Event('test')) def test_bind_callable(self): other_sc = io.import_from_yaml(open('tests/yaml/simple.yaml')) other_interpreter = Interpreter(other_sc) self.interpreter.bind(other_interpreter.send) self.assertEqual(self.interpreter._bound, [other_interpreter.send]) self.interpreter.send(Event('test'), internal=True) self.assertTrue(self.interpreter._events.pop(), Event('test')) self.assertTrue(other_interpreter._events.pop(), Event('test'))
def remote_elevator(elevator): sc = import_from_yaml( filepath='docs/examples/elevator/elevator_buttons.yaml') remote = Interpreter(sc) remote.bind(elevator) return remote
class StopwatchApplication(tk.Frame): def __init__(self, master=None): super().__init__(master) # Initialize widgets self.create_widgets() # Create a Stopwatch interpreter with open('stopwatch.yaml') as f: statechart = import_from_yaml(f) self.interpreter = Interpreter(statechart) self.interpreter.time = time.time() # Bind interpreter events to the GUI self.interpreter.bind(self.event_handler) # Run the interpreter self.run() def run(self): # This function does essentially the same job than ``sismic.interpreter.run_in_background`` # but uses Tkinter's mainloop instead of a Thread, which is more adequate. # Update internal clock and execute interpreter self.interpreter.time = time.time() self.interpreter.execute() # Queue a call every 100ms on tk's mainloop self.after(100, self.run) # Update the widget that contains the list of active states. self.w_states['text'] = 'active states: ' + ', '.join( self.interpreter.configuration) def create_widgets(self): self.pack() # Add buttons self.w_btn_start = tk.Button(self, text='start', command=self._start) self.w_btn_stop = tk.Button(self, text='stop', command=self._stop) self.w_btn_split = tk.Button(self, text='split', command=self._split) self.w_btn_unsplit = tk.Button(self, text='unsplit', command=self._unsplit) self.w_btn_reset = tk.Button(self, text='reset', command=self._reset) self.w_btn_quit = tk.Button(self, text='quit', command=self._quit) # Initial button states self.w_btn_stop['state'] = tk.DISABLED self.w_btn_unsplit['state'] = tk.DISABLED # Pack self.w_btn_start.pack(side=tk.LEFT, ) self.w_btn_stop.pack(side=tk.LEFT, ) self.w_btn_split.pack(side=tk.LEFT, ) self.w_btn_unsplit.pack(side=tk.LEFT, ) self.w_btn_reset.pack(side=tk.LEFT, ) self.w_btn_quit.pack(side=tk.LEFT, ) # Active states label self.w_states = tk.Label(root) self.w_states.pack(side=tk.BOTTOM, fill=tk.X) # Timer label self.w_timer = tk.Label(root, font=("Helvetica", 16), pady=5) self.w_timer.pack(side=tk.BOTTOM, fill=tk.X) def event_handler(self, event): # Update text widget when timer value is updated if event.name == 'refresh': self.w_timer['text'] = event.time def _start(self): self.interpreter.queue(Event('start')) self.w_btn_start['state'] = tk.DISABLED self.w_btn_stop['state'] = tk.NORMAL def _stop(self): self.interpreter.queue(Event('stop')) self.w_btn_start['state'] = tk.NORMAL self.w_btn_stop['state'] = tk.DISABLED def _reset(self): self.interpreter.queue(Event('reset')) def _split(self): self.interpreter.queue(Event('split')) self.w_btn_split['state'] = tk.DISABLED self.w_btn_unsplit['state'] = tk.NORMAL def _unsplit(self): self.interpreter.queue(Event('split')) self.w_btn_split['state'] = tk.NORMAL self.w_btn_unsplit['state'] = tk.DISABLED def _quit(self): self.master.destroy()
class MicrowaveApplication(tk.Frame): def __init__(self, master=None): super().__init__(master) # Initialize widgets self.create_widgets() # Create a Stopwatch interpreter with open('microwave.yaml') as f: statechart = import_from_yaml(f) self.interpreter = Interpreter(statechart) # Bind interpreter events to the GUI self.interpreter.bind(self.event_handler) self.execute() def execute(self): self.interpreter.execute() # Update the widget that contains the list of active states. self.w_states['text'] = '\n'.join(self.interpreter.configuration) self.w_timer['text'] = 'M.timer: %d' % self.interpreter.context.get( 'controller.timer', 'undefined') self.w_power['text'] = 'M.power: %d' % self.interpreter.context.get( 'controller.power', 'undefined') def create_widgets(self): self.pack(fill=tk.BOTH) # MAIN frame containing all others left_frame = tk.Frame(self) left_frame.pack(side=tk.LEFT, fill=tk.BOTH) # INPUT frame input_frame = tk.LabelFrame(left_frame, text='INPUT BUTTONS') input_frame.pack(side=tk.LEFT, fill=tk.BOTH, padx=(8, 8)) self.w_power_inc = tk.Button(input_frame, text='power +', command=partial( self.send_event, event_name='input_power_inc')) self.w_power_dec = tk.Button(input_frame, text='power -', command=partial( self.send_event, event_name='input_power_dec')) self.w_power_reset = tk.Button(input_frame, text='power reset', command=partial( self.send_event, event_name='input_power_reset')) self.w_power_inc.pack(side=tk.TOP, fill=tk.X) self.w_power_dec.pack(side=tk.TOP, fill=tk.X) self.w_power_reset.pack(side=tk.TOP, fill=tk.X) self.w_timer_inc = tk.Button(input_frame, text='timer +', command=partial( self.send_event, event_name='input_timer_inc')) self.w_timer_dec = tk.Button(input_frame, text='timer -', command=partial( self.send_event, event_name='input_timer_dec')) self.w_timer_reset = tk.Button(input_frame, text='timer 0', command=partial( self.send_event, event_name='input_timer_reset')) self.w_timer_inc.pack(side=tk.TOP, fill=tk.X, pady=(8, 0)) # leave some space before first button self.w_timer_dec.pack(side=tk.TOP, fill=tk.X) self.w_timer_reset.pack(side=tk.TOP, fill=tk.X) self.w_cooking_start = tk.Button(input_frame, text='start', command=partial( self.send_event, event_name='input_cooking_start')) self.w_cooking_stop = tk.Button(input_frame, text='stop', command=partial( self.send_event, event_name='input_cooking_stop')) self.w_cooking_start.pack( side=tk.TOP, fill=tk.X, pady=(8, 0)) # leave some space before first button self.w_cooking_stop.pack(side=tk.TOP, fill=tk.X) # SENSORS frame sensors_frame = tk.LabelFrame(left_frame, text='SENSORS') sensors_frame.pack(side=tk.LEFT, fill=tk.BOTH, padx=(8, 8)) # SENSORS > Clock frame clock_frame = tk.LabelFrame(sensors_frame, text='Clock') clock_frame.pack(side=tk.TOP, fill=tk.BOTH) self.w_clock = tk.Label(clock_frame) self.w_tick = tk.Button(clock_frame, text='tick', command=partial(self.send_event, event_name='timer_tick')) self.w_tick.pack(side=tk.TOP, fill=tk.X) # SENSORS > WeightSensor frame weight_frame = tk.LabelFrame(sensors_frame, text='WeightSensor') weight_frame.pack(side=tk.TOP, fill=tk.BOTH, pady=(8, 0)) self.w_weight = tk.Label(weight_frame) self.w_item_placed = tk.Button(weight_frame, text='place item', command=partial( self.send_event, event_name='item_placed')) self.w_item_removed = tk.Button(weight_frame, text='remove item', command=partial( self.send_event, event_name='item_removed')) self.w_item_placed.pack(side=tk.TOP, fill=tk.X) self.w_item_removed.pack(side=tk.TOP, fill=tk.X) # SENSORS > Door frame door_frame = tk.LabelFrame(sensors_frame, text='Door') door_frame.pack(side=tk.TOP, fill=tk.BOTH, pady=(8, 0)) self.w_door = tk.Label(door_frame) self.w_door_opened = tk.Button(door_frame, text='open door', command=partial( self.send_event, event_name='door_opened')) self.w_door_closed = tk.Button(door_frame, text='close door', command=partial( self.send_event, event_name='door_closed')) self.w_door_opened.pack(side=tk.TOP, fill=tk.X) self.w_door_closed.pack(side=tk.TOP, fill=tk.X) # ACTUATORS frame right_frame = tk.LabelFrame(self, text='ACTUATORS') right_frame.pack(side=tk.LEFT, fill=tk.BOTH, padx=(8, 8)) # Display component display_frame = tk.LabelFrame(right_frame, text='Display') display_frame.pack(side=tk.TOP, fill=tk.BOTH) self.w_display = tk.Label(display_frame) self.w_display.pack(side=tk.TOP) # Lamp component lamp_frame = tk.LabelFrame(right_frame, text='Lamp') lamp_frame.pack(side=tk.TOP, fill=tk.BOTH) self.w_lamp = tk.Label(lamp_frame) self.w_lamp.pack(side=tk.TOP) # Heating component heating_frame = tk.LabelFrame(right_frame, text='Heating') heating_frame.pack(side=tk.TOP, fill=tk.BOTH) self.w_heating_power = tk.Label(heating_frame) self.w_heating_status = tk.Label(heating_frame) self.w_heating_power.pack(side=tk.TOP) self.w_heating_status.pack(side=tk.TOP) # Beeper component beep_frame = tk.LabelFrame(right_frame, text='Beeper') beep_frame.pack(side=tk.TOP, fill=tk.BOTH) self.w_beep = tk.Label(beep_frame) self.w_beep.pack(side=tk.TOP) # Turntable component turntable_frame = tk.LabelFrame(right_frame, text='Turntable') turntable_frame.pack(side=tk.TOP, fill=tk.BOTH) self.w_turntable = tk.Label(turntable_frame) self.w_turntable.pack(side=tk.TOP) # Oven controller statechart component controller_frame = tk.LabelFrame(self, text='Oven Controller') controller_frame.pack(side=tk.LEFT, fill=tk.BOTH, padx=(8, 8)) # Microwave Controller Statechart status # statechart_frame = tk.LabelFrame(right_frame2, text='Controller') # statechart_frame.pack(side=tk.TOP, fill=tk.BOTH) states_frame = tk.LabelFrame(controller_frame, text='States') states_frame.pack(side=tk.TOP, fill=tk.BOTH) self.w_states = tk.Label(states_frame) self.w_states.pack(side=tk.TOP, fill=tk.X, pady=(8, 0)) variables_frame = tk.LabelFrame(controller_frame, text='Variables') variables_frame.pack(side=tk.TOP, fill=tk.BOTH, pady=(8, 0)) self.w_timer = tk.Label(variables_frame) self.w_timer.pack(side=tk.BOTTOM, fill=tk.X) self.w_power = tk.Label(variables_frame) self.w_power.pack(side=tk.BOTTOM, fill=tk.X) def event_handler(self, event): name = event.name if name == 'lamp_switch_on': self.w_lamp['text'] = 'on' elif name == 'lamp_switch_off': self.w_lamp['text'] = 'off' elif name == 'display_set': self.w_display['text'] = event.text elif name == 'display_clear': self.w_display['text'] = '' elif name == 'heating_set_power': self.w_heating_power['text'] = event.power elif name == 'heating_on': self.w_heating_status['text'] = 'on' elif name == 'heating_off': self.w_heating_status['text'] = 'off' elif name == 'beep': self.w_beep['text'] = event.number elif name == 'turntable_start': self.w_turntable['text'] = 'on' elif name == 'turntable_stop': self.w_turntable['text'] = 'off' else: raise ValueError('Unknown event %s' % event) def send_event(self, event_name): self.interpreter.queue(Event(event_name)) self.execute() def _quit(self): self.master.destroy()
class StopwatchApplication(tk.Frame): def __init__(self, master=None): super().__init__(master) # Initialize widgets self.create_widgets() # Create a Stopwatch interpreter with open('stopwatch.yaml') as f: statechart = import_from_yaml(f) self.interpreter = Interpreter(statechart, initial_time=time.time()) # Bind interpreter events to the GUI self.interpreter.bind(self.event_handler) # Run the interpreter self.run() def run(self): # This function does essentially the same job than ``sismic.interpreter.run_in_background`` # but uses Tkinter's mainloop instead of a Thread, which is more adequate. # Update internal clock and execute interpreter self.interpreter.time = time.time() self.interpreter.execute() # Queue a call every 100ms on tk's mainloop self.after(100, self.run) # Update the widget that contains the list of active states. self.w_states['text'] = 'active states: ' + ', '.join(self.interpreter.configuration) def create_widgets(self): self.pack() # Add buttons self.w_btn_start = tk.Button(self, text='start', command=self._start) self.w_btn_stop = tk.Button(self, text='stop', command=self._stop) self.w_btn_split = tk.Button(self, text='split', command=self._split) self.w_btn_unsplit = tk.Button(self, text='unsplit', command=self._unsplit) self.w_btn_reset = tk.Button(self, text='reset', command=self._reset) self.w_btn_quit = tk.Button(self, text='quit', command=self._quit) # Initial button states self.w_btn_stop['state'] = tk.DISABLED self.w_btn_unsplit['state'] = tk.DISABLED # Pack self.w_btn_start.pack(side=tk.LEFT,) self.w_btn_stop.pack(side=tk.LEFT,) self.w_btn_split.pack(side=tk.LEFT,) self.w_btn_unsplit.pack(side=tk.LEFT,) self.w_btn_reset.pack(side=tk.LEFT,) self.w_btn_quit.pack(side=tk.LEFT,) # Active states label self.w_states = tk.Label(root) self.w_states.pack(side=tk.BOTTOM, fill=tk.X) # Timer label self.w_timer = tk.Label(root, font=("Helvetica", 16), pady=5) self.w_timer.pack(side=tk.BOTTOM, fill=tk.X) def event_handler(self, event): # Update text widget when timer value is updated if event.name == 'refresh': self.w_timer['text'] = event.time def _start(self): self.interpreter.queue(Event('start')) self.w_btn_start['state'] = tk.DISABLED self.w_btn_stop['state'] = tk.NORMAL def _stop(self): self.interpreter.queue(Event('stop')) self.w_btn_start['state'] = tk.NORMAL self.w_btn_stop['state'] = tk.DISABLED def _reset(self): self.interpreter.queue(Event('reset')) def _split(self): self.interpreter.queue(Event('split')) self.w_btn_split['state'] = tk.DISABLED self.w_btn_unsplit['state'] = tk.NORMAL def _unsplit(self): self.interpreter.queue(Event('split')) self.w_btn_split['state'] = tk.NORMAL self.w_btn_unsplit['state'] = tk.DISABLED def _quit(self): self.master.destroy()
class MicrowaveApplication(tk.Frame): def __init__(self, master=None): super().__init__(master) # Initialize widgets self.create_widgets() # Create a Stopwatch interpreter with open('microwave.yaml') as f: statechart = import_from_yaml(f) self.interpreter = Interpreter(statechart) # Bind interpreter events to the GUI self.interpreter.bind(self.event_handler) self.execute() def execute(self): self.interpreter.execute() # Update the widget that contains the list of active states. self.w_states['text'] = '\n'.join(self.interpreter.configuration) self.w_timer['text'] = 'M.timer: %d' % self.interpreter.context.get('controller.timer', 'undefined') self.w_power['text'] = 'M.power: %d' % self.interpreter.context.get('controller.power', 'undefined') def create_widgets(self): self.pack(fill=tk.BOTH) # MAIN frame containing all others left_frame = tk.Frame(self) left_frame.pack(side=tk.LEFT, fill=tk.BOTH) # INPUT frame input_frame = tk.LabelFrame(left_frame, text='INPUT BUTTONS') input_frame.pack(side=tk.LEFT, fill=tk.BOTH, padx=(8, 8)) self.w_power_inc = tk.Button(input_frame, text='power +', command=partial(self.send_event, event_name='input_power_inc')) self.w_power_dec = tk.Button(input_frame, text='power -', command=partial(self.send_event, event_name='input_power_dec')) self.w_power_reset = tk.Button(input_frame, text='power reset', command=partial(self.send_event, event_name='input_power_reset')) self.w_power_inc.pack(side=tk.TOP, fill=tk.X) self.w_power_dec.pack(side=tk.TOP, fill=tk.X) self.w_power_reset.pack(side=tk.TOP, fill=tk.X) self.w_timer_inc = tk.Button(input_frame, text='timer +', command=partial(self.send_event, event_name='input_timer_inc')) self.w_timer_dec = tk.Button(input_frame, text='timer -', command=partial(self.send_event, event_name='input_timer_dec')) self.w_timer_reset = tk.Button(input_frame, text='timer 0', command=partial(self.send_event, event_name='input_timer_reset')) self.w_timer_inc.pack(side=tk.TOP, fill=tk.X, pady=(8, 0)) # leave some space before first button self.w_timer_dec.pack(side=tk.TOP, fill=tk.X) self.w_timer_reset.pack(side=tk.TOP, fill=tk.X) self.w_cooking_start = tk.Button(input_frame, text='start', command=partial(self.send_event, event_name='input_cooking_start')) self.w_cooking_stop = tk.Button(input_frame, text='stop', command=partial(self.send_event, event_name='input_cooking_stop')) self.w_cooking_start.pack(side=tk.TOP, fill=tk.X, pady=(8, 0)) # leave some space before first button self.w_cooking_stop.pack(side=tk.TOP, fill=tk.X) # SENSORS frame sensors_frame = tk.LabelFrame(left_frame, text='SENSORS') sensors_frame.pack(side=tk.LEFT, fill=tk.BOTH, padx=(8, 8)) # SENSORS > Clock frame clock_frame = tk.LabelFrame(sensors_frame, text='Clock') clock_frame.pack(side=tk.TOP, fill=tk.BOTH) self.w_clock = tk.Label(clock_frame) self.w_tick = tk.Button(clock_frame, text='tick', command=partial(self.send_event, event_name='timer_tick')) self.w_tick.pack(side=tk.TOP, fill=tk.X) # SENSORS > WeightSensor frame weight_frame = tk.LabelFrame(sensors_frame, text='WeightSensor') weight_frame.pack(side=tk.TOP, fill=tk.BOTH, pady=(8, 0)) self.w_weight = tk.Label(weight_frame) self.w_item_placed = tk.Button(weight_frame, text='place item', command=partial(self.send_event, event_name='item_placed')) self.w_item_removed = tk.Button(weight_frame, text='remove item', command=partial(self.send_event, event_name='item_removed')) self.w_item_placed.pack(side=tk.TOP, fill=tk.X) self.w_item_removed.pack(side=tk.TOP, fill=tk.X) # SENSORS > Door frame door_frame = tk.LabelFrame(sensors_frame, text='Door') door_frame.pack(side=tk.TOP, fill=tk.BOTH, pady=(8, 0)) self.w_door = tk.Label(door_frame) self.w_door_opened = tk.Button(door_frame, text='open door', command=partial(self.send_event, event_name='door_opened')) self.w_door_closed = tk.Button(door_frame, text='close door', command=partial(self.send_event, event_name='door_closed')) self.w_door_opened.pack(side=tk.TOP, fill=tk.X) self.w_door_closed.pack(side=tk.TOP, fill=tk.X) # ACTUATORS frame right_frame = tk.LabelFrame(self, text='ACTUATORS') right_frame.pack(side=tk.LEFT, fill=tk.BOTH, padx=(8, 8)) # Display component display_frame = tk.LabelFrame(right_frame, text='Display') display_frame.pack(side=tk.TOP, fill=tk.BOTH) self.w_display = tk.Label(display_frame) self.w_display.pack(side=tk.TOP) # Lamp component lamp_frame = tk.LabelFrame(right_frame, text='Lamp') lamp_frame.pack(side=tk.TOP, fill=tk.BOTH) self.w_lamp = tk.Label(lamp_frame) self.w_lamp.pack(side=tk.TOP) # Heating component heating_frame = tk.LabelFrame(right_frame, text='Heating') heating_frame.pack(side=tk.TOP, fill=tk.BOTH) self.w_heating_power = tk.Label(heating_frame) self.w_heating_status = tk.Label(heating_frame) self.w_heating_power.pack(side=tk.TOP) self.w_heating_status.pack(side=tk.TOP) # Beeper component beep_frame = tk.LabelFrame(right_frame, text='Beeper') beep_frame.pack(side=tk.TOP, fill=tk.BOTH) self.w_beep = tk.Label(beep_frame) self.w_beep.pack(side=tk.TOP) # Turntable component turntable_frame = tk.LabelFrame(right_frame, text='Turntable') turntable_frame.pack(side=tk.TOP, fill=tk.BOTH) self.w_turntable = tk.Label(turntable_frame) self.w_turntable.pack(side=tk.TOP) # Oven controller statechart component controller_frame = tk.LabelFrame(self, text='Oven Controller') controller_frame.pack(side=tk.LEFT, fill=tk.BOTH, padx=(8, 8)) # Microwave Controller Statechart status # statechart_frame = tk.LabelFrame(right_frame2, text='Controller') # statechart_frame.pack(side=tk.TOP, fill=tk.BOTH) states_frame = tk.LabelFrame(controller_frame, text='States') states_frame.pack(side=tk.TOP, fill=tk.BOTH) self.w_states = tk.Label(states_frame) self.w_states.pack(side=tk.TOP, fill=tk.X, pady=(8, 0)) variables_frame = tk.LabelFrame(controller_frame, text='Variables') variables_frame.pack(side=tk.TOP, fill=tk.BOTH, pady=(8, 0)) self.w_timer = tk.Label(variables_frame) self.w_timer.pack(side=tk.BOTTOM, fill=tk.X) self.w_power = tk.Label(variables_frame) self.w_power.pack(side=tk.BOTTOM, fill=tk.X) def event_handler(self, event): name = event.name if name == 'lamp_switch_on': self.w_lamp['text'] = 'on' elif name == 'lamp_switch_off': self.w_lamp['text'] = 'off' elif name == 'display_set': self.w_display['text'] = event.text elif name == 'display_clear': self.w_display['text'] = '' elif name == 'heating_set_power': self.w_heating_power['text'] = event.power elif name == 'heating_on': self.w_heating_status['text'] = 'on' elif name == 'heating_off': self.w_heating_status['text'] = 'off' elif name == 'beep': self.w_beep['text'] = event.number elif name == 'turntable_start': self.w_turntable['text'] = 'on' elif name == 'turntable_stop': self.w_turntable['text'] = 'off' else: raise ValueError('Unknown event %s' % event) def send_event(self, event_name): self.interpreter.queue(Event(event_name)) self.execute() def _quit(self): self.master.destroy()
class MicrowaveApplication(tk.Frame): def __init__(self, master, statechart, contracts, properties): super().__init__(master) # Initialize widgets self.create_widgets() # Create a Stopwatch interpreter statechart = import_from_yaml(statechart) self.interpreter = Interpreter(statechart, ignore_contract=not contracts) # Bind interpreter events to the GUI self.interpreter.bind(self.event_handler) # Bind execution watchers self.watcher = ExecutionWatcher(self.interpreter) for prop in properties if properties else []: self.watcher.watch_with(import_from_yaml(prop), fails_fast=True) self.watcher.start() # Hide disabled widgets for widget_name in DISABLED_WIDGETS: widget = getattr(self, widget_name) widget.pack_forget() self.on_autotick() self.execute() def execute(self): try: print(self.interpreter.execute()) except ContractError as e: messagebox.showerror( 'Contract error!', e.__class__.__name__ + '\n\n' + 'The following assertion does not hold in ' + str(e.obj) + ':\n' + e.condition + '\n\n' + 'Step: \n' + str(e.step)) self.master.destroy() raise except AssertionError as e: messagebox.showerror('Unsatisfied property', e.args[0]) self.master.destroy() raise except Exception as e: messagebox.showerror( 'Fatal error', e.__class__.__name__ + ' was raised during the execution.\n' + 'See console for the traceback.') self.master.destroy() raise # Update the widget that contains the list of active states. self.w_states['text'] = '\n'.join(self.interpreter.configuration) self.w_context['text'] = '\n'.join([ '%s: %s' % (key, self.interpreter.context[key]) for key in sorted(self.interpreter.context) ]) def create_widgets(self): self.pack(fill=tk.BOTH) # Statechart status controller_frame = tk.LabelFrame(self, text='CONTROLLER') controller_frame.pack(side=tk.BOTTOM, fill=tk.X, padx=(8, 8)) state_frame = tk.LabelFrame(controller_frame, text='Active configuration') state_frame.pack(side=tk.BOTTOM, fill=tk.X) self.w_states = tk.Label(state_frame) self.w_states.pack(side=tk.BOTTOM, fill=tk.X) context_frame = tk.LabelFrame(controller_frame, text='Context') context_frame.pack(side=tk.BOTTOM, fill=tk.X) self.w_context = tk.Label(context_frame) self.w_context.pack(side=tk.BOTTOM, fill=tk.X) # left_frame = tk.Frame(self) left_frame.pack(side=tk.LEFT, fill=tk.BOTH) # Input frame input_frame = tk.LabelFrame(left_frame, text='INPUT BUTTONS') input_frame.pack(side=tk.LEFT, fill=tk.BOTH, padx=(8, 8)) # Sensor frame sensors_frame = tk.LabelFrame(left_frame, text='ACTUATORS') sensors_frame.pack(side=tk.LEFT, fill=tk.BOTH, padx=(8, 8)) # Add buttons self.w_input_power_inc = tk.Button(input_frame, text='power +', command=partial( self.send_event, event_name='input_power_inc')) self.w_input_power_dec = tk.Button(input_frame, text='power -', command=partial( self.send_event, event_name='input_power_dec')) self.w_input_power_reset = tk.Button( input_frame, text='power 0', command=partial(self.send_event, event_name='input_power_reset')) self.w_input_timer_inc = tk.Button(input_frame, text='timer +', command=partial( self.send_event, event_name='input_timer_inc')) self.w_input_timer_dec = tk.Button(input_frame, text='timer -', command=partial( self.send_event, event_name='input_timer_dec')) self.w_input_timer_reset = tk.Button( input_frame, text='timer 0', command=partial(self.send_event, event_name='input_timer_reset')) self.w_input_cooking_start = tk.Button( input_frame, text='start', command=partial(self.send_event, event_name='input_cooking_start')) self.w_input_cooking_stop = tk.Button( input_frame, text='stop', command=partial(self.send_event, event_name='input_cooking_stop')) self.w_tick = tk.Button(sensors_frame, text='tick', command=partial(self.send_event, event_name='timer_tick')) self.v_autotick = tk.BooleanVar() self.v_autotick.set(True) self.w_autotick = tk.Checkbutton(sensors_frame, text='Auto-tick', var=self.v_autotick, command=self.on_autotick) self.w_item_placed = tk.Button(sensors_frame, text='place item', command=partial( self.send_event, event_name='item_placed')) self.w_item_removed = tk.Button(sensors_frame, text='remove item', command=partial( self.send_event, event_name='item_removed')) self.w_door_opened = tk.Button(sensors_frame, text='open door', command=partial( self.send_event, event_name='door_opened')) self.w_door_closed = tk.Button(sensors_frame, text='close door', command=partial( self.send_event, event_name='door_closed')) # Pack self.w_input_power_inc.pack(side=tk.TOP, fill=tk.X) self.w_input_power_dec.pack(side=tk.TOP, fill=tk.X) self.w_input_power_reset.pack(side=tk.TOP, fill=tk.X) self.w_input_timer_inc.pack(side=tk.TOP, fill=tk.X, pady=(8, 0)) self.w_input_timer_dec.pack(side=tk.TOP, fill=tk.X) self.w_input_timer_reset.pack(side=tk.TOP, fill=tk.X) self.w_input_cooking_start.pack(side=tk.TOP, fill=tk.X, pady=(8, 0)) self.w_input_cooking_stop.pack(side=tk.TOP, fill=tk.X) self.w_autotick.pack(side=tk.TOP, fill=tk.X) self.w_tick.pack(side=tk.TOP, fill=tk.X) self.w_item_placed.pack(side=tk.TOP, fill=tk.X, pady=(8, 0)) self.w_item_removed.pack(side=tk.TOP, fill=tk.X) self.w_door_opened.pack(side=tk.TOP, fill=tk.X, pady=(8, 0)) self.w_door_closed.pack(side=tk.TOP, fill=tk.X) right_frame = tk.LabelFrame(self, text='COMPONENTS') right_frame.pack(side=tk.LEFT, fill=tk.BOTH, padx=(8, 8)) # Door component self.w_doorsensor_frame = tk.LabelFrame(right_frame, text='Door') self.w_doorsensor_frame.pack(side=tk.TOP, fill=tk.BOTH) self.w_doorsensor = tk.Label(self.w_doorsensor_frame) self.w_doorsensor.config(text='closed') self.w_doorsensor.pack(side=tk.TOP) # Weightsensor component self.w_weightsensor_frame = tk.LabelFrame(right_frame, text='Weight sensor') self.w_weightsensor_frame.pack(side=tk.TOP, fill=tk.BOTH) self.w_weightsensor = tk.Label(self.w_weightsensor_frame) self.w_weightsensor.config(text='no item') self.w_weightsensor.pack(side=tk.TOP) # Display component self.w_display_frame = tk.LabelFrame(right_frame, text='Display') self.w_display_frame.pack(side=tk.TOP, fill=tk.BOTH) self.w_display = tk.Label(self.w_display_frame) self.w_display.pack(side=tk.TOP) # Lamp component self.w_lamp_frame = tk.LabelFrame(right_frame, text='Lamp') self.w_lamp_frame.pack(side=tk.TOP, fill=tk.BOTH) self.w_lamp = tk.Label(self.w_lamp_frame) self.w_lamp.pack(side=tk.TOP) # Heating component self.w_heating_frame = tk.LabelFrame(right_frame, text='Heating') self.w_heating_frame.pack(side=tk.TOP, fill=tk.BOTH) self.w_heating_power = tk.Label(self.w_heating_frame) self.w_heating_status = tk.Label(self.w_heating_frame) self.w_heating_power.pack(side=tk.TOP) self.w_heating_status.pack(side=tk.TOP) # Beeper component self.w_beep_frame = tk.LabelFrame(right_frame, text='Beeper') self.w_beep_frame.pack(side=tk.TOP, fill=tk.BOTH) self.w_beep = tk.Label(self.w_beep_frame) self.w_beep.pack(side=tk.TOP) # Turntable component self.w_turntable_frame = tk.LabelFrame(right_frame, text='Turntable') self.w_turntable_frame.pack(side=tk.TOP, fill=tk.BOTH) self.w_turntable = tk.Label(self.w_turntable_frame) self.w_turntable.pack(side=tk.TOP) def event_handler(self, event): name = event.name if name == 'lamp_switch_on': self.w_lamp['text'] = 'on' elif name == 'lamp_switch_off': self.w_lamp['text'] = 'off' elif name == 'display_set': self.w_display['text'] = event.text elif name == 'display_clear': self.w_display['text'] = '' elif name == 'heating_set_power': self.w_heating_power['text'] = event.power elif name == 'heating_on': self.w_heating_status['text'] = 'on' elif name == 'heating_off': self.w_heating_status['text'] = 'off' elif name == 'beep': self.w_beep['text'] = event.number elif name == 'turntable_start': self.w_turntable['text'] = 'on' elif name == 'turntable_stop': self.w_turntable['text'] = 'off' else: raise ValueError('Unknown event %s' % event) def on_autotick(self): if self.v_autotick.get(): self.send_event('timer_tick') self.after(1000, self.on_autotick) def send_event(self, event_name): if event_name == 'item_placed': self.w_weightsensor.config(text='item detected') elif event_name == 'item_removed': self.w_weightsensor.config(text='no item') elif event_name == 'door_opened': self.w_doorsensor.config(text='open') elif event_name == 'door_closed': self.w_doorsensor.config(text='closed') self.interpreter.queue(Event(event_name)) self.execute() def _quit(self): self.master.destroy()