diff --git a/Cargo.toml b/Cargo.toml index c5e84d5..fc299c3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,7 @@ repository = "https://gitea.austen-wares.com/stonewareslord/aw-lights.git" members = [ ".", "webui", + "mqtt", "common", "lunatic-webui", ] @@ -19,6 +20,7 @@ rppal = "0.14" ws2818-rgb-led-spi-driver = { path = "./lib-ws2818-rgb-led-spi-driver" } common = { path = "./common" } webui = { path = "./webui" } +mqtt = { path = "./mqtt" } dotenv = "0.15.0" clap = { version = "4.3.0", features = ["derive", "env"] } tracing = "0.1.37" diff --git a/common/Cargo.toml b/common/Cargo.toml index cdd1f8d..1f199cb 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -11,3 +11,4 @@ parking_lot = "0.12" crossbeam-channel = "0.5.6" strum = { version = "0.24.1", features = ["derive"] } tracing = "0.1.37" +clap = { version = "4.5.4", features = ["derive", "env"] } diff --git a/common/src/lib.rs b/common/src/lib.rs index 9e0be2d..46b32eb 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -1,5 +1,6 @@ #![feature(array_chunks)] +use clap::Parser; use error::ProgramError; mod cava; @@ -9,6 +10,13 @@ mod final_ring; pub mod pattern; pub mod strip; +/// Maximum number of lights allowed +pub const MAX_NUM_LIGHTS: u16 = 200; +/// Default time per tick +pub const DEFAULT_TICK_TIME_MS: u64 = 10; +/// Minimum time per tick before strip breaks +pub const MIN_TICK_TIME: u64 = 10; + #[derive(Debug)] pub enum Message { Error(ProgramError), @@ -16,3 +24,62 @@ pub enum Message { String(String), // InputPrompt(String), } + +#[derive(Debug, Clone, Parser)] +pub struct Config { + /// Number of lights + #[clap(short, long, env, help = "Number of lights in the strip", value_parser = clap::value_parser!(u16).range(1..=(MAX_NUM_LIGHTS as i64)))] + pub num_lights: u16, + /// Number of lights to skip + #[clap( + short, + long, + env, + default_value_t = 0, + help = "Number of lights to skip in the beginning" + )] + pub skip_lights: u16, + /// Global brightness multiplier + #[clap( + long, + env, + default_value_t = 255, + help = "The max brightness (clamped)" + )] + pub global_brightness_max: u8, + /// Time per tick + #[clap(long, env, default_value_t = DEFAULT_TICK_TIME_MS, help = "Tick time in milliseconds", value_parser = clap::value_parser!(u64).range(MIN_TICK_TIME..))] + pub tick_time_ms: u64, + + /// The default adapter + #[clap( + long, + env, + default_value = "/dev/spidev0.0", + help = "The serial interface" + )] + pub serial_interface: String, + + /// The initial pattern + #[clap(short, env, long, help = "The name of the initial pattern")] + pub initial_pattern: Option, + + #[clap(env, long, help = "The light strip should be mirrored down the middle")] + pub mirrored_lights: bool, + #[clap( + long, + env, + help = "If mirrored_lights is true, reverse the mirror direction" + )] + pub reverse_mirror: bool, + + #[clap(short, long, env, help = "Reverse all patterns")] + pub reverse: bool, + + #[clap(long, env, help = "MQTT broker host")] + pub mqtt_broker: String, + #[clap(long, env, help = "MQTT broker port")] + pub mqtt_port: u32, + #[clap(long, env, help = "MQTT id")] + pub mqtt_id: String, +} diff --git a/mqtt/Cargo.toml b/mqtt/Cargo.toml new file mode 100644 index 0000000..fd4b8cf --- /dev/null +++ b/mqtt/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "mqtt" +version = "0.1.0" +edition = "2021" + +[dependencies] +common = { path = "../common" } +rumqttc = "0.24.0" +tracing = "0.1.37" diff --git a/mqtt/src/lib.rs b/mqtt/src/lib.rs new file mode 100644 index 0000000..2aa25f7 --- /dev/null +++ b/mqtt/src/lib.rs @@ -0,0 +1,36 @@ +use rumqttc::{Client, MqttOptions, QoS}; +use std::{thread, time::Duration}; +use tracing::info; + +use common::{error::ProgramResult, strip}; +use std::{ + io, + sync::{mpsc::Sender, Arc, Mutex}, +}; + +pub fn start(strip_tx: Sender) -> ProgramResult<()> { + info!("Starting mqtt"); + + Ok(()) +} + +fn x() { + let mut mqttoptions = MqttOptions::new("rumqtt-sync", "test.mosquitto.org", 1883); + mqttoptions.set_keep_alive(Duration::from_secs(5)); + + let (mut client, mut connection) = Client::new(mqttoptions, 10); + client.subscribe("hello/rumqtt", QoS::AtMostOnce).unwrap(); + thread::spawn(move || { + for i in 0..10 { + client + .publish("hello/rumqtt", QoS::AtLeastOnce, false, vec![i; i as usize]) + .unwrap(); + thread::sleep(Duration::from_millis(100)); + } + }); + + // Iterate to poll the eventloop for connection progress + for (i, notification) in connection.iter().enumerate() { + println!("Notification = {:?}", notification); + } +} diff --git a/src/main.rs b/src/main.rs index 96c92a4..bc83e83 100644 --- a/src/main.rs +++ b/src/main.rs @@ -48,11 +48,12 @@ fn main() -> ProgramResult<()> { env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init(); // Use clap to parse the configuration - let config = strip::Config::parse(); + let config = common::Config::parse(); // Strip control transmitter and receiver let (strip_tx, strip_rx) = channel::(); let webui_strip_tx = strip_tx.clone(); + let mqtt_strip_tx = strip_tx.clone(); let (message_tx, message_rx) = channel::(); @@ -72,6 +73,12 @@ fn main() -> ProgramResult<()> { }, ); + // Mqtt user-interface + make_child( + message_tx.clone(), + move |_message_tx| -> ProgramResult<()> { mqtt::start(mqtt_strip_tx) }, + ); + std::mem::drop(message_tx); 'ret: loop { diff --git a/src/strip.rs b/src/strip.rs index 2a4b975..f9b24fe 100644 --- a/src/strip.rs +++ b/src/strip.rs @@ -1,9 +1,9 @@ -use clap::Parser; use common::{ color, error::ProgramError, pattern::{self, ColorIterator, Pattern}, strip::Message, + Config, MAX_NUM_LIGHTS, MIN_TICK_TIME, }; use std::{ cmp, @@ -16,65 +16,6 @@ use std::{ use tracing::{error, info}; use ws2818_rgb_led_spi_driver::{adapter_gen::Ws28xxAdapter, adapter_spi::Ws28xxSpiAdapter}; -/// Maximum number of lights allowed -pub const MAX_NUM_LIGHTS: u16 = 200; -/// Default time per tick -pub const DEFAULT_TICK_TIME_MS: u64 = 10; -/// Minimum time per tick before strip breaks -pub const MIN_TICK_TIME: u64 = 10; - -#[derive(Debug, Clone, Parser)] -pub struct Config { - /// Number of lights - #[clap(short, long, env, help = "Number of lights in the strip", value_parser = clap::value_parser!(u16).range(1..=(MAX_NUM_LIGHTS as i64)))] - pub num_lights: u16, - /// Number of lights to skip - #[clap( - short, - long, - env, - default_value_t = 0, - help = "Number of lights to skip in the beginning" - )] - pub skip_lights: u16, - /// Global brightness multiplier - #[clap( - long, - env, - default_value_t = 255, - help = "The max brightness (clamped)" - )] - pub global_brightness_max: u8, - /// Time per tick - #[clap(long, env, default_value_t = DEFAULT_TICK_TIME_MS, help = "Tick time in milliseconds", value_parser = clap::value_parser!(u64).range(MIN_TICK_TIME..))] - pub tick_time_ms: u64, - - /// The default adapter - #[clap( - long, - env, - default_value = "/dev/spidev0.0", - help = "The serial interface" - )] - pub serial_interface: String, - - /// The initial pattern - #[clap(short, env, long, help = "The name of the initial pattern")] - pub initial_pattern: Option, - - #[clap(env, long, help = "The light strip should be mirrored down the middle")] - pub mirrored_lights: bool, - #[clap( - long, - env, - help = "If mirrored_lights is true, reverse the mirror direction" - )] - pub reverse_mirror: bool, - - #[clap(short, long, env, help = "Reverse all patterns")] - pub reverse: bool, -} - #[allow(clippy::module_name_repetitions)] pub struct LedStrip { pub adapter: Box,