Skip to content

Commit

Permalink
extend weather block to show sunset and sunrise (#2028)
Browse files Browse the repository at this point in the history
* block[weather]: add sunrise/sunset

* block[weather]: Add sunrise/sunset to nws

---------

Co-authored-by: Simen Mailund Svendsen <[email protected]>
Co-authored-by: Bryan Malyn <[email protected]>
  • Loading branch information
3 people authored Nov 15, 2024
1 parent 8f6aad0 commit 08139b9
Show file tree
Hide file tree
Showing 6 changed files with 115 additions and 24 deletions.
10 changes: 10 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ shellexpand = "3.0"
signal-hook = "0.3"
signal-hook-tokio = { version = "0.3", features = ["futures-v0_3"] }
smart-default = "0.7"
sunrise-next = "1.2.3"
swayipc-async = "2.0"
thiserror = "1.0"
toml = { version = "0.8", features = ["preserve_order"] }
Expand Down
64 changes: 51 additions & 13 deletions src/blocks/weather.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,18 +70,20 @@
//!
//! # Available Format Keys
//!
//! Key | Value | Type | Unit
//! ---------------------------------------------|-------------------------------------------------------------------------------|--------|-----
//! `location` | Location name (exact format depends on the service) | Text | -
//! `icon{,_ffin}` | Icon representing the weather | Icon | -
//! `weather{,_ffin}` | Textual brief description of the weather, e.g. "Raining" | Text | -
//! `weather_verbose{,_ffin}` | Textual verbose description of the weather, e.g. "overcast clouds" | Text | -
//! `temp{,_{favg,fmin,fmax,ffin}}` | Temperature | Number | degrees
//! `apparent{,_{favg,fmin,fmax,ffin}}` | Australian Apparent Temperature | Number | degrees
//! `humidity{,_{favg,fmin,fmax,ffin}}` | Humidity | Number | %
//! `wind{,_{favg,fmin,fmax,ffin}}` | Wind speed | Number | -
//! `wind_kmh{,_{favg,fmin,fmax,ffin}}` | Wind speed. The wind speed in km/h | Number | -
//! `direction{,_{favg,fmin,fmax,ffin}}` | Wind direction, e.g. "NE" | Text | -
//! Key | Value | Type | Unit
//! ---------------------------------------------|-------------------------------------------------------------------------------|----------|-----
//! `location` | Location name (exact format depends on the service) | Text | -
//! `icon{,_ffin}` | Icon representing the weather | Icon | -
//! `weather{,_ffin}` | Textual brief description of the weather, e.g. "Raining" | Text | -
//! `weather_verbose{,_ffin}` | Textual verbose description of the weather, e.g. "overcast clouds" | Text | -
//! `temp{,_{favg,fmin,fmax,ffin}}` | Temperature | Number | degrees
//! `apparent{,_{favg,fmin,fmax,ffin}}` | Australian Apparent Temperature | Number | degrees
//! `humidity{,_{favg,fmin,fmax,ffin}}` | Humidity | Number | %
//! `wind{,_{favg,fmin,fmax,ffin}}` | Wind speed | Number | -
//! `wind_kmh{,_{favg,fmin,fmax,ffin}}` | Wind speed. The wind speed in km/h | Number | -
//! `direction{,_{favg,fmin,fmax,ffin}}` | Wind direction, e.g. "NE" | Text | -
//! `sunrise` | Time of sunrise | DateTime | -
//! `sunset` | Time of sunset | DateTime | -
//!
//! You can use the suffixes noted above to get the following:
//!
Expand All @@ -97,7 +99,7 @@
//! ----------------|-------------------------------------------|---------------
//! `toggle_format` | Toggles between `format` and `format_alt` | Left
//!
//! # Example
//! # Examples
//!
//! Show detailed weather in San Francisco through the OpenWeatherMap service:
//!
Expand All @@ -114,6 +116,17 @@
//! forecast_hours = 9
//! ```
//!
//! Show sunrise and sunset times in null island
//!
//! ```toml
//! [[block]]
//! block = "weather"
//! format = "up $sunrise.datetime(f:'%R') down $sunset.datetime(f:'%R')"
//! [block.service]
//! name = "metno"
//! coordinates = ["0", "0"]
//! ```
//!
//! # Used Icons
//!
//! - `weather_sun` (when weather is reported as "Clear" during the day)
Expand All @@ -132,6 +145,9 @@ use std::fmt;
use std::sync::{Arc, Mutex};
use std::time::Instant;

use chrono::{DateTime, Datelike, Utc};
use sunrise::{SolarDay, SolarEvent};

use crate::formatting::Format;

use super::prelude::*;
Expand Down Expand Up @@ -255,6 +271,8 @@ struct WeatherResult {
location: String,
current_weather: WeatherMoment,
forecast: Option<Forecast>,
sunrise: DateTime<Utc>,
sunset: DateTime<Utc>,
}

impl WeatherResult {
Expand All @@ -271,6 +289,8 @@ impl WeatherResult {
"wind" => Value::number(self.current_weather.wind),
"wind_kmh" => Value::number(self.current_weather.wind_kmh),
"direction" => Value::text(convert_wind_direction(self.current_weather.wind_direction).into()),
"sunrise" => Value::datetime(self.sunrise, None),
"sunset" => Value::datetime(self.sunset, None),
};

if let Some(forecast) = self.forecast {
Expand Down Expand Up @@ -301,6 +321,7 @@ impl WeatherResult {
"weather_verbose_ffin" => Value::text(forecast.fin.weather_verbose.clone()),
}
}

values
}
}
Expand Down Expand Up @@ -499,6 +520,23 @@ fn need_forecast(format: &Format, format_alt: Option<&Format>) -> bool {
has_forecast_key(format) || format_alt.is_some_and(has_forecast_key)
}

