Skip to content

Commit

Permalink
Bug found yesterday? Solved.
Browse files Browse the repository at this point in the history
  • Loading branch information
morosanmihail committed Jan 6, 2025
1 parent 8df2ade commit 1a1ff0e
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 86 deletions.
72 changes: 37 additions & 35 deletions src/homeassistant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,12 +91,12 @@ pub fn json_to_metadata(
}

impl MediaPlayerState {
pub fn new(entity_id: String, ha_url: String, ha_token: String) -> Result<Self> {
Ok(Self {
pub fn new(entity_id: String, ha_url: String, ha_token: String) -> Self {
Self {
ha_token,
ha_url,
entity_id,
})
}
}

pub async fn play(&self) -> Result<()> {
Expand Down Expand Up @@ -163,11 +163,11 @@ impl MediaPlayerState {
}

pub async fn get_media_players(
client: &Client,
home_assistant_url: &str,
token: &str,
entity_ids: Vec<String>,
) -> Result<Vec<MediaPlayer>> {
let client = Client::new();
let url = format!("{}/api/states", home_assistant_url);
let response = client
.get(&url)
Expand Down Expand Up @@ -225,40 +225,42 @@ pub async fn listen_for_events(

loop {
tokio::select! {
Some(Ok(Message::Text(text))) = read.next() => {
let event: serde_json::Value = serde_json::from_str(&text).expect("Invalid JSON");
let entity = event.get("event").and_then(|e| e.get("data")).and_then(|d| d.get("entity_id")).and_then(|e| e.as_str());
if let Some(entity_id) = entity
{
if let Some(media_player) = media_players.get_mut(entity_id) {
println!("{:?}", text);
if let Some(new_state) = event.get("event").and_then(|e| e.get("data")).and_then(|d| d.get("new_state")) {
let attr = new_state.get("attributes");
let state = new_state.get("state");
event = read.next() => {
match event {
None => println!("Oh no, nothing here"),
Some(Ok(Message::Text(text))) => {
let event: serde_json::Value = serde_json::from_str(&text)?;
if let Some(entity_id) = event.get("event").and_then(|e| e.get("data")).and_then(|d| d.get("entity_id")).and_then(|e| e.as_str())
{
if let Some(media_player) = media_players.get_mut(entity_id) {
if let Some(new_state) = event.get("event").and_then(|e| e.get("data")).and_then(|d| d.get("new_state")) {
let attr = new_state.get("attributes");
let state = new_state.get("state");

if attr.is_some() && state.is_some() {
match media_player
.update_metadata(
attr.unwrap().clone(),
state.unwrap().to_string().clone()
.to_string()
.clone(),
)
.await {
Ok(events) => {
for e in events {
channels
.get(entity_id)
.unwrap()
.send(e)
.await?;
}
},
Err(e) => println!("Died during metadata update event with {e}"),
};
if attr.is_some() && state.is_some() {
match media_player
.update_metadata(
attr.unwrap().clone(),
state.unwrap().to_string().clone(),
)
.await {
Ok(events) => {
for e in events {
channels
.get(entity_id)
.unwrap()
.send(e)
.await?;
}
},
Err(e) => println!("Died during metadata update event with {e}"),
};
}
}
}
}
}
},
_ => {},
}
}
Some((entity_id, msg)) = mpris_rx.recv() => {
Expand Down
101 changes: 50 additions & 51 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ use std::{collections::HashMap, io::Write, path::PathBuf};
use eyre::{OptionExt, Result};
use homeassistant::{get_media_players, listen_for_events, MediaPlayerState};
use mpris::new_mpris_player;
use reqwest::Client;
use serde::{Deserialize, Serialize};
use tokio::{sync::mpsc, task::JoinSet};

Expand All @@ -29,91 +28,91 @@ impl Default for Config {

#[tokio::main]
async fn main() -> Result<()> {
let home_dir = dirs::home_dir().ok_or_eyre("Could not find home directory")?;
let config: PathBuf = home_dir.join(".config/ha_mpris_bridge/config.toml");

if let Some(parent_dir) = config.parent() {
std::fs::create_dir_all(parent_dir)?;
}

if !config.exists() {
let default_config = Config::default();
let toml_content = toml::to_string_pretty(&default_config)?;

let mut file = std::fs::File::create(&config)?;
file.write_all(toml_content.as_bytes())?;
}

let config = std::fs::read_to_string(&config)?;

let config: Config = toml::from_str(&config)?;

let client = Client::new();
let config = get_config()?;
let media_players = get_media_players(
&client,
&config.home_assistant_url,
&config.home_assistant_token,
config.entity_ids,
)
.await
.unwrap();

let parsed_url = url::Url::parse(&config.home_assistant_url)?;
let websocket_url = format!(
"ws://{}{}/api/websocket",
parsed_url
.host_str()
.ok_or_eyre("Can not get host from HA URL")?,
match parsed_url.port() {
Some(v) => format!(":{}", v),
None => "".to_string(),
},
);

// Channel to handle events from HA to MPRIS
let mut channels = HashMap::new();

// Channel to handle events from MPRIS to HA
let (mpris_tx, mpris_rx) = mpsc::channel(100);
let mut set = JoinSet::new();

let mut media_player_states = HashMap::new();

for player in &media_players {
let (ha_tx, ha_rx) = mpsc::channel(100);
channels.insert(player.entity_id.clone(), ha_tx);

println!("{:?}", player.clone());
let _mp_task = set.spawn(new_mpris_player(
player.entity_id.clone(),
player.clone(),
config.home_assistant_url.clone(),
ha_rx,
mpris_tx.clone(),
));
}

let media_players: HashMap<_, _> = media_players
.iter()
.map(|d| {
(
d.entity_id.clone(),
MediaPlayerState::new(
d.entity_id.clone(),
config.home_assistant_url.to_string(),
config.home_assistant_token.to_string(),
)
.unwrap(),
)
})
.collect();
media_player_states.insert(
player.entity_id.clone(),
MediaPlayerState::new(
player.entity_id.clone(),
config.home_assistant_url.to_string(),
config.home_assistant_token.to_string(),
),
);
}

let parsed_url = url::Url::parse(&config.home_assistant_url)?;
let websocket_url = format!(
"ws://{}{}/api/websocket",
parsed_url
.host_str()
.ok_or_eyre("Can not get host from HA URL")?,
match parsed_url.port() {
Some(v) => format!(":{}", v),
None => "".to_string(),
},
);
println!("Connected to {}", websocket_url);
let _ha_task = set.spawn(listen_for_events(
websocket_url,
config.home_assistant_token.to_string(),
media_players,
media_player_states,
channels,
mpris_rx,
));

while (set.join_next().await).is_some() {}
while (set.join_next().await).is_some() {
println!("------ GOT SOME RESULT");
}
Ok(())
}

fn get_config() -> eyre::Result<Config> {
let home_dir = dirs::home_dir().ok_or_eyre("Could not find home directory")?;
let config: PathBuf = home_dir.join(".config/ha_mpris_bridge/config.toml");

if let Some(parent_dir) = config.parent() {
std::fs::create_dir_all(parent_dir)?;
}

if !config.exists() {
let default_config = Config::default();
let toml_content = toml::to_string_pretty(&default_config)?;

let mut file = std::fs::File::create(&config)?;
file.write_all(toml_content.as_bytes())?;
}

let config = std::fs::read_to_string(&config)?;

let config: Config = toml::from_str(&config)?;
Ok(config)
}

0 comments on commit 1a1ff0e

Please sign in to comment.