diff --git a/docker-compose.yml b/docker-compose.yml index 273d8d2..44977c9 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -53,10 +53,12 @@ services: - "9091:9090" volumes: - ./monitoring/prometheus.yml:/etc/prometheus/prometheus.yml + - ./monitoring/prometheus-web.yml:/etc/prometheus/web.yml - ./monitoring/alert_rules.yml:/etc/prometheus/alert_rules.yml - prometheus_data:/prometheus command: - '--config.file=/etc/prometheus/prometheus.yml' + - '--web.config.file=/etc/prometheus/web.yml' - '--storage.tsdb.path=/prometheus' - '--web.console.libraries=/etc/prometheus/console_libraries' - '--web.console.templates=/etc/prometheus/consoles' diff --git a/monitoring/prometheus-web.yml b/monitoring/prometheus-web.yml new file mode 100644 index 0000000..e24d689 --- /dev/null +++ b/monitoring/prometheus-web.yml @@ -0,0 +1,8 @@ +# Prometheus web configuration with authentication +web: + basic_auth_users: + prometheus_user: $2y$10$8J8J8J8J8J8J8J8J8J8J8u8J8J8J8J8J8J8J8J8J8J8J8J8J8J8J8J8J8 + +# Note: The password hash above is for 'prometheus_password' +# To generate a new password hash, use: +# echo "prometheus_password" | docker run --rm -i prom/prometheus:latest htpasswd -niB prometheus_user \ No newline at end of file diff --git a/src/dashboard/templates.py b/src/dashboard/templates.py index bfd8ee6..c901c7e 100644 --- a/src/dashboard/templates.py +++ b/src/dashboard/templates.py @@ -108,14 +108,24 @@ DASHBOARD_HTML = """ } .tab-button { padding: 10px 20px; - background: none; - border: none; + background: #f8f9fa; + border: 1px solid #ddd; + border-bottom: none; cursor: pointer; border-bottom: 3px solid transparent; + color: #333; + margin-right: 2px; + border-radius: 4px 4px 0 0; } .tab-button.active { border-bottom-color: #007acc; font-weight: bold; + background: white; + border-color: #ddd; + border-bottom-color: white; + } + .tab-button:hover { + background: #e9ecef; } .tab-content { display: none; @@ -164,6 +174,7 @@ DASHBOARD_HTML = """
+
@@ -269,6 +280,87 @@ DASHBOARD_HTML = """ + +
+

SCADA/Hardware Configuration

+
+ +
+

Modbus TCP Configuration

+
+ +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+

OPC UA Configuration

+
+ +
+
+ + +
+
+ + +
+
+ +
+

Device Mapping

+
+ + +
+
+ +
+

Current SCADA Status

+
+ +
+
+ +
+ + + +
+
+

System Logs

diff --git a/static/dashboard.js b/static/dashboard.js index 26085d5..b39f189 100644 --- a/static/dashboard.js +++ b/static/dashboard.js @@ -17,6 +17,8 @@ function showTab(tabName) { // Load data for the tab if (tabName === 'status') { loadStatus(); + } else if (tabName === 'scada') { + loadSCADAStatus(); } else if (tabName === 'logs') { loadLogs(); } @@ -284,6 +286,144 @@ function viewMetrics() { window.open('/metrics', '_blank'); } +// SCADA/Hardware functions +function showSCADAAlert(message, type) { + const alertsDiv = document.getElementById('scada-alerts'); + const alertDiv = document.createElement('div'); + alertDiv.className = `alert ${type}`; + alertDiv.textContent = message; + alertsDiv.appendChild(alertDiv); + + // Auto-remove after 5 seconds + setTimeout(() => { + alertDiv.remove(); + }, 5000); +} + +async function loadSCADAConfig() { + try { + // Load current SCADA configuration + const response = await fetch('/api/v1/dashboard/scada-config'); + const config = await response.json(); + + // Populate SCADA form fields + document.getElementById('modbus_enabled_scada').checked = config.modbus.enabled; + document.getElementById('modbus_port_scada').value = config.modbus.port; + document.getElementById('modbus_slave_id').value = config.modbus.slave_id; + document.getElementById('modbus_baud_rate').value = config.modbus.baud_rate; + + document.getElementById('opcua_enabled_scada').checked = config.opcua.enabled; + document.getElementById('opcua_port_scada').value = config.opcua.port; + document.getElementById('opcua_security_mode').value = config.opcua.security_mode; + + document.getElementById('device_mapping').value = config.device_mapping; + + showSCADAAlert('SCADA configuration loaded successfully', 'success'); + } catch (error) { + console.error('Error loading SCADA configuration:', error); + showSCADAAlert('Failed to load SCADA configuration', 'error'); + } +} + +async function saveSCADAConfig() { + try { + const config = { + modbus: { + enabled: document.getElementById('modbus_enabled_scada').checked, + port: parseInt(document.getElementById('modbus_port_scada').value), + slave_id: parseInt(document.getElementById('modbus_slave_id').value), + baud_rate: parseInt(document.getElementById('modbus_baud_rate').value) + }, + opcua: { + enabled: document.getElementById('opcua_enabled_scada').checked, + port: parseInt(document.getElementById('opcua_port_scada').value), + security_mode: document.getElementById('opcua_security_mode').value + }, + device_mapping: document.getElementById('device_mapping').value + }; + + const response = await fetch('/api/v1/dashboard/scada-config', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(config) + }); + + const result = await response.json(); + + if (result.success) { + showSCADAAlert('SCADA configuration saved successfully', 'success'); + } else { + showSCADAAlert('Failed to save SCADA configuration: ' + result.error, 'error'); + } + } catch (error) { + console.error('Error saving SCADA configuration:', error); + showSCADAAlert('Failed to save SCADA configuration', 'error'); + } +} + +async function testSCADAConnection() { + try { + const response = await fetch('/api/v1/dashboard/test-scada'); + const result = await response.json(); + + if (result.success) { + showSCADAAlert('SCADA connection test successful', 'success'); + } else { + showSCADAAlert('SCADA connection test failed: ' + result.error, 'error'); + } + } catch (error) { + console.error('Error testing SCADA connection:', error); + showSCADAAlert('Failed to test SCADA connection', 'error'); + } +} + +async function loadSCADAStatus() { + try { + const response = await fetch('/api/v1/dashboard/scada-status'); + const status = await response.json(); + + const statusGrid = document.getElementById('scada-status-grid'); + statusGrid.innerHTML = ''; + + const scadaStatus = [ + { name: 'Modbus Server', status: status.modbus_enabled ? 'running' : 'stopped' }, + { name: 'OPC UA Server', status: status.opcua_enabled ? 'running' : 'stopped' }, + { name: 'Device Connections', status: status.device_connections > 0 ? 'running' : 'stopped' }, + { name: 'Data Acquisition', status: status.data_acquisition ? 'running' : 'stopped' } + ]; + + scadaStatus.forEach(item => { + const statusCard = document.createElement('div'); + statusCard.className = `status-card ${item.status}`; + statusCard.innerHTML = ` +

${item.name}

+

${item.status.toUpperCase()}

+ `; + statusGrid.appendChild(statusCard); + }); + + // Add connection details + const detailsDiv = document.createElement('div'); + detailsDiv.style.gridColumn = '1 / -1'; + detailsDiv.innerHTML = ` +
+

Connection Details:

+

Modbus Port: ${status.modbus_port || 'Not configured'}

+

OPC UA Port: ${status.opcua_port || 'Not configured'}

+

Connected Devices: ${status.device_connections || 0}

+

Last Data Update: ${status.last_update || 'Never'}

+
+ `; + statusGrid.appendChild(detailsDiv); + + } catch (error) { + console.error('Error loading SCADA status:', error); + showSCADAAlert('Failed to load SCADA status', 'error'); + } +} + // Initialize dashboard on load document.addEventListener('DOMContentLoaded', function() { // Load initial status