Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
555 changes: 555 additions & 0 deletions agentic_chatbot.py

Large diffs are not rendered by default.

1,902 changes: 1,902 additions & 0 deletions agentic_tools.py

Large diffs are not rendered by default.

25 changes: 24 additions & 1 deletion core/power_system.py
Original file line number Diff line number Diff line change
Expand Up @@ -525,6 +525,12 @@ def _analyze_power_flow_results(self) -> PowerFlowResult:
# Get line flows
line_flows = self.network.lines_t.p0.iloc[0]
line_limits = self.network.lines.s_nom

# Align indices to ensure safe arithmetic
common_idx = line_flows.index.intersection(line_limits.index)
line_flows = line_flows.loc[common_idx]
line_limits = line_limits.loc[common_idx]

line_loading = abs(line_flows) / line_limits

# Find violations
Expand Down Expand Up @@ -836,6 +842,11 @@ def _store_network_state(self):
import json

try:
# Guard: Check if db_manager and get_session are available
if not hasattr(db_manager, 'get_session') or not callable(getattr(db_manager, 'get_session', None)):
# Database not configured - skip storage (this is optional for simulation)
return

with db_manager.get_session() as session:
state = NetworkState(
simulation_time=int(self.network.snapshots[0].timestamp()),
Expand All @@ -859,7 +870,8 @@ def _store_network_state(self):
session.commit()

except Exception as e:
logger.error(f"Failed to store network state: {e}")
# Don't spam logs - database storage is optional for demo
pass
def _calculate_health_score(self) -> float:
"""Calculate overall system health score (0-100)"""

Expand All @@ -880,6 +892,12 @@ def _calculate_health_score(self) -> float:
# Deduct for overloaded lines
line_flows = abs(self.network.lines_t.p0.iloc[0])
line_limits = self.network.lines.s_nom

# Align indices
common_idx = line_flows.index.intersection(line_limits.index)
line_flows = line_flows.loc[common_idx]
line_limits = line_limits.loc[common_idx]

overloads = (line_flows > line_limits).sum()
score -= overloads * 10

Expand All @@ -889,6 +907,11 @@ def _log_incident(self, impact: Dict[str, Any]):
"""Log incident to database"""

try:
# Guard: Check if db_manager and get_session are available
if not hasattr(db_manager, 'get_session') or not callable(getattr(db_manager, 'get_session', None)):
# Database not configured - skip logging (this is optional for simulation)
return

with db_manager.get_session() as session:
from config.database import Incident

Expand Down
73 changes: 73 additions & 0 deletions enhanced_v2g_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,38 @@ def _initialize_demo_vehicles(self):

print(f"[V2G] Initialized {len(self.vehicles)} vehicles, {self.total_v2g_capacity_kw:.1f}kW V2G capacity")

def enable_v2g_for_substation(self, substation_name: str) -> bool:
"""Enable V2G support for a specific substation (Chatbot hook)"""
print(f"[V2G] Enabling V2G for {substation_name}")

# 1. Activate all vehicles in the area
count = 0
capacity = 0

# Simple proximity check or just activate all for demo
for vehicle in self.vehicles.values():
# In a real system, we'd check location. For demo, if they are in the zone:
if vehicle.location.lower() in substation_name.lower().replace("_", " "):
vehicle.v2g_enabled = True
count += 1
capacity += vehicle.discharge_rate_kw

# Create transaction
if vehicle.vehicle_id not in self.active_transactions:
tx = V2GTransaction(
transaction_id=f"ACT_{vehicle.vehicle_id}_{int(time.time())}",
vehicle_id=vehicle.vehicle_id,
energy_amount_kwh=0,
transaction_type="activation",
price_per_kwh=0.15,
timestamp=datetime.now(),
grid_benefit=0
)
self.active_transactions[tx.transaction_id] = tx

print(f"[V2G] Activated {count} vehicles for {substation_name}, +{capacity:.1f}kW")
return True

def activate_all_vehicles(self) -> Dict[str, Any]:
"""Actually activate V2G for all eligible vehicles"""

Expand Down Expand Up @@ -238,6 +270,10 @@ def get_v2g_status(self) -> Dict[str, Any]:
'recent_transactions': list(self.active_transactions.values())[-5:] if self.active_transactions else []
}

def get_v2g_dashboard_data(self) -> Dict[str, Any]:
"""Alias for compatibility with main integration loop"""
return self.get_v2g_status()

def optimize_charging_schedule(self) -> Dict[str, Any]:
"""Optimize V2G charging/discharging schedule based on grid needs"""

