use std::time::Duration; use futures::stream; use influxdb2::models::DataPoint; use influxdb2::Client; use tokio::time::MissedTickBehavior; use tracing::{info, warn}; use crate::alarm::{SharedAlarms, Status}; use crate::config::InfluxConfig; use crate::gpio::SharedFan; use crate::thermal; pub async fn run(config: InfluxConfig, fan: SharedFan, alarms: SharedAlarms) -> anyhow::Result<()> { // Get client let client = Client::new(&config.url, &config.org, &config.token); // Get interval let mut interval = tokio::time::interval(Duration::from_secs_f64(config.metrics_interval_s)); interval.set_missed_tick_behavior(MissedTickBehavior::Skip); // Debug logging info!( url = %config.url, org = %config.org, bucket = %config.bucket, host = %config.host_tag, interval_s = config.metrics_interval_s, "Metrics task started" ); loop { // Main loop interval.tick().await; // Publish the metrics match publish(&client, &config, &fan, &alarms).await { Ok(()) => alarms.set_fault("metrics", false).await, Err(e) => { // Set the fault if the publish fails warn!(error = %e, "Failed to publish metrics"); alarms.set_fault("metrics", true).await; } } } } // Publish the metrics async fn publish( client: &Client, config: &InfluxConfig, fan: &SharedFan, alarms: &SharedAlarms, ) -> anyhow::Result<()> { let temp_c = tokio::task::spawn_blocking(thermal::read_cpu_temp_c) .await??; let fan_on = fan.lock().await.on(); let alarm = matches!(alarms.status(), Status::Alarm); let point = DataPoint::builder("tower") .tag("host", &config.host_tag) .field("cpu_temp_c", temp_c) .field("fan_on", fan_on) .field("alarm", alarm) .build()?; client .write(&config.bucket, stream::iter(vec![point])) .await .map_err(|e| anyhow::anyhow!("influxdb write failed: {e}"))?; Ok(()) }