CLI · commit 194c050

satpass

Satellite pass predictor with SGP4

Download satpass.zip
Quickstart
unzip satpass.zip && cd satpass
uv venv .venv && uv pip install -p .venv/bin/python -e '.[dev]'
.venv/bin/python -m pytest -q

satpass

satpass tells you when the ISS, Tiangong, Hubble, Starlink trains and the brightest rocket bodies will pass over your location, and whether you will be able to see them: the satellite has to be sunlit while your sky is dark. It works entirely offline from two-line element sets, using an SGP4/SDP4 propagator written from scratch after Vallado et al. (2006). That propagator matches the official reference vectors to better than a millimetre. The output can be a pass table, a live position readout, CSV tracks, SVG sky plots and ground-track maps, a "what's up tonight" list, or an iCalendar feed.

CSS pass sky plot

Features

Install

cd satpass
uv venv .venv && uv pip install -p .venv/bin/python -e '.[dev]'
# or: python3.12 -m venv .venv && .venv/bin/pip install -e '.[dev]'

The only runtime dependency is click. pytest and sgp4 are needed only for the test suite; sgp4 serves as the test oracle.

Quickstart

# 1. Tell satpass where you are (written to ~/.config/satpass/config.toml)
satpass config init --lat 12.9141 --lon 74.856 --elev 22 --tz Asia/Kolkata --name Mangaluru

# 2. Optional: fetch fresh elements (otherwise the bundled samples are used)
satpass tle update --group visual --group stations

# 3. Ask
satpass passes ISS --days 5 --min-el 10 --visible-only
satpass flyover-list --tonight

Every example below runs offline against the bundled TLEs and examples/config.toml, with a fixed --start so you get the same output:

alias sp="satpass --config examples/config.toml"

Usage

passes: upcoming passes of one satellite

$ satpass passes CSS --start 2026-10-16T00:00 --days 5 --min-el 10 --visible-only
note: using bundled sample TLEs; run `satpass tle update` for fresh data
CSS (TIANHE) [48274] passes over Mangaluru (12.9141, 74.8560, 22 m) · times in Asia/Kolkata
window 2026-10-16 00:00 + 5 d, min elevation 10°, visible only
 #  Date        AOS       Az    Culmination  El   Az    LOS       Az    Mag   Visible window
 1  2026-10-16  19:35:07  SSW   19:40:12      35°  SE    19:45:17  ENE  -0.7  19:35:07-19:38:26
 2  2026-10-17  05:23:54  NW    05:28:59      36°  NE    05:34:04  ESE  -1.9  05:26:26-05:34:04
 3  2026-10-17  18:36:17  SSW   18:40:49      14°  SE    18:45:21  ENE  -1.6  18:36:17-18:42:32
 4  2026-10-17  20:12:30  WSW   20:17:30      27°  NW    20:22:30  NE    2.1  20:12:30-20:14:48
 5  2026-10-18  04:24:48  NNW   04:29:27      16°  NE    04:34:06  E     1.1  04:30:28-04:34:06
 6  2026-10-18  19:12:46  SW    19:17:59      75°  NW    19:23:12  NE   -3.4  19:12:46-19:18:49
 7  2026-10-19  05:01:34  NW    05:06:46      74°  SW    05:11:58  SE   -3.6  05:06:46-05:11:58
 8  2026-10-19  19:50:56  W     19:55:20      12°  NW    19:59:44  NNE   0.7  19:50:56-19:54:59
 9  2026-10-20  04:02:07  NW    04:07:14      37°  NE    04:12:19  ESE   2.4  04:10:46-04:12:19
10  2026-10-20  05:39:40  W     05:43:51      10°  SW    05:48:04  S    -1.3  05:43:01-05:48:04
11  2026-10-20  18:50:41  WSW   18:55:39      26°  NW    19:00:38  NNE  -1.4  18:50:41-18:58:47

Options:

now: where is it right now?

