This commit is contained in:
Mateusz Gruszczyński
2026-09-01 11:10:28 +02:00
parent 3479ed750d
commit 9f08d7ccf9
30 changed files with 559 additions and 150 deletions
+45
View File
@@ -50,3 +50,48 @@ impl Db {
}
}
impl Db {
/// Merge device transition timestamps into zone JSON without replacing newer zone state.
/// `updated_at` acts as a compare-and-swap token but is intentionally not changed here:
/// thermostat cycles use it to detect real configuration/ownership updates.
pub fn merge_zone_device_transition_timestamps(
&self,
device_id: &str,
power_changed: bool,
mode_changed: bool,
at: DateTime<Utc>,
) -> Result<Vec<Zone>> {
if !power_changed && !mode_changed { return Ok(Vec::new()); }
let zone_ids: Vec<String> = self.list_zones()?.into_iter()
.filter(|zone| zone.device_id == device_id)
.map(|zone| zone.id)
.collect();
let mut updated = Vec::with_capacity(zone_ids.len());
for zone_id in zone_ids {
let mut saved = false;
for _ in 0..8 {
let Some(mut zone) = self.get_zone(&zone_id)? else { break; };
let expected_updated_at = zone.updated_at.to_rfc3339();
if power_changed { zone.last_power_change_at = Some(at); }
if mode_changed { zone.last_mode_change_at = Some(at); }
let payload = Self::to_json(&zone)?;
let conn = self.lock()?;
let changed = conn.execute(
"UPDATE zones SET payload = ?1 WHERE id = ?2 AND updated_at = ?3",
params![payload, zone.id, expected_updated_at],
)?;
drop(conn);
if changed > 0 {
updated.push(zone);
saved = true;
break;
}
}
if !saved && self.get_zone(&zone_id)?.is_some() {
return Err(anyhow::anyhow!("zone {zone_id} kept changing while device transition timestamps were merged"));
}
}
Ok(updated)
}
}