-
+
diff --git a/public/py/ephemeriden_api.py b/public/py/ephemeriden_api.py
index bc21f71..2411c8c 100644
--- a/public/py/ephemeriden_api.py
+++ b/public/py/ephemeriden_api.py
@@ -3,6 +3,7 @@ import json
import math
import os
import sys
+import base64
from datetime import datetime, timedelta, timezone
from zoneinfo import ZoneInfo
@@ -25,6 +26,12 @@ EPHEMERIS_BODIES = {
"Neptune": ("Neptun", astronomy.Body.Neptune),
}
+J2000_OBLIQUITY_DEG = 23.439279444444445
+GAUSSIAN_GRAVITATIONAL_CONSTANT = 0.01720209895
+PARABOLIC_ECCENTRICITY_TOLERANCE = 1.0e-6
+MAX_ROWS = 50000
+CUSTOM_EVENT_STEP_MINUTES = 10
+
def fail(message: str, *, extra: dict | None = None, code: int = 1) -> None:
payload = {"ok": False, "error": message}
@@ -41,6 +48,13 @@ def parse_float(value: str, label: str) -> float:
fail(f"{label} ist ungueltig.", extra={"details": str(exc), "value": value})
+def parse_payload_float(payload: dict, key: str) -> float:
+ value = payload.get(key)
+ if value is None:
+ raise ValueError(f"{key} fehlt.")
+ return float(value)
+
+
def dt_to_time(dt_utc: datetime) -> astronomy.Time:
dt_utc = dt_utc.astimezone(timezone.utc)
return astronomy.Time.Make(
@@ -155,6 +169,311 @@ def add_calendar_unit(base: datetime, amount: int, unit: str) -> datetime:
fail("Zeitraum-Einheit ist ungueltig.", extra={"unit": unit})
+def solve_elliptic_anomaly(mean_anomaly: float, eccentricity: float) -> float:
+ anomaly = mean_anomaly if eccentricity < 0.8 else (math.pi if mean_anomaly >= 0.0 else -math.pi)
+ for _ in range(30):
+ delta = (anomaly - eccentricity * math.sin(anomaly) - mean_anomaly) / (1.0 - eccentricity * math.cos(anomaly))
+ anomaly -= delta
+ if abs(delta) < 1.0e-12:
+ break
+ return anomaly
+
+
+def solve_hyperbolic_anomaly(mean_anomaly: float, eccentricity: float) -> float:
+ anomaly = 0.0 if mean_anomaly == 0.0 else math.asinh(mean_anomaly / eccentricity)
+ for _ in range(40):
+ sinh_value = math.sinh(anomaly)
+ cosh_value = math.cosh(anomaly)
+ delta = (eccentricity * sinh_value - anomaly - mean_anomaly) / (eccentricity * cosh_value - 1.0)
+ anomaly -= delta
+ if abs(delta) < 1.0e-12:
+ break
+ return anomaly
+
+
+def solve_parabolic_parameter(delta_days: float, perihelion_distance_au: float) -> float:
+ scale = GAUSSIAN_GRAVITATIONAL_CONSTANT * delta_days / math.sqrt(2.0 * perihelion_distance_au**3)
+ parameter = scale
+ for _ in range(40):
+ numerator = parameter + (parameter**3) / 3.0 - scale
+ denominator = 1.0 + parameter**2
+ delta = numerator / denominator
+ parameter -= delta
+ if abs(delta) < 1.0e-12:
+ break
+ return parameter
+
+
+def true_anomaly_and_radius(delta_days: float, perihelion_distance_au: float, eccentricity: float) -> tuple[float, float]:
+ if perihelion_distance_au <= 0.0:
+ raise ValueError("Periheldistanz muss positiv sein.")
+
+ if eccentricity < 1.0 - PARABOLIC_ECCENTRICITY_TOLERANCE:
+ semi_major_axis = perihelion_distance_au / (1.0 - eccentricity)
+ mean_motion = GAUSSIAN_GRAVITATIONAL_CONSTANT / (semi_major_axis ** 1.5)
+ mean_anomaly = math.fmod(mean_motion * delta_days, 2.0 * math.pi)
+ eccentric_anomaly = solve_elliptic_anomaly(mean_anomaly, eccentricity)
+ radius = semi_major_axis * (1.0 - eccentricity * math.cos(eccentric_anomaly))
+ true_anomaly = 2.0 * math.atan2(
+ math.sqrt(1.0 + eccentricity) * math.sin(eccentric_anomaly / 2.0),
+ math.sqrt(1.0 - eccentricity) * math.cos(eccentric_anomaly / 2.0),
+ )
+ return true_anomaly, radius
+
+ if eccentricity > 1.0 + PARABOLIC_ECCENTRICITY_TOLERANCE:
+ semi_major_axis_abs = perihelion_distance_au / (eccentricity - 1.0)
+ mean_anomaly = GAUSSIAN_GRAVITATIONAL_CONSTANT * delta_days / (semi_major_axis_abs ** 1.5)
+ hyperbolic_anomaly = solve_hyperbolic_anomaly(mean_anomaly, eccentricity)
+ radius = semi_major_axis_abs * (eccentricity * math.cosh(hyperbolic_anomaly) - 1.0)
+ true_anomaly = 2.0 * math.atan2(
+ math.sqrt(eccentricity + 1.0) * math.sinh(hyperbolic_anomaly / 2.0),
+ math.sqrt(eccentricity - 1.0) * math.cosh(hyperbolic_anomaly / 2.0),
+ )
+ return true_anomaly, radius
+
+ parabolic_parameter = solve_parabolic_parameter(delta_days, perihelion_distance_au)
+ true_anomaly = 2.0 * math.atan(parabolic_parameter)
+ radius = perihelion_distance_au * (1.0 + parabolic_parameter**2)
+ return true_anomaly, radius
+
+
+def ecliptic_to_equatorial(x_ecl: float, y_ecl: float, z_ecl: float) -> tuple[float, float, float]:
+ epsilon = math.radians(J2000_OBLIQUITY_DEG)
+ cos_epsilon = math.cos(epsilon)
+ sin_epsilon = math.sin(epsilon)
+ return (
+ x_ecl,
+ y_ecl * cos_epsilon - z_ecl * sin_epsilon,
+ y_ecl * sin_epsilon + z_ecl * cos_epsilon,
+ )
+
+
+def minorplanet_heliocentric_vector(payload: dict, dt_utc: datetime) -> tuple[float, float, float]:
+ epoch_date_iso = str(payload.get("epochDateIso") or "").strip()
+ if epoch_date_iso == "":
+ raise ValueError("Epochendatum fehlt.")
+
+ epoch_dt = datetime.fromisoformat(f"{epoch_date_iso}T00:00:00+00:00").astimezone(timezone.utc)
+ days_since_epoch = (dt_utc - epoch_dt).total_seconds() / 86400.0
+
+ mean_anomaly_deg = parse_payload_float(payload, "meanAnomalyDeg")
+ mean_motion_deg_per_day = parse_payload_float(payload, "meanMotionDegPerDay")
+ eccentricity = max(0.0, min(0.999999, parse_payload_float(payload, "eccentricity")))
+ semimajor_axis_au = parse_payload_float(payload, "semimajorAxisAu")
+ inclination = math.radians(parse_payload_float(payload, "inclinationDeg"))
+ ascending_node = math.radians(parse_payload_float(payload, "ascendingNodeDeg"))
+ arg_perihelion = math.radians(parse_payload_float(payload, "argPerihelionDeg"))
+
+ mean_anomaly = math.radians(mean_anomaly_deg + (mean_motion_deg_per_day * days_since_epoch))
+ eccentric_anomaly = solve_elliptic_anomaly(math.fmod(mean_anomaly, 2.0 * math.pi), eccentricity)
+ true_anomaly = 2.0 * math.atan2(
+ math.sqrt(1.0 + eccentricity) * math.sin(eccentric_anomaly / 2.0),
+ math.sqrt(1.0 - eccentricity) * math.cos(eccentric_anomaly / 2.0),
+ )
+ radius_au = semimajor_axis_au * (1.0 - eccentricity * math.cos(eccentric_anomaly))
+ argument_of_latitude = true_anomaly + arg_perihelion
+
+ x_ecl = radius_au * (
+ (math.cos(ascending_node) * math.cos(argument_of_latitude))
+ - (math.sin(ascending_node) * math.sin(argument_of_latitude) * math.cos(inclination))
+ )
+ y_ecl = radius_au * (
+ (math.sin(ascending_node) * math.cos(argument_of_latitude))
+ + (math.cos(ascending_node) * math.sin(argument_of_latitude) * math.cos(inclination))
+ )
+ z_ecl = radius_au * (math.sin(argument_of_latitude) * math.sin(inclination))
+
+ return ecliptic_to_equatorial(x_ecl, y_ecl, z_ecl)
+
+
+def comet_heliocentric_vector(payload: dict, dt_utc: datetime) -> tuple[float, float, float]:
+ perihelion_iso = str(payload.get("perihelionIso") or "").strip()
+ if perihelion_iso == "":
+ raise ValueError("Perihelzeit fehlt.")
+
+ perihelion_dt = datetime.fromisoformat(perihelion_iso.replace("Z", "+00:00")).astimezone(timezone.utc)
+ delta_days = (dt_utc - perihelion_dt).total_seconds() / 86400.0
+
+ perihelion_distance_au = parse_payload_float(payload, "perihelionDistanceAu")
+ eccentricity = parse_payload_float(payload, "eccentricity")
+ inclination = math.radians(parse_payload_float(payload, "inclinationDeg"))
+ ascending_node = math.radians(parse_payload_float(payload, "ascendingNodeDeg"))
+ arg_perihelion = math.radians(parse_payload_float(payload, "argPerihelionDeg"))
+
+ true_anomaly, radius = true_anomaly_and_radius(delta_days, perihelion_distance_au, eccentricity)
+ argument_of_latitude = arg_perihelion + true_anomaly
+
+ x_ecl = radius * (math.cos(ascending_node) * math.cos(argument_of_latitude) - math.sin(ascending_node) * math.sin(argument_of_latitude) * math.cos(inclination))
+ y_ecl = radius * (math.sin(ascending_node) * math.cos(argument_of_latitude) + math.cos(ascending_node) * math.sin(argument_of_latitude) * math.cos(inclination))
+ z_ecl = radius * (math.sin(argument_of_latitude) * math.sin(inclination))
+
+ return ecliptic_to_equatorial(x_ecl, y_ecl, z_ecl)
+
+
+def custom_geocentric_vector(body_type: str, payload: dict, time_value: astronomy.Time) -> astronomy.Vector:
+ dt_utc = time_to_datetime(time_value)
+ if body_type == "minorplanet":
+ helio = minorplanet_heliocentric_vector(payload, dt_utc)
+ elif body_type == "comet":
+ helio = comet_heliocentric_vector(payload, dt_utc)
+ else:
+ raise ValueError("Objekttyp ist ungueltig.")
+
+ earth_vector = astronomy.HelioVector(astronomy.Body.Earth, time_value)
+ return astronomy.Vector(
+ helio[0] - earth_vector.x,
+ helio[1] - earth_vector.y,
+ helio[2] - earth_vector.z,
+ time_value,
+ )
+
+
+def custom_topocentric_vector(body_type: str, payload: dict, observer: astronomy.Observer, time_value: astronomy.Time) -> astronomy.Vector:
+ geocentric_vector = custom_geocentric_vector(body_type, payload, time_value)
+ observer_vector = astronomy.ObserverVector(time_value, observer, False)
+ return astronomy.Vector(
+ geocentric_vector.x - observer_vector.x,
+ geocentric_vector.y - observer_vector.y,
+ geocentric_vector.z - observer_vector.z,
+ time_value,
+ )
+
+
+def custom_altitude_deg(body_type: str, payload: dict, observer: astronomy.Observer, time_value: astronomy.Time) -> float:
+ topocentric_vector = custom_topocentric_vector(body_type, payload, observer, time_value)
+ rotation = astronomy.Rotation_EQJ_HOR(time_value, observer)
+ horizontal_vector = astronomy.RotateVector(rotation, topocentric_vector)
+ horizontal = astronomy.HorizonFromVector(horizontal_vector, astronomy.Refraction.Normal)
+ return float(horizontal.lat)
+
+
+def refine_custom_event(
+ body_type: str,
+ payload: dict,
+ observer: astronomy.Observer,
+ left_dt: datetime,
+ right_dt: datetime,
+ *,
+ rising: bool,
+) -> datetime:
+ for _ in range(24):
+ midpoint = left_dt + (right_dt - left_dt) / 2
+ altitude = custom_altitude_deg(body_type, payload, observer, dt_to_time(midpoint))
+ if (altitude >= 0.0) == rising:
+ right_dt = midpoint
+ else:
+ left_dt = midpoint
+ return right_dt
+
+
+def search_custom_events_for_day(
+ body_type: str,
+ payload: dict,
+ observer: astronomy.Observer,
+ local_day_start: datetime,
+ tz: ZoneInfo,
+) -> tuple[str | None, str | None]:
+ step = timedelta(minutes=CUSTOM_EVENT_STEP_MINUTES)
+ day_end = local_day_start + timedelta(days=1)
+
+ previous_dt = local_day_start.astimezone(timezone.utc)
+ previous_altitude = custom_altitude_deg(body_type, payload, observer, dt_to_time(previous_dt))
+ rise_time = None
+ set_time = None
+
+ current_dt = previous_dt + step
+ while current_dt <= day_end.astimezone(timezone.utc):
+ current_altitude = custom_altitude_deg(body_type, payload, observer, dt_to_time(current_dt))
+
+ if rise_time is None and previous_altitude < 0.0 <= current_altitude:
+ rise_time = refine_custom_event(body_type, payload, observer, previous_dt, current_dt, rising=True)
+ if set_time is None and previous_altitude >= 0.0 > current_altitude:
+ set_time = refine_custom_event(body_type, payload, observer, previous_dt, current_dt, rising=False)
+
+ previous_dt = current_dt
+ previous_altitude = current_altitude
+ current_dt += step
+
+ rise_label = rise_time.astimezone(tz).strftime("%H:%M") if rise_time is not None else None
+ set_label = set_time.astimezone(tz).strftime("%H:%M") if set_time is not None else None
+ return rise_label, set_label
+
+
+def build_rows_response(
+ *,
+ observer: astronomy.Observer,
+ timezone_name: str,
+ object_key: str,
+ object_label: str,
+ interval_minutes: int,
+ range_value: int,
+ range_unit: str,
+ row_builder,
+ rise_set_builder,
+ action_name: str,
+) -> dict:
+ try:
+ tz = ZoneInfo(timezone_name)
+ except Exception as exc:
+ fail("Zeitzone ist ungueltig.", extra={"details": str(exc)})
+
+ local_start = datetime.now(tz).replace(second=0, microsecond=0)
+ local_end = add_calendar_unit(local_start, range_value, range_unit)
+
+ rows = []
+ current_local = local_start
+ step = timedelta(minutes=interval_minutes)
+ rise_set_cache: dict[str, tuple[str | None, str | None]] = {}
+
+ while current_local <= local_end:
+ if len(rows) >= MAX_ROWS:
+ fail(
+ "Die Anfrage erzeugt zu viele Tabellenzeilen. Bitte Zeitraum verkuerzen oder groesseres Intervall waehlen.",
+ extra={
+ "max_rows": MAX_ROWS,
+ "interval_minutes": interval_minutes,
+ "range_value": range_value,
+ "range_unit": range_unit,
+ },
+ )
+
+ current_utc = current_local.astimezone(timezone.utc)
+ time_value = dt_to_time(current_utc)
+
+ day_key = current_local.strftime("%Y-%m-%d")
+ if day_key not in rise_set_cache:
+ local_day_start = current_local.replace(hour=0, minute=0, second=0, microsecond=0)
+ rise_set_cache[day_key] = rise_set_builder(local_day_start)
+
+ rise_label, set_label = rise_set_cache[day_key]
+ row = row_builder(current_local, time_value, rise_label, set_label)
+ rows.append(row)
+ current_local += step
+
+ return {
+ "ok": True,
+ "action": action_name,
+ "observer": {
+ "latitude": observer.latitude,
+ "longitude": observer.longitude,
+ "elevation": observer.height,
+ "timezone": timezone_name,
+ },
+ "object": {
+ "key": object_key,
+ "label": object_label,
+ },
+ "window": {
+ "local_start": local_start.isoformat(),
+ "local_end": local_end.isoformat(),
+ "interval_minutes": interval_minutes,
+ "range_value": range_value,
+ "range_unit": range_unit,
+ },
+ "rows": rows,
+ }
+
+
def action_planet_ephemeris(args: list[str]) -> dict:
if len(args) != 8:
fail(
@@ -185,53 +504,12 @@ def action_planet_ephemeris(args: list[str]) -> dict:
if range_unit not in {"minutes", "hours", "days", "weeks", "months", "years"}:
fail("Zeitraum-Einheit ist ungueltig.", extra={"range_unit": range_unit})
- try:
- tz = ZoneInfo(timezone_name)
- except Exception as exc:
- fail("Zeitzone ist ungueltig.", extra={"details": str(exc)})
-
label, body = EPHEMERIS_BODIES[body_name]
observer = astronomy.Observer(latitude, longitude, elevation)
- local_start = datetime.now(tz).replace(second=0, microsecond=0)
- local_end = add_calendar_unit(local_start, range_value, range_unit)
- rows = []
- current_local = local_start
- step = timedelta(minutes=interval_minutes)
- rise_set_cache: dict[str, tuple[str | None, str | None]] = {}
- max_rows = 50000
-
- while current_local <= local_end:
- if len(rows) >= max_rows:
- fail(
- "Die Anfrage erzeugt zu viele Tabellenzeilen. Bitte Zeitraum verkuerzen oder groesseres Intervall waehlen.",
- extra={
- "max_rows": max_rows,
- "interval_minutes": interval_minutes,
- "range_value": range_value,
- "range_unit": range_unit,
- },
- )
-
- current_utc = current_local.astimezone(timezone.utc)
- time_value = dt_to_time(current_utc)
+ def row_builder(current_local: datetime, time_value: astronomy.Time, rise_label: str | None, set_label: str | None) -> dict:
eq = astronomy.Equator(body, time_value, observer, False, True)
-
- day_key = current_local.strftime("%Y-%m-%d")
- if day_key not in rise_set_cache:
- local_day_start = current_local.replace(hour=0, minute=0, second=0, microsecond=0)
- local_day_end = local_day_start + timedelta(days=1)
- day_start_time = dt_to_time(local_day_start.astimezone(timezone.utc))
- day_end_utc = local_day_end.astimezone(timezone.utc)
-
- rise = search_event(body, astronomy.Direction.Rise, observer, day_start_time, day_end_utc)
- set_ = search_event(body, astronomy.Direction.Set, observer, day_start_time, day_end_utc)
- rise_label = serialize_event("Aufgang", rise, tz).get("local_time") if rise is not None else None
- set_label = serialize_event("Untergang", set_, tz).get("local_time") if set_ is not None else None
- rise_set_cache[day_key] = (rise_label, set_label)
-
- rise_label, set_label = rise_set_cache[day_key]
- rows.append({
+ return {
"object_name": label,
"date_local": current_local.strftime("%d.%m.%Y"),
"time_local": current_local.strftime("%H:%M"),
@@ -241,37 +519,128 @@ def action_planet_ephemeris(args: list[str]) -> dict:
"dec_decimal_deg": round(float(eq.dec), 8),
"rise": rise_label,
"set": set_label,
- })
+ }
- current_local += step
+ def rise_set_builder(local_day_start: datetime) -> tuple[str | None, str | None]:
+ try:
+ tz = ZoneInfo(timezone_name)
+ except Exception as exc:
+ fail("Zeitzone ist ungueltig.", extra={"details": str(exc)})
- return {
- "ok": True,
- "action": "planet_ephemeris",
- "observer": {
- "latitude": latitude,
- "longitude": longitude,
- "elevation": elevation,
- "timezone": timezone_name,
- },
- "object": {
- "key": body_name,
- "label": label,
- },
- "window": {
- "local_start": local_start.isoformat(),
- "local_end": local_end.isoformat(),
- "interval_minutes": interval_minutes,
- "range_value": range_value,
- "range_unit": range_unit,
- },
- "rows": rows,
- }
+ local_day_end = local_day_start + timedelta(days=1)
+ day_start_time = dt_to_time(local_day_start.astimezone(timezone.utc))
+ day_end_utc = local_day_end.astimezone(timezone.utc)
+ rise = search_event(body, astronomy.Direction.Rise, observer, day_start_time, day_end_utc)
+ set_ = search_event(body, astronomy.Direction.Set, observer, day_start_time, day_end_utc)
+ rise_label = serialize_event("Aufgang", rise, tz).get("local_time") if rise is not None else None
+ set_label = serialize_event("Untergang", set_, tz).get("local_time") if set_ is not None else None
+ return rise_label, set_label
+
+ return build_rows_response(
+ observer=observer,
+ timezone_name=timezone_name,
+ object_key=body_name,
+ object_label=label,
+ interval_minutes=interval_minutes,
+ range_value=range_value,
+ range_unit=range_unit,
+ row_builder=row_builder,
+ rise_set_builder=rise_set_builder,
+ action_name="planet_ephemeris",
+ )
+
+
+def action_small_body_ephemeris(args: list[str]) -> dict:
+ if len(args) != 9:
+ fail(
+ "Aktion small_body_ephemeris erwartet 9 Argumente: latitude longitude elevation timezone bodyType payload intervalMinutes rangeValue rangeUnit",
+ extra={"argv": args},
+ )
+
+ latitude = parse_float(args[0], "Latitude")
+ longitude = parse_float(args[1], "Longitude")
+ elevation = parse_float(args[2], "Elevation")
+ timezone_name = args[3]
+ body_type = str(args[4]).strip().lower()
+
+ try:
+ payload_json = base64.b64decode(args[5]).decode("utf-8")
+ payload = json.loads(payload_json)
+ except json.JSONDecodeError as exc:
+ fail("Objektdaten sind ungueltig.", extra={"details": str(exc)})
+
+ try:
+ interval_minutes = int(args[6])
+ range_value = int(args[7])
+ except ValueError as exc:
+ fail("Intervall oder Zeitraum ist ungueltig.", extra={"details": str(exc), "argv": args})
+
+ range_unit = str(args[8]).strip()
+
+ if body_type not in {"minorplanet", "comet"}:
+ fail("Objekttyp ist ungueltig.", extra={"body_type": body_type})
+ if not isinstance(payload, dict):
+ fail("Objektdaten sind ungueltig.")
+ if interval_minutes <= 0:
+ fail("Intervall muss groesser als 0 sein.", extra={"interval_minutes": interval_minutes})
+ if range_value <= 0:
+ fail("Zeitraum muss groesser als 0 sein.", extra={"range_value": range_value})
+ if range_unit not in {"minutes", "hours", "days", "weeks", "months", "years"}:
+ fail("Zeitraum-Einheit ist ungueltig.", extra={"range_unit": range_unit})
+
+ observer = astronomy.Observer(latitude, longitude, elevation)
+ object_label = str(payload.get("designation") or payload.get("label") or "Objekt").strip() or "Objekt"
+ object_key = f"{body_type}:{payload.get('id', '')}"
+
+ def row_builder(current_local: datetime, time_value: astronomy.Time, rise_label: str | None, set_label: str | None) -> dict:
+ try:
+ topocentric_vector = custom_topocentric_vector(body_type, payload, observer, time_value)
+ except Exception as exc:
+ fail("Die Ephemeriden konnten fuer dieses Objekt nicht berechnet werden.", extra={"details": str(exc), "object": object_label})
+
+ eq = astronomy.EquatorFromVector(topocentric_vector)
+ return {
+ "object_name": object_label,
+ "date_local": current_local.strftime("%d.%m.%Y"),
+ "time_local": current_local.strftime("%H:%M"),
+ "ra": format_ra_hours(float(eq.ra)),
+ "ra_decimal_hours": round(float(eq.ra), 8),
+ "dec": format_dec_deg(float(eq.dec)),
+ "dec_decimal_deg": round(float(eq.dec), 8),
+ "rise": rise_label,
+ "set": set_label,
+ }
+
+ def rise_set_builder(local_day_start: datetime) -> tuple[str | None, str | None]:
+ try:
+ tz = ZoneInfo(timezone_name)
+ except Exception as exc:
+ fail("Zeitzone ist ungueltig.", extra={"details": str(exc)})
+
+ try:
+ return search_custom_events_for_day(body_type, payload, observer, local_day_start, tz)
+ except Exception as exc:
+ fail("Auf- und Untergang konnten fuer dieses Objekt nicht berechnet werden.", extra={"details": str(exc), "object": object_label})
+
+ return build_rows_response(
+ observer=observer,
+ timezone_name=timezone_name,
+ object_key=object_key,
+ object_label=object_label,
+ interval_minutes=interval_minutes,
+ range_value=range_value,
+ range_unit=range_unit,
+ row_builder=row_builder,
+ rise_set_builder=rise_set_builder,
+ action_name="small_body_ephemeris",
+ )
def main() -> None:
+ available_actions = ["planet_ephemeris", "small_body_ephemeris"]
+
if len(sys.argv) < 2:
- fail("Es wurde keine Aktion uebergeben.", extra={"available_actions": ["planet_ephemeris"]})
+ fail("Es wurde keine Aktion uebergeben.", extra={"available_actions": available_actions})
action = sys.argv[1]
args = sys.argv[2:]
@@ -281,7 +650,12 @@ def main() -> None:
print(json.dumps(result, ensure_ascii=True))
return
- fail("Unbekannte Aktion.", extra={"action": action, "available_actions": ["planet_ephemeris"]})
+ if action == "small_body_ephemeris":
+ result = action_small_body_ephemeris(args)
+ print(json.dumps(result, ensure_ascii=True))
+ return
+
+ fail("Unbekannte Aktion.", extra={"action": action, "available_actions": available_actions})
if __name__ == "__main__":