Aether API
Aether API¶
The AetherApi class is the base class used by all helper classes AetherServicesApi, AetherSatellitesApi and AetherSensorsApi. It may also be used directly for experienced users. The following example illustrates the use of the AetherApi class. The test data can be downloaded here while the notebook itself may be fetched here.
Authenticating to the Aether API¶
Before interacting with the Aether API, it is necessary to authenticate yourself. To do so, two main ways are possible:
- (Recommended) As explained in Getting Started, create a .env file at the root of your project, containing the specified keys, namely AETHER_AUTH0_USERNAME and AETHER_AUTH0_PASSWORD. Then, you may simply use the below lines of code which will automatically look for the .env file at the root of your project.
aether_api = AetherApi()
aether_api.login()
- Directly passing in your credentials to the login method of the AetherAPi class, as shown below:
aether_api = AetherApi()
aether_api.login(username="example@fakedomain.com", password="YourSafePassw0rd!")
import os
import pandas as pd
import matplotlib.pyplot as plt
from okapi_aether_sdk.aether_api import AetherApi
# Ensure that the .env file is populated with the required entries for authentication
aether_api = AetherApi()
aether_api.login()
max_iter = 10 # Maximum number of get requests to be sent
wait_time = 30 # seconds between each get request
# The below code is used to load data from a repository to illustrate the use of the Aether Services API.
here = globals()['_dh'][0]
testdata = here / "testdata" / "aether_services_api"
Sending a request directly using AetherApi¶
In this example, we will send a POST request for a specific satellite to the Aether API directly, without using the helper class AetherSatellitesApi. We will then retrieve it with a GET request.
# POST the satellite to OKAPI:Aether's satellites collection
satellite_definition = {
"satellite_id": "550e8400-e29b-11d4-a716-446655440000",
"name": "TEST-SAT",
"norad_ids": [
42784
],
"area": 0.2214382352941178,
"drag_area": 0.05,
"mass": 56,
"thrust_uncertainty": 2,
"thrust_pointing_uncertainty": 2,
"thrust_output": 1.1e-8,
"propulsion_type": "continuous",
"accepted_collision_probability": 0.0001,
"accepted_minimum_distance": 100,
"use_ai_risk_prediction": False,
"space_track_status": "satellite_registered",
"space_track_status_other": "string",
"space_track_company_name": "OKAPI:Orbits GmbH",
"space_track_poc_name": "Max Musterman",
"space_track_poc_address": "Examplestreet 32, 34562 Examplecity, Germany",
"space_track_login": "example@someprovider.com",
"active": True,
"maneuver_strategy": [
"short_term",
"long_term"
]
}
request = aether_api.post("satellites", satellite_definition)
print(f"Satellite uploaded with satellite_id {request["satellite_id"]}")
satellite_id = request["satellite_id"]
# GET the satellite from OKAPI:Aether
url = f"satellites/{satellite_id}"
satellite = aether_api.get(url)
print(satellite)
Satellite uploaded with satellite_id fe7800f0-59dc-4395-8ee5-dc34da17d601 {'satellite_id': 'fe7800f0-59dc-4395-8ee5-dc34da17d601', 'name': 'Satellite name to be set automatically', 'norad_ids': [42784], 'area': 0.2214382352941178, 'drag_area': 0.05, 'mass': 56, 'thrust_uncertainty': 2, 'thrust_pointing_uncertainty': 2, 'thrust_output': 1.1e-08, 'propulsion_type': 'continuous', 'accepted_collision_probability': 0.0001, 'accepted_minimum_distance': 100, 'use_ai_risk_prediction': False, 'space_track_status': 'satellite_registered', 'space_track_status_other': 'string', 'space_track_company_name': 'OKAPI:Orbits GmbH', 'space_track_poc_name': 'Max Musterman', 'space_track_poc_address': 'Examplestreet 32, 34562 Examplecity, Germany', 'space_track_login': 'example@someprovider.com', 'active': False, 'maneuver_strategy': ['short_term', 'long_term'], 'max_thrust_duration': 1, 'in_sun_constraint': False, 'constrain_entire_maneuver': False, 'symmetric_manoeuvres': False, 'use_offset_cdm_and_earliest_maneuver': True, 'offset_cdm_and_earliest_maneuver': 25200, 'min_time_till_pass': 3600, 'enable_accepted_collision_probability_limit_recommendation': True, 'enable_miss_distance_recommendation': True, 'enable_per_component_miss_distance_limit': False, 'enable_criticality_time_limit': False, 'criticality_time_limit': 5, 'send_mail_notifications': False, 'send_slack_notifications': False, 'send_teams_notifications': False, 'notification_verbosity': 'observe', 'maneuver_direction': ['auto'], 'use_hbr_lookup_table': False}
Adding ephemerides for an asset¶
This example uses the same example as presented in Aether Services. A NavSol is used to upload new ephemerides for a fictitious satellite with NORAD ID 12345. First, the NavSol is wrapped in a valid dictionary, before being sent to the "add_ephemerides/request" URL. After successfully submitting the ephemerides, the OEM resulting from the orbit determination process is retrieved from "add-ephemerides/results/" and plotted.
NOTE: The bare_navsol.txt file contains records on individual lines, as shown below:
SpacecraftTime,GNSS_S_ITOW,GNSS_S_FTOW,GNSS_S_WEEK,GNSS_S_GPSFIX,GNSS_S_TOWSET,GNSS_S_WKNSET,GNSS_S_DIFFSOLN,GNSS_S_GPSFIXOK,GNSS_S_ECEFX,GNSS_S_ECEFY,GNSS_S_ECEFZ,GNSS_S_PACC,GNSS_S_ECEFVX,GNSS_S_ECEFVY,GNSS_S_ECEFVZ,GNSS_S_SACC,GNSS_S_PDOP,GNSS_S_NUMSV
2021/04/30 00:00:00.240000,432018000,-224400,2155,3,True,True,False,True,128760841,16575059,-678742965,551,600149,-463648,102460,22,121,16
2021/04/30 00:00:29.190000,432047000,-262606,2155,3,True,True,False,True,146069400,3086385,-675423725,359,593420,-466515,126126,21,123,15
2021/04/30 00:01:00.237000,432078000,-303441,2155,3,True,True,False,True,164345222,-11415926,-671121539,309,585545,-469025,151268,19,103,16
with open(os.path.join(testdata, "add-ephemerides", "bare_navsol.txt"), "r", encoding="utf-8") as fp:
navsol_lines = fp.readlines()
# With the following line, we make the NavSol data a single string
navsol = r'\n'.join(navsol_lines)
request = {
"ephemerides": {
"type": "navsol",
"content": {
"id": {
"type": "norad_id",
"content": 12345
},
"lines": navsol}
}
}
request_id = aether_api.get_request_id("add-ephemerides/requests", request)
result_format = "oem"
print(request_id)
result_url = f"add-ephemerides/results/{request_id}/{result_format}"
result_oem = aether_api.wait_for_request_result(result_url, max_retries=max_iter, retry_delay=wait_time)
if "orbit" in result_oem:
data = pd.DataFrame(result_oem["orbit"]["OEM_META_DATA_DATA"][0]["DATA"])
data["EPOCH"] = pd.to_datetime(data["EPOCH"])
fig, ax = plt.subplots(figsize=(25, 12))
ax.set_xlabel("Epoch", fontsize=24)
ax.set_ylabel("Residuals (km)", fontsize=24)
ax.set_title("Orbit determination residuals in GCRF", fontsize=26)
ax.tick_params(axis='both', labelsize=20)
ax.scatter(data["EPOCH"], data["USER_DEFINED_RESIDUAL_1"], label="I", s=6)
ax.scatter(data["EPOCH"], data["USER_DEFINED_RESIDUAL_2"], label="J", s=6)
ax.scatter(data["EPOCH"], data["USER_DEFINED_RESIDUAL_3"], label="K", s=6)
fig.legend(loc="upper right", fontsize=16, bbox_to_anchor=(0.9,0.88))
plt.show()
22684180-a5ef-41e6-85bb-53e01fe1c442