# Script to automatically Schedule trains # # Author: Bill Fitch, copyright 2020 # Part of the JMRI distribution # Description: # We scan the operations:trains table and get a list of the trains that need to be scheduled # in SchedulerMaster init we set up a listener which triggers every minute # in the appropriate minute in the listener we append the train to the trains_to_be_scheduled # in SchedulerMaster handle we process trains_to_be_scheduled by running run_trains(trains_to_be_scheduled) # run_trains sets up a thread which moves the train, and removed the train from the trains_to_be_scheduled list from javax.swing import JFrame, JPanel, JButton, BoxLayout, Box, JComponent, BorderFactory, JLabel, JTextField from java.awt import GridLayout from java.awt import Color, Font from java.awt import Dimension, FlowLayout from java.beans import PropertyChangeEvent from java.awt.event import FocusAdapter, ActionListener from javax.swing import SwingWorker, SwingUtilities import os import copy import jmri import java import time from org.python.core.util import StringUtil from threading import Thread from collections import Counter # from javax.swing import JFrame # from java.awt.event import WindowAdapter from java.util.concurrent import CountDownLatch CreateSchedulerPanel = jmri.util.FileUtil.getExternalFilename('program:jython/DispatcherSystem/SchedulerPanel.py') execfile(CreateSchedulerPanel) CreateRoutesPanel = jmri.util.FileUtil.getExternalFilename('program:jython/DispatcherSystem/RoutesPanel.py') execfile(CreateRoutesPanel) CreateEditRoutePanel = jmri.util.FileUtil.getExternalFilename('program:jython/DispatcherSystem/EditRoutePanel.py') execfile(CreateEditRoutePanel) CreateEditRoutePanel = jmri.util.FileUtil.getExternalFilename('program:jython/DispatcherSystem/Timetable.py') execfile(CreateEditRoutePanel) try: basestring except NameError: basestring = str if "list" in globals() and type(globals()["list"]).__name__ != "type": # print(" Detected shadowed 'list' type: ", type(globals()["list"])) # list is being used in JMRI. This enables us to use list in Jython del globals()["list"] CreateEditRoutePanel = jmri.util.FileUtil.getExternalFilename('program:jython/DispatcherSystem/DisplayMqttTimetable.py') execfile(CreateEditRoutePanel) trains_to_be_scheduled = [] run_train_dict = {} scheduled = {} RunTrain_instance = {} tListener = None class SchedulerMaster(jmri.jmrit.automat.AbstractAutomaton): def __init__(self): global scheduling_in_operation_gbl self.logLevel = 0 self.frame = None self.f = None scheduling_in_operation_gbl = False self.od = OptionDialog() def exit(self): # called explicitly when scheduler thread is killed to stop multiple frames being visible try: self.frame.setVisible(False) self.f.setVisible(False) if "timetable_frame_gbl" in globals(): timetable_frame_gbl.setVisible(False) except: pass def setup(self): global schedule_trains_hourly global schedule_trains_glb global scheduling_in_operation_gbl # schedule trains initially # schedule_trains_glb = False scheduling_in_operation_gbl = "False" self.stop_schedule_trains_master() #don't really need this. # print "scheduling_in_operation_gbl 6 start setup", scheduling_in_operation_gbl # self.ToggleSchedulingtrains_action(None) # Toggle schedule_trains_glb # print "scheduling_in_operation_gbl 6a", scheduling_in_operation_gbl if 'schedule_trains_hourly' not in globals(): schedule_trains_hourly = False #run before setting up Schedule Master if self.logLevel > 0: print "starting SchedulerMaster setup" self.scheduler_master_sensor = sensors.getSensor("startSchedulerSensor") self.scheduler_view_scheduled_trains = sensors.getSensor("viewScheduledSensor") self.scheduler_edit_routes = sensors.getSensor("editRoutesSensor") self.scheduler_show_clock_sensor = sensors.getSensor("showClockSensor") self.timetable_sensor = sensors.getSensor("timetableSensor") self.departure_time_sensor = sensors.getSensor("departureTimeSensor") self.help_sensor = sensors.getSensor("helpSensor") if self.logLevel > 0: print "finished SchedulerMaster setup" if self.logLevel > 0: print "returned from setup" # print "scheduling_in_operation_gbl 7 end setup", scheduling_in_operation_gbl return True def init(self): global run_local_timetable_gbl # print "scheduling_in_operation_gbl 7 - init", scheduling_in_operation_gbl if "run_timetable_gbl" not in globals(): run_local_timetable_gbl = False self.train_scheduler_setup = False # print "scheduling_in_operation_gbl 7 - init end", scheduling_in_operation_gbl if self.logLevel > 0: print "returned from init" showing_clock = False showing_trains = False def handle(self): # print "start handle 0" global schedule_trains_hourly global schedule_trains_glb global run_local_timetable_gbl global station_name_list_gbl global station_name_list_mqtt_gbl global group_location_gbl global timetable_triggered_gbl if self.logLevel > 0: print "start handle" # print "start handle" # print "scheduling_in_operation_gbl 7 handle", scheduling_in_operation_gbl self.button_sensors_to_watch = [self.scheduler_master_sensor, self.scheduler_view_scheduled_trains, \ self.scheduler_edit_routes, \ self.scheduler_show_clock_sensor, self.timetable_sensor, \ self.departure_time_sensor, self.help_sensor] button_sensors_to_watch_JavaList = java.util.Arrays.asList(self.button_sensors_to_watch) self.waitSensorState(button_sensors_to_watch_JavaList, ACTIVE) # print "Z" if self.departure_time_sensor.getKnownState() == ACTIVE: self.set_departure_trains() # print "ZZ" self.departure_time_sensor.setKnownState(INACTIVE) # print "Y" if self.timetable_sensor.getKnownState() == ACTIVE: title = "" # if "station_name_list_gbl" not in globals(): # station_name_list_gbl = "" # print "b" TrainManager=jmri.InstanceManager.getDefault(jmri.jmrit.operations.trains.TrainManager) train_list = TrainManager.getTrainsByTimeList() my_scheduled_route_list = [train.getRoute() for train in train_list] if None in my_scheduled_route_list: OptionDialog().displayMessage("check scheduled routes are entered correctly\ncannot proceed with timetable") else: # print "my_scheduled_route_list", my_scheduled_route_list # print "c" RouteManager=jmri.InstanceManager.getDefault(jmri.jmrit.operations.routes.RouteManager) # print "d" station_list = [] for route in my_scheduled_route_list: route_locations_list = route.getLocationsBySequenceList() # print "route", route.getName(), "route_locations_list", route_locations_list station_list1 = [str(route_location.getName()) for route_location in route_locations_list \ if ".py" not in route_location.getName()] # print "e" , "station_list1", station_list1 for x in station_list1: if x not in station_list: station_list.append(x) station_list.sort() # print "station_list", station_list repeat = True while repeat: # get station_group list platform_list = [] station_group_list = [] station_group_list.append("All Stations") station_group_location_list = [] PlatformPanel = MyTableModel7() for location_name in station_list: LocationManager=jmri.InstanceManager.getDefault(jmri.jmrit.operations.locations.LocationManager) location = LocationManager.getLocationByName(location_name) platform = PlatformPanel.get_location_platform(location) station_group = PlatformPanel.get_location_station_group(location) if station_group.strip() is not None and station_group.strip() is not "": if station_group.strip() not in station_group_list: station_group_list.append(station_group.strip()) # print "type station_group", type(station_group.strip()) station_group_location_list.append([station_group.strip(), location_name]) station_group_location_list.append(["All Stations", location_name]) if self.logLevel > 0: print "station list", station_list msg = "timetables can be shown locally on this computer or\n" + \ "on remote computers/tablets communicating by mqtt\n\n" + \ "scheduler needs to be on and clock running" opt0 = "Cancel" if run_local_timetable_gbl == True: opt1 = "hide local timetable" else: opt1 = "show local timetable" opt4 = "set platforms and station groups" opt2 = "select station for local timetable" opt3 = "mqtt timetables" if 'timetable_triggered_gbl' not in globals(): reply = OptionDialog().customQuestionMessage4str(msg, title, opt0, opt4, opt2, opt3) else: reply = OptionDialog().customQuestionMessage5str(msg, title, opt0, opt1, opt4, opt2, opt3) # print "reply", reply if self.logLevel > 0: print "timetable_sensor active" if reply == OptionDialog().CLOSED_OPTION or reply == opt0: repeat = False elif reply == opt1: if run_local_timetable_gbl == True: run_local_timetable_gbl = False else: run_local_timetable_gbl = True elif reply == opt4: gui7 = CreateAndShowGUI7() # Create a latch that waits for CreateAndShowGUI7 frame to be closed # In CreateAndShowGUI7 the latch is decremented whe the frame is closed global latch latch = CountDownLatch(1) # Wait until the frame is closed latch.await() reply = True elif reply == opt2: repeat1 = True select_from_stations = True while repeat1 == True: if "station_name_list_gbl" not in globals(): station_name_list_gbl = "" list_items_no_trains = self.get_scheduled_routes("no_train") list_items_with_trains = self.get_scheduled_routes("with_train") if select_from_stations: title = "select station(s) for timetable - only stations on scheduled routes are shown" options = ["Cancel", "Select from Station Groups", "Show Timetable"] result = OptionDialog().MultipleListOptions(station_list, title, options, preferred_size = "default") else: title = "select station_group for timetable" options = ["Cancel", "Select from Stations", "Show Timetable"] result = OptionDialog().ListOptions(station_group_list, title, options, preferred_size = "default") option = result[1] if option == "Cancel" or self.od.CLOSED_OPTION == True: run_local_timetable_gbl = False self.timetable_sensor.setKnownState(INACTIVE) repeat1 = False elif option == "Show Timetable": if select_from_stations: station_name_list_gbl = result[0] # get group_station_name if len(station_name_list_gbl) == 1: group_location_gbl = station_name_list_gbl[0] # the first and only station station1 else: group_location_gbl = self.get_group_station_name(station_name_list_gbl) else: group_location_gbl = result[0] # get station list station_name_list = [] for l in station_group_location_list: if l[0] == group_location_gbl: station_name_list.append(l[1]) station_name_list_gbl = station_name_list run_local_timetable_gbl = True self.ensure_conditions_for_timetable_to_show_are_met() repeat1 = True else: if select_from_stations == True: select_from_stations = False else: select_from_stations = True repeat1 = True repeat = True elif reply == opt3: repeat = True while repeat: title = "MQTT timetables" msg = "timetables can be shown on remote computers/tablets communicating by mqtt\n\n" + \ "scheduler needs to be on and clock running" opt0 = "Cancel" opt1 = "Generate mqtt timetable" opt2 = "View/delete mqtt timetables" opt3 = "Display mqtt timetables" reply = OptionDialog().customQuestionMessage4str(msg, title, opt0, opt1, opt2, opt3) if self.od.CLOSED_OPTION == True or reply == opt0: repeat = False elif reply == opt1: select_from_stations = True if "station_name_list_gbl" not in globals(): station_name_list_gbl = "" list_items_no_trains = self.get_scheduled_routes("no_train") list_items_with_trains = self.get_scheduled_routes("with_train") if select_from_stations: title = "select station(s) for timetable - only stations on scheduled routes are shown" options = ["Cancel", "Select from Station Groups", "Generate Timetable"] result = OptionDialog().MultipleListOptions(station_list, title, options, preferred_size = "default") else: title = "select station_group for timetable" options = ["Cancel", "Select from Stations", "Generate Timetable"] result = OptionDialog().ListOptions(station_group_list, title, options, preferred_size = "default") option = result[1] if option == "Cancel" or self.od.CLOSED_OPTION == True: run_local_timetable_gbl = False self.timetable_sensor.setKnownState(INACTIVE) repeat = False elif option == "Generate Timetable": if select_from_stations: station_name_list_mqtt_gbl = result[0] # get group_station_name if len(station_name_list_gbl) == 1: group_location_mqtt_gbl = station_name_list_gbl[0] # the first and only station station1 else: group_location_mqtt_gbl = self.get_group_station_name(station_name_list_mqtt_gbl) print "group_location_mqtt_gbl", group_location_mqtt_gbl else: group_location_mqtt_gbl = result[0] # print "group_location_mqtt_gbl", group_location_mqtt_gbl # get station list station_name_list = [] for l in station_group_location_list: if l[0] == group_location_mqtt_gbl: station_name_list.append(l[1]) station_name_list_mqtt_gbl = station_name_list # print "station_name_list_mqtt_gbl", station_name_list_mqtt_gbl # get emblem title = "Display Train Operator Emblem?" emblem_list = ["GB (British Rail)", "Germany (DB)", "No Emblem"] options = ["Cancel", "Generate Timetable"] result = self.od.ListOptions(emblem_list, title, options, preferred_size = "default") # print "result", result train_operator_emblem = result[0] option1 = result[1] if option1 == "Cancel" or self.od.CLOSED_OPTION == True: # run_local_timetable_gbl = False self.timetable_sensor.setKnownState(INACTIVE) else: self.generate_node_red_code(station_name_list_mqtt_gbl, group_location_mqtt_gbl, train_operator_emblem) self.write_list2([train_operator_emblem]) repeat = True else: if select_from_stations == True: select_from_stations = False else: select_from_stations = True repeat = True elif reply == opt2: # view/delete mqtt timetables msg = "The generated timetables are saved in the following directory \n" +\ "Delete any that are not required" OptionDialog().displayMessage(msg) self.view_delete_mqtt_timetables() repeat = True elif reply == opt3: # display mqtt timetables msg = "Will attempt to display all generated timetables in default browser \n" +\ "If Node Red is installed the timetables will be displayed \n" + \ "If MQTT is set up in jmri and mosquitto is running the timetables will work \n" +\ " when the scheduler is running" OptionDialog().displayMessage(msg) dmt = DisplayMqttTimetable() repeat = True repeat = True self.timetable_sensor.setKnownState(INACTIVE) if self.scheduler_master_sensor.getKnownState() == ACTIVE: # pause processing if we turn the sensor off if self.logLevel > 0: print("checking valid operations trains") if self.logLevel > 0: print "train_scheduler_setup",self.train_scheduler_setup # # check whether can/want to schedule trains every hour # schedule_trains_hourly = self.check_whether_schedule_trains_every_hour() # print "scheduling_in_operation_gbl 8", scheduling_in_operation_gbl self.set_default_scheduling_values() # print "scheduling_in_operation_gbl 70", scheduling_in_operation_gbl self.set_period_trains_will_run_frame() # print "scheduling_in_operation_gbl 71", scheduling_in_operation_gbl self.show_analog_clock() # show the analog clock # set time to midnight if self.logLevel > 0: print "set minute time listener" global minute_time_listener_setup if "minute_time_listener_setup" not in globals(): minute_time_listener_setup = False if minute_time_listener_setup == False: self.setup_minute_time_listener_to_schedule_trains() # only do this first time setup self.train_scheduler_setup = True self.scheduler_master_sensor.setKnownState(INACTIVE) if self.scheduler_view_scheduled_trains.getKnownState() == ACTIVE: self.show_operations_trains() self.scheduler_view_scheduled_trains.setKnownState(INACTIVE) if self.scheduler_edit_routes.getKnownState() == ACTIVE: self.show_routes() self.scheduler_edit_routes.setKnownState(INACTIVE) if self.scheduler_show_clock_sensor.getKnownState() == ACTIVE: self.show_analog_clock() self.scheduler_show_clock_sensor.setKnownState(INACTIVE) if self.help_sensor.getKnownState() == ACTIVE: self.display_help() self.help_sensor.setKnownState(INACTIVE) self.waitMsec(500) if self.logLevel > 0: print "end handle" # print "scheduling_in_operation_gbl 7 handle end", scheduling_in_operation_gbl # print "F" return True def mqtt_timetable_directory(self): path = jmri.util.FileUtil.getUserFilesPath() + "dispatcher" + java.io.File.separator + "mqtt_timetables" if not os.path.exists(path): os.makedirs(path) return path + java.io.File.separator def view_delete_mqtt_timetables(self): dir = self.mqtt_timetable_directory() j = JFileChooser(dir); j.setAcceptAllFileFilterUsed(False) filter = FileNameExtensionFilter("json files json", ["json"]) j.addChoosableFileFilter(filter); j.setDialogTitle("Delete not wanted mqtt timetables"); ret = j.showDialog(None, "Delete"); if ret == JFileChooser.APPROVE_OPTION: file = j.getSelectedFile() if file == "" or file == None: return if file.exists(): os.remove(file.getAbsolutePath()) # print("File " + file.getName() + " has been deleted successfully.") else: print("The selected file does not exist.") else: print("File selection cancelled.") return def get_group_station_name(self, station_name_list_gbl): # print "station_name_list_gbl", station_name_list_gbl concatenated_names = " ".join(station_name_list_gbl) # [station1,station2] print "concatenated_names", concatenated_names station_groups = [] for station_name in station_name_list_gbl: LocationManager=jmri.InstanceManager.getDefault(jmri.jmrit.operations.locations.LocationManager) location = LocationManager.getLocationByName(station_name) station_group = MyTableModel7().get_location_station_group(location) print "station_name", station_name, "station_group", station_group.replace(" ", "*") if station_group != "" and station_group != " ": station_groups.append(station_group) # print "appending station_groups", station_groups counter = Counter(station_groups) print "counter", counter print "counter.most_common(1)", counter.most_common(1) most_common_item = " " if counter.most_common() != []: most_common_item = counter.most_common(1)[0][0] print "most_common_item", most_common_item if most_common_item != " ": group_location_gbl = most_common_item.strip() # need an option to rename this else: group_location_gbl = concatenated_names print "group_location_gbl", group_location_gbl return group_location_gbl def ensure_conditions_for_timetable_to_show_are_met(self): global scheduling_in_operation_gbl global timebase global start_hour_gbl, end_hour_gbl if "timebase" not in globals(): timebase = jmri.InstanceManager.getDefault(jmri.Timebase) if "start_hour_gbl" not in globals(): start_hour_gbl = None if start_hour_gbl == None: # check if Start Scheduler has been run sm = SchedulerMaster() # if not set up everything which would have been run sm.set_default_scheduling_values() # sm.set_period_trains_will_run_frame() # sm.show_analog_clock() # show the analog clock sm.setup_minute_time_listener_to_schedule_trains() sm.train_scheduler_setup = True if timebase.getRun() == False: # get the current time without using timebase date = jmri.implementation.DefaultClockControl().getTime() calendar = java.util.Calendar.getInstance() calendar.setTime(date) minute = calendar.get(calendar.MINUTE) # Manually create and trigger a PropertyChangeEvent # have to call it twice to get the timetable to display event = PropertyChangeEvent("TimeSource", "time",(minute - 2) % 60, (minute - 1) % 60) TimeListener().propertyChange(event) # Directly call the listener's method event = PropertyChangeEvent("TimeSource", "time", (minute - 1) % 60, minute) TimeListener().propertyChange(event) else: # print "should be OK to show timetable" pass def generate_node_red_code(self, station_name_list, station_name, train_operator_emblem): node_red_template_path = \ jmri.util.FileUtil.getExternalFilename('program:jython/DispatcherSystem/timetable_template/node_red_flow.json"') # read the file into a string #check if file is present if os.path.isfile(node_red_template_path): #open text file in read mode text_file = open(node_red_template_path, "r") #read whole file to a string data = text_file.read() #close file text_file.close() # create a unique reference for the websocketout node import uuid id = str(uuid.uuid1()) # change the file to work with station_name # websocket names cannot have spaces in them # so where we need to replace spaces we have My_Station$ instead of MyStation new_data = (data.replace('My_Station$_ref', id) \ .replace('My_Station$', station_name.replace(" ","-")) \ .replace("My_Station_List", str(station_name_list)) \ .replace("My_Station", station_name) \ .replace("My_Emblem", train_operator_emblem)) # 'My_Station$' for url without spaces # "My_Station" for title # "My_Station_List" for list of stations to include # store the modified file to a file in the user directory new_node_red_template_directory = jmri.util.FileUtil.getExternalFilename('preference:dispatcher/mqtt_timetables/') #create the folder if it does not exist if not os.path.exists(new_node_red_template_directory): os.makedirs(new_node_red_template_directory) file_path = new_node_red_template_directory + java.io.File.separator + station_name + ".json" f = open(file_path, "w") f.write(new_data) f.close() else: OptionDialog().displayMessage(file_path + "does not exist, reinstall latest JMRI") msg = "node red file for '" + station_name + "' is in " + file_path + "\n" + \ "import the file into a node_red instance on computer on same network \n" + \ "and edit as illustrated in the help, and open indicated web page on tablet/laptop \n" + \ "e.g. http://localhost:1880/" + station_name.replace(" ", "-") + ", where localhost should be replaced by network address \n" + \ "of computer hosting node_red instance\n\n" + \ "Note any spaces in the station name have been replaced by hyphens in the web address\n\n" + \ "ALSO ensure an MQTT Connection is set up in preferences, as detailed in help." OptionDialog().displayMessage(msg) def set_departure_trains(self): # allow running of scheduled routes to set journey times and wait times, # which allow durations and departure times to be set up # print "set departure trains" global wait_time_gbl global scheduled global scheduling_margin_gbl global set_departure_trains_gbl global CreateAndShowGUI5_glb set_departure_trains_gbl = True self.set_default_scheduling_values() msg = "Set Departure Times" opt1 = "set wait time in stations" opt2 = "run train on route to set journey times" opt3 = "set departure times manually" reply = OptionDialog().customQuestionMessage3str(msg, "", opt1, opt2, opt3) if reply == opt1: memory = memories.getMemory("IM:" + "DS_wait_time") # print "memory", type(memory) if memory is None or memory.getValue() == "": memory = memories.provideMemory("IM:" + "DS_wait_time") memory.setValue(3) title = "wait time at station" msg = "set wait time at all stations" default_value = str(memory.getValue()) wait_time = OptionDialog().input(msg, title, default_value) # memory = memories.getMemory("IM:" + "DS_wait_time") if memory is not None: memory.setValue(wait_time) # print "wait_time", wait_time return elif reply == opt2: list_items_no_trains = self.get_scheduled_routes("no_train") # print "list_items_no_trains", list_items_no_trains list_items_with_trains = self.get_scheduled_routes("with_train") # print "list_items_with_trains", list_items_with_trains list_items_starting_from_occupied_blocks = self.get_routes_starting_from_occupied_blocks() # print "list_items_starting_from_occupied_blocks", list_items_starting_from_occupied_blocks show_trains_in_occupied_blocks = True repeat = True while repeat: if show_trains_in_occupied_blocks: title = "Select Route to Record Journey Times: Showing routes from occupied blocks" options = ["Cancel", "Run Route", "Show all scheduled routes"] reply1 = OptionDialog().ListOptions(list_items_starting_from_occupied_blocks, title, options, preferred_size = "default") else: title = "Select Route to Record Journey Times: Showing scheduled routes" options = ["Cancel", "Run Route", "Show routes starting from occupied blocks"] reply1 = OptionDialog().ListOptions(list_items_no_trains, title, options, preferred_size = "default") my_list = reply1[0] route_name = str(my_list) option = str(reply1[1]) if OptionDialog().CLOSED_OPTION == True or option == "Cancel": # print "cancelling" return elif option == "Run Route": # print "Run Route" train_array = [trn for [rte, trn] in list_items_with_trains if str(rte) == route_name] if len(train_array) == 0: OptionDialog().displayMessage("Selected route is not on the scheduled list - try again") return else: train = train_array[0] set_departure_times = True param_scheduled_start = "00:00" journey_time_row_displayed = True if "CreateAndShowGUI5_glb" in globals(): if CreateAndShowGUI5_glb != None: CreateAndShowGUI5_glb.frame.dispose() CreateAndShowGUI5_glb = CreateAndShowGUI5(None, route_name, param_scheduled_start, journey_time_row_displayed = journey_time_row_displayed) title = "Run Train" msg = "Last time to cancel" opt1 = "Cancel" opt2 = "Run Train" reply = OptionDialog().customQuestionMessage2str(msg, title, opt1, opt2) if reply == JOptionPane.CANCEL_OPTION or reply == opt1: CreateAndShowGUI5_glb.frame.dispose() return OptionDialog().displayMessageNonModal("Run Train along route " + str(route_name) + " now","Check train is in required station
Then click to run route") # print "Ended non modal, wait for non modal" self.waitForNonModal() # print "finished wait for non modal" if self.logLevel > 0: print "running train %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", train.getDescription(), train.getName() # running_train = RunTrain(train, g.g_stopping, set_departure_times) route = train.getRoute() routeName = route.getName() station_from, station_to = self.get_first_and_last_station(route) # starting from beginning of route if self.logLevel > 0: print "station_from", station_from, "station_to", station_to start_block = blocks.getBlock(station_from) if self.logLevel > 0: "start_block",start_block, "station_to", station_to train_name = start_block.getValue() no_repetitions = 0 delay_val = 0 # print "%%%%%%%%%%%%%%train_name%%%%%%%%%%%%%%", train_name if train_name is None: OptionDialog().displayMessage("No train is in the start position \n\n(maybe it has not been set up so the system recognises it)\npress setup train - register the train - and try again") return else: # print "train_name is not none" pass if "stopping" in train.getDescription(): if self.logLevel > 0: print "A" run_train = RunRoute(route, g.g_stopping, station_from, station_to, no_repetitions, train_name, \ set_departure_times = True) run_train.setName("running_route_" + routeName) instanceList.append(run_train) run_train.start() else: if self.logLevel > 0: print "B" run_train = RunRoute(route, g.g_express, station_from, station_to, no_repetitions, train_name, \ set_departure_times = True) run_train.setName("running_route_" + routeName) instanceList.append(run_train) run_train.start() repeat = False else: if show_trains_in_occupied_blocks == True: show_trains_in_occupied_blocks = False else: show_trains_in_occupied_blocks = True repeat = True return elif reply == opt3: list_items_no_trains = self.get_scheduled_routes("no_train") # print "list_items_no_trains", list_items_no_trains list_items_with_trains = self.get_scheduled_routes("with_train") # print "list_items_with_trains", list_items_with_trains list_items_all_routes = self.get_all_routes() # print "list_items_all_routes", list_items_all_routes show_all_routes = True repeat = True while repeat: if show_all_routes: title = "Select Route to Record Journey Times: Showing all routes" options = ["Cancel", "Set Departure Times", "Show scheduled routes"] reply1 = OptionDialog().ListOptions(list_items_all_routes, title, options, preferred_size = "default") else: title = "Select Route to Record Journey Times: Showing scheduled routes" options = ["Cancel", "Set Departure Times", "Show all routes"] reply1 = OptionDialog().ListOptions(list_items_no_trains, title, options, preferred_size = "default") my_list = reply1[0] option = reply1[1] route_name = str(my_list) option = str(option) if OptionDialog().CLOSED_OPTION == True or option == "Cancel": # print "cancelling" return elif option == "Set Departure Times": param_scheduled_start = "00:00" journey_time_row_displayed = True if "CreateAndShowGUI5_glb" not in globals(): CreateAndShowGUI5_glb = CreateAndShowGUI5(None, route_name, param_scheduled_start, journey_time_row_displayed = journey_time_row_displayed) else: CreateAndShowGUI5_glb.frame.dispose() CreateAndShowGUI5_glb = CreateAndShowGUI5(None, route_name, param_scheduled_start, journey_time_row_displayed = journey_time_row_displayed) repeat = False else: if show_all_routes == True: show_all_routes = False else: show_all_routes = True repeat = True return def get_first_and_last_station(self, route): routelocationsSequenceNumber_list = [ [routelocation, routelocation.getSequenceNumber()] \ for routelocation in route.getLocationsBySequenceList() \ if ".py" not in routelocation.getName()] if self.logLevel > 0: print "routelocationsSequenceNumber_list", routelocationsSequenceNumber_list first_routelocation = [routelocation \ for [routelocation, sequenceNo] in routelocationsSequenceNumber_list \ ][0] last_routelocation = [routelocation \ for [routelocation, sequenceNo] in routelocationsSequenceNumber_list \ ][-1] if self.logLevel > 0: print "routelocation", routelocation return [str(first_routelocation), str(last_routelocation)] # row number starts from 0 def waitForNonModal(self): Jdialog_closed = sensors.getSensor("Jdialog_closed") Jdialog_closed.setKnownState(INACTIVE) btn = [Jdialog_closed] btn_to_watch = java.util.Arrays.asList(btn) # print "waiting for button" , Jdialog_closed.getKnownState() self.waitSensorState(btn_to_watch, ACTIVE) def get_scheduled_routes(self, option): TrainManager=jmri.InstanceManager.getDefault(jmri.jmrit.operations.trains.TrainManager) train_list = TrainManager.getTrainsByTimeList() if option == "with_train": my_list = [[train.getRoute().getName() if train is not None else "" , train] for train in train_list if train.getRoute() is not None] else: my_list = [train.getRoute().getName() if train is not None else "" for train in train_list if train.getRoute() is not None] return sorted(my_list) def get_routes_starting_from_occupied_blocks(self): RouteManager=jmri.InstanceManager.getDefault(jmri.jmrit.operations.routes.RouteManager) route_list = RouteManager.getRoutesByNameList() my_list = [route.getName() for route in route_list if blocks.getBlock(route.getLocationsBySequenceList()[0].getName()).getSensor().getState() == ACTIVE ] return sorted(my_list) def get_all_routes(self): RouteManager=jmri.InstanceManager.getDefault(jmri.jmrit.operations.routes.RouteManager) route_list = RouteManager.getRoutesByNameList() my_list = [route.getName() for route in route_list ] return sorted(my_list) def start_and_end_time_scheduling(self): if self.logLevel > 0: print "start_and_end_time_scheduling" TrainManager=jmri.InstanceManager.getDefault(jmri.jmrit.operations.trains.TrainManager) train_list = TrainManager.getTrainsByTimeList() start_time_hour = 23 end_time_hour = 0 for train in train_list: train_hour = int(train.getDepartureTimeHour()) if train_hour < start_time_hour: start_time_hour = train_hour else: pass if train_hour > end_time_hour: end_time_hour = train_hour else: pass # print "[start_time_hour, end_time_hour]", [start_time_hour, end_time_hour] if self.logLevel > 0: print "start_and_end_time_scheduling end" return [start_time_hour, end_time_hour] def set_period_trains_will_run_frame(self): global start_hour_gbl, end_hour_gbl, fast_clock_rate, speed_not_operational_gbl, \ scheduling_margin_gbl, scheduling_in_operation_gbl if self.frame == None: # print "frame is None" self.frame = jmri.util.JmriJFrame('Schedule Trains'); panel = JPanel() panel.setLayout(BoxLayout(panel, BoxLayout.Y_AXIS)) self.frame.add(panel) row0 = JPanel() row0.setLayout(BoxLayout(row0, BoxLayout.X_AXIS)) txt = JTextField(140) txt.setMaximumSize( txt.getPreferredSize() ); txt.setBorder(BorderFactory.createCompoundBorder( BorderFactory.createLineBorder(Color.red), txt.getBorder())); label_panel_location = JLabel() # btnpanelLocation = JButton("Set Panel Location", actionPerformed = btnpanelLocation_action) btnpanelLocation = JButton("Set Panel Location") row0.add(Box.createVerticalGlue()) row0.add(Box.createRigidArea(Dimension(20, 0))) row0.add(btnpanelLocation) row0.add(Box.createRigidArea(Dimension(20, 0))) row0.add(label_panel_location) row0.add(Box.createRigidArea(Dimension(20, 0))) rowTitle_22 = JPanel() rowTitle_22.setLayout(BoxLayout(rowTitle_22, BoxLayout.X_AXIS)) rowTitle_23 = JPanel() rowTitle_23.setLayout(BoxLayout(rowTitle_23, BoxLayout.X_AXIS)) rowStage1Title_1 = JLabel("Sets Up System to run hourly trains ") rowStage1Title_1.setFont(rowTitle_22.getFont().deriveFont(Font.BOLD, 13)); # get_start_filename() # get_backup_filename() # rowStage1Title_1 = JLabel(" Modifies: " + start_filename + " Creates backup: " + backup_filename) # rowStage1Title_1.add(Box.createHorizontalGlue()); # rowStage1Title_1.setAlignmentX(rowStage1Title_1.LEFT_ALIGNMENT) # rowStage1Title_2 = JLabel("Run Scheduled Trains") # rowStage1Title_3 = JLabel(" Read Help to see how system works") #start_filename + "_icons" rowTitle_22.add(Box.createVerticalGlue()) rowTitle_22.add(Box.createRigidArea(Dimension(20, 0))) rowTitle_22.add(rowStage1Title_1) # rowTitle_22.add(Box.createRigidArea(Dimension(20, 0))) # rowTitle_22.add(rowStage1Title_2) # rowTitle_22.add(Box.createVerticalGlue()) # rowTitle_22.add(Box.createRigidArea(Dimension(20, 0))) # rowTitle_22.add(JLabel("")) # rowTitle_23.add(rowStage1Title_3) rowTitle_33 = JPanel() rowTitle_33.setLayout(BoxLayout(rowTitle_33, BoxLayout.X_AXIS)) rowTitle_33.add(Box.createVerticalGlue()) rowTitle_33.add(Box.createRigidArea(Dimension(30, 0))) rowTitle_33.add(rowStage1Title_1) # buttons rowStage1Button = JPanel() rowStage1Button.setLayout(BoxLayout(rowStage1Button, BoxLayout.X_AXIS)) global rowrowStage4Button_4, rowAStage1Button_1, rowBStage1Button_1, rowCStage1Button_1, rowDStage1Button_1, rowEStage1Button_1, rowFStage1Button_1 rowAStage1Button = JPanel() rowAStage1Button.setLayout(BoxLayout(rowAStage1Button, BoxLayout.X_AXIS)) rowBStage1Button = JPanel() rowBStage1Button.setLayout(BoxLayout(rowBStage1Button, BoxLayout.X_AXIS)) rowCStage1Button = JPanel() rowCStage1Button.setLayout(BoxLayout(rowCStage1Button, BoxLayout.X_AXIS)) rowDStage1Button = JPanel() rowDStage1Button.setLayout(BoxLayout(rowDStage1Button, BoxLayout.X_AXIS)) rowEStage1Button = JPanel() rowEStage1Button.setLayout(BoxLayout(rowEStage1Button, BoxLayout.X_AXIS)) rowFStage1Button = JPanel() rowFStage1Button.setLayout(BoxLayout(rowFStage1Button, BoxLayout.X_AXIS)) rowrowStage1Button_1 = JLabel("Change parameters to run trains") rowrowStage1Button_1.setFont(rowTitle_22.getFont().deriveFont(Font.BOLD, 13)); rowrowStage1Button_1.add(Box.createHorizontalGlue()); rowrowStage1Button_1.setAlignmentX(rowrowStage1Button_1.LEFT_ALIGNMENT) stringToDisplay = "start hour: " + str(start_hour_gbl) rowAStage1Button_1 = JLabel(stringToDisplay) rowAStage1Button_1.setFont(rowTitle_22.getFont().deriveFont(Font.BOLD, 13)); rowAStage1Button_1.add(Box.createHorizontalGlue()); rowAStage1Button_1.setAlignmentX(rowAStage1Button_1.LEFT_ALIGNMENT) stringToDisplay = "end hour: " + str(end_hour_gbl) rowBStage1Button_1 = JLabel(stringToDisplay) rowBStage1Button_1.setFont(rowTitle_22.getFont().deriveFont(Font.BOLD, 13)); rowBStage1Button_1.add(Box.createHorizontalGlue()); rowBStage1Button_1.setAlignmentX(rowBStage1Button_1.LEFT_ALIGNMENT) stringToDisplay = "fast clock (when scheduling trains): x " + str(fast_clock_rate) rowCStage1Button_1 = JLabel(stringToDisplay) rowCStage1Button_1.setFont(rowTitle_22.getFont().deriveFont(Font.BOLD, 13)); rowCStage1Button_1.add(Box.createHorizontalGlue()); rowCStage1Button_1.setAlignmentX(rowCStage1Button_1.LEFT_ALIGNMENT) stringToDisplay = "fast clock (outside running times): x " + str(speed_not_operational_gbl) rowDStage1Button_1 = JLabel(stringToDisplay) rowDStage1Button_1.setFont(rowTitle_22.getFont().deriveFont(Font.BOLD, 13)); rowDStage1Button_1.add(Box.createHorizontalGlue()); rowDStage1Button_1.setAlignmentX(rowDStage1Button_1.LEFT_ALIGNMENT) stringToDisplay = "scheduling margin: " + str(scheduling_margin_gbl) + " fast mins" rowEStage1Button_1 = JLabel(stringToDisplay) rowEStage1Button_1.setFont(rowTitle_22.getFont().deriveFont(Font.BOLD, 13)); rowEStage1Button_1.add(Box.createHorizontalGlue()); rowEStage1Button_1.setAlignmentX(rowEStage1Button_1.LEFT_ALIGNMENT) stringToDisplay = "scheduling in operation: " + str(scheduling_in_operation_gbl) rowFStage1Button_1 = JLabel(stringToDisplay) rowFStage1Button_1.setFont(rowTitle_22.getFont().deriveFont(Font.BOLD, 13)); rowFStage1Button_1.add(Box.createHorizontalGlue()); rowFStage1Button_1.setAlignmentX(rowFStage1Button_1.LEFT_ALIGNMENT) rowStage1Button_1 = JButton("Initialisation", actionPerformed = self.setup_schedule_parameters_panel) stage1Button = rowStage1Button_1 rowStage2Button = JPanel() rowStage2Button.setLayout(BoxLayout(rowStage2Button, BoxLayout.X_AXIS)) rowrowStage2Button_2 = JLabel("Set Clock to Session Start") rowrowStage2Button_2.setFont(rowTitle_22.getFont().deriveFont(Font.BOLD, 13)); rowrowStage2Button_2.add(Box.createHorizontalGlue()); rowrowStage2Button_2.setAlignmentX(rowrowStage2Button_2.LEFT_ALIGNMENT) rowStage2Button_2 = JButton("Set Time ", actionPerformed = self.SetTime_action) stage2Button = rowStage2Button_2 rowStage3Button = JPanel() rowStage3Button.setLayout(BoxLayout(rowStage3Button, BoxLayout.X_AXIS)) rowrowStage3Button_3 = JLabel("Stop/Start Scheduling Trains") rowrowStage3Button_3.setFont(rowTitle_33.getFont().deriveFont(Font.BOLD, 13)); rowrowStage3Button_3.add(Box.createHorizontalGlue()); rowrowStage3Button_3.setAlignmentX(rowrowStage3Button_3.LEFT_ALIGNMENT) rowStage3Button_3 = JButton("Schedule ", actionPerformed = self.ToggleSchedulingtrains_action) stage3Button = rowStage3Button_3 rowStage4Button = JPanel() rowStage4Button.setLayout(BoxLayout(rowStage4Button, BoxLayout.X_AXIS)) rowrowStage4Button_4 = JLabel("Stop/Start Clock") rowrowStage4Button_4.setFont(rowTitle_33.getFont().deriveFont(Font.BOLD, 13)); rowrowStage4Button_4.add(Box.createHorizontalGlue()); rowrowStage4Button_4.setAlignmentX(rowrowStage4Button_4.LEFT_ALIGNMENT) rowStage4Button_4 = JButton("Stop/Start", actionPerformed = self.StopStartClock_action) stage4Button = rowStage4Button_4 rowStage5Button = JPanel() rowStage5Button.setLayout(BoxLayout(rowStage5Button, BoxLayout.X_AXIS)) rowrowStage5Button_5 = JLabel("Initialise time, start scheduler, start time
Stop scheduler, stop time") rowrowStage5Button_5.setFont(rowTitle_33.getFont().deriveFont(Font.BOLD, 13)); rowrowStage5Button_5.add(Box.createHorizontalGlue()); rowrowStage5Button_5.setAlignmentX(rowrowStage5Button_5.LEFT_ALIGNMENT) rowStage5Button_5 = JButton("Initialise", actionPerformed = self.StopStartScheduler_action) stage5Button = rowStage5Button_5 rowStage6Button = JPanel() rowStage6Button.setLayout(BoxLayout(rowStage6Button, BoxLayout.X_AXIS)) rowrowStage6Button_6 = JLabel("Start scheduler, start time
Stop scheduler, stop time") rowrowStage6Button_6.setFont(rowTitle_33.getFont().deriveFont(Font.BOLD, 13)); rowrowStage6Button_6.add(Box.createHorizontalGlue()); rowrowStage6Button_6.setAlignmentX(rowrowStage6Button_6.LEFT_ALIGNMENT) rowStage6Button_6 = JButton(" Run ", actionPerformed = self.Running_StopStartScheduler_action) stage6Button = rowStage6Button_6 rowStage1Button.add(Box.createVerticalGlue()) rowStage1Button.add(Box.createRigidArea(Dimension(20, 0))) rowStage1Button.add(rowStage1Button_1) rowStage1Button.add(Box.createRigidArea(Dimension(20, 0))) rowStage1Button.add(rowrowStage1Button_1) rowAStage1Button.add(Box.createVerticalGlue()) rowAStage1Button.add(Box.createRigidArea(Dimension(120, 0))) rowAStage1Button.add(rowAStage1Button_1) rowBStage1Button.add(Box.createVerticalGlue()) rowBStage1Button.add(Box.createRigidArea(Dimension(120, 0))) rowBStage1Button.add(rowBStage1Button_1) rowCStage1Button.add(Box.createVerticalGlue()) rowCStage1Button.add(Box.createRigidArea(Dimension(120, 0))) rowCStage1Button.add(rowCStage1Button_1) rowDStage1Button.add(Box.createVerticalGlue()) rowDStage1Button.add(Box.createRigidArea(Dimension(120, 0))) rowDStage1Button.add(rowDStage1Button_1) rowEStage1Button.add(Box.createVerticalGlue()) rowEStage1Button.add(Box.createRigidArea(Dimension(120, 0))) rowEStage1Button.add(rowEStage1Button_1) rowFStage1Button.add(Box.createVerticalGlue()) rowFStage1Button.add(Box.createRigidArea(Dimension(120, 0))) rowFStage1Button.add(rowFStage1Button_1) rowStage2Button.add(Box.createVerticalGlue()) rowStage2Button.add(Box.createRigidArea(Dimension(20, 0))) rowStage2Button.add(rowStage2Button_2) rowStage2Button.add(Box.createRigidArea(Dimension(20, 0))) rowStage2Button.add(rowrowStage2Button_2) rowStage3Button.add(Box.createVerticalGlue()) rowStage3Button.add(Box.createRigidArea(Dimension(20, 0))) rowStage3Button.add(rowStage3Button_3) rowStage3Button.add(Box.createRigidArea(Dimension(20, 0))) rowStage3Button.add(rowrowStage3Button_3) rowStage4Button.add(Box.createVerticalGlue()) rowStage4Button.add(Box.createRigidArea(Dimension(20, 0))) rowStage4Button.add(rowStage4Button_4) rowStage4Button.add(Box.createRigidArea(Dimension(20, 0))) rowStage4Button.add(rowrowStage4Button_4) rowStage5Button.add(Box.createVerticalGlue()) rowStage5Button.add(Box.createRigidArea(Dimension(20, 0))) rowStage5Button.add(rowStage5Button_5) rowStage5Button.add(Box.createRigidArea(Dimension(20, 0))) rowStage5Button.add(rowrowStage5Button_5) rowStage6Button.add(Box.createVerticalGlue()) rowStage6Button.add(Box.createRigidArea(Dimension(20, 0))) rowStage6Button.add(rowStage6Button_6) rowStage6Button.add(Box.createRigidArea(Dimension(20, 0))) rowStage6Button.add(rowrowStage6Button_6) #Title # panel.add(self.leftJustify(rowTitle_2)) panel.add(self.leftJustify(rowTitle_22)) panel.add(self._create_separator_row()) #stage1 panel.add(self.leftJustify(rowStage1Button)) panel.add(self.leftJustify(rowAStage1Button)) panel.add(self.leftJustify(rowBStage1Button)) panel.add(self.leftJustify(rowCStage1Button)) panel.add(self.leftJustify(rowDStage1Button)) panel.add(self.leftJustify(rowEStage1Button)) panel.add(self._create_separator_row()) #stage2 panel.add(self.leftJustify(rowStage2Button)) # panel.add(self.leftJustify(rowStage2Separator)) panel.add(self.leftJustify(rowStage3Button)) panel.add(self.leftJustify(rowFStage1Button)) panel.add(self.leftJustify(rowStage4Button)) panel.add(self._create_separator_row()) panel.add(self.leftJustify(rowStage5Button)) panel.add(self._create_separator_row()) panel.add(self.leftJustify(rowStage6Button)) panel.add(self._create_separator_row()) self.frame.pack() self.frame.setVisible(True) self.frame.setSize(450, 400) self.frame.setLocation(10,10) def _create_separator_row(self): """Creates and returns a new separator panel object.""" separatorPanel = JPanel() separatorPanel.setLayout(BoxLayout(separatorPanel, BoxLayout.X_AXIS)) separatorLabel = JLabel("*******************************************************************") separatorLabel.add(Box.createHorizontalGlue()) separatorLabel.setAlignmentX(separatorLabel.LEFT_ALIGNMENT) separatorPanel.add(Box.createVerticalGlue()) separatorPanel.add(Box.createRigidArea(Dimension(20, 0))) separatorPanel.add(separatorLabel) separatorPanel.add(Box.createRigidArea(Dimension(20, 0))) separatorPanel.add(JLabel("")) # Empty label for spacing return self.leftJustify(separatorPanel) def leftJustify(self, panel): b = Box.createHorizontalBox() b.add( panel ) b.add( Box.createHorizontalGlue() ) # (Note that you could throw a lot more components # and struts and glue in here.) return b # self.close_this_panel(event) # # self.run_trains() def close_this_panel(self, event): if self.logLevel > 0: print "closing panel" comp = event.getSource() win = SwingUtilities.getWindowAncestor(comp); win.dispose() def SetTime_action(self, event): global fast_clock_running_at_operational_speed global timebase # timebase needs to be running to set rate and time timebase.setRun(True) timebase.userSetRate(float(speed_not_operational_gbl)) # set clock to beginning of session self.set_timebase_start_hour(int(start_hour_gbl)-1, 55) # self.set_timebase_start_hour(0, 0) # set timebase to stop timebase.setRun(False) if "rowrowStage4Button_4" in globals(): if timebase.getRun(): state = "Started" else: state = "Stopped" stringToDisplay = "Stop/Start Clock: " + state rowrowStage4Button_4.setText(stringToDisplay) # Update the label def ToggleSchedulingtrains_action(self, event): global schedule_trains_glb global scheduling_in_operation_gbl global rowFStage1Button_1 # schedule_trains_glb = False if self.logLevel > 0: print "ToggleSchedulingtrains_action", "scheduling_in_operation_gbl", scheduling_in_operation_gbl #stop Scheduler if 'scheduling_in_operation_gbl' not in globals(): scheduling_in_operation_gbl = "True" # print "scheduling_in_operation_gbl 8", scheduling_in_operation_gbl if scheduling_in_operation_gbl == "False": self.start_schedule_trains_master() scheduling_in_operation_gbl = "True" else: self.stop_schedule_trains_master() scheduling_in_operation_gbl = "False" # print "scheduling_in_operation_gbl 0", scheduling_in_operation_gbl stringToDisplay = "scheduling in operation: " + str(scheduling_in_operation_gbl) if 'rowFStage1Button_1' in globals(): rowFStage1Button_1.setText(stringToDisplay) # Update the label if self.logLevel > 0: print "ToggleSchedulingtrains_action end", "scheduling_in_operation_gbl", scheduling_in_operation_gbl def StopStartClock_action(self, event): self.swap_timebase_state_run_stop() def StopStartScheduler_action(self, event): if scheduling_in_operation_gbl == "False": # start scheduler self.ToggleSchedulingtrains_action(event) # if timebase.getRun() == True: # set time self.SetTime_action(event) # sets time and sets timebase to stop # if timebase.getRun() == False: self.swap_timebase_state_run_stop() # start timebase else: # stop scheduler (was running) self.ToggleSchedulingtrains_action(event) # leave time at same time as before # stop timebase self.set_timebase_state_stop() def Running_StopStartScheduler_action(self, event): if scheduling_in_operation_gbl == "False": # start scheduler self.ToggleSchedulingtrains_action(event) if timebase.getRun() == False: self.swap_timebase_state_run_stop() # start timebase else: # stop scheduler (was running) self.ToggleSchedulingtrains_action(event) # leave time at same time as before # stop timebase self.set_timebase_state_stop() def swap_timebase_state_run_stop(self): global timebase global tListener global fast_clock_rate global rowrowStage4Button_4 if timebase.getRun() == True: timebase.removeMinuteChangeListener(tListener) timebase.setRun(False) # print "fast_clock_rate", fast_clock_rate else: timebase.setRun(True) if tListener is None: tListener = TimeListener() timebase.addMinuteChangeListener(tListener) if "rowrowStage4Button_4" in globals(): if timebase.getRun(): state = "Started" else: state = "Stopped" stringToDisplay = "Stop/Start Clock: " + state rowrowStage4Button_4.setText(stringToDisplay) # Update the label else: # print '"rowrowStage4Button_4" not in globals()' pass def set_timebase_state_stop(self): global timebase global tListener global fast_clock_rate global rowrowStage4Button_4 timebase.removeMinuteChangeListener(tListener) timebase.setRun(False) if "rowrowStage4Button_4" in globals(): state = "Stopped" stringToDisplay = "Stop/Start Clock: " + state rowrowStage4Button_4.setText(stringToDisplay) # Update the label else: # print '"rowrowStage4Button_4" not in globals()' pass def start_schedule_trains_master(self): global instanceList global rowFStage1Button_1 # start scheduler if self.logLevel > 0: print "setup values for running" schedule_trains_master = ScheduleTrains() schedule_trains_master.setName('Schedule Trains Master') list_existing_schedule_trains = [iL.getName() for iL in instanceList if iL.getName() == 'Schedule Trains Master'] # print "list_existing_schedule_trains", list_existing_schedule_trains if list_existing_schedule_trains == []: # print "appending instance list" instanceList.append(schedule_trains_master) if schedule_trains_master.setup(): # print "setting name" schedule_trains_master.setName('Schedule Trains Master') schedule_trains_master.start() scheduling_in_operation_gbl = "False" # print "scheduling_in_operation_gbl 2", scheduling_in_operation_gbl stringToDisplay = "scheduling in operation: " + str(scheduling_in_operation_gbl) if 'rowFStage1Button_1' in globals(): rowFStage1Button_1.setText(stringToDisplay) # Update the label if self.logLevel > 0: print "end setup values for running" def stop_schedule_trains_master(self): global instanceList #stop all threads even if there are duplications summary = jmri.jmrit.automat.AutomatSummary.instance() automatsList = java.util.concurrent.CopyOnWriteArrayList() schedule_trains_master = ScheduleTrains() for automat in summary.getAutomats(): automatsList.add(automat) # print "automatsList", automatsList for automat in automatsList: # print "automat", automat if "ScheduleTrains" in str(automat): automat.stop() # print automat, "stopped" # print "automatsList2", automatsList # print "end stop_all_threads" instanceList = [iL for iL in instanceList if str(iL.getName()) != 'Schedule Trains Master'] def set_default_scheduling_values(self): # self.show_analog_clock() # show the analog clock # print "set_default_scheduling_hourly_values" global start_hour_gbl, end_hour_gbl, fast_clock_rate, speed_not_operational_gbl, \ scheduling_margin_gbl, scheduling_in_operation_gbl # read parameters scheduling_in_operation_gbl1 = False # change of logic do not set scheduling_in_operation_gbl here [start_hour_gbl, end_hour_gbl, fast_clock_rate, speed_not_operational_gbl, \ scheduling_margin_gbl, scheduling_in_operation_gbl1] = self.read_list() if self.logLevel > 0: print "read list" , [start_hour_gbl, end_hour_gbl, speed_not_operational_gbl] if start_hour_gbl == "": start_hour_gbl = "04" end_hour_gbl = "22" fast_clock_rate = "10" speed_not_operational_gbl = "100" scheduling_margin_gbl = "3" scheduling_in_operation_gbl = "False" # print "1scheduling_in_operation_gbl", scheduling_in_operation_gbl self.write_list([start_hour_gbl, end_hour_gbl, fast_clock_rate, speed_not_operational_gbl, \ scheduling_margin_gbl, scheduling_in_operation_gbl]) # print "fast_clock_rate in set_default_scheduling_values", fast_clock_rate def setup_schedule_parameters_panel(self, event): """Creates and displays a panel for setting the scheduler parameters.""" # read parameters [self.start_hour, self.end_hour, fast_clock_rate, self.speed_not_operational, \ self.scheduling_margin, self.scheduling_in_operation] = self.read_list() if self.logLevel > 0: print "read list" , [self.start_hour, self.end_hour, self.speed_not_operational] if self.start_hour == "": self.start_hour = "04" self.end_hour = "22" fast_clock_rate = "10" self.speed_not_operational = "100" self.scheduling_margin = "10" self.scheduling_in_operation = "False" # Create and set up the window. self.params_frame = JFrame("Set Schedule Parameters") #NOI18N self.params_frame.setPreferredSize(Dimension(550, 250)) # Create and set up the panel using a simple grid layout. self.params_panel = JPanel(GridLayout(0, 2, 10, 5)) # hgap, vgap self.params_panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)) # top, left, bottom, right # Add the widgets to the panel. self.add_schedule_parameter_widgets() # Set the panel to be the content pane of the window. self.params_frame.setContentPane(self.params_panel) # Display the window. self.params_frame.pack() self.params_frame.setVisible(True) class FieldValidator(FocusAdapter, ActionListener): """ A listener that validates a text field when focus is lost or Enter is pressed. If validation fails, it reverts the field to its previous value. """ def __init__(self, validation_function, field): self.validation_function = validation_function self.field = field self.old_value = None def focusGained(self, event): """Store the current value when the field gains focus.""" self.old_value = self.field.getText() def _validate_and_revert(self): """Helper method to run validation and revert on failure.""" if not self.validation_function(self.field): # The validation function already shows the error message. # Now, revert the text field to the last known good value. self.field.setText(self.old_value) def focusLost(self, event): """Validate when focus is lost.""" self._validate_and_revert() def actionPerformed(self, event): """Validate when Enter is pressed.""" self._validate_and_revert() def add_schedule_parameter_widgets(self): """Adds labels, fields, and buttons to the parameters panel.""" global start_hour_gbl, end_hour_gbl, fast_clock_rate, speed_not_operational_gbl, \ scheduling_margin_gbl, scheduling_in_operation_gbl # --- Create Widgets --- start_hour_label = JLabel("Start Hour (0-23):") #NOI18N self.start_hour_field = JTextField(4) end_hour_label = JLabel("End Hour (0-23):") #NOI18N self.end_hour_field = JTextField(4) fast_clock_label = JLabel("Fast Clock Rate (Running Period):") #NOI18N self.fast_clock_field = JTextField(4) fast_clock_off_label = JLabel("Fast Clock Rate (Non Running Period) (1-100):") #NOI18N self.fast_clock_off_field = JTextField(4) margin_label = JLabel("Scheduling Margin (Fast Mins, 0-20):") #NOI18N self.margin_field = JTextField(4) save_button = JButton("Save") #NOI18N cancel_button = JButton("Cancel") #NOI18N # --- Pre-fill fields with existing values --- # This assumes the values are stored as attributes of your class. # If they are globals, you would reference them directly. self.start_hour_field.setText(str(self.start_hour)) self.end_hour_field.setText(str(self.end_hour)) self.fast_clock_field.setText(str(fast_clock_rate)) self.fast_clock_off_field.setText(str(self.speed_not_operational)) self.margin_field.setText(str(self.scheduling_margin)) # --- Add Listeners for real-time validation (on focus loss or Enter key) --- start_hour_validator = self.FieldValidator(self.validate_start_hour, self.start_hour_field) self.start_hour_field.addFocusListener(start_hour_validator) self.start_hour_field.addActionListener(start_hour_validator) end_hour_validator = self.FieldValidator(self.validate_end_hour, self.end_hour_field) self.end_hour_field.addFocusListener(end_hour_validator) self.end_hour_field.addActionListener(end_hour_validator) fast_clock_validator = self.FieldValidator(self.validate_fast_clock_rate, self.fast_clock_field) self.fast_clock_field.addFocusListener(fast_clock_validator) self.fast_clock_field.addActionListener(fast_clock_validator) fast_clock_off_validator = self.FieldValidator(self.validate_fast_clock_off_rate, self.fast_clock_off_field) self.fast_clock_off_field.addFocusListener(fast_clock_off_validator) self.fast_clock_off_field.addActionListener(fast_clock_off_validator) margin_validator = self.FieldValidator(self.validate_margin, self.margin_field) self.margin_field.addFocusListener(margin_validator) self.margin_field.addActionListener(margin_validator) # --- Add Action Listeners --- save_button.actionPerformed = self.save_schedule_parameters_action cancel_button.actionPerformed = self.cancel_schedule_parameters_action # --- Add Widgets to Panel in Order, wrapping fields to control size --- self.params_panel.add(start_hour_label) field_panel1 = JPanel(FlowLayout(FlowLayout.LEFT, 10, 0)) field_panel1.add(self.start_hour_field) self.params_panel.add(field_panel1) self.params_panel.add(end_hour_label) field_panel2 = JPanel(FlowLayout(FlowLayout.LEFT, 10, 0)) field_panel2.add(self.end_hour_field) self.params_panel.add(field_panel2) self.params_panel.add(fast_clock_label) field_panel3 = JPanel(FlowLayout(FlowLayout.LEFT, 10, 0)) field_panel3.add(self.fast_clock_field) self.params_panel.add(field_panel3) self.params_panel.add(fast_clock_off_label) field_panel4 = JPanel(FlowLayout(FlowLayout.LEFT, 10, 0)) field_panel4.add(self.fast_clock_off_field) self.params_panel.add(field_panel4) self.params_panel.add(margin_label) field_panel5 = JPanel(FlowLayout(FlowLayout.LEFT, 10, 0)) field_panel5.add(self.margin_field) self.params_panel.add(field_panel5) # --- Add Buttons --- # Create a panel to hold both buttons, so they can be centered together. button_panel = JPanel(FlowLayout(FlowLayout.CENTER, 10, 5)) # hgap=10, vgap=5 button_panel.add(save_button) button_panel.add(cancel_button) # Add an empty label to the first column of the last row to push the button panel to the right. self.params_panel.add(JLabel("")) self.params_panel.add(button_panel) def save_schedule_parameters_action(self, event): """Saves the parameters back to the class and closes the window.""" global start_hour_gbl, end_hour_gbl, fast_clock_rate, speed_not_operational_gbl, \ scheduling_margin_gbl, scheduling_in_operation_gbl # --- Run all validations one last time before saving --- if not self.validate_start_hour(self.start_hour_field): return if not self.validate_end_hour(self.end_hour_field): return if not self.validate_fast_clock_rate(self.fast_clock_field): return if not self.validate_fast_clock_off_rate(self.fast_clock_off_field): return if not self.validate_margin(self.margin_field): return # All validation passed, now save the values. self.start_hour = int(self.start_hour_field.getText()) self.end_hour = int(self.end_hour_field.getText()) fast_clock_rate = int(self.fast_clock_field.getText()) self.speed_not_operational = int(self.fast_clock_off_field.getText()) self.scheduling_margin = int(self.margin_field.getText()) items = [str(item) for item in [self.start_hour,self.end_hour, fast_clock_rate, \ self.speed_not_operational, \ self.scheduling_margin, scheduling_in_operation_gbl]] if self.logLevel > 0: print "items to write", items self.write_list(items) # store in globals start_hour_gbl = self.start_hour end_hour_gbl = self.end_hour speed_not_operational_gbl = self.speed_not_operational scheduling_margin_gbl = self.scheduling_margin # update the jlabel texts stringToDisplay = "start hour: " + str(start_hour_gbl) rowAStage1Button_1.setText(stringToDisplay) # Update the label stringToDisplay = "end hour: " + str(end_hour_gbl) rowBStage1Button_1.setText(stringToDisplay) # Update the label stringToDisplay = "fast clock (when scheduling trains): x " + str(fast_clock_rate) rowCStage1Button_1.setText(stringToDisplay) # Update the label stringToDisplay = "fast clock (outside running times): x " + str(speed_not_operational_gbl) rowDStage1Button_1.setText(stringToDisplay) # Update the label stringToDisplay = "scheduling margin: " + str(scheduling_margin_gbl) + " fast mins" rowEStage1Button_1.setText(stringToDisplay) # Update the label print "Scheduler parameters saved." # Close the window after saving. self.params_frame.dispose() def cancel_schedule_parameters_action(self, event): """Closes the window without saving.""" self.params_frame.dispose() # --- Validation Methods --- def validate_start_hour(self, field): """Validates the Start Hour field.""" try: value = int(field.getText()) if not (0 <= value <= 23): OptionDialog().displayMessage("Start Hour must be between 0 and 23.") return False except ValueError: OptionDialog().displayMessage("Start Hour must be a valid number.") return False return True def validate_end_hour(self, field): """Validates the End Hour field.""" try: value = int(field.getText()) if not (0 <= value <= 23): OptionDialog().displayMessage("End Hour must be between 0 and 23.") return False except ValueError: OptionDialog().displayMessage("End Hour must be a valid number.") return False return True def validate_fast_clock_rate(self, field): """Validates the Fast Clock Rate (Running) field.""" try: value = int(field.getText()) if value <= 0: OptionDialog().displayMessage("Fast Clock Rate (Running) must be a positive number.") return False except ValueError: OptionDialog().displayMessage("Fast Clock Rate (Running) must be a valid number.") return False return True def validate_fast_clock_off_rate(self, field): """Validates the Fast Clock Rate (Outside Hours) field.""" try: value = int(field.getText()) if not (1 <= value <= 100): OptionDialog().displayMessage("Fast Clock Rate (Outside Hours) must be between 1 and 100.") return False except ValueError: OptionDialog().displayMessage("Fast Clock Rate (Outside Hours) must be a valid number.") return False return True def validate_margin(self, field): """Validates the Scheduling Margin field.""" try: value = int(field.getText()) if not (0 <= value <= 20): OptionDialog().displayMessage("Scheduling Margin must be between 0 and 20.") return False except ValueError: OptionDialog().displayMessage("Scheduling Margin must be a valid number.") return False return True def directory(self): path = jmri.util.FileUtil.getUserFilesPath() + "dispatcher" + java.io.File.separator + "hourlySchedule" if not os.path.exists(path): os.makedirs(path) return path + java.io.File.separator def write_list(self, a_list): # store list in binary file so 'wb' mode file = self.directory() + "hourlySchedule.txt" if self.logLevel > 0: print "hourlySchedule" , a_list if self.logLevel > 0: print "file" , file with open(file, 'wb') as fp: if self.logLevel > 0: print "a_list", a_list i = 0 for items in a_list: if self.logLevel > 0: print "items", items fp.write('%s' %items) if i < 5 : fp.write(",") i+=1 # for item in items: # if self.logLevel > 0: print "item", item # fp.write('%s' %item) # if i < 3 : fp.write(",") # i+=1 # fp.write('\n') # Read list to memory def read_list(self): # for reading also binary mode is important file = self.directory() + "hourlySchedule.txt" n_list = [] try: with open(file, 'rb') as fp: for line in fp: # print "line", line # x = line[:-1] # print x y = line.split(",") if self.logLevel > 0: print "y" , y n_list = y return n_list except: return ["", "", "", "", "", ""] def directory2(self): path = jmri.util.FileUtil.getUserFilesPath() + "dispatcher" + java.io.File.separator + "train_operators_emblem" if not os.path.exists(path): os.makedirs(path) return path + java.io.File.separator def write_list2(self, a_list): # store list in binary file so 'wb' mode file = self.directory2() + "train_operator_emblem.txt" if self.logLevel > 0: print "train_operator_emblem" , a_list if self.logLevel > 0: print "file" , file with open(file, 'wb') as fp: if self.logLevel > 0: print "a_list", a_list i = 0 for items in a_list: if self.logLevel > 0: print "items", items fp.write('%s' %items) if i < 5 : fp.write(",") i+=1 # Read list to memory def read_list2(self): # for reading also binary mode is important file = self.directory2() + "train_operator_emblem.txt" n_list = [] try: with open(file, 'rb') as fp: for line in fp: # print "line", line # x = line[:-1] # print x y = line.split(",") if self.logLevel > 0: print "y" , y n_list = y return n_list except: return ["", "", "", "", "", ""] def is_time_format(self, input): try: time.strptime(input, '%H:%M') return True except IndexError: if self.logLevel > 0: print "a" except ValueError: return False def setup_minute_time_listener_to_schedule_trains(self): global tListener global timebase global start_hour_gbl, end_hour_gbl, fast_clock_rate, speed_not_operational_gbl, \ scheduling_margin_gbl, scheduling_in_operation_gbl global schedule_trains_hourly global minute_time_listener_setup if self.logLevel > 0: print "Setting up Time Scheduler" timebase = jmri.InstanceManager.getDefault(jmri.Timebase) # set up timebase and start at midnight if self.logLevel > 0: print "******************************************set timebase hour" self.set_default_scheduling_values() self.set_timebase_start_hour(int(start_hour_gbl)-1, 45) self.set_timebase_start_hour(12, 0) # # attach a listener to the timebase. tListener = TimeListener() # to set the rate, the timebase needs to be running mystate = timebase.getRun() if timebase.getRun() == False: self.swap_timebase_state_run_stop() timebase.userSetRate(float(fast_clock_rate)) desired_state = False if False != timebase.getRun(): self.swap_timebase_state_run_stop() minute_time_listener_setup = True self.init = True def set_timebase_start_hour(self, hour, minute): from java.util import Date global timebase mystate = timebase.getRun() if mystate == False: self.swap_timebase_state_run_stop() timebase = jmri.InstanceManager.getDefault(jmri.Timebase) date = Date(2020,10,21) #any date really date.setHours(hour) date.setMinutes(minute) timebase.userSetTime(date) ## set to 00:00 21/10/2020 (want the time to be 00:00) if mystate != timebase.getRun(): self.swap_timebase_state_run_stop() def train_scheduler(self): #reset fast clock self.reset_clock() #go through operations:trains and get the train starting now def reset_clock(self): pass f = None def display_help(self): ref = "html.scripthelp.DispatcherSystem.DispatcherSystem" jmri.util.HelpUtil.displayHelpRef(ref) def show_analog_clock(self): if self.f == None: self.f = jmri.jmrit.analogclock.AnalogClockFrame() self.f.setSize(300, 200) self.f.setLocationRelativeTo(None) if self.frame != None: self.f.setLocation(self.frame.getX() + self.frame.getWidth(), self.frame.getY()); self.f.setVisible(True) def set_time_to_beginning_of_hourly_train_working(self): global start_hour_gbl, end_hour_gbl, fast_clock_rate, speed_not_operational_gbl, scheduling_margin_gbl, scheduling_in_operation_gbl # start_hour_gbl is the start of hourly working start_hour = int(start_hour_gbl) if self.logLevel > 0: print "start_hour", start_hour self.set_timebase_start_hour(start_hour -1, 55) def show_routes(self): # a = jmri.jmrit.operations.routes.RoutesTableAction() # a.actionPerformed(None) CreateAndShowGUI6(self) def show_operations_trains(self): global CreateAndShowGUI4_frame # delete any previous frames if "CreateAndShowGUI4_frame" in globals(): CreateAndShowGUI4_frame.setVisible(False) else: # print "not in globals" pass # show dispatcher system form CreateAndShowGUI4(self) def get_train_list(self): TrainManager=jmri.InstanceManager.getDefault(jmri.jmrit.operations.trains.TrainManager) train_list = TrainManager.getTrainsByTimeList() return train_list from java.util.concurrent import TimeUnit class TimeListener(java.beans.PropertyChangeListener): # This is called every minute since it has been attached as timebase.addMinuteChangeListener(tListener) def __init__(self): # global timetable_gbl self.logLevel = 0 if self.logLevel > 0: print "set up TimeListener" self.prev_time = 0 if self.logLevel > 0: print "end TimeListener" def propertyChange(self, event): global fast_clock_running_at_operational_speed if 'fast_clock_running_at_at_operational_speed' not in globals(): fast_clock_running_at_operational_speed = True global minutes_old2, minutes_old3 global schedule_trains_hourly global timetable_gbl, run_local_timetable_gbl global fast_clock_rate global send_mqtt_messages_gbl if 'minutes_old3' not in globals(): minutes_old3 = 0 # print "a" minutes_old = int(event.getOldValue()) # print "b" minutes = int(event.getNewValue()) # print "c", minutes if self.logLevel > 0: print "property change", "minutes", minutes, if 'minutes_old2' not in globals(): minutes_old2 = minutes_old if self.logLevel > 0: print "before: minutes_old3", minutes_old3 if self.logLevel > 0: print "minutes_old", minutes_old, "minutes", minutes, "minutes_old2", minutes_old2, \ "(minutes_old - minutes_old2)", (minutes_old - minutes_old2), \ "(minutes_old - minutes_old2) % 60 == 1", (minutes_old - minutes_old2) % 60 == -1 # if self.logLevel > 0: print "property change", event.newValue if (minutes_old - minutes_old2) % 60 != 0: # when we set the fast clock in the event timer it triggers a new event at the same time # we then get into a recursion. This ignores the second call at the same time if self.logLevel > 0: print "two events are triggered with the same minutes" else: if self.logLevel > 0: print "timeListener: normal Operation" if self.logLevel > 0: print "minutes_old", minutes_old, "minutes", minutes, "minutes_old2", minutes_old2, \ "(minutes - minutes_old2) % 60 ", (minutes - minutes_old2) % 60 # print "y", minutes, type(minutes), int(minutes) if int(minutes) % 10 == 0: # only check every 10 minutes to prevent problens at non_operational_speeds # don't just check at 0 minutes in case train us started not on the hour if self.logLevel > 0: print "minutes", int(minutes), "int(minutes) % 10", int(minutes) % 10, "minutes", minutes # print "e" minutes_old2 = minutes # print "set fast clock rate" self.set_fast_clock_rate() # sets global fast_clock_at_operational_speed self.process_operations_trains(event) # scheduled trains send_mqtt_messages_gbl = True if 'send_mqtt_messages_gbl' not in globals(): send_mqtt_messages_gbl = False if 'run_local_timetable_gbl' not in globals(): run_local_timetable_gbl = False # print "send_mqtt_messages_gbl", send_mqtt_messages_gbl if run_local_timetable_gbl or send_mqtt_messages_gbl: # do not display more frequently than 5 secs # print "f1", fast_clock_rate fcr = int(str(fast_clock_rate)) x = (5.0 / 60.0) # print "x", x, "fcr", fcr, "x*fcr", x * fcr no_fast_minutes = int(x * fcr) if no_fast_minutes == 0: no_fast_minutes = 1 if minutes % no_fast_minutes == 0: Trigger_Timetable(minutes) else: # print "HIDING TIMETABLE WINDOW" # print "run_timetable_gbl", run_timetable_gbl, "send_mqtt_messages_gbl", send_mqtt_messages_gbl if 'timetable_gbl' in globals(): # timetable_gbl = None if timetable_gbl != None: timetable_gbl.hideWindow() minutes_old2 = minutes # use minutes_old2 to prevent recursion minutes_old3 = minutes_old if self.logLevel > 0: print "after: minutes_old3", minutes_old3 if self.logLevel > 0: print "end property change" ; print "" def stop(self): tListener.cancel() def set_fast_clock_rate(self): # set the fast clock rate global start_hour_gbl, end_hour_gbl, fast_clock_rate, speed_not_operational_gbl, scheduling_margin_gbl, scheduling_in_operation_gbl global schedule_trains_hourly global timebase global fast_clock_running_at_operational_speed # if self.logLevel > 0: print "TimeListener: change",event.propertyName, "from", event.oldValue, "to", event.newValue if self.logLevel > 0: print "set_fast_clock_rate: 1" if self.speed_not_operational_gbl__is_defined(): if self.logLevel > 0: print "set_fast_clock_rate: 2", speed_not_operational_gbl # if schedule_trains_hourly: if True: hour = int(timebase.getTime().getHours()) minutes = int(timebase.getTime().getMinutes()) rate = timebase.userGetRate() if self.logLevel > 0: print "set_fast_clock_rate:", "schedule_trains_hourly", schedule_trains_hourly fast_clock_during_non_operational_times = speed_not_operational_gbl if self.logLevel > 0: print "fast clock during non operational_times", fast_clock_during_non_operational_times if self.logLevel > 0: print "hour", hour, "start_hour_gbl", start_hour_gbl, "end_hour_gbl", end_hour_gbl, \ "fast_clock_rate", fast_clock_rate, "speed_not_operational_gbl", speed_not_operational_gbl, \ "hour >= start_hour_gbl and hour <= end_hour_gbl", hour >= int(start_hour_gbl) and hour <= int(end_hour_gbl) if hour >= int(start_hour_gbl) and hour <= int(end_hour_gbl): # or hour == int(start_hour_gbl - 1) % 24 and minutes == 59: if rate != fast_clock_rate: # check to stop recursion error timebase.userSetRate(float(fast_clock_rate)) fast_clock_running_at_operational_speed = True if self.logLevel > 0: print "set_fast_clock_rate:", "fast_clock_rate slow", fast_clock_rate pass else: if self.logLevel > 0: print "fast_clock_during_non_operational_times", fast_clock_during_non_operational_times fcr = fast_clock_during_non_operational_times if fcr > 100 : fcr = 100 # set to maximum if rate != fcr: timebase.userSetRate(float(fcr)) fast_clock_running_at_operational_speed = False if self.logLevel > 0: print "set_fast_clock_rate:", "fcr", fcr else: print "speed_not_operational_gbl__is_defined()", False def process_operations_trains(self, event ): global timebase global schedule_trains_hourly global start_hour_gbl, end_hour_gbl, fast_clock_rate, speed_not_operational_gbl, scheduling_margin_gbl, scheduling_in_operation_gbl global scheduled global trains_to_be_scheduled if self.logLevel > 0: print " ****** in process_operations_trains" if self.logLevel > 0: print "A1" if 'schedule_trains_hourly' not in globals(): schedule_trains_hourly = False if self.logLevel > 0: print "in process_operations_trains", "schedule_trains_hourly", schedule_trains_hourly hour = int(timebase.getTime().getHours()) if self.logLevel > 1: print "type hour" , type(hour) minutes = event.newValue if self.logLevel > 1: print "type minutes", type(minutes) self.curr_time = minutes + hour * 60 if self.logLevel > 1: print "curr_time", self.curr_time self.prev_time = self.curr_time -1 if self.logLevel > 1: print "prev_time", self.prev_time # only schedule within stat_hour and end_hour if int(start_hour_gbl) <= hour <= int(end_hour_gbl): pass # need to process trains else: if self.logLevel > 0: print "returning in process_operational_trains" return # outside operational time if self.logLevel > 0: print "A2" if self.logLevel > 1: print "TimeListener: process_operations_trains" TrainManager=jmri.InstanceManager.getDefault(jmri.jmrit.operations.trains.TrainManager) train_list = TrainManager.getTrainsByTimeList() train_list = [train for train in train_list if "skip" not in train.getComment()] # exclude trains marked as 'don't schedule' in Scheduled trains table if self.logLevel > 0: print "train_list",train_list #if self.logLevel > 1: print "prev_time", self.prev_time, "curr_time", self.curr_time if self.logLevel > 0: print "a3" for train in train_list: if self.logLevel > 1: print "*******************" if self.logLevel > 1: print ("train list: departure time: ", str(train.getDepartureTime()), str(train.getName())) if self.logLevel > 1: print "prev_time", self.prev_time, "curr_time", self.curr_time, "train.getDepartTimeMinutes()", train.getDepartTimeMinutes() #get the train that is triggered in the current minute if event == None: if self.logLevel > 0: print "event is none , returning" return if self.logLevel > 0: print "A4" # schedule the train taking account of the repeat command # trains_to_start = [] if self.logLevel > 0: print "train_list", train_list, "trains_to_be_scheduled", trains_to_be_scheduled for train in train_list: comment = train.getComment() repeat_command = self.find_between(comment, "[repeat-", "-repeat]") if self.logLevel > -1: print "train", train, "repeat_command", repeat_command max = int(minutes) min = (int(minutes) - 1) mid = int(train.getDepartTimeMinutes()) if repeat_command == "Once": if max == 0: min += 1; mid += 1; max += 1 print "hour", hour, "minutes", minutes, "mid", mid, "min", min, "max", max, "train.getDepartTimeMinutes()", train.getDepartTimeMinutes() min1 = hour - 1 mid1 = int(train.getDepartureTimeHour()) max1 = hour if max1 == 0: # ensure mid lies between min amd max (ensure we don't have 1 < 0 <= 0) min1 += 1; mid1 += 1; max1 += 1 print "min1", min1, "mid1", mid1, "max1", max1, "(min1) < (mid1) <= (max1)", (min1) < (mid1) <= (max1) if (min % 60 < (mid % 60) <= max % 60) and \ ((min1) < (mid1) <= (max1)): if train not in trains_to_be_scheduled: trains_to_be_scheduled.append(train) scheduled[train] = False elif repeat_command == "Repeat every 20 mins": if max % 20 == 0: min += 1; mid += 1; max += 1 # ensure mid lies between min amd max (ensure we don't have 59 < 0 <= 0) if (min % 20 < (mid % 20) <= max % 20): if train not in trains_to_be_scheduled: trains_to_be_scheduled.append(train) scheduled[train] = False elif repeat_command == "Repeat every 30 mins": if max % 30 == 0: min += 1; mid += 1; max += 1 if (min % 30 < (mid % 30) <= max % 30): if train not in trains_to_be_scheduled: trains_to_be_scheduled.append(train) scheduled[train] = False elif repeat_command == "Repeat every Hour": if self.logLevel > 0: print "min", min, "max", max, "mid", mid if max == 0: min += 1; mid += 1; max += 1 if self.logLevel > 0: print "min", min, "max", max, "mid", mid if (min < (mid % 60) <= max): if train not in trains_to_be_scheduled: trains_to_be_scheduled.append(train) scheduled[train] = False elif repeat_command == "Repeat every 2 Hours": if max == 0: min += 1; mid += 1; max += 1 min1 = hour - 1 mid1 = int(train.getDepartureTimeHour()) max1 = hour if max1 % 2 == 0: # ensure mid lies between min amd max (ensure we don't have 1 < 0 <= 0) min1 += 1; mid1 += 1; max1 += 1 if (min < (mid % 60) <= max) and \ ((min1 % 2) < (mid1 % 2) <= (max1 % 2)): if train not in trains_to_be_scheduled: trains_to_be_scheduled.append(train) scheduled[train] = False else: if self.logLevel > 0: print "incorrect repeat command", repeat_command # assume set to once if self.prev_time < int(train.getDepartTimeMinutes()) <= self.curr_time and \ "skip" not in train.getDescription(): # if skip in description of scheduled Train do not run the train if train not in trains_to_be_scheduled: trains_to_be_scheduled.append(train) scheduled[train] = False if self.logLevel > 0: print "trains_to_be_scheduled", trains_to_be_scheduled if self.logLevel > 0: print "Time listener: trains_to_be_scheduled", trains_to_be_scheduled if self.logLevel > 0: print "scheduled", scheduled if self.logLevel > 0: print "trains_to_be_scheduled", trains_to_be_scheduled def speed_not_operational_gbl__is_defined(self): global start_hour_gbl, end_hour_gbl, fast_clock_rate, speed_not_operational_gbl, scheduling_margin_gbl, scheduling_in_operation_gbl try: speed_not_operational_gbl except NameError: if self.logLevel > 0: print("well, it WASN'T defined after all!") return False else: if self.logLevel > 0: print("sure, it was defined.") return True def find_between(self, s, first, last): try: start = s.index(first) + len(first) end = s.index(last, start) return s[start:end] except IndexError: if self.logLevel > 0: print "D" except ValueError: return "" class Trigger_Timetable: def __init__(self, minutes): global timetable_triggered_gbl global print_count timetable_triggered_gbl = True if minutes == None: return self.run(minutes) def run(self, minutes): t1 = Thread(target=self.send_timetable_and_clock_via_mqtt, args=(minutes,)) t1.start() t1.join() def send_timetable_and_clock_via_mqtt(self, minutes): global station_name_list_gbl, group_location_gbl, run_local_timetable_gbl global timetable_gbl self.logLevel = 0 global timebase, print_count # print "****************start send_timetable_and_clock_via_mqtt" hour = int(timebase.getTime().getHours()) time = str(hour).zfill(2) + ":" + str(minutes).zfill(2) file = self.directory2() + "train_operator_emblem.txt" event = "" event = self.read_list2()[0] try: self.send_clock_message(hour, minutes, event) except: if "print_count" not in globals(): print_count = 0 if print_count < 1: print "clock message not sent" print_count += 1 if "station_name_list_gbl" not in globals(): station_name_list_gbl = "" if "group_location_gbl" not in globals(): group_location_gbl = "" # get list of origins, destinations and times at intermediate stations timetable = self.get_timetable(hour, minutes) if 'group_location_gbl' != "" and 'station_name_list_gbl' != "": station_name = group_location_gbl station_names_list = station_name_list_gbl else: station_name = 'Not Set' station_names_list = ['Not Set'] self.generate_local_timetable(station_name, station_names_list, time, timetable) if "run_local_timetable_gbl" not in globals(): print "run_local_timetable_gbl not defined" return if run_local_timetable_gbl == None: print "run_local_timetable_gbl None" return if run_local_timetable_gbl: if "timetable_gbl" in globals(): if timetable_gbl != None: timetable_gbl.frame.setVisible(True) else: if "timetable_gbl" in globals(): if timetable_gbl != None: timetable_gbl.frame.setVisible(False) try: self.send_timetable_messages(timetable) except: pass def find_between(self, s, first, last): try: start = s.index(first) + len(first) end = s.index(last, start) return str(s[start:end]) except ValueError: return "" except IndexError: print "index error find_between", "first", first, "last", last def get_timetable(self, hour, minutes1): global schedule_trains_hourly global start_hour_gbl, end_hour_gbl global fast_clock_rate self.curr_time = minutes1 + hour * 60 timetable = [] TrainManager=jmri.InstanceManager.getDefault(jmri.jmrit.operations.trains.TrainManager) train_list = TrainManager.getTrainsByTimeList() for train in train_list: if self.logLevel > 0: print "train", train, "train.getDescription()", train.getDescription() if train.getDescription() is not None and "skip" not in train.getDescription(): if self.logLevel > 0: print "train", train, train.getDescription() comment = train.getComment() repeat = self.find_between(comment, "[repeat-", "-repeat]") departure_time_minutes = train.getDepartTimeMinutes() % 60 departure_time_hour = train.getDepartureTimeHour() train_name = train.getName() if repeat == "Once": minutes = [departure_time_minutes] elif repeat == "Repeat every 20 mins": minutes = [minutes for minutes in range(0,59) if (minutes % 20) == (int(departure_time_minutes) % 20)] elif repeat == "Repeat every 30 mins": minutes = [minutes for minutes in range(0,59) if (minutes % 30) == (int(departure_time_minutes) % 30)] elif repeat == "Repeat every Hour": minutes = [departure_time_minutes] elif repeat == "Repeat every 2 Hours": minutes = [departure_time_minutes] else: minutes = [0] if repeat == "Once": hours = [departure_time_hour] else: if hour < int(end_hour_gbl): start_hour = max(hour, int(start_hour_gbl)) end_hour = max(hour + 3, int(start_hour_gbl)) else: start_hour = int(start_hour_gbl) end_hour = int(start_hour_gbl) + 3 hours = [hour1 for hour1 in range(start_hour, end_hour)] if repeat == "Repeat every 2 Hours": #update hours if 2 hourly hours = [hour1 for hour1 in hours if (int(train.getDepartureTimeHour()) % 2 == hour1 % 2)] for train_mins in minutes: for train_hour in hours: depart_time = int(str(train_mins)) + int(str(train_hour)) * 60 train_route_start_time = str(train_hour).zfill(2) + ":" + str(train_mins).zfill(2) if self.logLevel > 0: print "train", train, train.getDescription(), "train_route_start_time", train_route_start_time train_route = train.getRoute() if train_route is not None: if self.logLevel > 0: print "train_route", train_route locations = [location for location in train_route.getLocationsBySequenceList() \ if ".py" not in location.getName()] first_location = locations[0] first_station = str(first_location.getName()) last_location = locations[-1] last_station = str(last_location.getName()) comments = [location.getComment() for location in train_route.getLocationsBySequenceList() \ if ".py" not in location.getName()] journey_duration = 0 for comment in comments: duration_sec = self.find_between(comment, "[duration_sec-", "-duration_sec]") if self.logLevel > 0: print "duration_sec", duration_sec if duration_sec != "": duration = ((float(duration_sec) * int(str(fast_clock_rate))) / 60.0) # fast minutes else: # print "setting duration 0" duration = 0 journey_duration += int(duration) for i, route_location in enumerate(train_route.getLocationsBySequenceList()): station_name = str(route_location.getName()) platform_name = str(MyTableModel7().get_location_platform(route_location.getLocation())) if self.logLevel > 0: print "platform_name", platform_name if platform_name == "": platform_name = station_name if self.logLevel > 0: print "platform_name", platform_name if self.logLevel > 2: print "****************************", station_name, "***************************" if ".py" in station_name: # exclude actions break timetable_entry_names = ["train_name", "station_name", "station_departure_time", "last_station", "last_station_arrival_time", "via"] # remove items from start of via list, and the destination locations1 = train_route.getLocationsBySequenceList() locations = [str(loc) for loc in locations1] via = locations[i+1:-1] via = [location2 for location2 in via if ".py" not in location2] if via == []: via = "-" if i != 0 and last_station == station_name: via = ["Terminates Here"] via = str(via).replace('[','').replace(']','').replace("'", "") comment = route_location.getComment() if i == 0: station_departure_time = train_route_start_time time_to_station = 0 else: duration_sec = self.find_between(comment, "[duration_sec-", "-duration_sec]") if str(duration_sec) == "": duration_sec = 0 if self.logLevel > 2: print route_location, "duration_sec", duration_sec duration = float((float(duration_sec) * int(str(fast_clock_rate))) / 60.0) if self.logLevel > 2: print route_location, "duration", duration time_to_station = int(duration) if self.logLevel > 2: print "time_to_station", time_to_station previous_departure_time = station_departure_time if self.logLevel > 0: print train_name, "previous_departure_time", previous_departure_time station_departure_time = self.add_times(station_departure_time, time_to_station) if self.logLevel > 0: print train_name, route_location, "station_departure_time", station_departure_time # if the wait_time and journey_time have been set we can set the arrival time wait_time = self.find_between(comment, "[wait_time-", "-wait_time]") journey_time = self.find_between(comment, "[journey_time-", "-journey_time]") if journey_time == "": journey_time = "0" # convert journey time to fast minutes journey_time_fast_mins = ((float(str(journey_time)) * int(str(fast_clock_rate))) / 60.0) if wait_time != "" and journey_time != "": if i == -1: station_arrival_time = station_departure_time else: if self.logLevel > 0: print train_name, route_location, "journey_time", journey_time station_arrival_time = self.add_times(previous_departure_time, journey_time_fast_mins) else: if i == 0: station_arrival_time = "" else: station_arrival_time = station_departure_time [h, m] = station_departure_time.split(":") station_departure_time_in_mins = int(m) + int(h) * 60 # [h, m] = station_arrival_time.split(":") # station_arrival_time_in_mins = int(m) + int(h) * 60 if i != 0 and last_station == station_name: station_departure_time = "" # make sure we don't display trains that have a departure time > current time # keep departures up for 1 fast minutes after the departure time if self.curr_time - 1 < station_departure_time_in_mins: timetable_entry = [train_name, \ station_name , \ platform_name , \ station_arrival_time, \ station_departure_time, \ first_station, \ last_station, \ via] timetable.append(timetable_entry) #sort timetable by time timetable.sort(key = lambda row: max(row[3],row[4])) return timetable def generate_local_timetable(self, station_name, station_names_list, time, timetable): global timetable_gbl if "timetable_gbl" not in globals(): timetable_gbl = Timetable(station_name) timetable_gbl.update_timetable(station_name, station_names_list, time, timetable) elif timetable_gbl == None: timetable_gbl = Timetable(station_name) timetable_gbl.update_timetable(station_name, station_names_list, time, timetable) else: # update the Timetable, Timetable class has already been initiated timetable_gbl.update_timetable(station_name, station_names_list, time, timetable) def send_timetable_messages(self,timetable): i = 0 msg = "[" for [train_name, \ station_name , \ platform , \ station_arrival_time, \ station_departure_time, \ first_station, \ last_station, \ via] in timetable: msg += '{"type" : "' + "schedule" + '", ' + \ '"train_name" : "' + str(train_name) + '", ' + \ '"station_name" : "' + str(station_name) + '", ' + \ '"platform" : "' + str(platform) + '", ' + \ '"station_arrival_time" : "' + str(station_arrival_time) + '", ' + \ '"station_departure_time" : "' + str(station_departure_time) + '", ' + \ '"first_station" : "' + str(first_station) + '", ' + \ '"last_station" : "' + str(last_station) + '", ' + \ '"via" : "' + str(via) + '"},' i += 1 msg = msg[:-1] msg += "]" self.send_mqtt_message(msg) def send_mqtt_message(self, msg): global print_count try: # Find the MqttAdapter mqttAdapter = jmri.InstanceManager.getDefault( jmri.jmrix.mqtt.MqttSystemConnectionMemo ).getMqttAdapter() # create content to send "/jmri/timetable message content" topic = "jmri/timetable" payload = msg mqttAdapter.publish(topic, payload) except: if "print_count" not in globals(): print_count = 0 if print_count < 1: print "failure mqtt message" print_count += 1 def send_clock_message(self, hour, minutes, event): msg = '[{"type" : "' + "clock" + '", ' + \ '"time" : "' + str(hour).zfill(2) + ":" + str(minutes).zfill(2) + '",' \ '"emblem" : "' + str(event) + '"}]' self.send_mqtt_message(msg) def add_times(self, station_departure_time, time_to_station): # add time_to_station to station_departure time # station_departure_time is in form hh:mm # print "time_to_station", time_to_station , "should be mins" [hours, mins] = station_departure_time.split(":") # print "hours", hours, "mins", mins hour = int(hours) + int(time_to_station) // 60 min = (int(mins) + int(time_to_station)) % 60 # print "hour", hour, "min", min station_departure_time_new = str(hour).zfill(2) + ":" + str(min).zfill(2) # print "station_departure_time_new", station_departure_time_new return station_departure_time_new def directory2(self): # print "directory2" path = jmri.util.FileUtil.getUserFilesPath() + "dispatcher" + java.io.File.separator + "train_operators_emblem" # print "path", path if not os.path.exists(path): os.makedirs(path) return path + java.io.File.separator def write_list2(self, a_list): # store list in binary file so 'wb' mode file = self.directory2() + "train_operator_emblem.txt" if self.logLevel > 0: print "train_operator_emblem" , a_list if self.logLevel > 0: print "file" , file with open(file, 'wb') as fp: if self.logLevel > 0: print "a_list", a_list i = 0 for items in a_list: if self.logLevel > 0: print "items", items fp.write('%s' %items) if i < 5 : fp.write(",") i+=1 # Read list to memory def read_list2(self): # for reading also binary mode is important file = self.directory2() + "train_operator_emblem.txt" # print "file", file n_list = [] try: with open(file, 'rb') as fp: for line in fp: # print "line", line # x = line[:-1] # print x y = line.split(",") if self.logLevel > 0: print "y" , y n_list = y return n_list except: return ["", "", "", "", "", ""] class RunRoute(jmri.jmrit.automat.AbstractAutomaton): def __init__(self, route, graph, station_from, station_to, no_repetitions, train_name, \ delay = 0, scheduling_train = False, set_departure_times = False, train = None): # print ("route" , route, "station_from", station_from, "station_to", station_to, \ # "no_repetitions", no_repetitions, "train_name", train_name, \ # "scheduling_train", scheduling_train) # station_from is set to the initial position of the train, not necessarily # the start position of the route # station_to is set only if returning to start position # in that case it is set to station_from # the route gives the stations on the route # note station_to and station_from are strings, while elements of route are locations self.logLevel = 0 if self.logLevel > 0: print "loglevel", self.logLevel if self.logLevel > 0: print "in init RunRoute" if self.logLevel > 0: print route, station_from, station_to, no_repetitions, train_name, delay self.delay = delay self.scheduling_train = scheduling_train self.set_departure_times = set_departure_times if self.logLevel > 0: print "set_departure_times", set_departure_times self.route = route self.train = train # only used if scheduling_train = True self.train_name = train_name if route is None or train_name is None: self.mycount = None self.no_repetitions = -1 if self.logLevel > 0: print "RunRoute: route == ", route, " train_name == ", train_name else: if self.logLevel > 0: print "RunRoute: route =", route self.graph = graph self.station_from = station_from self.station_to = station_to self.no_repetitions = no_repetitions self.mycount = 0 # self.train_name_in = train_name self.train_name = train_name # null if train not in start block # set up station_list station_list_locations = self.route.getLocationsBySequenceList() #convert station_list to strings station_list = [location.getName() for location in station_list_locations] station_comment_list = [location.getComment() for location in station_list_locations] self.initial_station_in_route = station_list[0] # prepend station_from if required self.prepended = False if self.logLevel > 0: print "station_list before", station_list, "self.station_from",self.station_from,"self.station_to",self.station_to,"station_list[0]",station_list[0] if self.station_from == None: #ensure route starts at station_from pass elif self.station_from != station_list[0]: try: station_list.insert(0,self.station_from) station_comment_list.insert(0, None) except: if self.logLevel > 0: print "fred" self.prepended = True # we have to remove this initial station if we are repeating if self.logLevel > 0: print "station_list",station_list # append station_to if required if self.station_to == None: #ensure route ends at station_to pass elif self.station_to != station_list[-1]: station_list.append(self.station_to) try: station_comment_list.append(None) except: if self.logLevel > 0: print "jim" if self.logLevel > 0: print "station_list",station_list # if repeating append initial station in route if self.no_repetitions > 0: #ensure route end at start point if repeating if self.station_to != self.initial_station_in_route: if station_list[-1] != self.initial_station_in_route: station_list.append(self.initial_station_in_route) station_comment_list.append(None) if self.logLevel > 0: print "station_list after", station_list self.station_list = station_list self.station_comment_list = station_comment_list if self.logLevel > 0: print "self.station_comment_list", self.station_comment_list # ignore the number of repetitions if station_to was not set to station_from if self.station_list[0] != self.station_list[-1]: self.no_repetitions = 0 def handle(self): if self.route is not None and self.train_name is not None: if self.logLevel > 0: print "in handle", self.mycount if self.delay > 0 and self.mycount == 0: # only delay on the first iteration self.waitMsec(self.delay) if int(self.mycount) <= int(self.no_repetitions): # print "repeating", "self.mycount", self.mycount, "self.no_repetitions", self.no_repetitions if self.logLevel > 0: print "station_list in handle", self.station_list, "in handle", self.mycount response = self.run_route(self.train_name) if self.logLevel > 0: print "prepended", self.prepended if self.mycount == 0 and self.prepended: if self.logLevel > 0: print "station_list before pop", self.station_list self.station_list.pop(0) self.station_comment_list.pop(0) if self.logLevel > 0: print "station_list after pop", self.station_list if self.logLevel > 0: print "returning true", "train_name", self.train_name, "mycount", self.mycount, "reps" , self.no_repetitions self.mycount += 1 # 0 first time round return True else: if self.logLevel > 0: print "returning false", "train_name", self.train_name, "mycount", self.mycount, "reps" , self.no_repetitions return False def run_route(self, train_to_move): global check_action_route_flag global fast_clock_rate if self.logLevel > 0: print "************************************run train******************" if self.logLevel > 0: print "! start run_route" station_from = None prev_station_index = 0 for station_index, station in enumerate(self.station_list): # print "station_index", station_index, "station", station, "train_to_move", train_to_move if self.logLevel > 0: print "self.scheduling_train", self.scheduling_train # do action if one has been requested if self.station_is_action(station): #if the station_name is a python_file action = station self.execute_action(action) # execute the python file else: # print "running at station", "station_from", station_from station_to = station # both now strings if station_from != None: # first time round station_from is not set up # find the accumulated durations if self.scheduling_train or self.set_departure_times: durations = [MyTableModel5().find_between(comment, "[duration_sec-", "-duration_sec]") for comment in self.station_comment_list] # print "durations 4", durations accumulated_durations = [] total = 0 for n in durations: try: total += int(n) except: pass accumulated_durations.append(total) if station_index != self.find_row_first_location(self.route): previous_station_index = self.find_row_prev_location(station_index, self.route) station_comment = self.station_comment_list[previous_station_index] # do not use prev_station_index as it includes actions accumulated_duration = accumulated_durations[previous_station_index] else: station_comment = None accumulated_duration = 0 if self.logLevel > 0: print "station", station, "station_comment", station_comment, \ "station_index", station_index, "prev_station_index", prev_station_index if self.logLevel > 0: print "accumulated_duration", accumulated_duration if self.logLevel > 0: print self.route.getName(), "! moving from", station_from, "to", station_to self.station_from_name = station_from self.station_to_name = station_to start_block = blocks.getBlock(station_from) if self.logLevel > 0: "start_block",start_block, "station_to", station_to if self.logLevel > 0: print "calling move_between_stations","station_from",station_from,"station_to",station_to,"train_to_move",train_to_move if self.set_departure_times: # print "setting previous time" previous_time = int(round(time.time())) # in secs if self.scheduling_train: self.wait_for_scheduled_time(self.route, previous_station_index, accumulated_duration, train_to_move) # done when we know the transit name # print "__________________________Start__" + train_to_move + "___________________________________" strpad = station_index * " " success = self.check_train_in_block_for_scheduling_margin_fast_minutes(start_block, train_to_move, strpad) if success: move_train = MoveTrain(station_from, station_to, train_to_move, self.graph, mode = "scheduling", route = self.route) move_train.move_between_stations(station_from, station_to, train_to_move, self.graph, mode = "scheduling") transit_name = move_train.transit_name print "__________________________End____" + train_to_move + "__transit: " + transit_name else: print "failed to move train - no train in block - have waited for scheduling margin" transit_name = move_train.transit_name print "__________________________End____" + train_to_move + "__transit: " + transit_name else: success = self.check_train_in_block_allow_manual_repositioning(train_to_move, self.station_from_name) if success: move_train = MoveTrain(station_from, station_to, self.train_name, self.graph, route = self.route) move_train.move_between_stations(station_from, station_to, self.train_name, self.graph) move_train = None # train has moved, if we are in departure_time_setting mode, store the journey time if self.logLevel > 0: print "about to store departure times" if self.set_departure_times: if self.logLevel > 0: print "storing departure times" current_time = int(round(time.time())) # in secs journey_time_in_secs = current_time - previous_time print "previous_time", previous_time, "current_time", current_time if self.logLevel > 0: print "before store", "journey_time_in_secs", journey_time_in_secs self.store_journey_time(self.route, station_index, str(journey_time_in_secs)) if self.logLevel > 0: print "after store" if self.logLevel > 0: print "finished move between stations station_from = ", station_from, " station_to = ", station_to end_block = blocks.getBlock(station_to) #do following in case the block sensor is a bit dodgy end_block.setValue(self.train_name) check_action_route_flag = False # This flag may have been set by the action appearing in the route # before this move. It has to be reset. # print "check_action_route_flag reset", check_action_route_flag station_from = station_to prev_station_index = station_index if self.scheduling_train: fast_minute = 1000*60/int(str(fast_clock_rate)) self.waitMsec(fast_minute) else: self.waitMsec(4000) if self.logLevel > 0: print "! finished run_train" def find_row_first_location(self, route): # print "find_row_first_location" # get the row (sequenceNo) of the first location that is not an action (a python file xx.py) routelocationsSequenceNumber_list = [ [routelocation, routelocation.getSequenceNumber()] \ for routelocation in route.getLocationsBySequenceList() \ if ".py" not in routelocation.getName()] # print "routelocationsSequenceNumber_list", routelocationsSequenceNumber_list current_val = [[routelocation, sequenceNo] \ for [routelocation, sequenceNo] in routelocationsSequenceNumber_list \ if 1 == sequenceNo][0] # print "current_val", current_val current_index = routelocationsSequenceNumber_list.index(current_val) # print "current_index", current_index # print "routelocations_list", routelocations_list, "index", index try: [routelocation, row] = routelocationsSequenceNumber_list[current_index] # row = routelocationsSequenceNumber_list[currentIndex + 1] except: row = None # print "row", row return row - 1 # row number starts from 0 def find_row_prev_location(self, row, route): # get the row (sequenceNo) of the first location that is not an action (a python file xx.py) routelocationsSequenceNumber_list = [ [routelocation, routelocation.getSequenceNumber()] \ for routelocation in route.getLocationsBySequenceList() \ if ".py" not in routelocation.getName()] current_val_list = [[routelocation, sequenceNo] \ for [routelocation, sequenceNo] in routelocationsSequenceNumber_list \ if row == sequenceNo-1] current_val = current_val_list[0] current_index = routelocationsSequenceNumber_list.index(current_val) [routelocation, row] = routelocationsSequenceNumber_list[current_index - 1] return row - 1 # row number starts from 1 def check_train_in_block_for_scheduling_margin_fast_minutes(self, start_block, train_to_move, strpad = ""): global scheduling_margin_gbl global timebase # print "__________________________Start__" + train_to_move + "___________________________________" # timehm = str(timebase.getTime().getHours()) + ":" + str(timebase.getTime().getMinutes()) timehm = "{:02d}:{:02d}".format(timebase.getTime().getHours(), timebase.getTime().getMinutes()) print timehm, strpad, "check_train", train_to_move, "in_block", start_block.getUserName(), "for", scheduling_margin_gbl, "fast_minutes" global fast_clock_rate if self.logLevel > 0: print "check_train_in_block_for_scheduling_margin_fast_minutes" for j in range(int(scheduling_margin_gbl)): # try to schedule train for scheduling_margin_gbl fast minutes train_in_block = self.blockOccupied(start_block) train_block_name = start_block.getValue() if train_in_block and (train_block_name == train_to_move): # print strpad + "--" + str(train_to_move) + " train in start block " + str(start_block.getUserName()) return True else: print (strpad + "--" + str(train_to_move) + " not in start_block: " + str(start_block.getUserName()) \ + " time waited: " + str(j) + " fast minutes") fast_minute = 1000*60/int(str(fast_clock_rate)) self.waitMsec(fast_minute) return False def check_train_in_block_allow_manual_repositioning(self, train_name, station_from_name): i = 0 # print "train_name", train_name, "station_from_name", station_from_name while self.check_train_in_start_block(train_name, station_from_name) == False: if i > 2: # allow some time to recover title = "" msg = "Cannot run train, train not in start block\n" + \ train_name + " should be in block " + station_from_name + \ "\nmove it there manually and it might recover" opt1 = "have moved train, try again" opt2 = "cancel moving train" reply = OptionDialog().customQuestionMessage2str(msg, title, opt1, opt2) if reply == opt1: # "have moved train, try again" i = -1 else: # opt2 return False # "cancel moving train" self.waitMsec(5000) i += 1 # move_train = MoveTrain(station_from, station_to, train_to_move, self.graph, station_comment) # move_train.move_between_stations(station_from, station_to, train_to_move, self.graph) return True def store_journey_time(self, route, row, journey_time): global CreateAndShowGUI5_glb routeLocationList = route.getLocationsBySequenceList() routeLocation = routeLocationList[row] print "routeLocation", routeLocation, "row", row, "value", journey_time, "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%5" # OptionDialog().displayMessageNonModal("about to set_value_in_comment", "OK") self.set_value_in_comment(routeLocation, journey_time, "journey_time") wait_time = self.get_value_in_comment(routeLocation, "wait_time") duration_sec = int(journey_time) + int(wait_time) self.set_value_in_comment(routeLocation, duration_sec, "duration_sec") # OptionDialog().displayMessageNonModal("about to populate_action", "OK") CreateAndShowGUI5_glb.populate_action(None) # OptionDialog().displayMessageNonModal("about to update_journey_time_action", "OK") CreateAndShowGUI5_glb.update_journey_time_action(None) # OptionDialog().displayMessageNonModal("just did update_journey_time_action", "OK") # CreateAndShowGUI5_glb.update_duration_action(None) # def set_value_in_comment(self, routeLocation, value, duration_string): global CreateAndShowGUI5_glb comment = routeLocation.getComment() #Null if comment == None: comment = "" delim_start = "[" + duration_string + "-" delim_end = "-" + duration_string + "]" comment = CreateAndShowGUI5_glb.insert_between(comment, delim_start, delim_end, value) routeLocation.setComment(comment) def get_value_in_comment(self, routeLocation, duration_string): delim_start = "[" + duration_string + "-" delim_end = "-" + duration_string + "]" comment = routeLocation.getComment() value = self.find_between(comment, "[" + duration_string + "-", "-" + duration_string + "]") return value def find_between(self, s, first, last): try: start = s.index(first) + len(first) end = s.index(last, start) return s[start:end] except ValueError: return "" def wait_for_scheduled_time(self, route, row, accumulated_durations, train_to_move): global fast_clock_rate global timebase global scheduling_margin_gbl if 'timebase' not in globals(): timebase = jmri.InstanceManager.getDefault(jmri.Timebase) routeLocationList = route.getLocationsBySequenceList() routeLocation = routeLocationList[row] train_comment = self.train.getComment() if self.logLevel > 0: print "train_to_move", train_to_move, "routeLocation", routeLocation comment = routeLocation.getComment() # print "train_comment", train_comment, "comment", comment if self.logLevel > 0: print "x1" repeat_command = TimeListener().find_between(train_comment, "[repeat-", "-repeat]") if self.logLevel > 0: print "x3" current_minutes = int(timebase.getTime().getMinutes()) if self.logLevel > 0: print "x2", "current_minutes", current_minutes # the departure time for the train is the first one in the hour # get what would be the current time if we were running the first train in the hour # so we can get the difference of the two and hence get the wait time # this is easier than getting the actual departure time minutes of the train if repeat_command == "Once": current_minutes_mod = current_minutes current_minutes_mod_array = [current_minutes_mod] elif repeat_command == "Repeat every 20 mins": current_minutes_mod = current_minutes % 20 cmm20 = self.add_minutes(current_minutes_mod, 20) cmm40 = self.add_minutes(current_minutes_mod, 40) current_minutes_mod_array = [current_minutes_mod, cmm20, cmm40] elif repeat_command == "Repeat every 30 mins": current_minutes_mod = current_minutes % 30 cmm30 = self.add_minutes(current_minutes_mod, 30) current_minutes_mod_array = [current_minutes_mod, cmm30] elif repeat_command == "Repeat every Hour": current_minutes_mod = current_minutes current_minutes_mod_array = [current_minutes_mod] elif repeat_command == "Repeat every 2 Hours": current_minutes_mod = current_minutes current_minutes_mod_array = [current_minutes_mod] else: print "error wrong repeat command" return if self.logLevel > 0: print "d", current_minutes, "current_minutes_mod", current_minutes_mod current_hour = int(str(timebase.getTime().getHours())) if self.logLevel > 0: print("a"), current_hour current_time = str(current_hour).zfill(2) + ":" + str(current_minutes_mod).zfill(2) if self.logLevel > 0: print "c", current_time train_start_time = self.train.getDepartureTime() if self.logLevel > 0: print "train_start_time", train_start_time, "accumulated_durations", accumulated_durations accumulated_durations_fast_mins = (accumulated_durations / 60.0) * int(str(fast_clock_rate)) # convert to fast min if self.logLevel > 0: print "accumulated_durations_fast_mins", accumulated_durations_fast_mins station_start_time = self.add_minutes_to_time(train_start_time, accumulated_durations_fast_mins) [station_start_hours, station_start_mins] = station_start_time.split(":") if self.logLevel > 0: print "station_start_time", station_start_time if self.logLevel > 0: print "current_time", current_time, "station_start_time", station_start_time #calculate minutes to wait minutes_to_wait_array = [self.subtract_minutes(station_start_mins, cm) for cm in current_minutes_mod_array] if self.logLevel > 0: print "minutes_to_wait_array", minutes_to_wait_array minutes_to_wait = min(minutes_to_wait_array) if self.logLevel > 0: print "minutes_to_wait", minutes_to_wait minutes_late = max([m-60 for m in minutes_to_wait_array]) # get the minutes late abs_minutes_late = abs(minutes_late) if self.logLevel > 0: print "minutes_late", minutes_late if self.logLevel > 0: print "minutes_late", abs_minutes_late index = minutes_to_wait_array.index(minutes_to_wait) if abs_minutes_late < int(scheduling_margin_gbl): if self.logLevel > 0: print "minutes_late2", minutes_late, "scheduling_margin_gbl", scheduling_margin_gbl fast_ms_to_wait = 0 else: if self.logLevel > 0: print "minutes_to_wait", minutes_to_wait fast_ms_to_wait = abs(minutes_to_wait) * 60 * 1000 if self.logLevel > 0: print "waiting for ", current_minutes_mod_array[index] if self.logLevel > 0: print "v" ms_to_wait = fast_ms_to_wait / int(fast_clock_rate) if self.logLevel > 0: print "w" if self.logLevel > 0: print "waiting", "minutes_to_wait", minutes_to_wait if self.logLevel > 0: print "waiting", "ms_to_wait", ms_to_wait, "fast_secs_to_wait", fast_ms_to_wait/1000 if self.logLevel > 0: print "time before wait", str(timebase.getTime()) self.waitMsec(ms_to_wait) if self.logLevel > 0: print "time after wait", str(timebase.getTime()) if self.logLevel > 0: print "waited till start time" def add_minutes(self, min1, min2): min = (int(min1) + int(min2) ) % 60 return min def add_minutes_to_time(self, time, minutes): if self.logLevel > 0: print "z", time, minutes [day, time_hours, time_mins] = time.split(":") if self.logLevel > 0: print "add minutes to time" if self.logLevel > 0: print "time", time, "minutes", minutes # print "hours", hours, "mins", mins hour = int(str(time_hours)) + (int(time_mins) + int(minutes)) // 60 if self.logLevel > 0: print "hour" min = (int(minutes) + int(time_mins) ) % 60 if self.logLevel > 0: print "min", min if self.logLevel > 0: print "hour", hour, "min", min station_departure_time_new = str(hour).zfill(2) + ":" + str(min).zfill(2) if self.logLevel > 0: print "station_departure_time_new", station_departure_time_new return station_departure_time_new def subtract_times(self, current_time, station_time): if self.logLevel > 0: print "subtract times" [curr_hours, curr_mins] = current_time.split(":") # current_mins = int(curr_hours) * 60 + int(curr_mins) current_mins = int(curr_mins) if self.logLevel > 0: print "curr_hours", curr_hours, "curr_mins", curr_mins, "current_mins", current_mins [dep_hours, dep_mins] = station_time.split(":") # station_mins = int(dep_hours) * 60 + int(dep_mins) station_mins = int(dep_mins) if self.logLevel > 0: print "dep_hours", dep_hours, "dep_mins", dep_mins, "station_mins", station_mins # print "current_time", current_time, "mins", mins wait_time = station_mins - current_mins if self.logLevel > 0: print "wait_time", wait_time wait_time = wait_time % 60 if self.logLevel > 0: print "wait_time", wait_time return wait_time def subtract_minutes(self, min1, min2): wait_time = int(min1) - int(min2) if self.logLevel > 0: print "wait_time", wait_time wait_time = wait_time % 60 if self.logLevel > 0: print "wait_time", wait_time return wait_time def subtract_times_neg(self, current_time, station_time): if self.logLevel > 0: print "subtract times" [curr_hours, curr_mins] = current_time.split(":") # current_mins = int(curr_hours) * 60 + int(curr_mins) current_mins = int(curr_mins) if self.logLevel > 0: print "curr_hours", curr_hours, "curr_mins", curr_mins, "current_mins", current_mins [dep_hours, dep_mins] = station_time.split(":") # station_mins = int(dep_hours) * 60 + int(dep_mins) station_mins = int(dep_mins) if self.logLevel > 0: print "dep_hours", dep_hours, "dep_mins", dep_mins, "station_mins", station_mins # print "current_time", current_time, "mins", mins wait_time = station_mins - current_mins if self.logLevel > 0: print "wait_time", wait_time wait_time = wait_time % 60 if self.logLevel > 0: print "wait_time", wait_time return wait_time - 60 def get_next_item_in_list(self,elem, li ): if (li.index(elem))+1 != len(li): thiselem = elem nextelem = li[li.index(elem)+1] indexNextElem = li.index(elem)+1 # print 'thiselem',thiselem # print 'nextel',nextelem else: thiselem = elem nextelem = elem indexNextElem = li.index(elem) # print 'thiselem',li[li.index(elem)] # print 'nextel',li[li.index(elem)] return [nextelem, indexNextElem] def check_train_in_start_block(self, train_to_move, blockName): block = blocks.getBlock(blockName) if self.blockOccupied(block): if block.getValue() == train_to_move: return True else: "blockName" , blockName, "not occupied by", "train_to_move", train_to_move blockName = [block for block in blocks.getNamedBeanSet() if block.getValue() == train_to_move] if blockName != []: blockName = blockName[0] else: blockName = "train not in any block" #print "train_to_move", train_to_move, "in" , blockName return False else: #print "train_to_move", train_to_move, "not in" , blockName blockName = [block for block in blocks.getNamedBeanSet() if block.getValue() == train_to_move] if blockName != []: blockName = blockName[0] else: blockName = "train not in any block" #print "train_to_move", train_to_move, "in" , blockName return False def blockOccupied(self, block): if block.getState() == ACTIVE: state = True else: state = False return state def station_is_action(self, station): if station[-3:] == ".py": return True else: return False def action_directory_in_DispatcherSystem(self): path = jmri.util.FileUtil.getScriptsPath() + "DispatcherSystem" + java.io.File.separator + "actions" if not os.path.exists(path): os.makedirs(path) return path + java.io.File.separator def action_directory(self): path = jmri.util.FileUtil.getUserFilesPath() + "dispatcher" + java.io.File.separator + "actions" if not os.path.exists(path): os.makedirs(path) return path + java.io.File.separator def execute_action(self, action): # execute a python file in the dispatcher directory file = self.action_directory() + action if not os.path.isfile(file): file = self.action_directory_in_DispatcherSystem() + action if not os.path.isfile(file): self.displayMessage("action file " + action + " does not exist, it must have been deleted\n" + \ "should be in directories:\n" + \ self.action_directory_in_DispatcherSystem() + " or\n" + \ self.action_directory()) if self.logLevel > 0: print self.route.getName()," executing file", file exec(open(file).read()) # execute the file def displayMessage(self, msg, title = ""): self.CLOSED_OPTION = False s = JOptionPane.showOptionDialog(None, msg, title, JOptionPane.YES_NO_OPTION, JOptionPane.PLAIN_MESSAGE, None, ["OK"], None) #JOptionPane.showMessageDialog(None, msg, 'Message', JOptionPane.WARNING_MESSAGE) if s == JOptionPane.CLOSED_OPTION: self.CLOSED_OPTION = True return return s class ScheduleTrains(jmri.jmrit.automat.AbstractAutomaton): def setup(self): self.logLevel = 0 return True def handle(self): # print "run trains" self.run_trains() #schedule trains if schedule_trains_glb is set True external to this routine # continue scheduling trains # print "end run trains" return True def run_trains(self): global trains_to_be_scheduled global schedule_trains_glb global fast_clock_running_at_operational_speed global scheduled global timebase global fast_clock_rate if self.logLevel > 0 : print "************************************run trains******************" # schedule_trains_glb = True if True: if 'fast_clock_running_at_operational_speed' not in globals(): fast_clock_running_at_operational_speed = True if self.logLevel > 0 : print "run trains started: loop: scheduled trains", trains_to_be_scheduled, \ "fast_clock_running_at_operational_speed", fast_clock_running_at_operational_speed # print "scheduled", scheduled if fast_clock_running_at_operational_speed: for train in trains_to_be_scheduled: # print "train", train, "type", type(train) if train.getDescription() is not None: # print "description", train.getDescription() # print "scheduled[train]", scheduled[train] if scheduled[train] == False: if self.logLevel > 0: print "train",train,"scheduled[train]",scheduled[train] route = train.getRoute() if route is not None: routeName = route.getName() station_from, station_to = SchedulerMaster().get_first_and_last_station(route) # starting from beginning of route start_block = blocks.getBlock(station_from) if self.logLevel > 0: "start_block",start_block, "station_to", station_to # train_block_name = start_block.getValue() train_to_be_scheduled = train.getDescription() # this is obsolete: now checked in check_train_in_block_for_scheduling_margin_fast_minutes in run_route in class RunRoute # run_route_flag = self.check_train_ok_to_start(train, train_block_name) no_repetitions = 0 if True: if "stopping" in train.getDescription(): # print "running train %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", train run_train = RunRoute(route, g.g_stopping, station_from, station_to, no_repetitions, train_to_be_scheduled, \ scheduling_train = True, train = train) run_train.setName("running_route_" + routeName) instanceList.append(run_train) run_train.start() else: # print "running train %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", train run_train = RunRoute(route, g.g_express, station_from, station_to, no_repetitions, train_to_be_scheduled, \ scheduling_train = True, train = train) run_train.setName("running_route_" + routeName) instanceList.append(run_train) run_train.start() scheduled[train] = True trains_to_be_scheduled.pop(trains_to_be_scheduled.index(train)) if self.logLevel > 0: print "scheduled train ", train if self.logLevel > 0: print "!!!!!!!!!!!!!!!!!!!!!run_trains finished" if self.logLevel > 0: print "trains_to_be_scheduled ", trains_to_be_scheduled if 'timebase' in globals(): if self.logLevel > 0: print "timebase.getRate()",timebase.getRate() msecs_in_half_fast_minute = int(500.0 / float(str(fast_clock_rate)) * 60.0) # noMsec = int(1000/timebase.getRate()) self.waitMsec(msecs_in_half_fast_minute) # twice every fast minute def check_train_ok_to_start(self, train, train_block_name): # check the scheduled train is in the starting block if train_block_name == train.getDescription(): # print "returning true" return True else: # print "returning false", "train_block_name", train_block_name, "train.getDescription()", train.getDescription() return False