ftswarm/swarm_object/
led.rs

1use ftswarm_macros::{default_new_swarm_object_impls, impl_swarm_object};
2use ftswarm_proto::command::argument::Argument;
3use ftswarm_proto::command::rpc::RpcFunction;
4use crate::FtSwarm;
5use crate::swarm_object::{NewSwarmObject, SwarmObject, Updateable};
6
7#[derive(Updateable, Clone)]
8pub struct Led {
9    pub name: String,
10    swarm: FtSwarm
11}
12
13impl_swarm_object!(Led, ());
14
15impl NewSwarmObject<()> for Led {
16    fn new(name: &str, swarm: FtSwarm, _params: ()) -> Box<Self> {
17        Box::new(Led {
18            name: name.to_string(),
19            swarm
20        })
21    }
22
23    default_new_swarm_object_impls!();
24}
25
26#[derive(Clone, Debug, PartialEq, Eq, Hash)]
27pub struct LedColor {
28    pub red: i32,
29    pub green: i32,
30    pub blue: i32
31}
32
33impl LedColor {
34    pub fn new(red: i32, green: i32, blue: i32) -> Self {
35        LedColor {
36            red,
37            green,
38            blue
39        }
40    }
41
42    pub fn rgb(red: i32, green: i32, blue: i32) -> LedColor {
43        LedColor::new(red, green, blue)
44    }
45
46    pub fn hsl(hue: i32, saturation: i32, lightness: i32) -> LedColor {
47        let hue = hue as f64 / 360.0;
48        let saturation = saturation as f64 / 100.0;
49        let lightness = lightness as f64 / 100.0;
50
51        let c = (1.0 - (2.0 * lightness - 1.0).abs()) * saturation;
52        let x = c * (1.0 - ((hue * 6.0) % 2.0 - 1.0).abs());
53        let m = lightness - c / 2.0;
54
55        let (red, green, blue) = if hue < 1.0 / 6.0 {
56            (c, x, 0.0)
57        } else if hue < 2.0 / 6.0 {
58            (x, c, 0.0)
59        } else if hue < 3.0 / 6.0 {
60            (0.0, c, x)
61        } else if hue < 4.0 / 6.0 {
62            (0.0, x, c)
63        } else if hue < 5.0 / 6.0 {
64            (x, 0.0, c)
65        } else {
66            (c, 0.0, x)
67        };
68
69        LedColor::new(
70            ((red + m) * 255.0) as i32,
71            ((green + m) * 255.0) as i32,
72            ((blue + m) * 255.0) as i32
73        )
74    }
75
76    pub fn red() -> LedColor {
77        LedColor::new(255, 0, 0)
78    }
79
80    pub fn green() -> LedColor {
81        LedColor::new(0, 255, 0)
82    }
83
84    pub fn blue() -> LedColor {
85        LedColor::new(0, 0, 255)
86    }
87
88    pub fn yellow() -> LedColor {
89        LedColor::new(255, 255, 0)
90    }
91
92    pub fn cyan() -> LedColor {
93        LedColor::new(0, 255, 255)
94    }
95
96    pub fn magenta() -> LedColor {
97        LedColor::new(255, 0, 255)
98    }
99
100    pub fn white() -> LedColor {
101        LedColor::new(255, 255, 255)
102    }
103
104    pub fn off() -> LedColor {
105        LedColor::new(0, 0, 0)
106    }
107}
108
109impl From<String> for LedColor {
110    fn from(value: String) -> Self {
111        // try match hex
112
113        if value.starts_with("#") {
114            let hex = value.trim_start_matches("#");
115            let red = i32::from_str_radix(&hex[0..2], 16).unwrap();
116            let green = i32::from_str_radix(&hex[2..4], 16).unwrap();
117            let blue = i32::from_str_radix(&hex[4..6], 16).unwrap();
118            return LedColor::new(red, green, blue);
119        }
120
121        // try match rgb
122        let mut parts = value.split(",");
123        if let (Some(red), Some(green), Some(blue)) = (parts.next(), parts.next(), parts.next()) {
124            return LedColor::new(red.parse().unwrap(), green.parse().unwrap(), blue.parse().unwrap());
125        }
126
127        // try match normal color
128        match value.to_lowercase().as_str() {
129            "red" => LedColor::new(255, 0, 0),
130            "green" => LedColor::new(0, 255, 0),
131            "blue" => LedColor::new(0, 0, 255),
132            "yellow" => LedColor::new(255, 255, 0),
133            "cyan" => LedColor::new(0, 255, 255),
134            "magenta" => LedColor::new(255, 0, 255),
135            "white" => LedColor::new(255, 255, 255),
136            "black" => LedColor::new(0, 0, 0),
137            _ => panic!("Invalid color")
138        }
139    }
140}
141
142impl Into<i64> for LedColor {
143    fn into(self) -> i64 {
144        ((self.red << 16) | (self.green << 8) | self.blue) as i64
145    }
146}
147
148impl Led {
149    pub async fn set_color(&self, color: LedColor) -> Result<(), String> {
150        self.run_command(RpcFunction::SetColor, vec![Argument::Int(color.into())]).await
151        .map(|_| ())
152    }
153
154    pub async fn set_brightness(&self, brightness: i32) -> Result<(), String> {
155        let brightness = brightness.min(255).max(0);
156        self.run_command(RpcFunction::SetBrightness, vec![Argument::Int(brightness as i64)]).await
157        .map(|_| ())
158    }
159}