def get_utc_date_time(): """get the local date time""" return wxcutils.epoch_to_utc(time.time(), '%a %d %b %H:%M')
# load config CONFIG_INFO = wxcutils.load_json(CONFIG_PATH, 'config.json') # load satellites SATELLITE_INFO = wxcutils.load_json(CONFIG_PATH, 'satellites.json') # load image options IMAGE_OPTIONS = wxcutils.load_json(CONFIG_PATH, 'config-SSTV.json') # get local time zone LOCAL_TIME_ZONE = subprocess.check_output("date"). \ decode('utf-8').split(' ')[-2] # create filename base FILENAME_BASE = wxcutils.epoch_to_utc(START_EPOCH, '%Y-%m-%d-%H-%M-%S') + \ '-' + SATELLITE.replace(' ', '_').replace('(', '').replace(')', '') MY_LOGGER.debug('FILENAME_BASE = %s', FILENAME_BASE) # load pass information PASS_INFO = wxcutils.load_json(OUTPUT_PATH, FILENAME_BASE + '.json') MY_LOGGER.debug(PASS_INFO) # validate tle files exist wxcutils.validate_tle(WORKING_PATH) # to enable REPROCESSing using the original tle file, rename it to match the FILENAME_BASE wxcutils.copy_file(WORKING_PATH + 'weather.tle', OUTPUT_PATH + FILENAME_BASE + 'weather.tle') # write out process information
def get_predict(sat_data, sat, time_stamp, end_time_stamp, when, capture): """parse output from predict""" def date_value(row): """extract date time from row""" return row.split()[2][:2] + ' ' + \ row.split()[2][2:5] + ' 20' + \ row.split()[2][5:] + ' ' + row.split()[3] MY_LOGGER.debug('getting prediction between %s and %s', str(time_stamp), str(end_time_stamp)) # get the SDR data MY_LOGGER.debug('sat = %s', sat) antenna, chipset, sdr_type, centre_frequency, frequency_range, modules, \ sdr_active, serial_number, bias_t = get_sdr_data(sat['sdr']) MY_LOGGER.debug('Grabbing prediction') sat_id = sat['NORAD catalog number'] MY_LOGGER.debug('NORAD catalog number = %s', sat_id) MY_LOGGER.debug('Predict command: %s %s %s %s %s %s', '/usr/bin/predict', '-t', WORKING_PATH + 'weather.tle', '-p', sat_id, str(time_stamp)) cmd = Popen([ '/usr/bin/predict', '-t', WORKING_PATH + 'weather.tle', '-p', sat_id, str(time_stamp) ], stdout=PIPE, stderr=PIPE) stdout, stderr = cmd.communicate() MY_LOGGER.debug('stdout:%s', stdout) MY_LOGGER.debug('stderr:%s', stderr) lines = stdout.decode('utf-8').splitlines() lines_len = len(lines) - 1 MY_LOGGER.debug('lines_len = %d', lines_len) if lines_len > 1: MY_LOGGER.debug('Prediction data = %s', lines) else: MY_LOGGER.critical( 'No prediction data - validate satellites.json and predict code' ' - for satellite = %s', sat['name']) orbit = lines[0].split()[10] MY_LOGGER.debug('orbit = %s', orbit) MY_LOGGER.debug('Sat type = %s', sat['type']) elevation_type = 'Min Elevation-' + str(sat['type']) min_elevation = int(CONFIG_INFO[elevation_type]) MY_LOGGER.debug('min_elevation = %s', str(min_elevation)) # start to parse the predict output visible_start = '' visible_end = '' visible_at_start = False visible_at_end = False theta = [] radius = [] plot_labels = [] if '+' in stdout.decode('utf-8'): visible = '' counter = 0 for row in lines: elements = row.split() status = '' counter += 1 try: status = elements[11].replace('*', VISIBLE_NO).replace( '+', VISIBLE_YES).replace('0.000000', '_') except IndexError: status = '-' # capture if visible at the start of the pass if counter == 1 and status == VISIBLE_YES: visible_at_start = True # if visible and not yet started, start if status == VISIBLE_YES and visible_start == '': visible_start = date_value(row) # if not visible and has started, has not previously ended, end if status == VISIBLE_NO and visible_start != '' and visible_end == '': visible_end = date_value(row) # end of loop, so if started and not ended, end if visible_start != '' \ and visible_end == '' \ and counter == len(lines): visible_end = date_value(row) if status == VISIBLE_YES: visible_at_end = True # MY_LOGGER.debug(counter, len(lines), visible, visible_start, visible_end) else: visible = 'No' if visible != 'No': visible_duration = int(float(wxcutils.utc_to_epoch(visible_end, '%d %b %Y %H:%M:%S')) \ - float(wxcutils.utc_to_epoch(visible_start, '%d %b %Y %H:%M:%S'))) MY_LOGGER.debug('visible_duration = %s', str(visible_duration)) if visible_at_start and visible_at_end: visible = 'Yes - for all of pass' elif visible_at_start and not visible_at_end and visible_duration > 0: visible = 'Yes - for ' + str(visible_duration // 60) + ':' + \ str(visible_duration % 60).zfill(2) + ' from start' elif not visible_at_start and visible_at_end and visible_duration > 0: visible = 'Yes - for ' + str(visible_duration // 60) + ':' + \ str(visible_duration % 60).zfill(2) + ' from end' else: visible = 'No' MY_LOGGER.debug('visible = %s', visible) MY_LOGGER.debug('visible_start = %s', visible_start) MY_LOGGER.debug('visible_end = %s', visible_end) pass_start = lines[0].split()[1] + ' ' + lines[0].split()[2][:2] + \ ' ' + lines[0].split()[2][2:5] + ' 20' + lines[0].split()[2][5:] + \ ' ' + lines[0].split()[3] # MY_LOGGER.debug('pass start (UTC) = ' + pass_start) start_date_local = wxcutils.utc_to_local(pass_start, '%a %d %b %Y %H:%M:%S') # MY_LOGGER.debug('pass start (local) = ' + start_date_local) pass_end = lines[lines_len].split()[1] + ' ' + lines[lines_len].split()[2][:2] + ' ' + \ lines[lines_len].split()[2][2:5] + ' 20' + lines[lines_len].split()[2][5:] + ' ' + \ ' ' + lines[lines_len].split()[3] # MY_LOGGER.debug('pass end (UTC) = ' + pass_end) end_date_local = wxcutils.utc_to_local(pass_end, '%a %d %b %Y %H:%M:%S') # MY_LOGGER.debug('pass end (local) = ' + end_date_local) start_epoch = int(lines[0].split()[0]) # MY_LOGGER.debug('start_epoch = ' + str(start_epoch)) end_epoch = int(lines[lines_len].split()[0]) # MY_LOGGER.debug('end_epoch = ' + str(end_epoch)) duration = end_epoch - start_epoch # MY_LOGGER.debug('pass duration = ' + str(duration) + ' seconds') duration_string = str(duration // 60) + ':' + str(duration % 60).zfill(2) # MY_LOGGER.debug('pass duration = ' + duration_string) max_elevation = 0 azimuthmax_elevation = 0 for line in lines: elements = line.split() # MY_LOGGER.debug(elements) if int(elements[4]) > max_elevation: max_elevation = int(elements[4]) azimuthmax_elevation = int(elements[5]) # polar plot theta.append(-2 * math.pi * (float(elements[5]) - 90) / 360) radius.append((90 - float(elements[4])) / 90) plot_labels.append(wxcutils.epoch_to_local(elements[0], '%H:%M:%S')) MY_LOGGER.debug('max_elevation = %s', str(max_elevation)) MY_LOGGER.debug('azimuthmax_elevation = %s', str(azimuthmax_elevation)) if azimuthmax_elevation > 180: max_elevation_direction = 'W' max_elevation_direction_desc = 'West' else: max_elevation_direction = 'E' max_elevation_direction_desc = 'East' MY_LOGGER.debug('max_elevation_direction = %s', max_elevation_direction) MY_LOGGER.debug('predict first line = %s', lines[0]) MY_LOGGER.debug('predict last line = %s', lines[lines_len]) pass_radius_start = 1.0 - (float(lines[0].split()[4]) / 90.0) pass_radius_end = 1.0 - (float(lines[lines_len].split()[4]) / 90.0) pass_theta_start = (math.pi / 180.0) * float(lines[0].split()[5]) pass_theta_end = (math.pi / 180.0) * float(lines[lines_len].split()[5]) y_start = pass_radius_start * math.cos(pass_theta_start) y_end = pass_radius_end * math.cos(pass_theta_end) if y_start > y_end: MY_LOGGER.debug('Southbound pass') direction = 'Southbound' else: MY_LOGGER.debug('Northbound pass') direction = 'Northbound' plot_title = sat['name'] + '\n' + direction + ' Pass\n' capture_reason = 'Not defined' if capture == 'no': capture_reason = 'Not configured for capture' # only append if elevation high enough and in the current local day if (max_elevation >= min_elevation) and (start_epoch < end_time_stamp): # schedule pass # only schedule for today scheduler = '' receive_code = '???' if (when == 'today') and (capture == 'yes'): capture_reason = 'Capture criteria met' if sat['type'] == 'NOAA': receive_code = CODE_PATH + 'receive_noaa.py' scheduler = scheduler_command(receive_code, sat['name'], start_epoch, duration, max_elevation) # for Meteor, always record daylight passes, conditionally record night passes elif sat['type'] == 'METEOR': receive_code = CODE_PATH + 'receive_meteor.py' if is_daylight(float(start_epoch), float(end_epoch)) == 'Y': MY_LOGGER.debug('Daylight pass - %s', str(start_epoch)) scheduler = scheduler_command(receive_code, sat['name'], start_epoch, duration, max_elevation) elif sat['night'] == 'yes': MY_LOGGER.debug('Night pass - %s', str(start_epoch)) scheduler = scheduler_command(receive_code, sat['name'], start_epoch, duration, max_elevation) else: MY_LOGGER.debug('Not scheduled as sensor turned off') MY_LOGGER.debug('Darkness pass - %s', str(start_epoch)) capture_reason = 'Darkness and using visible light sensor' elif sat['type'] == 'SSTV': receive_code = CODE_PATH + 'receive_sstv.py' scheduler = scheduler_command( receive_code, sat['name'].replace('(', '').replace(')', ''), start_epoch, duration, max_elevation) elif sat['type'] == 'AMSAT': receive_code = CODE_PATH + 'receive_amsat.py' scheduler = scheduler_command(receive_code, sat['name'], start_epoch, duration, max_elevation) elif sat['type'] == 'MORSE': receive_code = CODE_PATH + 'receive_morse.py' scheduler = scheduler_command(receive_code, sat['name'], start_epoch, duration, max_elevation) else: MY_LOGGER.debug('No processsing code for %s of type %s', sat['name'], sat['type']) if 'METEOR' in sat['name']: symbol_rate = sat['meteor symbol rate'] mode = sat['meteor mode'] else: symbol_rate = 'n/a' mode = 'n/a' pass_meridian = 'am' MY_LOGGER.debug('start_date_local = %s', start_date_local) local_hour = int(start_date_local.split(' ')[4].split(':')[0]) MY_LOGGER.debug('local_hour = %d', local_hour) if (int(start_date_local.split(' ')[4].split(':')[0]) >= 13) or (int( start_date_local.split(' ')[4].split(':')[0]) <= 2): pass_meridian = 'pm' MY_LOGGER.debug('Setting to a night pass') else: MY_LOGGER.debug('Setting to a day pass') filename_base = wxcutils.epoch_to_utc(start_epoch, '%Y-%m-%d-%H-%M-%S') + \ '-' + sat['name'].replace(' ', '_').replace('(', '').replace(')', '') sat_data.append({ 'time': start_epoch, 'satellite': sat['name'], 'max_elevation': max_elevation, 'start_date_local': start_date_local, 'end_date_local': end_date_local, 'startDate': pass_start, 'endDate': pass_end, 'duration_string': duration_string, 'duration': duration, 'frequency': sat['frequency'], 'orbit': orbit, 'direction': direction, 'visible': visible, 'max_elevation_direction': max_elevation_direction, 'max_elevation_direction_desc': max_elevation_direction_desc, 'scheduler': scheduler, 'capture': sat['capture'], 'receive code': receive_code, 'capture reason': capture_reason, 'theta': theta, 'radius': radius, 'plot_labels': plot_labels, 'plot_title': plot_title, 'filename_base': filename_base, 'priority': sat['priority'], 'meteor symbol rate': symbol_rate, 'meteor mode': mode, 'antenna': antenna, 'chipset': chipset, 'sdr': sat['sdr'], 'sdr type': sdr_type, 'centre frequency': centre_frequency, 'frequency range': frequency_range, 'modules': modules, 'sdr active': sdr_active, 'serial number': serial_number, 'bias t': bias_t, 'pass meridian': pass_meridian, 'sat type': sat['type'] }) # return new start time for next pass search to start # 90 minutes for delay between passes (next orbit will be at least 90 minutes later) return end_epoch + (90 * 60)