Expand Down Expand Up @@ -286,6 +322,43 @@ def optimize_charging_schedule(self) -> Dict[str, Any]:
'schedule': optimization_plan
}

def update_v2g_sessions(self):
"""Update V2G sessions with REALISTIC FAST DISCHARGE (Ported from standard manager)"""

# If no active sessions, nothing to do
if not self.active_transactions:
return

# Simple update loop for efficiency
sessions_to_end = []

for tx_id, transaction in self.active_transactions.items():
if transaction.transaction_type != 'discharge':
continue

vehicle = self.vehicles.get(transaction.vehicle_id)
if not vehicle:
continue

# Discharge rate per step (assuming ~1 second per call for now, can refine)
discharge_amount = (vehicle.discharge_rate_kw / 3600) * 1.0 # 1 second of discharge

# Check battery
if vehicle.current_charge_kwh <= (vehicle.battery_capacity_kwh * 0.10): # 10% limit
sessions_to_end.append(tx_id)
continue

# Update state
vehicle.current_charge_kwh -= discharge_amount
transaction.energy_amount_kwh += discharge_amount
self.total_v2g_capacity_kw += vehicle.discharge_rate_kw # Keep tracking capacity

# Clean up ended sessions
for tx_id in sessions_to_end:
# Archive or just remove for now
if tx_id in self.active_transactions:
del self.active_transactions[tx_id]

def initialize_enhanced_v2g(integrated_system) -> Optional[EnhancedV2GManager]:
"""Initialize the enhanced V2G manager"""

Expand Down
63 changes: 43 additions & 20 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
<!-- Mapbox GL JS -->
<link href="https://api.mapbox.com/mapbox-gl-js/v2.15.0/mapbox-gl.css" rel="stylesheet">
<script src="https://api.mapbox.com/mapbox-gl-js/v2.15.0/mapbox-gl.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.1/socket.io.js"></script>

<!-- Typography -->
<link rel="preconnect" href="https://fonts.googleapis.com">
Expand All @@ -19,8 +20,8 @@
<script src="https://cdn.jsdelivr.net/npm/dompurify@3.0.8/dist/purify.min.js"></script>

<!-- Custom Styles -->
<link href="/static/styles.css" rel="stylesheet">
<link href="/static/chatbot-enhanced-ui.css" rel="stylesheet">
<link href="/static/styles.css?v=nocache_1769983928" rel="stylesheet">
<link href="/static/chatbot-enhanced-ui.css?v=nocache_1769983928" rel="stylesheet">
</head>
<body data-tab="overview">
<!-- Advanced Background Effects -->
Expand Down Expand Up @@ -95,6 +96,18 @@
<h1>Manhattan Power Grid</h1>
<div class="subtitle">Advanced Operations & Real-time Analytics</div>

<!-- Quick Tools - Always Visible -->
<div class="tools-section" style="margin-bottom: 16px;">
<div class="btn-group" style="display: flex; gap: 8px;">
<button class="btn btn-secondary" onclick="captureSnapshot()" style="flex: 1; display: flex; align-items: center; justify-content: center; gap: 6px;">
<span style="font-size: 16px;">πŸ“Έ</span> Snapshot
</button>
<button class="btn btn-secondary" onclick="generateReport()" style="flex: 1; display: flex; align-items: center; justify-content: center; gap: 6px;">
<span style="font-size: 16px;">πŸ“„</span> Report
</button>
</div>
</div>

<!-- Main Statistics -->
<div id="section-stats" class="stats-grid tab tab-overview">
<div class="stat-card">
Expand Down Expand Up @@ -361,7 +374,7 @@ <h4 style="color:var(--text-secondary);margin-bottom:12px;font-size:14px;font-we
<!-- V2G Controls -->
<div class="btn-group" style="margin-top:16px;">
<button class="btn btn-secondary" onclick="testV2G()">πŸ§ͺ Test V2G</button>
<button class="btn btn-secondary" onclick="updateV2GDashboard()">πŸ”„ Refresh</button>
<button class="btn btn-secondary" onclick="refreshV2GDashboard()">πŸ”„ Refresh</button>
</div>
</div>

