Start work on mqtt

This commit is contained in:
Austen Adler 2024-04-12 23:41:35 -04:00
parent a11168c8f1
commit 9032aba60a
6 changed files with 67 additions and 22 deletions

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
/.env
/debug/ /debug/
/target/ /target/
/Cargo.lock /Cargo.lock

View File

@ -1,6 +1,6 @@
#![feature(array_chunks)] #![feature(array_chunks)]
use clap::Parser; use clap::{Args, Parser};
use error::ProgramError; use error::ProgramError;
mod cava; mod cava;
@ -76,15 +76,32 @@ pub struct Config {
#[clap(short, long, env, help = "Reverse all patterns")] #[clap(short, long, env, help = "Reverse all patterns")]
pub reverse: bool, pub reverse: bool,
#[clap(long, env, help = "MQTT broker host", requires_all = ["mqtt_id", "mqtt_port"])] #[clap(flatten)]
pub mqtt_broker: Option<String>, pub mqtt: MqttConfig,
#[clap(long, env, help = "MQTT broker port", default_value = "1883")] }
pub mqtt_port: Option<u16>,
#[clap(long, env, help = "MQTT device id")]
pub mqtt_id: Option<String>,
#[derive(Debug, Args, Clone)]
pub struct MqttConfig {
#[clap(long, env, help = "MQTT broker host")]
pub mqtt_broker: String,
#[clap(long, env, help = "MQTT broker port", default_value = "1883")]
pub mqtt_port: u16,
#[clap(long, env, help = "MQTT device id", value_parser = mqtt_topic_segment)]
pub mqtt_id: String,
#[clap(long, env, help = "Discovery prefix", default_value = "homeassistant", value_parser = mqtt_topic_segment)]
pub mqtt_discovery_prefix: String,
#[clap(long, env, help = "MQTT username", requires_all = ["mqtt_password"])] #[clap(long, env, help = "MQTT username", requires_all = ["mqtt_password"])]
pub mqtt_username: Option<String>, pub mqtt_username: Option<String>,
#[clap(long, env, help = "MQTT user password")] #[clap(long, env, help = "MQTT user password")]
pub mqtt_password: Option<String>, pub mqtt_password: Option<String>,
} }
fn mqtt_topic_segment(s: &str) -> Result<String, &'static str> {
if s.is_empty() {
Err("MQTT topic segments must not be empty")
} else if s.contains('/') {
Err("MQTT topic segments cannot contain '/'")
} else {
Ok(s.to_string())
}
}

View File

@ -1 +1,8 @@
NUM_LIGHTS=89 NUM_LIGHTS=89
MQTT_BROKER=127.0.0.1
MQTT_ID=pilights00
# MQTT_PORT=1883
# MQTT_DISCOVERY_PREFIX=homeassistant
# MQTT_USERNAME=
# MQTT_PASSWORD=

View File

@ -9,3 +9,5 @@ rumqttc = "0.24.0"
serde = { version = "1.0.197", features = ["derive"] } serde = { version = "1.0.197", features = ["derive"] }
serde_json = "1.0.115" serde_json = "1.0.115"
tracing = "0.1.37" tracing = "0.1.37"
homeassistant-mqtt-discovery = { path = "../homeassistant-mqtt-discovery/" }
clap = { version = "4.5.4", features = ["derive"] }

View File

@ -1,5 +1,5 @@
#![feature(let_chains)] #![feature(let_chains)]
use common::Config; use common::MqttConfig;
use rumqttc::{Client, MqttOptions, QoS}; use rumqttc::{Client, MqttOptions, QoS};
use std::{thread, time::Duration}; use std::{thread, time::Duration};
use tracing::{info, warn}; use tracing::{info, warn};
@ -10,24 +10,17 @@ use std::{
sync::{mpsc::Sender, Mutex}, sync::{mpsc::Sender, Mutex},
}; };
pub fn start(strip_tx: Sender<strip::Message>, config: Config) -> ProgramResult<()> { pub fn start(strip_tx: Sender<strip::Message>, config: MqttConfig) -> ProgramResult<()> {
info!("Starting mqtt"); info!("Starting mqtt with config {config:?}");
x(&config); x(&config);
Ok(()) Ok(())
} }
fn x(config: &Config) { fn x(config: &MqttConfig) {
let mut mqttoptions = if let Some(mqtt_id) = config.mqtt_id.as_ref() let mut mqttoptions = MqttOptions::new(&config.mqtt_id, &config.mqtt_broker, config.mqtt_port);
&& let Some(mqtt_broker) = config.mqtt_broker.as_ref()
&& let Some(mqtt_port) = config.mqtt_port
{
MqttOptions::new(mqtt_id, mqtt_broker, mqtt_port)
} else {
warn!("MQTT is not emabled as flags are not all set");
return;
};
mqttoptions.set_keep_alive(Duration::from_secs(5)); mqttoptions.set_keep_alive(Duration::from_secs(5));
if let Some(mqtt_username) = config.mqtt_username.as_ref() if let Some(mqtt_username) = config.mqtt_username.as_ref()
@ -54,11 +47,36 @@ fn x(config: &Config) {
// Iterate to poll the eventloop for connection progress // Iterate to poll the eventloop for connection progress
for (i, notification) in connection.iter().enumerate() { for (i, notification) in connection.iter().enumerate() {
info!("Notification = {:?}", notification); info!("Notification #{i} = {:?}", notification);
} }
info!("Done with mqtt"); info!("Done with mqtt");
} }
use homeassistant_mqtt_discovery::{integrations::device_trigger, Common, Device};
fn gen_discovery_message(config: MqttConfig, button_id: &str) -> device_trigger::Discovery {
device_trigger::Discovery {
common: Common {
device: Some(Device {
identifiers: Some(vec![format!("aw_lights_{}", config.mqtt_id)]),
..Device::default()
}),
..Common::default()
},
// "<discovery_prefix>/device_automation/[<node_id>/]<object_id>/config",
// homeassistant/device_automation/0x90fd9ffffedf1266/action_arrow_left_click/config
topic: format!(
"{}/device_automation/{}/{}/config",
config.mqtt_discovery_prefix, config.mqtt_id, button_id
),
r#type: "".to_string(),
subtype: "".to_string(),
automation_type: "trigger".to_string(),
payload: None,
qos: None,
value_template: None,
}
}
// unique_id: bedroom_switch // unique_id: bedroom_switch
// name: "Bedroom Switch" // name: "Bedroom Switch"
// state_topic: "home/bedroom/switch1" // state_topic: "home/bedroom/switch1"

View File

@ -77,7 +77,7 @@ fn main() -> ProgramResult<()> {
// Mqtt user-interface // Mqtt user-interface
make_child( make_child(
message_tx.clone(), message_tx.clone(),
move |_message_tx| -> ProgramResult<()> { mqtt::start(mqtt_strip_tx, config) }, move |_message_tx| -> ProgramResult<()> { mqtt::start(mqtt_strip_tx, config.mqtt.clone()) },
); );
std::mem::drop(message_tx); std::mem::drop(message_tx);