Skip to content

Commit

Permalink
format code
Browse files Browse the repository at this point in the history
  • Loading branch information
nicholascioli committed Sep 16, 2023
1 parent 4f016a5 commit 0e02e62
Show file tree
Hide file tree
Showing 15 changed files with 389 additions and 249 deletions.
142 changes: 93 additions & 49 deletions examples/mqtt-broadlink.rs
Original file line number Diff line number Diff line change
@@ -1,24 +1,12 @@
use std::{
collections::HashMap,
net::Ipv4Addr,
time::Duration,
};
use std::{collections::HashMap, net::Ipv4Addr, time::Duration};

use clap::Parser;
use log::{info, warn};
use mqtt_async_client::{
client::{Client, KeepAlive, Publish, QoS, Subscribe, SubscribeTopic},
Error,

client::{
Client,
KeepAlive,
Publish,
QoS,
Subscribe,
SubscribeTopic,
},
};
use rbroadlink::{ Device, traits::DeviceTrait };
use rbroadlink::{traits::DeviceTrait, Device};

#[derive(Parser, Clone, Debug)]
#[clap(about, version, author)]
Expand Down Expand Up @@ -74,16 +62,16 @@ async fn main() {
info!("Starting broadlink-mqtt v{}...", env!("CARGO_PKG_VERSION"));

// Get the devices
let devices = get_devices(&args)
.expect("Could not find devices!");
let devices = get_devices(&args).expect("Could not find devices!");

// Start an update thread on all the devices
let mut threads: Vec<tokio::task::JoinHandle<_>> = vec![];
for (_, device) in devices {
let args_copy = args.clone();

threads.push(tokio::spawn(async move {
handle_device(&device, args_copy).await
handle_device(&device, args_copy)
.await
.expect("Could not handle device!");
}));
}
Expand All @@ -96,13 +84,18 @@ async fn main() {

async fn handle_device(device: &Device, args: Args) -> Result<(), String> {
let info = device.get_info();
let sanitized_name = info.friendly_model.to_lowercase().replace(" ", "-").replace("/", ">");
let sanitized_name = info
.friendly_model
.to_lowercase()
.replace(" ", "-")
.replace("/", ">");
let mqtt_id = format!("{}-{}", args.mqtt_id.clone(), sanitized_name);

// Construct the mqtt client
let mut builder = Client::builder();
builder
.set_url_string(&args.mqtt_broker).expect("Could not set MQTT broker URL!")
.set_url_string(&args.mqtt_broker)
.expect("Could not set MQTT broker URL!")
.set_username(args.username.clone())
.set_password(args.password.clone().map(|s| s.as_bytes().to_vec()))
.set_client_id(Some(mqtt_id))
Expand All @@ -111,30 +104,38 @@ async fn handle_device(device: &Device, args: Args) -> Result<(), String> {
.set_operation_timeout(Duration::from_secs(args.operation_timeout as u64))
.set_automatic_connect(args.auto_connect);

let mut mqtt_client = builder.build()
let mut mqtt_client = builder
.build()
.expect("Could not construct the MQTT client!");

// Connect to the broker
info!("Connecting to the MQTT broker at {}", &args.mqtt_broker);
mqtt_client.connect().await
mqtt_client
.connect()
.await
.expect("Could not connect to MQTT broker!");

// Publish the device information
let mut msg = Publish::new(get_path(&sanitized_name, &["info"]), info.friendly_type.into());
let mut msg = Publish::new(
get_path(&sanitized_name, &["info"]),
info.friendly_type.into(),
);
msg.set_qos(QoS::AtLeastOnce);
msg.set_retain(false);

mqtt_client.publish(&msg).await
mqtt_client
.publish(&msg)
.await
.expect("Could not publish to the broker!");

// Set up a listener for the commands
let command_subscription = Subscribe::new(vec![
SubscribeTopic{
qos: QoS::AtLeastOnce,
topic_path: get_path(&sanitized_name, &["cmd"]),
}
]);
mqtt_client.subscribe(command_subscription).await
let command_subscription = Subscribe::new(vec![SubscribeTopic {
qos: QoS::AtLeastOnce,
topic_path: get_path(&sanitized_name, &["cmd"]),
}]);
mqtt_client
.subscribe(command_subscription)
.await
.expect("Could not subscribe to command topic!")
.any_failures()
.expect("Failures encountered when subscribing to command topic!");
Expand All @@ -143,7 +144,9 @@ async fn handle_device(device: &Device, args: Args) -> Result<(), String> {
loop {
let response = mqtt_client.read_subscriptions().await;
match response {
Err(Error::Disconnected) => return Err("Device was disconnected from the broker!".into()),
Err(Error::Disconnected) => {
return Err("Device was disconnected from the broker!".into())
}
Ok(r) => {
// Consume the command
let data = String::from_utf8(r.payload().to_vec())
Expand All @@ -156,27 +159,49 @@ async fn handle_device(device: &Device, args: Args) -> Result<(), String> {

// Make sure that we skip non-cmds.
if cmd == None || payload == None {
warn!("Skipping incomplete command for {}: {}", &sanitized_name, &data);
warn!(
"Skipping incomplete command for {}: {}",
&sanitized_name, &data
);
continue;
}

let unwrapped_cmd = *cmd.unwrap();
let unwrapped_payload = *payload.unwrap();

info!("Got command '{}' with payload => {}", unwrapped_cmd, unwrapped_payload);
info!(
"Got command '{}' with payload => {}",
unwrapped_cmd, unwrapped_payload
);
match unwrapped_cmd {
"blast" => handle_blast(&mqtt_client, &device, &sanitized_name, &unwrapped_payload).await.expect("Could not handle blast!"),
"learn" => handle_learn(&mqtt_client, &device, &sanitized_name, &unwrapped_payload).await.expect("Could not handle learn!"),
_ => warn!("Skipping unknown command for {}: {}", &sanitized_name, &unwrapped_cmd),
"blast" => {
handle_blast(&mqtt_client, &device, &sanitized_name, &unwrapped_payload)
.await
.expect("Could not handle blast!")
}
"learn" => {
handle_learn(&mqtt_client, &device, &sanitized_name, &unwrapped_payload)
.await
.expect("Could not handle learn!")
}
_ => warn!(
"Skipping unknown command for {}: {}",
&sanitized_name, &unwrapped_cmd
),
}
},
}
Err(e) => warn!("Got unhandled error: {:?}", e),
}
}
}

/// Handles a blast command
async fn handle_blast(client: &Client, device: &Device, sanitized_name: &str, payload: &str) -> Result<(), String> {
async fn handle_blast(
client: &Client,
device: &Device,
sanitized_name: &str,
payload: &str,
) -> Result<(), String> {
// Decode the payload into a hex array.
let hex = hex::decode(payload);
if let Err(e) = hex {
Expand All @@ -190,12 +215,17 @@ async fn handle_blast(client: &Client, device: &Device, sanitized_name: &str, pa
match device {
Device::Remote { remote } => match remote.send_code(&hex) {
Err(e) => {
let err_msg = Publish::new(get_path(&sanitized_name, &["blast_error"]), e.to_string().into());
client.publish(&err_msg).await
let err_msg = Publish::new(
get_path(&sanitized_name, &["blast_error"]),
e.to_string().into(),
);
client
.publish(&err_msg)
.await
.expect("Could not publish blast error!");

return Ok(());
},
}
_ => info!("Blasted code successfully: {:?}", hex),
},
_ => {
Expand All @@ -206,21 +236,28 @@ async fn handle_blast(client: &Client, device: &Device, sanitized_name: &str, pa

// Tell the MQTT broker that we successfully blasted
let ok_msg = Publish::new(get_path(&sanitized_name, &["blast_status"]), "ok".into());
client.publish(&ok_msg).await
client
.publish(&ok_msg)
.await
.expect("Could not publish blast status!");

return Ok(());
}

/// Handles a learn command
async fn handle_learn(client: &Client, device: &Device, sanitized_name: &str, payload: &str) -> Result<(), String> {
async fn handle_learn(
client: &Client,
device: &Device,
sanitized_name: &str,
payload: &str,
) -> Result<(), String> {
// Only remotes can learn, so extract it here.
let remote = match device {
Device::Remote { remote } => remote,
_ => {
warn!("Device sent learn command, but is not a remote: {}", device);
return Ok(());
},
}
};

// Try to learn the code
Expand All @@ -230,14 +267,19 @@ async fn handle_learn(client: &Client, device: &Device, sanitized_name: &str, pa
_ => {
warn!("Skipping invalid learn mode {}", payload);
return Ok(());
},
}
};

// Short out if no code was learned.
if let Err(e) = code {
warn!("Device did not find any code! {:?}", e);
let err_msg = Publish::new(get_path(sanitized_name, &["code_error"]), e.to_string().into());
client.publish(&err_msg).await
let err_msg = Publish::new(
get_path(sanitized_name, &["code_error"]),
e.to_string().into(),
);
client
.publish(&err_msg)
.await
.expect("Could not publish code error message!");

return Ok(());
Expand All @@ -248,7 +290,9 @@ async fn handle_learn(client: &Client, device: &Device, sanitized_name: &str, pa

// Publish the learned code
let code_msg = Publish::new(get_path(sanitized_name, &["code"]), hex_code.into());
client.publish(&code_msg).await
client
.publish(&code_msg)
.await
.expect("Could not send learned code!");

return Ok(());
Expand Down
64 changes: 45 additions & 19 deletions examples/rbroadlink-cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,7 @@ use std::net::Ipv4Addr;
use clap::{ArgEnum, Parser, Subcommand};
use rpassword::read_password_from_tty;

use rbroadlink::{
Device,

network::WirelessConnection,
};
use rbroadlink::{network::WirelessConnection, Device};

/// Command line arguments for the CLI
#[derive(Parser, Debug)]
Expand Down Expand Up @@ -96,18 +92,34 @@ enum WirelessConnectionArg {
WPA,
}

fn main() -> Result<(), String>{
fn main() -> Result<(), String> {
// Get the args
let args = Args::parse();

// Run the command
return match args.command {
Commands::Blast { local_ip, device_ip, code } => blast(local_ip, device_ip, code),
Commands::Connect { security_mode, ssid, password, prompt } => connect(security_mode, ssid, password, prompt),
Commands::Learn { local_ip, device_ip, code_type } => learn(local_ip, device_ip, code_type),
Commands::Blast {
local_ip,
device_ip,
code,
} => blast(local_ip, device_ip, code),
Commands::Connect {
security_mode,
ssid,
password,
prompt,
} => connect(security_mode, ssid, password, prompt),
Commands::Learn {
local_ip,
device_ip,
code_type,
} => learn(local_ip, device_ip, code_type),
Commands::List { local_ip } => list(local_ip),
Commands::Info { local_ip, device_ip } => info(local_ip, device_ip),
}
Commands::Info {
local_ip,
device_ip,
} => info(local_ip, device_ip),
};
}

fn blast(local_ip: Option<Ipv4Addr>, device_ip: Ipv4Addr, code: String) -> Result<(), String> {
Expand All @@ -125,16 +137,23 @@ fn blast(local_ip: Option<Ipv4Addr>, device_ip: Ipv4Addr, code: String) -> Resul
return remote.send_code(&hex_code);
}

fn connect(sec_mode: WirelessConnectionArg, ssid: String, password: Option<String>, prompt: bool) -> Result<(), String> {
fn connect(
sec_mode: WirelessConnectionArg,
ssid: String,
password: Option<String>,
prompt: bool,
) -> Result<(), String> {
// Enforce unwrapping the password if using a security mode that requires it.
let password_prompt = Some("Wireless Password (will not show): ");
let unwrapped_pass = match sec_mode {
WirelessConnectionArg::None => "".into(),
_ => if prompt {
_ => {
if prompt {
read_password_from_tty(password_prompt).expect("Could not read password!")
} else {
password.expect("This mode requires a password!")
},
}
}
};

// Construct the connection information
Expand All @@ -147,15 +166,21 @@ fn connect(sec_mode: WirelessConnectionArg, ssid: String, password: Option<Strin
};

// Attempt to have the device connect
Device::connect_to_network(&connection)
.expect("Could not connect device to network!");
Device::connect_to_network(&connection).expect("Could not connect device to network!");

println!("Sending connection message with the following information: {:?}", connection);
println!(
"Sending connection message with the following information: {:?}",
connection
);

return Ok(());
}

fn learn(local_ip: Option<Ipv4Addr>, device_ip: Ipv4Addr, code_type: LearnCodeType) -> Result<(), String> {
fn learn(
local_ip: Option<Ipv4Addr>,
device_ip: Ipv4Addr,
code_type: LearnCodeType,
) -> Result<(), String> {
println!("Attempting to learn a code of type {:?}...", code_type);

// Ensure that the device is a remote
Expand All @@ -169,7 +194,8 @@ fn learn(local_ip: Option<Ipv4Addr>, device_ip: Ipv4Addr, code_type: LearnCodeTy
let code = match code_type {
LearnCodeType::IR => remote.learn_ir(),
LearnCodeType::RF => remote.learn_rf(),
}.expect("Could not learn code from device!");
}
.expect("Could not learn code from device!");

let hex_string = hex::encode(&code);
println!("Got code => {}", hex_string);
Expand Down
Loading

0 comments on commit 0e02e62

Please sign in to comment.