This commit is contained in:
Mateusz Gruszczyński
2026-09-15 09:04:29 +02:00
parent 0a2fb8c6c7
commit 2ff310bdc5
37 changed files with 731 additions and 141 deletions
+25 -2
View File
@@ -897,13 +897,36 @@ async fn apply_flow_zone_action(state: &AppState, zone_id: &str, preset: Option<
zone.control_reason = "Visual Flow automation".into();
}
refresh_zone_runtime_target(&mut zone, &schedules, &house_mode);
state.db.save_zone(&zone)?; state.broadcast("zone.updated", serde_json::to_value(&zone)?); state.wake_zone_control();
state.db.save_zone(&zone)?;
state.broadcast("zone.updated", serde_json::to_value(&zone)?);
let swing_command = DeviceCommand {
swing_vertical: action.swing_vertical,
swing_horizontal: action.swing_horizontal,
..Default::default()
};
if action.power == Some(false) {
// Disabled zones are intentionally skipped by the normal thermostat cycle. Perform the
// physical OFF under the canonical zone -> device lock order so the durable Flow intent
// cannot leave a unit running and polling/manual control cannot interleave with the frame.
// Swing can safely share this explicit frame because it is outside thermostat regulation.
let _device_guard = state.lock_device_operation(&device_id).await;
send_command_locked_forced(state, &device_id, DeviceCommand { power: Some(false), ..Default::default() }).await?;
send_command_locked_forced(
state,
&device_id,
DeviceCommand {
power: Some(false),
swing_vertical: swing_command.swing_vertical,
swing_horizontal: swing_command.swing_horizontal,
..Default::default()
},
)
.await?;
} else if !swing_command.is_empty() {
// Swing is intentionally a one-shot auxiliary unit setting. It does not participate in
// temperature/fan regulation, so the thermostat keeps ownership of the zone.
let _ = send_automatic_device_command_if_owned(state, &device_id, swing_command).await?;
}
state.wake_zone_control();
Ok(true)
}