diff --git a/period-test.py b/period-test.py index cf509b1..d654784 100644 --- a/period-test.py +++ b/period-test.py @@ -27,7 +27,7 @@ def main(): "23:59:59", ] - SimulationThread.initialize(periods, datetime.time.fromisoformat("07:59"), 60, 4.0) + SimulationThread.initialize(periods, datetime.time.fromisoformat("07:59"), 60, 4.0, True) for test_time in test_times: test_time_obj = datetime.time.fromisoformat(test_time) diff --git a/simulation/simulation_thread.py b/simulation/simulation_thread.py index 74bd7d7..699f462 100644 --- a/simulation/simulation_thread.py +++ b/simulation/simulation_thread.py @@ -14,11 +14,11 @@ class SimulationThread(threading.Thread): instance = None @classmethod - def initialize(cls, periods, start_time=None, run_time=None, time_factor=1.0): + def initialize(cls, periods, start_time=None, run_time=None, time_factor=1.0, verbose=False): """ Initializes the singleton Thread with the given values. The given arguments are passed directly to the instance constructor. See the `__init__` method for argument details. """ - cls.instance = SimulationThread(periods, start_time, run_time, time_factor) + cls.instance = SimulationThread(periods, start_time, run_time, time_factor, verbose) @classmethod def get_instance(cls): @@ -27,7 +27,7 @@ class SimulationThread(threading.Thread): """ return cls.instance - def __init__(self, periods, start_time, run_time, time_factor): + def __init__(self, periods, start_time, run_time, time_factor, verbose): """ Creates a simulation with the provided data and settings. @@ -36,6 +36,7 @@ class SimulationThread(threading.Thread): start_time (datetime.time): The time at which the simulation should start. run_time (int): The amount of (real) time the simulation should run for before terminating. If None, run indefinitely or until signal_stop() is called. time_factor (float): The time "accelleration" factor at which the simulation should run. A value of 1.0 indicates indentity with real time, and higher values run faster (e.g. 4.0 = four simulated seconds for each real second). + verbose (bool): If True, outputs progress information to stdout (for testing purposes only). """ # Parent constructor call (required). Uses parameter daemon=True to ensure thread shutdown when parent program finishes executing # See https://docs.python.org/3/library/threading.html @@ -47,6 +48,7 @@ class SimulationThread(threading.Thread): self.start_time = start_time self.run_time = run_time self.time_factor = time_factor + self.verbose = verbose # NOT a status variable, instead indicates whether signal_stop() has been called self.running = True @@ -140,15 +142,14 @@ class SimulationThread(threading.Thread): self.next_changeover_time = real_start_time + (self.periods[self.current_period_index]["states"][self.current_state_index]["duration"] / self.time_factor) - # print("Starting with simulation time {}".format(self.simulation_start_datetime.time())) - # print("Initial state data: {}".format(self.periods[self.current_period_index]["states"][self.current_state_index])) - """ - if self.run_time is None: - print("No simulation time limit.") - else: - print("Simulation duration (in real second(s)): {}".format(self.run_time)) - """ - # print("Time compression factor: {}".format(self.run_time, self.time_factor)) + if self.verbose: + print("Starting with simulation time {}".format(self.simulation_start_datetime.time())) + print("Initial state data: {}".format(self.periods[self.current_period_index]["states"][self.current_state_index])) + if self.run_time is None: + print("No simulation time limit.") + else: + print("Simulation duration (in real second(s)): {}".format(self.run_time)) + print("Time compression factor: {}".format(self.time_factor)) while (self.run_time is None) or (self.run_time is not None and time.time() < real_start_time + self.run_time): self.mutex.acquire() @@ -164,39 +165,38 @@ class SimulationThread(threading.Thread): if now >= self.next_changeover_time: timed_period_index = self._get_period_index(self.current_simulation_datetime.time()) if timed_period_index != self.current_period_index and self.current_state_index == len(self.periods[self.current_period_index]["states"])-1: - # print() - # print("{} : Changing PERIOD from {} to {}".format(self.current_simulation_datetime.time(), self.periods[self.current_period_index]["name"], self.periods[timed_period_index]["name"])) - # print(" Old state data: {}".format(self.periods[self.current_period_index]["states"][self.current_state_index])) + if self.verbose: + print() + print("{} : Changing PERIOD from {} to {}".format(self.current_simulation_datetime.time(), self.periods[self.current_period_index]["name"], self.periods[timed_period_index]["name"])) + print(" Old state data: {}".format(self.periods[self.current_period_index]["states"][self.current_state_index])) # Safe to change period self.current_period_index = timed_period_index self.current_state_index = 0 - # print(" New state data: {}".format(self.periods[self.current_period_index]["states"][self.current_state_index])) - # print(" Next changeover in {} second(s)".format(self.periods[self.current_period_index]["states"][self.current_state_index]["duration"])) + if self.verbose: + print(" New state data: {}".format(self.periods[self.current_period_index]["states"][self.current_state_index])) + print(" Next changeover in {} second(s)".format(self.periods[self.current_period_index]["states"][self.current_state_index]["duration"])) else: # Current sequence still completing, not safe to change to next period next_cycle_index = (self.current_state_index + 1) % len(self.periods[self.current_period_index]["states"]) - # print() - # print("{} : {} : Changing state from {} to {}".format(self.current_simulation_datetime.time(), self.periods[self.current_period_index]["name"], self.current_state_index, next_cycle_index)) - """ - if self.current_period_index != timed_period_index: - print(" [period change pending]") - """ - # print(" Old state data: {}".format(self.periods[self.current_period_index]["states"][self.current_state_index])) - # print(" New state data: {}".format(self.periods[self.current_period_index]["states"][next_cycle_index])) - # print(" Next changeover in {} second(s)".format(self.periods[self.current_period_index]["states"][next_cycle_index]["duration"])) + if self.verbose: + print() + print("{} : {} : Changing state from {} to {}".format(self.current_simulation_datetime.time(), self.periods[self.current_period_index]["name"], self.current_state_index, next_cycle_index)) + if self.current_period_index != timed_period_index: + print(" [period change pending]") + print(" Old state data: {}".format(self.periods[self.current_period_index]["states"][self.current_state_index])) + print(" New state data: {}".format(self.periods[self.current_period_index]["states"][next_cycle_index])) + print(" Next changeover in {} second(s)".format(self.periods[self.current_period_index]["states"][next_cycle_index]["duration"])) self.current_state_index = next_cycle_index self.next_changeover_time = self.next_changeover_time + (self.periods[self.current_period_index]["states"][self.current_state_index]["duration"] / self.time_factor) else: - pass - """ - print(".", end="") - sys.stdout.flush() - """ + if self.verbose: + print(".", end="") + sys.stdout.flush() self.mutex.release() time.sleep(1.0 / self.time_factor) diff --git a/trafficlightfrontend/apps.py b/trafficlightfrontend/apps.py index 455502d..670aed1 100644 --- a/trafficlightfrontend/apps.py +++ b/trafficlightfrontend/apps.py @@ -6,6 +6,7 @@ from django.conf import settings from simulation import SimulationThread + class TrafficlightfrontendConfig(AppConfig): default_auto_field = 'django.db.models.BigAutoField' name = 'trafficlightfrontend' @@ -24,7 +25,7 @@ class TrafficlightfrontendConfig(AppConfig): periods = json.load(open(os.path.join(settings.BASE_DIR, settings.SIMULATION_DATA_FILE))) - SimulationThread.initialize(periods, start_time=datetime.time.fromisoformat(settings.SIMULATION_START_TIME), time_factor=settings.SIMULATION_TIME_FACTOR) + SimulationThread.initialize(periods, start_time=datetime.time.fromisoformat(settings.SIMULATION_START_TIME), time_factor=settings.SIMULATION_TIME_FACTOR, verbose=False) SimulationThread.get_instance().start() TrafficlightfrontendConfig.initialized = True