Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Astrophotography Tab

The Astrophotography tab is the central planning dashboard. It consolidates every piece of data an astrophotographer needs to decide whether to observe tonight and what to expect.


Tab layout

Sub-tabContent
Astro weatherSummary conditions card + best imaging window
WindowDetailed best-window breakdown (3 modes)
MoonLunar phase, position, 7-night planner, monthly phase calendar
SunSolar times, twilight windows, next eclipse
AuroraKp index, geomagnetic forecast, visibility assessment
CalendarUpcoming celestial events (planetary, meteor showers, phenomena)

Best imaging window

Module: backend/astroweather/moon_astrotonight.py

Class: AstroTonightService

Cache TTL: 3 hours (CACHE_TTL_BEST_WINDOW).

The best imaging window is the longest continuous block of time where the sky is astronomically dark and moonlight is minimal, according to three selectable modes.

What “astronomical night” means

Astronomical night begins when the Sun’s altitude drops below −18° (astronomical dusk) and ends at −18° on the way back up (astronomical dawn). Only during this window can faint deep-sky objects be properly imaged.

Twilight typeSun altitudeNotes
Civil twilight0° to −6°Sky still blue
Nautical twilight−6° to −12°Horizon visible at sea
Astronomical twilight−12° to −18°Sky not yet fully dark
True astronomical night< −18°Required for deep-sky imaging

The three window modes

ModeMoon constraintUse case
strictMoon must be below the horizonMaximum darkness; works well near full moon
practicalMoon altitude < 5°30-min margin for moonrise/moonset
illuminationMoon illumination < 15%New moon neighbourhood; moon may be above horizon but is dim

All three modes use Sun < −18° as the primary constraint. The API returns all three simultaneously - the UI shows the one that gives the longest usable window.

Score

The window score (0-100) reflects how good the dark window is:

  • 100: No moon interference during full astronomical night.
  • 0: No dark window exists (full moon, high latitude in summer, polar day).

API endpoint

GET /api/tonight/best-window returns:

{
  "best_window": {
    "strict": { "start": "22:15", "end": "04:40", "duration_hours": 6.4, "score": 100 },
    "practical": { "start": "22:15", "end": "04:40", "duration_hours": 6.4, "score": 100 },
    "illumination": { "start": "22:15", "end": "04:40", "duration_hours": 6.4, "score": 100 }
  }
}

Moon

Modules: backend/astroweather/moon_phases.py, backend/astroweather/moon_planner.py, backend/astroweather/moon_eclipse.py

Cache TTL: 2 hours (CACHE_TTL_MOON_REPORT).

Moon report (astroweather/moon_phases.py)

MoonService computes:

FieldDescription
phase_nameNamed phase (New Moon, Waxing Crescent, First Quarter…)
illumination_percentFraction of disk illuminated (0-100 %)
distance_kmGeocentric distance
altitude_deg / azimuth_degCurrent topocentric position
next_moonrise / next_moonsetNext rise and set times
next_full_moon / next_new_moonTimestamps of next phase extremes
next_dark_night_start/endNext window where Sun < −18° AND Moon below horizon

Libraries used: astronomy (Astronomy Engine) for rise/set and phase search; astropy for AltAz position.

Moon planner (astroweather/moon_planner.py)

7-night forecast table. For each night it computes moonrise, moonset, illumination, and whether there is a usable dark window. This lets astrophotographers pick the best night within the coming week.

API: GET /api/moon/next-7-nights

Lunar phase calendar (astroweather/moon_calendar.py)

Full calendar-month grid shown under “Moon next days”. For every day it computes the illuminated fraction and waxing/waning state from the Moon phase angle (astronomy.MoonPhase, the same formula as the Moon report, so the drawings match the main Moon visual), flags near-new-moon nights (illumination < 15%) as better deep-sky windows, and locates the month’s four principal phases with astronomy.SearchMoonQuarter / NextMoonQuarter, bucketed into local calendar days via the active location’s timezone. Navigation is restricted to a 2-month window: the current month and the next one.

