TKK_E32230273/api_monitoring.php

212 lines
10 KiB
PHP

<?php
/**
* API Monitoring - Backend for Arduino ESP32 Component Monitoring
* Endpoints:
* GET ?action=status → Get all component statuses with extra data
* POST ?action=update → Update a component from Arduino/ESP32
* GET ?action=history&id=X → Get history for a specific component
* POST ?action=bulk_update → Update multiple components at once
*/
header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type');
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; }
include 'koneksi.php';
// ─── Create tables ──────────────────────────────────────────────────────────
$pdo->exec("
CREATE TABLE IF NOT EXISTS monitoring_components (
id INT AUTO_INCREMENT PRIMARY KEY,
component_key VARCHAR(50) UNIQUE NOT NULL,
component_name VARCHAR(100) NOT NULL,
component_type VARCHAR(50) NOT NULL DEFAULT 'sensor',
status ENUM('online','offline','warning','error') DEFAULT 'offline',
value VARCHAR(100) DEFAULT NULL,
unit VARCHAR(20) DEFAULT NULL,
icon VARCHAR(50) DEFAULT 'mdi-chip',
color VARCHAR(20) DEFAULT '#4B49AC',
image VARCHAR(100) DEFAULT NULL,
extra_data JSON DEFAULT NULL,
last_seen DATETIME DEFAULT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
");
$pdo->exec("
CREATE TABLE IF NOT EXISTS monitoring_history (
id INT AUTO_INCREMENT PRIMARY KEY,
component_id INT NOT NULL,
value VARCHAR(100) DEFAULT NULL,
status ENUM('online','offline','warning','error') DEFAULT 'online',
recorded_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (component_id) REFERENCES monitoring_components(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
");
// ─── Ensure columns exist ───────────────────────────────────────────────────
try { $pdo->query("SELECT extra_data FROM monitoring_components LIMIT 1"); } catch (Exception $e) {
$pdo->exec("ALTER TABLE monitoring_components ADD COLUMN extra_data JSON DEFAULT NULL");
}
try { $pdo->query("SELECT image FROM monitoring_components LIMIT 1"); } catch (Exception $e) {
$pdo->exec("ALTER TABLE monitoring_components ADD COLUMN image VARCHAR(100) DEFAULT NULL");
}
// ─── Seed defaults ──────────────────────────────────────────────────────────
$count = $pdo->query("SELECT COUNT(*) FROM monitoring_components")->fetchColumn();
if ($count == 0) {
$defaults = [
['esp32', 'Mikrokontroler ESP32', 'controller', 'offline', null, null,
'mdi-developer-board', '#4B49AC', 'esp32.jpeg',
json_encode(['wifi_status'=>'off','wifi_rssi'=>'0','wifi_ssid'=>'','wifi_ip'=>'',
'bluetooth'=>'off','cpu_freq'=>'240','free_heap'=>'0',
'uptime'=>'0','temperature'=>'0','voltage_in'=>'0'])],
['fingerprint', 'Sensor Sidik Jari AS608', 'sensor', 'offline', null, null,
'mdi-fingerprint', '#F3797E', 'as608.jpeg',
json_encode(['sensor_state'=>'ready','enrolled_count'=>'0',
'last_scan_result'=>'none','confidence'=>'0','last_matched_id'=>''])],
['tft_screen', 'Layar TFT Touch Screen ILI9488', 'display', 'offline', null, null,
'mdi-monitor', '#7DA0FA', 'ili9488.jpg',
json_encode(['display_state'=>'active','current_page'=>'Halaman Standby',
'brightness'=>'100','touch_enabled'=>'yes','resolution'=>'480x320'])],
['relay', 'Modul Relay 5V 1 Channel', 'actuator', 'offline', null, null,
'mdi-electric-switch', '#7978E9', 'relay.png',
json_encode(['relay_state'=>'off','circuit_connected'=>'no','trigger_count'=>'0'])],
['solenoid_lock', 'Solenoid Door Lock NC 12V', 'actuator', 'offline', null, null,
'mdi-lock', '#E74C3C', 'solenoid.jpg',
json_encode(['lock_state'=>'locked','voltage'=>'0','power_watts'=>'0',
'open_count'=>'0','last_opened'=>''])],
['buzzer', 'Buzzer', 'actuator', 'offline', null, null,
'mdi-volume-high', '#4ECDC4', 'buzzer.jpeg',
json_encode(['buzzer_state'=>'silent','last_tone'=>'none','beep_count'=>'0'])],
['led_red', 'LED Indikator Merah', 'indicator', 'offline', null, null,
'mdi-led-on', '#FF6B6B', 'led_red.png',
json_encode(['led_state'=>'off','blink_mode'=>'none','brightness'=>'0'])],
['led_green', 'LED Indikator Hijau', 'indicator', 'offline', null, null,
'mdi-led-on', '#51CF66', 'led_green.png',
json_encode(['led_state'=>'off','blink_mode'=>'none','brightness'=>'0'])],
['power_supply', 'Adaptor Power Supply 12V', 'power', 'offline', '0', 'V',
'mdi-power-plug', '#FFA726', 'power_supply.png',
json_encode(['voltage_in'=>'0','voltage_out'=>'0','current_out'=>'0',
'power_watts'=>'0'])],
['step_down', 'Step Down 12V ke 5V LM2596', 'power', 'offline', '0', 'V',
'mdi-arrow-down-bold', '#7DA0FA', 'step_down.png',
json_encode(['state'=>'active','voltage_in'=>'0','voltage_out'=>'0',
'current_out'=>'0','power_watts'=>'0','temperature'=>'0','efficiency'=>'0'])],
['battery', 'Baterai Li-ion 18650', 'power', 'offline', '0', '%',
'mdi-battery', '#66BB6A', 'battery.png',
json_encode(['bat_state'=>'standby','voltage'=>'0','charge_percent'=>'0',
'current'=>'0','power_watts'=>'0','temperature'=>'0'])],
];
$stmt = $pdo->prepare("INSERT INTO monitoring_components
(component_key,component_name,component_type,status,value,unit,icon,color,image,extra_data)
VALUES (?,?,?,?,?,?,?,?,?,?)");
foreach ($defaults as $d) $stmt->execute($d);
}
// ─── Router ─────────────────────────────────────────────────────────────────
$action = $_GET['action'] ?? '';
switch ($action) {
case 'status':
$rows = $pdo->query("
SELECT *, TIMESTAMPDIFF(SECOND, last_seen, NOW()) as seconds_ago
FROM monitoring_components
ORDER BY FIELD(component_type,'controller','sensor','display','actuator','indicator','power'), id
")->fetchAll();
foreach ($rows as &$r) {
if ($r['last_seen'] && $r['seconds_ago'] > 30 && $r['status'] === 'online') {
$pdo->prepare("UPDATE monitoring_components SET status='offline' WHERE id=?")->execute([$r['id']]);
$r['status'] = 'offline';
}
if (isset($r['extra_data']) && is_string($r['extra_data']))
$r['extra_data'] = json_decode($r['extra_data'], true);
}
$online = count(array_filter($rows, fn($r) => $r['status'] === 'online'));
$warning = count(array_filter($rows, fn($r) => $r['status'] === 'warning'));
$error = count(array_filter($rows, fn($r) => $r['status'] === 'error'));
$offline = count(array_filter($rows, fn($r) => $r['status'] === 'offline'));
echo json_encode([
'success' => true, 'data' => $rows,
'summary' => ['total'=>count($rows),'online'=>$online,'warning'=>$warning,'error'=>$error,'offline'=>$offline]
]);
break;
case 'update':
$input = json_decode(file_get_contents('php://input'), true) ?: $_POST;
$key = $input['key'] ?? '';
$status = $input['status'] ?? 'online';
$value = $input['value'] ?? null;
$extra = $input['extra'] ?? null;
if (!$key) { echo json_encode(['success'=>false,'error'=>'Missing key']); break; }
$stmt = $pdo->prepare("SELECT * FROM monitoring_components WHERE component_key=?");
$stmt->execute([$key]);
$comp = $stmt->fetch();
if (!$comp) { echo json_encode(['success'=>false,'error'=>'Not found: '.$key]); break; }
$cur = json_decode($comp['extra_data'] ?? '{}', true) ?: [];
if ($extra && is_array($extra)) $cur = array_merge($cur, $extra);
$pdo->prepare("UPDATE monitoring_components SET status=?, value=?, extra_data=?, last_seen=NOW() WHERE component_key=?")
->execute([$status, $value, json_encode($cur), $key]);
$pdo->prepare("INSERT INTO monitoring_history (component_id, value, status) VALUES (?,?,?)")
->execute([$comp['id'], $value, $status]);
echo json_encode(['success'=>true,'message'=>'Updated '.$key]);
break;
case 'history':
$id = (int)($_GET['id'] ?? 0);
$limit = (int)($_GET['limit'] ?? 50);
$stmt = $pdo->prepare("SELECT h.*, c.component_name, c.unit FROM monitoring_history h
JOIN monitoring_components c ON c.id=h.component_id WHERE h.component_id=?
ORDER BY h.recorded_at DESC LIMIT ?");
$stmt->execute([$id, $limit]);
echo json_encode(['success'=>true,'data'=>$stmt->fetchAll()]);
break;
case 'bulk_update':
$input = json_decode(file_get_contents('php://input'), true);
$components = $input['components'] ?? [];
$updated = 0;
foreach ($components as $c) {
$k = $c['key'] ?? ''; if (!$k) continue;
$s = $c['status'] ?? 'online'; $v = $c['value'] ?? null; $e = $c['extra'] ?? null;
$row = $pdo->prepare("SELECT extra_data FROM monitoring_components WHERE component_key=?");
$row->execute([$k]); $r = $row->fetch();
$cur = json_decode($r['extra_data'] ?? '{}', true) ?: [];
if ($e && is_array($e)) $cur = array_merge($cur, $e);
$pdo->prepare("UPDATE monitoring_components SET status=?, value=?, extra_data=?, last_seen=NOW() WHERE component_key=?")
->execute([$s, $v, json_encode($cur), $k]);
$updated++;
}
echo json_encode(['success'=>true,'updated'=>$updated]);
break;
default:
echo json_encode(['success'=>false,'error'=>'Invalid action',
'actions'=>['status','update','bulk_update','history']]);
}