Something went wrong. Try again.
Something went wrong. Try again.
2.8 kB · 99 lines
Rust
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100use core::future::pending;
use chrono::NaiveDate;use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, mutex::Mutex};use embassy_time::{Instant, Timer};use sunrise::{Coordinates, SolarDay, SolarEvent};use thiserror::Error;
pub static CLOCK: Mutex<CriticalSectionRawMutex, Clock> = Mutex::new(Clock::new());
#[derive(Debug, Error)]pub enum ClockError { #[error("invalid time")] InvalidTime, #[error("invalid coordinates")] InvalidCoordinates, #[error("no solar events")] NoSolarEvents,}
pub struct Clock { unix_time: i64, // seconds since Unix epoch sync_instant: Instant,
sun_sync_instant: Instant, sun_time: (i64, i64),}
impl Clock { const fn new() -> Self { Self { unix_time: 0, sync_instant: Instant::MIN, sun_sync_instant: Instant::MIN, sun_time: (0, 0), } }
fn update_sun(&mut self) -> Result<(), ClockError> { let (sun_rise, sun_set) = get_sun_time(self.unix_time)?; self.sun_time = (sun_rise, sun_set); self.sun_sync_instant = Instant::now();
Ok(()) }
pub fn update(&mut self, unix_time: i64) -> Result<(), ClockError> { self.unix_time = unix_time; self.sync_instant = Instant::now(); self.update_sun() }
#[must_use] pub fn now(&self) -> i64 { self.unix_time + ((Instant::now() - self.sync_instant).as_secs()).cast_signed() }
pub fn sun_time(&mut self) -> Result<(i64, i64), ClockError> { if self.sun_sync_instant.elapsed().as_secs() >= 60 * 60 * 24 { self.update_sun()?; }
Ok(self.sun_time) }}
fn get_sun_time(current_time: i64) -> Result<(i64, i64), ClockError> { let epoch_days = i32::try_from(current_time / (60 * 60 * 24)).map_err(|_| ClockError::InvalidTime)?;
let date = NaiveDate::from_epoch_days(epoch_days).ok_or(ClockError::InvalidTime)?;
// TODO: Get actual coordinates based on the current location let coordinates = Coordinates::new(48.210_033, 16.363_449).ok_or(ClockError::InvalidCoordinates)?;
let solar_day = SolarDay::new(coordinates, date);
Ok(( solar_day .event_time(SolarEvent::Dawn(sunrise::DawnType::Nautical)) .ok_or(ClockError::NoSolarEvents)? .timestamp() % (60 * 60 * 24), solar_day .event_time(SolarEvent::Dusk(sunrise::DawnType::Nautical)) .ok_or(ClockError::NoSolarEvents)? .timestamp() % (60 * 60 * 24), ))}
pub async fn maybe_timer(enabled: bool, delay: u64) { if enabled { Timer::after_secs(delay).await; } else { pending::<()>().await; }}