Skip to content

TALOS-SatNOGS Integration Analysis

Version: 0.3.0 Date: April 2026 Author: Libre Space Foundation / TALOS Project Status: Active Research


1. Current Integration Points

TALOS consumes two SatNOGS APIs through a single consolidated client (shared/satnogs_client.py). All SatNOGS interactions across the web backend and the mission director route through the SatNOGSClient class, which provides caching, error handling, and connection pooling via a persistent requests.Session.

SatNOGS DB API (https://db.satnogs.org/api)

Endpoint Method Purpose TALOS Consumer
/api/satellites/?status=alive get_satellites() Full satellite catalog sync sync_satnogs_data() in core/main.py
/api/tle/ (full catalog) get_all_tles() Bulk TLE download for sky scanning sync_satnogs_data() startup sync
/api/tle/?sat_id={id} get_tle(sat_id) Single-satellite TLE fetch TLEManager.fetch() in director/tle_manager.py
/api/tle/?norad_cat_id={id} Direct httpx call Public tracker TLE fetch _fetch_tle_for_norad() in core/main.py
/api/transmitters/?satellite__norad_cat_id={id} get_transmitters(norad_id) Transmitter metadata for campaigns Campaign creation, legacy mission creation

SatNOGS Network API (https://network.satnogs.org/api)

Endpoint Method Purpose TALOS Consumer
/api/stations/{id}/ get_station_info(network_id) Station metadata during provisioning provision_station() in core/main.py

Health Check

The client exposes health_check() which pings GET /api/ on DB API and returns True if the response status is below 500. This is used for readiness probes.


2. Data Flow

Satellite Catalog Sync

On startup (deferred 30 seconds to avoid blocking the HTTP server), sync_satnogs_data() executes a full two-phase sync:

Phase 1 -- Satellite metadata: 1. Fetches GET /api/satellites/?status=alive&format=json (typically 3000-5000 entries) 2. Upserts each satellite into the satellitecache PostgreSQL table (SatelliteCache model) 3. Fields stored: sat_id (PK), name, norad_id (indexed), status, updated_at 4. Satellites without a norad_cat_id are skipped

Phase 2 -- TLE physics cache: 1. Fetches GET /api/tle/ (the entire TLE catalog, typically 8000+ entries) 2. Compiles EarthSatellite objects in chunks of 500 to bound peak RAM (~30 MB per chunk) 3. Atomically swaps the GLOBAL_SAT_REGISTRY list so readers always see a consistent snapshot 4. This registry powers the "Magic Find" sky-scanning feature

The sync can be triggered manually via POST /api/sync which runs sync_satnogs_data as a background task.

TLE Caching (Mission Director)

The TLEManager in director/tle_manager.py handles per-campaign TLE management:

  1. On first tick for a campaign, MultiTLEManager.get_or_create() instantiates a TLEManager and calls fetch(satnogs_id, name)
  2. fetch() calls SatNOGSClient.get_tle(sat_id) which hits /api/tle/?sat_id={id}
  3. The response's first entry (most recent TLE) is compiled into an EarthSatellite
  4. TLE epoch is extracted and age is tracked with two thresholds:
  5. TLE_WARN_AGE: 24 hours (warning log)
  6. TLE_CRITICAL_AGE: 72 hours (critical warning log)
  7. On fetch failure, the cached satellite is returned as fallback
  8. MultiTLEManager.cleanup_stale() is called each tick to free TLE managers for deactivated campaigns

Transmitter Metadata

When a campaign is created (POST /api/orgs/{slug}/campaigns):

  1. norad_id is resolved from satnogs_id via the SatelliteCache table if not provided directly
  2. SatNOGSClient.get_transmitters(norad_id) fetches active transmitters from DB API
  3. Only transmitters with status == "active" are persisted
  4. A safety cap of 50 transmitters prevents runaway storage for multi-transmitter satellites
  5. Each transmitter is stored as a Transmitter row linked to the campaign, preserving: uuid, description, type, uplink_low/high, downlink_low/high, mode, baud, status

Station Metadata

During station provisioning (POST /api/orgs/{slug}/stations):

  1. Operator provides a SatNOGS Network station ID
  2. SatNOGSClient.get_station_info(network_id) fetches GET /api/stations/{id}/ from Network API
  3. Station name, latitude, longitude, and altitude are extracted (with fallbacks for field name variations: lon/lng, altitude/elevation)
  4. A TALOS station record is created with auto-generated station_id and api_key
  5. Station info is NOT cached -- it is a one-time fetch during provisioning

Public Satellite Tracker

The public tracker (/track route, public_track.html) fetches TLEs independently:

  1. Uses httpx.AsyncClient directly (not the shared SatNOGSClient) for async compatibility
  2. Hits GET /api/tle/?norad_cat_id={id}&format=json on each position request
  3. Propagates the TLE to current time using Skyfield's SGP4 implementation
  4. Returns: lat, lon, altitude_km, velocity_km_s, norad_id, tle_age_hours
  5. The frontend polls this every 2 seconds and displays a TLE age warning when age exceeds 24 hours
  6. Quick-select buttons default to PHASMA-LAMARR (66673), PHASMA-DIRAC (66681), PeakSat (98378), and ISS (25544)

3. API Usage Patterns

Caching Strategy

The SatNOGSClient implements a thread-safe in-memory cache with per-key TTLs:

Cache Key Pattern TTL Scope
satellites:{status} 15 min (default) Full satellite catalog
tle:all 30 min (explicit) Entire TLE catalog
tle:{sat_id} 15 min (default) Single-satellite TLE
transmitters:{norad_id} 15 min (default) Transmitter list per satellite
Station info Not cached One-time provisioning fetch

The default cache_ttl is 900 seconds (15 minutes). The bulk TLE catalog uses an explicit 1800 seconds (30 minutes) since it is a large payload that changes infrequently.

Stale Data Fallback

On any request failure (timeout, connection error, HTTP error, invalid JSON), the client checks for a stale cache entry via _cache_get_stale(). This returns expired data with a warning log, providing graceful degradation when SatNOGS APIs are unreachable. This is critical for satellite tracking continuity -- a stale TLE is far better than no TLE.

Timeouts

Operation Timeout
Catalog fetches (satellites, all TLEs) 45 seconds
Single-item fetches (one TLE, transmitters, station info) 10 seconds
Health check 10 seconds
Public tracker TLE fetch (httpx) 10 seconds

Rate Limiting

TALOS does not implement explicit rate limiting against SatNOGS APIs. The caching layer provides implicit rate reduction. The SatNOGS DB API is public and does not require authentication for read operations. The Network API station endpoint is also public. There is no API key configured in the client.

Error Handling

All requests exceptions are caught individually (Timeout, ConnectionError, HTTPError, RequestException, ValueError for JSON parse). Each is logged at ERROR level with the URL. The method returns None on failure after attempting the stale cache fallback.


4. Coexistence Strategy

Architecture: talos-agent Alongside satnogs-client

Both daemons can run on the same station host (Raspberry Pi or x86 PC):

Station Host
+-----------------------------------------------+
|                                                |
|  satnogs-client           talos-agent          |
|  (GNU Radio, DSP,         (MQTT, rotctld,      |
|   waterfall, upload)       rig control)         |
|       |                        |                |
|       +--- rotctld (TCP 4533) -+                |
|       +--- rigctld (TCP 4532) -+                |
|       +--- SDR device --------+                 |
|                                                |
+-----------------------------------------------+

Resource Contention Points

  1. Rotator (rotctld): Both systems send az/el commands via TCP. Only one should control at a time.
  2. SDR device: USB SDR dongles (RTL-SDR, Airspy) support single-client access. Simultaneous use causes device busy errors.
  3. Rig control (rigctld): Frequency tuning conflicts if both try to set different frequencies.

Coordination Mechanism (Not Yet Implemented)

The recommended approach is a file-lock or MQTT-based mutex: - When TALOS activates a campaign assignment for the station, it acquires the hardware lock - satnogs-client checks the lock before starting an observation and defers if locked - When the TALOS campaign deactivates, the lock is released - During idle periods, satnogs-client operates normally with SatNOGS-scheduled observations

This coordination layer is identified as a Phase 2 integration item and is not yet built.


5. Feature Comparison

Capability SatNOGS Network TALOS
Scheduling model Pre-scheduled per-station jobs, polled Real-time operator-directed, fleet-wide
Station coordination None (stations are independent) Central director drives all stations simultaneously
Doppler correction Client-side per-station (GNU Radio) Centralized physics engine, pushed via MQTT
Rotator tracking Client-side via rotctld Centralized az/el push at ~2 Hz
Signal processing GNU Radio flowgraphs (gr-satnogs) Not implemented
Data products Waterfall PNG, audio OGG, decoded frames, HDF5 None
Satellite database SatNOGS DB (authoritative) Consumes SatNOGS DB
Sky scanning Not available "Magic Find" -- 8000+ orbits scanned in real-time
Communication HTTP polling (~60s intervals) MQTT pub/sub (sub-second)
Station provisioning Manual via satnogs-config One-command deploy from SatNOGS Network ID
Multi-frequency coordination Not possible Different stations can monitor different transmitters
Pass handoff Not possible Designed for seamless station-to-station handoff

What TALOS Adds

  • Real-time multi-station coordination: SatNOGS treats each station as independent; TALOS orchestrates fleets
  • Centralized physics engine: All stations share the same orbital model, eliminating per-station drift
  • Sub-second command loop: MQTT-based az/el and Doppler push at 2 Hz
  • Live mission control UI: Real-time satellite footprint, rotator telemetry, Doppler display
  • Instant sky scanning: "What is overhead right now?" answered in milliseconds across 8000+ objects

6. Integration Gaps

Observation Scheduling

TALOS has no built-in scheduler. Campaigns are operator-activated, not time-scheduled. There is no integration with SatNOGS auto-scheduler or the Network's job dispatch system (GET /api/jobs/). Stations cannot currently accept SatNOGS-scheduled observations during TALOS idle time.

Waterfall and RF Data Capture

TALOS agents control rotators and tune radios but do not capture RF data. There is no IQ recording, waterfall generation, or audio capture. This means TALOS-driven passes produce no permanent data products and contribute nothing back to the SatNOGS observation archive.

Demodulation and Decoding

No demodulation pipeline exists. TALOS does not integrate with gr-satnogs flowgraphs or any alternative DSP stack. Decoded telemetry frames are not produced or submitted to the SatNOGS DB SiDS endpoint (POST /api/telemetry/).

Observation Submission

There is no mechanism to submit observation results to SatNOGS Network (POST /api/observations/). Even if RF data were captured, the upload pipeline is absent.

TLE Source Redundancy

TALOS relies exclusively on SatNOGS DB for TLEs. There is no fallback to CelesTrak, Space-Track, or other TLE sources. If SatNOGS DB is down, tracking degrades to stale cached TLEs.

Satellite Status Notifications

TALOS syncs the satellite catalog on startup and via manual trigger but does not detect status changes (new launches, re-entries, status updates) between syncs. There is no webhook or polling mechanism for incremental updates.


7. PHASMA Mission Context

The PHASMA mission consists of two CubeSats built by Libre Space Foundation:

  • PHASMA-LAMARR (NORAD 66673) -- Default tracked satellite in the TALOS public tracker
  • PHASMA-DIRAC (NORAD 66681) -- Second quick-select option

These are the primary operational targets for TALOS, which explains why the public tracker defaults to PHASMA-LAMARR rather than ISS.

How PHASMA Benefits from TALOS + SatNOGS Integration

Multi-station pass coverage: PHASMA CubeSats in LEO have short pass windows (typically 5-12 minutes). TALOS can coordinate multiple ground stations to track the same pass simultaneously, increasing total contact time through geographic diversity and enabling handoff tracking as the satellite moves between station footprints.

Centralized Doppler for command uplink: When commanding PHASMA satellites, precise Doppler correction is critical. TALOS computes Doppler centrally and pushes corrections to all stations, ensuring consistent frequency tracking across the fleet.

Transmitter metadata from SatNOGS DB: PHASMA transmitter frequencies, modes, and baud rates are maintained in SatNOGS DB. When a TALOS campaign is created for PHASMA-LAMARR or PHASMA-DIRAC, transmitter data is automatically fetched and linked to the campaign, providing operators with accurate frequency information.

TLE quality monitoring: The TLEManager tracks TLE age and warns at 24h and 72h thresholds. For active PHASMA operations, this alerts operators before orbital predictions degrade significantly.

Public visibility: The public tracker at /track?norad=66673 provides a zero-login satellite tracking page powered by SatNOGS TLEs, useful for outreach and public engagement around the PHASMA mission.

Current Gaps for PHASMA Operations

  • No telemetry decoding -- PHASMA telemetry frames received via SatNOGS Network stations cannot be correlated with TALOS tracking sessions
  • No IQ capture during TALOS-driven passes -- RF data from PHASMA passes is lost
  • No integration with PHASMA mission control systems beyond basic tracking

8. Recommendations

Priority 1: TLE Source Redundancy (Low effort, high resilience)

Add CelesTrak as a fallback TLE source in SatNOGSClient. When SatNOGS DB returns no data for a satellite, fall back to https://celestrak.org/NORAD/elements/gp.php?CATNR={norad_id}&FORMAT=TLE. This eliminates the single-point-of-failure on SatNOGS DB for orbital data.

Priority 2: Public Tracker TLE Caching (Low effort, reduces API load)

The public tracker's _fetch_tle_for_norad() bypasses the shared SatNOGSClient and uses raw httpx with no caching. Every 2-second frontend poll triggers a fresh API call. Refactor to use SatNOGSClient.get_tle() with its 15-minute cache, or add a simple in-memory cache to the async path.

Priority 3: Station Hardware Mutex (Medium effort, enables coexistence)

Implement a lock file or MQTT-based coordination protocol so talos-agent and satnogs-client can share station hardware without conflicts. This is the critical enabler for Phase 2 coexistence. Suggested approach: talos-agent writes a lock to /tmp/talos-station.lock when active; a wrapper script for satnogs-client checks this lock before starting observations.

Priority 4: Lightweight Waterfall Capture (Medium effort, high value)

Add optional IQ recording to talos-agent during active tracking passes using SoapySDR. Post-process with a simple FFT pipeline (numpy/scipy, no GNU Radio) to generate waterfall PNGs. This produces the first TALOS data products without the heavyweight gr-satnogs dependency.

Priority 5: SatNOGS Observation Submission (Medium effort, community value)

Build an upload pipeline to submit TALOS-generated waterfalls and metadata to SatNOGS Network via POST /api/observations/. This requires a SatNOGS Network API token per station and proper observation metadata formatting. Every TALOS pass would then contribute to the global open dataset.

Priority 6: Idle-Time SatNOGS Job Acceptance (High effort, full integration)

When no TALOS campaign is active, poll GET /api/jobs/?ground_station={id} for pending SatNOGS observations and execute them. This makes TALOS stations useful contributors to the SatNOGS network during idle periods and maximizes station utilization.

Design Principles

  1. Never duplicate SatNOGS DB. It is the authoritative satellite catalog. Always consume, never fork.
  2. Contribute data back. Every TALOS observation should eventually produce data that flows to the open commons.
  3. Coexist, do not compete. Stations should serve both TALOS and SatNOGS without conflict.
  4. Keep the agent lightweight. Run satnogs-client alongside talos-agent rather than reimplementing GNU Radio integration.
  5. TALOS adds the real-time layer. SatNOGS is batch-oriented; TALOS is real-time. These are complementary, not competing.

Data Model Reference

SatelliteCache (PostgreSQL)

Column Type Notes
sat_id str (PK) SatNOGS satellite identifier
name str (indexed) Satellite display name
norad_id int (indexed) NORAD catalog number
status str SatNOGS status (alive, re-entered, etc.)
updated_at datetime Last sync timestamp

Transmitter (PostgreSQL)

Column Type Notes
id int (PK) Auto-increment
campaign_id int (FK, nullable) Link to Campaign
uuid str (indexed) SatNOGS transmitter UUID
description str Transmitter description from SatNOGS
type str Transmitter/Transceiver/Transponder
uplink_low/high BigInteger Uplink frequency range (Hz)
downlink_low/high BigInteger Downlink frequency range (Hz)
mode str Modulation mode (FM, BPSK, etc.)
baud float Baud rate
status str Active/inactive from SatNOGS

Campaign (PostgreSQL)

Column Type Notes
satnogs_id str (indexed, nullable) SatNOGS satellite ID for TLE resolution
norad_id int NORAD catalog number
transmitter_uuid str (nullable) Selected transmitter for operations