5 Commits

Author SHA1 Message Date
01a7576d7f 0.2.0 2022-10-27 23:39:00 +02:00
1e55385645 Use absolute time instead of incrementing by 1w 2022-10-27 23:36:25 +02:00
1ac0dbe210 Fix alarm time calculation 2022-10-27 23:26:11 +02:00
939e4d9785 Fix wait_for_bulb_command logic 2022-10-27 22:54:52 +02:00
08bdeb693b cargo fmt 2022-10-27 22:50:54 +02:00
5 changed files with 61 additions and 32 deletions

6
Cargo.lock generated
View File

@ -172,7 +172,7 @@ dependencies = [
[[package]]
name = "common"
version = "0.1.0"
version = "0.2.0"
dependencies = [
"chrono",
"lighter_lib",
@ -525,7 +525,7 @@ checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9"
[[package]]
name = "hemma"
version = "0.1.0"
version = "0.2.0"
dependencies = [
"anyhow",
"async-trait",
@ -549,7 +549,7 @@ dependencies = [
[[package]]
name = "hemma_web"
version = "0.1.0"
version = "0.2.0"
dependencies = [
"anyhow",
"chrono",

View File

@ -1,6 +1,6 @@
[package]
name = "hemma"
version = "0.1.0"
version = "0.2.0"
edition = "2021"
[dependencies]

View File

@ -1,6 +1,6 @@
use std::collections::HashMap;
use chrono::{Datelike, Local, NaiveTime, Weekday};
use chrono::{DateTime, Datelike, Local, NaiveTime, Weekday};
use common::{ClientMessage, ServerMessage};
use lighter_lib::{BulbColor, BulbId};
use lighter_manager::manager::{BulbCommand, BulbManager, BulbSelector};
@ -40,7 +40,7 @@ pub async fn lights_task(state: &State) {
.flat_map(|(bulb, schedule)| schedule.iter().map(move |(day, time)| (bulb, day, time)))
.map(|(bulb, day, time)| {
let handle = spawn(wake_task(
state.client_message.subscribe(),
state.client_message.clone(),
cmd.clone(),
bulb.clone(),
*day,
@ -105,21 +105,21 @@ pub async fn lights_task(state: &State) {
schedule.insert(day, time);
}
else {
schedule.remove(&day);
schedule.remove(&day);
}
}).await {
error!("Failed to save wake schedule: {e}");
};
if let Some(time) = time {
let handle = spawn(wake_task(
state.client_message.subscribe(),
state.client_message.clone(),
cmd.clone(),
id.clone(),
day,
time,
));
if let Some(old_handle) = wake_tasks.insert((id, day), handle) {
old_handle.abort();
}} else {
@ -136,39 +136,23 @@ pub async fn lights_task(state: &State) {
}
async fn wake_task(
mut client_messages: broadcast::Receiver<ClientRequest>,
client_messages: broadcast::Sender<ClientRequest>,
cmd: mpsc::Sender<BulbCommand>,
id: BulbId,
day: Weekday,
time: NaiveTime,
) {
let now = Local::now();
let day_num = day.num_days_from_monday();
let now_day = now.weekday();
let now_day_num = now_day.num_days_from_monday();
let mut alarm = now;
if day_num >= now_day_num {
// next alarm is this week
alarm += chrono::Duration::days((day_num - now_day_num).into());
alarm = alarm.date().and_time(time).unwrap();
} else {
// next alarm is next week
alarm += chrono::Duration::weeks(1);
alarm -= chrono::Duration::days((now_day_num - day_num).into());
alarm = alarm.date().and_time(time).unwrap();
}
let mut alarm = next_alarm(Local::now(), day, time);
loop {
info!("sleeping until {alarm}");
sleep((alarm - Local::now()).to_std().unwrap()).await;
alarm += chrono::Duration::weeks(1);
// slowly turn up brightness of bulb
for brightness in (1..=75).map(|i| (i as f32) * 0.01) {
select! {
// abort if the client pokes the bulb
_ = wait_for_bulb_command(&id, &mut client_messages) => break,
_ = wait_for_bulb_command(&id, client_messages.subscribe()) => break,
_ = sleep(Duration::from_secs(12)) => {}
};
@ -186,13 +170,30 @@ async fn wake_task(
return;
};
}
alarm = next_alarm(Local::now(), day, time);
}
}
/// Get the next alarm, from a weekday+time schedule.
fn next_alarm(now: DateTime<Local>, day: Weekday, time: NaiveTime) -> DateTime<Local> {
let day_of_alarm = day.num_days_from_monday() as i64;
let day_now = now.weekday().num_days_from_monday() as i64;
let alarm = now + chrono::Duration::days(day_of_alarm - day_now);
let mut alarm = alarm.date().and_time(time).unwrap();
if alarm <= now {
alarm += chrono::Duration::weeks(1);
}
alarm
}
/// Wait until we receive a client request that mutates the given bulb
async fn wait_for_bulb_command(
bulb_id: &BulbId,
client_messages: &mut broadcast::Receiver<ClientRequest>,
mut client_messages: broadcast::Receiver<ClientRequest>,
) {
loop {
match client_messages.recv().await {
@ -210,3 +211,31 @@ async fn wait_for_bulb_command(
}
}
}
#[cfg(test)]
mod test {
use chrono::{offset::TimeZone, Local, NaiveTime, Weekday};
use super::next_alarm;
#[test]
fn test_alarm_date() {
const FMT: &str = "%Y-%m-%d %H:%M";
let now = Local.datetime_from_str("2022-10-18 15:30", FMT).unwrap();
let test_values = [
(Weekday::Tue, (16, 30), "2022-10-18 16:30"),
(Weekday::Tue, (14, 30), "2022-10-25 14:30"),
(Weekday::Wed, (15, 30), "2022-10-19 15:30"),
(Weekday::Mon, (15, 30), "2022-10-24 15:30"),
];
for (day, (hour, min), expected) in test_values {
let expected = Local.datetime_from_str(expected, FMT).unwrap();
assert_eq!(
next_alarm(now, day, NaiveTime::from_hms(hour, min, 0)),
expected
);
}
}
}

View File

@ -1,6 +1,6 @@
[package]
name = "common"
version = "0.1.0"
version = "0.2.0"
edition = "2021"
[dependencies]

View File

@ -1,6 +1,6 @@
[package]
name = "hemma_web"
version = "0.1.0"
version = "0.2.0"
authors = ["Joakim Hulthe <joakim@hulthe.net"]
edition = "2021"