This commit is contained in:
2022-07-22 22:35:39 +02:00
parent a780ad3b33
commit d6a25648ce
13 changed files with 679 additions and 108 deletions

7
lib/Cargo.toml Normal file
View File

@ -0,0 +1,7 @@
[package]
name = "lighter_lib"
version = "0.1.0"
edition = "2021"
[dependencies]
serde = { version = "1", features = ["derive"] }

148
lib/src/lib.rs Normal file
View File

@ -0,0 +1,148 @@
use serde::{Deserialize, Serialize};
use std::fmt::{self, Display, Formatter};
use std::num::ParseIntError;
use std::ops::Deref;
use std::str::FromStr;
/// The mqtt publish id of the bulb
#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd)]
pub struct BulbId(pub String);
#[derive(Serialize, Deserialize, Default, Debug, Clone)]
pub struct BulbMode {
pub power: bool,
pub color: BulbColor,
}
#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
pub enum BulbColor {
/// Light temperature, brightness
Kelvin { t: f32, b: f32 },
/// Hue, Saturation, Brightness
HSB { h: f32, s: f32, b: f32 },
}
impl FromStr for BulbColor {
type Err = ParseIntError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let parsed = u64::from_str_radix(s, 16)?;
let to_f32 = |byte: u8| byte as f32 / 255.;
let [.., red, green, blue, white, warm] = parsed.to_be_bytes().map(to_f32);
if (red + green + blue) != 0. {
let (h, s, b) = rgb_to_hsb(red, green, blue);
Ok(BulbColor::hsb(h, s, b))
} else {
let b = warm + white;
let t = white / b;
Ok(BulbColor::kelvin(t, b))
}
}
}
impl BulbColor {
pub fn color_string(self) -> String {
let [mut red, mut green, mut blue, mut white, mut warm] = [0u8; 5];
match self {
BulbColor::HSB { h, s, b } => (red, green, blue) = hsb_to_rgb(h, s, b),
BulbColor::Kelvin { t, b } => {
(white, warm) = ((t * b * 255.0) as u8, ((1. - t) * b * 255.0) as u8)
}
}
let s = format!("{red:02x}{green:02x}{blue:02x}{white:02x}{warm:02x}");
s
}
}
impl BulbColor {
pub fn hsb(h: f32, s: f32, b: f32) -> Self {
BulbColor::HSB {
h: h.clamp(0.0, 1.0),
s: s.clamp(0.0, 1.0),
b: b.clamp(0.0, 1.0),
}
}
pub fn kelvin(t: f32, b: f32) -> Self {
BulbColor::Kelvin {
t: t.clamp(0.0, 1.0),
b: b.clamp(0.0, 1.0),
}
}
}
impl Default for BulbColor {
fn default() -> Self {
BulbColor::Kelvin { t: 0.0, b: 0.0 }
}
}
fn rgb_to_hsb(red: f32, green: f32, blue: f32) -> (f32, f32, f32) {
let x_max = red.max(green).max(blue);
let x_min = red.min(green).min(blue);
let b = x_max;
let c = x_max - x_min;
let h = match b {
_ if c == 0. => 0.,
_ if b == red => (green - blue) / c,
_ if b == green => 2. + (blue - red) / c,
_ => 4. + (red - green) / c,
};
let mut h = h * 60.0 / 360.0;
if h < 0.0 {
h += 1.0;
}
let s = if b == 0.0 { 0.0 } else { c / b };
(h, s, b)
}
fn hsb_to_rgb(h: f32, s: f32, b: f32) -> (u8, u8, u8) {
let h = 360.0 * h.clamp(0.0, 1.0);
let c = b * s; // chroma
let x = c * (1. - ((h / 60.) % 2. - 1.).abs());
let m = b - c;
let m = |v| ((v + m) * 255.0) as u8;
let (r, g, b) = match h {
_ if h < 60. => (c, x, 0.0),
_ if h < 120.0 => (x, c, 0.0),
_ if h < 180.0 => (0.0, c, x),
_ if h < 240.0 => (0.0, x, c),
_ if h < 300.0 => (x, 0.0, c),
_ => (c, 0.0, x),
};
(m(r), m(g), m(b))
}
impl Display for BulbId {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl From<String> for BulbId {
fn from(s: String) -> Self {
BulbId(s)
}
}
impl Deref for BulbId {
type Target = str;
fn deref(&self) -> &Self::Target {
&self.0
}
}