Skip to content

Instantly share code, notes, and snippets.

@kingoflolz
Created January 16, 2020 03:34
Show Gist options
  • Save kingoflolz/3f6807b5f980b1e4c61ac96acc0a5649 to your computer and use it in GitHub Desktop.
Save kingoflolz/3f6807b5f980b1e4c61ac96acc0a5649 to your computer and use it in GitHub Desktop.
[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"
#![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