v0.14.21
This commit is contained in:
+102
-65
@@ -19,7 +19,9 @@ fn cloud_error_kind(error: &anyhow::Error) -> &'static str {
|
||||
}
|
||||
}
|
||||
|
||||
async fn cloud_api_from_settings(state: &AppState) -> Result<crate::protocol::gree_cloud::GreeCloudApi, AppError> {
|
||||
async fn cloud_api_from_settings(
|
||||
state: &AppState,
|
||||
) -> Result<crate::protocol::gree_cloud::GreeCloudApi, AppError> {
|
||||
let settings = state.settings.read().await.gree_cloud.clone();
|
||||
crate::protocol::gree_cloud::GreeCloudApi::for_region(
|
||||
state.http.clone(),
|
||||
@@ -33,7 +35,10 @@ async fn cloud_api_from_settings(state: &AppState) -> Result<crate::protocol::gr
|
||||
async fn test_gree_cloud(State(state): State<AppState>) -> Result<Json<Value>, AppError> {
|
||||
let mut api = cloud_api_from_settings(&state).await?;
|
||||
let started = Instant::now();
|
||||
cloud_debug_event(&state, json!({"operation":"test_connection","phase":"sent"}));
|
||||
cloud_debug_event(
|
||||
&state,
|
||||
json!({"operation":"test_connection","phase":"sent"}),
|
||||
);
|
||||
let result = async {
|
||||
api.login().await?;
|
||||
let devices = api.get_all_devices().await?;
|
||||
@@ -44,12 +49,15 @@ async fn test_gree_cloud(State(state): State<AppState>) -> Result<Json<Value>, A
|
||||
match result {
|
||||
Ok(device_count) => {
|
||||
let now = Utc::now();
|
||||
cloud_debug_event(&state, json!({
|
||||
"operation":"test_connection",
|
||||
"phase":"response",
|
||||
"duration_ms": started.elapsed().as_millis() as u64,
|
||||
"device_count": device_count,
|
||||
}));
|
||||
cloud_debug_event(
|
||||
&state,
|
||||
json!({
|
||||
"operation":"test_connection",
|
||||
"phase":"response",
|
||||
"duration_ms": started.elapsed().as_millis() as u64,
|
||||
"device_count": device_count,
|
||||
}),
|
||||
);
|
||||
{
|
||||
let _configuration_guard = state.lock_configuration_operation().await;
|
||||
let mut settings = state.settings.write().await;
|
||||
@@ -73,12 +81,15 @@ async fn test_gree_cloud(State(state): State<AppState>) -> Result<Json<Value>, A
|
||||
}
|
||||
Err(error) => {
|
||||
let kind = cloud_error_kind(&error);
|
||||
cloud_debug_event(&state, json!({
|
||||
"operation":"test_connection",
|
||||
"phase":"error",
|
||||
"duration_ms": started.elapsed().as_millis() as u64,
|
||||
"kind": kind,
|
||||
}));
|
||||
cloud_debug_event(
|
||||
&state,
|
||||
json!({
|
||||
"operation":"test_connection",
|
||||
"phase":"error",
|
||||
"duration_ms": started.elapsed().as_millis() as u64,
|
||||
"kind": kind,
|
||||
}),
|
||||
);
|
||||
tracing::warn!(kind, "GREE Cloud connection test failed");
|
||||
state.log(
|
||||
"warn",
|
||||
@@ -107,38 +118,42 @@ async fn discover_gree_cloud_devices(
|
||||
let mut api = cloud_api_from_settings(&state).await?;
|
||||
let started = Instant::now();
|
||||
cloud_debug_event(&state, json!({"operation":"discovery","phase":"sent"}));
|
||||
api.login()
|
||||
.await
|
||||
.map_err(|err| {
|
||||
cloud_debug_event(&state, json!({
|
||||
api.login().await.map_err(|err| {
|
||||
cloud_debug_event(
|
||||
&state,
|
||||
json!({
|
||||
"operation":"discovery",
|
||||
"phase":"error",
|
||||
"stage":"login",
|
||||
"duration_ms": started.elapsed().as_millis() as u64,
|
||||
"kind": cloud_error_kind(&err),
|
||||
}));
|
||||
AppError::Dependency(format!("GREE Cloud login failed: {err}"))
|
||||
})?;
|
||||
let devices = api
|
||||
.get_all_devices()
|
||||
.await
|
||||
.map_err(|err| {
|
||||
cloud_debug_event(&state, json!({
|
||||
}),
|
||||
);
|
||||
AppError::Dependency(format!("GREE Cloud login failed: {err}"))
|
||||
})?;
|
||||
let devices = api.get_all_devices().await.map_err(|err| {
|
||||
cloud_debug_event(
|
||||
&state,
|
||||
json!({
|
||||
"operation":"discovery",
|
||||
"phase":"error",
|
||||
"stage":"devices",
|
||||
"duration_ms": started.elapsed().as_millis() as u64,
|
||||
"kind": cloud_error_kind(&err),
|
||||
}));
|
||||
AppError::Dependency(format!("GREE Cloud discovery failed: {err}"))
|
||||
})?;
|
||||
}),
|
||||
);
|
||||
AppError::Dependency(format!("GREE Cloud discovery failed: {err}"))
|
||||
})?;
|
||||
let rest_duration_ms = started.elapsed().as_millis().min(u64::MAX as u128) as u64;
|
||||
cloud_debug_event(&state, json!({
|
||||
"operation":"discovery",
|
||||
"phase":"response",
|
||||
"duration_ms": rest_duration_ms,
|
||||
"device_count": devices.len(),
|
||||
}));
|
||||
cloud_debug_event(
|
||||
&state,
|
||||
json!({
|
||||
"operation":"discovery",
|
||||
"phase":"response",
|
||||
"duration_ms": rest_duration_ms,
|
||||
"device_count": devices.len(),
|
||||
}),
|
||||
);
|
||||
{
|
||||
let _configuration_guard = state.lock_configuration_operation().await;
|
||||
let mut settings = state.settings.write().await;
|
||||
@@ -153,7 +168,10 @@ async fn discover_gree_cloud_devices(
|
||||
let id = device.mac.replace([':', '-'], "").to_ascii_uppercase();
|
||||
let already_added = existing.iter().any(|saved| {
|
||||
saved.connection_type == ConnectionType::GreeCloud
|
||||
&& saved.cloud_device_id.as_deref().is_some_and(|value| value.eq_ignore_ascii_case(&id))
|
||||
&& saved
|
||||
.cloud_device_id
|
||||
.as_deref()
|
||||
.is_some_and(|value| value.eq_ignore_ascii_case(&id))
|
||||
});
|
||||
crate::protocol::gree_cloud::CloudDeviceView {
|
||||
parent_mac: crate::protocol::gree_cloud::parent_mac(&id),
|
||||
@@ -196,50 +214,63 @@ async fn add_gree_cloud_device(
|
||||
// Re-discover server-side so the frontend never needs to submit/store the device cipher key.
|
||||
let mut api = cloud_api_from_settings(&state).await?;
|
||||
let started = Instant::now();
|
||||
cloud_debug_event(&state, json!({
|
||||
"operation":"add_device_lookup",
|
||||
"phase":"sent",
|
||||
"cloud_device_id": cloud_id.clone(),
|
||||
}));
|
||||
api.login()
|
||||
.await
|
||||
.map_err(|err| {
|
||||
cloud_debug_event(&state, json!({
|
||||
cloud_debug_event(
|
||||
&state,
|
||||
json!({
|
||||
"operation":"add_device_lookup",
|
||||
"phase":"sent",
|
||||
"cloud_device_id": cloud_id.clone(),
|
||||
}),
|
||||
);
|
||||
api.login().await.map_err(|err| {
|
||||
cloud_debug_event(
|
||||
&state,
|
||||
json!({
|
||||
"operation":"add_device_lookup",
|
||||
"phase":"error",
|
||||
"stage":"login",
|
||||
"duration_ms": started.elapsed().as_millis() as u64,
|
||||
"kind": cloud_error_kind(&err),
|
||||
}));
|
||||
AppError::Dependency(format!("GREE Cloud login failed: {err}"))
|
||||
})?;
|
||||
}),
|
||||
);
|
||||
AppError::Dependency(format!("GREE Cloud login failed: {err}"))
|
||||
})?;
|
||||
let cloud_device = api
|
||||
.get_all_devices()
|
||||
.await
|
||||
.map_err(|err| {
|
||||
cloud_debug_event(&state, json!({
|
||||
"operation":"add_device_lookup",
|
||||
"phase":"error",
|
||||
"stage":"devices",
|
||||
"duration_ms": started.elapsed().as_millis() as u64,
|
||||
"kind": cloud_error_kind(&err),
|
||||
}));
|
||||
cloud_debug_event(
|
||||
&state,
|
||||
json!({
|
||||
"operation":"add_device_lookup",
|
||||
"phase":"error",
|
||||
"stage":"devices",
|
||||
"duration_ms": started.elapsed().as_millis() as u64,
|
||||
"kind": cloud_error_kind(&err),
|
||||
}),
|
||||
);
|
||||
AppError::Dependency(format!("GREE Cloud discovery failed: {err}"))
|
||||
})?
|
||||
.into_iter()
|
||||
.find(|device| device.mac.eq_ignore_ascii_case(&cloud_id))
|
||||
.ok_or_else(|| AppError::NotFound(format!("GREE Cloud device {cloud_id}")))?;
|
||||
cloud_debug_event(&state, json!({
|
||||
"operation":"add_device_lookup",
|
||||
"phase":"response",
|
||||
"duration_ms": started.elapsed().as_millis() as u64,
|
||||
"cloud_device_id": cloud_id.clone(),
|
||||
}));
|
||||
cloud_debug_event(
|
||||
&state,
|
||||
json!({
|
||||
"operation":"add_device_lookup",
|
||||
"phase":"response",
|
||||
"duration_ms": started.elapsed().as_millis() as u64,
|
||||
"cloud_device_id": cloud_id.clone(),
|
||||
}),
|
||||
);
|
||||
|
||||
let _configuration_guard = state.lock_configuration_operation().await;
|
||||
let now = Utc::now();
|
||||
let account_id = state.settings.read().await.gree_cloud.account_id.clone();
|
||||
let normalized_cloud_mac = cloud_device.mac.replace([':', '-'], "").to_ascii_uppercase();
|
||||
let normalized_cloud_mac = cloud_device
|
||||
.mac
|
||||
.replace([':', '-'], "")
|
||||
.to_ascii_uppercase();
|
||||
let device = Device {
|
||||
id: format!("gree-cloud-{}", normalized_cloud_mac.to_ascii_lowercase()),
|
||||
mac: normalized_cloud_mac.clone(),
|
||||
@@ -251,7 +282,9 @@ async fn add_gree_cloud_device(
|
||||
connection_type: ConnectionType::GreeCloud,
|
||||
connection_status: ConnectionStatus::CloudDisconnected,
|
||||
cloud_device_id: Some(normalized_cloud_mac.clone()),
|
||||
cloud_parent_mac: Some(crate::protocol::gree_cloud::parent_mac(&normalized_cloud_mac)),
|
||||
cloud_parent_mac: Some(crate::protocol::gree_cloud::parent_mac(
|
||||
&normalized_cloud_mac,
|
||||
)),
|
||||
cloud_account_id: Some(account_id),
|
||||
ip: String::new(),
|
||||
port: 0,
|
||||
@@ -383,7 +416,9 @@ async fn reconnect_gree_cloud(State(state): State<AppState>) -> Result<Json<Valu
|
||||
"GREE Cloud MQTT reconnected",
|
||||
json!({"device_count": devices.iter().filter(|device| device.connection_type == ConnectionType::GreeCloud).count()}),
|
||||
);
|
||||
Ok(Json(json!({"ok": true, "mqtt_status": "connected", "last_successful_contact": now})))
|
||||
Ok(Json(
|
||||
json!({"ok": true, "mqtt_status": "connected", "last_successful_contact": now}),
|
||||
))
|
||||
}
|
||||
|
||||
async fn cloud_device_diagnostics(
|
||||
@@ -395,7 +430,9 @@ async fn cloud_device_diagnostics(
|
||||
.get_device(&id)?
|
||||
.ok_or_else(|| AppError::NotFound(format!("device {id}")))?;
|
||||
if device.connection_type != ConnectionType::GreeCloud {
|
||||
return Err(AppError::BadRequest("Cloud diagnostics are available only for GREE Cloud devices".into()));
|
||||
return Err(AppError::BadRequest(
|
||||
"Cloud diagnostics are available only for GREE Cloud devices".into(),
|
||||
));
|
||||
}
|
||||
let diagnostics = state.providers.cloud().diagnostics(&device.id).await;
|
||||
Ok(Json(json!({
|
||||
|
||||
Reference in New Issue
Block a user