user_model->authorize(2)) { $this->session->set_flashdata('error', __("You're not allowed to do that!")); redirect('dashboard'); } } public function index() { $this->load->driver('cache', [ 'adapter' => $this->config->item('cache_adapter') ?? 'file', 'backup' => $this->config->item('cache_backup') ?? 'file', 'key_prefix' => $this->config->item('cache_key_prefix') ?? '' ]); $cache_key = 'amsatstatus_reports_24h'; $json = $this->cache->get($cache_key); if ($json === false) { $url = 'https://www.amsat.org/status/api/v1/reports.php?hours=24&limit=500'; $ctx = stream_context_create(['http' => [ 'method' => 'GET', 'timeout' => 15, 'user_agent' => 'Wavelog/'.$this->optionslib->get_option('version') ]]); $fetched = @file_get_contents($url, false, $ctx); if ($fetched === false) { $this->session->set_flashdata('message', __("The AMSAT status service is currently unavailable. Please try again later.")); $data['matrix'] = []; $data['sat_order'] = []; $data['display_names'] = []; $data['wl_link'] = []; $data['next_pass'] = []; $data['now'] = time(); $data['page_title'] = __("AMSAT Satellite Status"); $this->load->view('interface_assets/header', $data); $this->load->view('/amsatstatus/index', $data); $this->load->view('interface_assets/footer', []); return; } $this->cache->save($cache_key, $fetched, 60*15); $json = $fetched; } $decoded = json_decode($json, true); $reports = $decoded['data'] ?? []; $status_priority = [ 'Heard' => 1, 'Crew Active' => 2, 'Telemetry Only' => 3, 'Not Heard' => 4, ]; $now = time(); $buckets = []; $sat_latest = []; $display_names = []; foreach ($reports as $r) { $name = $r['name'] ?? ''; if ($name === '') continue; if (!empty($r['satellite_display_name'])) { $display_names[$name] = $r['satellite_display_name']; } elseif (!isset($display_names[$name])) { $display_names[$name] = $name; } $epoch = strtotime($r['reported_time'] ?? ''); if ($epoch === false) continue; $age_h = (int)floor(($now - $epoch) / 3600); if ($age_h < 0 || $age_h > 23) continue; $col = $age_h; $status = $r['report'] ?? ''; $callsign = $r['callsign'] ?? ''; $grid = $r['grid_square'] ?? ''; if (!isset($buckets[$name][$col])) { $buckets[$name][$col] = [ 'counts' => [], 'reporters' => [], 'winning' => $status, 'winning_priority' => $status_priority[$status] ?? 99, 'total' => 0, 'latest_epoch' => $epoch, 'latest_callsign' => $callsign, 'latest_grid' => $grid, ]; } $cell =& $buckets[$name][$col]; $cell['counts'][$status] = ($cell['counts'][$status] ?? 0) + 1; $cell['total']++; $cell['reporters'][] = ['epoch' => $epoch, 'callsign' => $callsign, 'grid' => $grid, 'status' => $status]; $p = $status_priority[$status] ?? 99; if ($p < $cell['winning_priority']) { $cell['winning'] = $status; $cell['winning_priority'] = $p; } if ($epoch > $cell['latest_epoch']) { $cell['latest_epoch'] = $epoch; $cell['latest_callsign'] = $callsign; $cell['latest_grid'] = $grid; } unset($cell); if (!isset($sat_latest[$name]) || $epoch > $sat_latest[$name]) { $sat_latest[$name] = $epoch; } } foreach ($buckets as $name => &$cells) { foreach ($cells as &$cell) { usort($cell['reporters'], function($a, $b) { return $b['epoch'] - $a['epoch']; }); } unset($cell); } unset($cells); $sat_order = array_keys($sat_latest); usort($sat_order, fn($a, $b) => strnatcasecmp($display_names[$a] ?? $a, $display_names[$b] ?? $b)); $matrix = []; foreach ($buckets as $name => $cells) { $row = []; for ($col = 0; $col < 24; $col++) { $row[$col] = $cells[$col] ?? null; } $matrix[$name] = $row; } $this->load->model('satellite_model'); $this->load->model('stations'); $this->load->library('satpredict'); $wl_map = []; foreach ($this->satellite_model->get_all_satellites_with_tle() as $wl) { $base = $wl->satname ?: ($wl->displayname ?? ''); if ($base === '') continue; $key = strtoupper(trim(preg_replace('/[\[_].*/', '', $base))); if ($key !== '' && !isset($wl_map[$key])) { $wl_map[$key] = $wl; } } $grid = $this->stations->find_gridsquare(); $have_grid = ($grid && strtoupper((string)$grid) !== '0'); $alias = [ 'ISS' => 'ARISS', 'SONATE-2' => 'SONATE', ]; $prefix_alias = [ 'TEVEL2-' => 'TEV2-', ]; $wl_link = []; $next_pass = []; foreach ($sat_order as $name) { $key = strtoupper(trim(preg_replace('/[\[_].*/', '', $name))); if (isset($alias[$key])) { $key = $alias[$key]; } else { foreach ($prefix_alias as $from => $to) { if (str_starts_with($key, $from)) { $key = $to . substr($key, strlen($from)); break; } } } $wl = $wl_map[$key] ?? null; if (!$wl) continue; $wl_link[$name] = $wl->satname ?: $wl->displayname; if ($have_grid) { $pass = $this->satpredict->next_pass($wl, $grid, 0, 1); if ($pass) { $next_pass[$name] = [ 'aos' => (float) $pass->aos, 'time' => Predict_Time::daynum2readable($pass->aos, 'UTC', 'H:i'), 'maxel' => isset($pass->max_el) ? (int)round($pass->max_el) : null, ]; } } } $data['matrix'] = $matrix; $data['sat_order'] = $sat_order; $data['display_names'] = $display_names; $data['wl_link'] = $wl_link; $data['next_pass'] = $next_pass; $data['now'] = $now; $data['page_title'] = __("AMSAT Satellite Status"); $footerData = []; $footerData['scripts'] = ['assets/js/sections/amsatstatus.js']; $this->load->view('interface_assets/header', $data); $this->load->view('/amsatstatus/index', $data); $this->load->view('interface_assets/footer', $footerData); } }