use clap::{AppSettings, Clap}; use serde_json::json; /// Bert #[derive(Clap, Debug)] #[clap(version, author, about)] #[clap(setting = AppSettings::ColoredHelp)] struct Opts { /// Home Assistant host #[clap(short, long)] host: String, /// Media player entity ID #[clap(short, long)] entity: String, /// API token #[clap(short, long)] token: String, /// Use HTTP instead of HTTPS #[clap(short, long)] insecure: bool, #[clap(subcommand)] cmd: Option, } #[derive(Clap, Debug, Clone, Copy)] enum Command { /// Toggle playback PlayPause, /// Raise volume VolumeUp, /// Lower volume VolumeDown, } fn main() -> Result<(), Box> { let opts = Opts::parse(); if let Some(cmd) = opts.cmd { call_service(cmd, &opts)?; } else { let url = format!( "{}://{}/api/states/{}", if opts.insecure { "http" } else { "https" }, opts.host, opts.entity ); let client = reqwest::blocking::Client::new(); let response = client .get(url) .bearer_auth(opts.token) .header("Accept", "application/json") .header("Content-Type", "application/json") .send()? .json::()?; if response["state"] == "playing" { let attributes = &response["attributes"]; let maybe_channel = attributes["media_channel"].as_str(); let now_playing = if let Some(channel) = maybe_channel { format!( "[{}] {} - {}", channel, attributes["media_artist"] .as_str() .map_or("No artist", |artist| { artist }), attributes["media_title"] .as_str() .map_or("No title", |title| { title }), ) } else { format!( "{} - {}", attributes["media_artist"] .as_str() .map_or("No artist", |artist| artist), attributes["media_title"] .as_str() .map_or("No title", |title| title), ) }; println!("{}", now_playing); } else { println!( "Sonos {}", response["state"] .as_str() .map_or("state unknown", |state| state) ); } } // println!("{:#?}", response); Ok(()) } fn call_service(command: Command, opts: &Opts) -> Result<(), Box> { let cmd = match command { Command::PlayPause => "media_play_pause", Command::VolumeUp => "volume_up", Command::VolumeDown => "volume_down", }; let url = format!( "{}://{}/api/services/media_player/{}", if opts.insecure { "http" } else { "https" }, opts.host, cmd ); let body = json!({"entity_id": opts.entity.clone()}).to_string(); let client = reqwest::blocking::Client::new(); let response = client .post(url) .body(body) .bearer_auth(opts.token.clone()) .header("Accept", "application/json") .header("Content-Type", "application/json") .send()? .json::()?; println!("{:#?}", response); Ok(()) }