01234567890123456789012345678901234567890123456789012345678901234567890123456789
144145146147148149150151152153154155156157158159160161162163164165 166167168169170171172173174175176177178179180181182183184185 898899900901902903904905906907908909910911912913914915916917 918919920921922923924925926927928929930931932933934935936937 202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070 26022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642 51525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192 52425243524452455246524752485249525052515252525352545255525652575258525952605261 52625263526452655266526752685269527052715272527352745275527652775278527952805281 57265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784 57855786578757885789579057915792579357945795579657975798579958005801580258035804 | <----SKIPPED LINES----> # of flights, by hour throughout the day, over the last seven days, normalized to # flights per day. This allows those parameters to be fine-tuned in a useful way. # This file is the location, on the webserver, of that image, which needs to be in # alignment with the html page that displays it. HOURLY_IMAGE_FILE = 'hours.png' # This is all messages that have been sent to the board since the last time the # file was manually cleared. Newest messages are at the bottom. It is visible at the # webserver. ALL_MESSAGE_FILE = 'all_messages.txt' #enumeration of all messages sent to board # This shows the most recent n messages sent to the board. Newest messages are at the # top for easier viewing of "what did I miss". ROLLING_MESSAGE_FILE = 'rolling_messages.txt' STDERR_FILE = 'stderr.txt' BACKUP_FILE = 'backup.txt' SERVICE_VERIFICATION_FILE = 'service-verification.txt' UPTIMES_FILE = 'uptimes.html' FLAG_MSG_FLIGHT = 1 # basic flight details FLAG_MSG_INTERESTING = 2 # random tidbit about a flight FLAG_MSG_HISTOGRAM = 3 # histogram message FLAG_INSIGHT_LAST_SEEN = 0 FLAG_INSIGHT_DIFF_AIRCRAFT = 1 FLAG_INSIGHT_NTH_FLIGHT = 2 FLAG_INSIGHT_GROUNDSPEED = 3 FLAG_INSIGHT_ALTITUDE = 4 FLAG_INSIGHT_VERTRATE = 5 FLAG_INSIGHT_FIRST_DEST = 6 FLAG_INSIGHT_FIRST_ORIGIN = 7 FLAG_INSIGHT_FIRST_AIRLINE = 8 FLAG_INSIGHT_FIRST_AIRCRAFT = 9 FLAG_INSIGHT_LONGEST_DELAY = 10 FLAG_INSIGHT_FLIGHT_DELAY_FREQUENCY = 11 FLAG_INSIGHT_FLIGHT_DELAY_TIME = 12 FLAG_INSIGHT_AIRLINE_DELAY_FREQUENCY = 13 FLAG_INSIGHT_AIRLINE_DELAY_TIME = 14 FLAG_INSIGHT_DESTINATION_DELAY_FREQUENCY = 15 FLAG_INSIGHT_DESTINATION_DELAY_TIME = 16 FLAG_INSIGHT_HOUR_DELAY_FREQUENCY = 17 FLAG_INSIGHT_HOUR_DELAY_TIME = 18 <----SKIPPED LINES----> def HourString(flight): """Formats now on flight into a a 3-digit string like '12a' or ' 1p'.""" time_string = DisplayTime(flight) if time_string: hour_string = time_string[11:13] hour_0_23 = int(hour_string) is_pm = int(hour_0_23/12) == 1 hour_number = hour_0_23 % 12 if hour_number == 0: hour_number = 12 out_string = str(hour_number).rjust(2) if is_pm: out_string += 'p' else: out_string += 'a' else: out_string = KEY_NOT_PRESENT_STRING return out_string def HoursSinceMidnight(timezone=TIMEZONE): """Returns the float number of hours elapsed since midnight in the given timezone.""" tz = pytz.timezone(timezone) now = datetime.datetime.now(tz) seconds_since_midnight = ( now - now.replace(hour=0, minute=0, second=0, microsecond=0)).total_seconds() hours = seconds_since_midnight / SECONDS_IN_HOUR return hours def HoursSinceFlight(now, then): """Returns the number of hours between a timestamp and a flight. Args: now: timezone-aware datetime representation of timestamp then: epoch (float) Returns: Number of hours between now and then (i.e.: now - then; a positive return value means now occurred after then). <----SKIPPED LINES----> if flight_altitude > config_max_altitude: flight_meets_criteria = False if log: Log( '%s not displayed because it fails altitude criteria - flight altitude: ' '%.0f; required altitude: %.0f' % ( DisplayFlightNumber(flight), flight_altitude, config_max_altitude)) else: flight_distance = flight.get('min_feet', float('inf')) config_max_distance = configuration['setting_max_distance'] if flight_distance > config_max_distance: flight_meets_criteria = False if log: Log( '%s not displayed because it fails distance criteria - flight distance: ' '%.0f; required distance: %.0f' % ( DisplayFlightNumber(flight), flight_distance, config_max_distance)) if not display_all_hours and flight_meets_criteria: flight_timestamp = flight['now'] dt = datetime.datetime.fromtimestamp(flight_timestamp, TZ) minute_of_day = dt.hour * MINUTES_IN_HOUR + dt.minute if minute_of_day <= configuration['setting_on_time']: flight_meets_criteria = False if log: Log( '%s not displayed because it occurs too early - minute_of_day: ' '%d; setting_on_time: %d' % ( DisplayFlightNumber(flight), minute_of_day, configuration['setting_on_time'])) elif minute_of_day > configuration['setting_off_time'] + 1: flight_meets_criteria = False if log: Log( '%s not displayed because it occurs too late - minute_of_day: ' '%d; setting_off_time: %d' % ( DisplayFlightNumber(flight), minute_of_day, configuration['setting_off_time'])) elif configuration.get('setting_screen_enabled', 'off') == 'off': flight_meets_criteria = False if log: Log( <----SKIPPED LINES----> def CheckForNewFilterCriteria(prev, new, message_queue, flights): """If filter criteria changed, generate new image and perhaps new message.""" if (new.get('setting_max_distance') != prev.get('setting_max_distance') or new.get('setting_max_altitude') != prev.get('setting_max_altitude')): FlightCriteriaHistogramPng( flights, new['setting_max_distance'], new['setting_max_altitude'], 7, last_max_distance_feet=prev.get('setting_max_distance'), last_max_altitude_feet=prev.get('setting_max_altitude')) if (new.get('setting_max_distance') != prev.get('setting_max_distance') or new.get('setting_max_altitude') != prev.get('setting_max_altitude') or new.get('setting_off_time') != prev.get('setting_off_time') or new.get('setting_on_time') != prev.get('setting_on_time')): if new.get('next_flight', 'off') == 'on': next_flight_message = FlightInsightNextFlight(flights, new) if next_flight_message: message_queue.append((FLAG_MSG_INTERESTING, next_flight_message)) def PercentileScore(scores, value): """Returns the percentile that a particular value is in a list of numbers. Roughly inverts numpy.percentile. That is, numpy.percentile(scores_list, percentile) to get the value of the list that is at that percentile; PercentileScore(scores_list, value) will yield back approximately that percentile. If the value matches identical elements in the list, this function takes the average position of those identical values to compute a percentile. Thus, for some lists (i.e.: where there are lots of flights that have a 0 second delay, or a 100% delay frequency), you may not get a percentile of 0 or 100 even with values equal to the min or max element in the list. Args: scores: the list of numbers, including value. value: the value for which we want to determine the percentile. Returns: <----SKIPPED LINES----> Returns: A 2-tuple of the (possibly-updated) message_queue and next_message_time. """ while not q.empty(): command, args = q.get() if command == 'pin': UpdateStatusLight(*args) elif command == 'replay': # a command might request info about flight to be (re)displayed, irrespective of # whether the screen is on; if so, let's put that message at the front of the message # queue, and delete any subsequent messages in queue because presumably the button # was pushed either a) when the screen was off (so no messages in queue), or b) # because the screen was on, but the last flight details got lost after other screens # that we're no longer interested in messageboard_flight_index = IdentifyFlightDisplayed( flights, configuration, display_all_hours=True) if messageboard_flight_index is not None: message_queue = [m for m in message_queue if m[0] != FLAG_MSG_INTERESTING] flight_message = CreateMessageAboutFlight(flights[messageboard_flight_index]) message_queue = [(FLAG_MSG_FLIGHT, flight_message)] next_message_time = time.time() elif command == 'histogram': if not flights: Log('Histogram requested by remote %s but no flights in memory' % str(args)) else: histogram_type, histogram_history = args message_queue.extend(MessageboardHistograms( flights, histogram_type, histogram_history, '_1', False)) elif command == 'update_configuration': WriteFile(CONFIG_FILE, *args) else: <----SKIPPED LINES----> curl.setopt(pycurl.READDATA, body_as_file_object) curl.setopt(pycurl.POSTFIELDSIZE, len(body_as_json_string)) failure_message = '' try: curl.perform() except pycurl.error as e: failure_message = 'curl.perform() failed with message %s' % e Log('curl.perform() failed with message %s' % e) error_code = True else: # you may want to check HTTP response code, e.g. status_code = curl.getinfo(pycurl.RESPONSE_CODE) if status_code != 200: Log('Server returned HTTP status code %d for message %s' % (status_code, s)) error_code = True curl.close() UpdateStatusLight(GPIO_ERROR_VESTABOARD_CONNECTION, error_code, failure_message) 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)] <----SKIPPED LINES----> # process this if its a truly new flight new_flight_flag = ConfirmNewFlight(flight, flights) if new_flight_flag: flights.append(flight) remote, servo = RefreshArduinos( remote, servo, to_remote_q, to_servo_q, to_main_q, shutdown, flights, json_desc_dict, configuration) flight_meets_display_criteria = FlightMeetsDisplayCriteria( flight, configuration, log=True) if flight_meets_display_criteria: flight_message = (FLAG_MSG_FLIGHT, CreateMessageAboutFlight(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 messages_to_delete = [m for m in message_queue if m[0] == FLAG_MSG_INTERESTING] if messages_to_delete and VERBOSE: Log( 'Deleting messages from queue due to new-found plane: %s' % messages_to_delete) message_queue = [m for m in message_queue if m[0] != FLAG_MSG_INTERESTING] # 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_INTERESTING, 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( remote, servo, to_remote_q, to_servo_q, to_main_q, shutdown, flights, json_desc_dict, configuration) message_queue, next_message_time = ProcessArduinoCommmands( to_main_q, flights, configuration, message_queue, next_message_time) 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 <----SKIPPED LINES----> |
01234567890123456789012345678901234567890123456789012345678901234567890123456789
144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187 900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945 203720382039204020412042204320442045204620472048204920502051205220532054205520562057 20582059206020612062206320642065206620672068206920702071207220732074207520762077 26092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649 51595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199 5249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303 574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828 | <----SKIPPED LINES----> # of flights, by hour throughout the day, over the last seven days, normalized to # flights per day. This allows those parameters to be fine-tuned in a useful way. # This file is the location, on the webserver, of that image, which needs to be in # alignment with the html page that displays it. HOURLY_IMAGE_FILE = 'hours.png' # This is all messages that have been sent to the board since the last time the # file was manually cleared. Newest messages are at the bottom. It is visible at the # webserver. ALL_MESSAGE_FILE = 'all_messages.txt' #enumeration of all messages sent to board # This shows the most recent n messages sent to the board. Newest messages are at the # top for easier viewing of "what did I miss". ROLLING_MESSAGE_FILE = 'rolling_messages.txt' STDERR_FILE = 'stderr.txt' BACKUP_FILE = 'backup.txt' SERVICE_VERIFICATION_FILE = 'service-verification.txt' UPTIMES_FILE = 'uptimes.html' FLAG_MSG_FLIGHT = 1 # basic flight details FLAG_MSG_INSIGHT = 2 # random tidbit about a flight FLAG_MSG_HISTOGRAM = 3 # histogram message FLAG_MSG_CLEAR = 4 # a blank message to clear the screen FLAG_MSG_PERSONAL = 5 # user-entered message to display for some duration of time FLAG_INSIGHT_LAST_SEEN = 0 FLAG_INSIGHT_DIFF_AIRCRAFT = 1 FLAG_INSIGHT_NTH_FLIGHT = 2 FLAG_INSIGHT_GROUNDSPEED = 3 FLAG_INSIGHT_ALTITUDE = 4 FLAG_INSIGHT_VERTRATE = 5 FLAG_INSIGHT_FIRST_DEST = 6 FLAG_INSIGHT_FIRST_ORIGIN = 7 FLAG_INSIGHT_FIRST_AIRLINE = 8 FLAG_INSIGHT_FIRST_AIRCRAFT = 9 FLAG_INSIGHT_LONGEST_DELAY = 10 FLAG_INSIGHT_FLIGHT_DELAY_FREQUENCY = 11 FLAG_INSIGHT_FLIGHT_DELAY_TIME = 12 FLAG_INSIGHT_AIRLINE_DELAY_FREQUENCY = 13 FLAG_INSIGHT_AIRLINE_DELAY_TIME = 14 FLAG_INSIGHT_DESTINATION_DELAY_FREQUENCY = 15 FLAG_INSIGHT_DESTINATION_DELAY_TIME = 16 FLAG_INSIGHT_HOUR_DELAY_FREQUENCY = 17 FLAG_INSIGHT_HOUR_DELAY_TIME = 18 <----SKIPPED LINES----> def HourString(flight): """Formats now on flight into a a 3-digit string like '12a' or ' 1p'.""" time_string = DisplayTime(flight) if time_string: hour_string = time_string[11:13] hour_0_23 = int(hour_string) is_pm = int(hour_0_23/12) == 1 hour_number = hour_0_23 % 12 if hour_number == 0: hour_number = 12 out_string = str(hour_number).rjust(2) if is_pm: out_string += 'p' else: out_string += 'a' else: out_string = KEY_NOT_PRESENT_STRING return out_string def MinuteOfDay(ts=time.time()): dt = datetime.datetime.fromtimestamp(ts, TZ) minute_of_day = dt.hour * MINUTES_IN_HOUR + dt.minute return minute_of_day def HoursSinceMidnight(timezone=TIMEZONE): """Returns the float number of hours elapsed since midnight in the given timezone.""" tz = pytz.timezone(timezone) now = datetime.datetime.now(tz) seconds_since_midnight = ( now - now.replace(hour=0, minute=0, second=0, microsecond=0)).total_seconds() hours = seconds_since_midnight / SECONDS_IN_HOUR return hours def HoursSinceFlight(now, then): """Returns the number of hours between a timestamp and a flight. Args: now: timezone-aware datetime representation of timestamp then: epoch (float) Returns: Number of hours between now and then (i.e.: now - then; a positive return value means now occurred after then). <----SKIPPED LINES----> if flight_altitude > config_max_altitude: flight_meets_criteria = False if log: Log( '%s not displayed because it fails altitude criteria - flight altitude: ' '%.0f; required altitude: %.0f' % ( DisplayFlightNumber(flight), flight_altitude, config_max_altitude)) else: flight_distance = flight.get('min_feet', float('inf')) config_max_distance = configuration['setting_max_distance'] if flight_distance > config_max_distance: flight_meets_criteria = False if log: Log( '%s not displayed because it fails distance criteria - flight distance: ' '%.0f; required distance: %.0f' % ( DisplayFlightNumber(flight), flight_distance, config_max_distance)) if not display_all_hours and flight_meets_criteria: flight_timestamp = flight['now'] minute_of_day = MinuteOfDay(flight_timestamp) if minute_of_day <= configuration['setting_on_time']: flight_meets_criteria = False if log: Log( '%s not displayed because it occurs too early - minute_of_day: ' '%d; setting_on_time: %d' % ( DisplayFlightNumber(flight), minute_of_day, configuration['setting_on_time'])) elif minute_of_day > configuration['setting_off_time'] + 1: flight_meets_criteria = False if log: Log( '%s not displayed because it occurs too late - minute_of_day: ' '%d; setting_off_time: %d' % ( DisplayFlightNumber(flight), minute_of_day, configuration['setting_off_time'])) elif configuration.get('setting_screen_enabled', 'off') == 'off': flight_meets_criteria = False if log: Log( <----SKIPPED LINES----> def CheckForNewFilterCriteria(prev, new, message_queue, flights): """If filter criteria changed, generate new image and perhaps new message.""" if (new.get('setting_max_distance') != prev.get('setting_max_distance') or new.get('setting_max_altitude') != prev.get('setting_max_altitude')): FlightCriteriaHistogramPng( flights, new['setting_max_distance'], new['setting_max_altitude'], 7, last_max_distance_feet=prev.get('setting_max_distance'), last_max_altitude_feet=prev.get('setting_max_altitude')) if (new.get('setting_max_distance') != prev.get('setting_max_distance') or new.get('setting_max_altitude') != prev.get('setting_max_altitude') or new.get('setting_off_time') != prev.get('setting_off_time') or new.get('setting_on_time') != prev.get('setting_on_time')): if new.get('next_flight', 'off') == 'on': next_flight_message = FlightInsightNextFlight(flights, new) if next_flight_message: message_queue.append((FLAG_MSG_INSIGHT, next_flight_message)) def PercentileScore(scores, value): """Returns the percentile that a particular value is in a list of numbers. Roughly inverts numpy.percentile. That is, numpy.percentile(scores_list, percentile) to get the value of the list that is at that percentile; PercentileScore(scores_list, value) will yield back approximately that percentile. If the value matches identical elements in the list, this function takes the average position of those identical values to compute a percentile. Thus, for some lists (i.e.: where there are lots of flights that have a 0 second delay, or a 100% delay frequency), you may not get a percentile of 0 or 100 even with values equal to the min or max element in the list. Args: scores: the list of numbers, including value. value: the value for which we want to determine the percentile. Returns: <----SKIPPED LINES----> Returns: A 2-tuple of the (possibly-updated) message_queue and next_message_time. """ while not q.empty(): command, args = q.get() if command == 'pin': UpdateStatusLight(*args) elif command == 'replay': # a command might request info about flight to be (re)displayed, irrespective of # whether the screen is on; if so, let's put that message at the front of the message # queue, and delete any subsequent messages in queue because presumably the button # was pushed either a) when the screen was off (so no messages in queue), or b) # because the screen was on, but the last flight details got lost after other screens # that we're no longer interested in messageboard_flight_index = IdentifyFlightDisplayed( flights, configuration, display_all_hours=True) if messageboard_flight_index is not None: message_queue = [m for m in message_queue if m[0] != FLAG_MSG_INSIGHT] flight_message = CreateMessageAboutFlight(flights[messageboard_flight_index]) message_queue = [(FLAG_MSG_FLIGHT, flight_message)] next_message_time = time.time() elif command == 'histogram': if not flights: Log('Histogram requested by remote %s but no flights in memory' % str(args)) else: histogram_type, histogram_history = args message_queue.extend(MessageboardHistograms( flights, histogram_type, histogram_history, '_1', False)) elif command == 'update_configuration': WriteFile(CONFIG_FILE, *args) else: <----SKIPPED LINES----> curl.setopt(pycurl.READDATA, body_as_file_object) curl.setopt(pycurl.POSTFIELDSIZE, len(body_as_json_string)) failure_message = '' try: curl.perform() except pycurl.error as e: failure_message = 'curl.perform() failed with message %s' % e Log('curl.perform() failed with message %s' % e) error_code = True else: # you may want to check HTTP response code, e.g. status_code = curl.getinfo(pycurl.RESPONSE_CODE) if status_code != 200: Log('Server returned HTTP status code %d for message %s' % (status_code, s)) error_code = True curl.close() UpdateStatusLight(GPIO_ERROR_VESTABOARD_CONNECTION, error_code, failure_message) def PersonalMessage(configuration, message_queue): 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'].split('\n') message_queue.append((FLAG_MSG_PERSONAL, message)) 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)] <----SKIPPED LINES----> # process this if its a truly new flight new_flight_flag = ConfirmNewFlight(flight, flights) if new_flight_flag: flights.append(flight) remote, servo = RefreshArduinos( remote, servo, to_remote_q, to_servo_q, to_main_q, shutdown, flights, json_desc_dict, configuration) flight_meets_display_criteria = FlightMeetsDisplayCriteria( flight, configuration, log=True) if flight_meets_display_criteria: flight_message = (FLAG_MSG_FLIGHT, CreateMessageAboutFlight(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 messages_to_delete = [m for m in message_queue if m[0] == FLAG_MSG_INSIGHT] if messages_to_delete and VERBOSE: Log( 'Deleting messages from queue due to new-found plane: %s' % messages_to_delete) message_queue = [m for m in message_queue if m[0] != 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( remote, servo, to_remote_q, to_servo_q, to_main_q, shutdown, flights, json_desc_dict, configuration) message_queue, next_message_time = ProcessArduinoCommmands( to_main_q, flights, configuration, message_queue, next_message_time) PersonalMessage(configuration, message_queue) 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 <----SKIPPED LINES----> |