Every day is sampled at the same fixed night hour (23:00 local) - the calendar is a night-observation planning aid, so each cell shows the Moon as it is when you would be out under it, and every cell is computed the same way. This can differ by a few percent from the live #moon-display widget during the day (that one is a “right now” readout); the two converge at night.

API: GET /api/moon/phase-calendar?year=<yyyy>&month=<1-12> - year / month are clamped to the allowed window; missing or malformed values fall back to the current month. The response also carries is_current_month, can_go_prev, can_go_next, today and principal_phases.

Lunar eclipse (astroweather/moon_eclipse.py)

LunarEclipseService finds the next lunar eclipse visible from the configured location.

FieldDescription
typeTotal, Partial, or Penumbral
peak_timeLocal time of maximum eclipse
partial_begin / total_begin / total_end / partial_endContact times
peak_altitude_degMoon altitude at peak (negative = below horizon = not visible)
total_duration_minutes / partial_duration_minutesDuration of each phase
astrophotography_score0-10 score for imaging value
altitude_vs_timeArray of alt/az at 5-min resolution for chart display

Astrophotography score factors in: eclipse type (total > partial > penumbral), altitude at peak, and total duration.

API: GET /api/moon/next-eclipse


Sun

Modules: backend/astroweather/sun_phases.py, backend/astroweather/sun_eclipse.py

Cache TTL: 6 hours (CACHE_TTL_SUN_REPORT).

Sun report (astroweather/sun_phases.py)

SunService computes for the current date at the configured location:

FieldDescription
sunrise / sunsetLocal times
civil_dusk / civil_dawnSun = −6°
nautical_dusk / nautical_dawnSun = −12°
astronomical_dusk / astronomical_dawnSun = −18°
true_night_hoursDuration of full astronomical night

Library: astropy - get_sun() + AltAz transforms over a dense time grid to find threshold crossings.

API: GET /api/sun/today

Solar eclipse (astroweather/sun_eclipse.py)

SolarEclipseService finds the next solar eclipse visible from the configured location.

FieldDescription
typeTotal, Annular, Partial, or Hybrid
maximum_timeLocal time of maximum coverage
obscuration_percentFraction of solar disk covered at maximum
altitude_degSun altitude at maximum
magnitudeEclipse magnitude (fraction of solar diameter covered by Moon)
duration_minutesDuration of partial phase
altitude_vs_timeAlt/az array for chart display

API: GET /api/sun/next-eclipse


Horizon graph

Module: backend/astroweather/horizon_graph.py

Cache TTL: 6 hours (CACHE_TTL_HORIZON_GRAPH).

The horizon graph displays the altitude vs. time curves for the Sun and Moon throughout the current day. This gives a quick visual of when targets are above the horizon and allows users to identify the dark window at a glance.

HorizonGraphService samples altitude and azimuth at 1-hour resolution using astropy’s get_sun() and get_body('moon') with AltAz transforms.

API: GET /api/astro/horizon-graph


Sidereal time

Module: backend/observation/sidereal_time.py

Cache TTL: 1 hour (CACHE_TTL_SIDEREAL_TIME).

Local Apparent Sidereal Time (LAST) is displayed as a quick reference. LAST equals the Right Ascension (RA) of objects currently on the meridian - useful when manually slewing to targets.

API: GET /api/astro/sidereal-time


Aurora

Module: backend/astroweather/aurora_predictions.py

Class: AuroraService

Cache TTL: 1 hour (CACHE_TTL_AURORA).

Data source: NOAA Space Weather Prediction Center

Kp index

The Kp index (0-9) is the primary indicator of global geomagnetic activity. Higher Kp = larger aurora oval extending further toward the equator.

KpActivity levelTypical aurora visibility
0-1QuietPolar regions only (> ~70° lat)
2-3UnsettledHigh latitudes (~65-70°)
4ActiveMid-high latitudes (~60-65°)
5Minor storm (G1)Visible ~55°
6Moderate storm (G2)Visible ~50°
7Strong storm (G3)Visible ~45°, sometimes ~40°
8-9Severe/ExtremeMid-latitude aurora possible

NOAA API: https://services.swpc.noaa.gov/products/noaa-planetary-k-index.json (current), noaa-planetary-k-index-forecast.json (3-day forecast).

