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)
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)
def get_local_date_time(): """get the local date time""" return wxcutils.epoch_to_local(time.time(), '%a %d %b %H:%M')
# 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
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/',
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'
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)