- 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>
After a successful start/stop command, write run=true/false directly
into the point monitor cache and broadcast PointNewValue via WebSocket.
Gated by SIMULATE_PLC=true env var; real OPC-UA values override it.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add 运维/配置 tab switch; grid-ops / grid-config layout classes
- New ops-panel: unit sidebar + equipment card grid (REM/RUN/FLT signals)
- All equipment cards shown by default; unit click acts as filter
- Signal cells seed from point_monitor cache on render, then update via WS PointNewValue
- New log-stream-panel: SSE realtime log stream, active only in config view
- Backend: get_unit_detail now includes point_monitor (current value) in each point
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Returns unit with its equipments, each embedding their bound points.
Uses 2 queries (equipment list + points via ANY) to avoid N+1.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Prevents browser from caching JS/CSS modules, so frontend changes take
effect immediately on page refresh without needing hard refresh.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Remove the special-case that silently ignored BadTimeout in the
subscription status callback. BadTimeout means the server has already
dropped the subscription, so reconnect must be triggered immediately
rather than waiting for the heartbeat check.
Also reduce lifetime_count (120→15) and max_keep_alive_count (10→5)
so failures are detected within 15s instead of 120s, while still
satisfying the OPC UA spec requirement of lifetime >= 3×keepalive.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Clarify event semantics by renaming ReloadEvent to AppEvent and route control vs telemetry traffic through dedicated channels. This keeps control events isolated from high-frequency PointNewValue updates while preserving the existing send() call pattern.
Made-with: Cursor
Always clear reconnect-in-progress markers after reconnect attempts so heartbeat-triggered retries are not blocked. Reduce high-frequency event overhead by coalescing consecutive point updates in the event worker and processing only the latest value per source/client handle.
Made-with: Cursor
Improve runtime resilience by bounding the reload event queue and processing telemetry updates without per-point spawned tasks. Also reduce security risk by sanitizing source responses, avoiding internal error detail leaks, and standardizing write-key configuration with backward compatibility.
Made-with: Cursor