01234567890123456789012345678901234567890123456789012345678901234567890123456789
5006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063 56345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683 56845685568656875688568956905691569256935694569556965697569856995700570157025703 61486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188 61976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252 | <----SKIPPED LINES----> ROLLING_LOGFILE = PrependFileName(ROLLING_LOGFILE, SIMULATION_PREFIX) ClearFile(ROLLING_LOGFILE) global ROLLING_MESSAGE_FILE ROLLING_MESSAGE_FILE = PrependFileName(ROLLING_MESSAGE_FILE, SIMULATION_PREFIX) ClearFile(ROLLING_MESSAGE_FILE) global PICKLE_FLIGHTS PICKLE_FLIGHTS = PrependFileName(PICKLE_FLIGHTS, SIMULATION_PREFIX) filenames = UnpickleObjectFromFile(PICKLE_FLIGHTS, True, max_days=None, filenames=True) for file in filenames: ClearFile(file) global PICKLE_DASHBOARD PICKLE_DASHBOARD = PrependFileName(PICKLE_DASHBOARD, SIMULATION_PREFIX) filenames = UnpickleObjectFromFile(PICKLE_DASHBOARD, True, max_days=None, filenames=True) for file in filenames: ClearFile(file) def SimulationEnd(message_queue, flights): """Clears message buffer, exercises histograms, and other misc test & status code. Args: message_queue: List of flight messages that have not yet been printed. flights: List of flights dictionaries. """ if flights: histogram = { 'type': 'both', 'histogram':'all', 'histogram_history':'30d', 'histogram_max_screens': '_2', 'histogram_data_summary': 'on'} message_queue.extend(TriggerHistograms(flights, histogram)) while message_queue: ManageMessageQueue(message_queue, 0, {'setting_delay': 0}) SaveFlightsByAltitudeDistanceCSV(flights) SaveFlightsToCSV(flights) # repickle to a new .pk with full track info file_parts = PICKLE_FLIGHTS.split('.') new_pickle_file = '.'.join([file_parts[0] + '_full_path', file_parts[1]]) RemoveFile(new_pickle_file) for flight in flights: PickleObjectToFile(flight, new_pickle_file, False) print('Simulation complete after %s dump json messages processed' % len(DUMP_JSONS)) def SimulationSlowdownNearFlight(flights, persistent_nearby_aircraft): """Slows down simulations when a reported-upon flight is nearby.""" if flights and flights[-1].get('flight_number') in persistent_nearby_aircraft: time.sleep(arduino.WRITE_DELAY_TIME) def DumpJsonChanges(): <----SKIPPED LINES----> Args: configuration: the settings dictionary. message_queue: the existing queue, to which the personal message - if any - is added. """ if 'clear_board' in configuration: RemoveSetting(configuration, 'clear_board') message_queue.append((FLAG_MSG_CLEAR, '')) minute_of_day = MinuteOfDay() if ( not message_queue and 'personal_message_enabled' in configuration and configuration['personal_message'] and minute_of_day <= configuration['personal_off_time'] and minute_of_day > configuration['personal_on_time'] + 1): message = configuration['personal_message'] lines = [TruncateEscapedLine(l) for l in message.split('\n')[:SPLITFLAP_LINE_COUNT]] message_queue.append((FLAG_MSG_PERSONAL, lines)) Log('Personal message added to queue: %s' % str(lines)) def ManageMessageQueue(message_queue, next_message_time, configuration): """Check time & if appropriate, display next message from queue. Args: message_queue: FIFO list of message tuples of (message type, message string). next_message_time: epoch at which next message should be displayed configuration: dictionary of configuration attributes. Returns: Next_message_time, potentially updated if a message has been displayed, or unchanged if no message was displayed. """ if message_queue and (time.time() >= next_message_time or SIMULATION): if SIMULATION: # drain the queue because the messages come so fast messages_to_display = list(message_queue) # passed by reference, so clear it out since we drained it to the display del message_queue[:] else: # display only one message, being mindful of the display timing messages_to_display = [message_queue.pop(0)] for message in messages_to_display: message_text = message[1] if isinstance(message_text, str): message_text = textwrap.wrap(message_text, width=SPLITFLAP_CHARS_PER_LINE) display_message = Screenify(message_text, False) Log(display_message, file=ALL_MESSAGE_FILE) # Saving this to disk allows us to identify persistently whats currently on the screen PickleObjectToFile(message, PICKLE_SCREENS, True) MaintainRollingWebLog(display_message, 25) if not SIMULATION: splitflap_message = Screenify(message_text, True) PublishMessage(splitflap_message) next_message_time = time.time() + configuration['setting_delay'] return next_message_time def DeleteMessageTypes(q, types_to_delete): """Delete messages from the queue if type is in the iterable types.""" if VERBOSE: messages_to_delete = [m for m in q if m[0] in types_to_delete] if messages_to_delete: Log('Deleting messages from queue due to new-found plane: %s' % messages_to_delete) updated_q = [m for m in q if m[0] not in types_to_delete] return updated_q <----SKIPPED LINES----> to_remote_q, to_servo_q, to_main_q, shutdown, flights, json_desc_dict, configuration, screen_history) flight_meets_display_criteria = FlightMeetsDisplayCriteria( flight, configuration, log=True) if flight_meets_display_criteria: flight_message = (FLAG_MSG_FLIGHT, CreateMessageAboutFlight(flight), flight) # display the next message about this flight now! next_message_time = time.time() message_queue.insert(0, flight_message) # and delete any queued insight messages about other flights that have # not yet displayed, since a newer flight has taken precedence message_queue = DeleteMessageTypes(message_queue, (FLAG_MSG_INSIGHT,)) # Though we also manage the message queue outside this conditional as well, # because it can take a half second to generate the flight insights, this allows # this message to start displaying on the board immediately, so it's up there # when it's most relevant next_message_time = ManageMessageQueue( message_queue, next_message_time, configuration) insight_messages = CreateFlightInsights( flights, configuration.get('insights'), insight_message_distribution) if configuration.get('next_flight', 'off') == 'on': next_flight_text = FlightInsightNextFlight(flights, configuration) if next_flight_text: insight_messages.insert(0, next_flight_text) insight_messages = [(FLAG_MSG_INSIGHT, m) for m in insight_messages] for insight_message in insight_messages: message_queue.insert(0, insight_message) else: # flight didn't meet display criteria flight['insight_types'] = [] PickleObjectToFile(flight, PICKLE_FLIGHTS, True, timestamp=flight['now']) else: remote, servo = RefreshArduinos( <----SKIPPED LINES----> if SIMULATION: if now: simulated_hour = EpochDisplayTime(now, '%Y-%m-%d %H:00%z') if simulated_hour != prev_simulated_hour: print(simulated_hour) prev_simulated_hour = simulated_hour histogram = ReadAndParseSettings(HISTOGRAM_CONFIG_FILE) RemoveFile(HISTOGRAM_CONFIG_FILE) # We also need to make sure there are flights on which to generate a histogram! Why # might there not be any flights? Primarily during a simulation, if there's a # lingering histogram file at the time of history restart. if histogram and not flights: Log('Histogram requested (%s) but no flights in memory' % histogram) if histogram and flights: message_queue.extend(TriggerHistograms(flights, histogram)) # check time & if appropriate, display next message from queue next_message_time = ManageMessageQueue(message_queue, next_message_time, configuration) reboot = CheckRebootNeeded(startup_time, message_queue, json_desc_dict, configuration) CheckTemperature() if not SIMULATION: time.sleep(max(0, next_loop_time - time.time())) next_loop_time = time.time() + LOOP_DELAY_SECONDS else: SIMULATION_COUNTER += 1 if simulation_slowdown: SimulationSlowdownNearFlight(flights, persistent_nearby_aircraft) if SIMULATION: SimulationEnd(message_queue, flights) PerformGracefulShutdown((to_remote_q, to_servo_q, to_main_q), shutdown, reboot) if __name__ == "__main__": #interrupt, as in ctrl-c signal.signal(signal.SIGINT, InterruptShutdownFromSignal) #terminate, when another instance found or via kill signal.signal(signal.SIGTERM, InterruptShutdownFromSignal) if '-i' in sys.argv: BootstrapInsightList() else: main_settings = ReadAndParseSettings(CONFIG_FILE) if 'code_profiling_enabled' in main_settings: import cProfile cProfile.run( 'main()', 'messageboard_stats-%s.profile' % EpochDisplayTime(time.time(), '%Y-%m-%d-%H%M')) else: <----SKIPPED LINES----> |
01234567890123456789012345678901234567890123456789012345678901234567890123456789
5006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063 56345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704 61496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189 61986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253 | <----SKIPPED LINES----> ROLLING_LOGFILE = PrependFileName(ROLLING_LOGFILE, SIMULATION_PREFIX) ClearFile(ROLLING_LOGFILE) global ROLLING_MESSAGE_FILE ROLLING_MESSAGE_FILE = PrependFileName(ROLLING_MESSAGE_FILE, SIMULATION_PREFIX) ClearFile(ROLLING_MESSAGE_FILE) global PICKLE_FLIGHTS PICKLE_FLIGHTS = PrependFileName(PICKLE_FLIGHTS, SIMULATION_PREFIX) filenames = UnpickleObjectFromFile(PICKLE_FLIGHTS, True, max_days=None, filenames=True) for file in filenames: ClearFile(file) global PICKLE_DASHBOARD PICKLE_DASHBOARD = PrependFileName(PICKLE_DASHBOARD, SIMULATION_PREFIX) filenames = UnpickleObjectFromFile(PICKLE_DASHBOARD, True, max_days=None, filenames=True) for file in filenames: ClearFile(file) def SimulationEnd(message_queue, flights, screens): """Clears message buffer, exercises histograms, and other misc test & status code. Args: message_queue: List of flight messages that have not yet been printed. flights: List of flights dictionaries. """ if flights: histogram = { 'type': 'both', 'histogram':'all', 'histogram_history':'30d', 'histogram_max_screens': '_2', 'histogram_data_summary': 'on'} message_queue.extend(TriggerHistograms(flights, histogram)) while message_queue: ManageMessageQueue(message_queue, 0, {'setting_delay': 0}, screens) SaveFlightsByAltitudeDistanceCSV(flights) SaveFlightsToCSV(flights) # repickle to a new .pk with full track info file_parts = PICKLE_FLIGHTS.split('.') new_pickle_file = '.'.join([file_parts[0] + '_full_path', file_parts[1]]) RemoveFile(new_pickle_file) for flight in flights: PickleObjectToFile(flight, new_pickle_file, False) print('Simulation complete after %s dump json messages processed' % len(DUMP_JSONS)) def SimulationSlowdownNearFlight(flights, persistent_nearby_aircraft): """Slows down simulations when a reported-upon flight is nearby.""" if flights and flights[-1].get('flight_number') in persistent_nearby_aircraft: time.sleep(arduino.WRITE_DELAY_TIME) def DumpJsonChanges(): <----SKIPPED LINES----> Args: configuration: the settings dictionary. message_queue: the existing queue, to which the personal message - if any - is added. """ if 'clear_board' in configuration: RemoveSetting(configuration, 'clear_board') message_queue.append((FLAG_MSG_CLEAR, '')) minute_of_day = MinuteOfDay() if ( not message_queue and 'personal_message_enabled' in configuration and configuration['personal_message'] and minute_of_day <= configuration['personal_off_time'] and minute_of_day > configuration['personal_on_time'] + 1): message = configuration['personal_message'] lines = [TruncateEscapedLine(l) for l in message.split('\n')[:SPLITFLAP_LINE_COUNT]] message_queue.append((FLAG_MSG_PERSONAL, lines)) Log('Personal message added to queue: %s' % str(lines)) def ManageMessageQueue(message_queue, next_message_time, configuration, screens): """Check time & if appropriate, display next message from queue. Args: message_queue: FIFO list of message tuples of (message type, message string). next_message_time: epoch at which next message should be displayed configuration: dictionary of configuration attributes. Returns: Next_message_time, potentially updated if a message has been displayed, or unchanged if no message was displayed. """ if message_queue and (time.time() >= next_message_time or SIMULATION): if SIMULATION: # drain the queue because the messages come so fast messages_to_display = list(message_queue) # passed by reference, so clear it out since we drained it to the display del message_queue[:] else: # display only one message, being mindful of the display timing messages_to_display = [message_queue.pop(0)] for message in messages_to_display: message_text = message[1] if isinstance(message_text, str): message_text = textwrap.wrap(message_text, width=SPLITFLAP_CHARS_PER_LINE) display_message = Screenify(message_text, False) Log(display_message, file=ALL_MESSAGE_FILE) # Saving this to disk allows us to identify persistently whats currently on the screen PickleObjectToFile(message, PICKLE_SCREENS, True) screens.append(message) MaintainRollingWebLog(display_message, 25) if not SIMULATION: splitflap_message = Screenify(message_text, True) PublishMessage(splitflap_message) next_message_time = time.time() + configuration['setting_delay'] return next_message_time def DeleteMessageTypes(q, types_to_delete): """Delete messages from the queue if type is in the iterable types.""" if VERBOSE: messages_to_delete = [m for m in q if m[0] in types_to_delete] if messages_to_delete: Log('Deleting messages from queue due to new-found plane: %s' % messages_to_delete) updated_q = [m for m in q if m[0] not in types_to_delete] return updated_q <----SKIPPED LINES----> to_remote_q, to_servo_q, to_main_q, shutdown, flights, json_desc_dict, configuration, screen_history) flight_meets_display_criteria = FlightMeetsDisplayCriteria( flight, configuration, log=True) if flight_meets_display_criteria: flight_message = (FLAG_MSG_FLIGHT, CreateMessageAboutFlight(flight), flight) # display the next message about this flight now! next_message_time = time.time() message_queue.insert(0, flight_message) # and delete any queued insight messages about other flights that have # not yet displayed, since a newer flight has taken precedence message_queue = DeleteMessageTypes(message_queue, (FLAG_MSG_INSIGHT,)) # Though we also manage the message queue outside this conditional as well, # because it can take a half second to generate the flight insights, this allows # this message to start displaying on the board immediately, so it's up there # when it's most relevant next_message_time = ManageMessageQueue( message_queue, next_message_time, configuration, screen_history) insight_messages = CreateFlightInsights( flights, configuration.get('insights'), insight_message_distribution) if configuration.get('next_flight', 'off') == 'on': next_flight_text = FlightInsightNextFlight(flights, configuration) if next_flight_text: insight_messages.insert(0, next_flight_text) insight_messages = [(FLAG_MSG_INSIGHT, m) for m in insight_messages] for insight_message in insight_messages: message_queue.insert(0, insight_message) else: # flight didn't meet display criteria flight['insight_types'] = [] PickleObjectToFile(flight, PICKLE_FLIGHTS, True, timestamp=flight['now']) else: remote, servo = RefreshArduinos( <----SKIPPED LINES----> if SIMULATION: if now: simulated_hour = EpochDisplayTime(now, '%Y-%m-%d %H:00%z') if simulated_hour != prev_simulated_hour: print(simulated_hour) prev_simulated_hour = simulated_hour histogram = ReadAndParseSettings(HISTOGRAM_CONFIG_FILE) RemoveFile(HISTOGRAM_CONFIG_FILE) # We also need to make sure there are flights on which to generate a histogram! Why # might there not be any flights? Primarily during a simulation, if there's a # lingering histogram file at the time of history restart. if histogram and not flights: Log('Histogram requested (%s) but no flights in memory' % histogram) if histogram and flights: message_queue.extend(TriggerHistograms(flights, histogram)) # check time & if appropriate, display next message from queue next_message_time = ManageMessageQueue(message_queue, next_message_time, configuration, screen_history) reboot = CheckRebootNeeded(startup_time, message_queue, json_desc_dict, configuration) CheckTemperature() if not SIMULATION: time.sleep(max(0, next_loop_time - time.time())) next_loop_time = time.time() + LOOP_DELAY_SECONDS else: SIMULATION_COUNTER += 1 if simulation_slowdown: SimulationSlowdownNearFlight(flights, persistent_nearby_aircraft) if SIMULATION: SimulationEnd(message_queue, flights, screen_history) PerformGracefulShutdown((to_remote_q, to_servo_q, to_main_q), shutdown, reboot) if __name__ == "__main__": #interrupt, as in ctrl-c signal.signal(signal.SIGINT, InterruptShutdownFromSignal) #terminate, when another instance found or via kill signal.signal(signal.SIGTERM, InterruptShutdownFromSignal) if '-i' in sys.argv: BootstrapInsightList() else: main_settings = ReadAndParseSettings(CONFIG_FILE) if 'code_profiling_enabled' in main_settings: import cProfile cProfile.run( 'main()', 'messageboard_stats-%s.profile' % EpochDisplayTime(time.time(), '%Y-%m-%d-%H%M')) else: <----SKIPPED LINES----> |