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---->
|