Scheduling Syntax#

banner

Astra uses a schedule to operate the observatory automatically. A schedule is a JSONL file (JSON Lines format). Each line of the file is one JSON object, and each object is one action. An action has these fields:

  • device_name: The name of the camera. The camera tells Astra which other devices the action uses through its configured paired devices.

  • action_type: The type of the action.

  • action_value: The parameters of the action.

  • start_time: The first time at which the action can start. Use the UTC ISO format YYYY-MM-DD HH:MM:SS.sss.

  • end_time: The last time at which the action can run. Use the UTC ISO format YYYY-MM-DD HH:MM:SS.sss.

Instrument-Centric Design

Each action gives a camera as the device_name. The camera does not control the other devices. It tells Astra which devices the action uses. The observatory configuration gives the paired_devices of each camera: the telescope, the dome, the filter wheel and the focuser. Astra operates these devices together for the action.

Timing and Execution Flow

The start_time and end_time fields give the window in which the action is valid. They do not give a fixed duration.

  • Early completion: If an action is completed correctly before its end_time, Astra does not wait. It starts the next action immediately. If the next action cannot start before its start_time, Astra waits until that time.

  • Order: Astra does the actions in sequence, in the order of their start times. The next action does not start until the current action is completed. This is also true when the start_time of the next action is in the past. To let actions run at the same time, set execute_parallel to true.

Example Schedule#

// open observatory
{
   "device_name":"camera_main",
   "action_type":"open",
   "action_value":{},
   "start_time":"2025-08-23 22:38:25.210",
   "end_time":"2025-08-24 10:49:15.363"
}
// dusk sky flats
{
   "device_name":"camera_main",
   "action_type":"flats",
   "action_value":{"filter":["r'", "g'"],"n":[20, 20]},
   "start_time":"2025-08-23 22:39:25.210",
   "end_time":"2025-08-23 23:16:00.018"
}
// science observations
{
   "device_name":"camera_main",
   "action_type":"object",
   "action_value":{"object":"Kepler-1","filter":"r'","ra":286.808542,"dec":49.316422,"exptime":8,"guiding":true,"pointing":true},
   "start_time":"2025-08-23 23:17:00.018",
   "end_time":"2025-08-24 04:43:40.018"
}
// dawn sky flats
{
   "device_name":"camera_main",
   "action_type":"flats",
   "action_value":{"filter":["r'", "g'"],"n":[20, 20]},
   "start_time":"2025-08-24 10:24:40.018",
   "end_time":"2025-08-24 10:49:15.363"
}
// close observatory
{
   "device_name":"camera_main",
   "action_type":"close",
   "action_value":{},
   "start_time":"2025-08-24 10:49:15.363",
   "end_time":"2025-08-24 11:49:15.363"
}
// calibration frames, biases and darks
{
   "device_name":"camera_main",
   "action_type":"calibration",
   "action_value":{"exptime":[0,10,15,30,38,60,120],"n":[10,10,10,10,10,10,10]},
   "start_time":"2025-08-24 10:55:15.363",
   "end_time":"2025-08-24 11:49:15.363"
}

JSONL Comments

In a JSONL file, a line that starts with // is a comment. Astra ignores it.

Schedule File Location#

Put the schedule file in the schedules directory of the observatory. The file must have the extension .jsonl. For example:

  • ~/Documents/Astra/schedules/{observatory_name}.jsonl

Astra finds a file with this name and loads it. If you change the file, Astra loads it again.

Supported Action Types#

Astra has these action types:

  • open: Open the observatory.

  • close: Close the observatory.

  • cool_camera: Start the camera cooling.

  • object: Record light frames. Pointing correction and autoguiding are optional.

  • calibration: Record dark frames and bias frames.

  • flats: Record sky flat frames.

  • autofocus: Focus the telescope.

  • calibrate_guiding: Calibrate the guiding parameters.

  • pointing_model: Collect data for a telescope pointing model.

  • complete_headers: Complete the FITS headers of all the images.

Note

Astra runs the complete_headers action at the end of each schedule. This makes sure that all the FITS files have the full metadata.

Note

Each action runs cool_camera first. This makes sure that the camera is at the correct temperature before an exposure starts. The open and close actions run cool_camera after they are completed.

