This commit is contained in:
Mateusz Gruszczyński
2026-09-14 16:32:28 +02:00
parent c3fbc5ccc6
commit 021cbddba5
68 changed files with 7780 additions and 202 deletions
+99
View File
@@ -17,6 +17,20 @@ fn gree_settings(settings: &RuntimeSettings) -> GreeSettings {
}
}
fn gree_cloud_settings(settings: &RuntimeSettings) -> GreeCloudSettingsView {
GreeCloudSettingsView {
enabled: settings.gree_cloud.enabled,
region: settings.gree_cloud.region.clone(),
username: settings.gree_cloud.username.clone(),
password_configured: !settings.gree_cloud.password.is_empty(),
polling_interval_seconds: settings.gree_cloud.polling_interval_seconds,
installation_id: settings.gree_cloud.installation_id.clone(),
account_id: settings.gree_cloud.account_id.clone(),
last_successful_contact: settings.gree_cloud.last_successful_contact,
last_rest_response_time_ms: settings.gree_cloud.last_rest_response_time_ms,
}
}
fn history_settings(settings: &RuntimeSettings) -> HistorySettings {
HistorySettings {
retention_days: settings.history_retention_days,
@@ -74,6 +88,7 @@ fn settings_snapshot(settings: &RuntimeSettings) -> SettingsSnapshot {
SettingsSnapshot {
application: application_settings(settings),
gree: gree_settings(settings),
gree_cloud: gree_cloud_settings(settings),
history: history_settings(settings),
influxdb: influxdb_settings(settings),
notifications: notification_settings(settings),
@@ -209,6 +224,84 @@ async fn update_gree_settings(
Ok(Json(payload))
}
async fn get_gree_cloud_settings(
State(state): State<AppState>,
) -> Json<GreeCloudSettingsView> {
Json(gree_cloud_settings(&*state.settings.read().await))
}
fn apply_gree_cloud_update(
current: &GreeCloudSettings,
input: GreeCloudSettingsUpdate,
) -> Result<GreeCloudSettings, AppError> {
if crate::protocol::gree_cloud::region_base_url(input.region.trim()).is_none() {
return Err(AppError::BadRequest(format!(
"unsupported GREE Cloud region: {}",
input.region
)));
}
let mut next = current.clone();
next.enabled = input.enabled;
next.region = input.region.trim().to_string();
next.username = input.username.trim().to_string();
next.polling_interval_seconds = input.polling_interval_seconds.clamp(30, 3600);
if let Some(password) = input.password {
next.password = password;
}
if next.enabled && next.username.is_empty() {
return Err(AppError::BadRequest(
"GREE Cloud login/email is required when cloud is enabled".into(),
));
}
if next.enabled && next.password.is_empty() {
return Err(AppError::BadRequest(
"GREE Cloud password is required when cloud is enabled".into(),
));
}
Ok(next)
}
async fn update_gree_cloud_settings(
State(state): State<AppState>,
Json(input): Json<GreeCloudSettingsUpdate>,
) -> Result<Json<GreeCloudSettingsView>, AppError> {
let _configuration_guard = state.lock_configuration_operation().await;
let (payload, reconnect_required) = {
let mut settings = state.settings.write().await;
let previous = settings.gree_cloud.clone();
let next = apply_gree_cloud_update(&previous, input)?;
let reconnect_required = previous.enabled != next.enabled
|| previous.region != next.region
|| previous.username != next.username
|| previous.password != next.password;
settings.gree_cloud = next;
state.db.save_runtime_settings(&settings)?;
(gree_cloud_settings(&settings), reconnect_required)
};
if reconnect_required {
// Never keep a broker session authenticated with stale/disabled account settings.
// The reconnect loop will establish a fresh session when Cloud remains enabled.
state.providers.cloud().shutdown().await;
}
state.log(
"info",
"settings.gree_cloud.updated",
"GREE Cloud settings updated",
json!({
"enabled": payload.enabled,
"region": payload.region,
"polling_interval_seconds": payload.polling_interval_seconds,
"password_configured": payload.password_configured
}),
);
state.broadcast(
"settings.gree_cloud.updated",
serde_json::to_value(&payload)?,
);
Ok(Json(payload))
}
async fn get_history_settings(State(state): State<AppState>) -> Json<HistorySettings> {
Json(history_settings(&*state.settings.read().await))
}
@@ -645,6 +738,12 @@ async fn update_debug_settings(
state
.debug_gree_frames
.store(input.gree_frames, Ordering::Relaxed);
state
.debug_cloud_requests
.store(input.cloud_requests, Ordering::Relaxed);
state
.debug_cloud_mqtt
.store(input.cloud_mqtt, Ordering::Relaxed);
state.broadcast("settings.debug.updated", serde_json::to_value(&input)?);
Ok(Json(input))
}