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