Tracking Moving Targets#

Solar system bodies and artificial satellites move against the background stars. You can see this movement in one exposure. To correct for it, Astra commands differential tracking rates in right ascension and declination.

To observe such a target, give a lookup_name in the object action. Give the name alone, because Astra points the mount from the ephemeris of the target. A fixed position cannot describe a moving target. If you also give ra and dec, or alt and az, Astra rejects the schedule. Astra rejects a tle with one of these pairs in the same way.

Astra finds the position for lookup_name when it loads the schedule. The source of the position sets the type of tracking:

Source of the position

Example

Tracking

Astropy’s built-in ephemeris

"mars", "moon"

Non-sidereal

JPL Horizons small-body search

"C/2023 A3", "Ceres"

Non-sidereal

A two-line element set that you give, with lookup_name set to "TLE"

The ISS

Non-sidereal

SIMBAD (stars and deep-sky objects)

"M31", "Vega"

Sidereal

Sequence of operations#

  1. Pointing. The mount slews to the calculated position of the target at start_time. A planet or a comet moves less than one arcsecond during a normal slew. Thus the mount points at it correctly. A satellite moves much more quickly. For example, the ISS moves about 20 degrees in 30 seconds. The mount cannot slew directly to a target that moves this quickly.

    For a satellite, set nonsidereal_start_lead_time_seconds. Make it equal to or more than the slew time and the settling time of the mount. The mount then slews to the position of the target at start_time plus this number of seconds. The mount waits there for the target.

    The exposures can start later than planned. The target can then be more than one arcminute from the position of the mount. If this occurs, Astra re-centers the mount before the exposures start. This limit is an angle, not a time. Thus the delay that is possible changes with the speed of the target. For Mars, the delay must be about 45 minutes before a re-center is necessary. For the ISS, a delay of a few milliseconds is enough.

  2. Tracking. Astra applies the differential rates and refreshes them during the full sequence. This includes the exposures and the time when Astra writes each frame to the disk. The re-center interval starts when Astra applies the rates for the first time.

  3. Re-centering. At each interval of nonsidereal_recenter_interval seconds, the mount slews to the current ephemeris position of the target. If you set the interval to zero, the mount does not do these slews. Only the rates then keep the target in the field. This does not stop non-sidereal tracking.

  4. Reset. Astra sets the rates to zero when the sequence ends, and also when an error occurs. Astra sets the rates to zero before each slew. So a sequence that stopped incorrectly cannot leave old rates on the mount.

Why periodic re-centering is necessary#

Differential rates are an open-loop control of speed. They tell the mount how quickly to move, but not where to point. So they remove the apparent movement of the target. They do not correct a position error that already occurred.

Astra stops autoguiding during non-sidereal tracking. So re-centering is the only feedback of position. Without it, three errors increase continuously.

The first pointing error continues. The initial slew leaves an offset. The offset comes from the pointing model, from an old ephemeris, or from the movement of the target during the slew. The rates keep this offset.

Rate errors become position errors. No mount applies a commanded rate exactly, and the correct rate changes between the updates.

Astra does not correct mechanical defects. Periodic error, flexure and polar misalignment have the same effect during non-sidereal tracking as during sidereal tracking.

The interval is a balance between drift and dead time. Each re-center needs a slew and a settling time. If a fast target moves more than one arcsecond during the first slew, the mount does a second slew to correct this. For a comet or an asteroid, start with an interval of a few minutes. A target that moves more quickly needs a shorter interval.

