setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); } catch (PDOException $e) { if (isset($_POST['action'])) { header('Content-Type: application/json'); echo json_encode(['success' => false, 'error' => 'Database connection failed: ' . $e->getMessage()]); exit; } die("Connection failed: " . $e->getMessage()); } // Handle AJAX requests if (isset($_POST['action'])) { // Clear any previous output and set proper headers while (ob_get_level()) { ob_end_clean(); } ob_start(); header('Content-Type: application/json'); try { switch ($_POST['action']) { case 'get_tags': $stmt = $pdo->prepare("SELECT DISTINCT name FROM id_names WHERE name IS NOT NULL AND name != '' ORDER BY name"); $stmt->execute(); $tags = $stmt->fetchAll(PDO::FETCH_COLUMN); echo json_encode(['success' => true, 'tags' => $tags]); break; case 'get_recent_data': $selectedTagsJson = $_POST['tags'] ?? '[]'; $selectedTags = is_string($selectedTagsJson) ? json_decode($selectedTagsJson, true) : $selectedTagsJson; $hours = (int)($_POST['hours'] ?? 24); if (empty($selectedTags) || !is_array($selectedTags)) { throw new Exception('No tags selected'); } $placeholders = str_repeat('?,', count($selectedTags) - 1) . '?'; $sql = "SELECT h.TimeStamp, n.name as tag_name, h.Value FROM historicaldata h INNER JOIN id_names n ON h.ID = n.idnumber WHERE n.name IN ($placeholders) AND h.TimeStamp >= DATE_SUB(NOW(), INTERVAL ? HOUR) ORDER BY h.TimeStamp DESC, n.name ASC LIMIT 10000"; $params = array_merge($selectedTags, [$hours]); $stmt = $pdo->prepare($sql); $stmt->execute($params); $results = $stmt->fetchAll(PDO::FETCH_ASSOC); echo json_encode([ 'success' => true, 'data' => $results, 'count' => count($results) ]); break; case 'analyze_anomalies': $selectedTagsJson = $_POST['tags'] ?? '[]'; $selectedTags = is_string($selectedTagsJson) ? json_decode($selectedTagsJson, true) : $selectedTagsJson; $sensitivity = (float)($_POST['sensitivity'] ?? 2.0); $lookbackHours = (int)($_POST['lookback_hours'] ?? 168); $analysisHours = (int)($_POST['analysis_hours'] ?? 24); if (empty($selectedTags) || !is_array($selectedTags)) { throw new Exception('No tags selected'); } $anomalies = []; foreach ($selectedTags as $tagName) { // Get historical baseline data (excluding recent analysis period) $baselineStmt = $pdo->prepare(" SELECT h.Value FROM historicaldata h INNER JOIN id_names n ON h.ID = n.idnumber WHERE n.name = ? AND h.TimeStamp >= DATE_SUB(NOW(), INTERVAL ? HOUR) AND h.TimeStamp < DATE_SUB(NOW(), INTERVAL ? HOUR) AND h.Value IS NOT NULL ORDER BY h.TimeStamp ASC "); $baselineStmt->execute([$tagName, $lookbackHours, $analysisHours]); $baselineData = $baselineStmt->fetchAll(PDO::FETCH_COLUMN); // Get recent data for analysis $recentStmt = $pdo->prepare(" SELECT h.Value, h.TimeStamp FROM historicaldata h INNER JOIN id_names n ON h.ID = n.idnumber WHERE n.name = ? AND h.TimeStamp >= DATE_SUB(NOW(), INTERVAL ? HOUR) AND h.Value IS NOT NULL ORDER BY h.TimeStamp ASC "); $recentStmt->execute([$tagName, $analysisHours]); $recentResults = $recentStmt->fetchAll(PDO::FETCH_ASSOC); if (count($baselineData) < 10 || count($recentResults) < 5) { continue; // Skip if insufficient data } // Convert baseline data to floats $baselineValues = array_map('floatval', $baselineData); // Calculate statistical baseline $mean = array_sum($baselineValues) / count($baselineValues); // Calculate standard deviation $variance = 0; foreach ($baselineValues as $value) { $variance += pow($value - $mean, 2); } $stdDev = sqrt($variance / (count($baselineValues) - 1)); // Sample standard deviation // Skip if standard deviation is too small (constant values) if ($stdDev < 0.001) { continue; } $upperThreshold = $mean + ($sensitivity * $stdDev); $lowerThreshold = $mean - ($sensitivity * $stdDev); // Check recent values for anomalies foreach ($recentResults as $point) { $value = (float)$point['Value']; $timestamp = $point['TimeStamp']; if ($value > $upperThreshold || $value < $lowerThreshold) { $deviation = abs($value - $mean) / $stdDev; // Determine severity based on deviation $severity = 'medium'; if ($deviation > $sensitivity * 2) { $severity = 'critical'; } elseif ($deviation > $sensitivity * 1.5) { $severity = 'high'; } $anomalies[] = [ 'tag_name' => $tagName, 'timestamp' => $timestamp, 'value' => $value, 'expected_range' => [$lowerThreshold, $upperThreshold], 'baseline_mean' => $mean, 'baseline_stddev' => $stdDev, 'deviation_factor' => $deviation, 'severity' => $severity, 'message' => sprintf( 'Value %.2f is %.1f standard deviations from normal (%.2f ± %.2f)', $value, $deviation, $mean, $stdDev ) ]; } } } // Sort anomalies by severity and timestamp usort($anomalies, function($a, $b) { $severityOrder = ['low' => 1, 'medium' => 2, 'high' => 3, 'critical' => 4]; $severityDiff = ($severityOrder[$b['severity']] ?? 2) - ($severityOrder[$a['severity']] ?? 2); if ($severityDiff !== 0) return $severityDiff; return strtotime($b['timestamp']) - strtotime($a['timestamp']); }); echo json_encode([ 'success' => true, 'anomalies' => $anomalies, 'analysis_summary' => [ 'total_anomalies' => count($anomalies), 'critical_count' => count(array_filter($anomalies, function($a) { return $a['severity'] === 'critical'; })), 'high_count' => count(array_filter($anomalies, function($a) { return $a['severity'] === 'high'; })), 'medium_count' => count(array_filter($anomalies, function($a) { return $a['severity'] === 'medium'; })), 'analysis_period' => $analysisHours . ' hours', 'baseline_period' => $lookbackHours . ' hours', 'sensitivity_level' => $sensitivity ] ]); break; case 'get_tag_statistics': $tagName = $_POST['tag_name'] ?? ''; $hours = (int)($_POST['hours'] ?? 168); if (empty($tagName)) { throw new Exception('No tag specified'); } $stmt = $pdo->prepare(" SELECT COUNT(*) as data_points, AVG(h.Value) as mean_value, STDDEV(h.Value) as std_deviation, MIN(h.Value) as min_value, MAX(h.Value) as max_value, VARIANCE(h.Value) as variance FROM historicaldata h INNER JOIN id_names n ON h.ID = n.idnumber WHERE n.name = ? AND h.TimeStamp >= DATE_SUB(NOW(), INTERVAL ? HOUR) AND h.Value IS NOT NULL "); $stmt->execute([$tagName, $hours]); $stats = $stmt->fetch(PDO::FETCH_ASSOC); echo json_encode([ 'success' => true, 'statistics' => $stats, 'tag_name' => $tagName, 'analysis_period' => $hours . ' hours' ]); break; default: throw new Exception('Invalid action specified'); } } catch (Exception $e) { echo json_encode(['success' => false, 'error' => $e->getMessage()]); } catch (Error $e) { echo json_encode(['success' => false, 'error' => 'PHP Error: ' . $e->getMessage()]); } ob_end_flush(); exit; } ?> LASUCA Controls - Anomaly Detection Dashboard

🚨 LASUCA Controls - Anomaly Detection Dashboard

Real-Time Equipment Monitoring & Predictive Analytics

🔧 Analysis Configuration

🏷️ Monitor Tags

Loading available tags...

⚙️ Detection Settings

🔄 Real-Time Monitoring

Never