This commit is contained in:
Mateusz Gruszczyński
2026-08-30 13:39:29 +02:00
parent 3e950ab5fa
commit 5c05eddb8f
83 changed files with 10130 additions and 9954 deletions
+109
View File
@@ -0,0 +1,109 @@
fn record_zone_history(state: &AppState, zone: &Zone, outdoor_temperature: Option<f64>, poll_interval_seconds: u64) {
let device = match state.db.get_device(&zone.device_id) {
Ok(Some(device)) => device,
Ok(None) => return,
Err(err) => {
tracing::warn!(error=?err, zone_id=%zone.id, "cannot load device for zone history");
return;
}
};
let reading = ZoneReading {
id: 0,
zone_id: zone.id.clone(),
device_id: zone.device_id.clone(),
timestamp: Utc::now(),
gree_temperature: zone.device_temperature.or(device.current_temperature),
external_temperature: zone.external_temperature,
control_temperature: zone.current_temperature.or(zone.device_temperature).or(device.current_temperature),
target_temperature: zone.effective_setpoint.or(zone.manual_setpoint).or(Some(zone.setpoint)),
device_setpoint: zone.device_setpoint.or(Some(device.target_temperature)),
outdoor_temperature: outdoor_temperature.or(device.outdoor_temperature),
power: device.power,
mode: if zone.effective_mode.is_empty() { device.mode.clone() } else { zone.effective_mode.clone() },
fan_speed: device.fan_speed,
demand: zone.demand,
control_source: zone.control_temperature_source.clone(),
active_preset: zone.active_preset.clone(),
};
let interval = poll_interval_seconds.max(15) as i64;
match state.db.add_zone_reading_if_due(&reading, interval) {
Ok(true) => queue_influx_zone(state, reading),
Ok(false) => {}
Err(err) => tracing::warn!(error=?err, zone_id=%zone.id, "cannot save zone history sample"),
}
}
fn record_ha_history(
state: &AppState,
entity_id: &str,
zone_id: Option<&str>,
kind: &str,
temperature: f64,
poll_interval_seconds: u64,
) {
let reading = HaReading {
id: 0,
entity_id: entity_id.to_string(),
zone_id: zone_id.map(str::to_string),
kind: kind.to_string(),
timestamp: Utc::now(),
temperature,
};
let interval = poll_interval_seconds.max(15) as i64;
match state.db.add_ha_reading_if_due(&reading, interval) {
Ok(true) => queue_influx_ha(state, reading),
Ok(false) => {}
Err(err) => tracing::warn!(error=?err, entity_id=%entity_id, "cannot save Home Assistant history sample"),
}
}
fn queue_influx_device(state: &AppState, reading: Reading) {
let state = state.clone();
tokio::spawn(async move {
let settings = state.settings.read().await.influxdb.clone();
if !settings.enabled { return; }
if let Err(err) = influxdb::write_device(&state.http, &settings, &reading).await {
tracing::warn!(error=?err, device_id=%reading.device_id, "cannot write device metric to InfluxDB");
}
});
}
fn queue_influx_zone(state: &AppState, reading: ZoneReading) {
let state = state.clone();
tokio::spawn(async move {
let settings = state.settings.read().await.influxdb.clone();
if !settings.enabled { return; }
if let Err(err) = influxdb::write_zone(&state.http, &settings, &reading).await {
tracing::warn!(error=?err, zone_id=%reading.zone_id, "cannot write zone metric to InfluxDB");
}
});
}
fn queue_influx_ha(state: &AppState, reading: HaReading) {
let state = state.clone();
tokio::spawn(async move {
let settings = state.settings.read().await.influxdb.clone();
if !settings.enabled { return; }
if let Err(err) = influxdb::write_ha(&state.http, &settings, &reading).await {
tracing::warn!(error=?err, entity_id=%reading.entity_id, "cannot write HA metric to InfluxDB");
}
});
}
fn gree_outdoor_temperature(devices: &[Device]) -> Option<f64> {
let mut values: Vec<f64> = devices.iter()
.filter(|device| device.enabled && device.online && device.communication_failures == 0)
.filter_map(|device| device.outdoor_temperature)
.filter(|value| value.is_finite() && (-60.0..=70.0).contains(value))
.collect();
if values.is_empty() { return None; }
values.sort_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal));
let middle = values.len() / 2;
let value = if values.len() % 2 == 0 {
(values[middle - 1] + values[middle]) / 2.0
} else {
values[middle]
};
Some((value * 10.0).round() / 10.0)
}