Requirements and limitations#

  • The mount must have differential rates. It must report the ASCOM capabilities CanSetRightAscensionRate and CanSetDeclinationRate. If no telescope in the observatory reports the two capabilities, Astra rejects the schedule when it loads it.

  • Astra stops autoguiding. The guide stars move across the field when the mount tracks a moving target. So the guider operates against the tracking rates. If you set guiding to true for a moving target, Astra gives a warning and ignores the field.

  • Astra sends few rate commands. Some mounts stop the tracking for a short time when they receive a new rate. So Astra sends a rate only when the current rate causes the target to trail. It does not send a rate more frequently than nonsidereal_rate_update_interval seconds. The default value is 10 seconds. Decrease the value for a target whose rate changes quickly. Increase it for a mount that is sensitive to rate commands.

  • All positions are ICRS (J2000) before they go to the mount. The planet positions from Astropy, the Horizons positions and the SIMBAD positions are all astrometric ICRS. So they agree to better than one arcsecond. If the mount reports that it needs JNow coordinates, Astra converts each slew position to the apparent frame of the date. Refer to equatorial_system in the telescope configuration.

  • The ephemeris interval agrees with the movement of the target. One sample each minute gives the position of a planet to better than one arcsecond. In one minute, the ISS moves 30 degrees. Astra cannot interpolate an arc that it did not sample, and the error becomes some degrees. So Astra uses an interval of a few seconds for a satellite, and one minute for a planet, a comet or an asteroid. It then measures the speed of the target in the ephemeris and changes the interval if the first value was not correct. A very fast target in a long window gets to the maximum number of samples. Astra then gives a warning.

  • Minor bodies and TLEs need a network connection when the schedule loads. Astra sends a request to JPL Horizons when it reads the schedule. It calculates an ephemeris and interpolates it during the night. Usually one request is enough. Astra sends a second request only when the interval does not agree with the speed of the target. So a network failure during the observations has no effect. But a network failure when the schedule loads causes Astra to reject the schedule. Astra calculates the positions of the planets and the Moon with the built-in ephemeris of Astropy. These positions need no network.

The target must be above the horizon#

Astra does this check for each object action, for a moving target and for a fixed target. It calculates the altitude of the target every 30 seconds, from start_time to end_time. If the altitude at one of these times is less than 0 degrees, Astra rejects the schedule. For a moving target, Astra uses the ephemeris. So the altitude is the altitude of the body at each time. The error message gives the altitude at the start and at the end when these are below the limit. It also gives the number of times below the limit, the first of them, and the lowest altitude.

This is most important for a satellite. A satellite rises and sets more than one time in a long window. Its altitude at the start, at the middle and at the end tells you little about the other times. Make the window no longer than one pass.

Examples#

This action tracks Saturn. The mount re-centers every five minutes:

{
   "device_name":"camera_main",
   "action_type":"object",
   "action_value":{"object":"Saturn","lookup_name":"saturn","filter":"r'","exptime":30,"nonsidereal_recenter_interval":300},
   "start_time":"2025-08-23 23:17:00.018",
   "end_time":"2025-08-24 00:17:00.018"
}

This action tracks a satellite with its two-line element set. Set lookup_name to "TLE". Give the two element lines in tle, with a \n between them. The lead time gives the mount 45 seconds to move to the position of the satellite. The rate update interval is short because the rates of a low orbit change quickly:

{
   "device_name":"camera_main",
   "action_type":"object",
   "action_value":{"object":"ISS","lookup_name":"TLE","tle":"1 25544U 98067A   26084.45430866  .00012951  00000-0  24673-3 0  9999\n2 25544  51.6344 354.4276 0006215 231.1671 128.8763 15.48531543558777","filter":"Clear","exptime":2,"nonsidereal_recenter_interval":60,"nonsidereal_rate_update_interval":1,"nonsidereal_start_lead_time_seconds":45},
   "start_time":"2025-08-23 23:17:00.018",
   "end_time":"2025-08-23 23:27:00.018"
}

Warning

A two-line element set becomes less accurate quickly. If a set is more than a few days old, it cannot give the position of a satellite in low Earth orbit with enough accuracy. The satellite is then not on the detector.

Action Value Parameters#

Each action type needs its own parameters in the action_value field. Astra generates the sections that follow from the action configuration dataclasses. So the documentation always agrees with the software.

object#

Capture a sequence of light frames.

Workflow:
  1. Pre-sequence setup (pointing, filters, focus, binning, sub-framing, headers)
    • Observatory opens if not already done by a prior action if coordinates specified

  2. Capture exposures in succession

  3. Perform pointing correction if pointing=true

  4. Start autoguiding if guiding=true

  5. Stop exposures, guiding, and tracking at completion

Non-sidereal tracking:

