01234567890123456789012345678901234567890123456789012345678901234567890123456789
6263646566676869707172737475767778798081828384858687888990919293949596979899100101102 444544464447444844494450445144524453445444554456445744584459446044614462446344644465 44664467446844694470447144724473447444754476447744784479 44804481448244834484448544864487448844894490449144924493449444954496449744984499 473447354736473747384739474047414742474347444745474647474748474947504751475247534754 47554756475747584759476047614762476347644765476647674768476947704771477247734774 58285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868 | <----SKIPPED LINES----> METERS_PER_SECOND_IN_KNOTS = 0.514444 MIN_METERS = 5000/FEET_IN_METER # only planes within this distance will be detailed # planes not seen within MIN_METERS in PERSISTENCE_SECONDS seconds will be dropped from # the nearby list PERSISTENCE_SECONDS = 300 TRUNCATE = 50 # max number of keys to include in a histogram image file # number of seconds to pause between each radio poll / command processing loop LOOP_DELAY_SECONDS = 1 # number of seconds to wait between recording heartbeats to the status file HEARTBEAT_SECONDS = 10 # version control directory CODE_REPOSITORY = '' VERSION_REPOSITORY = 'versions/' VERSION_WEBSITE_PATH = VERSION_REPOSITORY VERSION_MESSAGEBOARD = None VERSION_ARDUINO = None MAX_INSIGHT_HORIZON_DAYS = 30 # This file is where the radio drops its json file DUMP_JSON_FILE = '/run/readsb/aircraft.json' # At the time a flight is first identified as being of interest (in that it falls # within MIN_METERS meters of HOME), it - and core attributes derived from FlightAware, # if any - is appended to the end of this pickle file. However, since this file is # cached in working memory, flights older than 30 days are flushed from this periodically. PICKLE_FLIGHTS = 'pickle/flights.pk' # True splits all the flights created in simulation into separate date files, just like # the non-simulated runs; False consolidates all flights into one pickle file. SPLIT_SIMULATION_FLIGHT_PICKLE = False # Status data about messageboard - is it running, etc. Specifically, has tuples # of data (timestamp, system_id, status), where system_id is either the pin id of GPIO, # or a 0 to indicate overall system, and status is boolean PICKLE_DASHBOARD = 'pickle/dashboard.pk' CACHED_ELEMENT_PREFIX = 'cached_' <----SKIPPED LINES----> filename = ( WEBSERVER_IMAGE_RELATIVE_FOLDER + # i.e.: images/ filename_prefix + # i.e.: histogram_ histogram['generate'] + # i.e.: destination '.' + filename_suffix) # i.e.: .png filepath = WEBSERVER_PATH + filename # i.e.: /var/www/html/ + filename matplotlib.pyplot.savefig(filepath) matplotlib.pyplot.close() histograms_generated.append((histogram['generate'], filename)) return histograms_generated def MessageboardHistograms( flights, which_histograms, how_much_history, max_screens, data_summary): """Generates multiple split flap screen histograms. Args: flights: the iterable of the raw data from which the histogram will be generated; each element of the iterable is a dictionary, that contains at least the key 'now', and depending on other parameters, also potentially 'min_feet' amongst others. which_histograms: string paramater indicating which histogram(s) to generate, which can be either the special string 'all', or a string linked to a specific histogram. how_much_history: string parameter taking a value among ['today', '24h', '7d', '30d]. max_screens: string parameter taking a value among ['_1', '_2', '_5', or 'all']. data_summary: parameter that evaluates to a boolean indicating whether the data summary screen in the histogram should be displayed. Returns: Returns a list of printable strings (with embedded new line characters) representing the histogram, for each screen in the histogram. """ messages = [] hours = HistogramSettingsHours(how_much_history) screen_limit = HistogramSettingsScreens(max_screens) histograms_to_generate = [] if which_histograms in ['destination', 'all']: histograms_to_generate.append({ 'generate': 'destination', 'suppress_percent_sign': True, 'columns': 3}) if which_histograms in ['origin', 'all']: histograms_to_generate.append({ 'generate': 'origin', 'suppress_percent_sign': True, <----SKIPPED LINES----> Args: flights: List of flight attribute dictionaries. histogram_settings: Dictionary of histogram parameters. heartbeat: boolean indicating whether we should log heartbeats between each histogram to make sure monitoring does not mistake this slow procedure for being hung; this should be set to false if this is called from outside of messageboard.main. Returns: List of histogram messages, if text-based histograms are selected; empty list otherwise. """ histogram_messages = [] if histogram_settings['type'] in ('messageboard', 'both'): histogram_messages = MessageboardHistograms( flights, histogram_settings['histogram'], histogram_settings['histogram_history'], histogram_settings['histogram_max_screens'], histogram_settings.get('histogram_data_summary', False)) if histogram_settings['type'] in ('images', 'both'): # Since Google Chrome seems to ignore all instructions to not cache, we need # to make sure we do not reuse file names - hence the epoch_string - and then # we need to 1) update the histograms.html file with the correct file links, and # 2) delete the images that are now obsolete. epoch_string = '%d_' % round(time.time()) generated_histograms = ImageHistograms( flights, histogram_settings['histogram'], histogram_settings['histogram_history'], filename_prefix=HISTOGRAM_IMAGE_PREFIX + epoch_string, heartbeat=heartbeat) html_lines = ReadFile(HISTOGRAM_IMAGE_HTML).split('\n') replaced_images = [] for identifier, new_filename in generated_histograms: # for each histogram, find the html_line with the matching id # Example line: <img id="destination" src="images/histogram_destination.png"><p> identifier = '"%s"' % identifier # add quotations to make sure its complete <----SKIPPED LINES----> f, PICKLE_FLIGHTS, True, timestamp=f['now'], verify=False) return False def HeartbeatRestart(): """Logs a system down / system up pair of heartbeats as system is first starting.""" if SIMULATION: return 0 UpdateDashboard(True) # Indicates that this wasn't running a moment before, ... UpdateDashboard(False) # ... and now it is running! return time.time() 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) last_heartbeat_time = now return last_heartbeat_time def VersionControl(): """Copies the current instances of messageboard.py and arduino.py into a 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 <----SKIPPED LINES----> |
01234567890123456789012345678901234567890123456789012345678901234567890123456789
6263646566676869707172737475767778798081828384858687888990919293949596979899100101102 44454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503 473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779 58335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873 | <----SKIPPED LINES----> METERS_PER_SECOND_IN_KNOTS = 0.514444 MIN_METERS = 5000/FEET_IN_METER # only planes within this distance will be detailed # planes not seen within MIN_METERS in PERSISTENCE_SECONDS seconds will be dropped from # the nearby list PERSISTENCE_SECONDS = 300 TRUNCATE = 50 # max number of keys to include in a histogram image file # number of seconds to pause between each radio poll / command processing loop LOOP_DELAY_SECONDS = 1 # number of seconds to wait between recording heartbeats to the status file HEARTBEAT_SECONDS = 10 # version control directory CODE_REPOSITORY = '' VERSION_REPOSITORY = 'versions/' VERSION_WEBSITE_PATH = VERSION_REPOSITORY VERSION_MESSAGEBOARD = None VERSION_ARDUINO = None MAX_INSIGHT_HORIZON_DAYS = 31 # histogram logic truncates to exactly 30 days of hours # This file is where the radio drops its json file DUMP_JSON_FILE = '/run/readsb/aircraft.json' # At the time a flight is first identified as being of interest (in that it falls # within MIN_METERS meters of HOME), it - and core attributes derived from FlightAware, # if any - is appended to the end of this pickle file. However, since this file is # cached in working memory, flights older than 30 days are flushed from this periodically. PICKLE_FLIGHTS = 'pickle/flights.pk' # True splits all the flights created in simulation into separate date files, just like # the non-simulated runs; False consolidates all flights into one pickle file. SPLIT_SIMULATION_FLIGHT_PICKLE = False # Status data about messageboard - is it running, etc. Specifically, has tuples # of data (timestamp, system_id, status), where system_id is either the pin id of GPIO, # or a 0 to indicate overall system, and status is boolean PICKLE_DASHBOARD = 'pickle/dashboard.pk' CACHED_ELEMENT_PREFIX = 'cached_' <----SKIPPED LINES----> filename = ( WEBSERVER_IMAGE_RELATIVE_FOLDER + # i.e.: images/ filename_prefix + # i.e.: histogram_ histogram['generate'] + # i.e.: destination '.' + filename_suffix) # i.e.: .png filepath = WEBSERVER_PATH + filename # i.e.: /var/www/html/ + filename matplotlib.pyplot.savefig(filepath) matplotlib.pyplot.close() histograms_generated.append((histogram['generate'], filename)) return histograms_generated def MessageboardHistograms( flights, which_histograms, how_much_history, max_screens, data_summary, heartbeat=True): """Generates multiple split flap screen histograms. Args: flights: the iterable of the raw data from which the histogram will be generated; each element of the iterable is a dictionary, that contains at least the key 'now', and depending on other parameters, also potentially 'min_feet' amongst others. which_histograms: string paramater indicating which histogram(s) to generate, which can be either the special string 'all', or a string linked to a specific histogram. how_much_history: string parameter taking a value among ['today', '24h', '7d', '30d]. max_screens: string parameter taking a value among ['_1', '_2', '_5', or 'all']. data_summary: parameter that evaluates to a boolean indicating whether the data summary screen in the histogram should be displayed. heartbeat: boolean indicating whether we should log heartbeats between each histogram to make sure monitoring does not mistake this slow procedure for being hung; this should be set to false if this is called from outside of messageboard.main. Returns: Returns a list of printable strings (with embedded new line characters) representing the histogram, for each screen in the histogram. """ messages = [] hours = HistogramSettingsHours(how_much_history) screen_limit = HistogramSettingsScreens(max_screens) histograms_to_generate = [] if which_histograms in ['destination', 'all']: histograms_to_generate.append({ 'generate': 'destination', 'suppress_percent_sign': True, 'columns': 3}) if which_histograms in ['origin', 'all']: histograms_to_generate.append({ 'generate': 'origin', 'suppress_percent_sign': True, <----SKIPPED LINES----> Args: flights: List of flight attribute dictionaries. histogram_settings: Dictionary of histogram parameters. heartbeat: boolean indicating whether we should log heartbeats between each histogram to make sure monitoring does not mistake this slow procedure for being hung; this should be set to false if this is called from outside of messageboard.main. Returns: List of histogram messages, if text-based histograms are selected; empty list otherwise. """ histogram_messages = [] if histogram_settings['type'] in ('messageboard', 'both'): histogram_messages = MessageboardHistograms( flights, histogram_settings['histogram'], histogram_settings['histogram_history'], histogram_settings['histogram_max_screens'], histogram_settings.get('histogram_data_summary', False), heartbeat=heartbeat) if histogram_settings['type'] in ('images', 'both'): # Since Google Chrome seems to ignore all instructions to not cache, we need # to make sure we do not reuse file names - hence the epoch_string - and then # we need to 1) update the histograms.html file with the correct file links, and # 2) delete the images that are now obsolete. epoch_string = '%d_' % round(time.time()) generated_histograms = ImageHistograms( flights, histogram_settings['histogram'], histogram_settings['histogram_history'], filename_prefix=HISTOGRAM_IMAGE_PREFIX + epoch_string, heartbeat=heartbeat) html_lines = ReadFile(HISTOGRAM_IMAGE_HTML).split('\n') replaced_images = [] for identifier, new_filename in generated_histograms: # for each histogram, find the html_line with the matching id # Example line: <img id="destination" src="images/histogram_destination.png"><p> identifier = '"%s"' % identifier # add quotations to make sure its complete <----SKIPPED LINES----> f, PICKLE_FLIGHTS, True, timestamp=f['now'], verify=False) return False def HeartbeatRestart(): """Logs a system down / system up pair of heartbeats as system is first starting.""" if SIMULATION: return 0 UpdateDashboard(True) # Indicates that this wasn't running a moment before, ... UpdateDashboard(False) # ... and now it is running! return time.time() 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 the current instances of messageboard.py and arduino.py into a 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 <----SKIPPED LINES----> |