01234567890123456789012345678901234567890123456789012345678901234567890123456789
6262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301 63026303630463056306630763086309631063116312631363146315631663176318631963206321 63336334633563366337633863396340634163426343634463456346634763486349635063516352 635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433 | <----SKIPPED LINES----> def Heartbeat(last_heartbeat_time=None): """Logs a system up heartbeat.""" if SIMULATION: return last_heartbeat_time now = time.time() if not last_heartbeat_time or now - last_heartbeat_time > HEARTBEAT_SECONDS: UpdateDashboard(False) # Send an all-clear message last_heartbeat_time = now return last_heartbeat_time def VersionControl(): """Copies current instances of messageboard.py and arduino.py into repository. To aid debugging, we want to keep past versions of the code easily accessible, and linked to the errors that have been logged. This function copies the python code into a version control directory after adding in a date / time stamp to the file name. """ def MakeCopy(python_prefix): file_extension = '.py' live_name = python_prefix + '.py' live_path = os.path.join(CODE_REPOSITORY, live_name) epoch = os.path.getmtime(live_path) last_modified_suffix = EpochDisplayTime( epoch, format_string='-%Y-%m-%d-%H%M') version_name = python_prefix + last_modified_suffix + file_extension version_path = os.path.join(VERSION_REPOSITORY, version_name) if not os.path.exists(version_path): shutil.copyfile(live_path, version_path) return version_name global VERSION_MESSAGEBOARD global VERSION_ARDUINO VERSION_MESSAGEBOARD = MakeCopy('messageboard') VERSION_ARDUINO = MakeCopy('arduino') def main(): """Traffic cop between radio, configuration, and messageboard. This is the main logic, checking for new flights, augmenting the radio signal with additional web-scraped data, and generating messages in a form presentable to the messageboard. """ VersionControl() # Since this clears log files, it should occur first before we start logging if '-s' in sys.argv: global SIMULATION_COUNTER SimulationSetup() last_heartbeat_time = HeartbeatRestart() init_timing = [(time.time(), 0)] # This flag slows down simulation time around a flight, great for <----SKIPPED LINES----> if already_running_ids: for pid in already_running_ids: Log('Sending termination signal to %d' % pid) os.kill(pid, signal.SIGTERM) init_timing.append((time.time(), 2)) SetPinMode() configuration = ReadAndParseSettings(CONFIG_FILE) Log('Read CONFIG_FILE at %s: %s' % (CONFIG_FILE, str(configuration))) startup_time = time.time() json_desc_dict = {} init_timing.append((time.time(), 3)) flights = UnpickleObjectFromFile( PICKLE_FLIGHTS, True, max_days=MAX_INSIGHT_HORIZON_DAYS) # Clear the loaded flight of any cached data, identified by keys # with a specific suffix, since code fixes may change the values for # some of those cached elements for flight in flights: for key in list(flight.keys()): if key.endswith(CACHED_ELEMENT_PREFIX): flight.pop(key) init_timing.append((time.time(), 4)) screen_history = UnpickleObjectFromFile(PICKLE_SCREENS, True, max_days=2) # If we're displaying just a single insight message, we want it to be # something unique, to the extent possible; this dict holds a count of # the diff types of messages displayed so far insight_message_distribution = {} # bootstrap the flight insights distribution from a list of insights on each # flight (i.e.: flight['insight_types'] for a given flight might look like # [1, 2, 7, 9], or [], to indicate which insights were identified; this then # transforms that into {0: 25, 1: 18, ...} summing across all flights. missing_insights = [] for flight in flights: if 'insight_types' not in flight: missing_insights.append('%s on %s' % ( DisplayFlightNumber(flight), DisplayTime(flight, '%x %X'))) distribution = flight.get('insight_types', []) for key in distribution: insight_message_distribution[key] = ( insight_message_distribution.get(key, 0) + 1) if missing_insights: Log('Flights missing insight distributions: %s' % ';'.join(missing_insights)) init_timing.append((time.time(), 5)) # initialize objects required for arduinos, but we can only start them # in the main loop, because the tail end of the init section needs to # confirm that all other messageboard.py processes have exited! to_remote_q, to_servo_q, to_main_q, shutdown = InitArduinoVariables() remote, servo = None, None # used in simulation to print the hour of simulation once per simulated hour prev_simulated_hour = '' persistent_nearby_aircraft = {} # key = flight number; value = last seen epoch persistent_path = {} histogram = {} # Next up to print is index 0; this is a list of tuples: # tuple element#1: flag indicating the type of message that this is # tuple element#2: the message itself message_queue = [] next_message_time = time.time() # We repeat the loop every x seconds; this ensures that if the processing # time is long, we don't wait another x seconds after processing completes next_loop_time = time.time() + LOOP_DELAY_SECONDS # These files are read only if the version on disk has been modified more # recently than the last time it was read last_dump_json_timestamp = 0 init_timing.append((time.time(), 6)) WaitUntilKillComplete(already_running_ids) init_timing.append((time.time(), 7)) LogTimes(init_timing) Log('Finishing initialization of %d; starting radio polling loop' % os.getpid()) while ((not SIMULATION or SIMULATION_COUNTER < len(DUMP_JSONS)) and not SHUTDOWN_SIGNAL): last_heartbeat_time = Heartbeat(last_heartbeat_time) new_configuration = ReadAndParseSettings(CONFIG_FILE) UpdateRollingLogSize(new_configuration) CheckForNewFilterCriteria( configuration, new_configuration, message_queue, flights) configuration = new_configuration ResetLogs(configuration) # clear the logs if requested UpdateRollingLogSize(configuration) # if this is a SIMULATION, then process every diff dump. But if it <----SKIPPED LINES----> |
01234567890123456789012345678901234567890123456789012345678901234567890123456789
62626263626462656266626762686269627062716272627362746275627662776278627962806281 628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323 633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436 | <----SKIPPED LINES----> def Heartbeat(last_heartbeat_time=None): """Logs a system up heartbeat.""" if SIMULATION: return last_heartbeat_time now = time.time() if not last_heartbeat_time or now - last_heartbeat_time > HEARTBEAT_SECONDS: UpdateDashboard(False) # Send an all-clear message last_heartbeat_time = now return last_heartbeat_time def VersionControl(): """Copies current instances of messageboard.py and arduino.py into repository. To aid debugging, we want to keep past versions of the code easily accessible, and linked to the errors that have been logged. This function copies the python code into a version control directory after adding in a date / time stamp to the file name. """ global VERSION_MESSAGEBOARD global VERSION_ARDUINO VERSION_MESSAGEBOARD = MakeVersionCopy('messageboard') VERSION_ARDUINO = MakeVersionCopy('arduino') def MakeVersionCopy(python_prefix): file_extension = '.py' live_name = python_prefix + '.py' live_path = os.path.join(CODE_REPOSITORY, live_name) epoch = os.path.getmtime(live_path) last_modified_suffix = EpochDisplayTime( epoch, format_string='-%Y-%m-%d-%H%M') version_name = python_prefix + last_modified_suffix + file_extension version_path = os.path.join(VERSION_REPOSITORY, version_name) if not os.path.exists(version_path): shutil.copyfile(live_path, version_path) return version_name def main(): """Traffic cop between radio, configuration, and messageboard. This is the main logic, checking for new flights, augmenting the radio signal with additional web-scraped data, and generating messages in a form presentable to the messageboard. """ VersionControl() # Since this clears log files, it should occur first before we start logging if '-s' in sys.argv: global SIMULATION_COUNTER SimulationSetup() last_heartbeat_time = HeartbeatRestart() init_timing = [(time.time(), 0)] # This flag slows down simulation time around a flight, great for <----SKIPPED LINES----> if already_running_ids: for pid in already_running_ids: Log('Sending termination signal to %d' % pid) os.kill(pid, signal.SIGTERM) init_timing.append((time.time(), 2)) SetPinMode() configuration = ReadAndParseSettings(CONFIG_FILE) Log('Read CONFIG_FILE at %s: %s' % (CONFIG_FILE, str(configuration))) startup_time = time.time() json_desc_dict = {} init_timing.append((time.time(), 3)) flights = UnpickleObjectFromFile( PICKLE_FLIGHTS, True, max_days=MAX_INSIGHT_HORIZON_DAYS) # Clear the loaded flight of any cached data, identified by keys # with a specific suffix, since code fixes may change the values for # some of those cached elements init_timing.append((time.time(), 4)) for flight in flights: for key in list(flight.keys()): if key.endswith(CACHED_ELEMENT_PREFIX): flight.pop(key) init_timing.append((time.time(), 5)) screen_history = UnpickleObjectFromFile(PICKLE_SCREENS, True, max_days=2) # If we're displaying just a single insight message, we want it to be # something unique, to the extent possible; this dict holds a count of # the diff types of messages displayed so far insight_message_distribution = {} # bootstrap the flight insights distribution from a list of insights on each # flight (i.e.: flight['insight_types'] for a given flight might look like # [1, 2, 7, 9], or [], to indicate which insights were identified; this then # transforms that into {0: 25, 1: 18, ...} summing across all flights. missing_insights = [] for flight in flights: if 'insight_types' not in flight: missing_insights.append('%s on %s' % ( DisplayFlightNumber(flight), DisplayTime(flight, '%x %X'))) distribution = flight.get('insight_types', []) for key in distribution: insight_message_distribution[key] = ( insight_message_distribution.get(key, 0) + 1) if missing_insights: Log('Flights missing insight distributions: %s' % ';'.join(missing_insights)) init_timing.append((time.time(), 6)) # initialize objects required for arduinos, but we can only start them # in the main loop, because the tail end of the init section needs to # confirm that all other messageboard.py processes have exited! to_remote_q, to_servo_q, to_main_q, shutdown = InitArduinoVariables() remote, servo = None, None # used in simulation to print the hour of simulation once per simulated hour prev_simulated_hour = '' persistent_nearby_aircraft = {} # key = flight number; value = last seen epoch persistent_path = {} histogram = {} # Next up to print is index 0; this is a list of tuples: # tuple element#1: flag indicating the type of message that this is # tuple element#2: the message itself message_queue = [] next_message_time = time.time() # We repeat the loop every x seconds; this ensures that if the processing # time is long, we don't wait another x seconds after processing completes next_loop_time = time.time() + LOOP_DELAY_SECONDS # These files are read only if the version on disk has been modified more # recently than the last time it was read last_dump_json_timestamp = 0 init_timing.append((time.time(), 7)) WaitUntilKillComplete(already_running_ids) init_timing.append((time.time(), 8)) LogTimes(init_timing) Log('Finishing initialization of %d; starting radio polling loop' % os.getpid()) while ((not SIMULATION or SIMULATION_COUNTER < len(DUMP_JSONS)) and not SHUTDOWN_SIGNAL): last_heartbeat_time = Heartbeat(last_heartbeat_time) new_configuration = ReadAndParseSettings(CONFIG_FILE) UpdateRollingLogSize(new_configuration) CheckForNewFilterCriteria( configuration, new_configuration, message_queue, flights) configuration = new_configuration ResetLogs(configuration) # clear the logs if requested UpdateRollingLogSize(configuration) # if this is a SIMULATION, then process every diff dump. But if it <----SKIPPED LINES----> |