Example #1
0
def get_utc_date_time():
    """get the local date time"""
    return wxcutils.epoch_to_utc(time.time(), '%a %d %b %H:%M')
Example #2
0
    # 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
Example #3
0
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)