예제 #1
0
def schedule(sat_data, sat, when, capture):
    """schedule each satellite"""
    MY_LOGGER.debug('---')
    MY_LOGGER.debug('Frequency = %s', str(sat['frequency']))
    MY_LOGGER.debug('Name = %s', sat['name'])

    if when == 'today':
        starttime_stamp = float(wxcutils.local_datetime_to_epoch \
            (datetime.today().replace(hour=0).replace(minute=0) \
            .replace(second=0)))
        end_time_stamp = starttime_stamp + (24 * 60 * 60) - 1
        MY_LOGGER.debug('today %s %s', str(starttime_stamp),
                        str(end_time_stamp))
        MY_LOGGER.debug(
            'Start = %s',
            wxcutils.epoch_to_local(starttime_stamp, '%a %d %b %Y %H:%M:%S'))
        MY_LOGGER.debug(
            'End = %s',
            wxcutils.epoch_to_local(end_time_stamp, '%a %d %b %Y %H:%M:%S'))
    else:
        starttime_stamp = float(wxcutils.local_datetime_to_epoch \
            (datetime.today().replace(hour=0).replace(minute=0) \
            .replace(second=0))) + (24*60*60)
        end_time_stamp = starttime_stamp + \
            (int(CONFIG_INFO['Pass List Days']) * 24 * 60 * 60) - 1
        MY_LOGGER.debug('later %s %s', str(starttime_stamp),
                        str(end_time_stamp))
        MY_LOGGER.debug(
            'Start = %s',
            wxcutils.epoch_to_local(starttime_stamp, '%a %d %b %Y %H:%M:%S'))
        MY_LOGGER.debug(
            'End = %s',
            wxcutils.epoch_to_local(end_time_stamp, '%a %d %b %Y %H:%M:%S'))
    MY_LOGGER.debug('looping through date range')
    while starttime_stamp < end_time_stamp:
        starttime_stamp = get_predict(sat_data, sat, starttime_stamp,
                                      end_time_stamp, when, capture)
예제 #2
0
def build_pass_json():
    """build json file for all passes"""
    MY_LOGGER.debug('building pass json')
    json_data = []
    for filename in find_files(TARGET, '*.html'):
        if filename.split(
                TARGET
        )[1][:
             2] == '20' and 'captures' not in filename and 'meteor' not in filename and 'noaa' not in filename:
            # MY_LOGGER.debug('found pass page - filename = %s', filename)
            bpj_file_path, html_file = os.path.split(filename)
            base_filename, base_extension = os.path.splitext(html_file)
            filename_root = filename[:len(filename) - len(base_extension)]
            # look for all the image files and add to the list
            # to avoid the json file getting too large, extract the enhancement part only
            image_files = glob.glob(bpj_file_path + '/images/' +
                                    base_filename + '*.jpg')
            image_enhancements = []
            for entry in image_files:
                if entry[len(entry) - 7:] != '-tn.jpg':
                    result = entry.replace('.jpg', '').replace(
                        bpj_file_path + '/images/',
                        '').replace(base_filename, '')
                    image_enhancements.append(result[1:])

            json_data.append({
                'path': filename_root.replace(TARGET, ''),
                'enhancement': image_enhancements
            })
            # build data for catures pages
            # MY_LOGGER.debug('filename_root = %s', filename_root.replace(TARGET, '')[11:30])
            local_sort = wxcutils.epoch_to_local(
                wxcutils.utc_to_epoch(
                    filename_root.replace(TARGET, '')[11:30],
                    '%Y-%m-%d-%H-%M-%S'), '%Y-%m-%d-%H-%M-%S')
            # MY_LOGGER.debug('local = %s', local)
            ALL_PASSES.append({
                'path': filename_root.replace(TARGET, ''),
                'local sort': local_sort,
                'local year': local_sort[:4],
                'local month': local_sort[5:7],
                'local day': local_sort[8:10],
                'local time': local_sort[11:19]
            })
    MY_LOGGER.debug('saving passses.json')
    wxcutils.save_json(TARGET, 'passes.json', json_data)
예제 #3
0
def get_local_date_time():
    """get the local date time"""
    return wxcutils.epoch_to_local(time.time(), '%a %d %b %H:%M')
예제 #4
0
    # find latest file in each directory and copy to output directory
    for directory in data_directories:
        MY_LOGGER.debug('---------------------------------------------')
        MY_LOGGER.debug('directory = %s', directory)
        location = os.path.join(date_base_dir, directory)
        MY_LOGGER.debug('location = %s', location)
        latest_file = find_latest_file(location)
        MY_LOGGER.debug('latest_file = %s', latest_file)
        filename, extenstion = os.path.splitext(latest_file)
        MY_LOGGER.debug('extenstion = %s', extenstion)

        # date time for original file
        latest = os.path.getmtime(os.path.join(location, latest_file))
        MY_LOGGER.debug('latest = %d', latest)
        latest_local = wxcutils.epoch_to_local(latest, '%a %d %b %H:%M')
        MY_LOGGER.debug('latest_local = %s', latest_local)

        stored_timestamp = 0.0
        try:
            stored_timestamp = latest_timestamps[directory + extenstion]
        except NameError:
            pass
        except KeyError:
            pass

        # REMOVE REMOVE REMOVE
        # if directory == 'FD':
        #     stored_timestamp = 0

        delta = latest - stored_timestamp