$ satpass now ISS --at 2026-10-16T14:19:20
ISS (ZARYA) [25544] at 2026-10-16 14:19:20 IST
  azimuth        235.35° (SW)
  elevation       66.11°
  range           457.7 km   range-rate -0.079 km/s
  sub-point      12.018° lat    73.542° lon
  altitude        421.0 km
  velocity        7.660 km/s (inertial)
  illumination sunlit (lit fraction 1.00)
  sun altitude    52.41° (day)
  magnitude    2.4
  TLE epoch    2026-10-15 19:43:34 UTC (+0.55 d)

track: CSV time series

$ satpass track ISS --start 2026-10-16T14:15 --duration 2m --step 30s
time_utc,az_deg,el_deg,range_km,range_rate_km_s,lat_deg,lon_deg,alt_km,sunlit,sun_alt_deg,magnitude
2026-10-16T08:45:00Z,318.166,4.526,1908.813,-6.8542,24.7561,63.0042,423.067,1,53.28,-0.15
2026-10-16T08:45:30Z,317.481,7.032,1703.714,-6.8157,23.3279,64.3172,422.766,1,53.18,-0.31
2026-10-16T08:46:00Z,316.584,9.964,1500.128,-6.7514,21.8865,65.5998,422.479,1,53.08,-0.48
2026-10-16T08:46:30Z,315.367,13.513,1299.036,-6.6459,20.4330,66.8544,422.207,1,52.98,-0.66
2026-10-16T08:47:00Z,313.632,17.994,1102.077,-6.4690,18.9685,68.0832,421.950,1,52.88,-0.83

--duration and --step accept s, m, h and d suffixes. -o file.csv writes the table to a file.

skyplot: polar plot of one pass

$ satpass skyplot CSS --pass 1 --start 2026-10-16T00:00 --visible-only -o docs/img/css-pass.svg
wrote docs/img/css-pass.svg: CSS (TIANHE) pass 1, 2026-10-16 19:35:07 max 34.7°

The pass number refers to the same list passes prints with the same options. In the plot, the zenith is at the centre and the horizon is the outer ring. The path is drawn:

Each minute is marked with a tick.

groundtrack: map of the sub-satellite path

$ satpass groundtrack ISS --orbits 3 --start 2026-10-16T18:00 -o docs/img/iss-track.svg
wrote docs/img/iss-track.svg: ISS (ZARYA), 3 orbits (279 min)

ISS ground track

The map uses an equirectangular projection with embedded Natural Earth 1:110m coastlines (public domain, simplified to 0.1°). The track is solid where the satellite is sunlit and dashed where it is in shadow. The track is split cleanly where it crosses the antimeridian.

flyover-list: everything bright tonight

$ satpass flyover-list --group visual --tonight --start 2026-10-16T12:00
Bright passes (bundled:visual, 155 satellites) over Mangaluru (12.9141, 74.8560, 22 m) · times in Asia/Kolkata
2026-10-16 18:32 -> 2026-10-17 05:59, min el 20°, mag <= 3.5
Start     End       Mag   VisEl  Dir          Satellite
18:32:40  18:41:37    1.9    79°    S -> N     COSMOS 1953 [19210]
18:33:25  18:43:45    2.7    31°  NNW -> SE    SPACEMOBILE-006 [67232]
18:36:21  18:44:34    1.6    29°  SSE -> N     CZ-2C R/B [54039]
18:37:16  18:50:14    3.4    69°    N -> SSW   SAOCOM 1A [43641]
19:33:24  19:39:35    2.2    72°   SW -> ENE   XRISM [57800]
19:35:07  19:38:26   -0.7    18°  SSW -> ENE   CSS (TIANHE) [48274]
05:02:44  05:15:44    2.5    45°  SSW -> N     SL-14 R/B [17912]
...
05:44:57  05:53:38    3.4    24°  WNW -> SE    XRISM [57800]

ical: subscribe in your calendar

