This commit is contained in:
Mateusz Gruszczyński
2026-09-02 22:41:27 +02:00
parent 8004be0841
commit db6d2f09db
20 changed files with 945 additions and 59 deletions
+35
View File
@@ -145,3 +145,38 @@ pub async fn read_state(
let payload = read_entity(default_client, settings, entity_override).await?;
payload.get("state").and_then(Value::as_str).map(str::to_string).ok_or_else(|| anyhow!("Home Assistant state is missing"))
}
/// Call a Home Assistant service from a Flow action. The domain/service pair is explicit
/// and the payload is sent as JSON. Entity targeting is normalized through entity_id.
pub async fn call_service(
default_client: &reqwest::Client,
settings: &HomeAssistantSettings,
domain: &str,
service: &str,
entity_id: Option<&str>,
data: &Value,
) -> Result<Value> {
if settings.url.trim().is_empty() { bail!("Home Assistant URL is not configured") }
if settings.token.trim().is_empty() { bail!("Home Assistant token is not configured") }
if domain.trim().is_empty() || service.trim().is_empty() { bail!("Home Assistant domain/service is required") }
let mut base = Url::parse(settings.url.trim()).context("invalid Home Assistant URL")?;
if !matches!(base.scheme(), "http" | "https") { bail!("Home Assistant URL must use http or https") }
base = base.join(&format!("api/services/{}/{}", domain.trim(), service.trim())).context("cannot build Home Assistant service URL")?;
let mut payload = data.as_object().cloned().unwrap_or_default();
if let Some(entity) = entity_id.map(str::trim).filter(|v| !v.is_empty()) {
payload.insert("entity_id".into(), Value::String(entity.to_string()));
}
let client = request_client(default_client, settings)?;
let response = client.post(base).bearer_auth(settings.token.trim()).header("Accept", "application/json")
.json(&Value::Object(payload)).send().await.context("Home Assistant service request failed")?;
if !response.status().is_success() {
let status = response.status();
let body = response.text().await.unwrap_or_default();
bail!("Home Assistant returned {status}: {}", body.chars().take(200).collect::<String>())
}
match response.json::<Value>().await {
Ok(value) => Ok(value),
Err(_) => Ok(Value::Null),
}
}