Skip to content

Instantly share code, notes, and snippets.

@cgobat
Created March 25, 2026 23:32
Show Gist options
  • Select an option

  • Save cgobat/24f205a65b42217ddceddf6c52852dc7 to your computer and use it in GitHub Desktop.

Select an option

Save cgobat/24f205a65b42217ddceddf6c52852dc7 to your computer and use it in GitHub Desktop.
Populate Celestron Origin FITS header metadata using info.json
#!/usr/bin/env python
#
# This script populates metadata in the headers of FITS files produced by a Celestron Origin
# telescope, using information from an accompanying JSON file
#
# Author: @cgobat
import json
import argparse
import numpy as np
import datetime as dt
from pathlib import Path
from astropy.io import fits
def update_header(fits_file: Path, info_json: Path) -> None:
info = json.loads(info_json.read_bytes())
info = info.get("StackedInfo", {})
capture_time = dt.datetime.fromisoformat(info["dateTime"])
capture_time = capture_time.astimezone(dt.UTC)
ra_rad, dec_rad = info["celestial"]["first"], info["celestial"]["second"]
ra_deg, dec_deg = np.rad2deg(ra_rad), np.rad2deg(dec_rad)
with fits.open(fits_file, mode="update") as f:
h = f[0].header
h["TELESCOP"] = ("Celestron Origin", "Telescope name")
h["INSTRUME"] = ("Celestron Origin", "Instrument name")
h["APERTURE"] = (152., "[mm] Aperture diameter")
h["FOCALLEN"] = (335., "[mm] Focal length")
h["BAYERPAT"] = (info["bayer"].upper(), "Bayer (CFA) pattern")
h["FILTER"] = (info["filter"], "Filter name")
h["CCD-TEMP"] = (info["captureParams"]["temperature"], "[degC] Sensor temperature")
h["EXPOSURE"] = (info["captureParams"]["exposure"], "[s] Per-frame exposure time")
h["BINNING"] = (info["captureParams"]["binning"], "Camera binning (1 for 1x1, 2 for 2x2)")
h["ISO"] = (info["captureParams"]["iso"], "ISO (gain) setting")
h["DATE-OBS"] = (capture_time.strftime("%Y-%m-%dT%H:%M:%S"), "UTC time of observation")
h["OBJECT"] = (info["objectName"], "Target name")
h["RA"] = (ra_deg, "[deg] Nominal right ascension")
h["DEC"] = (dec_deg, "[deg] Nominal declination")
h["LATITUDE"] = (info["gps"]["latitude"], "[deg] Site latitude")
h["LONGITUD"] = (info["gps"]["longitude"], "[deg] Site longitude")
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("fits_files", nargs="+", type=Path, help="FITS file(s) to process/update")
parser.add_argument("-i", "--info", required=True, type=Path, help="JSON file containing capture metadata")
args = parser.parse_args()
for file in args.fits_files:
update_header(file, args.info)
print(f"Updated {file}")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment