v0.14.13
This commit is contained in:
@@ -27,7 +27,7 @@ async fn export_configuration(
|
||||
|
||||
fn validate_configuration_header(export: &ConfigurationExport) -> Result<(), AppError> {
|
||||
if export.format_version != 3 {
|
||||
return Err(AppError::BadRequest("unsupported configuration export version; version 3 is required by GREE Controller 0.14.12".into()));
|
||||
return Err(AppError::BadRequest("unsupported configuration export version; version 3 is required by GREE Controller 0.14.13".into()));
|
||||
}
|
||||
if export.settings.control_strategy != "setpoint" {
|
||||
return Err(AppError::BadRequest(
|
||||
|
||||
+54
-3
@@ -2,6 +2,7 @@ fn map_home_assistant_integration_error(error: anyhow::Error) -> AppError {
|
||||
let message = error.to_string();
|
||||
if message.contains("Home Assistant URL is not configured")
|
||||
|| message.contains("Home Assistant token is not configured")
|
||||
|| message.contains("Home Assistant Supervisor token is not available")
|
||||
|| message.contains("invalid Home Assistant URL")
|
||||
|| message.contains("Home Assistant URL must use http or https")
|
||||
|| message.contains("cannot build Home Assistant API URL")
|
||||
@@ -45,10 +46,58 @@ async fn test_home_assistant(
|
||||
State(state): State<AppState>,
|
||||
) -> Result<Json<Value>, AppError> {
|
||||
let settings = state.settings.read().await.clone();
|
||||
home_assistant::test_connection(&state.http, &settings.home_assistant)
|
||||
let sample = home_assistant::test_connection(&state.http, &settings.home_assistant)
|
||||
.await
|
||||
.map_err(map_home_assistant_integration_error)?;
|
||||
Ok(Json(json!({"ok": true})))
|
||||
Ok(Json(json!({
|
||||
"ok": true,
|
||||
"auth_mode": home_assistant::auth_mode(&settings.home_assistant),
|
||||
"sample": sample,
|
||||
})))
|
||||
}
|
||||
|
||||
async fn list_home_assistant_entities(
|
||||
State(state): State<AppState>,
|
||||
) -> Result<Json<Value>, AppError> {
|
||||
let settings = state.settings.read().await.home_assistant.clone();
|
||||
if !home_assistant::token_configured(&settings)
|
||||
|| home_assistant::effective_url(&settings).trim().is_empty()
|
||||
{
|
||||
return Ok(Json(json!({
|
||||
"configured": false,
|
||||
"entities": [],
|
||||
})));
|
||||
}
|
||||
|
||||
let mut entities = home_assistant::list_entities(&state.http, &settings)
|
||||
.await
|
||||
.map_err(map_home_assistant_integration_error)?
|
||||
.into_iter()
|
||||
.filter_map(|entity| {
|
||||
let entity_id = entity.get("entity_id")?.as_str()?.trim();
|
||||
if entity_id.is_empty() {
|
||||
return None;
|
||||
}
|
||||
let attributes = entity.get("attributes").and_then(Value::as_object);
|
||||
Some(json!({
|
||||
"entity_id": entity_id,
|
||||
"name": attributes.and_then(|value| value.get("friendly_name")).and_then(Value::as_str).unwrap_or_default(),
|
||||
"state": entity.get("state").and_then(Value::as_str).unwrap_or_default(),
|
||||
"unit": attributes.and_then(|value| value.get("unit_of_measurement")).and_then(Value::as_str).unwrap_or_default(),
|
||||
"device_class": attributes.and_then(|value| value.get("device_class")).and_then(Value::as_str).unwrap_or_default(),
|
||||
}))
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
entities.sort_by(|a, b| {
|
||||
a.get("entity_id")
|
||||
.and_then(Value::as_str)
|
||||
.unwrap_or_default()
|
||||
.cmp(b.get("entity_id").and_then(Value::as_str).unwrap_or_default())
|
||||
});
|
||||
Ok(Json(json!({
|
||||
"configured": true,
|
||||
"entities": entities,
|
||||
})))
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
@@ -116,7 +165,9 @@ async fn list_home_assistant_energy_sensors(
|
||||
State(state): State<AppState>,
|
||||
) -> Result<Json<Value>, AppError> {
|
||||
let settings = state.settings.read().await.home_assistant.clone();
|
||||
if settings.url.trim().is_empty() || settings.token.trim().is_empty() {
|
||||
if !home_assistant::token_configured(&settings)
|
||||
|| home_assistant::effective_url(&settings).trim().is_empty()
|
||||
{
|
||||
return Ok(Json(json!({
|
||||
"configured": false,
|
||||
"sensors": [],
|
||||
|
||||
@@ -50,9 +50,14 @@ fn public_settings(settings: &RuntimeSettings) -> Value {
|
||||
},
|
||||
"home_assistant": {
|
||||
"url": home_assistant::effective_url(&settings.home_assistant),
|
||||
"auth_mode": home_assistant::auth_mode(),
|
||||
"manual_url": settings.home_assistant.url,
|
||||
"auth_mode": home_assistant::auth_mode(&settings.home_assistant),
|
||||
"token": "",
|
||||
"token_configured": home_assistant::token_configured(&settings.home_assistant),
|
||||
"manual_token_configured": !settings.home_assistant.token.trim().is_empty(),
|
||||
"supervisor_detected": home_assistant::supervisor_detected(),
|
||||
"supervisor_token_detected": home_assistant::supervisor_token_detected(),
|
||||
"manual_auth_override": settings.home_assistant.manual_auth_override,
|
||||
"outdoor_entity_id": settings.home_assistant.outdoor_entity_id,
|
||||
"sensor_stale_after_seconds": settings.home_assistant.sensor_stale_after_seconds,
|
||||
"allow_invalid_tls": settings.home_assistant.allow_invalid_tls,
|
||||
|
||||
+12
-5
@@ -79,8 +79,13 @@ fn notification_settings(settings: &RuntimeSettings) -> NotificationSettingsView
|
||||
fn home_assistant_settings(settings: &RuntimeSettings) -> HomeAssistantSettingsView {
|
||||
HomeAssistantSettingsView {
|
||||
url: home_assistant::effective_url(&settings.home_assistant),
|
||||
auth_mode: home_assistant::auth_mode().to_string(),
|
||||
manual_url: settings.home_assistant.url.clone(),
|
||||
auth_mode: home_assistant::auth_mode(&settings.home_assistant).to_string(),
|
||||
token_configured: home_assistant::token_configured(&settings.home_assistant),
|
||||
manual_token_configured: !settings.home_assistant.token.trim().is_empty(),
|
||||
supervisor_detected: home_assistant::supervisor_detected(),
|
||||
supervisor_token_detected: home_assistant::supervisor_token_detected(),
|
||||
manual_auth_override: settings.home_assistant.manual_auth_override,
|
||||
outdoor_entity_id: settings.home_assistant.outdoor_entity_id.clone(),
|
||||
sensor_stale_after_seconds: settings.home_assistant.sensor_stale_after_seconds,
|
||||
allow_invalid_tls: settings.home_assistant.allow_invalid_tls,
|
||||
@@ -694,9 +699,10 @@ fn apply_home_assistant_update(
|
||||
current: &HomeAssistantSettings,
|
||||
input: HomeAssistantSettingsUpdate,
|
||||
) -> HomeAssistantSettings {
|
||||
let supervisor_managed = home_assistant::uses_supervisor_auth();
|
||||
let supervisor_detected = home_assistant::supervisor_detected();
|
||||
let manual_auth_override = supervisor_detected && input.manual_auth_override;
|
||||
let mut next = HomeAssistantSettings {
|
||||
url: if supervisor_managed {
|
||||
url: if supervisor_detected && !manual_auth_override {
|
||||
current.url.clone()
|
||||
} else {
|
||||
input.url
|
||||
@@ -705,10 +711,11 @@ fn apply_home_assistant_update(
|
||||
outdoor_entity_id: input.outdoor_entity_id,
|
||||
sensor_stale_after_seconds: input.sensor_stale_after_seconds.clamp(30, 86_400),
|
||||
allow_invalid_tls: input.allow_invalid_tls,
|
||||
manual_auth_override,
|
||||
sensor_aliases: input.sensor_aliases,
|
||||
flow_inputs: input.flow_inputs,
|
||||
};
|
||||
if !supervisor_managed {
|
||||
if !supervisor_detected || manual_auth_override {
|
||||
if let Some(token) = input.token {
|
||||
next.token = token;
|
||||
}
|
||||
@@ -728,7 +735,7 @@ async fn update_home_assistant_settings(
|
||||
normalize_sensor_aliases(&mut next);
|
||||
validate_flow_shared_inputs(&mut next, &state)?;
|
||||
canonicalize_home_assistant_entities(&mut next);
|
||||
if !home_assistant::uses_supervisor_auth() {
|
||||
if !home_assistant::uses_supervisor_auth(&next) {
|
||||
validate_home_assistant_url(&next)?;
|
||||
}
|
||||
settings.home_assistant = next.clone();
|
||||
|
||||
Reference in New Issue
Block a user