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>
- Add `rem_local: bool` to UnitRuntime; set true when any equipment's
REM signal is false with good quality
- Engine check_fault_comm: stop auto-control and fire AutoControlStopped
when any equipment switches to local mode
- Block start-auto when rem_local (backend + error message)
- Frontend: disable Start Auto button in units/ops views when rem_local
- Frontend: disable equipment Start/Stop buttons in config view when
unit's rem_local is true
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Prevent starting unit auto control while fault_locked or manual_ack_required,
enforcing that faults must be manually acknowledged before resuming automation.
Also disable the Start Auto button in the frontend with descriptive tooltips.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Moved simulate_run_feedback from command.rs into simulate.rs where it
reuses patch_signal. command.rs now only contains real PLC command logic.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- engine.rs: replace HashSet<Uuid> with HashMap<Uuid, JoinHandle> in
supervise(); use is_finished() to detect exited tasks so units that
are disabled then re-enabled get a new task on next 10s scan
- control/mod.rs: extract shared monitor_value_as_bool (using the more
complete validator version that includes "yes"); remove duplicate
copies from engine.rs and validator.rs
- runtime.rs: fix get_or_create_notify TOCTOU by using entry API
instead of read-drop-write pattern
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When auto_enabled or fault_locked changes externally, the engine task
wakes via notify but previously only pushed WS on the next state
transition (potentially seconds later). Now push the fresh runtime
immediately in the notify.notified() arm so the frontend reflects
the change without delay.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Engine now spawns one async task per enabled unit (supervised every 10s)
- wait_phase uses sleep_until + select! for precise timing; 500ms fault-tick
runs inside each phase so fault/comm is still checked promptly
- WS UnitRuntimeChanged pushed only on state transitions, not every tick
- ControlRuntimeStore gains notify_unit/get_or_create_notify for instant
wake-up when handlers change auto_enabled or fault_locked
- UnitRuntime: remove last_tick_at, current_run/stop/distributor_elapsed_sec;
add display_acc_sec (snapshot at transition, avoids mid-cycle jitter)
- accumulated_run_sec now increments by exact run_time_sec*1000 per cycle
- unit.state_changed events no longer written to DB (too frequent)
- Frontend: show display_acc_sec instead of accumulated_run_sec
- styles: event-card flex-shrink:0 fixes text overlap under flex column
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When accumulated_run_sec reaches acc_time_sec, the coal feeder must be stopped
before entering DistributorRunning state. Previously the feeder was left running
while the distributor also ran, which is incorrect per the control spec.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- validator: reject equipment start/stop when unit auto_enabled
- engine: fix stop_time_sec==0 causing infinite Stopped state (never starts)
- engine: call simulate_run_feedback after auto commands when SIMULATE_PLC=true
- command: extract simulate_run_feedback to shared module (was private in handler)
- web: disable Start/Stop buttons when unit auto is active; sync on WS runtime update
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>