fn calculate_sunrise_sunset(
lat: f64,
lon: f64,
altitude: Option<f64>,
) -> Result<(DateTime<Utc>, DateTime<Utc>)> {
let date = Utc::now();
let solar_day = SolarDay::new(lat, lon, date.year(), date.month(), date.day())
.with_altitude(altitude.unwrap_or_default());

Ok((
DateTime::<Utc>::from_timestamp(solar_day.event_time(SolarEvent::Sunrise), 0)
.error("Unable to convert timestamp to DateTime")?,
DateTime::<Utc>::from_timestamp(solar_day.event_time(SolarEvent::Sunset), 0)
.error("Unable to convert timestamp to DateTime")?,
))
}

#[derive(Debug, Deserialize, Clone, Copy, PartialEq, Eq, SmartDefault)]
#[serde(rename_all = "lowercase")]
enum UnitSystem {
Expand Down
20 changes: 18 additions & 2 deletions src/blocks/weather/met_no.rs
Original file line number Diff line number Diff line change
Expand Up @@ -189,9 +189,21 @@ impl WeatherProvider for Service<'_> {
.or_else(|| self.config.coordinates.clone())
.error("No location given")?;

let altitude = if let Some(altitude) = &self.config.altitude {
Some(altitude.parse().error("Unable to convert string to f64")?)
} else {
None
};

let (sunrise, sunset) = calculate_sunrise_sunset(
lat.parse().error("Unable to convert string to f64")?,
lon.parse().error("Unable to convert string to f64")?,
altitude,
)?;

let querystr: HashMap<&str, String> = map! {
"lat" => lat,
"lon" => lon,
"lat" => &lat,
"lon" => &lon,
[if let Some(alt) = &self.config.altitude] "altitude" => alt,
};

Expand All @@ -216,6 +228,8 @@ impl WeatherProvider for Service<'_> {
location: location_name,
current_weather,
forecast: None,
sunrise,
sunset,
});
}

Expand All @@ -241,6 +255,8 @@ impl WeatherProvider for Service<'_> {
location: location_name,
current_weather,
forecast,
sunset,
sunrise,
})
}
}
Expand Down
33 changes: 24 additions & 9 deletions src/blocks/weather/nws.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ pub struct Config {
struct LocationInfo {
query: String,
name: String,
lat: f64,
lon: f64,
}

pub(super) struct Service<'a> {
Expand All @@ -45,12 +47,19 @@ impl<'a> Service<'a> {
None
} else {
let coords = config.coordinates.as_ref().error("no location given")?;
Some(Self::get_location_query(&coords.0, &coords.1, config.units).await?)
Some(
Self::get_location_query(
coords.0.parse().error("Unable to convert string to f64")?,
coords.1.parse().error("Unable to convert string to f64")?,
config.units,
)
.await?,
)
};
Ok(Self { config, location })
}

async fn get_location_query(lat: &str, lon: &str, units: UnitSystem) -> Result<LocationInfo> {
async fn get_location_query(lat: f64, lon: f64, units: UnitSystem) -> Result<LocationInfo> {
let points_url = format!("{API_URL}/points/{lat},{lon}");

let response: ApiPoints = REQWEST_CLIENT
Expand All @@ -68,7 +77,12 @@ impl<'a> Service<'a> {
});
let location = response.properties.relative_location.properties;
let name = format!("{}, {}", location.city, location.state);
Ok(LocationInfo { query, name })
Ok(LocationInfo {
query,
name,
lat,
lon,
})
}
}

Expand Down Expand Up @@ -233,16 +247,13 @@ impl WeatherProvider for Service<'_> {
need_forecast: bool,
) -> Result<WeatherResult> {
let location = if let Some(coords) = autolocated {
Self::get_location_query(
&coords.latitude.to_string(),
&coords.longitude.to_string(),
self.config.units,
)
.await?
Self::get_location_query(coords.latitude, coords.longitude, self.config.units).await?
} else {
self.location.clone().error("No location was provided")?
};

let (sunrise, sunset) = calculate_sunrise_sunset(location.lat, location.lon, None)?;

let data: ApiForecastResponse = REQWEST_CLIENT
.get(location.query)
.header(
Expand All @@ -264,6 +275,8 @@ impl WeatherProvider for Service<'_> {
location: location.name,
current_weather,
forecast: None,
sunrise,
sunset,
});
}

Expand All @@ -281,6 +294,8 @@ impl WeatherProvider for Service<'_> {
location: location.name,
current_weather,
forecast,
sunrise,
sunset,
})
}
}
Expand Down
11 changes: 11 additions & 0 deletions src/blocks/weather/open_weather_map.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use super::*;
use chrono::{DateTime, Utc};
use serde::{de, Deserializer};

pub(super) const GEO_URL: &str = "https://api.openweathermap.org/geo/1.0";
Expand Down Expand Up @@ -274,11 +275,19 @@ impl WeatherProvider for Service<'_> {

let current_weather = current_data.to_moment(self.units);

let sunrise = DateTime::<Utc>::from_timestamp(current_data.sys.sunrise, 0)
.error("Unable to convert timestamp to DateTime")?;

let sunset = DateTime::<Utc>::from_timestamp(current_data.sys.sunset, 0)
.error("Unable to convert timestamp to DateTime")?;

if !need_forecast || self.forecast_hours == 0 {
return Ok(WeatherResult {
location: current_data.name,
current_weather,
forecast: None,
sunrise,
sunset,
});
}

Expand Down Expand Up @@ -322,6 +331,8 @@ impl WeatherProvider for Service<'_> {
location: current_data.name,
current_weather,
forecast,
sunrise,
sunset,
})
}
}
Expand Down

0 comments on commit 08139b9

Please sign in to comment.