Expand Down Expand Up @@ -413,7 +426,7 @@ <h4 style="color:var(--text-secondary);margin-bottom:12px;font-size:14px;font-we
<div class="layer-item">
<span>13.8kV Cables</span>
<label class="toggle">
<input type="checkbox" id="layer-primary" onchange="toggleLayer('primary')">
<input type="checkbox" checked id="layer-primary" onchange="toggleLayer('primary')">
<span class="slider"></span>
</label>
</div>
Expand Down Expand Up @@ -465,6 +478,11 @@ <h4 style="color:var(--text-secondary);margin-bottom:12px;font-size:14px;font-we
<div class="status-item">
🌑️ <span id="temperature">72</span>°F
</div>
<div class="status-item sync-monitor" id="syncMonitor" title="SUMO ↔ PyPSA Synchronization">
<div class="sync-dot"></div>
<span class="sync-label">SYNC</span>
<span class="sync-value" id="syncStatus">Idle</span>
</div>
</div>

<!-- Blackout Alert -->
Expand All @@ -477,8 +495,11 @@ <h4 style="color:var(--text-secondary);margin-bottom:12px;font-size:14px;font-we
</div>

<!-- Premium Legend -->
<div class="legend">
<div class="legend-title">System Components</div>
<div class="legend collapsed" id="system-legend">
<div class="legend-header" onclick="toggleLegend()">
<div class="legend-title">System Components</div>
<button class="legend-toggle" id="legend-toggle-btn">β–Ά</button>
</div>
<div class="legend-grid">
<div style="font-size: 11px; color: var(--text-muted); text-transform: uppercase; letter-spacing: 1px; margin-bottom: 8px;">Infrastructure</div>
<div class="legend-row">
Expand All @@ -501,28 +522,28 @@ <h4 style="color:var(--text-secondary);margin-bottom:12px;font-size:14px;font-we
</div>
<div style="font-size: 11px; color: var(--text-muted); margin-top: 12px; text-transform: uppercase; letter-spacing: 1px;">Vehicles</div>
<div class="legend-row">
<span class="legend-car" style="color:#00ff00;">
<span class="legend-car" style="color:#00FFD4;">
<svg viewBox="0 0 22 14"><rect x="1" y="2" rx="2" ry="2" width="20" height="10"/></svg>
</span>
<span>EV High 40%+</span>
<span id="legend-ev-high" class="badge">0</span>
</div>
<div class="legend-row">
<span class="legend-car" style="color:#ffaa00;">
<span class="legend-car" style="color:#4488FF;">
<svg viewBox="0 0 22 14"><rect x="1" y="2" rx="2" ry="2" width="20" height="10"/></svg>
</span>
<span>EV Medium 20-40%</span>
<span id="legend-ev-medium" class="badge">0</span>
</div>
<div class="legend-row">
<span class="legend-car" style="color:#ff0000;">
<span class="legend-car" style="color:#FF44AA;">
<svg viewBox="0 0 22 14"><rect x="1" y="2" rx="2" ry="2" width="20" height="10"/></svg>
</span>
<span>EV Low 2-20%</span>
<span id="legend-ev-low" class="badge">0</span>
</div>
<div class="legend-row">
<span class="legend-car" style="color:#6464ff;">
<span class="legend-car" style="color:#8899AA;">
<svg viewBox="0 0 22 14"><rect x="1" y="2" rx="2" ry="2" width="20" height="10"/></svg>
</span>
<span>Gas Vehicle</span>
Expand All @@ -531,18 +552,20 @@ <h4 style="color:var(--text-secondary);margin-bottom:12px;font-size:14px;font-we
</div>
</div>



<!-- Custom JavaScript -->
<script src="/static/script.js"></script>
<script src="/static/ai-enhanced.js"></script>
<script src="/static/ai-functions.js"></script>
<script src="/static/world-class-map.js"></script>
<script src="/static/scenario-director.js"></script>
<script src="/static/chatbot-scenarios.js"></script>
<script src="/static/script.js?v=nocache_1771265000"></script>
<script src="/static/ai-enhanced.js?v=nocache_1771265000"></script>
<script src="/static/ai-functions.js?v=nocache_1771265000"></script>
<script src="/static/world-class-map.js?v=nocache_1771265000"></script>
<script src="/static/scenario-director.js?v=nocache_1771265000"></script>
<script src="/static/chatbot-scenarios.js?v=nocache_1771265000"></script>

<!-- Scenario Controller -->
<script src="/static/traffic-patterns.js"></script>
<script src="/static/time-vehicle-manager.js"></script>
<script src="/static/scenario-controls.js"></script>
<script src="/static/chatbot-scenario-llm.js"></script>
<script src="/static/traffic-patterns.js?v=nocache_1771265000"></script>
<script src="/static/time-vehicle-manager.js?v=nocache_1771265000"></script>
<script src="/static/scenario-controls.js?v=nocache_1771265000"></script>
<script src="/static/chatbot-scenario-llm.js?v=nocache_1771265000"></script>
</body>
</html>
Loading