Nareshkumar Rao
7 months ago
7 changed files with 128 additions and 104 deletions
@ -0,0 +1,17 @@ |
|||||
|
use crate::{ |
||||
|
config::*, |
||||
|
io::{Relay, RelaySwitchState}, |
||||
|
GenericResult, |
||||
|
}; |
||||
|
|
||||
|
pub fn switch_lights(relay: &mut Relay, state: RelaySwitchState) -> GenericResult<()> { |
||||
|
relay.switch(LIGHT_RELAY_PIN, state) |
||||
|
} |
||||
|
|
||||
|
pub fn switch_fan(relay: &mut Relay, state: RelaySwitchState) -> GenericResult<()> { |
||||
|
relay.switch(FAN_RELAY_PIN, state) |
||||
|
} |
||||
|
|
||||
|
pub fn switch_water_pump(relay: &mut Relay, state: RelaySwitchState) -> GenericResult<()> { |
||||
|
relay.switch(WATER_PUMP_RELAY_PIN, state) |
||||
|
} |
@ -0,0 +1,8 @@ |
|||||
|
pub const LOGIC_LEVEL: f32 = 3.3; |
||||
|
pub const THERMISTOR_ANALOG_PIN: u8 = 0; |
||||
|
pub const THERMISTOR_VOLTAGE_DIVIDER_RESISTANCE: f32 = 9_700.; |
||||
|
|
||||
|
pub const LIGHT_RELAY_PIN: u8 = 0; |
||||
|
pub const FAN_RELAY_PIN: u8 = 1; |
||||
|
pub const WATER_PUMP_RELAY_PIN: u8 = 2; |
||||
|
pub const RELAY_GPIO_PINS: [Option<u8>; 4] = [Some(17), Some(27), Some(22), None]; |
@ -1,98 +0,0 @@ |
|||||
use std::{error::Error, time::Duration}; |
|
||||
|
|
||||
use rppal::gpio::Gpio; |
|
||||
|
|
||||
pub struct Dht11Data { |
|
||||
pub temperature: f32, |
|
||||
pub humidity: f32, |
|
||||
} |
|
||||
pub struct Dht11Sensor { |
|
||||
pin: rppal::gpio::IoPin, |
|
||||
} |
|
||||
impl Dht11Sensor { |
|
||||
pub fn new(pin: u8) -> Result<Dht11Sensor, Box<dyn Error>> { |
|
||||
let pin = Gpio::new()?.get(pin)?.into_io(rppal::gpio::Mode::Input); |
|
||||
Ok(Dht11Sensor { pin }) |
|
||||
} |
|
||||
|
|
||||
fn expect_pulse(&mut self, expected_level: bool) -> Result<u32, Box<dyn Error>> { |
|
||||
let _guard = interrupts::disable(); |
|
||||
let mut count: u32 = 0; |
|
||||
let mut rtclock = linux_realtime::Clock::new()?; |
|
||||
loop { |
|
||||
if self.pin.is_high() != expected_level { |
|
||||
break; |
|
||||
} |
|
||||
if count >= 1000 { |
|
||||
return Err(std::io::Error::new( |
|
||||
std::io::ErrorKind::InvalidData, |
|
||||
"Timeout while reading pulse", |
|
||||
) |
|
||||
.into()); |
|
||||
} |
|
||||
count += 1; |
|
||||
rtclock.sleep(Duration::from_micros(1))?; |
|
||||
} |
|
||||
Ok(count) |
|
||||
} |
|
||||
|
|
||||
pub fn read(&mut self) -> Result<Dht11Data, Box<dyn Error>> { |
|
||||
use rppal::gpio::{Bias, Mode}; |
|
||||
|
|
||||
let mut data = [0; 5]; |
|
||||
let mut cycles: [u32; 80] = [0; 80]; |
|
||||
|
|
||||
let mut rtclock = linux_realtime::Clock::new()?; |
|
||||
|
|
||||
self.pin.set_mode(Mode::Input); |
|
||||
self.pin.set_bias(Bias::PullUp); |
|
||||
rtclock.sleep(Duration::from_millis(1))?; |
|
||||
|
|
||||
self.pin.set_mode(Mode::Output); |
|
||||
self.pin.set_low(); |
|
||||
rtclock.sleep(Duration::from_millis(20))?; |
|
||||
|
|
||||
// Timing Critical Code
|
|
||||
self.pin.set_mode(Mode::Input); |
|
||||
self.pin.set_bias(Bias::PullUp); |
|
||||
rtclock.sleep(Duration::from_micros(55))?; |
|
||||
|
|
||||
self.expect_pulse(false)?; |
|
||||
self.expect_pulse(true)?; |
|
||||
for i in (0..80).step_by(2) { |
|
||||
cycles[i] = self.expect_pulse(false)?; |
|
||||
cycles[i + 1] = self.expect_pulse(true)?; |
|
||||
} |
|
||||
|
|
||||
for i in 0..40 { |
|
||||
let low_cycles = cycles[2 * i]; |
|
||||
let high_cycles = cycles[2 * i + 1]; |
|
||||
data[i / 8] <<= 1; |
|
||||
if high_cycles > low_cycles { |
|
||||
data[i / 8] |= 1; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
if data[4] != ((data[0] + data[1] + data[2] + data[3]) & 0xFF) { |
|
||||
return Err(std::io::Error::new( |
|
||||
std::io::ErrorKind::InvalidData, |
|
||||
"DHT Checksum Failure", |
|
||||
) |
|
||||
.into()); |
|
||||
} |
|
||||
|
|
||||
let mut temperature = data[2] as f32; |
|
||||
if data[3] & 0x80 != 0 { |
|
||||
temperature = -1. - temperature; |
|
||||
} |
|
||||
temperature += ((data[3] & 0x0F) as f32) * 0.1; |
|
||||
|
|
||||
let mut humidity = data[0] as f32; |
|
||||
humidity += (data[1] as f32) * 0.1; |
|
||||
|
|
||||
Ok(Dht11Data { |
|
||||
temperature, |
|
||||
humidity, |
|
||||
}) |
|
||||
} |
|
||||
} |
|
@ -0,0 +1,3 @@ |
|||||
|
use std::error::Error; |
||||
|
|
||||
|
type GenericResult<T> = Result<T, Box<dyn Error>>; |
@ -0,0 +1,75 @@ |
|||||
|
use ads1x1x::{Ads1x1x, ChannelSelection, DynamicOneShot}; |
||||
|
use nb::block; |
||||
|
use rppal::gpio::{Gpio, OutputPin}; |
||||
|
|
||||
|
use crate::{config::*, GenericResult}; |
||||
|
|
||||
|
pub fn get_input_voltage(pin: u8) -> GenericResult<f32> { |
||||
|
const ADS1115_DEFAULT_RANGE: f32 = 2.048; |
||||
|
let adc = rppal::i2c::I2c::new()?; |
||||
|
let mut adc = Ads1x1x::new_ads1115(adc, ads1x1x::SlaveAddr::Alternative(false, false)); |
||||
|
let channel: ChannelSelection = match pin { |
||||
|
0 => ChannelSelection::SingleA0, |
||||
|
1 => ChannelSelection::SingleA1, |
||||
|
2 => ChannelSelection::SingleA2, |
||||
|
3 => ChannelSelection::SingleA3, |
||||
|
_ => return Err(format!("Pin {} not available. Only 0-3", pin).into()), |
||||
|
}; |
||||
|
let result = block!(adc.read(channel)).map_err(|e| format!("{:?}", e))?; |
||||
|
let result = result as f32; |
||||
|
let result = result / i16::MAX as f32 * ADS1115_DEFAULT_RANGE; |
||||
|
Ok(result) |
||||
|
} |
||||
|
|
||||
|
pub struct Relay { |
||||
|
relay_pins: [Option<rppal::gpio::OutputPin>; RELAY_GPIO_PINS.len()], |
||||
|
} |
||||
|
pub enum RelaySwitchState { |
||||
|
On, |
||||
|
Off, |
||||
|
} |
||||
|
impl Relay { |
||||
|
pub fn new() -> GenericResult<Relay> { |
||||
|
let mut output_pins = RELAY_GPIO_PINS.map(|pin| { |
||||
|
pin.and_then(|pin| { |
||||
|
let result = |
||||
|
(|| -> GenericResult<OutputPin> { Ok(Gpio::new()?.get(pin)?.into_output()) })(); |
||||
|
result.ok() |
||||
|
}) |
||||
|
}); |
||||
|
for pin in output_pins.iter_mut().flatten() { |
||||
|
// The relay turns ON on LOW
|
||||
|
pin.set_high(); |
||||
|
} |
||||
|
Ok(Relay { |
||||
|
relay_pins: output_pins, |
||||
|
}) |
||||
|
} |
||||
|
pub fn toggle(&mut self, pin: u8) -> GenericResult<()> { |
||||
|
let pin = self.get_output_pin(pin)?; |
||||
|
pin.toggle(); |
||||
|
Ok(()) |
||||
|
} |
||||
|
|
||||
|
pub fn switch(&mut self, pin: u8, state: RelaySwitchState) -> GenericResult<()> { |
||||
|
let pin = self.get_output_pin(pin)?; |
||||
|
match state { |
||||
|
RelaySwitchState::On => pin.set_low(), |
||||
|
RelaySwitchState::Off => pin.set_high(), |
||||
|
} |
||||
|
Ok(()) |
||||
|
} |
||||
|
|
||||
|
fn get_output_pin(&mut self, pin: u8) -> GenericResult<&mut OutputPin> { |
||||
|
Ok(self |
||||
|
.relay_pins |
||||
|
.get_mut(pin as usize) |
||||
|
.ok_or(format!( |
||||
|
"Pin {} not within pin array with length {}", |
||||
|
pin, |
||||
|
RELAY_GPIO_PINS.len() |
||||
|
))? |
||||
|
.as_mut() |
||||
|
.ok_or("Pin not configured.")?) |
||||
|
} |
||||
|
} |
@ -0,0 +1,15 @@ |
|||||
|
use crate::{config::*, io::get_input_voltage, GenericResult}; |
||||
|
|
||||
|
pub fn get_temperature() -> GenericResult<f32> { |
||||
|
const THERMISTOR_NOMINAL_RESISTANCE: f32 = 10_000.; |
||||
|
const THERMISTOR_NOMINAL_TEMPERATURE: f32 = 298.15; |
||||
|
const THERMISTOR_CONSTANT: f32 = 3950.; |
||||
|
|
||||
|
let voltage = get_input_voltage(THERMISTOR_ANALOG_PIN)?; |
||||
|
let resistance = (LOGIC_LEVEL / voltage - 1.) * THERMISTOR_VOLTAGE_DIVIDER_RESISTANCE; |
||||
|
let temperature = 1. |
||||
|
/ ((1. / THERMISTOR_NOMINAL_TEMPERATURE) |
||||
|
+ (1. / THERMISTOR_CONSTANT * f32::ln(resistance / THERMISTOR_NOMINAL_RESISTANCE))) |
||||
|
- 273.15; |
||||
|
Ok(temperature) |
||||
|
} |
Loading…
Reference in new issue