Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/ManiFed/TTN/llms.txt

Use this file to discover all available pages before exploring further.

The Telescope Net turns a donated Seestar telescope into a node in a worldwide scientific instrument — automatically, every clear night, without any action from the member. This page traces the complete journey of a single observation: from the moment an alert arrives in the cloud to the moment a calibrated magnitude lands in the AAVSO database under the contributing member’s name.

Member Experience

After the initial setup (approximately 15 minutes), members never need to interact with the system for it to produce science. The Node Agent handles everything: waking the telescope at twilight, following the night’s observation plan, running photometry on each image, uploading measurements to the cloud, and parking the telescope at dawn. Members receive a morning notification summarising what was observed, what was accepted, and confirming any AAVSO submissions. Their name is on every record. One-time setup steps:
  1. Download the Node Agent installer for your operating system (Windows, macOS, or Linux)
  2. Create a member account and request a Node Activation Code (BS-YYYY-XXXXXXXX)
  3. Enable Station Mode on your Seestar so it connects to your home Wi-Fi
  4. Run the installer — it prompts for the activation code, configures sleep prevention, and installs as a system service
  5. The Node Agent starts, finds the Seestar via ALPACA autodiscovery, registers with the cloud, and is live
From that point on, the member does nothing. The network does the science.

Architecture Overview

The system is composed of two major runtime environments — the Node Agent running on the member’s local computer, and the cloud server running on a VPS — connected by a REST API.
src/dashboard.py (Flask, port 5173)

  ├─ API endpoints (telescope, camera, schedule, photometry, config, logs, …)

  ├─ SafetyManager (daemon thread)
  │   heartbeat monitor, reconnect, dawn parking, horizon mask, SIGTERM handler

  ├─ ImageWatcher (daemon thread, when enabled)
  │   OS filesystem events → debounce → photometry pipeline

  ├─ Photometry pipeline (photometry.py)
  │   WCS → comp stars → aperture phot → differential → AAVSO submission

  ├─ CloudCommunicator (daemon threads, when cloud.enabled)
  │   auto-register → heartbeats → plan polling → measurement upload (retry queue)

  └─ DeviceManager → AlpacaClient (HTTP/JSON)
       Telescope, Camera, Focuser, FilterWheel

cloud/ (Flask, port 8800)

  ├─ Background loops
  │   alert-ingest → scoring → (optionally) replan  every 60 min
  │   replan                                         every 120 min
  │   aavso-batch                                    every 360 min
  │   weight-tuning (Claude advisory monitor)        daily
  │   maintenance (image pruning, night summaries,   daily
  │                performance refresh, LP refresh)

  ├─ nodes table — the AI scheduler's view of each telescope
  │   location → observability windows, airmass, moon
  │   hardware → what the scope can see and how long it can expose
  │   autonomy → likelihood of completing a night unattended
  │   performance → what it has actually delivered to AAVSO
  │   reliability_score → multiplier on every (target, node) score pair

  └─ tuning_state + weight_history tables (when tuning enabled)
      active observability sub-weights, audit trail of all changes

The Nightly Flow

Each observing night follows the same sequence, executed entirely by software.
1

Twilight Wakeup

The Node Agent’s SafetyManager monitors the Sun’s altitude continuously. At astronomical twilight (Sun below −18°), the agent wakes, connects to the Seestar via ALPACA, and begins the night sequence.
2

Plan Download

The CloudCommunicator polls GET /api/v1/plan to retrieve tonight’s observation plan — an ordered list of targets with RA/Dec, exposure duration, exposure count, and scheduled start time. Plans are regenerated by the cloud every 120 minutes, so late-breaking alerts can appear mid-night.
3

ALPACA Telescope Control

For each plan item, the Node Agent instructs the Seestar via the ALPACA REST protocol: slew to coordinates, expose for the specified duration and count, and save images to the local SMB share. The ASTAP plate solver verifies pointing and closes the loop if needed.
4

Image Retrieval from SMB Share

The ImageWatcher monitors the Seestar’s SMB network share using OS-native filesystem events (FSEvents on macOS, inotify on Linux, ReadDirectoryChangesW on Windows). New FITS files trigger the photometry pipeline after a brief debounce delay.
5

On-Node Photometry

The photometry pipeline runs locally on each new FITS file — see Photometry Pipeline below for the full step sequence. The result is a small measurement dict (~1 KB) containing the calibrated magnitude, uncertainty, filter, airmass, SNR, and a quality flag.
6

Upload to Cloud

Measurements are posted to POST /api/v1/measurements via the CloudCommunicator’s retry queue. Raw FITS files are also optionally uploaded to POST /api/v1/images and retained for 14 days. Heartbeat calls to POST /api/v1/nodes/heartbeat keep the node’s status current every 60 seconds.
7

