v0.9.4
This commit is contained in:
+5
-21
@@ -155,7 +155,7 @@ fn set_device_manual_override(state: &AppState, zone: &mut Zone, fields: Vec<Str
|
||||
zone.control_source = normalized_direct_source(source).into();
|
||||
zone.control_reason = "Direct/manual device control has priority".into();
|
||||
// Direct/pilot control is an explicit ownership takeover, not a temporary preset.
|
||||
// Keep it manual until the user explicitly chooses Resume automation. A one-shot global
|
||||
// Keep it manual until the user explicitly chooses Resume automation. A global
|
||||
// ON/OFF command changes physical power only and must never erase manual ownership.
|
||||
// A schedule boundary must never silently take the unit back from the person controlling it.
|
||||
zone.device_manual_override_until = None;
|
||||
@@ -262,9 +262,8 @@ pub async fn send_manual_command(state: &AppState, device_id: &str, command: Dev
|
||||
}
|
||||
|
||||
pub async fn force_house_power_off_device(state: &AppState, device_id: &str, _source: &str) -> Result<Device, AppError> {
|
||||
// Whole-house OFF is a one-shot physical action. Preserve every zone/manual/group owner,
|
||||
// while still taking zone -> device locks so a concurrent local/manual action cannot race
|
||||
// the forced OFF frame. Controllers are free to make a later independent decision.
|
||||
// Whole-house OFF physically forces the unit down after the API has persisted per-zone local OFF.
|
||||
// Keep zone -> device ordering so a concurrent local/manual action cannot race the frame.
|
||||
let mut zone_ids: Vec<String> = state.db.list_zones()?.into_iter()
|
||||
.filter(|zone| zone.device_id == device_id)
|
||||
.map(|zone| zone.id)
|
||||
@@ -280,7 +279,7 @@ pub async fn force_house_power_off_device(state: &AppState, device_id: &str, _so
|
||||
}
|
||||
|
||||
pub async fn one_shot_house_power_on_device(state: &AppState, device_id: &str) -> Result<Device, AppError> {
|
||||
// Global ON is also one-shot and must not take thermostat ownership. For thermostat-managed
|
||||
// Global ON releases per-zone OFF state in the API and must not create a local-ON ownership marker. For thermostat-managed
|
||||
// units it still respects compressor protection; a protected start is stored as a visible
|
||||
// queue item and executed at the protection deadline unless a newer intent cancels/replaces it.
|
||||
let mut zone_ids: Vec<String> = state.db.list_zones()?.into_iter()
|
||||
@@ -330,7 +329,7 @@ pub async fn one_shot_house_power_on_device(state: &AppState, device_id: &str) -
|
||||
}
|
||||
}
|
||||
|
||||
// The device lock is already held. This is physical one-shot power only: no manual marker.
|
||||
// The device lock is already held. This is physical global power only: no manual marker.
|
||||
send_command_locked(state, device_id, DeviceCommand { power: Some(true), ..Default::default() }).await
|
||||
}
|
||||
|
||||
@@ -365,18 +364,3 @@ pub async fn disable_device_safely(state: &AppState, device_id: &str) -> Result<
|
||||
Ok(device)
|
||||
}
|
||||
|
||||
pub fn clear_all_device_manual_overrides(state: &AppState, source: &str) -> Result<usize, AppError> {
|
||||
let mut cleared = 0usize;
|
||||
for mut zone in state.db.list_zones()? {
|
||||
if !reset_device_manual_override(&mut zone) { continue; }
|
||||
zone.updated_at = Utc::now();
|
||||
state.db.save_zone(&zone)?;
|
||||
state.broadcast("zone.updated", serde_json::to_value(&zone)?);
|
||||
state.log("info", "zone.device_manual_override_cleared", &format!("Automation resumed for {}", zone.name), json!({
|
||||
"zone_id": zone.id, "device_id": zone.device_id, "source": source
|
||||
}));
|
||||
cleared += 1;
|
||||
}
|
||||
Ok(cleared)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user