예제 #5
0
                                PREVIOUS = nc2
                                MY_LOGGER.debug('Previous = %s', PREVIOUS)

                CHANGE = 'N'
                if nc['status'] != PREVIOUS['status']:
                    EMAIL_REQUIRED = True
                    CHANGE = 'Y'
                EMAIL_HTML3 += '<td align = \"center\">' + CHANGE + '</td>'

                EMAIL_TEXT3 += nc['description'] + ' - '
                EMAIL_HTML3 += '<td>' + nc['description'] + '</td>'

                if nc['status'] == 'OK':
                    EMAIL_TEXT3 += 'OK - network connectivity is good' + ' - '
                    EMAIL_HTML3 += '<td>Good connectivity</td><td>' + \
                        wxcutils.epoch_to_local(nc['when'], '%m/%d/%Y %H:%M') + '</td></tr>' + NEWLINE
                else:
                    EMAIL_TEXT3 = 'Error - network connecitivity issue - ' + nc[
                        'status'] + ''
                    EMAIL_HTML3 += '<td>' + nc['status'] + '</td><td>' + \
                        wxcutils.epoch_to_local(nc['when'], '%m/%d/%Y %H:%M') + '</td></tr>' + NEWLINE

MY_LOGGER.debug('HTML = ' + EMAIL_HTML3)
MY_LOGGER.debug('txt = ' + EMAIL_TEXT3)

# save last
wxcutils.save_json(CONFIG_PATH, 'network.json', LATESTNETWORK)

# validate satellite status
MY_LOGGER.debug('-' * 20)
LATESTSATSTATUS = wxcutils.load_json(WEB_PATH + 'gk-2a/',
예제 #6
0
def is_daylight(id_pass_start, id_pass_end):
    """check if it is daylight at the time"""
    def get_timestamp(tmp_dt):
        part = tmp_dt.strftime('%Y-%m-%d-%H-%M')
        bits = part.split('-')
        return time_scale.utc(int(bits[0]), int(bits[1]), int(bits[2]),
                              int(bits[3]), int(bits[4]))

    # if unable to load files, assume daylight is true
    # avoids crash and at worst will capture a nighttime pass
    try:

        # update planets info
        MY_LOGGER.debug('Loading new files')
        load = Loader(WORKING_PATH)
        time_scale = load.timescale()
        e_e = load('de421.bsp')

        start_time_epoch = float(wxcutils.local_datetime_to_epoch \
                    (datetime.today().replace(hour=0).replace(minute=0) \
                    .replace(second=0)))
        end_time_epoch = start_time_epoch + (24 * 60 * 60) - 1
        start_dt = wxcutils.epoch_to_datetime_utc(start_time_epoch)
        end_dt = wxcutils.epoch_to_datetime_utc(end_time_epoch)

        gps_location = api.Topos(CONFIG_INFO['GPS location NS'],
                                 CONFIG_INFO['GPS location EW'])

        a_t, a_y = almanac.find_discrete(
            get_timestamp(start_dt), get_timestamp(end_dt),
            almanac.sunrise_sunset(e_e, gps_location))
        MY_LOGGER.debug(a_t)
        MY_LOGGER.debug(a_y)

        daylight_start = wxcutils.utc_to_epoch(
            a_t[0].utc_iso().replace('T', ' ').replace('Z', ''),
            '%Y-%m-%d %H:%M:%S')
        daylight_end = wxcutils.utc_to_epoch(
            a_t[1].utc_iso().replace('T', ' ').replace('Z', ''),
            '%Y-%m-%d %H:%M:%S')

        # capture if middle of the pass is in daylight
        id_pass_midpoint = id_pass_start + ((id_pass_end - id_pass_start) / 2)
        MY_LOGGER.debug(
            'daylight_start = %s, %s', daylight_start,
            wxcutils.epoch_to_local(daylight_start, '%a %d %b %H:%M'))
        MY_LOGGER.debug(
            'daylight_end = %s, %s', daylight_end,
            wxcutils.epoch_to_local(daylight_end, '%a %d %b %H:%M'))
        MY_LOGGER.debug(
            'id_pass_start = %s, %s', id_pass_start,
            wxcutils.epoch_to_local(id_pass_start, '%a %d %b %H:%M'))
        MY_LOGGER.debug(
            'id_pass_midpoint = %s, %s', id_pass_midpoint,
            wxcutils.epoch_to_local(id_pass_midpoint, '%a %d %b %H:%M'))
        MY_LOGGER.debug('id_pass_end = %s, %s', id_pass_end,
                        wxcutils.epoch_to_local(id_pass_end, '%a %d %b %H:%M'))

        MY_LOGGER.debug('twighlight allowance in minutes = %s',
                        CONFIG_INFO['twilight allowance'])
        id_twighlight = float(CONFIG_INFO['twilight allowance']) * 60
        MY_LOGGER.debug('twighlight allowance in seconds = %f', id_twighlight)

        if (float(daylight_start) - id_twighlight) <= id_pass_midpoint <= (float(daylight_end) + id_twighlight) or \
            (float(daylight_start) - id_twighlight) <= id_pass_midpoint <= (float(daylight_end) + id_twighlight):
            MY_LOGGER.debug('This is a daylight pass')
            return 'Y'
        else:
            MY_LOGGER.debug('This is NOT a daylight pass')
    except:
        MY_LOGGER.debug('Exception during is_daylight: %s %s %s',
                        sys.exc_info()[0],
                        sys.exc_info()[1],
                        sys.exc_info()[2])
        MY_LOGGER.debug(
            'Assuming it is daylight so as to always capture a file in this case'
        )
        return 'Y'
    return 'N'
예제 #7
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)