import streamlit as st import pandas as pd import numpy as np import plotly.graph_objects as go import time # --- CONFIGURATION --- st.set_page_config(page_title="Veritas SCADA Simulator", layout="wide") # --- SIDEBAR (Compliance) --- st.sidebar.image("https://img.icons8.com/color/96/000000/shield.png", width=50) st.sidebar.header("🛡️ Veritas Sentinel") st.sidebar.markdown("**System Status:** ✅ ONLINE") st.sidebar.markdown("---") st.sidebar.subheader("NIST AI RMF Controls") st.sidebar.checkbox("Map-1.3: Asset Inventory", value=True) st.sidebar.checkbox("Manage-2.4: Incident Response", value=True) st.sidebar.checkbox("Gov-3.1: Human Oversight", value=True) # --- MAIN DASHBOARD --- st.title("🌊 Water Treatment Plant #4 - SCADA Monitor") st.markdown("Real-time telemetry monitoring for **Cyber-Physical Anomalies**.") # --- SIMULATION LOGIC --- # Create placeholders for the live graph placeholder = st.empty() alert_box = st.empty() # Button to trigger "Attack" if st.button('⚠️ SIMULATE RANSOMWARE ATTACK'): attack_mode = True else: attack_mode = False # Generate Data seconds = 0 data = [] # --- LIVE LOOP (Simulated) --- # In a real app, this would run indefinitely. For the demo, we show a snapshot. for i in range(50): seconds += 1 # Normal Pressure is 60-80 PSI. Attack spikes to 150 PSI. if attack_mode and i > 25: pressure = np.random.randint(140, 160) status_color = "red" alert_box.error("🚨 CRITICAL ALERT: PLC CONTROL FAILURE DETECTED. MANUAL OVERRIDE REQUIRED.") else: pressure = np.random.randint(60, 80) status_color = "#00ff00" # Neon Green if not attack_mode: alert_box.success("System Normal. AI Governance Active.") data.append(pressure) # Draw Graph fig = go.Figure() fig.add_trace(go.Scatter(y=data, mode='lines+markers', line=dict(color=status_color, width=3))) fig.update_layout( title="Main Pump Discharge Pressure (PSI)", yaxis_range=[0, 200], template="plotly_dark", height=400 ) placeholder.plotly_chart(fig, use_container_width=True) time.sleep(0.1)