Differential tracking is enabled implicitly: whenever lookup_name is given in place of a fixed ra/dec and resolves to a moving body, the sequence is tracked non-sidereally. Names resolved against Astropy’s built-in ephemeris (the planets, the Moon and the Sun) or against JPL Horizons (asteroids and comets) are treated as moving, while names resolved as stars or deep-sky objects are tracked sidereally. nonsidereal_recenter_interval governs only how often the mount re-slews once tracking is under way. Autoguiding is incompatible with non-sidereal tracking and is disabled automatically. For Earth-orbiting objects, supply tle and set lookup_name to “TLE”.

The mount must report the ASCOM capabilities CanSetRightAscensionRate and CanSetDeclinationRate. Where lookup_name resolves to a moving body and no telescope in the observatory reports both, the schedule is rejected as it is loaded rather than run sidereally.

Schedule example for tracking Saturn:

{
    "device_name": "camera_name",
    "action_type": "object",
    "action_value": {
        "object": "Saturn",
        "lookup_name": "saturn",
        "exptime": 30,
        "filter": "Clear",
        "nonsidereal_recenter_interval": 300,
    },
    "start_time":"2025-01-01 00:00:00.000",
    "end_time":"2025-01-01 01:00:00.000",
}

Minimal schedule example

{
    "device_name": "camera_name",
    "action_type": "object",
    "action_value": {
        "object": "M42",
        "exptime": 60.0,
        "ra": 83.82208,
        "dec": -5.39111,
        "filter": "V",
        "n": 3,
        "guiding": true,
        "pointing": true,
        "metadata": {
            "id": "47026",
            "requested_by_user": "[email protected]"
        }
    },
    "start_time": "2025-01-01 00:00:00.000",
    "end_time": "2025-02-01 00:00:00.000"
}

Action values

object: str Required — Target name.
exptime: float Required — Exposure time per frame in seconds.
ra: float | None = None — Right Ascension to slew to
dec: float | None = None — Declination to slew to
alt: float | None = None — Altitude coordinate when issuing Alt/Az pointings.
az: float | None = None — Azimuth coordinate when issuing Alt/Az pointings.
lookup_name: str | None = None — Instead of specifying ra/dec or alt/az, use SIMBAD/Astropy to look up coordinates for celestial body to observe (e.g., 'mars', 'M31').
tle: str | None = None — Two-line element set for an Earth-orbiting object, given as the two element lines separated by a newline. Set lookup_name to 'TLE' when this is supplied. Requires a mount that can set differential tracking rates.
filter: str | None = None — Filter name to load before imaging.
focus_shift: float | None = None — Focus offset relative to the stored best focus.
focus_position: float | None = None — Absolute focus position override.
n: int | None = None — Number of exposures in the sequence. If not specified, defaults to infinite exposures until end_time.
guiding: bool = false — Start autoguiding with Donuts before imaging. Should be False for solar system objects using non-sidereal tracking, as the star field drifts relative to the guide reference.
pointing: bool = false — Perform pointing correction with twirl before imaging.
bin: int = 1 — Camera binning factor.
dir: str | None = None — Base directory path for saving images.
execute_parallel: bool = false — Execute action in parallel mode when supported.
disable_telescope_movement: bool = false — Prevent any telescope motion during the sequence.
reset_guiding_reference: bool = true — Acquire a fresh guiding reference frame at the start.
subframe_width: int | None = None — Width of the requested subframe in binned pixels.
subframe_height: int | None = None — Height of the requested subframe in binned pixels.
subframe_center_x: float = 0.5 — Horizontal location of the subframe center (0=left, 1=right).
subframe_center_y: float = 0.5 — Vertical location of the subframe center (0=top, 1=bottom).
nonsidereal_recenter_interval: int = 0 — Interval in seconds at which the mount re-slews to the target's current ephemeris position, refreshing the tracking rates as it does so. Setting it to 0 suppresses the re-slews and leaves the differential rates to work alone, which does not disable non-sidereal tracking. Has no effect on fixed targets.
nonsidereal_start_lead_time_seconds: float = 0.0 — Lead time in seconds for the initial slew, for targets too fast to slew to directly. The mount is sent to the position the target will occupy at start_time plus this value, idles until that moment, and only then begins exposing. Set it to at least the slew and settling time. The default of 0 slews straight at the target, which is accurate to well under an arcsecond for a planet or comet; only satellites, which cross degrees during a slew, need a lead time.
nonsidereal_rate_update_interval: float | None = None — Minimum interval in seconds between differential rate commands sent to the mount. Astra will not issue a new rate more often than this, however rapidly the ephemeris changes. Lengthen it for mounts that stutter when a rate is applied; shorten it for targets whose rate changes over seconds, such as satellites in low orbit. Defaults to 10 seconds.
metadata: Dict[str, Any] = {} — Arbitrary user-defined key/value pairs that are not otherwise interpreted by Astra.Values ca be written to the FITS header via a `device_type=action_metadata` row in the FITS header configuration CSV, where `device_command` names the metadata key.

