Created
January 16, 2020 03:34
-
-
Save kingoflolz/3f6807b5f980b1e4c61ac96acc0a5649 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[package] | |
name = "alarm" | |
version = "0.1.0" | |
authors = ["Ben Wang <[email protected]>"] | |
edition = "2018" | |
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | |
[dependencies] | |
mcp3xxx = "0.1.0-pre.1" | |
rppal = "0.11.3" | |
failure = "0.1" | |
chrono = "0.4" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#![feature(div_duration)] | |
use std::time::{Duration, Instant}; | |
use std::thread; | |
use failure; | |
use chrono::{Timelike, Local}; | |
use rppal::gpio::{Gpio, InputPin, OutputPin}; | |
use rppal::pwm::{Channel, Pwm}; | |
use rppal::spi::{Bus, Mode, SlaveSelect, Spi}; | |
use mcp3xxx::Mcp3202; | |
enum State { | |
OnManual { | |
brightness: f64, | |
last_active: Instant, | |
}, | |
Sunrise { | |
start_time: Instant, | |
rise_time: Duration, | |
full_brightness: f64, | |
}, | |
Sunset { | |
start_time: Instant, | |
set_time: Duration, | |
full_brightness: f64, | |
}, | |
Idle, | |
Error, | |
} | |
fn check_wake() -> bool { | |
let local = Local::now(); | |
let (h, m) = (local.time().hour(), local.time().minute()); | |
if (h, m) == (8, 30) { | |
true | |
} else { | |
false | |
} | |
} | |
fn check_set() -> bool { | |
let local = Local::now(); | |
let (h, m) = (local.time().hour(), local.time().minute()); | |
if (h, m) == (0, 15) { | |
true | |
} else { | |
false | |
} | |
} | |
fn thermistor_math(adc_fraction: f64) -> f64 { | |
adc_fraction | |
} | |
impl State { | |
fn get_brightness(&self) -> f64 { | |
match self { | |
State::OnManual { brightness, .. } => { | |
*brightness | |
} | |
State::Sunrise { start_time, rise_time, full_brightness, .. } => { | |
let elapsed = start_time.elapsed(); | |
brightness_ramp(elapsed.div_duration_f64(*rise_time)) * full_brightness | |
} | |
State::Sunset { start_time, set_time, full_brightness, .. } => { | |
let elapsed = start_time.elapsed(); | |
brightness_ramp(1.0f64 - elapsed.div_duration_f64(*set_time)) * full_brightness | |
} | |
State::Idle => { | |
0.0f64 | |
} | |
State::Error => { | |
0.0f64 | |
} | |
} | |
} | |
fn fan_ctrl(&mut self, io: &mut IO) -> Result<(), failure::Error> { | |
let temp = thermistor_math(io.adc.single_ended_read(mcp3xxx::Channel::new(0)?)?.as_fraction()); | |
if temp > 80.0f64 { | |
*self = State::Error; | |
io.fan_pwm.set_duty_cycle(1.0f64); | |
} else if temp > 60.0f64 { | |
io.fan_pwm.set_duty_cycle(0.8f64); | |
} else if temp > 40.0f64 { | |
io.fan_pwm.set_duty_cycle(0.5f64); | |
} else { | |
io.fan_pwm.set_duty_cycle(0.0f64); | |
} | |
Ok(()) | |
} | |
fn update(&mut self, io: &mut IO) -> Result<(), failure::Error> { | |
match *self { | |
State::OnManual { mut brightness, mut last_active } => { | |
brightness = io.adc.single_ended_read(mcp3xxx::Channel::new(0)?)?.as_fraction(); | |
if io.pir.is_high() { | |
last_active = Instant::now() | |
} else if last_active - Instant::now() > Duration::from_secs(300) { | |
*self = State::Idle; | |
} | |
if check_set() { | |
*self = State::Sunset { | |
start_time: Instant::now(), | |
set_time: Duration::from_secs(5 * 60), | |
full_brightness: brightness, | |
} | |
} | |
} | |
State::Sunrise { start_time, rise_time, .. } => { | |
if Instant::now() > start_time + rise_time { | |
*self = State::Idle; | |
} | |
} | |
State::Sunset { start_time, set_time, .. } => { | |
if Instant::now() > start_time + set_time { | |
*self = State::Idle; | |
} | |
} | |
State::Idle => { | |
if check_wake() { | |
*self = State::Sunrise { | |
start_time: Instant::now(), | |
rise_time: Duration::from_secs(30 * 60), | |
full_brightness: 1.0f64, | |
} | |
} | |
if io.button.is_high() { | |
*self = State::OnManual { brightness: 0.0f64, last_active: Instant::now() } | |
} | |
} | |
State::Error => { | |
io.brightness.disable()?; | |
} | |
}; | |
io.brightness.set_duty_cycle(self.get_brightness())?; | |
self.fan_ctrl(io); | |
Ok(()) | |
} | |
} | |
struct IO { | |
brightness: Pwm, | |
fan_pwm: Pwm, | |
adc: Mcp3202, | |
pir: InputPin, | |
button: InputPin, | |
} | |
impl IO { | |
fn init(&mut self) -> Result<(), failure::Error> { | |
self.brightness.enable()?; | |
Ok(()) | |
} | |
} | |
fn brightness_ramp(x: f64) -> f64 { | |
x | |
} | |
fn main() -> Result<(), failure::Error> { | |
let mut s = State::Idle; | |
let gpio = Gpio::new()?; | |
let mut io = IO { | |
brightness: Pwm::new(Channel::Pwm0)?, | |
fan_pwm: Pwm::new(Channel::Pwm1)?, | |
adc: Mcp3202::new(Spi::new(Bus::Spi0, SlaveSelect::Ss0, 1_000_000, Mode::Mode0)?)?, | |
pir: gpio.get(0)?.into_input(), | |
button: gpio.get(0)?.into_input(), | |
}; | |
io.init()?; | |
loop { | |
thread::sleep(Duration::from_millis(10)); | |
s.update(&mut io)?; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment