async fn health(State(state): State) -> Json { Json(json!({ "status": "ok", "name": "gree-controller", "version": env!("CARGO_PKG_VERSION"), "uptime_seconds": state.started.elapsed().as_secs(), "control_ready": state.initial_device_sync_complete.load(Ordering::Acquire), "time": Utc::now(), })) } async fn bootstrap(State(state): State) -> Result, AppError> { Ok(Json(build_bootstrap(&state).await?)) } async fn build_bootstrap(state: &AppState) -> Result { let settings = state.settings.read().await.clone(); let devices = state.db.list_devices()?; let device_count = devices.len(); let online_count = devices.iter().filter(|value| value.online).count(); let simulator_count = devices.iter().filter(|value| value.simulated).count(); let (received_frames_total, received_frames_by_device) = state.gree.received_frame_stats(); let control_plan = engine::get_control_plan_snapshot(state).await?; Ok(json!({ "devices": devices, "zones": state.db.list_zones()?, "groups": state.db.list_groups()?, "schedules": state.db.list_schedules()?, "automations": state.db.list_automations()?, "flows": state.db.list_flows()?, "access_tokens": state.db.list_api_tokens()?, "house": {"mode": settings.house_mode}, "outdoor_temperature": *state.outdoor_temperature.read().await, "control_plan": control_plan.plan.as_ref(), "control_plan_revision": control_plan.revision, "system": { "version": env!("CARGO_PKG_VERSION"), "uptime_seconds": state.started.elapsed().as_secs(), "auth_required": !state.config.app_token.trim().is_empty(), "control_ready": state.initial_device_sync_complete.load(Ordering::Acquire), "database": state.config.database.display().to_string(), "device_count": device_count, "online_count": online_count, "simulator_count": simulator_count, "bind": state.config.bind.to_string(), "base_path": if state.config.base_path.is_empty() { "/" } else { state.config.base_path.as_str() }, "gree_interface": if state.config.gree_interface.trim().is_empty() { "auto" } else { state.config.gree_interface.trim() }, "gree_received_frames": received_frames_total, "gree_received_frames_by_device": received_frames_by_device, } })) } async fn system_info(State(state): State) -> Result, AppError> { let devices = state.db.list_devices()?; let (received_frames_total, received_frames_by_device) = state.gree.received_frame_stats(); Ok(Json(json!({ "version": env!("CARGO_PKG_VERSION"), "uptime_seconds": state.started.elapsed().as_secs(), "database": state.config.database.display().to_string(), "device_count": devices.len(), "online_count": devices.iter().filter(|v| v.online).count(), "simulator_count": devices.iter().filter(|v| v.simulated).count(), "control_ready": state.initial_device_sync_complete.load(Ordering::Acquire), "auth_required": !state.config.app_token.trim().is_empty(), "bind": state.config.bind.to_string(), "base_path": if state.config.base_path.is_empty() { "/" } else { state.config.base_path.as_str() }, "gree_interface": if state.config.gree_interface.trim().is_empty() { "auto" } else { state.config.gree_interface.trim() }, "gree_received_frames": received_frames_total, "gree_received_frames_by_device": received_frames_by_device, }))) }