Aurora visibility probability

AuroraService.calculate_aurora_probability() estimates aurora probability (0-100 %) from the current Kp and observer latitude:

aurora_edge_latitude = 67° - (Kp × 3.5°)
  • Observer poleward of the edge -> probability = 25% + Kp × 7 (max 88%)
  • Observer near the edge -> probability = 15% + Kp × 6
  • Observer 5° equatorward -> probability = 5% + Kp × 4
  • Observer far equatorward -> probability = max(0, (Kp − 3) × 6)

The latitude of 67° is an approximation of the mean auroral oval edge during quiet conditions; the factor of 3.5°/Kp unit is a well-known empirical rule of thumb.

Best aurora window

Auroras are most visible between 22:00 and 02:00 local time (midnight maximum). The service reports whether the current night has a suitable window given Kp and darkness.

API: GET /api/aurora/predictions


Celestial events

Three separate services feed the Calendar sub-tab.

Planetary events

Module: backend/observation/planetary_events.py

Class: PlanetaryEventsService

Cache TTL: 24 hours (CACHE_TTL_PLANETARY_EVENTS).

Covers all seven naked-eye planets (Mercury, Venus, Mars, Jupiter, Saturn, Uranus, Neptune).

Event typeDescriptionWhich planets
OppositionPlanet is 180° from the Sun - closest approach, highest altitude at midnightOuter planets only (Mars and beyond)
ConjunctionPlanet appears very close to another planet or the SunAll
Greatest elongationMaximum angular distance from the Sun - best for inner planetsMercury (18°), Venus (46°)
Retrograde begin/endApparent backward motion as Earth overtakes an outer planetAll outer planets

Events are computed over a 365-day rolling window from today using astropy body positions.

API: GET /api/events/planetary

Special phenomena

Module: backend/observation/special_phenomena.py

Class: SpecialPhenomenaService

Cache TTL: 24 hours (CACHE_TTL_SPECIAL_PHENOMENA).

EventDescription
Vernal equinoxSun crosses the celestial equator northward (≈ March 20)
Summer solsticeLongest day in the northern hemisphere (≈ June 21)
Autumnal equinoxSun crosses the celestial equator southward (≈ September 22)
Winter solsticeShortest day (≈ December 21)
Zodiacal light windowBest period to see the faint dust band in the ecliptic (western sky after dusk in spring, eastern sky before dawn in autumn)
Milky Way core visibilityPeriod when the galactic centre (Sagittarius) rises and sets in darkness

Library: astropy - get_sun() position for equinox/solstice crossing detection; SkyCoord for galactic-plane altitudes.

API: GET /api/events/phenomena

Solar system events (meteor showers)

Module: backend/observation/solar_system_events.py

Class: SolarSystemEventsService

Cache TTL: 24 hours (CACHE_TTL_SOLAR_SYSTEM_EVENTS).

Contains a curated database of annual meteor showers with:

FieldDescription
nameShower name
peak_dateDate of peak activity
zenith_hourly_rateZHR at peak
parent_bodyComet or asteroid producing the shower
radiant_ra / radiant_decRadiant position
radiant_altitudeRadiant altitude at peak local midnight from configured location
hemispherenorth, south, or both

Major showers included: Quadrantids, Lyrids, Eta Aquariids, Delta Aquariids, Perseids, Orionids, Leonids, Geminids, Ursids.

Radiant altitude is computed using astropy AltAz transforms - a shower with a radiant below the horizon is flagged as not visible from the configured location.

API: GET /api/events/solarsystem

Upcoming events aggregator

Module: backend/utils/events_aggregator.py

GET /api/events/upcoming merges all three event sources and returns a single sorted list of events in the coming days/weeks - used for the Calendar sub-tab and for push notification triggers N4 and N5.


Push notification triggers

Two astrophotography events feed the push notification system (see NOTIFICATIONS.md):

TriggerEventDefault lead
N4Lunar eclipse totality begins30 min
N5Solar eclipse maximum30 min
N6Astronomical darkness begins20 min

Last updated 2026-11-13