//! hinoirisetr library //! Contains core logic for computing temperature and gamma and applying settings. use std::fs; use std::path::Path; use std::process::Command; use chrono::{DateTime, Local, Timelike}; use serde::Deserialize; pub mod log; #[derive(Debug, Deserialize, Copy, Clone)] #[serde(default)] pub struct Config { pub temp_day: u16, pub temp_night: u16, pub gamma_day: u16, pub gamma_night: u16, pub sunset_start: u8, pub sunset_end: u8, pub sunrise_start: u8, pub sunrise_end: u8, pub notification_timeout: u32, } impl Default for Config { fn default() -> Self { Self { temp_day: 6500, temp_night: 2700, gamma_day: 100, gamma_night: 95, sunset_start: 19, sunset_end: 22, sunrise_start: 4, sunrise_end: 7, notification_timeout: 5000, } } } impl Config { pub fn load + std::fmt::Debug>( path: P, ) -> Result> { trace!("Config::load({path:?})"); let content = fs::read_to_string(path)?; let config = toml::from_str(&content)?; Ok(config) } } /// Linearly interpolate between start and end by factor [0.0, 1.0] pub fn interpolate(start: u16, end: u16, factor: f64) -> u16 { trace!("interpolate({start}, {end}, {factor})"); if end < start { (end as f64 + (start - end) as f64 * (1.0 - factor)).round() as u16 } else { (start as f64 + (end - start) as f64 * factor).round() as u16 } } /// Compute current temperature and gamma based on provided time pub fn compute_settings(now: DateTime, config: &Config) -> (u16, u16) { trace!("compute_settings({now:?})"); let time_in_hours = now.hour() as f64 + now.minute() as f64 / 60.0; trace!("time_in_hours: {time_in_hours}"); if (time_in_hours >= config.sunset_start as f64) && (time_in_hours <= config.sunset_end as f64) { trace!("time_in_hours is within sunset"); let factor = ((time_in_hours - config.sunset_start as f64) / (config.sunset_end - config.sunset_start) as f64) .clamp(0.0, 1.0); ( interpolate(config.temp_day, config.temp_night, factor), interpolate(config.gamma_day, config.gamma_night, factor), ) } else if (time_in_hours >= config.sunrise_start as f64) && (time_in_hours <= config.sunrise_end as f64) { trace!("time_in_hours is within sunrise"); let factor = 1.0 - ((time_in_hours - config.sunrise_start as f64) / (config.sunrise_end - config.sunrise_start) as f64) .clamp(0.0, 1.0); ( interpolate(config.temp_day, config.temp_night, factor), interpolate(config.gamma_day, config.gamma_night, factor), ) } else if time_in_hours > config.sunset_end as f64 || time_in_hours < config.sunrise_start as f64 { trace!("time_in_hours is within night"); (config.temp_night, config.gamma_night) } else { trace!("time_in_hours is within day"); (config.temp_day, config.gamma_day) } } /// Apply given temperature (Kelvin) and gamma (%) via hyprctl commands pub fn apply_settings(temp: u16, gamma: u16) { trace!("apply_settings({temp}, {gamma})"); debug!("applying temperature: {temp}"); debug!("applying gamma: {gamma}"); let _ = Command::new("hyprctl") .args(["hyprsunset", "temperature", &temp.to_string()]) .output(); trace!("hyprctl hyprsunset temperature {temp}"); let _ = Command::new("hyprctl") .args(["hyprsunset", "gamma", &gamma.to_string()]) .output(); trace!("hyprctl hyprsunset gamma {gamma}"); }