Cross-Validation

The cloud’s data_pipeline.py ingests measurements from all nodes. Measurements of the same target on the same night are compared across nodes. Outliers — readings that disagree with the network consensus beyond the expected scatter — are flagged rather than submitted. This cross-validation step is the primary quality gate that prevents a single malfunctioning node from polluting the AAVSO record.
8

AAVSO Batch Submission

Every six hours, the cloud batches all measurements that have passed quality gates and posts them to the AAVSO WebObs API in Extended File Format. Each record carries the contributing member’s observer code, making their contribution permanent and citable in the AAVSO database.
9

Morning Notification

After dawn parking, the nightly maintenance loop generates a night summary for each active node and dispatches push notifications via Firebase. Members see which targets were observed, how many measurements were accepted, and confirmation of any AAVSO submissions made overnight.

Data Pipeline Layers

The cloud processes data through seven distinct layers, from raw alert stream to AAVSO submission.
LayerFunctionImplementation
1 — Alert IngestionPull candidate targets from public astronomical streamsALeRCE, ATLAS, ASAS-SN, AAVSO, Gaia, TNS polled hourly
2 — ScoringRank every (target, node) pair with a composite scoreWeighted sum of six components: brightness match, scientific value, time criticality, coverage gap, observability, and science ROI
3 — SchedulingGenerate nightly observation plansCHORUS nightly greedy dispatch with real-time interrupt handling
4 — Node ControlOperate the telescope hardwareALPACA REST API via seestar_alp; SMB image retrieval
5 — Local PhotometryCalibrate magnitudes from raw FITSASTAP plate solve → comparison stars → aperture photometry → differential
6 — Cloud ValidationEnsure measurement quality and cross-node consistencySNR/uncertainty/airmass gates, cross-node agreement, light curve management
7 — SubmissionDeliver data to professional databasesAAVSO WebObs API (batched every 6 hours); TNS reporting for significant detections

Photometry Pipeline

The photometry pipeline runs on the node machine for every new FITS file. It is fully offline — no internet connection is required during image processing.
FITS file
  → 1. Ensure WCS         (check header; run ASTAP plate solve if absent)
  → 2. Locate target      (world_to_pixel; reject if too close to edge)
  → 3. Estimate FWHM      (DAOStarFinder + second-moment Gaussian stamps)
  → 4. Comparison stars   (AAVSO VSP API → Gaia DR3 fallback; merge, deduplicate)
  → 5. Aperture photometry (CircularAperture + sigma-clipped annulus background)
  → 6. Differential photometry (weighted zero-point ensemble; Poisson + ZP scatter)
  → 7. Ancillary data     (BJD_TCB via astropy, airmass from Alt/Az or header)
  → 8. Quality flag       (good / acceptable / poor based on SNR, uncertainty, comp stars)
  → result dict
A successful pipeline run produces the following measurement dict, which is uploaded to the cloud and (if it passes quality gates) eventually submitted to AAVSO:
{
    "target_name":      "SS Cyg",
    "bjd":              2460500.123456,
    "magnitude":        12.341,
    "uncertainty":      0.031,
    "filter":           "CV",
    "airmass":          1.24,
    "fwhm":             3.8,
    "snr":              52.0,
    "comparison_stars": 9,
    "quality_flag":     "good",
    "node_id":          "node_001",
    "zero_point":       22.413,
    "zp_scatter":       0.028,
    "fits_file":        "seestar_image.fits",
}
The quality_flag field has three possible values. good measurements are submitted to AAVSO without further review. acceptable measurements are submitted but noted. poor measurements are retained in the database for diagnostics but are never submitted to AAVSO unless submit_poor_quality: true is set in config.yaml (not recommended).

Background Cloud Loops

The cloud server runs five recurring background tasks that keep the network operating without manual intervention.
Runs alerts.ingest_all() to pull fresh candidates from all configured alert streams (ALeRCE, ATLAS, ASAS-SN, AAVSO, Gaia, TNS), cross-match against existing targets within a 3 arcsecond radius, upsert new records, and immediately trigger scoring.score_all() so new targets appear in plans at the next replan window.

Interrupt Handling

High-priority targets — for example, a nova suddenly brightening by three magnitudes — can be pushed to nodes as interrupts between plan cycles. Nodes poll GET /api/v1/interrupts on each heartbeat cycle. When an interrupt is received, the Node Agent can preempt the current plan item and slew to the new target immediately, typically achieving a response time under one hour from alert to first measurement.
Interrupt handling requires cloud.auto_run_plans: true in the node’s config.yaml. Nodes with this setting disabled will still receive interrupts in the API response, but they will not act on them automatically.

Build docs developers (and LLMs) love