homeassistant_cli/commands/
event.rs1use owo_colors::OwoColorize;
2
3use crate::api::{self, HaClient, HaError};
4use crate::output::{self, OutputConfig};
5
6pub async fn fire(
7 out: &OutputConfig,
8 client: &HaClient,
9 event_type: &str,
10 data: Option<&str>,
11) -> Result<(), HaError> {
12 let body = if let Some(d) = data {
13 Some(
14 serde_json::from_str::<serde_json::Value>(d)
15 .map_err(|e| HaError::InvalidInput(format!("Invalid JSON data: {e}")))?,
16 )
17 } else {
18 None
19 };
20
21 let result = api::events::fire_event(client, event_type, body.as_ref()).await?;
22
23 if out.is_json() {
24 out.print_data(
25 &serde_json::to_string_pretty(&serde_json::json!({"ok": true, "data": result}))
26 .expect("serialize"),
27 );
28 } else {
29 out.print_data(&format!("✔ Fired event: {event_type}"));
30 }
31 Ok(())
32}
33
34pub async fn watch(
35 out: &OutputConfig,
36 client: &HaClient,
37 event_type: Option<&str>,
38) -> Result<(), HaError> {
39 out.print_message(&format!(
40 "Watching events{} (Ctrl+C to stop)...",
41 event_type.map(|t| format!(": {t}")).unwrap_or_default()
42 ));
43
44 api::events::watch_stream(client, event_type, |event| {
45 if out.is_json() {
46 if let Ok(s) =
47 serde_json::to_string_pretty(&serde_json::json!({"ok": true, "data": event}))
48 {
49 println!("{s}");
50 }
51 } else {
52 let time = event
53 .time_fired
54 .as_deref()
55 .map(output::relative_time)
56 .unwrap_or_else(|| "-".to_owned());
57 let data_str = if event.data.is_null() || event.data == serde_json::json!({}) {
58 String::new()
59 } else {
60 format!(" {}", event.data.to_string().dimmed())
61 };
62 println!("{} {}{}", time.dimmed(), event.event_type.bold(), data_str);
63 }
64 true
65 })
66 .await
67}
68
69#[cfg(test)]
70mod tests {
71 use super::*;
72 use crate::api::HaClient;
73 use crate::output::{OutputConfig, OutputFormat};
74 use wiremock::matchers::{method, path};
75 use wiremock::{Mock, MockServer, ResponseTemplate};
76
77 fn json_out() -> OutputConfig {
78 OutputConfig::new(Some(OutputFormat::Json), false)
79 }
80
81 #[tokio::test]
82 async fn fire_succeeds_on_200() {
83 let server = MockServer::start().await;
84 Mock::given(method("POST"))
85 .and(path("/api/events/my_event"))
86 .respond_with(
87 ResponseTemplate::new(200)
88 .set_body_json(serde_json::json!({"message": "Event my_event fired."})),
89 )
90 .mount(&server)
91 .await;
92
93 let client = HaClient::new(server.uri(), "tok");
94 let result = fire(&json_out(), &client, "my_event", None).await;
95 assert!(result.is_ok());
96 }
97
98 #[tokio::test]
99 async fn fire_with_invalid_json_returns_error() {
100 let server = MockServer::start().await;
101 let client = HaClient::new(server.uri(), "tok");
102 let result = fire(&json_out(), &client, "my_event", Some("{invalid}")).await;
103 assert!(matches!(result, Err(crate::api::HaError::InvalidInput(_))));
104 }
105}