use crate::{addresses, Error, I2cDevice, Result};
use embedded_hal::i2c::I2c;
pub struct LatchRelay<I2C> {
device: I2cDevice<I2C>,
}
impl<I2C, E> LatchRelay<I2C>
where
I2C: I2c<Error = E>,
{
pub fn new(i2c: I2C) -> Result<Self, E> {
Self::new_with_address(i2c, addresses::LATCH_RELAY)
}
pub fn discover(i2c: &mut I2C) -> Result<u8, E> {
let addresses = [addresses::LATCH_RELAY];
for &addr in &addresses {
if i2c.write(addr, &[]).is_ok() {
return Ok(addr);
}
}
i2c.write(addresses[0], &[])
.map(|_| addresses[0])
.map_err(Error::I2c)
}
pub fn new_with_address(i2c: I2C, address: u8) -> Result<Self, E> {
let relay = Self {
device: I2cDevice::new(i2c, address),
};
Ok(relay)
}
pub fn address(&self) -> u8 {
self.device.address
}
pub fn on(&mut self) -> Result<(), E> {
let data = [1u8, 0, 0];
self.device.write(&data)?;
Ok(())
}
pub fn off(&mut self) -> Result<(), E> {
let data = [0u8, 0, 0];
self.device.write(&data)?;
Ok(())
}
pub fn set(&mut self, on: bool) -> Result<(), E> {
if on {
self.on()
} else {
self.off()
}
}
pub fn toggle(&mut self) -> Result<(), E> {
match self.is_on()? {
Some(true) => self.off(),
_ => self.on(),
}
}
pub fn is_on(&mut self) -> Result<Option<bool>, E> {
let mut buf = [0u8; 4]; self.device.read(&mut buf)?;
let status0 = buf[1];
let status1 = buf[2];
if status0 == 0 && status1 == 0 {
Ok(None)
} else if status0 == 1 {
Ok(Some(false)) } else {
Ok(Some(true)) }
}
pub fn release(self) -> I2C {
self.device.release()
}
}