#![no_std]
use embedded_hal::i2c::I2c;
const CMD_HUMIDITY: u8 = 0x76;
const CMD_TEMPERATURE: u8 = 0x74;
const CMD_RAW_HUMIDITY: u8 = 0x72;
const CMD_REFERENCE_DRY: u8 = 0x64;
const CMD_REFERENCE_WET: u8 = 0x75;
const CMD_HARDWARE_VERSION: u8 = 0x68;
const CMD_FIRMWARE_VERSION: u8 = 0x66;
const CMD_SET_REFERENCE_DRY: u8 = 0x44;
const CMD_SET_REFERENCE_WET: u8 = 0x55;
const CMD_SET_NEW_ADDR: u8 = 0x41;
const CMD_RESET: u8 = 0x52;
const CMD_FACTORY_RESET: u8 = 0x46;
const CMD_SET_ENERGY_SAVE: u8 = 0x4C;
const CMD_START_MEASUREMENT: u8 = 0x4D;
const CMD_OPTIONS: u8 = 0x6F;
pub struct Somose<I2C> {
i2c: I2C,
addr: u8,
}
impl<I2C: I2c> Somose<I2C> {
pub fn new(i2c: I2C, addr: u8) -> Result<Self, I2C::Error> {
let mut this = Self { i2c, addr };
let _ = this.firmware_version()?;
Ok(this)
}
pub fn humidity(&mut self) -> Result<(u8, u8), I2C::Error> {
let mut read = [0u8; 2];
self.i2c.write_read(self.addr, &[CMD_HUMIDITY], &mut read)?;
Ok((read[0], read[1]))
}
pub fn temperature(&mut self) -> Result<i8, I2C::Error> {
let mut read = [0u8; 1];
self.i2c
.write_read(self.addr, &[CMD_TEMPERATURE], &mut read)?;
Ok(read[0] as i8)
}
pub fn raw_humidity(&mut self) -> Result<u16, I2C::Error> {
let mut read = [0u8; 2];
self.i2c
.write_read(self.addr, &[CMD_RAW_HUMIDITY], &mut read)?;
Ok(u16::from_be_bytes(read))
}
pub fn reference_dry(&mut self) -> Result<u16, I2C::Error> {
let mut read = [0u8; 2];
self.i2c
.write_read(self.addr, &[CMD_REFERENCE_DRY], &mut read)?;
Ok(u16::from_be_bytes(read))
}
pub fn reference_wet(&mut self) -> Result<u16, I2C::Error> {
let mut read = [0u8; 2];
self.i2c
.write_read(self.addr, &[CMD_REFERENCE_WET], &mut read)?;
Ok(u16::from_be_bytes(read))
}
pub fn hardware_version(&mut self) -> Result<(u8, u8), I2C::Error> {
let mut read = [0u8; 4];
self.i2c
.write_read(self.addr, &[CMD_HARDWARE_VERSION], &mut read)?;
debug_assert_eq!(read[0], b'v');
debug_assert_eq!(read[2], b'.');
Ok((read[1], read[3]))
}
pub fn firmware_version(&mut self) -> Result<(u8, u8), I2C::Error> {
let mut read = [0u8; 4];
self.i2c
.write_read(self.addr, &[CMD_FIRMWARE_VERSION], &mut read)?;
debug_assert_eq!(read[0], b'v');
debug_assert_eq!(read[2], b'.');
Ok((read[1], read[3]))
}
pub fn set_reference_dry(&mut self, value: u16) -> Result<(), I2C::Error> {
let bytes = value.to_be_bytes();
self.i2c
.write(self.addr, &[CMD_SET_REFERENCE_DRY, bytes[0], bytes[1]])
}
pub fn set_reference_wet(&mut self, value: u16) -> Result<(), I2C::Error> {
let bytes = value.to_be_bytes();
self.i2c
.write(self.addr, &[CMD_SET_REFERENCE_WET, bytes[0], bytes[1]])
}
pub fn set_new_addr(&mut self, addr: u8) -> Result<(), I2C::Error> {
self.i2c.write(self.addr, &[CMD_SET_NEW_ADDR, addr])?;
self.addr = addr;
Ok(())
}
pub fn reset(&mut self) -> Result<(), I2C::Error> {
self.i2c.write(self.addr, &[CMD_RESET])
}
pub fn factory_reset(&mut self) -> Result<(), I2C::Error> {
self.i2c.write(self.addr, &[CMD_FACTORY_RESET])
}
pub fn set_energy_save(&mut self, enable: bool) -> Result<(), I2C::Error> {
self.i2c.write(
self.addr,
&[CMD_SET_ENERGY_SAVE, if enable { 1 } else { 0 }],
)
}
pub fn start_measurement(&mut self, repetitions: u8) -> Result<(), I2C::Error> {
self.i2c
.write(self.addr, &[CMD_START_MEASUREMENT, repetitions])
}
pub fn options(&mut self) -> Result<Options, I2C::Error> {
let mut read = [0u8; 1];
self.i2c.write_read(self.addr, &[CMD_OPTIONS], &mut read)?;
Ok(Options {
measurement_active: read[0] & 1 != 0,
energy_save_active: (read[0] & (1 << 1)) != 0,
})
}
}
impl<I2C: embedded_hal_async::i2c::I2c> Somose<I2C> {
pub async fn new_async(i2c: I2C, addr: u8) -> Result<Self, I2C::Error> {
let mut this = Self { i2c, addr };
let _ = this.firmware_version_async().await?;
Ok(this)
}
pub async fn humidity_async(&mut self) -> Result<(u8, u8), I2C::Error> {
let mut read = [0u8; 2];
self.i2c
.write_read(self.addr, &[CMD_HUMIDITY], &mut read)
.await?;
Ok((read[0], read[1]))
}
pub async fn temperature_async(&mut self) -> Result<i8, I2C::Error> {
let mut read = [0u8; 1];
self.i2c
.write_read(self.addr, &[CMD_TEMPERATURE], &mut read)
.await?;
Ok(read[0] as i8)
}
pub async fn raw_humidity_async(&mut self) -> Result<u16, I2C::Error> {
let mut read = [0u8; 2];
self.i2c
.write_read(self.addr, &[CMD_RAW_HUMIDITY], &mut read)
.await?;
Ok(u16::from_be_bytes(read))
}
pub async fn reference_dry_async(&mut self) -> Result<u16, I2C::Error> {
let mut read = [0u8; 2];
self.i2c
.write_read(self.addr, &[CMD_REFERENCE_DRY], &mut read)
.await?;
Ok(u16::from_be_bytes(read))
}
pub async fn reference_wet_async(&mut self) -> Result<u16, I2C::Error> {
let mut read = [0u8; 2];
self.i2c
.write_read(self.addr, &[CMD_REFERENCE_WET], &mut read)
.await?;
Ok(u16::from_be_bytes(read))
}
pub async fn hardware_version_async(&mut self) -> Result<(u8, u8), I2C::Error> {
let mut read = [0u8; 4];
self.i2c
.write_read(self.addr, &[CMD_HARDWARE_VERSION], &mut read)
.await?;
debug_assert_eq!(read[0], b'v');
debug_assert_eq!(read[2], b'.');
Ok((read[1], read[3]))
}
pub async fn firmware_version_async(&mut self) -> Result<(u8, u8), I2C::Error> {
let mut read = [0u8; 4];
self.i2c
.write_read(self.addr, &[CMD_FIRMWARE_VERSION], &mut read)
.await?;
debug_assert_eq!(read[0], b'v');
debug_assert_eq!(read[2], b'.');
Ok((read[1], read[3]))
}
pub async fn set_reference_dry_async(&mut self, value: u16) -> Result<(), I2C::Error> {
let bytes = value.to_be_bytes();
self.i2c
.write(self.addr, &[CMD_SET_REFERENCE_DRY, bytes[0], bytes[1]])
.await
}
pub async fn set_reference_wet_async(&mut self, value: u16) -> Result<(), I2C::Error> {
let bytes = value.to_be_bytes();
self.i2c
.write(self.addr, &[CMD_SET_REFERENCE_WET, bytes[0], bytes[1]])
.await
}
pub async fn set_new_addr_async(&mut self, addr: u8) -> Result<(), I2C::Error> {
self.i2c.write(self.addr, &[CMD_SET_NEW_ADDR, addr]).await?;
self.addr = addr;
Ok(())
}
pub async fn reset_async(&mut self) -> Result<(), I2C::Error> {
self.i2c.write(self.addr, &[CMD_RESET]).await
}
pub async fn factory_reset_async(&mut self) -> Result<(), I2C::Error> {
self.i2c.write(self.addr, &[CMD_FACTORY_RESET]).await
}
pub async fn set_energy_save_async(&mut self, enable: bool) -> Result<(), I2C::Error> {
self.i2c
.write(
self.addr,
&[CMD_SET_ENERGY_SAVE, if enable { 1 } else { 0 }],
)
.await
}
pub async fn start_measurement_async(&mut self, repetitions: u8) -> Result<(), I2C::Error> {
self.i2c
.write(self.addr, &[CMD_START_MEASUREMENT, repetitions])
.await
}
pub async fn options_async(&mut self) -> Result<Options, I2C::Error> {
let mut read = [0u8; 1];
self.i2c
.write_read(self.addr, &[CMD_OPTIONS], &mut read)
.await?;
Ok(Options {
measurement_active: read[0] & 1 != 0,
energy_save_active: (read[0] & (1 << 1)) != 0,
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Options {
pub measurement_active: bool,
pub energy_save_active: bool,
}