v0.8.20
This commit is contained in:
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user