1use get_if_addrs::{get_if_addrs, IfAddr, Ifv4Addr};
8use lifx_rs::lan::{get_product_info, BuildOptions, Message, PowerLevel, ProductInfo, RawMessage, HSBK};
9use std::collections::HashMap;
10use std::net::{IpAddr, SocketAddr, UdpSocket};
11use std::sync::{Arc, Mutex};
12use std::thread::{spawn};
13use std::time::{Duration, Instant};
14use rouille::try_or_400;
15use rand::{thread_rng, Rng};
16use rand::distributions::Alphanumeric;
17use std::thread;
18
19use rouille::Response;
20use rouille::post_input;
21
22
23use serde::{Serialize, Deserialize};
24
25use palette::FromColor;
26
27use colors_transform::{Rgb, Color};
28
29
30
31const HOUR: Duration = Duration::from_secs(60 * 60);
32
33
34#[derive(Debug)]
35struct RefreshableData<T> {
36 data: Option<T>,
37 max_age: Duration,
38 last_updated: Instant,
39 refresh_msg: Message,
40}
41
42impl<T> RefreshableData<T> {
43 fn empty(max_age: Duration, refresh_msg: Message) -> RefreshableData<T> {
44 RefreshableData {
45 data: None,
46 max_age,
47 last_updated: Instant::now(),
48 refresh_msg,
49 }
50 }
51 fn update(&mut self, data: T) {
52 self.data = Some(data);
53 self.last_updated = Instant::now();
54
55
56 }
57 fn needs_refresh(&self) -> bool {
58 self.data.is_none() || self.last_updated.elapsed() > self.max_age
59 }
60 fn as_ref(&self) -> Option<&T> {
61 self.data.as_ref()
62 }
63}
64
65#[derive(Debug, Serialize)]
66struct BulbInfo {
67 pub id: String,
68 pub uuid: String,
69 pub label: String,
70 pub connected: bool,
71 pub power: String,
72 #[serde(rename = "color")]
73 pub lifx_color: Option<LifxColor>,
74 pub brightness: f64,
75 #[serde(rename = "group")]
76 pub lifx_group: Option<LifxGroup>,
77 #[serde(rename = "location")]
78 pub lifx_location: Option<LifxLocation>,
79 pub product: Option<ProductInfo>,
80 #[serde(rename = "last_seen")]
81 pub lifx_last_seen: String,
82 #[serde(rename = "seconds_since_seen")]
83 pub seconds_since_seen: i64,
84 #[serde(skip_serializing)]
88 last_seen: Instant,
89
90 source: u32,
91
92 target: u64,
93
94 addr: SocketAddr,
95
96 #[serde(skip_serializing)]
97 group: RefreshableData<LifxGroup>,
98
99
100 #[serde(skip_serializing)]
101 name: RefreshableData<String>,
102 #[serde(skip_serializing)]
103 model: RefreshableData<(u32, u32)>,
104 #[serde(skip_serializing)]
105 location: RefreshableData<String>,
106 #[serde(skip_serializing)]
107 host_firmware: RefreshableData<u32>,
108 #[serde(skip_serializing)]
109 wifi_firmware: RefreshableData<u32>,
110 #[serde(skip_serializing)]
111 power_level: RefreshableData<PowerLevel>,
112 #[serde(skip_serializing)]
113 color: LiColor,
114}
115
116#[derive(Debug)]
117enum LiColor {
118 Unknown,
119 Single(RefreshableData<HSBK>),
120 Multi(RefreshableData<Vec<Option<HSBK>>>),
121}
122
123#[derive(Debug, Serialize)]
124#[serde(rename_all = "camelCase")]
125#[doc(hidden)]
126pub struct LifxLocation {
127 pub id: String,
128 pub name: String,
129}
130
131#[derive(Debug, Serialize)]
133#[serde(rename_all = "camelCase")]
134pub struct LifxColor {
135 pub hue: u16,
136 pub saturation: u16,
137 pub kelvin: u16,
138 pub brightness: u16,
139}
140
141#[derive(Debug, Serialize)]
142#[serde(rename_all = "camelCase")]
143#[doc(hidden)]
144pub struct LifxGroup {
145 pub id: String,
146 pub name: String,
147}
148
149impl BulbInfo {
150 fn new(source: u32, target: u64, addr: SocketAddr) -> BulbInfo {
151 let id: String = thread_rng().sample_iter(&Alphanumeric).take(12).map(char::from).collect();
152 let uuid: String = thread_rng().sample_iter(&Alphanumeric).take(30).map(char::from).collect();
153 BulbInfo {
154 id: id.to_string(),
155 uuid: uuid.to_string(),
156 label: format!(""),
157 connected: true,
158 power: format!("off"),
159 lifx_color: None,
160 brightness: 0.0,
161 lifx_group: None,
162 lifx_location: None,
163 product: None,
164 lifx_last_seen: format!(""),
165 seconds_since_seen: 0,
166 last_seen: Instant::now(),
167 source,
168 target,
169 addr,
170 group: RefreshableData::empty(HOUR, Message::GetGroup),
171 location: RefreshableData::empty(HOUR, Message::GetLocation),
172 name: RefreshableData::empty(HOUR, Message::GetLabel),
173 model: RefreshableData::empty(HOUR, Message::GetVersion),
174 host_firmware: RefreshableData::empty(HOUR, Message::GetHostFirmware),
175 wifi_firmware: RefreshableData::empty(HOUR, Message::GetWifiFirmware),
176 power_level: RefreshableData::empty(Duration::from_millis(500), Message::GetPower),
177 color: LiColor::Unknown,
178 }
179 }
180
181 fn update(&mut self, addr: SocketAddr) {
182 self.last_seen = Instant::now();
183 self.addr = addr;
184 }
185
186 fn refresh_if_needed<T>(
187 &self,
188 sock: &UdpSocket,
189 data: &RefreshableData<T>,
190 ) -> Result<(), failure::Error> {
191 if data.needs_refresh() {
192 let options = BuildOptions {
193 target: Some(self.target),
194 res_required: true,
195 source: self.source,
196 ..Default::default()
197 };
198 let message = RawMessage::build(&options, data.refresh_msg.clone())?;
199 sock.send_to(&message.pack()?, self.addr)?;
200 }
201 Ok(())
202 }
203
204 fn set_power(
205 &self,
206 sock: &UdpSocket,
207 power_level: PowerLevel,
208 ) -> Result<(), failure::Error> {
209
210 let options = BuildOptions {
211 target: Some(self.target),
212 res_required: true,
213 source: self.source,
214 ..Default::default()
215 };
216 let message = RawMessage::build(&options, Message::SetPower{level: power_level})?;
217 sock.send_to(&message.pack()?, self.addr)?;
218
219 Ok(())
220 }
221
222 fn set_infrared(
223 &self,
224 sock: &UdpSocket,
225 brightness: u16,
226 ) -> Result<(), failure::Error> {
227
228 let options = BuildOptions {
229 target: Some(self.target),
230 res_required: true,
231 source: self.source,
232 ..Default::default()
233 };
234 let message = RawMessage::build(&options, Message::LightSetInfrared{brightness: brightness})?;
235 sock.send_to(&message.pack()?, self.addr)?;
236
237 Ok(())
238 }
239
240
241 fn set_color(
242 &self,
243 sock: &UdpSocket,
244 color: HSBK,
245 duration: u32
246 ) -> Result<(), failure::Error> {
247
248 let options = BuildOptions {
249 target: Some(self.target),
250 res_required: true,
251 source: self.source,
252 ..Default::default()
253 };
254 let message = RawMessage::build(&options, Message::LightSetColor{reserved: 0, color: color, duration: duration})?;
255 sock.send_to(&message.pack()?, self.addr)?;
256
257 Ok(())
258 }
259
260
261
262
263 fn query_for_missing_info(&self, sock: &UdpSocket) -> Result<(), failure::Error> {
264 self.refresh_if_needed(sock, &self.name)?;
265 self.refresh_if_needed(sock, &self.model)?;
266 self.refresh_if_needed(sock, &self.location)?;
267 self.refresh_if_needed(sock, &self.host_firmware)?;
268 self.refresh_if_needed(sock, &self.wifi_firmware)?;
269 self.refresh_if_needed(sock, &self.power_level)?;
270 self.refresh_if_needed(sock, &self.group)?;
271 match &self.color {
272 LiColor::Unknown => (), LiColor::Single(d) => self.refresh_if_needed(sock, d)?,
274 LiColor::Multi(d) => self.refresh_if_needed(sock, d)?,
275 }
276
277
278
279 Ok(())
280 }
281}
282
283struct Manager {
346 bulbs: Arc<Mutex<HashMap<u64, BulbInfo>>>,
347 last_discovery: Instant,
348 sock: UdpSocket,
349 source: u32,
350}
351
352impl Manager {
353 fn new() -> Result<Manager, failure::Error> {
354 let sock = UdpSocket::bind("0.0.0.0:56700")?;
355 sock.set_broadcast(true)?;
356
357 let recv_sock = sock.try_clone()?;
359
360 let bulbs = Arc::new(Mutex::new(HashMap::new()));
361 let receiver_bulbs = bulbs.clone();
362 let source = 0x72757374;
363
364 spawn(move || Self::worker(recv_sock, source, receiver_bulbs));
366
367 let mut mgr = Manager {
368 bulbs,
369 last_discovery: Instant::now(),
370 sock,
371 source,
372 };
373 mgr.discover()?;
374 Ok(mgr)
375 }
376
377 fn handle_message(raw: RawMessage, bulb: &mut BulbInfo) -> Result<(), lifx_rs::lan::Error> {
378 match Message::from_raw(&raw)? {
379 Message::StateService { port: _, service: _ } => {
380 }
384 Message::StateLabel { label } => {
385 bulb.name.update(label.0);
386 bulb.label = bulb.name.data.as_ref().unwrap().to_string();
387
388 },
389
390
391 Message::StateLocation { location, label, updated_at: _ } => {
392
393 let lab = label.0;
394
395 bulb.location.update(lab.clone());
396
397
398
399 let group_two = LifxLocation{id: format!("{:?}", location.0).replace(", ", "").replace("[", "").replace("]", ""), name: lab};
400 bulb.lifx_location = Some(group_two);
401
402 },
403 Message::StateVersion {
404 vendor, product, ..
405 } => {
406 bulb.model.update((vendor, product));
407 if let Some(info) = get_product_info(vendor, product) {
408 bulb.product = Some(info.clone());
411
412 if info.capabilities.has_multizone {
413 bulb.color = LiColor::Multi(RefreshableData::empty(
414 Duration::from_secs(15),
415 Message::GetColorZones {
416 start_index: 0,
417 end_index: 255,
418 },
419 ))
420 } else {
421 bulb.color = LiColor::Single(RefreshableData::empty(
422 Duration::from_secs(15),
423 Message::LightGet,
424 ))
425 }
426 }
427 }
428 Message::StatePower { level } => {
429 bulb.power_level.update(level);
430
431 if bulb.power_level.data.as_ref().unwrap() == &PowerLevel::Enabled{
432 bulb.power = format!("on");
433 } else {
434 bulb.power = format!("off");
435 }
436
437
438 },
439
440 Message::StateGroup { group, label, updated_at: _ } => {
441
442 let group_one = LifxGroup{id: format!("{:?}", group.0), name: label.to_string()};
443
444 let group_two = LifxGroup{id: format!("{:?}", group.0).replace(", ", "").replace("[", "").replace("]", ""), name: label.to_string()};
445 bulb.group.update(group_one);
446 bulb.lifx_group = Some(group_two);
447 },
448
449
450
451 Message::StateHostFirmware { version, .. } => bulb.host_firmware.update(version),
452 Message::StateWifiFirmware { version, .. } => bulb.wifi_firmware.update(version),
453 Message::LightState {
454 color,
455 power,
456 label,
457 ..
458 } => {
459 if let LiColor::Single(ref mut d) = bulb.color {
460 d.update(color);
461
462 let bc = color;
463
464
465 bulb.lifx_color = Some(LifxColor{
466 hue: bc.hue,
467 saturation: bc.saturation,
468 kelvin: bc.kelvin,
469 brightness: bc.brightness,
470 });
471
472 bulb.brightness = (bc.brightness / 65535) as f64;
473
474
475 bulb.power_level.update(power);
476 }
477 bulb.name.update(label.0);
478 }
479 Message::StateZone {
480 count,
481 index,
482 color,
483 } => {
484 if let LiColor::Multi(ref mut d) = bulb.color {
485 d.data.get_or_insert_with(|| {
486 let mut v = Vec::with_capacity(count as usize);
487 v.resize(count as usize, None);
488 assert!(index <= count);
489 v
490 })[index as usize] = Some(color);
491 }
492 }
493 Message::StateMultiZone {
494 count,
495 index,
496 color0,
497 color1,
498 color2,
499 color3,
500 color4,
501 color5,
502 color6,
503 color7,
504 } => {
505 if let LiColor::Multi(ref mut d) = bulb.color {
506 let v = d.data.get_or_insert_with(|| {
507 let mut v = Vec::with_capacity(count as usize);
508 v.resize(count as usize, None);
509 assert!(index + 7 <= count);
510 v
511 });
512
513 v[index as usize + 0] = Some(color0);
514 v[index as usize + 1] = Some(color1);
515 v[index as usize + 2] = Some(color2);
516 v[index as usize + 3] = Some(color3);
517 v[index as usize + 4] = Some(color4);
518 v[index as usize + 5] = Some(color5);
519 v[index as usize + 6] = Some(color6);
520 v[index as usize + 7] = Some(color7);
521 }
522 }
523 unknown => {
524 println!("Received, but ignored {:?}", unknown);
525 }
526 }
527 Ok(())
528 }
529
530 fn worker(
531 recv_sock: UdpSocket,
532 source: u32,
533 receiver_bulbs: Arc<Mutex<HashMap<u64, BulbInfo>>>,
534 ) {
535 let mut buf = [0; 1024];
536 loop {
537 match recv_sock.recv_from(&mut buf) {
538 Ok((0, addr)) => println!("Received a zero-byte datagram from {:?}", addr),
539 Ok((nbytes, addr)) => match RawMessage::unpack(&buf[0..nbytes]) {
540 Ok(raw) => {
541 if raw.frame_addr.target == 0 {
542 continue;
543 }
544 if let Ok(mut bulbs) = receiver_bulbs.lock() {
545 let bulb = bulbs
546 .entry(raw.frame_addr.target)
547 .and_modify(|bulb| bulb.update(addr))
548 .or_insert_with(|| {
549 BulbInfo::new(source, raw.frame_addr.target, addr)
550 });
551 if let Err(e) = Self::handle_message(raw, bulb) {
552 println!("Error handling message from {}: {}", addr, e)
553 }
554 }
555 }
556 Err(e) => println!("Error unpacking raw message from {}: {}", addr, e),
557 },
558 Err(e) => panic!("recv_from err {:?}", e),
559 }
560 }
561 }
562
563 fn discover(&mut self) -> Result<(), failure::Error> {
564 println!("Doing discovery");
565
566 let opts = BuildOptions {
567 source: self.source,
568 ..Default::default()
569 };
570 let rawmsg = RawMessage::build(&opts, Message::GetService).unwrap();
571 let bytes = rawmsg.pack().unwrap();
572
573 for addr in get_if_addrs().unwrap() {
574 match addr.addr {
575 IfAddr::V4(Ifv4Addr {
576 broadcast: Some(bcast),
577 ..
578 }) => {
579 if addr.ip().is_loopback() {
580 continue;
581 }
582 let addr = SocketAddr::new(IpAddr::V4(bcast), 56700);
583 println!("Discovering bulbs on LAN {:?}", addr);
584 self.sock.send_to(&bytes, &addr)?;
585 }
586 _ => {}
587 }
588 }
589
590 self.last_discovery = Instant::now();
591
592 Ok(())
593 }
594
595 fn refresh(&self) {
596 if let Ok(bulbs) = self.bulbs.lock() {
597 for bulb in bulbs.values() {
598 match bulb.query_for_missing_info(&self.sock){
599 Ok(_missing_info) => {
600 },
601 Err(e) => {
602 println!("Error querying for missing info: {:?}", e);
603 }
604 }
605 }
606 }
607 }
608}
609
610#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
612#[serde(rename_all = "camelCase")]
613pub struct Config {
614 pub secret_key: String,
615 pub port: u16,
616}
617
618pub fn start(config: Config) {
619
620
621 sudo::with_env(&["SECRET_KEY"]).unwrap();
622 sudo::escalate_if_needed().unwrap();
623
624
625 let mgr = Manager::new();
626
627 match mgr {
628 Ok(mgr) => {
629 let mgr_arc = Arc::new(Mutex::new(mgr));
630
631 let th_arc_mgr = Arc::clone(&mgr_arc);
632
633 thread::spawn(move || {
634 loop{
635 let mut lock = th_arc_mgr.lock().unwrap();
636 let mgr = &mut *lock;
637
638 mgr.refresh();
643 std::mem::drop(mgr);
644 std::mem::drop(lock);
645 thread::sleep(Duration::from_millis(1000));
646 }
647
648 });
649
650
651 let th2_arc_mgr = Arc::clone(&mgr_arc);
652
653 thread::spawn(move || {
654 rouille::start_server(format!("0.0.0.0:{}", config.port).as_str(), move |request| {
655
656
657 let auth_header = request.header("Authorization");
658
659 if auth_header.is_none(){
660 return Response::empty_404();
661 } else {
662 if auth_header.unwrap().to_string() != format!("Bearer {}", config.secret_key){
663 return Response::empty_404();
664 }
665 }
666
667
668
669
670 let mut response = Response::text("hello world");
671
672 let mut lock = th2_arc_mgr.lock().unwrap();
673 let mgr = &mut *lock;
674
675
676 mgr.refresh();
677
678
679 let urls = request.url().to_string();
680 let split = urls.split("/");
681 let vec: Vec<&str> = split.collect();
682
683 let mut selector = "";
684
685 if vec.len() >= 3 {
686 selector = vec[3];
687 }
688
689
690
691 let mut bulbs_vec: Vec<&BulbInfo> = Vec::new();
692
693 let bulbs = mgr.bulbs.lock().unwrap();
694
695
696 for bulb in bulbs.values() {
697 println!("{:?}", *bulb);
698 bulbs_vec.push(bulb);
699 }
700
701 if selector == "all"{
702
703 }
704
705 if selector.contains("group_id:"){
706 bulbs_vec = bulbs_vec
707 .into_iter()
708 .filter(|b| b.lifx_group.as_ref().unwrap().id.contains(&selector.replace("group_id:", "")))
709 .collect();
710 }
711
712 if selector.contains("location_id:"){
713 bulbs_vec = bulbs_vec
714 .into_iter()
715 .filter(|b| b.lifx_location.as_ref().unwrap().id.contains(&selector.replace("location_id:", "")))
716 .collect();
717 }
718
719 if selector.contains("id:"){
720 bulbs_vec = bulbs_vec
721 .into_iter()
722 .filter(|b| b.id.contains(&selector.replace("id:", "")))
723 .collect();
724 }
725
726
727 if request.url().contains("/lights/states"){
731 }
735
736 if request.url().contains("/state"){
739
740 let input = try_or_400!(post_input!(request, {
741 power: Option<String>,
742 color: Option<String>,
743 brightness: Option<f64>,
744 duration: Option<f64>,
745 infrared: Option<f64>,
746 fast: Option<bool>
747 }));
748
749
750 if input.power.is_some() {
752 let power = input.power.unwrap();
753 if power == format!("on"){
754 for bulb in &bulbs_vec {
755 bulb.set_power(&mgr.sock, PowerLevel::Enabled);
756 }
757 }
758
759 if power == format!("off"){
760 for bulb in &bulbs_vec {
761 bulb.set_power(&mgr.sock, PowerLevel::Standby);
762 }
763 }
764 }
765
766 if input.color.is_some() {
768 let cc = input.color.unwrap();
769
770
771
772 for bulb in &bulbs_vec {
773
774
775 let mut kelvin = 6500;
776 let mut brightness = 65535;
777 let mut saturation = 0;
778 let mut hue = 0;
779
780 let mut duration = 0;
781 if input.duration.is_some(){
782 duration = input.duration.unwrap() as u32;
783 }
784
785 if bulb.lifx_color.is_some() {
786 let lifxc = bulb.lifx_color.as_ref().unwrap();
787 kelvin = lifxc.kelvin;
788 brightness = lifxc.brightness;
789 saturation = lifxc.saturation;
790 hue = lifxc.hue;
791 }
792
793 if cc.contains("white"){
794 let hbsk_set = HSBK {
795 hue: 0,
796 saturation: 0,
797 brightness: brightness,
798 kelvin: kelvin,
799 };
800 bulb.set_color(&mgr.sock, hbsk_set, duration);
801 }
802
803 if cc.contains("red"){
804 let hbsk_set = HSBK {
805 hue: 0,
806 saturation: 65535,
807 brightness: brightness,
808 kelvin: kelvin,
809 };
810 bulb.set_color(&mgr.sock, hbsk_set, duration);
811 }
812
813 if cc.contains("orange"){
814 let hbsk_set = HSBK {
815 hue: 7098,
816 saturation: 65535,
817 brightness: brightness,
818 kelvin: kelvin,
819 };
820 bulb.set_color(&mgr.sock, hbsk_set, duration);
821 }
822
823 if cc.contains("yellow"){
824 let hbsk_set = HSBK {
825 hue: 10920,
826 saturation: 65535,
827 brightness: brightness,
828 kelvin: kelvin,
829 };
830 bulb.set_color(&mgr.sock, hbsk_set, duration);
831 }
832
833 if cc.contains("cyan"){
834 let hbsk_set = HSBK {
835 hue: 32760,
836 saturation: 65535,
837 brightness: brightness,
838 kelvin: kelvin,
839 };
840 bulb.set_color(&mgr.sock, hbsk_set, duration);
841 }
842
843 if cc.contains("green"){
844 let hbsk_set = HSBK {
845 hue: 21840,
846 saturation: 65535,
847 brightness: brightness,
848 kelvin: kelvin,
849 };
850 bulb.set_color(&mgr.sock, hbsk_set, duration);
851 }
852
853 if cc.contains("blue"){
854 let hbsk_set = HSBK {
855 hue: 43680,
856 saturation: 65535,
857 brightness: brightness,
858 kelvin: kelvin,
859 };
860 bulb.set_color(&mgr.sock, hbsk_set, duration);
861 }
862
863 if cc.contains("purple"){
864 let hbsk_set = HSBK {
865 hue: 50050,
866 saturation: 65535,
867 brightness: brightness,
868 kelvin: kelvin,
869 };
870 bulb.set_color(&mgr.sock, hbsk_set, duration);
871 }
872
873 if cc.contains("pink"){
874 let hbsk_set = HSBK {
875 hue: 63700,
876 saturation: 25000,
877 brightness: brightness,
878 kelvin: kelvin,
879 };
880 bulb.set_color(&mgr.sock, hbsk_set, duration);
881 }
882
883
884 if cc.contains("hue:"){
885
886 let hue_split = cc.split("hue:");
887 let hue_vec: Vec<&str> = hue_split.collect();
888 let new_hue = hue_vec[1].to_string().parse::<u16>().unwrap();
889 let hbsk_set = HSBK {
890 hue: new_hue,
891 saturation: saturation,
892 brightness: brightness,
893 kelvin: kelvin,
894 };
895 bulb.set_color(&mgr.sock, hbsk_set, duration);
896 }
897
898 if cc.contains("saturation:"){
899 let saturation_split = cc.split("saturation:");
900 let saturation_vec: Vec<&str> = saturation_split.collect();
901 let new_saturation_float = saturation_vec[1].to_string().parse::<f64>().unwrap();
902 let new_saturation: u16 = (f64::from(100) * new_saturation_float) as u16;
903 let hbsk_set = HSBK {
904 hue: hue,
905 saturation: new_saturation,
906 brightness: brightness,
907 kelvin: kelvin,
908 };
909 bulb.set_color(&mgr.sock, hbsk_set, duration);
910 }
911
912 if cc.contains("brightness:"){
913 let brightness_split = cc.split("brightness:");
914 let brightness_vec: Vec<&str> = brightness_split.collect();
915 let new_brightness_float = brightness_vec[1].to_string().parse::<f64>().unwrap();
916 let new_brightness: u16 = (f64::from(65535) * new_brightness_float) as u16;
917 let hbsk_set = HSBK {
918 hue: hue,
919 saturation: saturation,
920 brightness: new_brightness,
921 kelvin: kelvin,
922 };
923 bulb.set_color(&mgr.sock, hbsk_set, duration);
924 }
925
926 if cc.contains("kelvin:"){
927 let kelvin_split = cc.split("kelvin:");
928 let kelvin_vec: Vec<&str> = kelvin_split.collect();
929 let new_kelvin = kelvin_vec[1].to_string().parse::<u16>().unwrap();
930 let hbsk_set = HSBK {
931 hue: hue,
932 saturation: 0,
933 brightness: brightness,
934 kelvin: new_kelvin,
935 };
936 bulb.set_color(&mgr.sock, hbsk_set, duration);
937 }
938
939 if cc.contains("rgb:"){
940
941
942 let rgb_split = cc.split("rgb:");
943 let rgb_vec: Vec<&str> = rgb_split.collect();
944 let rgb_parts = rgb_vec[1].to_string();
945
946 let rgb_part_split = rgb_parts.split(",");
947 let rgb_parts_vec: Vec<&str> = rgb_part_split.collect();
948
949 let red_int = rgb_parts_vec[0].to_string().parse::<i64>().unwrap();
950 let red_float: f32 = (red_int) as f32;
951
952 let green_int = rgb_parts_vec[1].to_string().parse::<i64>().unwrap();
953 let green_float: f32 = (green_int) as f32;
954
955 let blue_int = rgb_parts_vec[2].to_string().parse::<i64>().unwrap();
956 let blue_float: f32 = (blue_int) as f32;
957
958 let hcc = palette::Hsv::from_rgb(palette::Rgb{
959 red: red_float,
960 green: green_float,
961 blue: blue_float,
962 });
963
964 let hbsk_set = HSBK {
966 hue: (hcc.hue.to_positive_degrees() * 182.0) as u16,
967 saturation: (hcc.saturation.to_degrees() * 1000.0) as u16,
968 brightness: brightness,
969 kelvin: kelvin,
970 };
971
972
973 bulb.set_color(&mgr.sock, hbsk_set, duration);
974
975 }
976
977 if cc.contains("#"){
978 println!("!CC!");
979 let hex_split = cc.split("#");
980 let hex_vec: Vec<&str> = hex_split.collect();
981 let hex = hex_vec[1].to_string();
982
983 let rgb2 = Rgb::from_hex_str(format!("#{}", hex).as_str()).unwrap();
984 println!("{:?}", rgb2);
987
988 let red_int = rgb2.get_red().to_string().parse::<i64>().unwrap();
989 let red_float: f32 = (red_int) as f32;
990
991 let green_int = rgb2.get_green().to_string().parse::<i64>().unwrap();
992 let green_float: f32 = (green_int) as f32;
993
994 let blue_int = rgb2.get_blue().to_string().parse::<i64>().unwrap();
995 let blue_float: f32 = (blue_int) as f32;
996
997
998 println!("red_float: {:?}", red_float);
999 println!("green_float: {:?}", green_float);
1000 println!("blue_float: {:?}", blue_float);
1001
1002
1003 let hcc = palette::Hsv::from_rgb(palette::Rgb{
1004 red: red_float,
1005 green: green_float,
1006 blue: blue_float,
1007 });
1008
1009 println!("hcc: {:?}", hcc);
1010
1011 let hbsk_set = HSBK {
1013 hue: (hcc.hue.to_positive_degrees() * 182.0) as u16,
1014 saturation: (hcc.saturation.to_degrees() * 1000.0) as u16,
1015 brightness: brightness,
1016 kelvin: kelvin,
1017 };
1018
1019 println!("hbsk_set: {:?}", hbsk_set);
1020
1021
1022
1023 bulb.set_color(&mgr.sock, hbsk_set, duration);
1024
1025 }
1026
1027 }
1028 }
1029
1030
1031 if input.brightness.is_some() {
1033 let brightness = input.brightness.unwrap();
1034
1035 for bulb in &bulbs_vec {
1036
1037
1038 let mut kelvin = 6500;
1039 let mut saturation = 0;
1040 let mut hue = 0;
1041
1042 let mut duration = 0;
1043 if input.duration.is_some(){
1044 duration = input.duration.unwrap() as u32;
1045 }
1046
1047 if bulb.lifx_color.is_some() {
1048 let lifxc = bulb.lifx_color.as_ref().unwrap();
1049 kelvin = lifxc.kelvin;
1050 saturation = lifxc.saturation;
1051 hue = lifxc.hue;
1052 }
1053
1054 let new_brightness_float = brightness.to_string().parse::<f64>().unwrap();
1055 let new_brightness: u16 = (f64::from(65535) * new_brightness_float) as u16;
1056 let hbsk_set = HSBK {
1057 hue: hue,
1058 saturation: saturation,
1059 brightness: new_brightness,
1060 kelvin: kelvin,
1061 };
1062 bulb.set_color(&mgr.sock, hbsk_set, duration);
1063
1064 }
1065
1066 }
1067
1068 if input.infrared.is_some() {
1070 let new_brightness: u16 = (f64::from(65535) * input.infrared.unwrap()) as u16;
1071
1072 for bulb in &bulbs_vec {
1073 bulb.set_infrared(&mgr.sock, new_brightness);
1074 }
1075 }
1076
1077
1078 response = Response::text("done");
1093
1094 }
1095
1096
1097 if request.url().contains("/v1/lights/") && !request.url().contains("/state"){
1100 response = Response::json(&bulbs_vec.clone());
1101 }
1102
1103
1104 std::mem::drop(bulbs);
1106 std::mem::drop(mgr);
1107 std::mem::drop(lock);
1108
1109 return response;
1110 });
1111 });
1112
1113
1114 },
1115 Err(e) => {
1116 println!("{:?}", e);
1117 }
1118 }
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129}