Folder reorganize 1

This commit is contained in:
Rucus
2026-02-17 12:44:37 -06:00
parent ec99d85bc2
commit f0ae0ab905
17427 changed files with 2071 additions and 1059030 deletions

309
includes/alerts.php Normal file
View File

@@ -0,0 +1,309 @@
<?php
/**
* System-wide alerts include
*
* Include this file in data pages to display conditional alerts.
* Expects $value array to be populated from items.php or shared endpoint.
*
* Usage: require __DIR__ . '/../includes/alerts.php';
*/
$alerts = [];
// ============================================================================
// Database Connection for Alerts (singleton)
// ============================================================================
function getAlertConnection() {
static $connection = null;
if ($connection === null) {
$connection = mysqli_connect('192.168.0.16', 'lasucaai', 'is413#dfslw', 'controls');
if ($connection) {
mysqli_set_charset($connection, 'utf8mb4');
// Create tables if not exists
$createLogTable = "CREATE TABLE IF NOT EXISTS alert_log (
id INT AUTO_INCREMENT PRIMARY KEY,
alert_type VARCHAR(50) NOT NULL,
alert_tag VARCHAR(100) NOT NULL,
alert_value DECIMAL(18,4) NULL,
threshold_value DECIMAL(18,4) NULL,
alert_message VARCHAR(500) NOT NULL,
source_page VARCHAR(255) NULL,
logged_at DATETIME DEFAULT CURRENT_TIMESTAMP,
INDEX idx_alert_type (alert_type),
INDEX idx_alert_tag (alert_tag),
INDEX idx_logged_at (logged_at)
)";
mysqli_query($connection, $createLogTable);
// Create throttle table to track last log time per alert
$createThrottleTable = "CREATE TABLE IF NOT EXISTS alert_throttle (
alert_key VARCHAR(150) PRIMARY KEY,
last_logged DATETIME NOT NULL,
INDEX idx_last_logged (last_logged)
)";
mysqli_query($connection, $createThrottleTable);
// Create condition state table to track duration
$createStateTable = "CREATE TABLE IF NOT EXISTS alert_condition_state (
alert_key VARCHAR(150) PRIMARY KEY,
condition_started DATETIME NOT NULL,
last_seen DATETIME NOT NULL,
INDEX idx_last_seen (last_seen)
)";
mysqli_query($connection, $createStateTable);
}
}
return $connection;
}
// ============================================================================
// Check if condition has persisted for required duration (in seconds)
// Returns true if condition has been active for >= duration seconds
// ============================================================================
function checkAlertDuration($alertKey, $conditionMet, $durationSeconds = 0) {
if ($durationSeconds <= 0) {
// No duration requirement - trigger immediately
return $conditionMet;
}
$conn = getAlertConnection();
if (!$conn) {
return $conditionMet; // Fallback to immediate if no DB
}
$now = date('Y-m-d H:i:s');
if ($conditionMet) {
// Condition is currently true - check/update state
$stmt = mysqli_prepare($conn,
"SELECT condition_started FROM alert_condition_state WHERE alert_key = ?"
);
if ($stmt) {
mysqli_stmt_bind_param($stmt, 's', $alertKey);
mysqli_stmt_execute($stmt);
$result = mysqli_stmt_get_result($stmt);
$row = mysqli_fetch_assoc($result);
mysqli_stmt_close($stmt);
if ($row) {
// Condition already being tracked - update last_seen
$updateStmt = mysqli_prepare($conn,
"UPDATE alert_condition_state SET last_seen = ? WHERE alert_key = ?"
);
if ($updateStmt) {
mysqli_stmt_bind_param($updateStmt, 'ss', $now, $alertKey);
mysqli_stmt_execute($updateStmt);
mysqli_stmt_close($updateStmt);
}
// Check if duration has been met
$started = strtotime($row['condition_started']);
$elapsed = time() - $started;
return $elapsed >= $durationSeconds;
} else {
// First time seeing this condition - start tracking
$insertStmt = mysqli_prepare($conn,
"INSERT INTO alert_condition_state (alert_key, condition_started, last_seen)
VALUES (?, ?, ?)"
);
if ($insertStmt) {
mysqli_stmt_bind_param($insertStmt, 'sss', $alertKey, $now, $now);
mysqli_stmt_execute($insertStmt);
mysqli_stmt_close($insertStmt);
}
return false; // Just started, duration not met yet
}
}
} else {
// Condition is false - clear the tracking state
$deleteStmt = mysqli_prepare($conn,
"DELETE FROM alert_condition_state WHERE alert_key = ?"
);
if ($deleteStmt) {
mysqli_stmt_bind_param($deleteStmt, 's', $alertKey);
mysqli_stmt_execute($deleteStmt);
mysqli_stmt_close($deleteStmt);
}
return false;
}
return $conditionMet;
}
// ============================================================================
// Alert Logging Function (throttled to once per minute per alert)
// ============================================================================
function logAlert($alertType, $alertTag, $alertValue, $alertMessage, $threshold = null) {
$conn = getAlertConnection();
if (!$conn) {
return;
}
try {
// Check throttle - only log once per minute per alert type+tag
$alertKey = $alertType . ':' . $alertTag;
$throttleCheck = mysqli_prepare($conn,
"SELECT last_logged FROM alert_throttle
WHERE alert_key = ? AND last_logged > DATE_SUB(NOW(), INTERVAL 1 MINUTE)"
);
if ($throttleCheck) {
mysqli_stmt_bind_param($throttleCheck, 's', $alertKey);
mysqli_stmt_execute($throttleCheck);
$result = mysqli_stmt_get_result($throttleCheck);
$recentLog = mysqli_fetch_assoc($result);
mysqli_stmt_close($throttleCheck);
if ($recentLog) {
return; // Skip - already logged within last minute
}
}
// Log the alert
$sourcePage = $_SERVER['PHP_SELF'] ?? 'unknown';
$stmt = mysqli_prepare($conn,
"INSERT INTO alert_log (alert_type, alert_tag, alert_value, threshold_value, alert_message, source_page)
VALUES (?, ?, ?, ?, ?, ?)"
);
if ($stmt) {
mysqli_stmt_bind_param($stmt, 'ssddss',
$alertType,
$alertTag,
$alertValue,
$threshold,
$alertMessage,
$sourcePage
);
mysqli_stmt_execute($stmt);
mysqli_stmt_close($stmt);
// Update throttle timestamp
$throttleUpdate = mysqli_prepare($conn,
"INSERT INTO alert_throttle (alert_key, last_logged) VALUES (?, NOW())
ON DUPLICATE KEY UPDATE last_logged = NOW()"
);
if ($throttleUpdate) {
mysqli_stmt_bind_param($throttleUpdate, 's', $alertKey);
mysqli_stmt_execute($throttleUpdate);
mysqli_stmt_close($throttleUpdate);
}
}
} catch (Exception $e) {
// Silent fail - logging should never break the page
error_log('Alert logging failed: ' . $e->getMessage());
}
}
// ============================================================================
// Alert Definitions (Now managed via alerts-admin.php)
// ============================================================================
// All alerts are now loaded from the alert_definitions table below.
// Use the admin panel at /alerts-admin.php to add, edit, or disable alerts.
// ============================================================================
// Database-Driven Alerts (from alerts-admin.php)
// ============================================================================
$alertConn = getAlertConnection();
if ($alertConn) {
$defResult = mysqli_query($alertConn,
"SELECT * FROM alert_definitions WHERE is_active = 1"
);
if ($defResult) {
while ($def = mysqli_fetch_assoc($defResult)) {
$tagName = $def['tag_name'];
$tagValue = $value[$tagName] ?? null;
if ($tagValue === null) {
continue; // Tag not found in current data
}
// Evaluate condition based on comparison operator
$conditionMet = false;
$threshold = floatval($def['threshold_value']);
switch ($def['comparison']) {
case '<':
$conditionMet = ($tagValue < $threshold);
break;
case '<=':
$conditionMet = ($tagValue <= $threshold);
break;
case '>':
$conditionMet = ($tagValue > $threshold);
break;
case '>=':
$conditionMet = ($tagValue >= $threshold);
break;
case '=':
$conditionMet = ($tagValue == $threshold);
break;
case '!=':
$conditionMet = ($tagValue != $threshold);
break;
}
// Check duration requirement
$alertKey = 'db_' . $def['id'] . '_' . $tagName;
$durationMet = checkAlertDuration($alertKey, $conditionMet, intval($def['duration_seconds']));
if ($durationMet) {
// Build message from template
$alertMessage = str_replace(
['{value}', '{threshold}', '{tag}'],
[$tagValue, $threshold, $tagName],
$def['message_template']
);
$alerts[] = [
'type' => $def['alert_type'],
'icon' => $def['icon'],
'tag' => $tagName,
'value' => $tagValue,
'threshold' => $threshold,
'display' => $def['display_alert'],
'message' => htmlspecialchars($alertMessage, ENT_QUOTES, 'UTF-8')
];
logAlert($def['alert_type'], $tagName, $tagValue, $alertMessage, $threshold);
}
}
}
}
// ============================================================================
// Render Alerts (info alerts are logged only, not displayed)
// ============================================================================
if (!empty($alerts)) {
foreach ($alerts as $alert) {
// Skip info alerts - they are logged but not displayed
if ($alert['type'] === 'info') {
continue;
}
// Skip alerts with display=0 (database-driven alerts can disable display)
if (isset($alert['display']) && !$alert['display']) {
continue;
}
$bgColor = '#c62828'; // danger (red)
if ($alert['type'] === 'warning') {
$bgColor = '#f57c00'; // warning (orange)
}
echo '<tr>';
echo '<td colspan="4" style="background: ' . $bgColor . '; color: white; text-align: center; font-weight: bold; padding: 10px;">';
echo $alert['icon'] . ' ' . $alert['message'];
echo '</td>';
echo '</tr>';
}
}