calibration#

Capture a sequence of calibration images (bias/dark).

Minimal schedule example

{
    "device_name": "camera_name",
    "action_type": "calibration",
    "action_value": {
        "exptime": [0.0, 5.0, 30.0],
        "n": [10, 5, 3]
    },
    "start_time": "2025-01-01 00:00:00.000",
    "end_time": "2025-02-01 00:00:00.000"
}

Action values

exptime: List[float] Required — Exposure times (seconds) to iterate.
n: List[int] Required — Exposure counts aligned with each exposure time.
filter: str | None = None — Filter name to load before imaging.
dir: str | None = None — Base directory path for saving images.
bin: int = 1 — Camera binning factor.
execute_parallel: bool = false — Execute action in parallel mode when supported.
subframe_width: int | None = None — Width of the requested subframe in binned pixels.
subframe_height: int | None = None — Height of the requested subframe in binned pixels.
subframe_center_x: float = 0.5 — Horizontal subframe center (0=left, 1=right).
subframe_center_y: float = 0.5 — Vertical subframe center (0=top, 1=bottom).
metadata: Dict[str, Any] = {} — Arbitrary user-defined key/value pairs, exposed to FITS headers via `device_type=action_metadata` rows in the FITS header configuration CSV.

flats#

Capture a sequence of sky flats as the sky brightness evolves.

Steps:
  1. Wait for Sun altitude between -1° and -12°

  2. Point to a near-uniform patch of sky opposite the Sun
    • Opens observatory if not already done by a prior action

  3. Capture exposures and re-position between frames

  4. Iterate through requested filters while auto-adjusting exposure times

Minimal schedule example

{
    "device_name": "camera_name",
    "action_type": "flats",
    "action_value": {
        "filter": ["V", "R"],
        "n": [10, 10]
    },
    "start_time": "2025-01-01 00:00:00.000",
    "end_time": "2025-02-01 00:00:00.000"
}

Action values

filter: List[str] Required — Filters to iterate while capturing flats.
n: List[int] Required — Number of flats to capture per filter.
dir: str | None = None — Base directory path for saving images.
bin: int = 1 — Camera binning factor.
execute_parallel: bool = false — Execute action in parallel mode when supported.
disable_telescope_movement: bool = false — Prevent telescope motion during the sequence.
subframe_width: int | None = None — Width of the requested subframe in binned pixels.
subframe_height: int | None = None — Height of the requested subframe in binned pixels.
subframe_center_x: float = 0.5 — Horizontal subframe center (0=left, 1=right).
subframe_center_y: float = 0.5 — Vertical subframe center (0=top, 1=bottom).

calibrate_guiding#

Calibrate guiding parameters using timed guide pulses.

Steps:
  1. Slews telescope to RA = LST - 1 hour, Dec = 0° at the start of sequence
    • Opens observatory if not already done by a prior action

  2. Issues a series of guide pulses in each cardinal direction with specified duration and settling time

  3. Captures exposures after each pulse and measures star shifts to determine pixel-to-time scales and camera orientation relative to mount axes

  4. Averages results over specified number of cycles

  5. Saves calibration parameters in the observatory configuration for use in guiding

Minimal schedule example

{
    "device_name": "camera_name",
    "action_type": "calibrate_guiding",
    "action_value": {},
    "start_time": "2025-01-01 00:00:00.000",
    "end_time": "2025-02-01 00:00:00.000"
}

Action values

