This commit is contained in:
Mateusz Gruszczyński
2026-09-01 10:20:19 +02:00
parent 1a5c1305dc
commit 3479ed750d
34 changed files with 575 additions and 113 deletions
+19 -1
View File
@@ -73,8 +73,20 @@ pub fn finish_temporary_quick_thermostat(zone: &mut Zone, schedules: &[Schedule]
zone.manual_preset = None;
zone.manual_setpoint = None;
zone.manual_override_until = None;
} else if matches!(preset, "comfort" | "sleep" | "away") {
} else if matches!(preset, "comfort" | "sleep" | "away" | "custom") {
zone.manual_preset = Some(preset.to_string());
if preset != "custom" { zone.manual_setpoint = None; }
zone.manual_override_until = next_schedule_boundary_utc(&zone.id, schedules, Local::now());
}
}
// A deferred custom temperature is valid only while the final deferred preset is custom.
// This makes the hand-back robust even if an older persisted session contains a stale
// deferred_setpoint from a previously selected Custom action.
if session.deferred_preset.as_deref() == Some("custom") {
if let Some(setpoint) = session.deferred_setpoint {
zone.setpoint = setpoint;
zone.manual_preset = Some("custom".into());
zone.manual_setpoint = Some(setpoint);
zone.manual_override_until = next_schedule_boundary_utc(&zone.id, schedules, Local::now());
}
}
@@ -88,6 +100,8 @@ async fn expire_temporary_quick_thermostats(state: &AppState, zones: &mut [Zone]
for zone in zones.iter_mut() {
let zone_id = zone.id.clone();
let _zone_guard = state.lock_zone_operation(&zone_id).await;
let Some(snapshot) = state.db.get_zone(&zone_id)? else { continue; };
let _device_guard = state.lock_device_operation(&snapshot.device_id).await;
let Some(latest) = state.db.get_zone(&zone_id)? else { continue; };
*zone = latest;
let active_under_manual = zone.device_manual_override
@@ -153,6 +167,8 @@ async fn activate_due_temporary_quick_thermostats(
for zone in zones.iter_mut() {
let zone_id = zone.id.clone();
let _zone_guard = state.lock_zone_operation(&zone_id).await;
let Some(snapshot) = state.db.get_zone(&zone_id)? else { continue; };
let _device_guard = state.lock_device_operation(&snapshot.device_id).await;
let Some(latest) = state.db.get_zone(&zone_id)? else { continue; };
*zone = latest;
let Some((session_state, started_at)) = zone.temporary_quick_thermostat.as_ref()
@@ -330,6 +346,8 @@ async fn expire_local_thermostat_overrides(state: &AppState, zones: &mut [Zone],
for zone in zones.iter_mut() {
let zone_id = zone.id.clone();
let _zone_guard = state.lock_zone_operation(&zone_id).await;
let Some(snapshot) = state.db.get_zone(&zone_id)? else { continue; };
let _device_guard = state.lock_device_operation(&snapshot.device_id).await;
let Some(latest) = state.db.get_zone(&zone_id)? else { continue; };
*zone = latest;
// A direct device/pilot takeover has higher priority than the local-OFF hand-back.