diff --git a/src/platform/esp32.rs b/src/platform/esp32.rs index f25e270..b952ea8 100644 --- a/src/platform/esp32.rs +++ b/src/platform/esp32.rs @@ -4,6 +4,7 @@ use std::fmt::Debug; use std::sync::Mutex; use chrono::DateTime; +use chrono::Timelike; use chrono::Utc; use esp_idf_svc::eventloop::{EspSubscription, EspSystemEventLoop, System}; @@ -203,11 +204,95 @@ impl Board for Esp32Board { let nvs = EspDefaultNvsPartition::take().unwrap(); FixedSizeScheduler::new([ Box::new(WifiTask::new(self.modem.take().unwrap(), self.sys_loop.clone(), &nvs)), + Box::new(CircadianRhythm::new()), Box::new(self.surfaces.clone()) ]) } } +#[derive(Debug, Clone, Copy)] +struct ScheduleEntry { + hour: u8, + brightness: u8 +} + +struct CircadianRhythm { + time_check: Periodically, + schedule: [ScheduleEntry;10] +} + +impl CircadianRhythm { + fn new() -> Self { + CircadianRhythm { + time_check: Periodically::new_every_n_seconds(5), + schedule: [ + ScheduleEntry { hour: 0, brightness: 0 }, + ScheduleEntry { hour: 5, brightness: 0 }, + ScheduleEntry { hour: 6, brightness: 10 }, + ScheduleEntry { hour: 7, brightness: 20 }, + ScheduleEntry { hour: 8, brightness: 80 }, + ScheduleEntry { hour: 11, brightness: 120 }, + ScheduleEntry { hour: 18, brightness: 200 }, + ScheduleEntry { hour: 19, brightness: 255 }, + ScheduleEntry { hour: 22, brightness: 120 }, + ScheduleEntry { hour: 23, brightness: 5 } + ] + } + } + + fn brightness_for_time(&self, hour: u8, minute: u8) -> u8 { + let mut start = self.schedule.last().unwrap(); + let mut end = self.schedule.first().unwrap(); + for cur in self.schedule.iter() { + if (cur.hour <= hour ) { + start = cur; + } else { + end = cur; + break; + } + } + + log::info!("hour={:?} minute={:?} start={:?} end={:?}", hour, minute, start, end); + + let mut adjusted_end = end.clone(); + if start.hour > end.hour { + adjusted_end.hour += 24; + } + + let start_time = start.hour * 60; + let end_time = end.hour * 60; + let now_time = hour * 60 + minute; + + let duration = end_time - start_time; + let cur_duration = now_time - start_time; + + let frac = map_range(cur_duration.into(), 0, duration.into(), 0, 255) as u8; + + lerp8by8(start.brightness, end.brightness, frac) + } +} + +fn map_range(x: u16, in_min: u16, in_max: u16, out_min: u16, out_max: u16) -> u16 { + let run = in_max - in_min; + if run == 0 { + return 0; + } + let rise = out_max - out_min; + let delta = x - in_min; + return (delta * rise) / run + out_min; +} + + +impl Task for CircadianRhythm { + fn tick(&mut self, event: &Event, bus: &mut EventBus) { + if self.time_check.tick() || event.eq(&Event::ReadyToRock) { + let now: DateTime = std::time::SystemTime::now().into(); + let next_brightness = self.brightness_for_time(now.hour() as u8, now.minute() as u8); + bus.push(Event::new_property_change("output.brightness", next_brightness)); + } + } +} + impl Debug for WifiTask { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("WifiTask").finish()