diff --git a/README.md b/README.md index e15d8d0..a2788a3 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,2 @@ -# Ambilight -Updates homeasssistant lights based upon screenshots. +# Ambilight +Updates homeasssistant lights based upon screenshots. diff --git a/src/main.rs b/src/main.rs index d09b495..73e28c1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,120 +1,120 @@ -use reqwest::Client; -use serde::Serialize; -use std::time::{Duration, Instant}; - -use win_screenshot::prelude::*; - -const URL: &str = "https://homeassistant.pvv.ntnu.no:8123/api/services/light/turn_on"; -const TOKEN: &str = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiI4YWVmZWI2ZjYwNDg0ZmJlODNkOWI2YTUyM2UwODk4NCIsImlhdCI6MTc3MzI0MzYxNywiZXhwIjoyMDg4NjAzNjE3fQ.xZ9pWCymgwfJfyQdgdHmiFMuDgmstfpx1vDohl34_rw"; - -#[derive(Serialize, Clone)] -struct Payload { - entity_id: String, - brightness: u8, - rgb_color: [u8; 3], -} - -#[tokio::main] -async fn main() { - let client = Client::new(); - let mut payload = Payload { - entity_id: String::from("light.fargelys"), - brightness: 200, - rgb_color: [0, 0, 0], - }; - let logging = false; - let time_between_requests = Duration::from_millis(100); - let mut moving_average = [0u8; 3]; - let beta = 0.9f64; - loop { - let frame_start = Instant::now(); - let v = loop { - let buf = capture_display().unwrap(); - - let now = Instant::now(); - let v = - get_next_rgb_value_for_asynchronously_setting_mood_lights_in_koserommet_at_pvv_by_using_a_mean(buf); - let elapsed = now.elapsed(); - if logging { - println!( - "calculated average pixel value in: {} milliseconds", - elapsed.as_millis() - ); - println!("new_rgb_color: {:?}", v); - println!("rgb_color: {:?}", payload.rgb_color); - } - - std::thread::sleep(Duration::from_millis(33)); - if frame_start.elapsed() > time_between_requests { - for i in 0..3 { - moving_average[i] = - (moving_average[i] as f64 * beta + v[i] as f64 * (1.0 - beta)) as u8; - } - payload.rgb_color = moving_average; - break moving_average; - } - }; - payload.rgb_color = v; - let now = Instant::now(); - client - .post(URL) - .bearer_auth(TOKEN) - .body(serde_json::to_string(&payload).unwrap()) - .send() - .await - .unwrap() - .text() - .await - .unwrap(); - let elapsed = now.elapsed(); - if logging { - println!("got response in: {} milliseconds", elapsed.as_millis()); - } - } -} - -fn get_next_rgb_value_for_asynchronously_setting_mood_lights_in_koserommet_at_pvv_by_using_a_mean( - frame: RgbBuf, -) -> [u8; 3] { - let pixel_count = frame.width as u64 * frame.height as u64; - let v: [u8; 3] = frame - .pixels - .chunks_exact(4) - .fold([0u64, 0u64, 0u64], |[acc_r, acc_g, acc_b], pixel| { - [ - acc_r + pixel[0] as u64, - acc_g + pixel[1] as u64, - acc_b + pixel[2] as u64, - ] - }) - .map(|sum| (sum / pixel_count) as u8); - v -} - -fn get_next_rgb_value_for_asynchronously_setting_mood_lights_in_koserommet_at_pvv_by_finding_main_colors( - frame: RgbBuf, -) -> [u8; 3] { - let v: Vec = frame - .pixels - .iter() - .enumerate() - .filter(|(i, _)| i % 4 != 3) - .map(|(_, n)| *n) - .collect(); - let mut output = okmain::colors( - okmain::InputImage::from_bytes(frame.width as u16, frame.height as u16, &v).unwrap(), - ); - let a = output.pop().unwrap(); - [a.r, a.g, a.b] -} - -fn _color_difference_is_great_enough_for_making_a_request_to_change_light_colors_using_euclidian_distance( - a: [u8; 3], - b: [u8; 3], -) -> f64 { - (((a[0].max(b[0]) - a[0].min(b[0])) as f64).powf(2.0) - + ((a[1].max(b[1]) - a[1].min(b[1])) as f64).powf(2.0) - + ((a[2].max(b[2]) - a[2].min(b[2])) as f64).powf(2.0)) - .sqrt() - / ((255.0f64.powf(2.0) * 3.0).sqrt()) -} +use reqwest::Client; +use serde::Serialize; +use std::time::{Duration, Instant}; + +use win_screenshot::prelude::*; + +const URL: &str = "https://homeassistant.pvv.ntnu.no:8123/api/services/light/turn_on"; +const TOKEN: &str = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiI4YWVmZWI2ZjYwNDg0ZmJlODNkOWI2YTUyM2UwODk4NCIsImlhdCI6MTc3MzI0MzYxNywiZXhwIjoyMDg4NjAzNjE3fQ.xZ9pWCymgwfJfyQdgdHmiFMuDgmstfpx1vDohl34_rw"; + +#[derive(Serialize, Clone)] +struct Payload { + entity_id: String, + brightness: u8, + rgb_color: [u8; 3], +} + +#[tokio::main] +async fn main() { + let client = Client::new(); + let mut payload = Payload { + entity_id: String::from("light.fargelys"), + brightness: 200, + rgb_color: [0, 0, 0], + }; + let logging = false; + let time_between_requests = Duration::from_millis(100); + let mut moving_average = [0u8; 3]; + let beta = 0.9f64; + loop { + let frame_start = Instant::now(); + let v = loop { + let buf = capture_display().unwrap(); + + let now = Instant::now(); + let v = + get_next_rgb_value_for_asynchronously_setting_mood_lights_in_koserommet_at_pvv_by_using_a_mean(buf); + let elapsed = now.elapsed(); + if logging { + println!( + "calculated average pixel value in: {} milliseconds", + elapsed.as_millis() + ); + println!("new_rgb_color: {:?}", v); + println!("rgb_color: {:?}", payload.rgb_color); + } + + std::thread::sleep(Duration::from_millis(33)); + if frame_start.elapsed() > time_between_requests { + for i in 0..3 { + moving_average[i] = + (moving_average[i] as f64 * beta + v[i] as f64 * (1.0 - beta)) as u8; + } + payload.rgb_color = moving_average; + break moving_average; + } + }; + payload.rgb_color = v; + let now = Instant::now(); + client + .post(URL) + .bearer_auth(TOKEN) + .body(serde_json::to_string(&payload).unwrap()) + .send() + .await + .unwrap() + .text() + .await + .unwrap(); + let elapsed = now.elapsed(); + if logging { + println!("got response in: {} milliseconds", elapsed.as_millis()); + } + } +} + +fn get_next_rgb_value_for_asynchronously_setting_mood_lights_in_koserommet_at_pvv_by_using_a_mean( + frame: RgbBuf, +) -> [u8; 3] { + let pixel_count = frame.width as u64 * frame.height as u64; + let v: [u8; 3] = frame + .pixels + .chunks_exact(4) + .fold([0u64, 0u64, 0u64], |[acc_r, acc_g, acc_b], pixel| { + [ + acc_r + pixel[0] as u64, + acc_g + pixel[1] as u64, + acc_b + pixel[2] as u64, + ] + }) + .map(|sum| (sum / pixel_count) as u8); + v +} + +fn get_next_rgb_value_for_asynchronously_setting_mood_lights_in_koserommet_at_pvv_by_finding_main_colors( + frame: RgbBuf, +) -> [u8; 3] { + let v: Vec = frame + .pixels + .iter() + .enumerate() + .filter(|(i, _)| i % 4 != 3) + .map(|(_, n)| *n) + .collect(); + let mut output = okmain::colors( + okmain::InputImage::from_bytes(frame.width as u16, frame.height as u16, &v).unwrap(), + ); + let a = output.pop().unwrap(); + [a.r, a.g, a.b] +} + +fn _color_difference_is_great_enough_for_making_a_request_to_change_light_colors_using_euclidian_distance( + a: [u8; 3], + b: [u8; 3], +) -> f64 { + (((a[0].max(b[0]) - a[0].min(b[0])) as f64).powf(2.0) + + ((a[1].max(b[1]) - a[1].min(b[1])) as f64).powf(2.0) + + ((a[2].max(b[2]) - a[2].min(b[2])) as f64).powf(2.0)) + .sqrt() + / ((255.0f64.powf(2.0) * 3.0).sqrt()) +}