$ satpass ical CSS --start 2026-10-16T00:00 --days 14 -o css.ics
wrote css.ics: 13 events
BEGIN:VEVENT
UID:48274-20261016T141012Z@satpass
DTSTART:20261016T140507Z
DTEND:20261016T140826Z
SUMMARY:CSS (TIANHE) pass\, max 35° SE\, mag -0.7
DESCRIPTION:AOS 14:05:07 UTC az 213° (SSW)\nMax 14:10:12 UTC el 34.7° az
 136°\nLOS 14:15:17 UTC az 59° (ENE)\nVisible to the naked eye during thi
 s event.

Events cover the visible window. By default only visible passes are exported; add --all-passes to include every pass above --min-el. Lines are folded to 75 octets as RFC 5545 requires.

tle: element sets

$ satpass tle update --group visual
visual: 155 element sets downloaded to /home/you/.cache/satpass/visual.tle
$ satpass tle update --group visual
visual: 155 element sets fresh in /home/you/.cache/satpass/visual.tle
$ satpass --tle examples/geo.tle tle info GSAT-30
GSAT-30  NORAD 45026  COSPAR 20005A
1 45026U 20005A   26288.95331432 -.00000164  00000+0  00000+0 0  9990
2 45026   0.0126 241.5401 0002275 287.4500 281.7263  1.00273494 24710
epoch        2026-10-15 22:52:46.357248 UTC
inclination  0.0126°   RAAN 241.5401°
eccentricity 0.0002275   arg perigee 287.4500°
mean motion  1.00273494 rev/day  (period 1436.07 min)
B*           0.00000e+00
model        deep-space (SDP4)

Configuration

The location file is TOML (see examples/config.toml):

[observer]
name = "Mangaluru"
lat = 12.9141      # degrees, north positive
lon = 74.856       # degrees, east positive
elev = 22.0        # metres above the WGS-84 ellipsoid
tz = "Asia/Kolkata"  # IANA zone used for displayed times

Lookup order:

  1. --config PATH
  2. $SATPASS_CONFIG
  3. $XDG_CONFIG_HOME/satpass/config.toml (normally ~/.config/satpass/config.toml)

--lat/--lon/--elev/--tz override the file, or replace it if you give both lat and lon.

Where TLEs are read from:

  1. --tle FILE, which uses only that file.
  2. The download cache $SATPASS_CACHE_DIR, otherwise ~/.cache/satpass/*.tle.
  3. The bundled samples.

When several sets share a NORAD id, the one with the newest epoch wins.

Global options such as --config, --tle and --lat go before the subcommand: satpass --tle my.tle passes ISS.

Bundled sample TLEs

These were downloaded from CelesTrak on 2026-10-16 and are copied in examples/ and in the package:

File Sets Epochs (UTC)
visual.tle 155 2026-10-13 18:28 → 2026-10-16 07:57
stations.tle 17 2026-10-15 07:27 → 2026-10-16 07:57
starlink.tle 10 2026-10-15 12:54 → 2026-10-16 06:17
geo.tle 9 (GSAT/INSAT/TDRS/GOES/…) 2026-10-15 14:09 → 2026-10-16 05:25

They are good for predictions within about a week of those dates.

Architecture

Module Role
tle.py TLE parsing, checksum, epoch → datetime/JD, lazy propagator
sgp4.py SGP4 initialisation and propagation (near-Earth core)
deepspace.py SDP4 resonance setup (dsinit) and integrator (dspace)
lunisolar.py Lunar-solar coefficients (dscom) and periodics (dpper, Lyddane)
constants.py WGS-72 constants
frames.py GMST, TEME↔ECEF, WGS-84 geodetic, SEZ look angles, Observer
sun.py Sun ephemeris, conical/cylindrical shadow, phase angle, twilight
magnitude.py Standard magnitudes and diffuse-sphere brightness
rootfind.py Brent root finder and Brent maximiser
passes.py observe(), pass search, visibility windows, dark interval
svg.py Sky plot and ground-track renderers
ical.py RFC 5545 export
catalog.py Bundled/cached sources, CelesTrak download, name lookup, age warnings
config.py TOML location config
cli.py, cli_admin.py, clictx.py Click commands

docs/algorithms.md explains the maths with worked examples:

Tests

.venv/bin/pytest -q

The suite has 112 tests:

Limitations