diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 7ba06ec..1473c3f 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -14,7 +14,7 @@ version = "0.7.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" dependencies = [ - "memchr", + "memchr 2.5.0", ] [[package]] @@ -156,7 +156,7 @@ dependencies = [ "gloo-timers", "kv-log-macro", "log", - "memchr", + "memchr 2.5.0", "once_cell", "pin-project-lite", "pin-utils", @@ -326,7 +326,7 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" dependencies = [ - "memchr", + "memchr 2.5.0", ] [[package]] @@ -492,7 +492,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35ed6e9d84f0b51a7f52daf1c7d71dd136fd7a3f41a8462b8cdb8c78d920fad4" dependencies = [ "bytes", - "memchr", + "memchr 2.5.0", ] [[package]] @@ -516,10 +516,16 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" dependencies = [ - "core-foundation-sys", + "core-foundation-sys 0.8.3", "libc", ] +[[package]] +name = "core-foundation-sys" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b" + [[package]] name = "core-foundation-sys" version = "0.8.3" @@ -717,6 +723,72 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "ddc" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba69f2c53e320fc4abad17cb02bbbf04d1a36f18e9907f347589ec5991b3c6c5" +dependencies = [ + "mccs", +] + +[[package]] +name = "ddc-hi" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c6747b17c926a2aa34739b30f1a6cc726e3a7baf0e2f69a4c03a95cf5de94de" +dependencies = [ + "anyhow", + "ddc", + "ddc-i2c", + "ddc-macos", + "ddc-winapi", + "edid", + "log", + "mccs", + "mccs-caps", + "mccs-db", + "nvapi", +] + +[[package]] +name = "ddc-i2c" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66503057bd41fc21b532b3ebe33b2ec57e5d4971fcfc3844306ebcb499b6c8c2" +dependencies = [ + "ddc", + "i2c", + "i2c-linux", + "resize-slice", +] + +[[package]] +name = "ddc-macos" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cbaf316c113cfc30da8856c8104dfb4168b73fdd78562d1542e358fe8299dea" +dependencies = [ + "core-foundation", + "core-foundation-sys 0.8.3", + "core-graphics", + "ddc", + "io-kit-sys", + "mach 0.3.2", + "thiserror", +] + +[[package]] +name = "ddc-winapi" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3238e71b65c870e236de529546a689202fca64a2eaeec43995d28f6920d7fc9e" +dependencies = [ + "ddc", + "widestring", + "winapi 0.3.9", +] + [[package]] name = "derive_more" version = "0.99.17" @@ -775,6 +847,7 @@ dependencies = [ "base64", "bmp", "color_space", + "ddc-hi", "either", "futures", "hex", @@ -828,6 +901,15 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bd4b30a6560bbd9b4620f4de34c3f14f60848e58a9b7216801afcb4c7b31c3c" +[[package]] +name = "edid" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24ce75530893d834dcfe3bb67ce0e7dec489484e7cb4423ca31618af4bab24fe" +dependencies = [ + "nom", +] + [[package]] name = "either" version = "1.8.0" @@ -1035,7 +1117,7 @@ dependencies = [ "fastrand", "futures-core", "futures-io", - "memchr", + "memchr 2.5.0", "parking", "pin-project-lite", "waker-fn", @@ -1076,7 +1158,7 @@ dependencies = [ "futures-macro", "futures-sink", "futures-task", - "memchr", + "memchr 2.5.0", "pin-project-lite", "pin-utils", "slab", @@ -1468,6 +1550,39 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21dec9db110f5f872ed9699c3ecf50cf16f423502706ba5c72462e28d3157573" +[[package]] +name = "i2c" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60c7b7bdd7b3a985fdcf94a0d7d98e7a47fde8b7f22fb55ce1a91cc104a2ce9a" +dependencies = [ + "bitflags", +] + +[[package]] +name = "i2c-linux" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0268a871aaa071221d6c2875ebedcf64710e59b0d87c68c8faf5e98b87dd2a4" +dependencies = [ + "bitflags", + "i2c", + "i2c-linux-sys", + "resize-slice", + "udev", +] + +[[package]] +name = "i2c-linux-sys" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55cd060ed0016621d3da4ed3a23b0158084de90d1f3a8e59f3d391aacd3bbcf8" +dependencies = [ + "bitflags", + "byteorder", + "libc", +] + [[package]] name = "ico" version = "0.2.0" @@ -1504,7 +1619,7 @@ dependencies = [ "globset", "lazy_static", "log", - "memchr", + "memchr 2.5.0", "regex", "same-file", "thread_local", @@ -1559,6 +1674,16 @@ dependencies = [ "cfg-if 1.0.0", ] +[[package]] +name = "io-kit-sys" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f21dcc74995dd4cd090b147e79789f8d65959cbfb5f0b118002db869ea3bd0a0" +dependencies = [ + "core-foundation-sys 0.6.2", + "mach 0.2.3", +] + [[package]] name = "itoa" version = "0.4.8" @@ -1700,6 +1825,16 @@ dependencies = [ "pkg-config", ] +[[package]] +name = "libudev-sys" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c8469b4a23b962c1396b9b451dda50ef5b283e8dd309d69033475fa9b334324" +dependencies = [ + "libc", + "pkg-config", +] + [[package]] name = "libwebp-sys" version = "0.4.2" @@ -1718,6 +1853,12 @@ dependencies = [ "safemem", ] +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + [[package]] name = "lock_api" version = "0.4.9" @@ -1772,6 +1913,24 @@ dependencies = [ "time", ] +[[package]] +name = "mach" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86dd2487cdfea56def77b88438a2c915fb45113c5319bfe7e14306ca4cd0b0e1" +dependencies = [ + "libc", +] + +[[package]] +name = "mach" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa" +dependencies = [ + "libc", +] + [[package]] name = "macos-app-nap" version = "0.0.1" @@ -1821,6 +1980,38 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" +[[package]] +name = "mccs" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74366c6da4179141e0d4551a46799a7e667a68eda60561690d5048bd8e0f8422" +dependencies = [ + "void", +] + +[[package]] +name = "mccs-caps" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9766b1345aec53f3f1781797e31f7367a8c53871a0e30214d8372fe2ccbe3ce" +dependencies = [ + "mccs", + "nom", +] + +[[package]] +name = "mccs-db" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99726fbbe1e11e2908c461e8fab6c9106a5cb13338cc4feb68a01cced38026d0" +dependencies = [ + "mccs", + "nom", + "serde", + "serde_derive", + "serde_yaml", +] + [[package]] name = "mdns" version = "3.0.0" @@ -1837,6 +2028,15 @@ dependencies = [ "net2", ] +[[package]] +name = "memchr" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "148fab2e51b4f1cfc66da2a7c32981d1d3c083a803978268bb11fe4b86925e7a" +dependencies = [ + "libc", +] + [[package]] name = "memchr" version = "2.5.0" @@ -1960,6 +2160,15 @@ version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" +[[package]] +name = "nom" +version = "3.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05aec50c70fd288702bcd93284a8444607f3292dbdf2a30de5ea5dcdbe72287b" +dependencies = [ + "memchr 1.0.2", +] + [[package]] name = "notify-rust" version = "4.6.0" @@ -2042,6 +2251,28 @@ dependencies = [ "syn", ] +[[package]] +name = "nvapi" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c63de8cd8362e2c38d1a48dea6ae68e6293a8d8d22a52180d0f8dcc779b3158" +dependencies = [ + "i2c", + "log", + "nvapi-sys", + "void", +] + +[[package]] +name = "nvapi-sys" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b29e9a9393c69ee856bfcf5f76ed1ef32d2c0dd6f58558fd43334278fc1e7ea7" +dependencies = [ + "bitflags", + "winapi 0.3.9", +] + [[package]] name = "objc" version = "0.2.7" @@ -2513,7 +2744,7 @@ version = "0.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "11bafc859c6815fbaffbbbf4229ecb767ac913fecb27f9ad4343662e9ef099ea" dependencies = [ - "memchr", + "memchr 2.5.0", ] [[package]] @@ -2664,7 +2895,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a" dependencies = [ "aho-corasick", - "memchr", + "memchr 2.5.0", "regex-syntax", ] @@ -2692,6 +2923,15 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "resize-slice" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a3cb2f74a9891e76958b9e0ccd269a25b466c3ae3bb3efd71db157248308c4a" +dependencies = [ + "uninitialized", +] + [[package]] name = "rfd" version = "0.10.0" @@ -2895,7 +3135,7 @@ checksum = "2bc1bb97804af6631813c55739f771071e0f2ed33ee20b68c86ec505d906356c" dependencies = [ "bitflags", "core-foundation", - "core-foundation-sys", + "core-foundation-sys 0.8.3", "libc", "security-framework-sys", ] @@ -2906,7 +3146,7 @@ version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556" dependencies = [ - "core-foundation-sys", + "core-foundation-sys 0.8.3", "libc", ] @@ -3033,6 +3273,18 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_yaml" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef8099d3df28273c99a1728190c7a9f19d444c941044f64adf986bee7ec53051" +dependencies = [ + "dtoa", + "linked-hash-map", + "serde", + "yaml-rust", +] + [[package]] name = "serialize-to-javascript" version = "0.1.1" @@ -3525,7 +3777,7 @@ dependencies = [ "infer", "json-patch", "kuchiki", - "memchr", + "memchr 2.5.0", "phf 0.10.1", "proc-macro2", "quote", @@ -3690,7 +3942,7 @@ dependencies = [ "autocfg", "bytes", "libc", - "memchr", + "memchr 2.5.0", "mio", "num_cpus", "parking_lot", @@ -3815,6 +4067,16 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81" +[[package]] +name = "udev" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47504d1a49b2ea1b133e7ddd1d9f0a83cf03feb9b440c2c470d06db4589cf301" +dependencies = [ + "libc", + "libudev-sys", +] + [[package]] name = "unicode-bidi" version = "0.3.8" @@ -3848,6 +4110,12 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +[[package]] +name = "uninitialized" +version = "0.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74c1aa4511c38276c548406f0b1f5f8b793f000cfb51e18f278a102abd057e81" + [[package]] name = "untrusted" version = "0.7.1" @@ -3927,6 +4195,12 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" + [[package]] name = "waker-fn" version = "1.1.0" @@ -4152,6 +4426,12 @@ dependencies = [ "cc", ] +[[package]] +name = "widestring" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a212922ea58fbf5044f83663aa4fc6281ff890f1fd7546c0c3f52f5290831781" + [[package]] name = "winapi" version = "0.2.8" @@ -4490,3 +4770,12 @@ name = "xml-rs" version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3" + +[[package]] +name = "yaml-rust" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" +dependencies = [ + "linked-hash-map", +] diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 0321989..3c09e75 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -36,6 +36,7 @@ either = "1.8.0" image = "0.24.5" mdns = "3.0.0" macos-app-nap = "0.0.1" +ddc-hi = "0.4.1" [features] # by default Tauri runs in production mode diff --git a/src-tauri/src/core/core.rs b/src-tauri/src/core/core.rs index dc747d2..da07422 100644 --- a/src-tauri/src/core/core.rs +++ b/src-tauri/src/core/core.rs @@ -75,7 +75,8 @@ impl CoreManager { colors.push(color); } hue = (hue + 1.0) % 360.0; - match rpc::manager::Manager::global() + match rpc::Manager::global() + .await .publish_led_colors(&colors) .await { @@ -187,7 +188,8 @@ impl CoreManager { } // info!("{:?}", colors); global_sub_pixels = HashMap::new(); - match rpc::manager::Manager::global() + match rpc::Manager::global() + .await .publish_led_sub_pixels(colors) .await { diff --git a/src-tauri/src/display/brightness.rs b/src-tauri/src/display/brightness.rs new file mode 100644 index 0000000..c45857e --- /dev/null +++ b/src-tauri/src/display/brightness.rs @@ -0,0 +1,13 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Copy, Serialize, Deserialize, Debug)] +pub enum Brightness { + Relative(u16), + Absolute(u16), +} + +#[derive(Clone, Copy, Serialize, Deserialize, Debug)] +pub struct DisplayBrightness { + pub brightness: Brightness, + pub display_index: usize, +} \ No newline at end of file diff --git a/src-tauri/src/display/manager.rs b/src-tauri/src/display/manager.rs new file mode 100644 index 0000000..39a776d --- /dev/null +++ b/src-tauri/src/display/manager.rs @@ -0,0 +1,78 @@ +use ddc_hi::Display; +use paris::{info, error}; +use tokio::sync::{broadcast, OnceCell}; + +use crate::{display::Brightness, rpc}; + +use super::DisplayBrightness; +use ddc_hi::Ddc; + +pub struct Manager {} + +impl Manager { + pub async fn global() -> &'static Self { + static DISPLAY_MANAGER: OnceCell = OnceCell::const_new(); + + DISPLAY_MANAGER.get_or_init(|| Self::create()).await + } + + pub async fn create() -> Self { + let rpc = rpc::Manager::global().await; + + let rx = rpc.client().subscribe_change_display_brightness_rx(); + tokio::spawn(Self::subscribe_display_brightness(rx)); + + Self {} + } + + pub async fn subscribe_display_brightness(mut rx: broadcast::Receiver) { + while let Ok(display_brightness) = rx.recv().await { + if let Err(err) = Self::set_display_brightness(display_brightness) { + error!("set_display_brightness failed. {:?}", err); + } + } + } + + pub fn set_display_brightness(display_brightness: DisplayBrightness) -> anyhow::Result<()> { + match Display::enumerate().get_mut(display_brightness.display_index) { + Some(display) => match display.handle.get_vcp_feature(0x10) { + Ok(curr_brightness) => { + let curr = curr_brightness.value(); + info!("curr_brightness: {:?}", curr); + let mut target = match display_brightness.brightness { + Brightness::Relative(v) => v + curr, + Brightness::Absolute(v) => v, + }; + if target.gt(&curr_brightness.maximum()) { + target = curr_brightness.maximum(); + } else if target.lt(&0) { + target = 0; + } + display + .handle + .set_vcp_feature(0x10, target) + .map_err(|err| anyhow::anyhow!("can not set brightness. {:?}", err))?; + } + Err(err) => { + info!( + "can not get display#{} brightness. {:?}", + display_brightness.display_index, err + ); + if let Brightness::Absolute(v) = display_brightness.brightness { + display + .handle + .set_vcp_feature(0x10, v) + .map_err(|err| anyhow::anyhow!("can not set brightness. {:?}", err))?; + }; + } + }, + None => { + anyhow::bail!( + "display#{} was not found.", + display_brightness.display_index + ); + } + } + Ok(()) + } +} diff --git a/src-tauri/src/display/mod.rs b/src-tauri/src/display/mod.rs new file mode 100644 index 0000000..1509dfb --- /dev/null +++ b/src-tauri/src/display/mod.rs @@ -0,0 +1,8 @@ +mod brightness; +mod manager; + +pub use brightness::*; +pub use manager::*; + + + diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index b9dc33c..b9a4ea5 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -5,24 +5,28 @@ #![feature(bool_to_option)] mod core; +mod display; mod picker; mod rpc; use crate::core::AmbientLightMode; use crate::core::CoreManager; +use once_cell::sync::OnceCell; use paris::*; use picker::config::DisplayConfig; use picker::manager::Picker; use picker::screenshot::ScreenshotDto; use tauri::async_runtime::Mutex; -use once_cell::sync::OnceCell; static GET_SCREENSHOT_LOCK: OnceCell> = OnceCell::new(); #[tauri::command] async fn take_snapshot() -> Vec { info!("Hi?"); - let _lock = GET_SCREENSHOT_LOCK.get_or_init(|| Mutex::new(false)).lock().await; + let _lock = GET_SCREENSHOT_LOCK + .get_or_init(|| Mutex::new(false)) + .lock() + .await; info!("Hi!"); let manager = Picker::global().await; @@ -88,8 +92,7 @@ async fn play_mode(target_mode: AmbientLightMode) { } #[tokio::main] -async fn main() { - rpc::manager::Manager::global(); +async fn main() {display::Manager::global().await; tauri::Builder::default() .invoke_handler(tauri::generate_handler![ take_snapshot, diff --git a/src-tauri/src/rpc/manager.rs b/src-tauri/src/rpc/manager.rs index d37c224..cc8f0db 100644 --- a/src-tauri/src/rpc/manager.rs +++ b/src-tauri/src/rpc/manager.rs @@ -1,23 +1,35 @@ -use crate::picker::led_color::LedColor; +use paris::error; +use tokio::sync::{broadcast, OnceCell}; -use super::mqtt::MqttConnection; -use once_cell::sync::OnceCell; +use crate::{display, picker::led_color::LedColor}; + +use super::mqtt::MqttRpc; pub struct Manager { - mqtt: MqttConnection, + client: MqttRpc, + initialized: bool, } impl Manager { - pub fn global() -> &'static Self { - static RPC_MANAGER: OnceCell = OnceCell::new(); + pub async fn global() -> &'static Self { + static RPC_MANAGER: OnceCell = OnceCell::const_new(); - RPC_MANAGER.get_or_init(|| Manager::new()) + RPC_MANAGER.get_or_init(|| Manager::new()).await } - pub fn new() -> Self { - let mut mqtt = MqttConnection::new(); - mqtt.initialize(); - Self { mqtt } + pub async fn new() -> Self { + let mut mqtt = MqttRpc::new(); + let initialized = match mqtt.initialize().await { + Ok(_) => true, + Err(err) => { + error!("initialize for mqtt was failed. {:?}", err); + false + } + }; + Self { + client: mqtt, + initialized, + } } pub async fn publish_led_colors(&self, colors: &Vec) -> anyhow::Result<()> { @@ -27,29 +39,14 @@ impl Manager { .flatten() .collect::>(); - self.mqtt - .client - .publish( - "display-ambient-light/desktop/colors", - rumqttc::QoS::AtLeastOnce, - false, - payload, - ) - .await - .map_err(|error| anyhow::anyhow!("mqtt publish failed. {}", error)) + self.publish_led_sub_pixels(payload).await } pub async fn publish_led_sub_pixels(&self, payload: Vec) -> anyhow::Result<()> { + self.client.publish_led_sub_pixels(payload).await + } - self.mqtt - .client - .publish( - "display-ambient-light/desktop/colors", - rumqttc::QoS::AtLeastOnce, - false, - payload, - ) - .await - .map_err(|error| anyhow::anyhow!("mqtt publish failed. {}", error)) + pub fn client(&self) -> &MqttRpc { + &self.client } } diff --git a/src-tauri/src/rpc/mod.rs b/src-tauri/src/rpc/mod.rs index 54a385b..789e00e 100644 --- a/src-tauri/src/rpc/mod.rs +++ b/src-tauri/src/rpc/mod.rs @@ -1,2 +1,4 @@ -pub mod manager; -pub mod mqtt; \ No newline at end of file +mod manager; +pub mod mqtt; + +pub use manager::*; \ No newline at end of file diff --git a/src-tauri/src/rpc/mqtt.rs b/src-tauri/src/rpc/mqtt.rs index a154a84..eeadc5b 100644 --- a/src-tauri/src/rpc/mqtt.rs +++ b/src-tauri/src/rpc/mqtt.rs @@ -1,41 +1,106 @@ -use rumqttc::{AsyncClient, MqttOptions, QoS}; +use crate::display; +use image::EncodableLayout; +use paris::warn; +use rumqttc::{AsyncClient, Event, Incoming, MqttOptions, QoS}; +use serde::Deserialize; use std::time::Duration; use time::{format_description, OffsetDateTime}; -use tokio::task; -use tracing::warn; +use tokio::{sync::broadcast, task}; -pub struct MqttConnection { - pub client: AsyncClient, +const DISPLAY_TOPIC: &'static str = "display-ambient-light/display"; +const DISPLAY_BRIGHTNESS_TOPIC: &'static str = "display-ambient-light/display/brightness"; + +pub struct MqttRpc { + client: AsyncClient, + change_display_brightness_tx: broadcast::Sender, } -impl MqttConnection { +impl MqttRpc { pub fn new() -> Self { let mut options = MqttOptions::new("rumqtt-async", "192.168.31.11", 1883); options.set_keep_alive(Duration::from_secs(5)); let (client, mut eventloop) = AsyncClient::new(options, 10); + + let (change_display_brightness_tx, _) = + broadcast::channel::(16); + + let change_display_brightness_tx2 = change_display_brightness_tx.clone(); + task::spawn(async move { loop { match eventloop.poll().await { - Ok(_) => {} + Ok(notification) => { + let handled = || -> anyhow::Result<()> { + println!("MQTT notification = {:?}", notification); + if let Event::Incoming(notification) = notification { + if let Incoming::Publish(notification) = notification { + match notification.topic.as_str() { + DISPLAY_BRIGHTNESS_TOPIC => { + let payload_text = String::from_utf8( + notification.payload.as_bytes().to_owned(), + ) + .map_err(|err| { + anyhow::anyhow!("can not parse json. {:?}", err) + })?; + let display_brightness: display::DisplayBrightness = + serde_json::from_str(payload_text.as_str()) + .map_err(|err| { + anyhow::anyhow!( + "can not deserialize display brightness. {:?}", + err + ) + })?; + change_display_brightness_tx2 + .send(display_brightness) + .map_err(|err| { + anyhow::anyhow!( + "can not broadcast display brightness. {:?}", + err + ) + })?; + } + &_ => {} + }; + } + } + Ok(()) + }; + if let Err(err) = handled() { + warn!("handle notification was failed. Error: {:?}", err); + } + } Err(err) => { println!("MQTT Error Event = {:?}", err); } } } }); - Self { client } + + Self { + client, + change_display_brightness_tx, + } } - pub fn initialize(&mut self) { - self.subscribe_board(); + pub async fn initialize(&mut self) -> anyhow::Result<()> { + self.subscribe_board().await?; + self.subscribe_display().await?; self.broadcast_desktop_online(); + anyhow::Ok(()) } - async fn subscribe_board(&self) { + async fn subscribe_board(&self) -> anyhow::Result<()> { self.client .subscribe("display-ambient-light/board/#", QoS::AtMostOnce) - .await; + .await + .map_err(|err| anyhow::anyhow!("subscribe board failed. {:?}", err)) + } + async fn subscribe_display(&self) -> anyhow::Result<()> { + self.client + .subscribe(format!("{}/#", DISPLAY_TOPIC), QoS::AtMostOnce) + .await + .map_err(|err| anyhow::anyhow!("subscribe board failed. {:?}", err)) } fn broadcast_desktop_online(&mut self) { @@ -69,4 +134,20 @@ impl MqttConnection { } }); } + + pub async fn publish_led_sub_pixels(&self, payload: Vec) -> anyhow::Result<()> { + self.client + .publish( + "display-ambient-light/desktop/colors", + rumqttc::QoS::AtLeastOnce, + false, + payload, + ) + .await + .map_err(|error| anyhow::anyhow!("mqtt publish failed. {}", error)) + } + + pub fn subscribe_change_display_brightness_rx(&self) -> broadcast::Receiver { + self.change_display_brightness_tx.subscribe() + } }