Init
This commit is contained in:
commit
56d058c2fd
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/target
|
||||
.env
|
1190
Cargo.lock
generated
Normal file
1190
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
13
Cargo.toml
Normal file
13
Cargo.toml
Normal file
@ -0,0 +1,13 @@
|
||||
[package]
|
||||
name = "satellit-ansage"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
dotenv = "0.15.0"
|
||||
reqwest = { version = "0.11.16", features = ["json"] }
|
||||
serde = { version = "1.0.160", features = ["derive"] }
|
||||
serde_json = "1.0.96"
|
||||
tokio = { version = "1.27.0", features = ["full"] }
|
19
src/main.rs
Normal file
19
src/main.rs
Normal file
@ -0,0 +1,19 @@
|
||||
use std::{env, error::Error};
|
||||
|
||||
use crate::n2yo::N2YO;
|
||||
|
||||
mod n2yo;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), Box<dyn Error>> {
|
||||
dotenv::dotenv().ok();
|
||||
let api_key = env::var("N2YO_API_KEY")?;
|
||||
|
||||
let n2yo = N2YO::new(api_key);
|
||||
|
||||
let tle = n2yo.tle(25544).await?;
|
||||
|
||||
println!("{}", tle.tle);
|
||||
|
||||
Ok(())
|
||||
}
|
199
src/n2yo/mod.rs
Normal file
199
src/n2yo/mod.rs
Normal file
@ -0,0 +1,199 @@
|
||||
use reqwest::Client;
|
||||
use serde::de::DeserializeOwned;
|
||||
|
||||
use self::proto::{Above, Positions, RadioPasses, VisualPasses, TLE};
|
||||
|
||||
mod proto;
|
||||
|
||||
const BASE_URL: &str = "https://api.n2yo.com/rest/v1/satellite";
|
||||
|
||||
pub struct N2YO {
|
||||
api_key: String,
|
||||
client: Client,
|
||||
}
|
||||
|
||||
type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;
|
||||
|
||||
impl N2YO {
|
||||
pub fn new(api_key: String) -> Self {
|
||||
Self {
|
||||
api_key,
|
||||
client: Client::new(),
|
||||
}
|
||||
}
|
||||
|
||||
async fn query<T: DeserializeOwned>(&self, s: &str) -> Result<T> {
|
||||
let result = self
|
||||
.client
|
||||
.get(s)
|
||||
.query(&[("apiKey", &self.api_key)])
|
||||
.send()
|
||||
.await?
|
||||
.json()
|
||||
.await?;
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
/// Get TLE
|
||||
///
|
||||
/// Retrieve the Two Line Elements (TLE) for a satellite identified by NORAD id.
|
||||
#[allow(dead_code)]
|
||||
pub async fn tle(&self, id: u64) -> Result<TLE> {
|
||||
self.query(&format!("{BASE_URL}/tle/{id}")).await
|
||||
}
|
||||
|
||||
/// Get satellite positions
|
||||
///
|
||||
/// Retrieve the future positions of any satellite as groundtrack (latitude, longitude) to display
|
||||
/// orbits on maps. Also return the satellite's azimuth and elevation with respect to the observer
|
||||
/// location. Each element in the response array is one second of calculation. First element is
|
||||
/// calculated for current UTC time.
|
||||
#[allow(dead_code)]
|
||||
pub async fn positions(
|
||||
&self,
|
||||
id: u64,
|
||||
lat: f64,
|
||||
lng: f64,
|
||||
alt: f64,
|
||||
seconds: u16,
|
||||
) -> Result<Positions> {
|
||||
self.query(&format!(
|
||||
"{BASE_URL}/positions/{id}/{lat}/{lng}/{alt}/{seconds}"
|
||||
))
|
||||
.await
|
||||
}
|
||||
|
||||
/// Get visual passes
|
||||
///
|
||||
/// Get predicted visual passes for any satellite relative to a location on Earth. A "visual pass"
|
||||
/// is a pass that should be optically visible on the entire (or partial) duration of crossing the
|
||||
/// sky. For that to happen, the satellite must be above the horizon, illumintaed by Sun (not in
|
||||
/// Earth shadow), and the sky dark enough to allow visual satellite observation.
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub async fn visual_passes(
|
||||
&self,
|
||||
id: u64,
|
||||
lat: f64,
|
||||
lng: f64,
|
||||
alt: f64,
|
||||
days: u8,
|
||||
min_visibility: u64,
|
||||
) -> Result<VisualPasses> {
|
||||
self.query(&format!(
|
||||
"{BASE_URL}/positions/{id}/{lat}/{lng}/{alt}/{days}/{min_visibility}"
|
||||
))
|
||||
.await
|
||||
}
|
||||
|
||||
/// Get radio passes
|
||||
///
|
||||
/// The "radio passes" are similar to "visual passes", the only difference being the requirement
|
||||
/// for the objects to be optically visible for observers. This function is useful mainly for
|
||||
/// predicting satellite passes to be used for radio communications. The quality of the pass depends
|
||||
/// essentially on the highest elevation value during the pass, which is one of the input parameters.
|
||||
#[allow(dead_code)]
|
||||
pub async fn radio_passes(
|
||||
&self,
|
||||
id: u64,
|
||||
lat: f64,
|
||||
lng: f64,
|
||||
alt: f64,
|
||||
days: u8,
|
||||
min_elevation: u64,
|
||||
) -> Result<RadioPasses> {
|
||||
self.query(&format!(
|
||||
"{BASE_URL}/positions/{id}/{lat}/{lng}/{alt}/{days}/{min_elevation}"
|
||||
))
|
||||
.await
|
||||
}
|
||||
|
||||
/// What's up?
|
||||
///
|
||||
/// The "above" function will return all objects within a given search radius above observer's location.
|
||||
/// The radius (θ), expressed in degrees, is measured relative to the point in the sky directly above
|
||||
/// an observer (azimuth). This image may offer a better explanation:
|
||||
///
|
||||
/// 
|
||||
///
|
||||
/// The search radius range is 0 to 90 degrees, nearly 0 meaning to show only satellites passing exactly
|
||||
/// above the observer location, while 90 degrees to return all satellites above the horizon. Since there
|
||||
/// are many satellites and debris in the sky at any point in time, the result could be filtered by
|
||||
/// satellite category (integer). The following categories are currently available at n2yo.com:
|
||||
///
|
||||
/// | Category | id |
|
||||
/// |----------|---:|
|
||||
/// |Amateur radio|18|
|
||||
/// |Beidou Navigation System|35|
|
||||
/// |Brightest|1|
|
||||
/// |Celestis|45|
|
||||
/// |Chinese Space Station|54|
|
||||
/// |CubeSats|32|
|
||||
/// |Disaster monitoring|8|
|
||||
/// |Earth resources|6|
|
||||
/// |Education|29|
|
||||
/// |Engineering|28|
|
||||
/// |Experimental|19|
|
||||
/// |Flock|48|
|
||||
/// |Galileo|22|
|
||||
/// |Geodetic|27|
|
||||
/// |Geostationary|10|
|
||||
/// |Global Positioning System (GPS) Constellation|50|
|
||||
/// |Global Positioning System (GPS) Operational|20|
|
||||
/// |Globalstar|17|
|
||||
/// |Glonass Constellation|51|
|
||||
/// |Glonass Operational|21|
|
||||
/// |GOES|5|
|
||||
/// |Gonets|40|
|
||||
/// |Gorizont|12|
|
||||
/// |Intelsat|11|
|
||||
/// |Iridium|15|
|
||||
/// IRNSS|46|
|
||||
/// ISS|2|
|
||||
/// Lemur|49|
|
||||
/// Military|30|
|
||||
/// Molniya|14|
|
||||
/// Navy Navigation Satellite System|24|
|
||||
/// NOAA|4|
|
||||
/// O3B Networks|43|
|
||||
/// OneWeb|53|
|
||||
/// Orbcomm|16|
|
||||
/// Parus|38|
|
||||
/// QZSS|47|
|
||||
/// Radar Calibration|31|
|
||||
/// Raduga|13|
|
||||
/// Russian LEO Navigation|25|
|
||||
/// Satellite-Based Augmentation System|23|
|
||||
/// Search & rescue|7|
|
||||
/// Space & Earth Science|26|
|
||||
/// Starlink|52|
|
||||
/// Strela|39|
|
||||
/// Tracking and Data Relay Satellite System|9|
|
||||
/// Tselina|44|
|
||||
/// Tsikada|42|
|
||||
/// Tsiklon|41|
|
||||
/// TV|34|
|
||||
/// Weather|3|
|
||||
/// Westford Needles|37|
|
||||
/// XM and Sirius|33|
|
||||
/// Yaogan|36|
|
||||
///
|
||||
/// Please use this function responsably as there is a lot of CPU needed in order to calculate exact
|
||||
/// positions for all satellites in the sky. The function will return altitude, latitude and longitude
|
||||
/// of satellites footprints to be displayed on a map, and some minimal information to identify the object.
|
||||
#[allow(dead_code)]
|
||||
pub async fn above(
|
||||
&self,
|
||||
lat: f64,
|
||||
lng: f64,
|
||||
alt: f64,
|
||||
search_radius: u8,
|
||||
category_id: u8,
|
||||
) -> Result<Above> {
|
||||
self.query(&format!(
|
||||
"{BASE_URL}/above/{lat}/{lng}/{alt}/{search_radius}/{category_id}"
|
||||
))
|
||||
.await
|
||||
}
|
||||
}
|
472
src/n2yo/proto.rs
Normal file
472
src/n2yo/proto.rs
Normal file
@ -0,0 +1,472 @@
|
||||
#![allow(clippy::upper_case_acronyms)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
use serde::Deserialize;
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct Info {
|
||||
/// NORAD id used in input
|
||||
#[serde(rename = "satid")]
|
||||
pub sat_id: u64,
|
||||
|
||||
/// Satellite name
|
||||
#[serde(rename = "satname")]
|
||||
pub sat_name: String,
|
||||
|
||||
/// Count of transactions performed with this API key in last 60 minutes
|
||||
#[serde(rename = "transactionscount")]
|
||||
pub transaction_count: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct TLE {
|
||||
pub info: Info,
|
||||
/// TLE on single line string. Split the line in two by \r\n to get original two lines
|
||||
pub tle: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct Positions {
|
||||
pub info: Info,
|
||||
pub positions: Vec<Position>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct Position {
|
||||
/// Satellite footprint latitude (decimal degrees format)
|
||||
#[serde(rename = "satlatitude")]
|
||||
pub sat_latitude: f64,
|
||||
|
||||
/// Satellite footprint longitude (decimal degrees format)
|
||||
#[serde(rename = "satlongitude")]
|
||||
pub sat_longitude: f64,
|
||||
|
||||
#[serde(rename = "sataltitude")]
|
||||
pub sat_altitude: f64,
|
||||
|
||||
/// Satellite azimuth with respect to observer's location (degrees)
|
||||
pub azimuth: f64,
|
||||
|
||||
/// Satellite elevation with respect to observer's location (degrees)
|
||||
pub elevation: f64,
|
||||
|
||||
/// Satellite right ascension (degrees)
|
||||
pub ra: f64,
|
||||
|
||||
/// Satellite declination (degrees)
|
||||
pub dec: f64,
|
||||
|
||||
/// Unix time for this position (seconds). You should convert this UTC value to observer's time zone
|
||||
pub timestamp: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct PassInfo {
|
||||
/// NORAD id used in input
|
||||
#[serde(rename = "satid")]
|
||||
pub sat_id: u64,
|
||||
|
||||
/// Satellite name
|
||||
#[serde(rename = "satname")]
|
||||
pub sat_name: String,
|
||||
|
||||
/// Count of transactions performed with this API key in last 60 minutes
|
||||
#[serde(rename = "transactionscount")]
|
||||
pub transaction_count: u64,
|
||||
|
||||
/// Count of passes returned
|
||||
#[serde(rename = "passescount")]
|
||||
pub pass_count: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub enum Compass {
|
||||
N,
|
||||
NNE,
|
||||
NE,
|
||||
ENE,
|
||||
E,
|
||||
ESE,
|
||||
SE,
|
||||
SSE,
|
||||
S,
|
||||
SSW,
|
||||
SW,
|
||||
WSW,
|
||||
W,
|
||||
WNW,
|
||||
NW,
|
||||
NNW,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct VisualPasses {
|
||||
pub info: PassInfo,
|
||||
pub passes: Option<Vec<VisualPass>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct VisualPass {
|
||||
// start
|
||||
/// Satellite azimuth for the start of this pass (relative to the observer, in degrees)
|
||||
#[serde(rename = "startAz")]
|
||||
pub start_az: f64,
|
||||
|
||||
/// Satellite azimuth for the start of this pass (relative to the observer). Possible values: N, NE, E, SE, S, SW, W, NW
|
||||
#[serde(rename = "startAzCompass")]
|
||||
pub start_az_compass: Compass,
|
||||
|
||||
/// Satellite elevation for the start of this pass (relative to the observer, in degrees)
|
||||
#[serde(rename = "startEl")]
|
||||
pub start_el: f64,
|
||||
|
||||
/// Unix time for the start of this pass. You should convert this UTC value to observer's time zone
|
||||
#[serde(rename = "startUTC")]
|
||||
pub start_utc: u64,
|
||||
|
||||
// max
|
||||
/// Satellite azimuth for the max elevation of this pass (relative to the observer, in degrees)
|
||||
#[serde(rename = "maxAz")]
|
||||
pub max_az: f64,
|
||||
|
||||
/// Satellite azimuth for the max elevation of this pass (relative to the observer). Possible values: N, NE, E, SE, S, SW, W, NW
|
||||
#[serde(rename = "maxAzCompass")]
|
||||
pub max_az_compass: Compass,
|
||||
|
||||
/// Satellite max elevation for this pass (relative to the observer, in degrees)
|
||||
#[serde(rename = "maxEl")]
|
||||
pub max_el: f64,
|
||||
|
||||
/// Unix time for the max elevation of this pass. You should convert this UTC value to observer's time zone
|
||||
#[serde(rename = "maxUTC")]
|
||||
pub max_utc: u64,
|
||||
|
||||
// end
|
||||
/// Satellite azimuth for the end of this pass (relative to the observer, in degrees)
|
||||
#[serde(rename = "endAz")]
|
||||
pub end_az: f64,
|
||||
|
||||
/// Satellite azimuth for the end of this pass (relative to the observer). Possible values: N, NE, E, SE, S, SW, W, NW
|
||||
#[serde(rename = "endAzCompass")]
|
||||
pub end_az_compass: Compass,
|
||||
|
||||
/// Satellite elevation for the end of this pass (relative to the observer, in degrees)
|
||||
#[serde(rename = "endEl")]
|
||||
pub end_el: f64,
|
||||
|
||||
/// Unix time for the end of this pass. You should convert this UTC value to observer's time zone
|
||||
#[serde(rename = "endUTC")]
|
||||
pub end_utc: u64,
|
||||
|
||||
/// Max visual magnitude of the pass, same scale as star brightness. If magnitude cannot be determined, the value is 100000
|
||||
pub mag: f64,
|
||||
|
||||
/// Total visible duration of this pass (in seconds)
|
||||
pub duration: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct RadioPasses {
|
||||
pub info: PassInfo,
|
||||
pub passes: Option<Vec<RadioPass>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct RadioPass {
|
||||
// start
|
||||
/// Satellite azimuth for the start of this pass (relative to the observer, in degrees)
|
||||
#[serde(rename = "startAz")]
|
||||
pub start_az: f64,
|
||||
|
||||
/// Satellite azimuth for the start of this pass (relative to the observer). Possible values: N, NE, E, SE, S, SW, W, NW
|
||||
#[serde(rename = "startAzCompass")]
|
||||
pub start_az_compass: Compass,
|
||||
|
||||
/// Unix time for the start of this pass. You should convert this UTC value to observer's time zone
|
||||
#[serde(rename = "startUTC")]
|
||||
pub start_utc: u64,
|
||||
|
||||
// max
|
||||
/// Satellite azimuth for the max elevation of this pass (relative to the observer, in degrees)
|
||||
#[serde(rename = "maxAz")]
|
||||
pub max_az: f64,
|
||||
|
||||
/// Satellite azimuth for the max elevation of this pass (relative to the observer). Possible values: N, NE, E, SE, S, SW, W, NW
|
||||
#[serde(rename = "maxAzCompass")]
|
||||
pub max_az_compass: Compass,
|
||||
|
||||
/// Satellite max elevation for this pass (relative to the observer, in degrees)
|
||||
#[serde(rename = "maxEl")]
|
||||
pub max_el: f64,
|
||||
|
||||
/// Unix time for the max elevation of this pass. You should convert this UTC value to observer's time zone
|
||||
#[serde(rename = "maxUTC")]
|
||||
pub max_utc: u64,
|
||||
|
||||
// end
|
||||
/// Satellite azimuth for the end of this pass (relative to the observer, in degrees)
|
||||
#[serde(rename = "endAz")]
|
||||
pub end_az: f64,
|
||||
|
||||
/// Satellite azimuth for the end of this pass (relative to the observer). Possible values: N, NE, E, SE, S, SW, W, NW
|
||||
#[serde(rename = "endAzCompass")]
|
||||
pub end_az_compass: Compass,
|
||||
|
||||
/// Unix time for the end of this pass. You should convert this UTC value to observer's time zone
|
||||
#[serde(rename = "endUTC")]
|
||||
pub end_utc: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct Above {
|
||||
pub info: AboveInfo,
|
||||
pub above: Option<Vec<AboveSat>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct AboveInfo {
|
||||
/// Category name (ANY if category id requested was 0)
|
||||
pub category: String,
|
||||
|
||||
/// Count of transactions performed with this API key in last 60 minutes
|
||||
#[serde(rename = "transactionscount")]
|
||||
pub transaction_count: u64,
|
||||
|
||||
/// Count of satellites returned
|
||||
#[serde(rename = "satcount")]
|
||||
pub sat_count: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct AboveSat {
|
||||
/// Satellite NORAD id
|
||||
#[serde(rename = "satid")]
|
||||
pub sat_id: u64,
|
||||
|
||||
/// Satellite international designator
|
||||
#[serde(rename = "satname")]
|
||||
pub sat_name: String,
|
||||
|
||||
/// Satellite name
|
||||
#[serde(rename = "intDesignator")]
|
||||
pub int_designator: String,
|
||||
|
||||
/// Satellite launch date (YYYY-MM-DD)
|
||||
#[serde(rename = "launchDate")]
|
||||
pub launch_date: String,
|
||||
|
||||
/// Satellite footprint latitude (decimal degrees format)
|
||||
#[serde(rename = "satlat")]
|
||||
pub sat_lat: f64,
|
||||
|
||||
/// Satellite footprint longitude (decimal degrees format)
|
||||
#[serde(rename = "satlng")]
|
||||
pub sat_lng: f64,
|
||||
|
||||
/// Satellite altitude (km)
|
||||
#[serde(rename = "satalt")]
|
||||
pub sat_alt: f64,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_tle() {
|
||||
let data = r#"{
|
||||
"info": {
|
||||
"satid": 25544,
|
||||
"satname": "SPACE STATION",
|
||||
"transactionscount": 4
|
||||
},
|
||||
"tle": "1 25544U 98067A 18077.09047010 .00001878 00000-0 35621-4 0 9999\r\n2 25544 51.6412 112.8495 0001928 208.4187 178.9720 15.54106440104358"
|
||||
}"#;
|
||||
|
||||
let parsed = serde_json::from_str::<TLE>(data);
|
||||
assert!(parsed.is_ok())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_positions() {
|
||||
let data = r#"{
|
||||
"info": {
|
||||
"satname": "SPACE STATION",
|
||||
"satid": 25544,
|
||||
"transactionscount": 5
|
||||
},
|
||||
"positions": [
|
||||
{
|
||||
"satlatitude": -39.90318514,
|
||||
"satlongitude": 158.28897924,
|
||||
"sataltitude": 417.85,
|
||||
"azimuth": 254.31,
|
||||
"elevation": -69.09,
|
||||
"ra": 44.77078138,
|
||||
"dec": -43.99279118,
|
||||
"timestamp": 1521354418
|
||||
},
|
||||
{
|
||||
"satlatitude": -39.86493451,
|
||||
"satlongitude": 158.35261287,
|
||||
"sataltitude": 417.84,
|
||||
"azimuth": 254.33,
|
||||
"elevation": -69.06,
|
||||
"ra": 44.81676119,
|
||||
"dec": -43.98086419,
|
||||
"timestamp": 1521354419
|
||||
}
|
||||
]
|
||||
}"#;
|
||||
|
||||
let parsed = serde_json::from_str::<Positions>(data);
|
||||
assert!(parsed.is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_visualpasses() {
|
||||
let data = r#"{
|
||||
"info": {
|
||||
"satid": 25544,
|
||||
"satname": "SPACE STATION",
|
||||
"transactionscount": 4,
|
||||
"passescount": 3
|
||||
},
|
||||
"passes": [
|
||||
{
|
||||
"startAz": 307.21,
|
||||
"startAzCompass": "NW",
|
||||
"startEl": 13.08,
|
||||
"startUTC": 1521368025,
|
||||
"maxAz": 225.45,
|
||||
"maxAzCompass": "SW",
|
||||
"maxEl": 78.27,
|
||||
"maxUTC": 1521368345,
|
||||
"endAz": 132.82,
|
||||
"endAzCompass": "SE",
|
||||
"endEl": 0,
|
||||
"endUTC": 1521368660,
|
||||
"mag": -2.4,
|
||||
"duration": 485
|
||||
},
|
||||
{
|
||||
"startAz": 311.56,
|
||||
"startAzCompass": "NW",
|
||||
"startEl": 50.94,
|
||||
"startUTC": 1521451295,
|
||||
"maxAz": 37.91,
|
||||
"maxAzCompass": "NE",
|
||||
"maxEl": 52.21,
|
||||
"maxUTC": 1521451615,
|
||||
"endAz": 118.61,
|
||||
"endAzCompass": "ESE",
|
||||
"endEl": 0,
|
||||
"endUTC": 1521451925,
|
||||
"mag": -2,
|
||||
"duration": 325
|
||||
},
|
||||
{
|
||||
"startAz": 291.06,
|
||||
"startAzCompass": "WNW",
|
||||
"startEl": 3.47,
|
||||
"startUTC": 1521457105,
|
||||
"maxAz": 231.58,
|
||||
"maxAzCompass": "SW",
|
||||
"maxEl": 14.75,
|
||||
"maxUTC": 1521457380,
|
||||
"endAz": 170.63,
|
||||
"endAzCompass": "S",
|
||||
"endEl": 0,
|
||||
"endUTC": 1521457650,
|
||||
"mag": -0.1,
|
||||
"duration": 485
|
||||
}
|
||||
]
|
||||
}"#;
|
||||
|
||||
let parsed = serde_json::from_str::<VisualPasses>(data);
|
||||
assert!(parsed.is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_radiopasses() {
|
||||
let data = r#"{
|
||||
"info": {
|
||||
"satid": 25544,
|
||||
"satname": "SPACE STATION",
|
||||
"transactionscount": 2,
|
||||
"passescount": 2
|
||||
},
|
||||
"passes": [
|
||||
{
|
||||
"startAz": 311.57,
|
||||
"startAzCompass": "NW",
|
||||
"startUTC": 1521451295,
|
||||
"maxAz": 37.98,
|
||||
"maxAzCompass": "NE",
|
||||
"maxEl": 52.19,
|
||||
"maxUTC": 1521451615,
|
||||
"endAz": 118.6,
|
||||
"endAzCompass": "ESE",
|
||||
"endUTC": 1521451925
|
||||
},
|
||||
{
|
||||
"startAz": 242.34,
|
||||
"startAzCompass": "WSW",
|
||||
"startUTC": 1521600275,
|
||||
"maxAz": 328.03,
|
||||
"maxAzCompass": "NW",
|
||||
"maxEl": 49.59,
|
||||
"maxUTC": 1521600595,
|
||||
"endAz": 47.97,
|
||||
"endAzCompass": "NE",
|
||||
"endUTC": 1521600905
|
||||
}
|
||||
]
|
||||
}"#;
|
||||
let parsed = serde_json::from_str::<RadioPasses>(data);
|
||||
assert!(parsed.is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_above() {
|
||||
let data = r#"{
|
||||
"info": {
|
||||
"category": "Amateur radio",
|
||||
"transactionscount": 17,
|
||||
"satcount": 3
|
||||
},
|
||||
"above": [
|
||||
{
|
||||
"satid": 20480,
|
||||
"satname": "JAS 1B (FUJI 2)",
|
||||
"intDesignator": "1990-013C",
|
||||
"launchDate": "1990-02-07",
|
||||
"satlat": 49.5744,
|
||||
"satlng": -96.7081,
|
||||
"satalt": 1227.9326
|
||||
},
|
||||
{
|
||||
"satid": 26609,
|
||||
"satname": "AMSAT OSCAR 40",
|
||||
"intDesignator": "2000-072B",
|
||||
"launchDate": "2000-11-16",
|
||||
"satlat": 5.5105,
|
||||
"satlng": -21.4478,
|
||||
"satalt": 49678.6389
|
||||
},
|
||||
{
|
||||
"satid": 40719,
|
||||
"satname": "DEORBITSAIL",
|
||||
"intDesignator": "2015-032E",
|
||||
"launchDate": "2015-07-10",
|
||||
"satlat": 43.8106,
|
||||
"satlng": -90.3944,
|
||||
"satalt": 657.5516
|
||||
}
|
||||
]
|
||||
}"#;
|
||||
let parsed = serde_json::from_str::<Above>(data);
|
||||
assert!(parsed.is_ok());
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user