feat(event): add RemLocal/RemRecovered events for REM-triggered auto-stop
When any equipment's REM signal switches to local mode, fire a dedicated `unit.rem_local` event (with unit + equipment context) and record it to the event log. Also fire `unit.rem_recovered` when all REM signals return to remote. AutoControlStopped is still fired alongside RemLocal when auto was running at the time. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
4227747852
commit
7ae952f93e
|
|
@ -326,6 +326,22 @@ async fn check_fault_comm(
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Find the first equipment that just switched to local (for event payload).
|
||||||
|
let rem_local_eq_id = if any_rem_local && !runtime.rem_local {
|
||||||
|
all_roles
|
||||||
|
.iter()
|
||||||
|
.find(|(_, roles)| {
|
||||||
|
roles
|
||||||
|
.get("rem")
|
||||||
|
.and_then(|rp| monitor.get(&rp.point_id))
|
||||||
|
.map(|m| !super::monitor_value_as_bool(m) && m.quality == PointQuality::Good)
|
||||||
|
.unwrap_or(false)
|
||||||
|
})
|
||||||
|
.map(|(eq_id, _)| *eq_id)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
drop(monitor);
|
drop(monitor);
|
||||||
|
|
||||||
let prev_comm = runtime.comm_locked;
|
let prev_comm = runtime.comm_locked;
|
||||||
|
|
@ -362,11 +378,19 @@ async fn check_fault_comm(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop auto-control when any equipment switches to local mode.
|
// Fire RemLocal event when any equipment first switches to local mode.
|
||||||
if any_rem_local && runtime.auto_enabled {
|
if let Some(eq_id) = rem_local_eq_id {
|
||||||
|
let _ = state.event_manager.send(AppEvent::RemLocal { unit_id: unit.id, equipment_id: eq_id });
|
||||||
|
if runtime.auto_enabled {
|
||||||
runtime.auto_enabled = false;
|
runtime.auto_enabled = false;
|
||||||
let _ = state.event_manager.send(AppEvent::AutoControlStopped { unit_id: unit.id });
|
let _ = state.event_manager.send(AppEvent::AutoControlStopped { unit_id: unit.id });
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fire RemRecovered when all rem signals return to remote.
|
||||||
|
if prev_rem_local && !any_rem_local {
|
||||||
|
let _ = state.event_manager.send(AppEvent::RemRecovered { unit_id: unit.id });
|
||||||
|
}
|
||||||
|
|
||||||
runtime.comm_locked != prev_comm
|
runtime.comm_locked != prev_comm
|
||||||
|| runtime.flt_active != prev_flt
|
|| runtime.flt_active != prev_flt
|
||||||
|
|
|
||||||
27
src/event.rs
27
src/event.rs
|
|
@ -41,6 +41,8 @@ pub enum AppEvent {
|
||||||
FaultAcked { unit_id: Uuid },
|
FaultAcked { unit_id: Uuid },
|
||||||
CommLocked { unit_id: Uuid },
|
CommLocked { unit_id: Uuid },
|
||||||
CommRecovered { unit_id: Uuid },
|
CommRecovered { unit_id: Uuid },
|
||||||
|
RemLocal { unit_id: Uuid, equipment_id: Uuid },
|
||||||
|
RemRecovered { unit_id: Uuid },
|
||||||
UnitStateChanged { unit_id: Uuid, from_state: String, to_state: String },
|
UnitStateChanged { unit_id: Uuid, from_state: String, to_state: String },
|
||||||
PointNewValue(crate::telemetry::PointNewValue),
|
PointNewValue(crate::telemetry::PointNewValue),
|
||||||
}
|
}
|
||||||
|
|
@ -245,6 +247,12 @@ async fn handle_control_event(
|
||||||
AppEvent::CommRecovered { unit_id } => {
|
AppEvent::CommRecovered { unit_id } => {
|
||||||
tracing::info!("Comm recovered for unit {}", unit_id);
|
tracing::info!("Comm recovered for unit {}", unit_id);
|
||||||
}
|
}
|
||||||
|
AppEvent::RemLocal { unit_id, equipment_id } => {
|
||||||
|
tracing::warn!("REM local: unit={}, equipment={}", unit_id, equipment_id);
|
||||||
|
}
|
||||||
|
AppEvent::RemRecovered { unit_id } => {
|
||||||
|
tracing::info!("REM recovered for unit {}", unit_id);
|
||||||
|
}
|
||||||
AppEvent::UnitStateChanged { unit_id, from_state, to_state } => {
|
AppEvent::UnitStateChanged { unit_id, from_state, to_state } => {
|
||||||
tracing::info!("Unit {} state: {} → {}", unit_id, from_state, to_state);
|
tracing::info!("Unit {} state: {} → {}", unit_id, from_state, to_state);
|
||||||
}
|
}
|
||||||
|
|
@ -413,6 +421,25 @@ async fn persist_event_if_needed(
|
||||||
serde_json::json!({ "unit_id": unit_id }),
|
serde_json::json!({ "unit_id": unit_id }),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
AppEvent::RemLocal { unit_id, equipment_id } => {
|
||||||
|
let unit_code = fetch_unit_code(pool, *unit_id).await;
|
||||||
|
let eq_code = fetch_equipment_code(pool, *equipment_id).await;
|
||||||
|
Some((
|
||||||
|
"unit.rem_local", "warn",
|
||||||
|
Some(*unit_id), Some(*equipment_id), None,
|
||||||
|
format!("单元【{}】切换为本地控制,触发设备:{},自动控制已停止", unit_code, eq_code),
|
||||||
|
serde_json::json!({ "unit_id": unit_id, "equipment_id": equipment_id }),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
AppEvent::RemRecovered { unit_id } => {
|
||||||
|
let code = fetch_unit_code(pool, *unit_id).await;
|
||||||
|
Some((
|
||||||
|
"unit.rem_recovered", "info",
|
||||||
|
Some(*unit_id), None, None,
|
||||||
|
format!("单元【{}】已切换回远程控制", code),
|
||||||
|
serde_json::json!({ "unit_id": unit_id }),
|
||||||
|
))
|
||||||
|
}
|
||||||
AppEvent::UnitStateChanged { .. } => None,
|
AppEvent::UnitStateChanged { .. } => None,
|
||||||
AppEvent::PointNewValue(_) => None,
|
AppEvent::PointNewValue(_) => None,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue