This commit is contained in:
Mateusz Gruszczyński
2026-09-01 12:07:04 +02:00
parent 6207bc4de6
commit e496f911da
25 changed files with 227 additions and 309 deletions
+3 -30
View File
@@ -1,7 +1,6 @@
async fn control_zones(state: &AppState) -> Result<()> {
let _cycle_guard = state.lock_zone_control_cycle().await;
let schedules = state.db.list_schedules()?;
let groups = state.db.list_groups()?;
let settings = state.settings.read().await.clone();
let mut zone_snapshot = state.db.list_zones()?;
// Local quick-thermostat OFF is intentionally temporary. Expire the ownership marker
@@ -119,9 +118,7 @@ async fn control_zones(state: &AppState) -> Result<()> {
// remains authoritative and is checked before this loop.
let effective_mode_owned = effective_zone_mode(&zone, &settings.house_mode);
zone.effective_mode = effective_mode_owned.clone();
let ownership_blocked_by_group = zone.local_thermostat_power != Some(true)
&& groups.iter().any(|group| !group.power_enabled && group.zone_ids.iter().any(|zone_id| zone_id == &zone.id));
refresh_control_ownership(&mut zone, settings.house_power_enabled, ownership_blocked_by_group);
refresh_control_ownership(&mut zone, settings.house_power_enabled);
let effective_mode = effective_mode_owned.as_str();
let previous_source = zone.control_temperature_source.clone();
@@ -289,30 +286,6 @@ async fn control_zones(state: &AppState) -> Result<()> {
continue;
}
let blocked_by_group = ownership_blocked_by_group;
if blocked_by_group {
zone.effective_mode = "off".into();
zone.demand = false;
zone.demand_since = None;
zone.device_setpoint = None;
if device.online && device.communication_failures == 0 && device.power {
match send_zone_command_if_owned(
state,
&zone.id,
&zone.device_id,
DeviceCommand { power: Some(false), ..Default::default() },
true,
).await {
Ok(_) => {}
Err(err) => state.log("error", "group.power_error", &err.to_string(), json!({"zone_id": zone.id, "device_id": zone.device_id})),
}
}
record_zone_history(state, &zone, outdoor_temperature, settings.poll_interval_seconds);
let persisted_zone = persist_zone_cycle(state, &zone, cycle_started_at)?;
state.broadcast("zone.updated", serde_json::to_value(&persisted_zone)?);
continue;
}
if discrepancy && previous_source != "device_discrepancy_fallback" {
state.log("warn", "zone.sensor_discrepancy", &format!("Zone {} sensors differ by more than {:.1} C; using GREE sensor", zone.name, zone.max_sensor_difference), json!({
"zone_id": zone.id,
@@ -464,7 +437,7 @@ async fn control_zones(state: &AppState) -> Result<()> {
state.broadcast("zone.updated", serde_json::to_value(&persisted_zone)?);
continue;
}
match send_zone_command_if_owned(state, &zone.id, &zone.device_id, DeviceCommand { power: Some(false), ..Default::default() }, false).await {
match send_zone_command_if_owned(state, &zone.id, &zone.device_id, DeviceCommand { power: Some(false), ..Default::default() }).await {
Ok(Some(_)) => {
zone.last_power_change_at = Some(now);
zone.lockout_until = Some(now + chrono::Duration::seconds(zone.min_off_seconds as i64));
@@ -516,7 +489,7 @@ async fn control_zones(state: &AppState) -> Result<()> {
sleep: desired_sleep,
..Default::default()
};
match send_zone_command_if_owned(state, &zone.id, &zone.device_id, command, false).await {
match send_zone_command_if_owned(state, &zone.id, &zone.device_id, command).await {
Ok(Some(updated_device)) => {
let transition_at = Utc::now();
if device.power != updated_device.power { zone.last_power_change_at = Some(transition_at); }