filter: str | None = None — Filter to use during calibration.
pulse_time: int = 5000 — Duration of guide pulses in milliseconds.
exptime: float = 1.0 — Exposure time for calibration images.
settle_time: float = 1.0 — Wait time after pulses before exposing.
number_of_cycles: int = 10 — How many calibration cycles to take average over.
focus_shift: float | None = None — Focus offset relative to best focus.
focus_position: float | None = None — Absolute focus position override.
bin: int = 1 — Camera binning factor.
subframe_width: int | None = None — Width of the requested subframe in binned pixels.
subframe_height: int | None = None — Height of the requested subframe in binned pixels.
subframe_center_x: float = 0.5 — Horizontal subframe center (0=left, 1=right).
subframe_center_y: float = 0.5 — Vertical subframe center (0=top, 1=bottom).

autofocus#

Perform an autofocus sweep to determine the optimal focus position.

Steps:
  1. Select a suitable autofocus field (or use provided coordinates)
    • Opens observatory if not already done by a prior action

  2. Move the telescope if needed

  3. Capture images at different focus positions

  4. Measure star sharpness in each image

  5. Fit a curve to determine optimal focus

  6. Save plots/results and save the best focus position in the observatory configuration

Note:

Coarse searches (for example fft, normalized_variance) use non-parametric focus measures that characterise overall frame sharpness and are well suited for very broad search ranges where stars appear as large, defocused “donuts”. Analytic response-function autofocusers (for example HFR/StarSize), which fit a V-curve to measured star sizes, are better for fine-tuning near the focus peak but can give incorrect results if applied over an excessively large range because the assumed response model may not fit across the whole span.

Minimal schedule example

{
    "device_name": "camera_name",
    "action_type": "autofocus",
    "action_value": {
        "exptime": 1.0,
        "filter": "V",
        "focus_measure_operator": "HFR",
        "search_range_is_relative": true,
        "search_range": 1000,
        "n_steps": [30, 20],
        "n_exposures": [1, 1]
    },
    "start_time": "2025-01-01 00:00:00.000",
    "end_time": "2025-02-01 00:00:00.000"
}

Action values

exptime: float | int = 3.0 — Exposure time for focus frames in seconds.
filter: str | None = None — Filter to use during autofocus procedure.
bin: int = 1 — Camera binning factor.
reduce_exposure_time: bool = false — Automatically shorten exposures to prevent saturation.
search_range: List[int] | int | None = None — Range of focus positions to search. Accepts a single width or explicit bounds.
search_range_is_relative: bool = false — Interpret search_range relative to the current focus position.
n_steps: List[int] = [30, 20] — Number of steps for each sweep.
n_exposures: List[int] | int = [1, 1] — Number of exposures at each focus position or an array specifying exposures for each sweep. If an integer is given, the same number of exposures is used for each sweep. If an array is given, the length of the array must match the number of sweeps. 
decrease_search_range: bool = true — Reduce the search range after each sweep.
star_find_threshold: float | int = 5.0 — DAOStarFinder threshold for star detection.
fwhm: int | None = None — DAOStarFinder FWHM of the Gaussian kernel in pixels. If not set, derived from the camera/telescope plate scale assuming ~2" seeing.
percent_to_cut: int = 60 — Percentage of worst-performing focus samples to drop when shrinking the range.
focus_measure_operator: str = 'HFR' — Focus metric to optimize (e.g., hfr, gauss, tenengrad, fft, normalized_variance).
save: bool = true — Persist the optimal focus position back into observatory configuration.
extremum_estimator: str = 'LOWESS' — Curve-fitting method used to determine the minimum (LOWESS, medianfilter, spline, rbf).
extremum_estimator_kwargs: Dict[str, Any] = {} — Additional keyword overrides for the extremum estimator.
secondary_focus_measure_operators: List[str] = ['fft', 'normalized_variance', 'tenengrad'] — Additional focus metrics to compute for diagnostics.
maximal_zenith_angle: float | int | Angle | None = None — Maximum zenith angle allowed when selecting autofocus fields.
airmass_threshold: float = 1.01 — Highest acceptable airmass for autofocus candidates.
g_mag_range: List[float | int] = [0, 10] — Inclusive Gaia G magnitude range to consider.
j_mag_range: List[float | int] = [0, 10] — Inclusive 2MASS J magnitude range to consider.
fov_height: float | int = 0 — Height of the field of view in degrees.
fov_width: float | int = 0 — Width of the field of view in degrees.
selection_method: SelectionMethod | str = 'single' — Strategy for selecting stars (single, maximal, any).
use_gaia: bool = true — Whether to rely on Gaia catalog sources.
observation_time: Time | None = None — Observation time used when evaluating constraints.
maximal_number_of_stars: int = 100000 — Maximum number of stars to query or consider.
ra: float | int | None = None — Fixed Right Ascension used to bypass automatic selection.
dec: float | int | None = None — Fixed Declination used to bypass automatic selection.
save_path: Path | None = None — Directory override for saving autofocus results.
subframe_width: int | None = None — Width of the requested subframe in binned pixels.
subframe_height: int | None = None — Height of the requested subframe in binned pixels.
subframe_center_x: float = 0.5 — Horizontal subframe center (0=left, 1=right).
subframe_center_y: float = 0.5 — Vertical subframe center (0=top, 1=bottom).

