use crate::{
contracts::{LightGet, LightPut, LightsGet, LightsPut},
ecc::Ecc,
};
use anyhow::{Result, anyhow};
pub struct Light<'a> {
ecc: &'a Ecc,
endpoint: &'a str,
}
impl<'a> Light<'a> {
pub fn new(ecc: &'a Ecc, endpoint: &'a str) -> Self {
Self { ecc, endpoint }
}
pub async fn on(&self) -> Result<()> {
self.set_light(|_| LightPut {
on: Some(true),
..Default::default()
})
.await?;
Ok(())
}
pub async fn off(&self) -> Result<()> {
self.set_light(|_| LightPut {
on: Some(false),
..Default::default()
})
.await?;
Ok(())
}
pub async fn toggle(&self) -> Result<()> {
self.set_light(|x| LightPut {
on: Some(!x.on),
..Default::default()
})
.await?;
Ok(())
}
pub async fn state_get(&self) -> Result<bool> {
self.field_get(|x| x.on).await
}
pub async fn state_set(&self, state: bool) -> Result<()> {
self.set_light(|_| LightPut {
on: Some(state),
..Default::default()
})
.await?;
Ok(())
}
pub async fn temperature_get(&self) -> Result<u16> {
self.field_get(|x| x.temperature).await
}
pub async fn temperature_set(&self, value: u16) -> Result<LightsGet> {
self.set_light(|_| LightPut {
temperature: Some(value),
..Default::default()
})
.await
}
pub async fn brightness_get(&self) -> Result<u8> {
self.field_get(|x| x.brightness).await
}
pub async fn brightness_set(&self, value: u8) -> Result<LightsGet> {
self.set_light(|_| LightPut {
brightness: Some(value),
..Default::default()
})
.await
}
async fn field_get<F, T>(&self, f: F) -> Result<T>
where
F: FnOnce(LightGet) -> T,
{
let lights = self.ecc.lights_get(self.endpoint).await?;
let value = lights
.lights
.into_iter()
.next()
.map(f)
.ok_or(anyhow!("No lights found"))?;
Ok(value)
}
async fn set_light<F>(&self, f: F) -> Result<LightsGet>
where
F: Fn(LightGet) -> LightPut,
{
let lights = self.ecc.lights_get(self.endpoint).await?;
let lights_put = lights.lights.into_iter().map(&f).collect::<Vec<_>>();
self.ecc
.lights_put(self.endpoint, &LightsPut { lights: lights_put })
.await
}
}