diff --git a/Cargo.lock b/Cargo.lock index 1c07ef7..f2e6a0a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -174,6 +174,17 @@ dependencies = [ "pin-utils", ] +[[package]] +name = "getrandom" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + [[package]] name = "h2" version = "0.3.17" @@ -383,6 +394,12 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + [[package]] name = "mime" version = "0.3.17" @@ -429,6 +446,15 @@ dependencies = [ "libc", ] +[[package]] +name = "num_threads" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" +dependencies = [ + "libc", +] + [[package]] name = "once_cell" version = "1.17.1" @@ -502,12 +528,59 @@ dependencies = [ "windows-sys 0.45.0", ] +[[package]] +name = "parse-zoneinfo" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c705f256449c60da65e11ff6626e0c16a0a0b96aaa348de61376b249bc340f41" +dependencies = [ + "regex", +] + [[package]] name = "percent-encoding" version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" +[[package]] +name = "phf" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259" +dependencies = [ + "phf_shared", +] + +[[package]] +name = "phf_codegen" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb1c3a8bc4dd4e5cfce29b44ffc14bedd2ee294559a294e2a4d4c9e9a6a13cd" +dependencies = [ + "phf_generator", + "phf_shared", +] + +[[package]] +name = "phf_generator" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6" +dependencies = [ + "phf_shared", + "rand", +] + +[[package]] +name = "phf_shared" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" +dependencies = [ + "siphasher", +] + [[package]] name = "pin-project-lite" version = "0.2.9" @@ -526,6 +599,12 @@ version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + [[package]] name = "proc-macro2" version = "1.0.56" @@ -544,6 +623,36 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + [[package]] name = "redox_syscall" version = "0.2.16" @@ -562,6 +671,21 @@ dependencies = [ "bitflags", ] +[[package]] +name = "regex" +version = "1.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b1f693b24f6ac912f4893ef08244d70b6067480d2f1a46e950c9691e6749d1d" +dependencies = [ + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + [[package]] name = "reqwest" version = "0.11.16" @@ -627,7 +751,10 @@ dependencies = [ "reqwest", "serde", "serde_json", + "time", + "time-tz", "tokio", + "toml", ] [[package]] @@ -677,6 +804,18 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "serde-xml-rs" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65162e9059be2f6a3421ebbb4fef3e74b7d9e7c60c50a0e292c6239f19f1edfa" +dependencies = [ + "log", + "serde", + "thiserror", + "xml-rs", +] + [[package]] name = "serde_derive" version = "1.0.160" @@ -699,6 +838,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_spanned" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0efd8caf556a6cebd3b285caf480045fcc1ac04f6bd786b09a6f11af30c4fcf4" +dependencies = [ + "serde", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -720,6 +868,12 @@ dependencies = [ "libc", ] +[[package]] +name = "siphasher" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" + [[package]] name = "slab" version = "0.4.8" @@ -780,6 +934,69 @@ dependencies = [ "windows-sys 0.45.0", ] +[[package]] +name = "thiserror" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.15", +] + +[[package]] +name = "time" +version = "0.3.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd0cbfecb4d19b5ea75bb31ad904eb5b9fa13f21079c3b92017ebdf4999a5890" +dependencies = [ + "libc", + "num_threads", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" + +[[package]] +name = "time-macros" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd80a657e71da814b8e5d60d3374fc6d35045062245d80224748ae522dd76f36" +dependencies = [ + "time-core", +] + +[[package]] +name = "time-tz" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "980bd5c9ec52d862803a716b6f3913881910e96124a618a9a0679a984d5c361d" +dependencies = [ + "cfg-if", + "parse-zoneinfo", + "phf", + "phf_codegen", + "serde", + "serde-xml-rs", + "time", +] + [[package]] name = "tinyvec" version = "1.6.0" @@ -849,6 +1066,40 @@ dependencies = [ "tracing", ] +[[package]] +name = "toml" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b403acf6f2bb0859c93c7f0d967cb4a75a7ac552100f9322faf64dc047669b21" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ab8ed2edee10b50132aed5f331333428b011c99402b5a534154ed15746f9622" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.19.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "239410c8609e8125456927e6707163a3b1fdb40561e4b803bc041f466ccfdc13" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + [[package]] name = "tower-service" version = "0.3.2" @@ -1180,6 +1431,15 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +[[package]] +name = "winnow" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae8970b36c66498d8ff1d66685dc86b91b29db0c7739899012f63a63814b4b28" +dependencies = [ + "memchr", +] + [[package]] name = "winreg" version = "0.10.1" @@ -1188,3 +1448,9 @@ checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" dependencies = [ "winapi", ] + +[[package]] +name = "xml-rs" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3" diff --git a/Cargo.toml b/Cargo.toml index fdab461..e8ea8e7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,4 +10,7 @@ dotenv = "0.15.0" reqwest = { version = "0.11.16", features = ["json"] } serde = { version = "1.0.160", features = ["derive"] } serde_json = "1.0.96" +time = { version = "0.3.20", features = ["local-offset"] } +time-tz = { version = "1.0.2", features = ["db"] } tokio = { version = "1.27.0", features = ["full"] } +toml = { version = "0.7.3", features = ["parse"] } diff --git a/config.toml b/config.toml new file mode 100644 index 0000000..e8e2a0c --- /dev/null +++ b/config.toml @@ -0,0 +1,22 @@ +[observer] +# UdS +latitude = 49.2550319 +longitude = 7.0384001 +altitude = 0 # ? +timezone = "Europe/Berlin" + +[satellites."Meteor M2"] +norad = 40069 +downlink = ["137.1", "137.925"] + +[satellites."NOAA 15"] +norad = 25338 +downlink = ["137.62"] + +[satellites."NOAA 18"] +norad = 28654 +downlink = ["137.9125"] + +[satellites."NOAA 19"] +norad = 33591 +downlink = ["137.1"] \ No newline at end of file diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 0000000..8ba32d2 --- /dev/null +++ b/src/config.rs @@ -0,0 +1,31 @@ +use std::{collections::HashMap, fs}; + +use crate::util::Result; +use serde::Deserialize; + +#[derive(Debug, Deserialize)] +pub struct Config { + pub observer: Observer, + pub satellites: HashMap, +} + +#[derive(Debug, Deserialize)] +pub struct Observer { + pub latitude: f64, + pub longitude: f64, + pub altitude: f64, + pub timezone: String, +} + +#[derive(Debug, Deserialize)] +pub struct Satellite { + pub norad: u64, + pub downlink: Vec, +} + +impl Config { + pub fn from_file(filename: &str) -> Result { + let content = fs::read_to_string(filename)?; + Ok(toml::from_str(&content)?) + } +} diff --git a/src/main.rs b/src/main.rs index d4ad9fc..0f8ad5c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,19 +1,55 @@ use std::{env, error::Error}; +use config::Config; +use time::OffsetDateTime; +use time_tz::{timezones, OffsetDateTimeExt}; + use crate::n2yo::N2YO; +mod config; mod n2yo; +mod util; #[tokio::main] async fn main() -> Result<(), Box> { dotenv::dotenv().ok(); let api_key = env::var("N2YO_API_KEY")?; + let config_file = env::var("CONFIG_FILE").unwrap_or("config.toml".into()); + + let config = Config::from_file(&config_file)?; let n2yo = N2YO::new(api_key); - let tle = n2yo.tle(25544).await?; + let tz = timezones::get_by_name(&config.observer.timezone) + .ok_or("Could not find observer timezone")?; - println!("{}", tle.tle); + for (name, sat) in &config.satellites { + println!("[{}] {}", sat.norad, name); + let passes = n2yo + .radio_passes( + sat.norad, + config.observer.latitude, + config.observer.longitude, + config.observer.altitude, + 1, + 0, + ) + .await?; + + if let Some(passes) = passes.passes { + for pass in passes { + let start = OffsetDateTime::from_unix_timestamp(pass.start_utc as i64)?; + let end = OffsetDateTime::from_unix_timestamp(pass.end_utc as i64)?; + + let (h1, m1, s1) = start.to_timezone(tz).to_hms(); + let (h2, m2, s2) = end.to_timezone(tz).to_hms(); + + println!("Pass from {:02}:{:02}:{:02} to {:02}:{:02}:{:02}", h1, m1, s1, h2, m2, s2,); + } + } else { + println!("No passes :("); + } + } Ok(()) } diff --git a/src/n2yo/mod.rs b/src/n2yo/mod.rs index 7f0c549..2b75540 100644 --- a/src/n2yo/mod.rs +++ b/src/n2yo/mod.rs @@ -2,6 +2,7 @@ use reqwest::Client; use serde::de::DeserializeOwned; use self::proto::{Above, Positions, RadioPasses, VisualPasses, TLE}; +use crate::util::Result; mod proto; @@ -12,8 +13,6 @@ pub struct N2YO { client: Client, } -type Result = std::result::Result>; - impl N2YO { pub fn new(api_key: String) -> Self { Self { @@ -23,16 +22,14 @@ impl N2YO { } async fn query(&self, s: &str) -> Result { - let result = self + Ok(self .client .get(s) .query(&[("apiKey", &self.api_key)]) .send() .await? .json() - .await?; - - Ok(result) + .await?) } /// Get TLE @@ -82,7 +79,7 @@ impl N2YO { min_visibility: u64, ) -> Result { self.query(&format!( - "{BASE_URL}/positions/{id}/{lat}/{lng}/{alt}/{days}/{min_visibility}" + "{BASE_URL}/visualpasses/{id}/{lat}/{lng}/{alt}/{days}/{min_visibility}" )) .await } @@ -104,7 +101,7 @@ impl N2YO { min_elevation: u64, ) -> Result { self.query(&format!( - "{BASE_URL}/positions/{id}/{lat}/{lng}/{alt}/{days}/{min_elevation}" + "{BASE_URL}/radiopasses/{id}/{lat}/{lng}/{alt}/{days}/{min_elevation}" )) .await } diff --git a/src/util.rs b/src/util.rs new file mode 100644 index 0000000..708451d --- /dev/null +++ b/src/util.rs @@ -0,0 +1 @@ +pub type Result = std::result::Result>;