pointing_model#

Aid building a telescope pointing model. Astra itself does not build or maintain a pointing model.

Captures a spiral of points from zenith down to 30° altitude while avoiding positions within 20° of the Moon.

Plate solves each pointing and sends SyncToCoordinates commands to the mount. The receipt of these commands can be used to build a pointing model in the mount control software. The action can be configured to use the local star catalog for plate solving to speed up the process if the online Gaia catalog is unavailable or slow.

Minimal schedule example

{
    "device_name": "camera_name",
    "action_type": "pointing_model",
    "action_value": {},
    "start_time": "2025-01-01 00:00:00.000",
    "end_time": "2025-02-01 00:00:00.000"
}

Action values

n: int = 50 — Number of points to include in the model.
exptime: float = 3.0 — Exposure time for each pointing image.
dark_subtraction: bool = false — Enable dark subtraction using previously taken calibration frames of same exposure time in the same date folder.
object: str = 'Pointing Model' — Descriptive label for the pointing run.
use_local_db: bool = false — Use local star catalog database for plate solving (faster).
filter: str | None = None — Filter to use for exposures.
focus_shift: float | None = None — Focus offset relative to best focus.
focus_position: float | None = None — Absolute focus position override.
bin: int = 1 — Camera binning factor.
dir: str | None = None — Directory path for saving images.
subframe_width: int | None = None — Width of the requested subframe in binned pixels.
subframe_height: int | None = None — Height of the requested subframe in binned pixels.
subframe_center_x: float = 0.5 — Horizontal subframe center (0=left, 1=right).
subframe_center_y: float = 0.5 — Vertical subframe center (0=top, 1=bottom).

open#

Open the observatory for observations.

Steps:
  1. Opens dome shutter

  2. Unparks telescope

  3. Cools camera

Minimal schedule example

{
    "device_name": "camera_name",
    "action_type": "open",
    "action_value": {},
    "start_time": "2025-01-01 00:00:00.000",
    "end_time": "2025-02-01 00:00:00.000"
}

close#

Close the observatory safely.

Steps:
  1. Stop any active guiding operations

  2. Stop telescope slewing and tracking

  3. Park the telescope

  4. Park the dome and close shutter

  5. Cools camera

Minimal schedule example

{
    "device_name": "camera_name",
    "action_type": "close",
    "action_value": {},
    "start_time": "2025-01-01 00:00:00.000",
    "end_time": "2025-02-01 00:00:00.000"
}

cool_camera#

Configuration for the cool_camera schedule action.

Activates the camera cooler and sets the target temperature with specified tolerance and timeout from observatory configuration.

Minimal schedule example

{
    "device_name": "camera_name",
    "action_type": "cool_camera",
    "action_value": {},
    "start_time": "2025-01-01 00:00:00.000",
    "end_time": "2025-02-01 00:00:00.000"
}

complete_headers#

Complete FITS headers after exposures finish.

Uses paired device polled data to fill in FITS header fields that were unavailable at exposure time. Automatically executed at the end of every schedule.

Minimal schedule example

{
    "device_name": "camera_name",
    "action_type": "complete_headers",
    "action_value": {},
    "start_time": "2025-01-01 00:00:00.000",
    "end_time": "2025-02-01 00:00:00.000"
}